homePageSearch.vue 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617
  1. <template>
  2. <view class="container">
  3. <!-- 顶部导航 Tab -->
  4. <view class="top-nav">
  5. <view class="search-cont">
  6. <view class="inner">
  7. <image class="icon-search"
  8. src="https://jnlzjk-1323137866.cos.ap-chongqing.myqcloud.com/shop/images/search.png" mode="">
  9. </image>
  10. <input type="text" @confirm="goSearch" v-model="keywordValue" placeholder="请输入关键字搜索内容"
  11. placeholder-style="font-size:28rpx;color:#BBBBBB;font-family: PingFang SC;" />
  12. <u-icon v-if="keywordValue != ''" name="close-circle" color="#00000073" size="20"
  13. @tap="deleteKeywordMethods"></u-icon>
  14. </view>
  15. <view class="searchBtnViewClass" @tap="goSearch">搜索</view>
  16. </view>
  17. <view v-if="false" class="nav-row">
  18. <view class="nav-all" :class="{ active: activeId === 'all' }" @tap.stop="onSelectAll">
  19. <text>全部</text>
  20. </view>
  21. <scroll-view scroll-x class="nav-scroll" :show-scrollbar="false">
  22. <view class="nav-inner">
  23. <view v-for="(item, index) in navList" :key="index"
  24. :class="['nav-item', { active: item.id === activeId }]"
  25. @tap.stop="onSelectByIndex(item.id)">
  26. <text>{{ item.categoryName }}</text>
  27. </view>
  28. </view>
  29. </scroll-view>
  30. </view>
  31. </view>
  32. <scroll-view scroll-y class="scroll-wrap" :show-scrollbar="false" :scroll-top="scrollTop"
  33. @scrolltolower="isSearch ? getPageSearchCoursesData() : getPageRecommendCoursesData()">
  34. <!-- 没有搜索词-推荐课程 -->
  35. <template v-if="!isSearch">
  36. <view style="height: 300rpx;width: 100%;"> </view>
  37. <view class="recommend-section">
  38. <text class="recommend-title">大家都在学习</text>
  39. <view v-if="recommendList.length > 0" class="course-grid" style="padding: 0;">
  40. <view v-for="(course, idx) in recommendList" :key="idx" class="course-card"
  41. @click="onCourseClick(course)">
  42. <view class="card-cover">
  43. <image :src="course.imgUrl || '/static/logo.jpg'" mode="aspectFill" class="cover-img">
  44. </image>
  45. </view>
  46. <view class="card-footer">
  47. <text class="card-title">{{ course.courseName }}</text>
  48. <view class="x-end" style="justify-content: space-between;">
  49. <view class="course-meta">
  50. <image src="@/static/images/new/renshu.png"></image>
  51. <text class="meta-count">{{ $formattedViewCount(course.watchUserCount) }}</text>
  52. </view>
  53. <view class="btn-watch" @click.stop="onCourseClick(course)">立即观看</view>
  54. </view>
  55. </view>
  56. </view>
  57. </view>
  58. <view v-else class="empty-state">
  59. <image class="empty-icon" src="@/static/images/new/nodata.png"></image>
  60. <text class="empty-text">暂无课程</text>
  61. </view>
  62. </view>
  63. </template>
  64. <!-- 搜索后的课程列表 内容 -->
  65. <template v-else>
  66. <view v-if="courseList.length > 0" class="course-grid">
  67. <view v-for="(course, idx) in courseList" :key="idx" class="course-card"
  68. @click="onCourseClick(course)">
  69. <view class="card-cover">
  70. <image :src="course.imgUrl || '/static/logo.jpg'" mode="aspectFill" class="cover-img">
  71. </image>
  72. </view>
  73. <view class="course-info">
  74. <text class="card-title">{{ course.courseName }}</text>
  75. <view class="x-end" style="justify-content: space-between;">
  76. <view class="course-meta">
  77. <image src="@/static/images/new/renshu.png"></image>
  78. <text class="meta-count">{{ $formattedViewCount(course.watchUserCount) }}</text>
  79. </view>
  80. <view class="btn-watch" @click.stop="onCourseClick(course)">立即观看</view>
  81. </view>
  82. </view>
  83. </view>
  84. </view>
  85. <view v-if="isSearch && courseList.length == 0" class="empty-state">
  86. <image class="empty-icon" src="@/static/images/new/nodata.png"></image>
  87. <text class="empty-text">没有搜索任何内容,换个词试试</text>
  88. </view>
  89. </template>
  90. <view class="bottom-placeholder"></view>
  91. </scroll-view>
  92. </view>
  93. </template>
  94. <script>
  95. import {
  96. courseListDataApi
  97. } from '@/api/home'
  98. export default {
  99. data() {
  100. return {
  101. keywordValue: '',
  102. statusBarHeight: uni.getSystemInfoSync().statusBarHeight + 'px',
  103. activeId: 'all',
  104. courseList: [],
  105. isSearch: false,
  106. scrollTop: 0,
  107. searchPage: {
  108. pageNum: 1,
  109. pageSize: 10,
  110. total: 0,
  111. },
  112. navList: [{
  113. id: 37,
  114. categoryName: "健康食品"
  115. },
  116. {
  117. id: 35,
  118. categoryName: "绿色有机"
  119. },
  120. {
  121. id: 36,
  122. categoryName: "膳食营养"
  123. },
  124. {
  125. id: 33,
  126. categoryName: "太极养生"
  127. }
  128. ],
  129. recommendList: [],
  130. recommendPage: {
  131. pageNum: 1,
  132. pageSize: 6,
  133. total: 0,
  134. },
  135. }
  136. },
  137. onLoad() {
  138. this.getRecommendData()
  139. },
  140. methods: {
  141. deleteKeywordMethods() {
  142. this.keywordValue = ''
  143. this.isSearch = false
  144. this.courseList = []
  145. this.scrollTop = 0
  146. },
  147. goSearch() {
  148. if (this.keywordValue == '') {
  149. this.isSearch = false
  150. this.searchPage.pageNum = 1;
  151. this.searchPage.total = 0;
  152. this.courseList = [];
  153. } else {
  154. this.resetSearchDataList()
  155. }
  156. },
  157. onSelectAll() {
  158. this.activeId = 'all'
  159. },
  160. onCourseClick(course) {
  161. uni.navigateTo({
  162. url: `/pages/course/info?courseId=${course.courseId}`
  163. })
  164. },
  165. onSelectByIndex(id) {
  166. this.activeId = id
  167. },
  168. // 搜索课程列表
  169. async searchCourseList() {
  170. let params = {
  171. pageNum: this.searchPage.pageNum,
  172. pageSize: this.searchPage.pageSize,
  173. keyword: this.keywordValue,
  174. // yxxTag: 3
  175. };
  176. uni.showLoading({
  177. title: "加载中...",
  178. mask: true,
  179. })
  180. const res = await courseListDataApi(params);
  181. this.isSearch = true
  182. uni.hideLoading()
  183. if (res.code === 200 && res.data.list.length > 0) {
  184. this.searchPage.total = res.data.total;
  185. this.courseList = [...this.courseList, ...res.data.list];
  186. }
  187. },
  188. // 分页获取搜索课程列表
  189. getPageSearchCoursesData() {
  190. if (this.searchPage.total <= this.courseList.length) {
  191. return;
  192. }
  193. this.searchPage.pageNum++;
  194. this.searchCourseList();
  195. },
  196. // 搜索课程列表重置方法
  197. resetSearchDataList() {
  198. this.searchPage.pageNum = 1;
  199. this.searchPage.total = 0;
  200. this.courseList = [];
  201. this.scrollTop = 0;
  202. this.searchCourseList();
  203. },
  204. // 获取推荐课程列表
  205. async getRecommendData() {
  206. let params = {
  207. pageNum: this.recommendPage.pageNum,
  208. pageSize: this.recommendPage.pageSize,
  209. };
  210. const res = await courseListDataApi(params);
  211. if (res.code === 200 && res.data.list.length > 0) {
  212. this.recommendPage.total = res.data.total;
  213. this.recommendList = [...this.recommendList, ...res.data.list];
  214. }
  215. },
  216. // 分页获取推荐课程列表
  217. getPageRecommendCoursesData() {
  218. return;
  219. if (this.recommendPage.total <= this.recommendList.length) {
  220. return;
  221. }
  222. this.recommendPage.pageNum++;
  223. this.getRecommendData();
  224. },
  225. // 推荐课程列表重置方法
  226. resetRecommendDataList() {
  227. this.recommendPage.pageNum = 1;
  228. this.recommendPage.total = 0;
  229. this.recommendList = [];
  230. this.getRecommendData();
  231. },
  232. }
  233. }
  234. </script>
  235. <style lang="scss" scoped>
  236. /* 图片箭头旋转类(展开时向上) */
  237. .rotate-arrow {
  238. transform: rotate(180deg);
  239. }
  240. .container {
  241. // min-height: 100vh;
  242. background: #F5F5F5;
  243. display: flex;
  244. flex-direction: column;
  245. }
  246. /* 顶部 Tab */
  247. .top-nav {
  248. display: flex;
  249. flex-direction: column;
  250. background: #fff;
  251. }
  252. .search-cont {
  253. padding: 24rpx 24rpx 20rpx;
  254. background-color: #FFFFFF;
  255. display: flex;
  256. align-items: center;
  257. justify-content: space-between;
  258. .inner {
  259. box-sizing: border-box;
  260. width: calc(100vw - 135rpx);
  261. height: 72rpx;
  262. background: #F7F7F7;
  263. border-radius: 38rpx;
  264. display: flex;
  265. align-items: center;
  266. padding: 0 20rpx;
  267. .icon-search {
  268. width: 28upx;
  269. height: 28upx;
  270. margin-right: 20upx;
  271. }
  272. input {
  273. height: 65rpx;
  274. line-height: 65rpx;
  275. flex: 1;
  276. font-size: 32rpx;
  277. padding-right: 15rpx;
  278. }
  279. }
  280. .searchBtnViewClass {
  281. font-weight: 400;
  282. font-size: 36rpx;
  283. color: #222222;
  284. }
  285. .icon-search {
  286. margin-left: 10upx;
  287. width: 40upx;
  288. height: 40upx;
  289. image {
  290. width: 40upx;
  291. height: 40upx;
  292. }
  293. }
  294. }
  295. .nav-row {
  296. display: flex;
  297. align-items: center;
  298. padding: 0 24rpx 24rpx;
  299. gap: 30rpx;
  300. }
  301. .nav-all {
  302. flex-shrink: 0;
  303. font-family: PingFangSC, PingFang SC;
  304. font-weight: 400;
  305. font-size: 40rpx;
  306. color: rgba(0, 0, 0, 0.85);
  307. line-height: 56rpx;
  308. }
  309. .nav-all.active {
  310. color: #FF233C;
  311. font-weight: 600;
  312. }
  313. .nav-scroll {
  314. flex: 1;
  315. }
  316. .nav-inner {
  317. display: inline-flex;
  318. padding: 0;
  319. gap: 30rpx;
  320. }
  321. .nav-item {
  322. flex-shrink: 0;
  323. font-family: PingFangSC, PingFang SC;
  324. font-weight: 400;
  325. font-size: 40rpx;
  326. color: rgba(0, 0, 0, 0.85);
  327. line-height: 56rpx;
  328. }
  329. .nav-item.active {
  330. color: #FF233C;
  331. font-weight: 600;
  332. }
  333. /* 滚动区 */
  334. .scroll-wrap {
  335. flex: 1;
  336. height: 0;
  337. }
  338. /* 课程网格 */
  339. .course-grid {
  340. display: flex;
  341. flex-wrap: wrap;
  342. padding: 24rpx;
  343. gap: 24rpx 20rpx;
  344. flex-direction: column;
  345. }
  346. .course-card {
  347. display: flex;
  348. background: #fff;
  349. border-radius: 20rpx;
  350. overflow: hidden;
  351. padding: 20rpx;
  352. }
  353. .course-tag {
  354. position: absolute;
  355. left: 0;
  356. bottom: 0;
  357. right: 0;
  358. padding: 8rpx 12rpx;
  359. background: linear-gradient(transparent, rgba(0, 0, 0, 0.6));
  360. font-size: 22rpx;
  361. color: #fff;
  362. }
  363. .course-info {
  364. flex: 1;
  365. padding-left: 24rpx;
  366. /* padding: 20rpx 24rpx; */
  367. display: flex;
  368. flex-direction: column;
  369. justify-content: space-between;
  370. min-width: 0;
  371. }
  372. .course-meta {
  373. display: flex;
  374. align-items: center;
  375. image {
  376. width: 30rpx;
  377. height: 30rpx;
  378. }
  379. }
  380. .meta-icon {
  381. font-size: 24rpx;
  382. margin-right: 6rpx;
  383. color: #999;
  384. }
  385. .meta-count {
  386. margin-left: 10rpx;
  387. font-family: PingFangSC, PingFang SC;
  388. font-weight: 400;
  389. font-size: 32rpx;
  390. color: #666666;
  391. }
  392. .card-cover {
  393. position: relative;
  394. width: 296rpx;
  395. height: 222rpx;
  396. border-radius: 20rpx;
  397. overflow: hidden;
  398. flex-shrink: 0;
  399. }
  400. .cover-img {
  401. width: 100%;
  402. height: 100%;
  403. background: #BB6D6D;
  404. }
  405. .card-title {
  406. font-family: PingFangSC, PingFang SC;
  407. font-weight: 600;
  408. font-size: 36rpx;
  409. color: #222222;
  410. line-height: 50rpx;
  411. text-align: justify;
  412. overflow: hidden;
  413. text-overflow: ellipsis;
  414. display: -webkit-box;
  415. -webkit-line-clamp: 2;
  416. -webkit-box-orient: vertical;
  417. }
  418. .card-footer {
  419. flex: 1;
  420. padding-left: 24rpx;
  421. /* padding: 20rpx 24rpx; */
  422. display: flex;
  423. flex-direction: column;
  424. justify-content: space-between;
  425. min-width: 0;
  426. }
  427. .card-views {
  428. font-family: PingFangSC, PingFang SC;
  429. font-weight: 400;
  430. font-size: 32rpx;
  431. color: #666666;
  432. line-height: 44rpx;
  433. }
  434. .btn-watch {
  435. width: 168rpx;
  436. height: 64rpx;
  437. line-height: 60rpx;
  438. text-align: center;
  439. background: linear-gradient(135deg, #FF5267 0%, #FF233C 100%);
  440. border-radius: 32rpx;
  441. font-family: PingFangSC, PingFang SC;
  442. font-weight: 600;
  443. font-size: 32rpx;
  444. color: #FFFFFF;
  445. }
  446. /* 最近学习 - 按日期分组 */
  447. .recent-group {
  448. padding: 24rpx 24rpx 0;
  449. }
  450. .group-date {
  451. display: flex;
  452. align-items: center;
  453. margin-bottom: 24rpx;
  454. }
  455. .date-icon {
  456. width: 32rpx;
  457. height: 32rpx;
  458. margin-right: 8rpx;
  459. }
  460. .date-text {
  461. font-family: PingFangSC, PingFang SC;
  462. font-weight: 600;
  463. font-size: 40rpx;
  464. line-height: 56rpx;
  465. color: #222222;
  466. }
  467. .recent-card {
  468. display: flex;
  469. background: #fff;
  470. border-radius: 20rpx;
  471. overflow: hidden;
  472. padding: 20rpx;
  473. margin-bottom: 24rpx;
  474. }
  475. .recent-card:last-child {
  476. margin-bottom: 0;
  477. }
  478. .recent-thumb {
  479. position: relative;
  480. width: 296rpx;
  481. height: 222rpx;
  482. border-radius: 20rpx;
  483. overflow: hidden;
  484. flex-shrink: 0;
  485. }
  486. .thumb-img {
  487. width: 100%;
  488. height: 100%;
  489. background: #BB6D6D;
  490. }
  491. .recent-info {
  492. flex: 1;
  493. padding-left: 24rpx;
  494. /* padding: 20rpx 24rpx; */
  495. display: flex;
  496. flex-direction: column;
  497. justify-content: space-between;
  498. min-width: 0;
  499. }
  500. .recent-title {
  501. font-family: PingFangSC, PingFang SC;
  502. font-weight: 600;
  503. font-size: 36rpx;
  504. color: #222222;
  505. line-height: 50rpx;
  506. text-align: justify;
  507. overflow: hidden;
  508. text-overflow: ellipsis;
  509. display: -webkit-box;
  510. -webkit-line-clamp: 2;
  511. -webkit-box-orient: vertical;
  512. }
  513. .recent-progress {
  514. font-family: PingFangSC, PingFang SC;
  515. font-weight: 400;
  516. font-size: 32rpx;
  517. color: rgba(0, 0, 0, 0.65);
  518. line-height: 44rpx;
  519. }
  520. /* 空态 */
  521. .empty-state {
  522. display: flex;
  523. flex-direction: column;
  524. align-items: center;
  525. justify-content: center;
  526. padding: 80rpx 0 48rpx;
  527. /* background: linear-gradient(180deg, #fff5f5 0%, #fff 100%); */
  528. }
  529. .empty-icon {
  530. width: 310rpx;
  531. height: 260rpx;
  532. margin-bottom: 30rpx;
  533. }
  534. .empty-text {
  535. font-family: PingFangSC, PingFang SC;
  536. font-weight: 400;
  537. font-size: 36rpx;
  538. color: rgba(0, 0, 0, 0.25);
  539. line-height: 50rpx;
  540. }
  541. /* 为您精选 */
  542. .recommend-section {
  543. padding: 0 24rpx 32rpx;
  544. }
  545. .recommend-title {
  546. display: block;
  547. font-family: PingFangSC, PingFang SC;
  548. font-weight: 600;
  549. font-size: 40rpx;
  550. color: #222222;
  551. line-height: 56rpx;
  552. padding-bottom: 24rpx;
  553. }
  554. .bottom-placeholder {
  555. height: 120rpx;
  556. }
  557. </style>