result.vue 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744
  1. <template>
  2. <view class="sr-page">
  3. <view class="sr-hd" :style="{ paddingTop: (statusBar + 12) + 'px' }">
  4. <view class="sr-hd-row">
  5. <view class="sr-back" @tap="goBack">
  6. <text class="sr-back-icon">←</text>
  7. </view>
  8. <view class="sr-search-bar" @tap="openSearch">
  9. <text class="sr-search-icon">🔍</text>
  10. <text class="sr-search-text">{{ keyword || copy.placeholder }}</text>
  11. </view>
  12. </view>
  13. <scroll-view scroll-x class="sr-tabs-scroll" :show-scrollbar="false">
  14. <view class="sr-tabs">
  15. <view
  16. v-for="(tab, index) in tabs"
  17. :key="tab.type"
  18. class="sr-tab"
  19. :class="{ 'sr-tab--on': currentTab === index }"
  20. @tap="onTabChange(index)"
  21. >
  22. <text class="sr-tab-text">{{ tabLabel(index) }}</text>
  23. </view>
  24. </view>
  25. </scroll-view>
  26. </view>
  27. <!-- 作品:双列网格 -->
  28. <scroll-view
  29. v-if="currentTab === 0"
  30. scroll-y
  31. class="sr-scroll"
  32. :style="{ height: scrollHeight + 'px' }"
  33. :lower-threshold="120"
  34. @scrolltolower="loadMore"
  35. >
  36. <view class="sr-body" :style="{ paddingBottom: safeBottom + 'px' }">
  37. <view v-if="activeTab.loading && !activeTab.rows.length" class="sr-state">
  38. <text class="sr-state-txt">{{ copy.loading }}</text>
  39. </view>
  40. <empty
  41. v-else-if="activeTab.loaded && !activeTab.rows.length"
  42. src="find_default3x"
  43. :text="copy.emptyWorks"
  44. />
  45. <view v-else class="sr-works">
  46. <view
  47. v-for="(item, index) in activeTab.rows"
  48. :key="item.id || index"
  49. class="sr-work-card"
  50. >
  51. <view class="sr-work-cover-wrap" @tap="openFind(item)">
  52. <image
  53. v-if="coverOf(item)"
  54. class="sr-work-cover"
  55. :src="coverOf(item)"
  56. mode="aspectFill"
  57. />
  58. <view v-else class="sr-work-cover sr-work-cover--ph" />
  59. <view v-if="isVideoItem(item)" class="sr-work-video-badge">
  60. <text class="sr-work-video-icon">▶</text>
  61. </view>
  62. </view>
  63. <view class="sr-work-body">
  64. <view class="sr-work-title" @tap="openFind(item)">
  65. <text v-if="item.type_text" class="sr-work-tag">{{ item.type_text }}</text>
  66. <text class="sr-work-txt">{{ formatContent(item.content) }}</text>
  67. </view>
  68. <view class="sr-work-ft">
  69. <text class="sr-work-date">{{ formatDate(item.createtime) }}</text>
  70. <view class="sr-work-like" @tap.stop="onLike(index)">
  71. <text
  72. class="sr-work-like-icon"
  73. :class="{ 'sr-work-like-icon--on': item.isLike === 1 }"
  74. >♥</text>
  75. <text class="sr-work-like-num">{{ item.likes || 0 }}</text>
  76. </view>
  77. </view>
  78. </view>
  79. </view>
  80. </view>
  81. <uni-load-more
  82. v-if="activeTab.rows.length"
  83. :status="activeTab.loadStatus"
  84. :content-text="loadMoreText"
  85. />
  86. </view>
  87. </scroll-view>
  88. <!-- 用户 -->
  89. <scroll-view
  90. v-else
  91. scroll-y
  92. class="sr-scroll"
  93. :style="{ height: scrollHeight + 'px' }"
  94. :lower-threshold="120"
  95. @scrolltolower="loadMore"
  96. >
  97. <view class="sr-body" :style="{ paddingBottom: safeBottom + 'px' }">
  98. <view v-if="activeTab.loading && !activeTab.rows.length" class="sr-state">
  99. <text class="sr-state-txt">{{ copy.loading }}</text>
  100. </view>
  101. <empty
  102. v-else-if="activeTab.loaded && !activeTab.rows.length"
  103. src="find_default3x"
  104. :text="copy.emptyUsers"
  105. />
  106. <view v-else class="sr-users">
  107. <view
  108. v-for="(item, index) in activeTab.rows"
  109. :key="item.user_no || index"
  110. class="sr-user-card"
  111. @tap="openUser(item)"
  112. >
  113. <image class="sr-user-avatar" :src="userAvatar(item)" mode="aspectFill" />
  114. <view class="sr-user-main">
  115. <view class="sr-user-info">
  116. <view class="sr-user-name-row">
  117. <text v-if="item.shop" class="sr-user-shop-tag">{{ copy.shopTag }}</text>
  118. <text class="sr-user-name">{{ userName(item) }}</text>
  119. </view>
  120. <view class="sr-user-stats">
  121. <text class="sr-user-stat">{{ statFans(item) }}</text>
  122. <text class="sr-user-stat">{{ statPraised(item) }}</text>
  123. </view>
  124. </view>
  125. <button
  126. class="sr-follow-btn"
  127. :class="{ 'sr-follow-btn--on': item.isFollow === 1 }"
  128. @tap.stop="onFollow(index)"
  129. >
  130. {{ item.isFollow === 1 ? copy.followed : copy.follow }}
  131. </button>
  132. </view>
  133. </view>
  134. </view>
  135. <uni-load-more
  136. v-if="activeTab.rows.length"
  137. :status="activeTab.loadStatus"
  138. :content-text="loadMoreText"
  139. />
  140. </view>
  141. </scroll-view>
  142. </view>
  143. </template>
  144. <script>
  145. import { fetchFindSearchPage } from '@/features/search/search-gateway'
  146. import { stripHtml } from '@/features/feed/clip-normalize'
  147. import { toggleClipLike } from '@/features/feed/feed-gateway'
  148. import { toggleProfileFollow } from '@/features/profile/profile-gateway'
  149. import { detailPageUrl, videoDetailUrl } from '@/features/dynamics/post-media'
  150. function createTabState(type) {
  151. return {
  152. type,
  153. rows: [],
  154. page: 1,
  155. loadStatus: 'more',
  156. loading: false,
  157. loaded: false
  158. }
  159. }
  160. export default {
  161. data() {
  162. return {
  163. statusBar: 0,
  164. safeBottom: 0,
  165. scrollHeight: 600,
  166. keyword: '',
  167. currentTab: 0,
  168. tabs: [
  169. createTabState('works'),
  170. createTabState('user')
  171. ]
  172. }
  173. },
  174. computed: {
  175. copy() {
  176. const t = this.$t.bind(this)
  177. return {
  178. placeholder: t('search.placeholder'),
  179. tabWorks: t('search.tabWorks'),
  180. tabUser: t('search.tabUser'),
  181. loading: t('search.loading'),
  182. emptyWorks: t('search.emptyWorks'),
  183. emptyUsers: t('search.emptyUsers'),
  184. shopTag: t('search.shopTag'),
  185. follow: t('search.follow'),
  186. followed: t('search.followed'),
  187. loadFailed: t('search.loadFailed'),
  188. actionFailed: t('search.actionFailed'),
  189. contentUnavailable: t('search.contentUnavailable')
  190. }
  191. },
  192. loadMoreText() {
  193. const t = this.$t.bind(this)
  194. return {
  195. contentdown: t('search.loadMore'),
  196. contentrefresh: t('search.loading'),
  197. contentnomore: t('search.noMore')
  198. }
  199. },
  200. activeTab() {
  201. return this.tabs[this.currentTab] || this.tabs[0]
  202. },
  203. headerHeight() {
  204. return this.statusBar + uni.upx2px(180)
  205. }
  206. },
  207. onLoad(query) {
  208. this.keyword = query && query.search ? decodeURIComponent(query.search) : ''
  209. this.initLayout()
  210. this.loadTab(0, true)
  211. },
  212. onPullDownRefresh() {
  213. this.loadTab(this.currentTab, true).finally(() => {
  214. try { uni.stopPullDownRefresh() } catch (_) {}
  215. })
  216. },
  217. methods: {
  218. tabLabel(index) {
  219. if (index === 0) return this.copy.tabWorks
  220. if (index === 1) return this.copy.tabUser
  221. return ''
  222. },
  223. statFans(item) {
  224. return this.$t('search.statFans', { n: item.fans || 0 })
  225. },
  226. statPraised(item) {
  227. return this.$t('search.statPraised', { n: item.praised || 0 })
  228. },
  229. initLayout() {
  230. try {
  231. const info = uni.getSystemInfoSync()
  232. this.statusBar = info.statusBarHeight || 0
  233. this.safeBottom = (info.safeAreaInsets && info.safeAreaInsets.bottom) || 0
  234. this.scrollHeight = (info.windowHeight || 667) - this.headerHeight
  235. } catch (_) {}
  236. },
  237. goBack() {
  238. uni.navigateBack({
  239. fail: () => uni.switchTab({ url: '/pages/index/index' })
  240. })
  241. },
  242. openSearch() {
  243. const q = this.keyword
  244. ? `?keywords=${encodeURIComponent(this.keyword)}&type=find`
  245. : '?type=find'
  246. uni.navigateTo({ url: `/pages/search/index${q}` })
  247. },
  248. onTabChange(index) {
  249. if (this.currentTab === index) return
  250. this.currentTab = index
  251. const tab = this.tabs[index]
  252. if (!tab.loaded) {
  253. this.loadTab(index, true)
  254. }
  255. },
  256. loadMore() {
  257. this.loadTab(this.currentTab, false)
  258. },
  259. async loadTab(tabIndex, reset) {
  260. const tab = this.tabs[tabIndex]
  261. if (!tab) return
  262. if (tab.loadStatus === 'noMore' && !reset) return
  263. if (tab.loading) return
  264. if (reset) {
  265. tab.page = 1
  266. tab.rows = []
  267. tab.loadStatus = 'more'
  268. tab.loaded = false
  269. }
  270. tab.loading = true
  271. tab.loadStatus = 'loading'
  272. try {
  273. const pack = await fetchFindSearchPage(tab.page, {
  274. search: this.keyword,
  275. listType: tab.type
  276. })
  277. const list = (pack.rows || []).map((row) =>
  278. Object.assign({}, row, { listPage: pack.currentPage || tab.page })
  279. )
  280. tab.rows = reset ? list : tab.rows.concat(list)
  281. tab.page = pack.currentPage || tab.page
  282. if ((pack.currentPage || 1) >= (pack.lastPage || 1)) {
  283. tab.loadStatus = 'noMore'
  284. } else {
  285. tab.loadStatus = 'more'
  286. tab.page = (pack.currentPage || tab.page) + 1
  287. }
  288. tab.loaded = true
  289. } catch (err) {
  290. tab.loadStatus = 'more'
  291. if (reset) tab.rows = []
  292. tab.loaded = true
  293. this.$appKit && this.$appKit.msg(err.message || this.copy.loadFailed)
  294. } finally {
  295. tab.loading = false
  296. }
  297. },
  298. oss(url, w = 400, h = 0) {
  299. if (this.$appKit && typeof this.$appKit.oss === 'function') {
  300. return this.$appKit.oss(url, w, h)
  301. }
  302. return url || ''
  303. },
  304. coverOf(item) {
  305. const images = Array.isArray(item.images) ? item.images : []
  306. const cover =
  307. images[0] ||
  308. (item.video && item.video.cover_url) ||
  309. item.cover ||
  310. ''
  311. return cover ? this.oss(cover, 400, 460) : ''
  312. },
  313. formatContent(content) {
  314. const text = stripHtml(content)
  315. if (!text) return ' '
  316. return text.length > 48 ? `${text.slice(0, 48)}…` : text
  317. },
  318. formatDate(ts) {
  319. if (this.$appKit && typeof this.$appKit.timeFormat === 'function') {
  320. return this.$appKit.timeFormat(ts, 'mm-dd')
  321. }
  322. return ''
  323. },
  324. userAvatar(item) {
  325. if (item.shop && item.shop.avatar) return this.oss(item.shop.avatar, 88, 88)
  326. if (item.user && item.user.avatar) return this.oss(item.user.avatar, 88, 88)
  327. return ''
  328. },
  329. userName(item) {
  330. if (item.shop && item.shop.shopname) return item.shop.shopname
  331. if (item.user && item.user.nickname) return item.user.nickname
  332. return '—'
  333. },
  334. isVideoItem(item) {
  335. if (!item) return false
  336. if (item.type === 'video') return true
  337. return !!(item.video && (item.video.url || item.video.cover_url))
  338. },
  339. openFind(item) {
  340. if (!item) return
  341. if (item.state && item.state !== 'normal') {
  342. this.$appKit && this.$appKit.msg(this.copy.contentUnavailable)
  343. return
  344. }
  345. if (item.type === 'live' && item.live_id) {
  346. uni.navigateTo({ url: `/pages/live/watch?id=${item.live_id}` })
  347. return
  348. }
  349. if (this.isVideoItem(item)) {
  350. uni.navigateTo({
  351. url: videoDetailUrl(item.id, {
  352. type: 'work',
  353. page: item.listPage || item.page || 1,
  354. search: this.keyword || undefined
  355. })
  356. })
  357. return
  358. }
  359. if (item.id) {
  360. uni.navigateTo({ url: detailPageUrl(item.id) })
  361. }
  362. },
  363. openUser(item) {
  364. if (!item || !item.user_no) return
  365. uni.navigateTo({
  366. url: `/pages/profile/show?id=${encodeURIComponent(String(item.user_no))}`
  367. })
  368. },
  369. async onLike(index) {
  370. if (!this.$appKit || !this.$appKit.requireLogin()) return
  371. const tab = this.tabs[0]
  372. const row = tab.rows[index]
  373. if (!row || !row.id) return
  374. try {
  375. const flag = await toggleClipLike(row.id)
  376. if (flag === 0 || flag === '0') {
  377. row.isLike = 0
  378. row.likes = Math.max(0, Number(row.likes || 0) - 1)
  379. } else if (flag === 1 || flag === '1') {
  380. row.isLike = 1
  381. row.likes = Number(row.likes || 0) + 1
  382. }
  383. } catch (err) {
  384. this.$appKit.msg(err.message || this.copy.actionFailed)
  385. }
  386. },
  387. async onFollow(index) {
  388. if (!this.$appKit || !this.$appKit.requireLogin()) return
  389. const tab = this.tabs[1]
  390. const row = tab.rows[index]
  391. if (!row || !row.user_no) return
  392. try {
  393. const flag = await toggleProfileFollow(row.user_no)
  394. if (flag === 0 || flag === '0') row.isFollow = 0
  395. else if (flag === 1 || flag === '1') row.isFollow = 1
  396. } catch (err) {
  397. this.$appKit.msg(err.message || this.copy.actionFailed)
  398. }
  399. }
  400. }
  401. }
  402. </script>
  403. <style scoped>
  404. .sr-page {
  405. min-height: 100vh;
  406. background-color: #eef3fb;
  407. }
  408. .sr-hd {
  409. padding-left: 32rpx;
  410. padding-right: 32rpx;
  411. padding-bottom: 8rpx;
  412. }
  413. .sr-hd-row {
  414. display: flex;
  415. flex-direction: row;
  416. align-items: center;
  417. margin-bottom: 20rpx;
  418. }
  419. .sr-back {
  420. width: 72rpx;
  421. height: 72rpx;
  422. border-radius: 20rpx;
  423. background-color: #ffffff;
  424. box-shadow: 0 6rpx 20rpx rgba(74, 140, 255, 0.12);
  425. display: flex;
  426. align-items: center;
  427. justify-content: center;
  428. flex-shrink: 0;
  429. margin-right: 20rpx;
  430. }
  431. .sr-back-icon {
  432. font-size: 36rpx;
  433. color: #4a8cff;
  434. line-height: 1;
  435. }
  436. .sr-search-bar {
  437. flex: 1;
  438. min-width: 0;
  439. height: 72rpx;
  440. border-radius: 20rpx;
  441. background-color: #ffffff;
  442. box-shadow: 0 6rpx 20rpx rgba(74, 140, 255, 0.1);
  443. display: flex;
  444. flex-direction: row;
  445. align-items: center;
  446. padding: 0 24rpx;
  447. box-sizing: border-box;
  448. }
  449. .sr-search-icon {
  450. font-size: 28rpx;
  451. margin-right: 12rpx;
  452. opacity: 0.7;
  453. }
  454. .sr-search-text {
  455. flex: 1;
  456. font-size: 28rpx;
  457. color: #1a1d29;
  458. overflow: hidden;
  459. text-overflow: ellipsis;
  460. white-space: nowrap;
  461. }
  462. .sr-tabs-scroll {
  463. white-space: nowrap;
  464. }
  465. .sr-tabs {
  466. display: inline-flex;
  467. flex-direction: row;
  468. padding-bottom: 12rpx;
  469. }
  470. .sr-tab {
  471. padding: 12rpx 28rpx;
  472. margin-right: 16rpx;
  473. border-radius: 999rpx;
  474. background-color: rgba(255, 255, 255, 0.7);
  475. }
  476. .sr-tab--on {
  477. background: linear-gradient(135deg, #4a8cff 0%, #6ba0ff 100%);
  478. box-shadow: 0 6rpx 16rpx rgba(74, 140, 255, 0.25);
  479. }
  480. .sr-tab-text {
  481. font-size: 28rpx;
  482. color: #8a8d9e;
  483. font-weight: 500;
  484. }
  485. .sr-tab--on .sr-tab-text {
  486. color: #ffffff;
  487. font-weight: 600;
  488. }
  489. .sr-body {
  490. padding: 16rpx 24rpx 0;
  491. box-sizing: border-box;
  492. }
  493. .sr-state {
  494. padding: 120rpx 0;
  495. text-align: center;
  496. }
  497. .sr-state-txt {
  498. font-size: 28rpx;
  499. color: #8a8d9e;
  500. }
  501. .sr-works {
  502. display: flex;
  503. flex-direction: row;
  504. flex-wrap: wrap;
  505. justify-content: space-between;
  506. }
  507. .sr-work-card {
  508. width: calc((100% - 16rpx) / 2);
  509. margin-bottom: 24rpx;
  510. background-color: #ffffff;
  511. border-radius: 24rpx;
  512. overflow: hidden;
  513. box-shadow: 0 6rpx 24rpx rgba(74, 140, 255, 0.08);
  514. }
  515. .sr-work-cover-wrap {
  516. position: relative;
  517. width: 100%;
  518. height: 460rpx;
  519. background-color: #eef2f8;
  520. }
  521. .sr-work-video-badge {
  522. position: absolute;
  523. left: 50%;
  524. top: 50%;
  525. transform: translate(-50%, -50%);
  526. width: 72rpx;
  527. height: 72rpx;
  528. border-radius: 36rpx;
  529. background-color: rgba(0, 0, 0, 0.42);
  530. display: flex;
  531. align-items: center;
  532. justify-content: center;
  533. }
  534. .sr-work-video-icon {
  535. color: #ffffff;
  536. font-size: 32rpx;
  537. margin-left: 4rpx;
  538. }
  539. .sr-work-cover {
  540. width: 100%;
  541. height: 100%;
  542. display: block;
  543. }
  544. .sr-work-cover--ph {
  545. background: linear-gradient(135deg, #c1c8d6 0%, #8e96a6 100%);
  546. }
  547. .sr-work-body {
  548. padding: 16rpx 18rpx 18rpx;
  549. }
  550. .sr-work-title {
  551. margin-bottom: 12rpx;
  552. }
  553. .sr-work-tag {
  554. display: inline-block;
  555. font-size: 20rpx;
  556. color: #4a8cff;
  557. background-color: rgba(74, 140, 255, 0.12);
  558. padding: 2rpx 10rpx;
  559. border-radius: 8rpx;
  560. margin-right: 8rpx;
  561. vertical-align: middle;
  562. }
  563. .sr-work-txt {
  564. font-size: 26rpx;
  565. font-weight: 600;
  566. color: #1a1d29;
  567. line-height: 36rpx;
  568. overflow: hidden;
  569. text-overflow: ellipsis;
  570. display: -webkit-box;
  571. -webkit-line-clamp: 2;
  572. -webkit-box-orient: vertical;
  573. }
  574. .sr-work-ft {
  575. display: flex;
  576. flex-direction: row;
  577. align-items: center;
  578. justify-content: space-between;
  579. }
  580. .sr-work-date {
  581. font-size: 22rpx;
  582. color: #8a8d9e;
  583. }
  584. .sr-work-like {
  585. display: flex;
  586. flex-direction: row;
  587. align-items: center;
  588. }
  589. .sr-work-like-icon {
  590. font-size: 28rpx;
  591. color: #b0b4c0;
  592. margin-right: 6rpx;
  593. }
  594. .sr-work-like-icon--on {
  595. color: #ff4d4f;
  596. }
  597. .sr-work-like-num {
  598. font-size: 24rpx;
  599. color: #5c6070;
  600. }
  601. .sr-users {
  602. display: flex;
  603. flex-direction: column;
  604. }
  605. .sr-user-card {
  606. display: flex;
  607. flex-direction: row;
  608. align-items: center;
  609. padding: 24rpx;
  610. margin-bottom: 20rpx;
  611. background-color: #ffffff;
  612. border-radius: 24rpx;
  613. box-shadow: 0 6rpx 24rpx rgba(74, 140, 255, 0.08);
  614. }
  615. .sr-user-avatar {
  616. width: 100rpx;
  617. height: 100rpx;
  618. border-radius: 50rpx;
  619. flex-shrink: 0;
  620. background-color: #eef2f8;
  621. }
  622. .sr-user-main {
  623. flex: 1;
  624. min-width: 0;
  625. margin-left: 20rpx;
  626. display: flex;
  627. flex-direction: row;
  628. align-items: center;
  629. }
  630. .sr-user-info {
  631. flex: 1;
  632. min-width: 0;
  633. margin-right: 16rpx;
  634. }
  635. .sr-user-name-row {
  636. display: flex;
  637. flex-direction: row;
  638. align-items: center;
  639. margin-bottom: 8rpx;
  640. }
  641. .sr-user-shop-tag {
  642. flex-shrink: 0;
  643. margin-right: 8rpx;
  644. padding: 2rpx 10rpx;
  645. border-radius: 8rpx;
  646. background: linear-gradient(135deg, #4a8cff 0%, #6ec8ff 100%);
  647. font-size: 20rpx;
  648. color: #ffffff;
  649. }
  650. .sr-user-name {
  651. font-size: 30rpx;
  652. font-weight: 600;
  653. color: #1a1d26;
  654. overflow: hidden;
  655. text-overflow: ellipsis;
  656. white-space: nowrap;
  657. }
  658. .sr-user-stats {
  659. display: flex;
  660. flex-direction: row;
  661. }
  662. .sr-user-stat {
  663. font-size: 24rpx;
  664. color: #8a8d9e;
  665. margin-right: 20rpx;
  666. }
  667. .sr-follow-btn {
  668. flex-shrink: 0;
  669. margin: 0;
  670. padding: 0 28rpx;
  671. height: 56rpx;
  672. line-height: 56rpx;
  673. font-size: 24rpx;
  674. color: #ffffff;
  675. background: linear-gradient(135deg, #4a8cff 0%, #6ec8ff 100%);
  676. border-radius: 999rpx;
  677. border: none;
  678. }
  679. .sr-follow-btn--on {
  680. color: #8a8d9e;
  681. background: #f4f6fb;
  682. border: 1rpx solid #e8edf5;
  683. }
  684. .sr-follow-btn::after {
  685. border: none;
  686. }
  687. </style>