feat(test): 新增活动列表和课程列表测试页面
- 新增活动列表测试页面 (ActivityListTestPage.vue) - 新增课程列表测试页面 (CourseListTestPage.vue) - 配置测试路由:/test/activity-list 和 /test/course-list - 更新 CHANGELOG.md 记录变更 - 修复 ESLint 配置:添加 vue-eslint-parser 以正确解析 .vue 文件 Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Showing
8 changed files
with
390 additions
and
10 deletions
| ... | @@ -3,6 +3,11 @@ | ... | @@ -3,6 +3,11 @@ |
| 3 | 说明:该章节从 README 迁移到本文件,避免 README 过长。后续新增变更建议追加在文件顶部。 | 3 | 说明:该章节从 README 迁移到本文件,避免 README 过长。后续新增变更建议追加在文件顶部。 |
| 4 | 4 | ||
| 5 | 5 | ||
| 6 | +## 2026-01-29 15:30:00 | ||
| 7 | +- 新增活动列表测试页面:[/src/views/test/ActivityListTestPage.vue](file:///Users/huyirui/program/itomix/git/mlaj/src/views/test/ActivityListTestPage.vue) | ||
| 8 | + - 实现高保真 UI 还原(导航栏、筛选栏、活动列表卡片) | ||
| 9 | + - 配置测试路由:`/test/activity-list` | ||
| 10 | + | ||
| 6 | ## 2026-01-26 13:40:00 | 11 | ## 2026-01-26 13:40:00 |
| 7 | - 优化打卡卡片组件(CheckinCard): | 12 | - 优化打卡卡片组件(CheckinCard): |
| 8 | - 增加长文本折叠功能:内容超过5行自动显示省略号,并提供“全文/收起”切换按钮 | 13 | - 增加长文本折叠功能:内容超过5行自动显示省略号,并提供“全文/收起”切换按钮 | ... | ... |
| ... | @@ -4,6 +4,7 @@ | ... | @@ -4,6 +4,7 @@ |
| 4 | */ | 4 | */ |
| 5 | import vue from 'eslint-plugin-vue' | 5 | import vue from 'eslint-plugin-vue' |
| 6 | import prettier from 'eslint-config-prettier' | 6 | import prettier from 'eslint-config-prettier' |
| 7 | +import vueParser from 'vue-eslint-parser' | ||
| 7 | 8 | ||
| 8 | export default [ | 9 | export default [ |
| 9 | { | 10 | { |
| ... | @@ -32,6 +33,14 @@ export default [ | ... | @@ -32,6 +33,14 @@ export default [ |
| 32 | languageOptions: { | 33 | languageOptions: { |
| 33 | ecmaVersion: 'latest', | 34 | ecmaVersion: 'latest', |
| 34 | sourceType: 'module', | 35 | sourceType: 'module', |
| 36 | + parser: vueParser, | ||
| 37 | + parserOptions: { | ||
| 38 | + ecmaVersion: 'latest', | ||
| 39 | + sourceType: 'module', | ||
| 40 | + ecmaFeatures: { | ||
| 41 | + jsx: true, | ||
| 42 | + }, | ||
| 43 | + }, | ||
| 35 | globals: { | 44 | globals: { |
| 36 | // 浏览器环境 | 45 | // 浏览器环境 |
| 37 | window: 'readonly', | 46 | window: 'readonly', | ... | ... |
| ... | @@ -104,6 +104,7 @@ | ... | @@ -104,6 +104,7 @@ |
| 104 | "unplugin-auto-import": "^19.1.1", | 104 | "unplugin-auto-import": "^19.1.1", |
| 105 | "unplugin-vue-components": "^28.4.1", | 105 | "unplugin-vue-components": "^28.4.1", |
| 106 | "vite": "^6.2.0", | 106 | "vite": "^6.2.0", |
| 107 | - "vitest": "^3.2.0" | 107 | + "vitest": "^3.2.0", |
| 108 | + "vue-eslint-parser": "^10.2.0" | ||
| 108 | } | 109 | } |
| 109 | } | 110 | } | ... | ... |
| ... | @@ -177,6 +177,9 @@ importers: | ... | @@ -177,6 +177,9 @@ importers: |
| 177 | vitest: | 177 | vitest: |
| 178 | specifier: ^3.2.0 | 178 | specifier: ^3.2.0 |
| 179 | version: 3.2.4(@types/node@20.19.25)(jiti@1.21.7)(jsdom@24.1.3(canvas@2.11.2))(less@4.4.2)(yaml@2.8.2) | 179 | version: 3.2.4(@types/node@20.19.25)(jiti@1.21.7)(jsdom@24.1.3(canvas@2.11.2))(less@4.4.2)(yaml@2.8.2) |
| 180 | + vue-eslint-parser: | ||
| 181 | + specifier: ^10.2.0 | ||
| 182 | + version: 10.2.0(eslint@9.39.2(jiti@1.21.7)) | ||
| 180 | 183 | ||
| 181 | packages: | 184 | packages: |
| 182 | 185 | ... | ... |
| ... | @@ -94,6 +94,8 @@ declare module 'vue' { | ... | @@ -94,6 +94,8 @@ declare module 'vue' { |
| 94 | VanSwipe: typeof import('vant/es')['Swipe'] | 94 | VanSwipe: typeof import('vant/es')['Swipe'] |
| 95 | VanSwipeItem: typeof import('vant/es')['SwipeItem'] | 95 | VanSwipeItem: typeof import('vant/es')['SwipeItem'] |
| 96 | VanTab: typeof import('vant/es')['Tab'] | 96 | VanTab: typeof import('vant/es')['Tab'] |
| 97 | + VanTabbar: typeof import('vant/es')['Tabbar'] | ||
| 98 | + VanTabbarItem: typeof import('vant/es')['TabbarItem'] | ||
| 97 | VanTabs: typeof import('vant/es')['Tabs'] | 99 | VanTabs: typeof import('vant/es')['Tabs'] |
| 98 | VanTag: typeof import('vant/es')['Tag'] | 100 | VanTag: typeof import('vant/es')['Tag'] |
| 99 | VanTimePicker: typeof import('vant/es')['TimePicker'] | 101 | VanTimePicker: typeof import('vant/es')['TimePicker'] | ... | ... |
| 1 | /* | 1 | /* |
| 2 | * @Date: 2025-03-20 20:36:36 | 2 | * @Date: 2025-03-20 20:36:36 |
| 3 | * @LastEditors: hookehuyr hookehuyr@gmail.com | 3 | * @LastEditors: hookehuyr hookehuyr@gmail.com |
| 4 | - * @LastEditTime: 2026-01-20 10:23:54 | 4 | + * @LastEditTime: 2026-01-29 00:08:03 |
| 5 | * @FilePath: /mlaj/src/router/routes.js | 5 | * @FilePath: /mlaj/src/router/routes.js |
| 6 | * @Description: 路由地址映射配置 | 6 | * @Description: 路由地址映射配置 |
| 7 | */ | 7 | */ |
| ... | @@ -16,8 +16,8 @@ export const routes = [ | ... | @@ -16,8 +16,8 @@ export const routes = [ |
| 16 | meta: { | 16 | meta: { |
| 17 | title: '欢迎页', | 17 | title: '欢迎页', |
| 18 | requiresAuth: false, | 18 | requiresAuth: false, |
| 19 | - hideInMenu: true | 19 | + hideInMenu: true, |
| 20 | - } | 20 | + }, |
| 21 | }, | 21 | }, |
| 22 | { | 22 | { |
| 23 | path: '/', | 23 | path: '/', |
| ... | @@ -264,6 +264,18 @@ export const routes = [ | ... | @@ -264,6 +264,18 @@ export const routes = [ |
| 264 | meta: { title: 'test' }, | 264 | meta: { title: 'test' }, |
| 265 | }, | 265 | }, |
| 266 | { | 266 | { |
| 267 | + path: '/test/course-list', | ||
| 268 | + name: 'CourseListTest', | ||
| 269 | + component: () => import('../views/test/CourseListTestPage.vue'), | ||
| 270 | + meta: { title: '课程列表测试' }, | ||
| 271 | + }, | ||
| 272 | + { | ||
| 273 | + path: '/test/activity-list', | ||
| 274 | + name: 'ActivityListTest', | ||
| 275 | + component: () => import('../views/test/ActivityListTestPage.vue'), | ||
| 276 | + meta: { title: '活动列表测试' }, | ||
| 277 | + }, | ||
| 278 | + { | ||
| 267 | path: '/test/icon', | 279 | path: '/test/icon', |
| 268 | name: 'IconTest', | 280 | name: 'IconTest', |
| 269 | component: () => import('../views/IconTestPage.vue'), | 281 | component: () => import('../views/IconTestPage.vue'), |
| ... | @@ -280,19 +292,20 @@ export const routes = [ | ... | @@ -280,19 +292,20 @@ export const routes = [ |
| 280 | name: 'upload_video', | 292 | name: 'upload_video', |
| 281 | component: () => import('../views/upload_video.vue'), | 293 | component: () => import('../views/upload_video.vue'), |
| 282 | meta: { title: 'upload_video' }, | 294 | meta: { title: 'upload_video' }, |
| 283 | - }, { | 295 | + }, |
| 296 | + { | ||
| 284 | path: '/auth', | 297 | path: '/auth', |
| 285 | component: () => import('@/views/auth.vue'), | 298 | component: () => import('@/views/auth.vue'), |
| 286 | meta: { | 299 | meta: { |
| 287 | title: '微信授权页面', | 300 | title: '微信授权页面', |
| 288 | - } | 301 | + }, |
| 289 | }, | 302 | }, |
| 290 | { | 303 | { |
| 291 | path: '/study', | 304 | path: '/study', |
| 292 | component: () => import('@/views/study/studyPage.vue'), | 305 | component: () => import('@/views/study/studyPage.vue'), |
| 293 | meta: { | 306 | meta: { |
| 294 | title: '学习页面', | 307 | title: '学习页面', |
| 295 | - } | 308 | + }, |
| 296 | }, | 309 | }, |
| 297 | { | 310 | { |
| 298 | path: '/studyDetail/:id', | 311 | path: '/studyDetail/:id', |
| ... | @@ -300,7 +313,7 @@ export const routes = [ | ... | @@ -300,7 +313,7 @@ export const routes = [ |
| 300 | meta: { | 313 | meta: { |
| 301 | title: '学习详情页面', | 314 | title: '学习详情页面', |
| 302 | requiresAuth: true, | 315 | requiresAuth: true, |
| 303 | - } | 316 | + }, |
| 304 | }, | 317 | }, |
| 305 | { | 318 | { |
| 306 | path: '/pdfPreview', | 319 | path: '/pdfPreview', |
| ... | @@ -308,14 +321,14 @@ export const routes = [ | ... | @@ -308,14 +321,14 @@ export const routes = [ |
| 308 | component: () => import('@/views/study/PdfPreviewPage.vue'), | 321 | component: () => import('@/views/study/PdfPreviewPage.vue'), |
| 309 | meta: { | 322 | meta: { |
| 310 | title: 'PDF预览', | 323 | title: 'PDF预览', |
| 311 | - } | 324 | + }, |
| 312 | }, | 325 | }, |
| 313 | { | 326 | { |
| 314 | path: '/profile/studyCourse/:id', | 327 | path: '/profile/studyCourse/:id', |
| 315 | component: () => import('@/views/profile/StudyCoursePage.vue'), | 328 | component: () => import('@/views/profile/StudyCoursePage.vue'), |
| 316 | meta: { | 329 | meta: { |
| 317 | title: '课程集合页面', | 330 | title: '课程集合页面', |
| 318 | - } | 331 | + }, |
| 319 | }, | 332 | }, |
| 320 | ...checkinRoutes, | 333 | ...checkinRoutes, |
| 321 | ...teacherRoutes, | 334 | ...teacherRoutes, | ... | ... |
src/views/test/ActivityListTestPage.vue
0 → 100644
| 1 | +<template> | ||
| 2 | + <div class="pb-safe min-h-screen bg-gray-50"> | ||
| 3 | + <!-- 顶部导航栏 --> | ||
| 4 | + <van-nav-bar fixed placeholder z-index="50" class="nav-bar"> | ||
| 5 | + <template #left> | ||
| 6 | + <van-icon name="arrow-left" size="22" color="#333" /> | ||
| 7 | + </template> | ||
| 8 | + <template #title> | ||
| 9 | + <span class="text-lg font-medium text-gray-800">最新活动</span> | ||
| 10 | + </template> | ||
| 11 | + <template #right> | ||
| 12 | + <van-icon name="ellipsis" size="22" color="#333" /> | ||
| 13 | + </template> | ||
| 14 | + </van-nav-bar> | ||
| 15 | + | ||
| 16 | + <!-- 筛选栏 --> | ||
| 17 | + <div | ||
| 18 | + class="sticky top-[46px] z-40 flex items-center justify-between bg-white px-3 py-2 shadow-sm" | ||
| 19 | + > | ||
| 20 | + <div class="flex items-center gap-6"> | ||
| 21 | + <!-- 全部 --> | ||
| 22 | + <div class="relative text-[15px] font-bold text-gray-900"> | ||
| 23 | + 全部 | ||
| 24 | + <div | ||
| 25 | + class="absolute -bottom-2 left-1/2 h-[3px] w-4 -translate-x-1/2 rounded-full bg-gray-800" | ||
| 26 | + ></div> | ||
| 27 | + </div> | ||
| 28 | + | ||
| 29 | + <!-- 活动地点 --> | ||
| 30 | + <div class="flex items-center gap-1 text-[14px] text-gray-600"> | ||
| 31 | + <span>活动地点</span> | ||
| 32 | + <van-icon name="play" class="rotate-90 text-[10px] text-gray-400" /> | ||
| 33 | + </div> | ||
| 34 | + | ||
| 35 | + <!-- 活动状态 --> | ||
| 36 | + <div class="flex items-center gap-1 text-[14px] text-gray-600"> | ||
| 37 | + <span>活动状态</span> | ||
| 38 | + <van-icon name="play" class="rotate-90 text-[10px] text-gray-400" /> | ||
| 39 | + </div> | ||
| 40 | + </div> | ||
| 41 | + | ||
| 42 | + <!-- 筛选图标 --> | ||
| 43 | + <van-icon name="filter-o" size="18" color="#333" /> | ||
| 44 | + </div> | ||
| 45 | + | ||
| 46 | + <!-- 活动列表 --> | ||
| 47 | + <div class="space-y-3 p-3"> | ||
| 48 | + <div | ||
| 49 | + v-for="item in activityList" | ||
| 50 | + :key="item.id" | ||
| 51 | + class="flex gap-3 rounded-xl bg-white p-3 shadow-sm transition-transform active:scale-[0.99]" | ||
| 52 | + > | ||
| 53 | + <!-- 左侧封面图 --> | ||
| 54 | + <div | ||
| 55 | + class="relative h-[100px] w-[100px] flex-shrink-0 overflow-hidden rounded-lg bg-gray-100" | ||
| 56 | + > | ||
| 57 | + <img | ||
| 58 | + :src="getOptimizedImage(item.imageUrl)" | ||
| 59 | + :alt="item.title" | ||
| 60 | + class="h-full w-full object-cover" | ||
| 61 | + /> | ||
| 62 | + </div> | ||
| 63 | + | ||
| 64 | + <!-- 右侧内容 --> | ||
| 65 | + <div class="flex flex-1 flex-col justify-between py-0.5"> | ||
| 66 | + <!-- 标题 --> | ||
| 67 | + <h3 class="line-clamp-2 text-[15px] font-bold leading-snug text-gray-900"> | ||
| 68 | + {{ item.fullTitle }} | ||
| 69 | + </h3> | ||
| 70 | + | ||
| 71 | + <!-- 信息区域 --> | ||
| 72 | + <div class="space-y-1.5"> | ||
| 73 | + <!-- 地点与状态 --> | ||
| 74 | + <div class="flex items-center gap-2"> | ||
| 75 | + <span class="text-xs text-gray-500">地点: {{ item.location }}</span> | ||
| 76 | + <span | ||
| 77 | + class="rounded border px-1.5 py-0.5 text-[10px]" | ||
| 78 | + :class="getStatusStyle(item.status)" | ||
| 79 | + > | ||
| 80 | + {{ item.status }} | ||
| 81 | + </span> | ||
| 82 | + </div> | ||
| 83 | + | ||
| 84 | + <!-- 时间 --> | ||
| 85 | + <div class="text-xs text-gray-400">时间: {{ item.period }}</div> | ||
| 86 | + </div> | ||
| 87 | + </div> | ||
| 88 | + </div> | ||
| 89 | + </div> | ||
| 90 | + </div> | ||
| 91 | +</template> | ||
| 92 | + | ||
| 93 | +<script setup> | ||
| 94 | +import { ref, computed } from 'vue' | ||
| 95 | +import { activities } from '@/utils/mockData' | ||
| 96 | + | ||
| 97 | +/** | ||
| 98 | + * 处理图片链接,如果是指定CDN域名则添加压缩参数 | ||
| 99 | + * @param {string} url - 图片链接 | ||
| 100 | + * @returns {string} - 处理后的链接 | ||
| 101 | + */ | ||
| 102 | +const getOptimizedImage = url => { | ||
| 103 | + if (!url) return '' | ||
| 104 | + if (url.includes('cdn.ipadbiz.cn')) { | ||
| 105 | + // 检查是否已有参数 | ||
| 106 | + return url.includes('?') | ||
| 107 | + ? `${url}&imageMogr2/thumbnail/200x/strip/quality/70` | ||
| 108 | + : `${url}?imageMogr2/thumbnail/200x/strip/quality/70` | ||
| 109 | + } | ||
| 110 | + return url | ||
| 111 | +} | ||
| 112 | + | ||
| 113 | +// 处理活动数据,拼接标题 | ||
| 114 | +const activityList = computed(() => | ||
| 115 | + activities.map(item => ({ | ||
| 116 | + ...item, | ||
| 117 | + fullTitle: item.subtitle ? `${item.title} ${item.subtitle}` : item.title, | ||
| 118 | + })) | ||
| 119 | +) | ||
| 120 | + | ||
| 121 | +/** | ||
| 122 | + * 获取状态样式 | ||
| 123 | + * @param {string} status - 状态文本 | ||
| 124 | + * @returns {string} - Tailwind 类名 | ||
| 125 | + */ | ||
| 126 | +const getStatusStyle = status => { | ||
| 127 | + if (status === '活动中') { | ||
| 128 | + return 'bg-blue-50 text-blue-500 border-blue-100' | ||
| 129 | + } | ||
| 130 | + if (status === '进行中' || status === '即将开始') { | ||
| 131 | + return 'bg-orange-50 text-orange-500 border-orange-100' | ||
| 132 | + } | ||
| 133 | + return 'bg-gray-50 text-gray-500 border-gray-100' | ||
| 134 | +} | ||
| 135 | +</script> | ||
| 136 | + | ||
| 137 | +<style lang="less" scoped> | ||
| 138 | +// 自定义导航栏样式以匹配设计图 | ||
| 139 | +:deep(.van-nav-bar) { | ||
| 140 | + --van-nav-bar-height: 46px; | ||
| 141 | + .van-nav-bar__content { | ||
| 142 | + height: 46px; | ||
| 143 | + } | ||
| 144 | +} | ||
| 145 | + | ||
| 146 | +// 隐藏滚动条但保持滚动 | ||
| 147 | +.hide-scrollbar::-webkit-scrollbar { | ||
| 148 | + display: none; | ||
| 149 | +} | ||
| 150 | +.hide-scrollbar { | ||
| 151 | + -ms-overflow-style: none; | ||
| 152 | + scrollbar-width: none; | ||
| 153 | +} | ||
| 154 | +</style> |
src/views/test/CourseListTestPage.vue
0 → 100644
| 1 | +<template> | ||
| 2 | + <div class="pb-safe min-h-screen bg-gray-50"> | ||
| 3 | + <!-- 顶部导航栏 --> | ||
| 4 | + <van-nav-bar title="课程" left-arrow fixed placeholder class="nav-bar" /> | ||
| 5 | + | ||
| 6 | + <!-- 选项卡 --> | ||
| 7 | + <div class="bg-white shadow-sm"> | ||
| 8 | + <van-tabs | ||
| 9 | + v-model:active="activeTab" | ||
| 10 | + :line-width="40" | ||
| 11 | + :line-height="3" | ||
| 12 | + color="#4caf50" | ||
| 13 | + title-active-color="#4caf50" | ||
| 14 | + title-inactive-color="#666666" | ||
| 15 | + :swipeable="false" | ||
| 16 | + > | ||
| 17 | + <van-tab title="全部" title-class="tab-title"></van-tab> | ||
| 18 | + <van-tab title="已购买" title-class="tab-title"></van-tab> | ||
| 19 | + <van-tab title="免费" title-class="tab-title"></van-tab> | ||
| 20 | + </van-tabs> | ||
| 21 | + </div> | ||
| 22 | + | ||
| 23 | + <!-- 课程列表 --> | ||
| 24 | + <div class="p-3 pb-20"> | ||
| 25 | + <div | ||
| 26 | + v-for="course in courses" | ||
| 27 | + :key="course.id" | ||
| 28 | + class="mb-3 cursor-pointer overflow-hidden rounded-xl bg-white shadow-md transition-transform active:scale-95" | ||
| 29 | + @click="handleCourseClick(course)" | ||
| 30 | + > | ||
| 31 | + <!-- 课程封面 --> | ||
| 32 | + <div class="relative h-44 w-full overflow-hidden"> | ||
| 33 | + <img :src="course.cover" :alt="course.title" class="h-full w-full object-cover" /> | ||
| 34 | + <!-- 免费标签 --> | ||
| 35 | + <div | ||
| 36 | + v-if="course.isFree" | ||
| 37 | + class="absolute left-3 top-3 rounded-full bg-gradient-to-r from-purple-500 to-indigo-500 px-3 py-1 text-xs font-semibold text-white shadow-md" | ||
| 38 | + > | ||
| 39 | + 免费 | ||
| 40 | + </div> | ||
| 41 | + </div> | ||
| 42 | + | ||
| 43 | + <!-- 课程信息 --> | ||
| 44 | + <div class="p-3"> | ||
| 45 | + <!-- 课程标题 --> | ||
| 46 | + <h3 class="mb-2 line-clamp-2 text-base font-semibold leading-snug text-gray-900"> | ||
| 47 | + {{ course.title }} | ||
| 48 | + </h3> | ||
| 49 | + | ||
| 50 | + <!-- 统计信息 --> | ||
| 51 | + <div class="mb-2 flex items-center gap-3"> | ||
| 52 | + <span class="flex items-center gap-1 text-xs text-gray-500"> | ||
| 53 | + <van-icon name="user-o" :size="12" color="#4caf50" /> | ||
| 54 | + {{ course.studentCount }} | ||
| 55 | + </span> | ||
| 56 | + <span class="flex items-center gap-1 text-xs text-gray-500"> | ||
| 57 | + <van-icon name="video-o" :size="12" color="#4caf50" /> | ||
| 58 | + {{ course.lessonCount }}课时 | ||
| 59 | + </span> | ||
| 60 | + </div> | ||
| 61 | + | ||
| 62 | + <!-- 讲师信息 --> | ||
| 63 | + <div class="flex items-center gap-1.5"> | ||
| 64 | + <img | ||
| 65 | + :src="course.teacherAvatar" | ||
| 66 | + :alt="course.teacherName" | ||
| 67 | + class="h-5 w-5 rounded-full object-cover" | ||
| 68 | + /> | ||
| 69 | + <span class="text-sm text-gray-600">{{ course.teacherName }}</span> | ||
| 70 | + </div> | ||
| 71 | + </div> | ||
| 72 | + </div> | ||
| 73 | + </div> | ||
| 74 | + | ||
| 75 | + <!-- 底部导航栏(装饰用) --> | ||
| 76 | + <van-tabbar | ||
| 77 | + v-model="activeTabbar" | ||
| 78 | + fixed | ||
| 79 | + :safe-area-inset-bottom="true" | ||
| 80 | + active-color="#4caf50" | ||
| 81 | + inactive-color="#999999" | ||
| 82 | + > | ||
| 83 | + <van-tabbar-item icon="wap-home-o">首页</van-tabbar-item> | ||
| 84 | + <van-tabbar-item icon="apps-o">课程</van-tabbar-item> | ||
| 85 | + <van-tabbar-item icon="chat-o">活动</van-tabbar-item> | ||
| 86 | + <van-tabbar-item icon="user-o">我的</van-tabbar-item> | ||
| 87 | + </van-tabbar> | ||
| 88 | + </div> | ||
| 89 | +</template> | ||
| 90 | + | ||
| 91 | +<script setup> | ||
| 92 | +import { ref } from 'vue' | ||
| 93 | + | ||
| 94 | +// 当前激活的选项卡 | ||
| 95 | +const activeTab = ref(0) | ||
| 96 | + | ||
| 97 | +// 底部导航栏激活项 | ||
| 98 | +const activeTabbar = ref(1) | ||
| 99 | + | ||
| 100 | +// 模拟课程数据 | ||
| 101 | +const courses = ref([ | ||
| 102 | + { | ||
| 103 | + id: 1, | ||
| 104 | + title: '家庭教育指导师(初级)第12期', | ||
| 105 | + cover: 'https://cdn.ipadbiz.cn/public/mlaj/course-cover-1.jpg', | ||
| 106 | + isFree: true, | ||
| 107 | + studentCount: 1289, | ||
| 108 | + lessonCount: 24, | ||
| 109 | + teacherName: '张老师', | ||
| 110 | + teacherAvatar: 'https://cdn.ipadbiz.cn/public/mlaj/teacher-1.jpg', | ||
| 111 | + }, | ||
| 112 | + { | ||
| 113 | + id: 2, | ||
| 114 | + title: '智慧父母成长营第8期', | ||
| 115 | + cover: 'https://cdn.ipadbiz.cn/public/mlaj/course-cover-2.jpg', | ||
| 116 | + isFree: false, | ||
| 117 | + studentCount: 856, | ||
| 118 | + lessonCount: 16, | ||
| 119 | + teacherName: '李老师', | ||
| 120 | + teacherAvatar: 'https://cdn.ipadbiz.cn/public/mlaj/teacher-2.jpg', | ||
| 121 | + }, | ||
| 122 | + { | ||
| 123 | + id: 3, | ||
| 124 | + title: '儿童心理学基础课程', | ||
| 125 | + cover: 'https://cdn.ipadbiz.cn/public/mlaj/course-cover-3.jpg', | ||
| 126 | + isFree: true, | ||
| 127 | + studentCount: 2341, | ||
| 128 | + lessonCount: 32, | ||
| 129 | + teacherName: '王老师', | ||
| 130 | + teacherAvatar: 'https://cdn.ipadbiz.cn/public/mlaj/teacher-3.jpg', | ||
| 131 | + }, | ||
| 132 | +]) | ||
| 133 | + | ||
| 134 | +// 点击课程卡片 | ||
| 135 | +const handleCourseClick = course => { | ||
| 136 | + console.log('点击课程:', course.title) | ||
| 137 | +} | ||
| 138 | +</script> | ||
| 139 | + | ||
| 140 | +<style lang="less" scoped> | ||
| 141 | +// 仅用于修改 Vant 组件的深层样式 | ||
| 142 | +:deep(.nav-bar) { | ||
| 143 | + background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); | ||
| 144 | + | ||
| 145 | + .van-nav-bar__title { | ||
| 146 | + color: #ffffff; | ||
| 147 | + font-size: 18px; | ||
| 148 | + font-weight: 600; | ||
| 149 | + } | ||
| 150 | + | ||
| 151 | + .van-icon { | ||
| 152 | + color: #ffffff; | ||
| 153 | + } | ||
| 154 | +} | ||
| 155 | + | ||
| 156 | +:deep(.van-tabs) { | ||
| 157 | + .van-tabs__nav { | ||
| 158 | + padding-bottom: 0; | ||
| 159 | + } | ||
| 160 | + | ||
| 161 | + .van-tab { | ||
| 162 | + flex: 1; | ||
| 163 | + padding: 0; | ||
| 164 | + | ||
| 165 | + .tab-title { | ||
| 166 | + font-size: 15px; | ||
| 167 | + font-weight: 500; | ||
| 168 | + } | ||
| 169 | + } | ||
| 170 | + | ||
| 171 | + .van-tabs__line { | ||
| 172 | + bottom: 0; | ||
| 173 | + } | ||
| 174 | +} | ||
| 175 | + | ||
| 176 | +:deep(.van-tabbar) { | ||
| 177 | + box-shadow: 0 -2px 8px rgba(0, 0, 0, 0.05); | ||
| 178 | +} | ||
| 179 | + | ||
| 180 | +// TailwindCSS 不支持的样式(自定义安全区域) | ||
| 181 | +.pb-safe { | ||
| 182 | + padding-bottom: constant(safe-area-inset-bottom); | ||
| 183 | + padding-bottom: env(safe-area-inset-bottom); | ||
| 184 | +} | ||
| 185 | + | ||
| 186 | +// TailwindCSS 不支持的样式(行数限制) | ||
| 187 | +.line-clamp-2 { | ||
| 188 | + display: -webkit-box; | ||
| 189 | + -webkit-box-orient: vertical; | ||
| 190 | + -webkit-line-clamp: 2; | ||
| 191 | + overflow: hidden; | ||
| 192 | +} | ||
| 193 | +</style> |
-
Please register or login to post a comment