courseSearch.vue 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637
  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" src="https://bjzmky-1323137866.cos.ap-chongqing.myqcloud.com/class/search.png" mode=""></image>
  8. <input type="text" v-model="keyword" @input="clearInput" placeholder="请输入关键字搜索内容" placeholder-style="font-size:28rpx;color:#BBBBBB;"/>
  9. <view class="close-circle" v-if="showClearIcon" @click="clearIcon">
  10. <u-icon name="close-circle" color="#999" size="22" ></u-icon>
  11. </view>
  12. </view>
  13. <view class="sousuo" @click="goSearch">搜索</view>
  14. </view>
  15. <!-- <view class="nav-row">
  16. <view class="nav-all" :class="{ active: activeId === 'all'}" @tap.stop="onSelectAll" @click.stop="onSelectAll">
  17. <text>全部</text>
  18. </view>
  19. <scroll-view scroll-x class="nav-scroll" :show-scrollbar="false">
  20. <view class="nav-inner">
  21. <view
  22. v-for="(item, index) in navList"
  23. :key="index"
  24. :class="['nav-item', { active: item.id === activeId }]"
  25. @tap.stop="onSelectByIndex(index)"
  26. @click.stop="onSelectByIndex(index)"
  27. >
  28. <text>{{ item.categoryName}}</text>
  29. </view>
  30. </view>
  31. </scroll-view>
  32. </view> -->
  33. </view>
  34. <!-- 最近学习 内容 -->
  35. <scroll-view scroll-y class="scroll-wrap" :show-scrollbar="false">
  36. <!-- 有学习记录:按日期分组列表 -->
  37. <template v-if="isSearch">
  38. <view class="course-grid">
  39. <view
  40. v-for="(course, idx) in courseList"
  41. :key="idx"
  42. class="course-card"
  43. @click="onCourseClick(course)"
  44. >
  45. <view class="card-cover">
  46. <image :src="course.cover" mode="aspectFill" class="cover-img"></image>
  47. </view>
  48. <view class="course-info">
  49. <text class="card-title">{{ course.title }}</text>
  50. <view class="x-end" style="justify-content: space-between;">
  51. <view class="course-meta">
  52. <image src="https://bjzmky-1323137866.cos.ap-chongqing.myqcloud.com/class/renshu.png"></image>
  53. <text class="meta-count">{{ courseViewsDisplay(course.views)}}</text>
  54. </view>
  55. <view class="btn-watch" @click.stop="onCourseClick(course)">立即观看</view>
  56. </view>
  57. </view>
  58. </view>
  59. </view>
  60. </template>
  61. <!-- 无学习记录:空态 + 为您精选 -->
  62. <template v-else>
  63. <view class="recommend-section">
  64. <text class="recommend-title">大家都在学习</text>
  65. <view class="course-grid" style="padding: 0;">
  66. <view
  67. v-for="(course, idx) in recommendList"
  68. :key="idx"
  69. class="course-card"
  70. @click="onCourseClick(course)"
  71. >
  72. <view class="card-cover">
  73. <image :src="course.cover || '/static/logo.jpg'" mode="aspectFill" class="cover-img"></image>
  74. </view>
  75. <view class="card-footer">
  76. <text class="card-title">{{ course.title }}</text>
  77. <view class="x-end" style="justify-content: space-between;">
  78. <view class="course-meta">
  79. <image src="https://bjzmky-1323137866.cos.ap-chongqing.myqcloud.com/class/renshu.png"></image>
  80. <text class="meta-count">{{ courseViewsDisplay(course.views) }}</text>
  81. </view>
  82. <view class="btn-watch" @click.stop="onCourseClick(course)">立即观看</view>
  83. </view>
  84. </view>
  85. </view>
  86. </view>
  87. </view>
  88. </template>
  89. <template v-if="keyword&&courseList.length==0">
  90. <view class="empty-state">
  91. <!-- <view class="empty-icon"></view> -->
  92. <image class="empty-icon" src="https://bjzmky-1323137866.cos.ap-chongqing.myqcloud.com/class/nodata.png"></image>
  93. <text class="empty-text">没有搜索任何内容,换个词试试</text>
  94. </view>
  95. </template>
  96. <view class="bottom-placeholder"></view>
  97. </scroll-view>
  98. </view>
  99. </template>
  100. <script>
  101. import { listPublicCourse } from '@/api/home.js'
  102. export default {
  103. data() {
  104. return {
  105. statusBarHeight: uni.getSystemInfoSync().statusBarHeight + 'px',
  106. keyword: '',
  107. tabIndex: 0,
  108. activeId:'all',
  109. categoryExpand: true,
  110. isSearch:false,
  111. showClearIcon: false,
  112. categoryIndex: 0,
  113. categories: ['全部', '歌唱艺术', '太极养生', '防骗指南', '手机摄影', '棋牌益智', '用药指导', '膳食营养', '慢病管理'],
  114. courseList: [],
  115. recentList: [
  116. // {
  117. // date: '2026-02-08',
  118. // list: [
  119. // { title: '歌唱家刘金的《0基础金曲演唱速练课》', progress: 87, cover: '' },
  120. // { title: '资深编辑邹方斌讲《毛笔书法修心课》', progress: 56, cover: '' }
  121. // ]
  122. // },
  123. // {
  124. // date: '2026-02-01',
  125. // list: [
  126. // { title: '张斌《元气八段锦》系列课', progress: 56, cover: '' }
  127. // ]
  128. // }
  129. ],
  130. navList:[
  131. // {id: 37,categoryName: "健康食品"},
  132. // {id: 35,categoryName: "绿色有机"}
  133. ],
  134. recommendList: [
  135. // { title: '刘金的《0基础金曲演唱速练课》', views: '9239', cover: '' },
  136. // { title: '邹方斌讲《毛笔书法修心课》', views: '10.8w', cover: '' },
  137. // { title: '张斌《元气八段锦》系列课', views: '2.5w', cover: '' },
  138. // { title: '翔哥精讲摄影课-手机微距拍摄技巧...', views: '100w+', cover: '' }
  139. ]
  140. }
  141. },
  142. onLoad(options) {
  143. // this.keyword = (options && options.keyword) || ''
  144. this.getCourseList()
  145. this.getNewCourseList()
  146. },
  147. methods: {
  148. courseViewsDisplay(views) {
  149. const raw = views;
  150. const n = Number(raw);
  151. if (!Number.isFinite(n) || n < 0) {
  152. return "0";
  153. }
  154. if (n < 100000) {
  155. return String(Math.floor(n));
  156. }
  157. if (n < 1000000) {
  158. return (n / 10000).toFixed(1) + "w";
  159. }
  160. return "100w+";
  161. },
  162. onSelectAll() {
  163. this.$emit('select', { id: 'all', categoryName: '全部' });
  164. },
  165. clearInput: function(event) {
  166. this.keyword = event.detail.value;
  167. if (event.detail.value.length > 0) {
  168. this.showClearIcon = true;
  169. } else {
  170. this.showClearIcon = false;
  171. }
  172. },
  173. clearIcon: function() {
  174. this.keyword = '';
  175. this.showClearIcon = false;
  176. this.isSearch=false;
  177. },
  178. async getCourseList(keyword) {
  179. try {
  180. const params = { pageNum: 1, pageSize: 10 }
  181. if (keyword) {
  182. params.keyword = keyword
  183. }
  184. const res = await listPublicCourse(params)
  185. const list = (res && res.data && res.data.list) || []
  186. this.courseList = list.map(item => ({
  187. courseId: item.courseId,
  188. title: item.courseTitle || item.courseName || '',
  189. views: item.watchUserCount || 0,
  190. cover: item.imgUrl || ''
  191. }))
  192. } catch (e) {
  193. this.courseList = []
  194. }
  195. },
  196. async getNewCourseList() {
  197. try {
  198. const params = { pageNum: 1, pageSize: 6 }
  199. const res = await listPublicCourse(params)
  200. const list = (res && res.data && res.data.list) || []
  201. this.recommendList = list.map(item => ({
  202. courseId: item.courseId,
  203. title: item.courseTitle || item.courseName || '',
  204. views: item.watchUserCount || 0,
  205. cover: item.imgUrl || ''
  206. }))
  207. } catch (e) {
  208. this.recommendList = []
  209. }
  210. },
  211. goSearch() {
  212. this.isSearch=!this.isSearch
  213. if (!this.keyword.trim()) {
  214. uni.showToast({
  215. icon: 'none',
  216. title: '请输入搜索内容'
  217. });
  218. return;
  219. }
  220. this.getCourseList(this.keyword)
  221. },
  222. onCourseClick(course) {
  223. if (course && course.courseId) {
  224. uni.navigateTo({ url: '/pages_index/courseDetail?courseId=' + course.courseId + '&type=1' })
  225. return
  226. }
  227. }
  228. }
  229. }
  230. </script>
  231. <style lang="scss" scoped>
  232. /* 图片箭头旋转类(展开时向上) */
  233. .rotate-arrow {
  234. transform: rotate(180deg);
  235. }
  236. .container {
  237. min-height: 100vh;
  238. background: #F5F5F5;
  239. display: flex;
  240. flex-direction: column;
  241. }
  242. /* 顶部 Tab */
  243. .top-nav {
  244. display: flex;
  245. flex-direction: column;
  246. background: #fff;
  247. /* border-bottom: 1rpx solid #f0f0f0; */
  248. }
  249. .search-cont{
  250. padding: 24rpx 24rpx 20rpx;
  251. background-color: #FFFFFF;
  252. display:flex;
  253. align-items: center;
  254. justify-content: space-between;
  255. .inner{
  256. box-sizing: border-box;
  257. flex:1;
  258. // width: 100%;
  259. height: 76rpx;
  260. background: #F7F7F7;
  261. border-radius: 38rpx;
  262. display: flex;
  263. align-items: center;
  264. padding-left:20rpx;
  265. margin-right: 24rpx;
  266. .icon-search{
  267. width: 44rpx;
  268. height: 44rpx;
  269. margin-right: 12rpx;
  270. }
  271. input{
  272. height: 76rpx;
  273. line-height: 76rpx;
  274. flex: 1;
  275. font-family: PingFangSC, PingFang SC;
  276. font-weight: 400;
  277. font-size: 32rpx;
  278. }
  279. .close-circle{
  280. position: relative;
  281. z-index:999;
  282. padding:0 20rpx;
  283. }
  284. }
  285. .sousuo{
  286. font-family: PingFangSC, PingFang SC;
  287. font-weight: 400;
  288. font-size: 36rpx;
  289. color: #222222;
  290. line-height: 50rpx;
  291. }
  292. }
  293. .nav-row {
  294. display: flex;
  295. align-items: center;
  296. padding: 0 24rpx 24rpx;
  297. gap: 30rpx;
  298. }
  299. .nav-all {
  300. flex-shrink: 0;
  301. font-family: PingFangSC, PingFang SC;
  302. font-weight: 400;
  303. font-size: 40rpx;
  304. color: rgba(0,0,0,0.85);
  305. line-height: 56rpx;
  306. }
  307. .nav-all.active {
  308. color: #FF233C;
  309. font-weight: 600;
  310. }
  311. .nav-scroll {
  312. flex: 1;
  313. }
  314. .nav-inner {
  315. display: inline-flex;
  316. padding:0;
  317. gap: 30rpx;
  318. }
  319. .nav-item {
  320. flex-shrink: 0;
  321. font-family: PingFangSC, PingFang SC;
  322. font-weight: 400;
  323. font-size: 40rpx;
  324. color: rgba(0,0,0,0.85);
  325. line-height: 56rpx;
  326. }
  327. .nav-item.active {
  328. color: #FF233C;
  329. font-weight: 600;
  330. }
  331. /* 滚动区 */
  332. .scroll-wrap {
  333. flex: 1;
  334. height: 0;
  335. }
  336. /* 分类标签 */
  337. .category-wrap {
  338. padding:24rpx 0;
  339. border-radius: 0rpx 0rpx 20rpx 20rpx;
  340. background: #fff;
  341. display: flex;
  342. align-items: center;
  343. flex-direction: column;
  344. }
  345. .category-tags {
  346. display: flex;
  347. flex-wrap: wrap;
  348. gap:24rpx;
  349. flex-direction: row;
  350. justify-content: center;
  351. }
  352. .category-tags.collapsed {
  353. max-height: 88rpx;
  354. overflow: hidden;
  355. }
  356. .tag-item {
  357. width: 30%;
  358. padding: 20rpx 0;
  359. text-align: center;
  360. border-radius: 20rpx;
  361. background: #f0f0f0;
  362. }
  363. .tag-item text {
  364. font-family: PingFangSC, PingFang SC;
  365. font-weight: 400;
  366. font-size: 40rpx;
  367. color: rgba(0,0,0,0.85);
  368. }
  369. .tag-item.active {
  370. background: linear-gradient( 135deg, #FF5267 0%, #FF233C 100%);
  371. }
  372. .tag-item.active text {
  373. color: #fff;
  374. }
  375. .expand-btn {
  376. display: flex;
  377. align-items: center;
  378. justify-content: center;
  379. margin-top: 20rpx;
  380. width: 166rpx;
  381. height: 64rpx;
  382. border-radius: 32rpx;
  383. border: 2rpx solid #FF233C;
  384. }
  385. .expand-btn text {
  386. font-family: PingFangSC, PingFang SC;
  387. font-weight: 400;
  388. font-size: 32rpx;
  389. color: #FF233C;
  390. }
  391. .expand-btn .arrow {
  392. margin-left: 6rpx;
  393. font-size: 22rpx;
  394. }
  395. .expand-btn image{
  396. margin-left:10rpx ;
  397. width: 32rpx;
  398. height: 32rpx;
  399. }
  400. /* 课程网格 */
  401. .course-grid {
  402. display: flex;
  403. flex-wrap: wrap;
  404. padding:24rpx;
  405. gap: 24rpx 20rpx;
  406. flex-direction: column;
  407. }
  408. .course-card {
  409. display: flex;
  410. background: #fff;
  411. border-radius: 20rpx;
  412. overflow: hidden;
  413. padding: 20rpx;
  414. }
  415. .course-tag {
  416. position: absolute;
  417. left: 0;
  418. bottom: 0;
  419. right: 0;
  420. padding: 8rpx 12rpx;
  421. background: linear-gradient(transparent, rgba(0,0,0,0.6));
  422. font-size: 22rpx;
  423. color: #fff;
  424. }
  425. .course-info {
  426. flex: 1;
  427. padding-left: 24rpx;
  428. /* padding: 20rpx 24rpx; */
  429. display: flex;
  430. flex-direction: column;
  431. justify-content: space-between;
  432. min-width: 0;
  433. }
  434. .course-meta {
  435. display: flex;
  436. align-items: center;
  437. image{
  438. width: 30rpx;
  439. height: 30rpx;
  440. }
  441. }
  442. .meta-icon {
  443. font-size: 24rpx;
  444. margin-right: 6rpx;
  445. color: #999;
  446. }
  447. .meta-count {
  448. margin-left: 10rpx;
  449. font-family: PingFangSC, PingFang SC;
  450. font-weight: 400;
  451. font-size: 32rpx;
  452. color: #666666;
  453. }
  454. .card-cover {
  455. position: relative;
  456. width: 296rpx;
  457. height: 222rpx;
  458. border-radius: 20rpx;
  459. overflow: hidden;
  460. flex-shrink: 0;
  461. }
  462. .cover-img {
  463. width: 100%;
  464. height: 100%;
  465. background: #BB6D6D;
  466. }
  467. .card-title {
  468. font-family: PingFangSC, PingFang SC;
  469. font-weight: 600;
  470. font-size: 36rpx;
  471. color: #222222;
  472. line-height: 50rpx;
  473. text-align: justify;
  474. overflow: hidden;
  475. text-overflow: ellipsis;
  476. display: -webkit-box;
  477. -webkit-line-clamp: 2;
  478. -webkit-box-orient: vertical;
  479. }
  480. .card-footer {
  481. flex: 1;
  482. padding-left: 24rpx;
  483. /* padding: 20rpx 24rpx; */
  484. display: flex;
  485. flex-direction: column;
  486. justify-content: space-between;
  487. min-width: 0;
  488. }
  489. .card-views {
  490. font-family: PingFangSC, PingFang SC;
  491. font-weight: 400;
  492. font-size: 32rpx;
  493. color: #666666;
  494. line-height: 44rpx;
  495. }
  496. .btn-watch {
  497. width: 168rpx;
  498. height: 64rpx;
  499. line-height: 64rpx;
  500. text-align: center;
  501. background: linear-gradient( 135deg, #FF5267 0%, #FF233C 100%);
  502. border-radius: 32rpx;
  503. font-family: PingFangSC, PingFang SC;
  504. font-weight: 600;
  505. font-size: 32rpx;
  506. color: #FFFFFF;
  507. }
  508. /* 最近学习 - 按日期分组 */
  509. .recent-group {
  510. padding: 24rpx 24rpx 0;
  511. }
  512. .group-date {
  513. display: flex;
  514. align-items: center;
  515. margin-bottom: 24rpx;
  516. }
  517. .date-icon {
  518. width: 32rpx;
  519. height: 32rpx;
  520. margin-right: 8rpx;
  521. }
  522. .date-text {
  523. font-family: PingFangSC, PingFang SC;
  524. font-weight: 600;
  525. font-size: 40rpx;
  526. line-height: 56rpx;
  527. color: #222222;
  528. }
  529. .recent-card {
  530. display: flex;
  531. background: #fff;
  532. border-radius: 20rpx;
  533. overflow: hidden;
  534. padding: 20rpx;
  535. margin-bottom: 24rpx;
  536. }
  537. .recent-card:last-child{
  538. margin-bottom: 0;
  539. }
  540. .recent-thumb {
  541. position: relative;
  542. width: 296rpx;
  543. height: 222rpx;
  544. border-radius: 20rpx;
  545. overflow: hidden;
  546. flex-shrink: 0;
  547. }
  548. .thumb-img {
  549. width: 100%;
  550. height: 100%;
  551. background: #BB6D6D;
  552. }
  553. .recent-info {
  554. flex: 1;
  555. padding-left: 24rpx;
  556. /* padding: 20rpx 24rpx; */
  557. display: flex;
  558. flex-direction: column;
  559. justify-content: space-between;
  560. min-width: 0;
  561. }
  562. .recent-title {
  563. font-family: PingFangSC, PingFang SC;
  564. font-weight: 600;
  565. font-size: 36rpx;
  566. color: #222222;
  567. line-height: 50rpx;
  568. text-align: justify;
  569. overflow: hidden;
  570. text-overflow: ellipsis;
  571. display: -webkit-box;
  572. -webkit-line-clamp: 2;
  573. -webkit-box-orient: vertical;
  574. }
  575. .recent-progress {
  576. font-family: PingFangSC, PingFang SC;
  577. font-weight: 400;
  578. font-size: 32rpx;
  579. color: rgba(0,0,0,0.65);
  580. line-height: 44rpx;
  581. }
  582. /* 空态 */
  583. .empty-state {
  584. display: flex;
  585. flex-direction: column;
  586. align-items: center;
  587. justify-content: center;
  588. padding: 80rpx 0 48rpx;
  589. /* background: linear-gradient(180deg, #fff5f5 0%, #fff 100%); */
  590. }
  591. .empty-icon {
  592. width: 310rpx;
  593. height: 260rpx;
  594. margin-bottom: 30rpx;
  595. }
  596. .empty-text {
  597. font-family: PingFangSC, PingFang SC;
  598. font-weight: 400;
  599. font-size: 36rpx;
  600. color: rgba(0,0,0,0.25);
  601. line-height: 50rpx;
  602. }
  603. /* 为您精选 */
  604. .recommend-section {
  605. margin-top: 300rpx;
  606. padding: 0 24rpx 32rpx;
  607. }
  608. .recommend-title {
  609. display: block;
  610. font-family: PingFangSC, PingFang SC;
  611. font-weight: 600;
  612. font-size: 40rpx;
  613. color: #222222;
  614. line-height: 56rpx;
  615. padding-bottom: 24rpx;
  616. }
  617. .bottom-placeholder {
  618. height: 120rpx;
  619. }
  620. </style>