feat: 添加三师七证详情页和瀑布流展示功能
重构路由配置,新增MastersDetail页面 实现戒子页面的瀑布流图片展示功能 优化新闻详情页的样式和布局 移除不再使用的Teachers相关组件 添加Vant组件类型声明和mock数据
Showing
12 changed files
with
1047 additions
and
2977 deletions
| ... | @@ -19,14 +19,17 @@ declare module 'vue' { | ... | @@ -19,14 +19,17 @@ declare module 'vue' { |
| 19 | VanCheckbox: typeof import('vant/es')['Checkbox'] | 19 | VanCheckbox: typeof import('vant/es')['Checkbox'] |
| 20 | VanCollapse: typeof import('vant/es')['Collapse'] | 20 | VanCollapse: typeof import('vant/es')['Collapse'] |
| 21 | VanCollapseItem: typeof import('vant/es')['CollapseItem'] | 21 | VanCollapseItem: typeof import('vant/es')['CollapseItem'] |
| 22 | + VanEmpty: typeof import('vant/es')['Empty'] | ||
| 22 | VanField: typeof import('vant/es')['Field'] | 23 | VanField: typeof import('vant/es')['Field'] |
| 23 | VanForm: typeof import('vant/es')['Form'] | 24 | VanForm: typeof import('vant/es')['Form'] |
| 24 | VanGrid: typeof import('vant/es')['Grid'] | 25 | VanGrid: typeof import('vant/es')['Grid'] |
| 25 | VanGridItem: typeof import('vant/es')['GridItem'] | 26 | VanGridItem: typeof import('vant/es')['GridItem'] |
| 26 | VanIcon: typeof import('vant/es')['Icon'] | 27 | VanIcon: typeof import('vant/es')['Icon'] |
| 27 | VanImage: typeof import('vant/es')['Image'] | 28 | VanImage: typeof import('vant/es')['Image'] |
| 29 | + VanList: typeof import('vant/es')['List'] | ||
| 28 | VanNavBar: typeof import('vant/es')['NavBar'] | 30 | VanNavBar: typeof import('vant/es')['NavBar'] |
| 29 | VanNoticeBar: typeof import('vant/es')['NoticeBar'] | 31 | VanNoticeBar: typeof import('vant/es')['NoticeBar'] |
| 32 | + VanOverlay: typeof import('vant/es')['Overlay'] | ||
| 30 | VanProgress: typeof import('vant/es')['Progress'] | 33 | VanProgress: typeof import('vant/es')['Progress'] |
| 31 | VanRate: typeof import('vant/es')['Rate'] | 34 | VanRate: typeof import('vant/es')['Rate'] |
| 32 | VanSidebar: typeof import('vant/es')['Sidebar'] | 35 | VanSidebar: typeof import('vant/es')['Sidebar'] |
| ... | @@ -42,5 +45,6 @@ declare module 'vue' { | ... | @@ -42,5 +45,6 @@ declare module 'vue' { |
| 42 | VanTabs: typeof import('vant/es')['Tabs'] | 45 | VanTabs: typeof import('vant/es')['Tabs'] |
| 43 | VanTag: typeof import('vant/es')['Tag'] | 46 | VanTag: typeof import('vant/es')['Tag'] |
| 44 | VideoPlayer: typeof import('./components/VideoPlayer.vue')['default'] | 47 | VideoPlayer: typeof import('./components/VideoPlayer.vue')['default'] |
| 48 | + WaterfallGallery: typeof import('./components/WaterfallGallery.vue')['default'] | ||
| 45 | } | 49 | } |
| 46 | } | 50 | } | ... | ... |
| 1 | /* | 1 | /* |
| 2 | * @Date: 2025-10-30 10:29:15 | 2 | * @Date: 2025-10-30 10:29:15 |
| 3 | * @LastEditors: hookehuyr hookehuyr@gmail.com | 3 | * @LastEditors: hookehuyr hookehuyr@gmail.com |
| 4 | - * @LastEditTime: 2025-10-30 10:29:24 | 4 | + * @LastEditTime: 2025-10-30 20:53:14 |
| 5 | - * @FilePath: /itomix/h5_vite_template/src/router/index.js | 5 | + * @FilePath: /stdj_h5/src/router/index.js |
| 6 | * @Description: 文件描述 | 6 | * @Description: 文件描述 |
| 7 | */ | 7 | */ |
| 8 | import { createRouter, createWebHistory } from 'vue-router' | 8 | import { createRouter, createWebHistory } from 'vue-router' |
| ... | @@ -20,34 +20,29 @@ const routes = [ | ... | @@ -20,34 +20,29 @@ const routes = [ |
| 20 | component: Home | 20 | component: Home |
| 21 | }, | 21 | }, |
| 22 | { | 22 | { |
| 23 | - path: '/teachers', | 23 | + path: '/masters', |
| 24 | - name: 'Teachers', | 24 | + name: '三師七證', |
| 25 | - component: () => import('../views/Teachers.vue') | 25 | + component: () => import('../views/Masters.vue') |
| 26 | }, | 26 | }, |
| 27 | { | 27 | { |
| 28 | - path: '/teachers/:id', | 28 | + path: '/masters/:id', |
| 29 | - name: 'TeacherDetail', | 29 | + name: '三師七證详情', |
| 30 | - component: () => import('../views/TeacherDetail.vue') | 30 | + component: () => import('../views/MastersDetail.vue') |
| 31 | }, | 31 | }, |
| 32 | { | 32 | { |
| 33 | - path: '/volunteers', | 33 | + path: '/news/:id', |
| 34 | - name: 'Volunteers', | 34 | + name: 'NewsDetail', |
| 35 | - component: () => import('../views/Volunteers.vue') | 35 | + component: () => import('../views/NewsDetail.vue') |
| 36 | }, | 36 | }, |
| 37 | { | 37 | { |
| 38 | path: '/students', | 38 | path: '/students', |
| 39 | - name: 'Students', | 39 | + name: '戒子', |
| 40 | component: () => import('../views/Students.vue') | 40 | component: () => import('../views/Students.vue') |
| 41 | }, | 41 | }, |
| 42 | { | 42 | { |
| 43 | - path: '/students/:id', | 43 | + path: '/volunteers', |
| 44 | - name: 'StudentDetail', | 44 | + name: '义工', |
| 45 | - component: () => import('../views/StudentDetail.vue') | 45 | + component: () => import('../views/Volunteers.vue') |
| 46 | - }, | ||
| 47 | - { | ||
| 48 | - path: '/news/:id', | ||
| 49 | - name: 'NewsDetail', | ||
| 50 | - component: () => import('../views/NewsDetail.vue') | ||
| 51 | }, | 46 | }, |
| 52 | { | 47 | { |
| 53 | path: '/:pathMatch(.*)*', | 48 | path: '/:pathMatch(.*)*', |
| ... | @@ -74,7 +69,7 @@ router.beforeEach((to, from, next) => { | ... | @@ -74,7 +69,7 @@ router.beforeEach((to, from, next) => { |
| 74 | if (to.meta.title) { | 69 | if (to.meta.title) { |
| 75 | document.title = to.meta.title | 70 | document.title = to.meta.title |
| 76 | } | 71 | } |
| 77 | - | 72 | + |
| 78 | // 这里可以添加权限验证逻辑 | 73 | // 这里可以添加权限验证逻辑 |
| 79 | next() | 74 | next() |
| 80 | }) | 75 | }) |
| ... | @@ -83,4 +78,4 @@ router.afterEach(() => { | ... | @@ -83,4 +78,4 @@ router.afterEach(() => { |
| 83 | // 路由跳转后的逻辑 | 78 | // 路由跳转后的逻辑 |
| 84 | }) | 79 | }) |
| 85 | 80 | ||
| 86 | -export default router | ||
| ... | \ No newline at end of file | ... | \ No newline at end of file |
| 81 | +export default router | ... | ... |
| ... | @@ -240,3 +240,87 @@ export const communityPosts = [ | ... | @@ -240,3 +240,87 @@ export const communityPosts = [ |
| 240 | createdAt: '2023-03-14T15:45:00Z' | 240 | createdAt: '2023-03-14T15:45:00Z' |
| 241 | } | 241 | } |
| 242 | ]; | 242 | ]; |
| 243 | + | ||
| 244 | +// 瀑布流图片数据 - 用于义工和戒子页面 | ||
| 245 | +export const waterfallImages = [ | ||
| 246 | + { | ||
| 247 | + id: 1, | ||
| 248 | + url: 'https://cdn.ipadbiz.cn/mlaj/images/zMRLZh40kms.jpg', | ||
| 249 | + height: 300, | ||
| 250 | + title: '义工活动' | ||
| 251 | + }, | ||
| 252 | + { | ||
| 253 | + id: 2, | ||
| 254 | + url: 'https://cdn.ipadbiz.cn/mlaj/images/27kCu7bXGEI.jpg', | ||
| 255 | + height: 400, | ||
| 256 | + title: '学习交流' | ||
| 257 | + }, | ||
| 258 | + { | ||
| 259 | + id: 3, | ||
| 260 | + url: 'https://cdn.ipadbiz.cn/mlaj/images/jbwr0qZvpD4.jpg', | ||
| 261 | + height: 350, | ||
| 262 | + title: '禅修体验' | ||
| 263 | + }, | ||
| 264 | + { | ||
| 265 | + id: 4, | ||
| 266 | + url: 'https://cdn.ipadbiz.cn/mlaj/images/GGCP6vshpPY.jpg', | ||
| 267 | + height: 280, | ||
| 268 | + title: '传统文化' | ||
| 269 | + }, | ||
| 270 | + { | ||
| 271 | + id: 5, | ||
| 272 | + url: 'https://cdn.ipadbiz.cn/mlaj/images/2JIvboGLeho.jpg', | ||
| 273 | + height: 320, | ||
| 274 | + title: '法会现场' | ||
| 275 | + }, | ||
| 276 | + { | ||
| 277 | + id: 6, | ||
| 278 | + url: 'https://cdn.ipadbiz.cn/mlaj/images/_6HzPU9Hyfg (2).jpg', | ||
| 279 | + height: 380, | ||
| 280 | + title: '诵经学习' | ||
| 281 | + }, | ||
| 282 | + { | ||
| 283 | + id: 7, | ||
| 284 | + url: 'https://cdn.ipadbiz.cn/mlaj/images/2Juj2cXWB7U.jpg', | ||
| 285 | + height: 290, | ||
| 286 | + title: '义工服务' | ||
| 287 | + }, | ||
| 288 | + { | ||
| 289 | + id: 8, | ||
| 290 | + url: 'https://cdn.ipadbiz.cn/mlaj/images/Y17FE9Fuw4Y.jpg', | ||
| 291 | + height: 360, | ||
| 292 | + title: '戒子生活' | ||
| 293 | + }, | ||
| 294 | + { | ||
| 295 | + id: 9, | ||
| 296 | + url: 'https://cdn.ipadbiz.cn/mlaj/images/-G3rw6Y02D0.jpg', | ||
| 297 | + height: 310, | ||
| 298 | + title: '修行日常' | ||
| 299 | + }, | ||
| 300 | + { | ||
| 301 | + id: 10, | ||
| 302 | + url: 'https://cdn.ipadbiz.cn/mlaj/images/Oalh2MojUuk.jpg', | ||
| 303 | + height: 340, | ||
| 304 | + title: '集体活动' | ||
| 305 | + } | ||
| 306 | +]; | ||
| 307 | + | ||
| 308 | +// 生成更多瀑布流数据的函数 | ||
| 309 | +export const generateWaterfallData = (page = 1, pageSize = 10) => { | ||
| 310 | + const baseImages = waterfallImages; | ||
| 311 | + const startIndex = (page - 1) * pageSize; | ||
| 312 | + const data = []; | ||
| 313 | + | ||
| 314 | + for (let i = 0; i < pageSize; i++) { | ||
| 315 | + const baseIndex = i % baseImages.length; | ||
| 316 | + const baseImage = baseImages[baseIndex]; | ||
| 317 | + data.push({ | ||
| 318 | + ...baseImage, | ||
| 319 | + id: startIndex + i + 1, | ||
| 320 | + height: Math.floor(Math.random() * 200) + 250, // 随机高度 250-450px | ||
| 321 | + title: `${baseImage.title} ${Math.floor((startIndex + i) / baseImages.length) + 1}` | ||
| 322 | + }); | ||
| 323 | + } | ||
| 324 | + | ||
| 325 | + return data; | ||
| 326 | +}; | ... | ... |
| ... | @@ -187,6 +187,9 @@ | ... | @@ -187,6 +187,9 @@ |
| 187 | import { ref, computed, nextTick, onMounted, watch } from 'vue' | 187 | import { ref, computed, nextTick, onMounted, watch } from 'vue' |
| 188 | import VideoPlayer from '@/components/VideoPlayer.vue' | 188 | import VideoPlayer from '@/components/VideoPlayer.vue' |
| 189 | import { useTitle } from '@vueuse/core'; | 189 | import { useTitle } from '@vueuse/core'; |
| 190 | +import { useRouter } from 'vue-router' | ||
| 191 | + | ||
| 192 | +const router = useRouter() | ||
| 190 | 193 | ||
| 191 | // 页面标题 | 194 | // 页面标题 |
| 192 | useTitle('西园戒幢律寺三坛大戒法会'); | 195 | useTitle('西园戒幢律寺三坛大戒法会'); |
| ... | @@ -322,14 +325,17 @@ const viewMore = (type) => { | ... | @@ -322,14 +325,17 @@ const viewMore = (type) => { |
| 322 | case 'masters': | 325 | case 'masters': |
| 323 | console.log('跳转到三师七证页面') | 326 | console.log('跳转到三师七证页面') |
| 324 | // 这里可以添加跳转到三师七证页面的逻辑 | 327 | // 这里可以添加跳转到三师七证页面的逻辑 |
| 328 | + router.push('/masters') | ||
| 325 | break | 329 | break |
| 326 | case 'students': | 330 | case 'students': |
| 327 | console.log('跳转到戒子页面') | 331 | console.log('跳转到戒子页面') |
| 328 | // 这里可以添加跳转到戒子页面的逻辑 | 332 | // 这里可以添加跳转到戒子页面的逻辑 |
| 333 | + router.push('/students') | ||
| 329 | break | 334 | break |
| 330 | case 'volunteers': | 335 | case 'volunteers': |
| 331 | console.log('跳转到义工页面') | 336 | console.log('跳转到义工页面') |
| 332 | // 这里可以添加跳转到义工页面的逻辑 | 337 | // 这里可以添加跳转到义工页面的逻辑 |
| 338 | + router.push('/volunteers') | ||
| 333 | break | 339 | break |
| 334 | } | 340 | } |
| 335 | } else { | 341 | } else { |
| ... | @@ -467,6 +473,7 @@ const attachTransitionEndOnce = (looping) => { | ... | @@ -467,6 +473,7 @@ const attachTransitionEndOnce = (looping) => { |
| 467 | const handleNewsClick = (item) => { | 473 | const handleNewsClick = (item) => { |
| 468 | console.log('点击新闻:', item) | 474 | console.log('点击新闻:', item) |
| 469 | // 这里可以添加跳转到新闻详情页面的逻辑 | 475 | // 这里可以添加跳转到新闻详情页面的逻辑 |
| 476 | + router.push({ name: 'NewsDetail', params: { id: item.date } }) | ||
| 470 | } | 477 | } |
| 471 | </script> | 478 | </script> |
| 472 | 479 | ... | ... |
src/views/Masters.vue
0 → 100644
| 1 | +<template> | ||
| 2 | + <div class="masters-container"> | ||
| 3 | + <!-- 一行一个 Item(单列) --> | ||
| 4 | + <section class="single-list"> | ||
| 5 | + <div | ||
| 6 | + class="item-card" | ||
| 7 | + v-for="(item, i) in singleItems" | ||
| 8 | + :key="`single-${i}`" | ||
| 9 | + @click="goDetail(item)" | ||
| 10 | + > | ||
| 11 | + <div class="item-image"> | ||
| 12 | + <img :src="item.image" :alt="item.name" /> | ||
| 13 | + </div> | ||
| 14 | + <div class="item-caption"> | ||
| 15 | + <div class="item-role">{{ item.role }}</div> | ||
| 16 | + <div class="item-name">{{ item.name }}</div> | ||
| 17 | + </div> | ||
| 18 | + </div> | ||
| 19 | + </section> | ||
| 20 | + | ||
| 21 | + <!-- 一行两个 Item(双列) --> | ||
| 22 | + <section class="grid-two"> | ||
| 23 | + <div | ||
| 24 | + class="item-card small" | ||
| 25 | + v-for="(item, i) in gridItems" | ||
| 26 | + :key="`grid-${i}`" | ||
| 27 | + @click="goDetail(item)" | ||
| 28 | + > | ||
| 29 | + <div class="item-image"> | ||
| 30 | + <img :src="item.image" :alt="item.name" /> | ||
| 31 | + </div> | ||
| 32 | + <div class="item-caption"> | ||
| 33 | + <div class="item-role">{{ item.role }}</div> | ||
| 34 | + <div class="item-name">{{ item.name }}</div> | ||
| 35 | + </div> | ||
| 36 | + </div> | ||
| 37 | + </section> | ||
| 38 | + </div> | ||
| 39 | +</template> | ||
| 40 | + | ||
| 41 | +<script setup> | ||
| 42 | +import { ref } from 'vue' | ||
| 43 | +import { useRouter } from 'vue-router' | ||
| 44 | +import { useTitle } from '@vueuse/core'; | ||
| 45 | + | ||
| 46 | +const router = useRouter() | ||
| 47 | + | ||
| 48 | +useTitle('三師七證') | ||
| 49 | + | ||
| 50 | +// 单列数据(示例) | ||
| 51 | +const singleItems = ref([ | ||
| 52 | + { | ||
| 53 | + id: 101, | ||
| 54 | + role: '中国·戒幢律寺', | ||
| 55 | + name: '上明仁传师', | ||
| 56 | + image: '/src/assets/images/02 西园戒幢律寺三坛大戒法会/截图/全家福3_副本.jpg' | ||
| 57 | + }, | ||
| 58 | + { | ||
| 59 | + id: 102, | ||
| 60 | + role: '中国·戒幢律寺', | ||
| 61 | + name: '上明仁传师', | ||
| 62 | + image: '/src/assets/images/02 西园戒幢律寺三坛大戒法会/截图/全家福3_副本.jpg' | ||
| 63 | + }, | ||
| 64 | + { | ||
| 65 | + id: 103, | ||
| 66 | + role: '中国·戒幢律寺', | ||
| 67 | + name: '上明仁传师', | ||
| 68 | + image: '/src/assets/images/02 西园戒幢律寺三坛大戒法会/截图/全家福3_副本.jpg' | ||
| 69 | + } | ||
| 70 | +]) | ||
| 71 | + | ||
| 72 | +// 双列数据(示例) | ||
| 73 | +const gridItems = ref([ | ||
| 74 | + { | ||
| 75 | + id: 201, | ||
| 76 | + role: '传戒师', | ||
| 77 | + name: '上智和法师', | ||
| 78 | + image: '/src/assets/images/02 西园戒幢律寺三坛大戒法会/截图/全家福3_副本.jpg' | ||
| 79 | + }, | ||
| 80 | + { | ||
| 81 | + id: 202, | ||
| 82 | + role: '教授师', | ||
| 83 | + name: '上德弘法师', | ||
| 84 | + image: '/src/assets/images/02 西园戒幢律寺三坛大戒法会/截图/全家福3_副本.jpg' | ||
| 85 | + }, | ||
| 86 | + { | ||
| 87 | + id: 203, | ||
| 88 | + role: '羯磨师', | ||
| 89 | + name: '上寂明法师', | ||
| 90 | + image: '/src/assets/images/02 西园戒幢律寺三坛大戒法会/截图/全家福3_副本.jpg' | ||
| 91 | + }, | ||
| 92 | + { | ||
| 93 | + id: 204, | ||
| 94 | + role: '得戒和尚', | ||
| 95 | + name: '上慧觉法师', | ||
| 96 | + image: '/src/assets/images/02 西园戒幢律寺三坛大戒法会/截图/全家福3_副本.jpg' | ||
| 97 | + }, | ||
| 98 | + { | ||
| 99 | + id: 205, | ||
| 100 | + role: '引礼师', | ||
| 101 | + name: '上圆道法师', | ||
| 102 | + image: '/src/assets/images/02 西园戒幢律寺三坛大戒法会/截图/全家福3_副本.jpg' | ||
| 103 | + }, | ||
| 104 | + { | ||
| 105 | + id: 206, | ||
| 106 | + role: '开导师', | ||
| 107 | + name: '上演真法师', | ||
| 108 | + image: '/src/assets/images/02 西园戒幢律寺三坛大戒法会/截图/全家福3_副本.jpg' | ||
| 109 | + } | ||
| 110 | +]) | ||
| 111 | + | ||
| 112 | +const goDetail = (item) => { | ||
| 113 | + router.push(`/masters/${item.id}`) | ||
| 114 | +} | ||
| 115 | +</script> | ||
| 116 | + | ||
| 117 | +<style scoped> | ||
| 118 | +/* 页面容器 */ | ||
| 119 | +.masters-container { | ||
| 120 | + padding: 1.5rem; | ||
| 121 | + background: #F2EBDB; | ||
| 122 | +} | ||
| 123 | + | ||
| 124 | +/* 单列列表区 */ | ||
| 125 | +.single-list { | ||
| 126 | + display: flex; | ||
| 127 | + flex-direction: column; | ||
| 128 | + gap: 1rem; | ||
| 129 | + margin-bottom: 1rem; | ||
| 130 | +} | ||
| 131 | + | ||
| 132 | +/* 双列网格区 */ | ||
| 133 | +.grid-two { | ||
| 134 | + display: grid; | ||
| 135 | + grid-template-columns: repeat(2, 1fr); | ||
| 136 | + gap: 0.75rem; | ||
| 137 | +} | ||
| 138 | + | ||
| 139 | +/* 卡片 */ | ||
| 140 | +.item-card { | ||
| 141 | + position: relative; | ||
| 142 | + background: #fff; | ||
| 143 | + border: 2px solid #6B4102; | ||
| 144 | + overflow: hidden; | ||
| 145 | + transition: transform 0.2s ease; | ||
| 146 | + padding: 0.5rem; | ||
| 147 | +} | ||
| 148 | + | ||
| 149 | +.item-card:hover { | ||
| 150 | + transform: translateY(-0.125rem); | ||
| 151 | +} | ||
| 152 | + | ||
| 153 | +.item-card.small { | ||
| 154 | + /* 双列卡片视觉上更紧凑 */ | ||
| 155 | + border: 1px solid rgba(107, 65, 2, 0.8); | ||
| 156 | +} | ||
| 157 | + | ||
| 158 | +/* 图片区域 - 采用固定纵向比例 */ | ||
| 159 | +.item-image { | ||
| 160 | + width: 100%; | ||
| 161 | + aspect-ratio: 3 / 4; | ||
| 162 | + background: #f5f5f5; | ||
| 163 | +} | ||
| 164 | + | ||
| 165 | +.item-image img { | ||
| 166 | + width: 100%; | ||
| 167 | + height: 100%; | ||
| 168 | + object-fit: cover; | ||
| 169 | + display: block; | ||
| 170 | +} | ||
| 171 | + | ||
| 172 | +/* 底部说明条 */ | ||
| 173 | +.item-caption { | ||
| 174 | + position: absolute; | ||
| 175 | + left: 0; | ||
| 176 | + right: 0; | ||
| 177 | + bottom: 0; | ||
| 178 | + background: rgba(107, 65, 2, 0.8); | ||
| 179 | + color: #fff; | ||
| 180 | + padding: 0.75rem; | ||
| 181 | + text-align: center; | ||
| 182 | +} | ||
| 183 | + | ||
| 184 | +.item-role { | ||
| 185 | + font-size: 0.75rem; | ||
| 186 | + opacity: 0.95; | ||
| 187 | +} | ||
| 188 | + | ||
| 189 | +.item-name { | ||
| 190 | + font-size: 0.875rem; | ||
| 191 | + font-weight: 600; | ||
| 192 | + margin-top: 0.25rem; | ||
| 193 | +} | ||
| 194 | + | ||
| 195 | +/* 响应式调整 */ | ||
| 196 | +@media (max-width: 48rem) { | ||
| 197 | + .item-caption { | ||
| 198 | + padding: 0.625rem; | ||
| 199 | + margin: 0.5rem; | ||
| 200 | + } | ||
| 201 | +} | ||
| 202 | + | ||
| 203 | +@media (max-width: 30rem) { | ||
| 204 | + .masters-container { | ||
| 205 | + padding: 0.75rem; | ||
| 206 | + } | ||
| 207 | + .item-caption { | ||
| 208 | + padding: 0.5rem; | ||
| 209 | + margin: 0.5rem; | ||
| 210 | + } | ||
| 211 | + .item-name { | ||
| 212 | + font-size: 0.8125rem; | ||
| 213 | + } | ||
| 214 | +} | ||
| 215 | + | ||
| 216 | +@media (max-width: 20rem) { | ||
| 217 | + .grid-two { | ||
| 218 | + gap: 0.5rem; | ||
| 219 | + } | ||
| 220 | + .item-caption { | ||
| 221 | + padding: 0.375rem; | ||
| 222 | + margin: 0.5rem; | ||
| 223 | + } | ||
| 224 | + .item-name { | ||
| 225 | + font-size: 0.75rem; | ||
| 226 | + } | ||
| 227 | +} | ||
| 228 | +</style> |
src/views/MastersDetail.vue
0 → 100644
| 1 | +<!-- | ||
| 2 | + * @Date: 2025-10-30 20:00:25 | ||
| 3 | + * @LastEditors: hookehuyr hookehuyr@gmail.com | ||
| 4 | + * @LastEditTime: 2025-10-30 20:50:36 | ||
| 5 | + * @FilePath: /stdj_h5/src/views/MastersDetail.vue | ||
| 6 | + * @Description: 文件描述 | ||
| 7 | +--> | ||
| 8 | +<template> | ||
| 9 | + <div class="masters-detail-container"> | ||
| 10 | + <section class="single-list"> | ||
| 11 | + <div class="item-card"> | ||
| 12 | + | ||
| 13 | + </div> | ||
| 14 | + </section> | ||
| 15 | + </div> | ||
| 16 | +</template> | ||
| 17 | + | ||
| 18 | +<script setup> | ||
| 19 | +import { ref } from 'vue' | ||
| 20 | +import { useTitle } from '@vueuse/core'; | ||
| 21 | + | ||
| 22 | +useTitle('三師七證 - 詳情') | ||
| 23 | +</script> | ||
| 24 | + | ||
| 25 | + | ||
| 26 | +<style scoped> | ||
| 27 | +.masters-detail-container { | ||
| 28 | + padding: 1.5rem; | ||
| 29 | + background: #F2EBDB; | ||
| 30 | + min-height: 100vh; /* 背景至少覆盖整个视口高度 */ | ||
| 31 | + width: 100%; | ||
| 32 | + box-sizing: border-box; | ||
| 33 | +} | ||
| 34 | + | ||
| 35 | +.single-list { | ||
| 36 | + display: flex; | ||
| 37 | + flex-direction: column; | ||
| 38 | + gap: 1rem; | ||
| 39 | + margin-bottom: 1rem; | ||
| 40 | +} | ||
| 41 | + | ||
| 42 | +.item-card { | ||
| 43 | + position: relative; | ||
| 44 | + background: #fff; | ||
| 45 | + border: 2px solid #6B4102; | ||
| 46 | + overflow: hidden; | ||
| 47 | + transition: transform 0.2s ease; | ||
| 48 | + padding: 0.5rem; | ||
| 49 | +} | ||
| 50 | + | ||
| 51 | +</style> |
| 1 | <template> | 1 | <template> |
| 2 | <div class="page-container"> | 2 | <div class="page-container"> |
| 3 | - <!-- 导航栏 --> | ||
| 4 | - <van-nav-bar title="新闻详情" left-arrow @click-left="$router.back()" class="custom-nav"> | ||
| 5 | - <template #right> | ||
| 6 | - <van-icon name="share-o" size="18" @click="handleShare" /> | ||
| 7 | - </template> | ||
| 8 | - </van-nav-bar> | ||
| 9 | - | ||
| 10 | <!-- 内容区域 --> | 3 | <!-- 内容区域 --> |
| 11 | <div class="content-container"> | 4 | <div class="content-container"> |
| 12 | <!-- 文章头部 --> | 5 | <!-- 文章头部 --> |
| ... | @@ -14,152 +7,21 @@ | ... | @@ -14,152 +7,21 @@ |
| 14 | <h1 class="article-title">{{ article.title }}</h1> | 7 | <h1 class="article-title">{{ article.title }}</h1> |
| 15 | <div class="article-meta"> | 8 | <div class="article-meta"> |
| 16 | <div class="meta-info"> | 9 | <div class="meta-info"> |
| 17 | - <span class="publish-date">{{ article.publishDate }}</span> | 10 | + <van-icon name="clock-o" /><span class="publish-date">{{ article.publishDate }}</span> |
| 18 | - <span class="author">{{ article.author }}</span> | 11 | + <van-icon name="manager-o" /><span class="author">{{ article.author }}</span> |
| 19 | </div> | 12 | </div> |
| 20 | - <div class="article-stats"> | ||
| 21 | - <span class="view-count"> | ||
| 22 | - <van-icon name="eye-o" /> | ||
| 23 | - {{ article.viewCount }} | ||
| 24 | - </span> | ||
| 25 | - <span class="like-count" @click="handleLike"> | ||
| 26 | - <van-icon :name="article.isLiked ? 'like' : 'like-o'" :color="article.isLiked ? '#ff6b6b' : '#999'" /> | ||
| 27 | - {{ article.likeCount }} | ||
| 28 | - </span> | ||
| 29 | - </div> | ||
| 30 | - </div> | ||
| 31 | - | ||
| 32 | - <!-- 标签 --> | ||
| 33 | - <div class="article-tags" v-if="article.tags && article.tags.length"> | ||
| 34 | - <van-tag | ||
| 35 | - v-for="tag in article.tags" | ||
| 36 | - :key="tag" | ||
| 37 | - type="primary" | ||
| 38 | - size="small" | ||
| 39 | - class="article-tag" | ||
| 40 | - > | ||
| 41 | - {{ tag }} | ||
| 42 | - </van-tag> | ||
| 43 | </div> | 13 | </div> |
| 44 | </div> | 14 | </div> |
| 45 | - | 15 | + |
| 46 | <!-- 文章封面 --> | 16 | <!-- 文章封面 --> |
| 47 | <div class="article-cover" v-if="article.coverImage"> | 17 | <div class="article-cover" v-if="article.coverImage"> |
| 48 | <img :src="article.coverImage" :alt="article.title" /> | 18 | <img :src="article.coverImage" :alt="article.title" /> |
| 49 | </div> | 19 | </div> |
| 50 | - | 20 | + |
| 51 | <!-- 文章内容 --> | 21 | <!-- 文章内容 --> |
| 52 | <div class="article-content"> | 22 | <div class="article-content"> |
| 53 | <div class="content-text" v-html="article.content"></div> | 23 | <div class="content-text" v-html="article.content"></div> |
| 54 | </div> | 24 | </div> |
| 55 | - | ||
| 56 | - <!-- 文章底部 --> | ||
| 57 | - <div class="article-footer"> | ||
| 58 | - <div class="footer-actions"> | ||
| 59 | - <div class="action-item" @click="handleLike"> | ||
| 60 | - <van-icon :name="article.isLiked ? 'like' : 'like-o'" :color="article.isLiked ? '#ff6b6b' : '#666'" size="20" /> | ||
| 61 | - <span>{{ article.isLiked ? '已赞' : '点赞' }}</span> | ||
| 62 | - </div> | ||
| 63 | - <div class="action-item" @click="handleCollect"> | ||
| 64 | - <van-icon :name="article.isCollected ? 'star' : 'star-o'" :color="article.isCollected ? '#fbbf24' : '#666'" size="20" /> | ||
| 65 | - <span>{{ article.isCollected ? '已收藏' : '收藏' }}</span> | ||
| 66 | - </div> | ||
| 67 | - <div class="action-item" @click="handleShare"> | ||
| 68 | - <van-icon name="share-o" color="#666" size="20" /> | ||
| 69 | - <span>分享</span> | ||
| 70 | - </div> | ||
| 71 | - <div class="action-item" @click="handleComment"> | ||
| 72 | - <van-icon name="chat-o" color="#666" size="20" /> | ||
| 73 | - <span>评论</span> | ||
| 74 | - </div> | ||
| 75 | - </div> | ||
| 76 | - </div> | ||
| 77 | - | ||
| 78 | - <!-- 相关文章 --> | ||
| 79 | - <div class="related-articles" v-if="relatedArticles.length"> | ||
| 80 | - <h3 class="section-title">相关文章</h3> | ||
| 81 | - <div class="related-list"> | ||
| 82 | - <div | ||
| 83 | - v-for="related in relatedArticles" | ||
| 84 | - :key="related.id" | ||
| 85 | - class="related-item" | ||
| 86 | - @click="handleRelatedClick(related)" | ||
| 87 | - > | ||
| 88 | - <div class="related-cover"> | ||
| 89 | - <img v-if="related.coverImage" :src="related.coverImage" :alt="related.title" /> | ||
| 90 | - <div v-else class="cover-placeholder"> | ||
| 91 | - <van-icon name="photo-o" size="24" color="#ccc" /> | ||
| 92 | - </div> | ||
| 93 | - </div> | ||
| 94 | - <div class="related-info"> | ||
| 95 | - <h4 class="related-title">{{ related.title }}</h4> | ||
| 96 | - <div class="related-meta"> | ||
| 97 | - <span class="related-date">{{ related.publishDate }}</span> | ||
| 98 | - <span class="related-views">{{ related.viewCount }}阅读</span> | ||
| 99 | - </div> | ||
| 100 | - </div> | ||
| 101 | - </div> | ||
| 102 | - </div> | ||
| 103 | - </div> | ||
| 104 | - | ||
| 105 | - <!-- 评论区 --> | ||
| 106 | - <div class="comments-section"> | ||
| 107 | - <h3 class="section-title">评论 ({{ comments.length }})</h3> | ||
| 108 | - | ||
| 109 | - <!-- 评论输入 --> | ||
| 110 | - <div class="comment-input"> | ||
| 111 | - <van-field | ||
| 112 | - v-model="commentText" | ||
| 113 | - type="textarea" | ||
| 114 | - placeholder="写下你的评论..." | ||
| 115 | - rows="3" | ||
| 116 | - maxlength="500" | ||
| 117 | - show-word-limit | ||
| 118 | - /> | ||
| 119 | - <van-button | ||
| 120 | - type="primary" | ||
| 121 | - size="small" | ||
| 122 | - @click="handleSubmitComment" | ||
| 123 | - :disabled="!commentText.trim()" | ||
| 124 | - class="submit-btn" | ||
| 125 | - > | ||
| 126 | - 发表 | ||
| 127 | - </van-button> | ||
| 128 | - </div> | ||
| 129 | - | ||
| 130 | - <!-- 评论列表 --> | ||
| 131 | - <div class="comments-list"> | ||
| 132 | - <div | ||
| 133 | - v-for="comment in comments" | ||
| 134 | - :key="comment.id" | ||
| 135 | - class="comment-item" | ||
| 136 | - > | ||
| 137 | - <div class="comment-avatar"> | ||
| 138 | - <img v-if="comment.avatar" :src="comment.avatar" :alt="comment.author" /> | ||
| 139 | - <div v-else class="avatar-placeholder"> | ||
| 140 | - <span>{{ comment.author.charAt(0) }}</span> | ||
| 141 | - </div> | ||
| 142 | - </div> | ||
| 143 | - <div class="comment-content"> | ||
| 144 | - <div class="comment-header"> | ||
| 145 | - <span class="comment-author">{{ comment.author }}</span> | ||
| 146 | - <span class="comment-date">{{ comment.date }}</span> | ||
| 147 | - </div> | ||
| 148 | - <p class="comment-text">{{ comment.content }}</p> | ||
| 149 | - <div class="comment-actions"> | ||
| 150 | - <span class="comment-like" @click="handleCommentLike(comment)"> | ||
| 151 | - <van-icon :name="comment.isLiked ? 'like' : 'like-o'" :color="comment.isLiked ? '#ff6b6b' : '#999'" size="14" /> | ||
| 152 | - {{ comment.likeCount || '' }} | ||
| 153 | - </span> | ||
| 154 | - <span class="comment-reply" @click="handleCommentReply(comment)">回复</span> | ||
| 155 | - </div> | ||
| 156 | - </div> | ||
| 157 | - </div> | ||
| 158 | - </div> | ||
| 159 | - | ||
| 160 | - <!-- 空状态 --> | ||
| 161 | - <van-empty v-if="comments.length === 0" description="暂无评论,快来抢沙发吧~" /> | ||
| 162 | - </div> | ||
| 163 | </div> | 25 | </div> |
| 164 | </div> | 26 | </div> |
| 165 | </template> | 27 | </template> |
| ... | @@ -177,158 +39,26 @@ const commentText = ref('') | ... | @@ -177,158 +39,26 @@ const commentText = ref('') |
| 177 | // 文章数据 | 39 | // 文章数据 |
| 178 | const article = ref({ | 40 | const article = ref({ |
| 179 | id: 1, | 41 | id: 1, |
| 180 | - title: '三坛大戒传戒法会圆满举行', | 42 | + title: '三坛大戒 | 护戒胜福田 成就最上因', |
| 181 | content: ` | 43 | content: ` |
| 182 | - <p>2024年春季三坛大戒传戒法会于今日在本寺圆满举行。此次法会历时21天,共有来自全国各地的68位戒子参加,在诸位戒师的慈悲教导下,圆满受持三坛大戒。</p> | 44 | + <p>为弘承世尊遗教,光大如来戒法,绍隆佛种,续佛慧命,经研究并报中国佛教协会批复同意(中佛会〔2025〕35号),由江苏省佛教协会主办,苏州市佛教协会、苏州市姑苏区佛教协会、苏州工业园区佛教协会协办,苏州西园戒幢律寺、苏州工业园区积善寺承办的传戒三坛大戒法会定于2025年10月15日至11月15日举办。</p> |
| 183 | - | 45 | + |
| 184 | - <p>三坛大戒是佛教出家众必须受持的重要戒律,包括沙弥戒、比丘戒和菩萨戒三个层次。通过严格的戒律学习和实践,戒子们不仅在戒律知识上有了深入的理解,更在修行品格上得到了显著提升。</p> | 46 | + <h3>天增上三学,以戒为首</h3> |
| 185 | - | 47 | + <h3>佛灭度后,以戒为师</h3> |
| 186 | - <p>在传戒期间,戒子们每日早起晚睡,精进修学。从戒律理论的学习到实际生活中的践行,从个人修持到集体共修,每一个环节都体现了佛教戒律的庄严与神圣。</p> | 48 | + |
| 187 | - | 49 | + <p>《梵网经》云:"众生受佛戒,即入诸佛位。位同大觉已,真是诸佛子。"传戒法会,具称"千佛三坛大戒法会",三坛大戒是成就僧人最重要的增上缘仪式,谓授千佛共同所制戒。戒场分非同一般之法会场所,庄妙标有,无过之者。</p> |
| 188 | - <p>本次传戒法会得到了十方善信的大力护持,义工菩萨们日夜辛劳,为法会的顺利进行提供了有力保障。在此向所有护持法会的善信表示衷心感谢。</p> | 50 | + |
| 189 | - | 51 | + <p>今苏州西园戒幢律寺作为主戒场传戒三坛大戒,正值因时,其事庄严,此意成就道场通达。</p> |
| 190 | - <p>愿诸位新戒比丘能够严持净戒,精进修行,早证菩提,广度众生。愿佛法久住,法轮常转,众生离苦得乐。</p> | ||
| 191 | `, | 52 | `, |
| 192 | - author: '释智慧法师', | 53 | + author: '戒幢律寺编辑部', |
| 193 | - publishDate: '2024-01-15', | 54 | + publishDate: '2025-10-1', |
| 194 | - viewCount: 1256, | 55 | + viewCount: 2156, |
| 195 | - likeCount: 89, | 56 | + likeCount: 156, |
| 196 | isLiked: false, | 57 | isLiked: false, |
| 197 | isCollected: false, | 58 | isCollected: false, |
| 198 | - coverImage: null, | 59 | + coverImage: 'https://images.unsplash.com/photo-1545558014-8692077e9b5c?w=800&h=600&fit=crop', |
| 199 | - tags: ['三坛大戒', '传戒法会', '戒律', '修行'] | ||
| 200 | }) | 60 | }) |
| 201 | 61 | ||
| 202 | -// 相关文章 | ||
| 203 | -const relatedArticles = ref([ | ||
| 204 | - { | ||
| 205 | - id: 2, | ||
| 206 | - title: '戒律学习的重要性与方法', | ||
| 207 | - publishDate: '2024-01-10', | ||
| 208 | - viewCount: 856, | ||
| 209 | - coverImage: null | ||
| 210 | - }, | ||
| 211 | - { | ||
| 212 | - id: 3, | ||
| 213 | - title: '沙弥戒的基本要求与实践', | ||
| 214 | - publishDate: '2024-01-08', | ||
| 215 | - viewCount: 642, | ||
| 216 | - coverImage: null | ||
| 217 | - }, | ||
| 218 | - { | ||
| 219 | - id: 4, | ||
| 220 | - title: '比丘戒的深层含义解析', | ||
| 221 | - publishDate: '2024-01-05', | ||
| 222 | - viewCount: 789, | ||
| 223 | - coverImage: null | ||
| 224 | - } | ||
| 225 | -]) | ||
| 226 | - | ||
| 227 | -// 评论数据 | ||
| 228 | -const comments = ref([ | ||
| 229 | - { | ||
| 230 | - id: 1, | ||
| 231 | - author: '慧心居士', | ||
| 232 | - content: '随喜赞叹!三坛大戒的传承是佛教的重要传统,愿新戒比丘们都能严持净戒,精进修行。', | ||
| 233 | - date: '2024-01-15 14:30', | ||
| 234 | - likeCount: 12, | ||
| 235 | - isLiked: false, | ||
| 236 | - avatar: null | ||
| 237 | - }, | ||
| 238 | - { | ||
| 239 | - id: 2, | ||
| 240 | - author: '觉悟行者', | ||
| 241 | - content: '感恩诸位法师的慈悲教导,戒律是修行的基础,希望能有更多这样的法会。', | ||
| 242 | - date: '2024-01-15 15:45', | ||
| 243 | - likeCount: 8, | ||
| 244 | - isLiked: false, | ||
| 245 | - avatar: null | ||
| 246 | - }, | ||
| 247 | - { | ||
| 248 | - id: 3, | ||
| 249 | - author: '清净莲花', | ||
| 250 | - content: '阿弥陀佛!看到这样的法会真是法喜充满,愿佛法久住世间。', | ||
| 251 | - date: '2024-01-15 16:20', | ||
| 252 | - likeCount: 5, | ||
| 253 | - isLiked: false, | ||
| 254 | - avatar: null | ||
| 255 | - } | ||
| 256 | -]) | ||
| 257 | - | ||
| 258 | -// 处理点赞 | ||
| 259 | -const handleLike = () => { | ||
| 260 | - article.value.isLiked = !article.value.isLiked | ||
| 261 | - if (article.value.isLiked) { | ||
| 262 | - article.value.likeCount++ | ||
| 263 | - Toast('点赞成功') | ||
| 264 | - } else { | ||
| 265 | - article.value.likeCount-- | ||
| 266 | - Toast('取消点赞') | ||
| 267 | - } | ||
| 268 | -} | ||
| 269 | - | ||
| 270 | -// 处理收藏 | ||
| 271 | -const handleCollect = () => { | ||
| 272 | - article.value.isCollected = !article.value.isCollected | ||
| 273 | - if (article.value.isCollected) { | ||
| 274 | - Toast('收藏成功') | ||
| 275 | - } else { | ||
| 276 | - Toast('取消收藏') | ||
| 277 | - } | ||
| 278 | -} | ||
| 279 | - | ||
| 280 | -// 处理分享 | ||
| 281 | -const handleShare = () => { | ||
| 282 | - Toast('分享功能开发中...') | ||
| 283 | -} | ||
| 284 | - | ||
| 285 | -// 处理评论 | ||
| 286 | -const handleComment = () => { | ||
| 287 | - document.querySelector('.comment-input').scrollIntoView({ behavior: 'smooth' }) | ||
| 288 | -} | ||
| 289 | - | ||
| 290 | -// 处理相关文章点击 | ||
| 291 | -const handleRelatedClick = (related) => { | ||
| 292 | - router.push(`/news/${related.id}`) | ||
| 293 | -} | ||
| 294 | - | ||
| 295 | -// 提交评论 | ||
| 296 | -const handleSubmitComment = () => { | ||
| 297 | - if (!commentText.value.trim()) { | ||
| 298 | - Toast('请输入评论内容') | ||
| 299 | - return | ||
| 300 | - } | ||
| 301 | - | ||
| 302 | - const newComment = { | ||
| 303 | - id: Date.now(), | ||
| 304 | - author: '当前用户', | ||
| 305 | - content: commentText.value.trim(), | ||
| 306 | - date: new Date().toLocaleString('zh-CN'), | ||
| 307 | - likeCount: 0, | ||
| 308 | - isLiked: false, | ||
| 309 | - avatar: null | ||
| 310 | - } | ||
| 311 | - | ||
| 312 | - comments.value.unshift(newComment) | ||
| 313 | - commentText.value = '' | ||
| 314 | - Toast('评论发表成功') | ||
| 315 | -} | ||
| 316 | - | ||
| 317 | -// 处理评论点赞 | ||
| 318 | -const handleCommentLike = (comment) => { | ||
| 319 | - comment.isLiked = !comment.isLiked | ||
| 320 | - if (comment.isLiked) { | ||
| 321 | - comment.likeCount = (comment.likeCount || 0) + 1 | ||
| 322 | - } else { | ||
| 323 | - comment.likeCount = Math.max(0, (comment.likeCount || 0) - 1) | ||
| 324 | - } | ||
| 325 | -} | ||
| 326 | - | ||
| 327 | -// 处理评论回复 | ||
| 328 | -const handleCommentReply = (comment) => { | ||
| 329 | - Toast('回复功能开发中...') | ||
| 330 | -} | ||
| 331 | - | ||
| 332 | // 组件挂载时加载数据 | 62 | // 组件挂载时加载数据 |
| 333 | onMounted(() => { | 63 | onMounted(() => { |
| 334 | const articleId = route.params.id | 64 | const articleId = route.params.id |
| ... | @@ -340,339 +70,89 @@ onMounted(() => { | ... | @@ -340,339 +70,89 @@ onMounted(() => { |
| 340 | <style scoped> | 70 | <style scoped> |
| 341 | .page-container { | 71 | .page-container { |
| 342 | min-height: 100vh; | 72 | min-height: 100vh; |
| 343 | - background: #fafafa; | 73 | + background: #f5f5f5; |
| 344 | -} | ||
| 345 | - | ||
| 346 | -.custom-nav { | ||
| 347 | - background: linear-gradient(135deg, #3b82f6, #1d4ed8); | ||
| 348 | - color: white; | ||
| 349 | -} | ||
| 350 | - | ||
| 351 | -.custom-nav :deep(.van-nav-bar__title) { | ||
| 352 | - color: white; | ||
| 353 | - font-weight: 600; | ||
| 354 | -} | ||
| 355 | - | ||
| 356 | -.custom-nav :deep(.van-icon) { | ||
| 357 | - color: white; | ||
| 358 | } | 74 | } |
| 359 | 75 | ||
| 360 | .content-container { | 76 | .content-container { |
| 361 | - padding-top: 46px; | 77 | + background-color: #F2EBDB; |
| 362 | } | 78 | } |
| 363 | 79 | ||
| 364 | .article-header { | 80 | .article-header { |
| 365 | - background: white; | 81 | + padding: 1rem; |
| 366 | - padding: 20px; | ||
| 367 | - margin-bottom: 12px; | ||
| 368 | } | 82 | } |
| 369 | 83 | ||
| 370 | .article-title { | 84 | .article-title { |
| 371 | - font-size: 24px; | 85 | + font-size: 1.25rem; |
| 372 | font-weight: 700; | 86 | font-weight: 700; |
| 373 | - color: #333; | 87 | + color: #8b4513; |
| 374 | line-height: 1.4; | 88 | line-height: 1.4; |
| 375 | - margin: 0 0 16px 0; | 89 | + margin: 0 0 1rem 0; |
| 90 | + text-align: center; | ||
| 376 | } | 91 | } |
| 377 | 92 | ||
| 378 | .article-meta { | 93 | .article-meta { |
| 379 | display: flex; | 94 | display: flex; |
| 380 | - justify-content: space-between; | 95 | + justify-content: center; |
| 381 | align-items: center; | 96 | align-items: center; |
| 382 | - margin-bottom: 16px; | 97 | + margin-bottom: 1rem; |
| 98 | + gap: 1rem; | ||
| 383 | } | 99 | } |
| 384 | 100 | ||
| 385 | .meta-info { | 101 | .meta-info { |
| 386 | display: flex; | 102 | display: flex; |
| 387 | - gap: 16px; | 103 | + gap: 1rem; |
| 104 | + align-items: center; | ||
| 388 | } | 105 | } |
| 389 | 106 | ||
| 390 | .publish-date, | 107 | .publish-date, |
| 391 | .author { | 108 | .author { |
| 392 | - font-size: 14px; | 109 | + font-size: 0.875rem; |
| 393 | - color: #666; | 110 | + color: #8b4513; |
| 394 | -} | ||
| 395 | - | ||
| 396 | -.article-stats { | ||
| 397 | - display: flex; | ||
| 398 | - gap: 16px; | ||
| 399 | -} | ||
| 400 | - | ||
| 401 | -.view-count, | ||
| 402 | -.like-count { | ||
| 403 | display: flex; | 111 | display: flex; |
| 404 | align-items: center; | 112 | align-items: center; |
| 405 | - gap: 4px; | 113 | + gap: 0.25rem; |
| 406 | - font-size: 14px; | ||
| 407 | - color: #666; | ||
| 408 | - cursor: pointer; | ||
| 409 | -} | ||
| 410 | - | ||
| 411 | -.article-tags { | ||
| 412 | - display: flex; | ||
| 413 | - gap: 8px; | ||
| 414 | - flex-wrap: wrap; | ||
| 415 | -} | ||
| 416 | - | ||
| 417 | -.article-tag { | ||
| 418 | - background: #e0f2fe !important; | ||
| 419 | - color: #0277bd !important; | ||
| 420 | - border: 1px solid #81d4fa !important; | ||
| 421 | } | 114 | } |
| 422 | 115 | ||
| 423 | .article-cover { | 116 | .article-cover { |
| 424 | - background: white; | 117 | + margin: 1rem 0; |
| 425 | - padding: 0 20px 20px; | ||
| 426 | - margin-bottom: 12px; | ||
| 427 | } | 118 | } |
| 428 | 119 | ||
| 429 | .article-cover img { | 120 | .article-cover img { |
| 430 | width: 100%; | 121 | width: 100%; |
| 431 | - border-radius: 8px; | 122 | + border-radius: 0.5rem; |
| 123 | + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); | ||
| 432 | } | 124 | } |
| 433 | 125 | ||
| 434 | .article-content { | 126 | .article-content { |
| 435 | - background: white; | 127 | + background: #f9f7f4; |
| 436 | - padding: 20px; | 128 | + padding: 1.5rem; |
| 437 | - margin-bottom: 12px; | 129 | + margin: 1rem 0; |
| 130 | + border-radius: 1rem; | ||
| 131 | + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); | ||
| 132 | + border: 1px solid #e8e3dc; | ||
| 438 | } | 133 | } |
| 439 | 134 | ||
| 440 | .content-text { | 135 | .content-text { |
| 441 | - font-size: 16px; | 136 | + font-size: 1rem; |
| 442 | line-height: 1.8; | 137 | line-height: 1.8; |
| 443 | - color: #333; | 138 | + color: #5d4e37; |
| 444 | } | 139 | } |
| 445 | 140 | ||
| 446 | .content-text :deep(p) { | 141 | .content-text :deep(p) { |
| 447 | - margin: 0 0 16px 0; | 142 | + margin: 0 0 1rem 0; |
| 448 | text-indent: 2em; | 143 | text-indent: 2em; |
| 449 | } | 144 | } |
| 450 | 145 | ||
| 451 | -.content-text :deep(p:last-child) { | 146 | +.content-text :deep(h3) { |
| 452 | - margin-bottom: 0; | 147 | + font-size: 1.125rem; |
| 453 | -} | ||
| 454 | - | ||
| 455 | -.article-footer { | ||
| 456 | - background: white; | ||
| 457 | - padding: 20px; | ||
| 458 | - margin-bottom: 12px; | ||
| 459 | - border-top: 1px solid #eee; | ||
| 460 | -} | ||
| 461 | - | ||
| 462 | -.footer-actions { | ||
| 463 | - display: flex; | ||
| 464 | - justify-content: space-around; | ||
| 465 | -} | ||
| 466 | - | ||
| 467 | -.action-item { | ||
| 468 | - display: flex; | ||
| 469 | - flex-direction: column; | ||
| 470 | - align-items: center; | ||
| 471 | - gap: 8px; | ||
| 472 | - cursor: pointer; | ||
| 473 | - padding: 12px; | ||
| 474 | - border-radius: 8px; | ||
| 475 | - transition: background-color 0.2s; | ||
| 476 | -} | ||
| 477 | - | ||
| 478 | -.action-item:active { | ||
| 479 | - background: #f5f5f5; | ||
| 480 | -} | ||
| 481 | - | ||
| 482 | -.action-item span { | ||
| 483 | - font-size: 12px; | ||
| 484 | - color: #666; | ||
| 485 | -} | ||
| 486 | - | ||
| 487 | -.related-articles { | ||
| 488 | - background: white; | ||
| 489 | - padding: 20px; | ||
| 490 | - margin-bottom: 12px; | ||
| 491 | -} | ||
| 492 | - | ||
| 493 | -.section-title { | ||
| 494 | - font-size: 18px; | ||
| 495 | font-weight: 600; | 148 | font-weight: 600; |
| 496 | - color: #333; | 149 | + color: #8b4513; |
| 497 | - margin: 0 0 16px 0; | 150 | + text-align: center; |
| 498 | - padding-left: 4px; | 151 | + margin: 1.5rem 0 1rem 0; |
| 499 | - border-left: 4px solid #3b82f6; | 152 | + text-indent: 0; |
| 500 | } | 153 | } |
| 501 | 154 | ||
| 502 | -.related-list { | 155 | +.content-text :deep(p:last-child) { |
| 503 | - space-y: 12px; | 156 | + margin-bottom: 0; |
| 504 | -} | ||
| 505 | - | ||
| 506 | -.related-item { | ||
| 507 | - display: flex; | ||
| 508 | - gap: 12px; | ||
| 509 | - padding: 12px; | ||
| 510 | - border-radius: 8px; | ||
| 511 | - cursor: pointer; | ||
| 512 | - transition: background-color 0.2s; | ||
| 513 | - margin-bottom: 12px; | ||
| 514 | -} | ||
| 515 | - | ||
| 516 | -.related-item:active { | ||
| 517 | - background: #f5f5f5; | ||
| 518 | -} | ||
| 519 | - | ||
| 520 | -.related-cover { | ||
| 521 | - width: 80px; | ||
| 522 | - height: 60px; | ||
| 523 | - border-radius: 6px; | ||
| 524 | - overflow: hidden; | ||
| 525 | - flex-shrink: 0; | ||
| 526 | - background: #f5f5f5; | ||
| 527 | -} | ||
| 528 | - | ||
| 529 | -.related-cover img { | ||
| 530 | - width: 100%; | ||
| 531 | - height: 100%; | ||
| 532 | - object-fit: cover; | ||
| 533 | -} | ||
| 534 | - | ||
| 535 | -.cover-placeholder { | ||
| 536 | - width: 100%; | ||
| 537 | - height: 100%; | ||
| 538 | - display: flex; | ||
| 539 | - align-items: center; | ||
| 540 | - justify-content: center; | ||
| 541 | - background: #f5f5f5; | ||
| 542 | -} | ||
| 543 | - | ||
| 544 | -.related-info { | ||
| 545 | - flex: 1; | ||
| 546 | -} | ||
| 547 | - | ||
| 548 | -.related-title { | ||
| 549 | - font-size: 16px; | ||
| 550 | - font-weight: 500; | ||
| 551 | - color: #333; | ||
| 552 | - margin: 0 0 8px 0; | ||
| 553 | - line-height: 1.4; | ||
| 554 | - display: -webkit-box; | ||
| 555 | - -webkit-line-clamp: 2; | ||
| 556 | - -webkit-box-orient: vertical; | ||
| 557 | - overflow: hidden; | ||
| 558 | -} | ||
| 559 | - | ||
| 560 | -.related-meta { | ||
| 561 | - display: flex; | ||
| 562 | - gap: 12px; | ||
| 563 | -} | ||
| 564 | - | ||
| 565 | -.related-date, | ||
| 566 | -.related-views { | ||
| 567 | - font-size: 12px; | ||
| 568 | - color: #999; | ||
| 569 | -} | ||
| 570 | - | ||
| 571 | -.comments-section { | ||
| 572 | - background: white; | ||
| 573 | - padding: 20px; | ||
| 574 | - margin-bottom: 20px; | ||
| 575 | -} | ||
| 576 | - | ||
| 577 | -.comment-input { | ||
| 578 | - margin-bottom: 20px; | ||
| 579 | - position: relative; | ||
| 580 | -} | ||
| 581 | - | ||
| 582 | -.submit-btn { | ||
| 583 | - position: absolute; | ||
| 584 | - bottom: 12px; | ||
| 585 | - right: 12px; | ||
| 586 | - background: #3b82f6 !important; | ||
| 587 | - border-color: #3b82f6 !important; | ||
| 588 | -} | ||
| 589 | - | ||
| 590 | -.comments-list { | ||
| 591 | - space-y: 16px; | ||
| 592 | -} | ||
| 593 | - | ||
| 594 | -.comment-item { | ||
| 595 | - display: flex; | ||
| 596 | - gap: 12px; | ||
| 597 | - padding: 16px 0; | ||
| 598 | - border-bottom: 1px solid #f0f0f0; | ||
| 599 | -} | ||
| 600 | - | ||
| 601 | -.comment-item:last-child { | ||
| 602 | - border-bottom: none; | ||
| 603 | -} | ||
| 604 | - | ||
| 605 | -.comment-avatar { | ||
| 606 | - width: 40px; | ||
| 607 | - height: 40px; | ||
| 608 | - border-radius: 50%; | ||
| 609 | - overflow: hidden; | ||
| 610 | - flex-shrink: 0; | ||
| 611 | -} | ||
| 612 | - | ||
| 613 | -.comment-avatar img { | ||
| 614 | - width: 100%; | ||
| 615 | - height: 100%; | ||
| 616 | - object-fit: cover; | ||
| 617 | -} | ||
| 618 | - | ||
| 619 | -.avatar-placeholder { | ||
| 620 | - width: 100%; | ||
| 621 | - height: 100%; | ||
| 622 | - background: linear-gradient(135deg, #3b82f6, #1d4ed8); | ||
| 623 | - display: flex; | ||
| 624 | - align-items: center; | ||
| 625 | - justify-content: center; | ||
| 626 | - color: white; | ||
| 627 | - font-size: 16px; | ||
| 628 | - font-weight: 600; | ||
| 629 | -} | ||
| 630 | - | ||
| 631 | -.comment-content { | ||
| 632 | - flex: 1; | ||
| 633 | -} | ||
| 634 | - | ||
| 635 | -.comment-header { | ||
| 636 | - display: flex; | ||
| 637 | - justify-content: space-between; | ||
| 638 | - align-items: center; | ||
| 639 | - margin-bottom: 8px; | ||
| 640 | -} | ||
| 641 | - | ||
| 642 | -.comment-author { | ||
| 643 | - font-size: 14px; | ||
| 644 | - font-weight: 500; | ||
| 645 | - color: #333; | ||
| 646 | -} | ||
| 647 | - | ||
| 648 | -.comment-date { | ||
| 649 | - font-size: 12px; | ||
| 650 | - color: #999; | ||
| 651 | -} | ||
| 652 | - | ||
| 653 | -.comment-text { | ||
| 654 | - font-size: 14px; | ||
| 655 | - color: #666; | ||
| 656 | - line-height: 1.6; | ||
| 657 | - margin: 0 0 12px 0; | ||
| 658 | -} | ||
| 659 | - | ||
| 660 | -.comment-actions { | ||
| 661 | - display: flex; | ||
| 662 | - gap: 16px; | ||
| 663 | -} | ||
| 664 | - | ||
| 665 | -.comment-like, | ||
| 666 | -.comment-reply { | ||
| 667 | - display: flex; | ||
| 668 | - align-items: center; | ||
| 669 | - gap: 4px; | ||
| 670 | - font-size: 12px; | ||
| 671 | - color: #999; | ||
| 672 | - cursor: pointer; | ||
| 673 | -} | ||
| 674 | - | ||
| 675 | -.comment-reply:hover { | ||
| 676 | - color: #3b82f6; | ||
| 677 | } | 157 | } |
| 678 | -</style> | ||
| ... | \ No newline at end of file | ... | \ No newline at end of file |
| 158 | +</style> | ... | ... |
src/views/StudentDetail.vue
deleted
100644 → 0
| 1 | -<template> | ||
| 2 | - <div class="page-container"> | ||
| 3 | - <!-- 导航栏 --> | ||
| 4 | - <van-nav-bar title="戒子详情" left-arrow @click-left="$router.back()" class="custom-nav"> | ||
| 5 | - <template #right> | ||
| 6 | - <van-icon name="edit" size="18" @click="handleEdit" /> | ||
| 7 | - </template> | ||
| 8 | - </van-nav-bar> | ||
| 9 | - | ||
| 10 | - <!-- 内容区域 --> | ||
| 11 | - <div class="content-container"> | ||
| 12 | - <!-- 戒子基本信息 --> | ||
| 13 | - <div class="profile-section"> | ||
| 14 | - <div class="profile-header"> | ||
| 15 | - <div class="avatar-container"> | ||
| 16 | - <img v-if="student.avatar" :src="student.avatar" :alt="student.name" class="avatar" /> | ||
| 17 | - <div v-else class="avatar-placeholder"> | ||
| 18 | - <span>{{ student.name.charAt(0) }}</span> | ||
| 19 | - </div> | ||
| 20 | - <div class="precept-badge" :class="getPreceptClass(student.preceptType)"> | ||
| 21 | - {{ getPreceptText(student.preceptType) }} | ||
| 22 | - </div> | ||
| 23 | - </div> | ||
| 24 | - | ||
| 25 | - <div class="profile-info"> | ||
| 26 | - <h2 class="student-name">{{ student.name }}</h2> | ||
| 27 | - <p class="student-dharma-name">法名:{{ student.dharmaName }}</p> | ||
| 28 | - <p class="student-temple">{{ student.temple }}</p> | ||
| 29 | - <div class="status-badge" :class="getStatusClass(student.status)"> | ||
| 30 | - {{ getStatusText(student.status) }} | ||
| 31 | - </div> | ||
| 32 | - </div> | ||
| 33 | - </div> | ||
| 34 | - | ||
| 35 | - <!-- 统计信息 --> | ||
| 36 | - <div class="stats-grid"> | ||
| 37 | - <div class="stat-item"> | ||
| 38 | - <div class="stat-value">{{ student.studyDays }}</div> | ||
| 39 | - <div class="stat-label">学习天数</div> | ||
| 40 | - </div> | ||
| 41 | - <div class="stat-item"> | ||
| 42 | - <div class="stat-value">{{ student.progress }}%</div> | ||
| 43 | - <div class="stat-label">学习进度</div> | ||
| 44 | - </div> | ||
| 45 | - <div class="stat-item"> | ||
| 46 | - <div class="stat-value">{{ student.completedCourses }}</div> | ||
| 47 | - <div class="stat-label">完成课程</div> | ||
| 48 | - </div> | ||
| 49 | - <div class="stat-item"> | ||
| 50 | - <div class="stat-value">{{ student.merits }}</div> | ||
| 51 | - <div class="stat-label">功德积分</div> | ||
| 52 | - </div> | ||
| 53 | - </div> | ||
| 54 | - </div> | ||
| 55 | - | ||
| 56 | - <!-- 详细信息 --> | ||
| 57 | - <div class="details-section"> | ||
| 58 | - <!-- 基本信息 --> | ||
| 59 | - <van-cell-group title="基本信息" class="info-group"> | ||
| 60 | - <van-cell title="戒师" :value="student.teacher" /> | ||
| 61 | - <van-cell title="入学时间" :value="student.entryDate" /> | ||
| 62 | - <van-cell title="预计毕业" :value="student.expectedGraduation" /> | ||
| 63 | - <van-cell title="籍贯" :value="student.hometown" /> | ||
| 64 | - <van-cell title="年龄" :value="student.age + '岁'" /> | ||
| 65 | - </van-cell-group> | ||
| 66 | - | ||
| 67 | - <!-- 学习进度 --> | ||
| 68 | - <div class="progress-section"> | ||
| 69 | - <h3 class="section-title">学习进度</h3> | ||
| 70 | - <div class="progress-card"> | ||
| 71 | - <div class="progress-header"> | ||
| 72 | - <span class="progress-text">总体进度</span> | ||
| 73 | - <span class="progress-percent">{{ student.progress }}%</span> | ||
| 74 | - </div> | ||
| 75 | - <van-progress :percentage="student.progress" color="#8b5cf6" /> | ||
| 76 | - </div> | ||
| 77 | - | ||
| 78 | - <div class="course-list"> | ||
| 79 | - <div | ||
| 80 | - v-for="course in student.courses" | ||
| 81 | - :key="course.id" | ||
| 82 | - class="course-item" | ||
| 83 | - > | ||
| 84 | - <div class="course-info"> | ||
| 85 | - <h4 class="course-name">{{ course.name }}</h4> | ||
| 86 | - <p class="course-teacher">授课法师:{{ course.teacher }}</p> | ||
| 87 | - </div> | ||
| 88 | - <div class="course-progress"> | ||
| 89 | - <div class="course-status" :class="getCourseStatusClass(course.status)"> | ||
| 90 | - {{ getCourseStatusText(course.status) }} | ||
| 91 | - </div> | ||
| 92 | - <div class="course-score" v-if="course.score"> | ||
| 93 | - {{ course.score }}分 | ||
| 94 | - </div> | ||
| 95 | - </div> | ||
| 96 | - </div> | ||
| 97 | - </div> | ||
| 98 | - </div> | ||
| 99 | - | ||
| 100 | - <!-- 戒律修学记录 --> | ||
| 101 | - <div class="records-section"> | ||
| 102 | - <h3 class="section-title">修学记录</h3> | ||
| 103 | - <van-timeline> | ||
| 104 | - <van-timeline-item | ||
| 105 | - v-for="record in student.studyRecords" | ||
| 106 | - :key="record.id" | ||
| 107 | - :time="record.date" | ||
| 108 | - > | ||
| 109 | - <div class="record-content"> | ||
| 110 | - <h4 class="record-title">{{ record.title }}</h4> | ||
| 111 | - <p class="record-description">{{ record.description }}</p> | ||
| 112 | - <div class="record-tags"> | ||
| 113 | - <van-tag | ||
| 114 | - v-for="tag in record.tags" | ||
| 115 | - :key="tag" | ||
| 116 | - type="primary" | ||
| 117 | - size="small" | ||
| 118 | - class="record-tag" | ||
| 119 | - > | ||
| 120 | - {{ tag }} | ||
| 121 | - </van-tag> | ||
| 122 | - </div> | ||
| 123 | - </div> | ||
| 124 | - </van-timeline-item> | ||
| 125 | - </van-timeline> | ||
| 126 | - </div> | ||
| 127 | - | ||
| 128 | - <!-- 联系方式 --> | ||
| 129 | - <van-cell-group title="联系方式" class="info-group"> | ||
| 130 | - <van-cell title="手机号码" :value="student.phone" /> | ||
| 131 | - <van-cell title="紧急联系人" :value="student.emergencyContact" /> | ||
| 132 | - <van-cell title="紧急联系电话" :value="student.emergencyPhone" /> | ||
| 133 | - </van-cell-group> | ||
| 134 | - </div> | ||
| 135 | - </div> | ||
| 136 | - </div> | ||
| 137 | -</template> | ||
| 138 | - | ||
| 139 | -<script setup> | ||
| 140 | -import { ref, onMounted } from 'vue' | ||
| 141 | -import { useRoute, useRouter } from 'vue-router' | ||
| 142 | -import { Toast } from 'vant' | ||
| 143 | - | ||
| 144 | -const route = useRoute() | ||
| 145 | -const router = useRouter() | ||
| 146 | - | ||
| 147 | -// 戒子详细信息 | ||
| 148 | -const student = ref({ | ||
| 149 | - id: 1, | ||
| 150 | - name: '释慧明', | ||
| 151 | - dharmaName: '慧明', | ||
| 152 | - temple: '大雄宝殿', | ||
| 153 | - teacher: '释智慧法师', | ||
| 154 | - preceptType: 'bhiksu', | ||
| 155 | - status: 'studying', | ||
| 156 | - entryDate: '2023-03-15', | ||
| 157 | - expectedGraduation: '2024-03-15', | ||
| 158 | - hometown: '江苏南京', | ||
| 159 | - age: 28, | ||
| 160 | - studyDays: 285, | ||
| 161 | - progress: 75, | ||
| 162 | - completedCourses: 12, | ||
| 163 | - merits: 1580, | ||
| 164 | - phone: '138****8888', | ||
| 165 | - emergencyContact: '张居士', | ||
| 166 | - emergencyPhone: '139****9999', | ||
| 167 | - avatar: null, | ||
| 168 | - courses: [ | ||
| 169 | - { | ||
| 170 | - id: 1, | ||
| 171 | - name: '沙弥律仪', | ||
| 172 | - teacher: '释智慧法师', | ||
| 173 | - status: 'completed', | ||
| 174 | - score: 95 | ||
| 175 | - }, | ||
| 176 | - { | ||
| 177 | - id: 2, | ||
| 178 | - name: '比丘戒本', | ||
| 179 | - teacher: '释慈悲法师', | ||
| 180 | - status: 'studying', | ||
| 181 | - score: null | ||
| 182 | - }, | ||
| 183 | - { | ||
| 184 | - id: 3, | ||
| 185 | - name: '戒律学纲要', | ||
| 186 | - teacher: '释般若法师', | ||
| 187 | - status: 'completed', | ||
| 188 | - score: 88 | ||
| 189 | - }, | ||
| 190 | - { | ||
| 191 | - id: 4, | ||
| 192 | - name: '四分律删繁补阙行事钞', | ||
| 193 | - teacher: '释智慧法师', | ||
| 194 | - status: 'pending', | ||
| 195 | - score: null | ||
| 196 | - } | ||
| 197 | - ], | ||
| 198 | - studyRecords: [ | ||
| 199 | - { | ||
| 200 | - id: 1, | ||
| 201 | - date: '2024-01-15', | ||
| 202 | - title: '完成沙弥律仪考试', | ||
| 203 | - description: '以优异成绩通过沙弥律仪课程考试,获得95分', | ||
| 204 | - tags: ['考试', '沙弥律仪', '优秀'] | ||
| 205 | - }, | ||
| 206 | - { | ||
| 207 | - id: 2, | ||
| 208 | - date: '2024-01-10', | ||
| 209 | - title: '参加戒律研讨会', | ||
| 210 | - description: '积极参与戒律研讨,发表见解,获得法师好评', | ||
| 211 | - tags: ['研讨会', '戒律', '积极参与'] | ||
| 212 | - }, | ||
| 213 | - { | ||
| 214 | - id: 3, | ||
| 215 | - date: '2024-01-05', | ||
| 216 | - title: '开始比丘戒本学习', | ||
| 217 | - description: '正式开始比丘戒本课程的学习,制定详细学习计划', | ||
| 218 | - tags: ['比丘戒', '学习计划'] | ||
| 219 | - }, | ||
| 220 | - { | ||
| 221 | - id: 4, | ||
| 222 | - date: '2023-12-20', | ||
| 223 | - title: '戒律学纲要结业', | ||
| 224 | - description: '完成戒律学纲要课程,掌握戒律基本理论', | ||
| 225 | - tags: ['结业', '戒律学', '理论'] | ||
| 226 | - } | ||
| 227 | - ] | ||
| 228 | -}) | ||
| 229 | - | ||
| 230 | -// 获取戒律类型样式类 | ||
| 231 | -const getPreceptClass = (type) => { | ||
| 232 | - const classes = { | ||
| 233 | - novice: 'precept-novice', | ||
| 234 | - bhiksu: 'precept-bhiksu', | ||
| 235 | - bodhisattva: 'precept-bodhisattva' | ||
| 236 | - } | ||
| 237 | - return classes[type] || 'precept-novice' | ||
| 238 | -} | ||
| 239 | - | ||
| 240 | -// 获取戒律类型文本 | ||
| 241 | -const getPreceptText = (type) => { | ||
| 242 | - const texts = { | ||
| 243 | - novice: '沙弥戒', | ||
| 244 | - bhiksu: '比丘戒', | ||
| 245 | - bodhisattva: '菩萨戒' | ||
| 246 | - } | ||
| 247 | - return texts[type] || '沙弥戒' | ||
| 248 | -} | ||
| 249 | - | ||
| 250 | -// 获取状态样式类 | ||
| 251 | -const getStatusClass = (status) => { | ||
| 252 | - const classes = { | ||
| 253 | - studying: 'status-studying', | ||
| 254 | - graduated: 'status-graduated', | ||
| 255 | - suspended: 'status-suspended' | ||
| 256 | - } | ||
| 257 | - return classes[status] || 'status-studying' | ||
| 258 | -} | ||
| 259 | - | ||
| 260 | -// 获取状态文本 | ||
| 261 | -const getStatusText = (status) => { | ||
| 262 | - const texts = { | ||
| 263 | - studying: '在学', | ||
| 264 | - graduated: '毕业', | ||
| 265 | - suspended: '暂停' | ||
| 266 | - } | ||
| 267 | - return texts[status] || '在学' | ||
| 268 | -} | ||
| 269 | - | ||
| 270 | -// 获取课程状态样式类 | ||
| 271 | -const getCourseStatusClass = (status) => { | ||
| 272 | - const classes = { | ||
| 273 | - completed: 'course-completed', | ||
| 274 | - studying: 'course-studying', | ||
| 275 | - pending: 'course-pending' | ||
| 276 | - } | ||
| 277 | - return classes[status] || 'course-pending' | ||
| 278 | -} | ||
| 279 | - | ||
| 280 | -// 获取课程状态文本 | ||
| 281 | -const getCourseStatusText = (status) => { | ||
| 282 | - const texts = { | ||
| 283 | - completed: '已完成', | ||
| 284 | - studying: '学习中', | ||
| 285 | - pending: '未开始' | ||
| 286 | - } | ||
| 287 | - return texts[status] || '未开始' | ||
| 288 | -} | ||
| 289 | - | ||
| 290 | -// 处理编辑 | ||
| 291 | -const handleEdit = () => { | ||
| 292 | - Toast('编辑功能开发中...') | ||
| 293 | -} | ||
| 294 | - | ||
| 295 | -// 组件挂载时加载数据 | ||
| 296 | -onMounted(() => { | ||
| 297 | - // 这里可以根据路由参数加载具体的戒子数据 | ||
| 298 | - const studentId = route.params.id | ||
| 299 | - console.log('Loading student data for ID:', studentId) | ||
| 300 | -}) | ||
| 301 | -</script> | ||
| 302 | - | ||
| 303 | -<style scoped> | ||
| 304 | -.page-container { | ||
| 305 | - min-height: 100vh; | ||
| 306 | - background: #fafafa; | ||
| 307 | -} | ||
| 308 | - | ||
| 309 | -.custom-nav { | ||
| 310 | - background: linear-gradient(135deg, #8b5cf6, #7c3aed); | ||
| 311 | - color: white; | ||
| 312 | -} | ||
| 313 | - | ||
| 314 | -.custom-nav :deep(.van-nav-bar__title) { | ||
| 315 | - color: white; | ||
| 316 | - font-weight: 600; | ||
| 317 | -} | ||
| 318 | - | ||
| 319 | -.custom-nav :deep(.van-icon) { | ||
| 320 | - color: white; | ||
| 321 | -} | ||
| 322 | - | ||
| 323 | -.content-container { | ||
| 324 | - padding-top: 46px; | ||
| 325 | -} | ||
| 326 | - | ||
| 327 | -.profile-section { | ||
| 328 | - background: white; | ||
| 329 | - padding: 20px; | ||
| 330 | - margin-bottom: 12px; | ||
| 331 | -} | ||
| 332 | - | ||
| 333 | -.profile-header { | ||
| 334 | - display: flex; | ||
| 335 | - align-items: center; | ||
| 336 | - margin-bottom: 20px; | ||
| 337 | -} | ||
| 338 | - | ||
| 339 | -.avatar-container { | ||
| 340 | - position: relative; | ||
| 341 | - width: 80px; | ||
| 342 | - height: 80px; | ||
| 343 | - border-radius: 50%; | ||
| 344 | - overflow: hidden; | ||
| 345 | - margin-right: 20px; | ||
| 346 | - flex-shrink: 0; | ||
| 347 | -} | ||
| 348 | - | ||
| 349 | -.avatar { | ||
| 350 | - width: 100%; | ||
| 351 | - height: 100%; | ||
| 352 | - object-fit: cover; | ||
| 353 | -} | ||
| 354 | - | ||
| 355 | -.avatar-placeholder { | ||
| 356 | - width: 100%; | ||
| 357 | - height: 100%; | ||
| 358 | - background: linear-gradient(135deg, #8b5cf6, #7c3aed); | ||
| 359 | - display: flex; | ||
| 360 | - align-items: center; | ||
| 361 | - justify-content: center; | ||
| 362 | - color: white; | ||
| 363 | - font-size: 32px; | ||
| 364 | - font-weight: 600; | ||
| 365 | -} | ||
| 366 | - | ||
| 367 | -.precept-badge { | ||
| 368 | - position: absolute; | ||
| 369 | - bottom: -2px; | ||
| 370 | - right: -2px; | ||
| 371 | - padding: 4px 8px; | ||
| 372 | - border-radius: 12px; | ||
| 373 | - font-size: 10px; | ||
| 374 | - font-weight: 500; | ||
| 375 | - border: 2px solid white; | ||
| 376 | -} | ||
| 377 | - | ||
| 378 | -.precept-novice { | ||
| 379 | - background: #10b981; | ||
| 380 | - color: white; | ||
| 381 | -} | ||
| 382 | - | ||
| 383 | -.precept-bhiksu { | ||
| 384 | - background: #3b82f6; | ||
| 385 | - color: white; | ||
| 386 | -} | ||
| 387 | - | ||
| 388 | -.precept-bodhisattva { | ||
| 389 | - background: #f59e0b; | ||
| 390 | - color: white; | ||
| 391 | -} | ||
| 392 | - | ||
| 393 | -.profile-info { | ||
| 394 | - flex: 1; | ||
| 395 | -} | ||
| 396 | - | ||
| 397 | -.student-name { | ||
| 398 | - font-size: 24px; | ||
| 399 | - font-weight: 700; | ||
| 400 | - color: #333; | ||
| 401 | - margin: 0 0 8px 0; | ||
| 402 | -} | ||
| 403 | - | ||
| 404 | -.student-dharma-name { | ||
| 405 | - font-size: 16px; | ||
| 406 | - color: #666; | ||
| 407 | - margin: 0 0 4px 0; | ||
| 408 | -} | ||
| 409 | - | ||
| 410 | -.student-temple { | ||
| 411 | - font-size: 16px; | ||
| 412 | - color: #666; | ||
| 413 | - margin: 0 0 12px 0; | ||
| 414 | -} | ||
| 415 | - | ||
| 416 | -.status-badge { | ||
| 417 | - display: inline-block; | ||
| 418 | - padding: 6px 12px; | ||
| 419 | - border-radius: 16px; | ||
| 420 | - font-size: 12px; | ||
| 421 | - font-weight: 500; | ||
| 422 | -} | ||
| 423 | - | ||
| 424 | -.status-studying { | ||
| 425 | - background: #dbeafe; | ||
| 426 | - color: #1d4ed8; | ||
| 427 | - border: 1px solid #93c5fd; | ||
| 428 | -} | ||
| 429 | - | ||
| 430 | -.status-graduated { | ||
| 431 | - background: #dcfce7; | ||
| 432 | - color: #166534; | ||
| 433 | - border: 1px solid #86efac; | ||
| 434 | -} | ||
| 435 | - | ||
| 436 | -.status-suspended { | ||
| 437 | - background: #fef3c7; | ||
| 438 | - color: #92400e; | ||
| 439 | - border: 1px solid #fcd34d; | ||
| 440 | -} | ||
| 441 | - | ||
| 442 | -.stats-grid { | ||
| 443 | - display: grid; | ||
| 444 | - grid-template-columns: repeat(4, 1fr); | ||
| 445 | - gap: 16px; | ||
| 446 | -} | ||
| 447 | - | ||
| 448 | -.stat-item { | ||
| 449 | - text-align: center; | ||
| 450 | -} | ||
| 451 | - | ||
| 452 | -.stat-value { | ||
| 453 | - font-size: 20px; | ||
| 454 | - font-weight: 700; | ||
| 455 | - color: #8b5cf6; | ||
| 456 | - margin-bottom: 4px; | ||
| 457 | -} | ||
| 458 | - | ||
| 459 | -.stat-label { | ||
| 460 | - font-size: 12px; | ||
| 461 | - color: #666; | ||
| 462 | -} | ||
| 463 | - | ||
| 464 | -.details-section { | ||
| 465 | - padding: 0 16px 20px; | ||
| 466 | -} | ||
| 467 | - | ||
| 468 | -.info-group { | ||
| 469 | - margin-bottom: 16px; | ||
| 470 | -} | ||
| 471 | - | ||
| 472 | -.info-group :deep(.van-cell-group__title) { | ||
| 473 | - color: #333; | ||
| 474 | - font-weight: 600; | ||
| 475 | -} | ||
| 476 | - | ||
| 477 | -.section-title { | ||
| 478 | - font-size: 18px; | ||
| 479 | - font-weight: 600; | ||
| 480 | - color: #333; | ||
| 481 | - margin: 20px 0 16px 0; | ||
| 482 | - padding-left: 4px; | ||
| 483 | - border-left: 4px solid #8b5cf6; | ||
| 484 | -} | ||
| 485 | - | ||
| 486 | -.progress-section { | ||
| 487 | - background: white; | ||
| 488 | - border-radius: 12px; | ||
| 489 | - padding: 20px; | ||
| 490 | - margin-bottom: 16px; | ||
| 491 | -} | ||
| 492 | - | ||
| 493 | -.progress-card { | ||
| 494 | - background: #f8fafc; | ||
| 495 | - border-radius: 8px; | ||
| 496 | - padding: 16px; | ||
| 497 | - margin-bottom: 20px; | ||
| 498 | -} | ||
| 499 | - | ||
| 500 | -.progress-header { | ||
| 501 | - display: flex; | ||
| 502 | - justify-content: space-between; | ||
| 503 | - align-items: center; | ||
| 504 | - margin-bottom: 12px; | ||
| 505 | -} | ||
| 506 | - | ||
| 507 | -.progress-text { | ||
| 508 | - font-size: 16px; | ||
| 509 | - font-weight: 500; | ||
| 510 | - color: #333; | ||
| 511 | -} | ||
| 512 | - | ||
| 513 | -.progress-percent { | ||
| 514 | - font-size: 18px; | ||
| 515 | - font-weight: 700; | ||
| 516 | - color: #8b5cf6; | ||
| 517 | -} | ||
| 518 | - | ||
| 519 | -.course-list { | ||
| 520 | - space-y: 12px; | ||
| 521 | -} | ||
| 522 | - | ||
| 523 | -.course-item { | ||
| 524 | - display: flex; | ||
| 525 | - justify-content: space-between; | ||
| 526 | - align-items: center; | ||
| 527 | - padding: 16px; | ||
| 528 | - background: #f8fafc; | ||
| 529 | - border-radius: 8px; | ||
| 530 | - margin-bottom: 12px; | ||
| 531 | -} | ||
| 532 | - | ||
| 533 | -.course-info { | ||
| 534 | - flex: 1; | ||
| 535 | -} | ||
| 536 | - | ||
| 537 | -.course-name { | ||
| 538 | - font-size: 16px; | ||
| 539 | - font-weight: 600; | ||
| 540 | - color: #333; | ||
| 541 | - margin: 0 0 4px 0; | ||
| 542 | -} | ||
| 543 | - | ||
| 544 | -.course-teacher { | ||
| 545 | - font-size: 14px; | ||
| 546 | - color: #666; | ||
| 547 | - margin: 0; | ||
| 548 | -} | ||
| 549 | - | ||
| 550 | -.course-progress { | ||
| 551 | - display: flex; | ||
| 552 | - flex-direction: column; | ||
| 553 | - align-items: flex-end; | ||
| 554 | - gap: 4px; | ||
| 555 | -} | ||
| 556 | - | ||
| 557 | -.course-status { | ||
| 558 | - padding: 4px 8px; | ||
| 559 | - border-radius: 12px; | ||
| 560 | - font-size: 12px; | ||
| 561 | - font-weight: 500; | ||
| 562 | -} | ||
| 563 | - | ||
| 564 | -.course-completed { | ||
| 565 | - background: #dcfce7; | ||
| 566 | - color: #166534; | ||
| 567 | -} | ||
| 568 | - | ||
| 569 | -.course-studying { | ||
| 570 | - background: #dbeafe; | ||
| 571 | - color: #1d4ed8; | ||
| 572 | -} | ||
| 573 | - | ||
| 574 | -.course-pending { | ||
| 575 | - background: #f3f4f6; | ||
| 576 | - color: #6b7280; | ||
| 577 | -} | ||
| 578 | - | ||
| 579 | -.course-score { | ||
| 580 | - font-size: 14px; | ||
| 581 | - font-weight: 600; | ||
| 582 | - color: #8b5cf6; | ||
| 583 | -} | ||
| 584 | - | ||
| 585 | -.records-section { | ||
| 586 | - background: white; | ||
| 587 | - border-radius: 12px; | ||
| 588 | - padding: 20px; | ||
| 589 | - margin-bottom: 16px; | ||
| 590 | -} | ||
| 591 | - | ||
| 592 | -.record-content { | ||
| 593 | - padding-left: 16px; | ||
| 594 | -} | ||
| 595 | - | ||
| 596 | -.record-title { | ||
| 597 | - font-size: 16px; | ||
| 598 | - font-weight: 600; | ||
| 599 | - color: #333; | ||
| 600 | - margin: 0 0 8px 0; | ||
| 601 | -} | ||
| 602 | - | ||
| 603 | -.record-description { | ||
| 604 | - font-size: 14px; | ||
| 605 | - color: #666; | ||
| 606 | - margin: 0 0 12px 0; | ||
| 607 | - line-height: 1.5; | ||
| 608 | -} | ||
| 609 | - | ||
| 610 | -.record-tags { | ||
| 611 | - display: flex; | ||
| 612 | - gap: 8px; | ||
| 613 | - flex-wrap: wrap; | ||
| 614 | -} | ||
| 615 | - | ||
| 616 | -.record-tag { | ||
| 617 | - background: #f3e8ff !important; | ||
| 618 | - color: #8b5cf6 !important; | ||
| 619 | - border: 1px solid #c4b5fd !important; | ||
| 620 | -} | ||
| 621 | -</style> | ||
| ... | \ No newline at end of file | ... | \ No newline at end of file |
| 1 | +<!-- | ||
| 2 | + * @Date: 2025-10-30 20:52:19 | ||
| 3 | + * @LastEditors: hookehuyr hookehuyr@gmail.com | ||
| 4 | + * @LastEditTime: 2025-10-30 21:22:42 | ||
| 5 | + * @FilePath: /stdj_h5/src/views/Students.vue | ||
| 6 | + * @Description: 戒子页面 - 图片瀑布流展示 | ||
| 7 | +--> | ||
| 8 | + | ||
| 1 | <template> | 9 | <template> |
| 2 | - <div class="page-container"> | 10 | + <div class="students-container"> |
| 3 | - <!-- 导航栏 --> | 11 | + <!-- 瀑布流内容 --> |
| 4 | - <van-nav-bar title="戒子管理" left-arrow @click-left="$router.back()" class="custom-nav"> | 12 | + <div class="waterfall-content"> |
| 5 | - <template #right> | 13 | + <van-list |
| 6 | - <van-icon name="search" size="18" @click="handleSearch" /> | 14 | + v-model:loading="loading" |
| 7 | - </template> | 15 | + :finished="finished" |
| 8 | - </van-nav-bar> | 16 | + finished-text="没有更多了" |
| 9 | - | 17 | + @load="onLoad" |
| 10 | - <!-- 内容区域 --> | 18 | + > |
| 11 | - <div class="content-container"> | 19 | + <div class="waterfall-container"> |
| 12 | - <!-- 顶部统计 --> | 20 | + <div class="waterfall-column" v-for="(column, index) in columns" :key="index"> |
| 13 | - <div class="stats-section"> | 21 | + <div |
| 14 | - <div class="stat-card"> | 22 | + class="waterfall-item" |
| 15 | - <div class="stat-icon">🙏</div> | 23 | + v-for="item in column" |
| 16 | - <div class="stat-info"> | 24 | + :key="item.id" |
| 17 | - <div class="stat-number">{{ totalStudents }}</div> | 25 | + @click="onImageClick(item)" |
| 18 | - <div class="stat-label">总戒子数</div> | 26 | + > |
| 27 | + <div class="image-wrapper"> | ||
| 28 | + <img | ||
| 29 | + :src="item.url" | ||
| 30 | + :alt="item.title" | ||
| 31 | + :style="{ height: item.height + 'px' }" | ||
| 32 | + @load="onImageLoad" | ||
| 33 | + @error="onImageError" | ||
| 34 | + /> | ||
| 35 | + <div class="image-overlay"> | ||
| 36 | + <span class="image-title">{{ item.title }}</span> | ||
| 37 | + </div> | ||
| 38 | + </div> | ||
| 39 | + </div> | ||
| 19 | </div> | 40 | </div> |
| 20 | </div> | 41 | </div> |
| 21 | - <div class="stat-card"> | 42 | + </van-list> |
| 22 | - <div class="stat-icon">📚</div> | 43 | + </div> |
| 23 | - <div class="stat-info"> | 44 | + |
| 24 | - <div class="stat-number">{{ studyingStudents }}</div> | 45 | + <!-- 遮罩层弹窗 --> |
| 25 | - <div class="stat-label">在学戒子</div> | 46 | + <van-overlay :show="showOverlay" @click="closeOverlay"> |
| 26 | - </div> | 47 | + <div class="overlay-content" @click.stop> |
| 48 | + <!-- 关闭按钮 --> | ||
| 49 | + <div class="close-btn" @click="closeOverlay"> | ||
| 50 | + <van-icon name="cross" size="1.5rem" color="#fff" /> | ||
| 27 | </div> | 51 | </div> |
| 28 | - <div class="stat-card"> | 52 | + |
| 29 | - <div class="stat-icon">🎓</div> | 53 | + <!-- 图片展示 --> |
| 30 | - <div class="stat-info"> | 54 | + <div class="overlay-image-wrapper"> |
| 31 | - <div class="stat-number">{{ graduatedStudents }}</div> | 55 | + <img |
| 32 | - <div class="stat-label">已毕业</div> | 56 | + :src="selectedImage?.url" |
| 33 | - </div> | 57 | + :alt="selectedImage?.title" |
| 58 | + class="overlay-image" | ||
| 59 | + /> | ||
| 34 | </div> | 60 | </div> |
| 35 | - </div> | 61 | + |
| 36 | - | 62 | + <!-- 描述内容 --> |
| 37 | - <!-- 筛选栏 --> | 63 | + <div class="overlay-description"> |
| 38 | - <div class="filter-section"> | 64 | + <h3 class="overlay-title">{{ selectedImage?.title }}</h3> |
| 39 | - <van-tabs v-model:active="activeTab" @change="handleTabChange" class="custom-tabs"> | 65 | + <p class="overlay-text">{{ selectedImage?.description }}</p> |
| 40 | - <van-tab title="全部" name="all"></van-tab> | ||
| 41 | - <van-tab title="沙弥戒" name="novice"></van-tab> | ||
| 42 | - <van-tab title="比丘戒" name="bhiksu"></van-tab> | ||
| 43 | - <van-tab title="菩萨戒" name="bodhisattva"></van-tab> | ||
| 44 | - </van-tabs> | ||
| 45 | - </div> | ||
| 46 | - | ||
| 47 | - <!-- 戒子列表 --> | ||
| 48 | - <div class="students-list"> | ||
| 49 | - <div | ||
| 50 | - v-for="student in filteredStudents" | ||
| 51 | - :key="student.id" | ||
| 52 | - class="student-card" | ||
| 53 | - @click="handleStudentClick(student)" | ||
| 54 | - > | ||
| 55 | - <div class="student-avatar"> | ||
| 56 | - <img v-if="student.avatar" :src="student.avatar" :alt="student.name" /> | ||
| 57 | - <div v-else class="avatar-placeholder"> | ||
| 58 | - <span>{{ student.name.charAt(0) }}</span> | ||
| 59 | - </div> | ||
| 60 | - <div class="precept-badge" :class="getPreceptClass(student.preceptType)"> | ||
| 61 | - {{ getPreceptText(student.preceptType) }} | ||
| 62 | - </div> | ||
| 63 | - </div> | ||
| 64 | - | ||
| 65 | - <div class="student-info"> | ||
| 66 | - <div class="student-header"> | ||
| 67 | - <h4 class="student-name">{{ student.name }}</h4> | ||
| 68 | - <div class="student-status" :class="getStatusClass(student.status)"> | ||
| 69 | - {{ getStatusText(student.status) }} | ||
| 70 | - </div> | ||
| 71 | - </div> | ||
| 72 | - | ||
| 73 | - <div class="student-details"> | ||
| 74 | - <p class="student-temple">{{ student.temple }}</p> | ||
| 75 | - <p class="student-teacher">戒师:{{ student.teacher }}</p> | ||
| 76 | - <div class="student-meta"> | ||
| 77 | - <span class="entry-date">{{ student.entryDate }}入学</span> | ||
| 78 | - <span class="progress">进度:{{ student.progress }}%</span> | ||
| 79 | - </div> | ||
| 80 | - </div> | ||
| 81 | - </div> | ||
| 82 | - | ||
| 83 | - <div class="student-actions"> | ||
| 84 | - <van-icon name="arrow" /> | ||
| 85 | - </div> | ||
| 86 | </div> | 66 | </div> |
| 87 | </div> | 67 | </div> |
| 88 | - | 68 | + </van-overlay> |
| 89 | - <!-- 空状态 --> | ||
| 90 | - <van-empty v-if="filteredStudents.length === 0" description="暂无戒子信息" /> | ||
| 91 | - </div> | ||
| 92 | </div> | 69 | </div> |
| 93 | </template> | 70 | </template> |
| 94 | 71 | ||
| 95 | <script setup> | 72 | <script setup> |
| 96 | -import { ref, computed } from 'vue' | 73 | +import { ref, reactive, onMounted } from 'vue' |
| 97 | -import { useRouter } from 'vue-router' | 74 | +import { generateWaterfallData } from '@/utils/mockData' |
| 98 | -import { Toast } from 'vant' | 75 | +import { useTitle } from '@vueuse/core'; |
| 99 | - | 76 | + |
| 100 | -const router = useRouter() | 77 | +useTitle('同戒录') |
| 101 | -const activeTab = ref('all') | 78 | + |
| 102 | - | 79 | +// 响应式数据 |
| 103 | -// 统计数据 | 80 | +const loading = ref(false) |
| 104 | -const totalStudents = ref(68) | 81 | +const finished = ref(false) |
| 105 | -const studyingStudents = ref(52) | 82 | +const currentPage = ref(1) |
| 106 | -const graduatedStudents = ref(16) | 83 | +const pageSize = 10 |
| 107 | - | 84 | +const allImages = ref([]) |
| 108 | -// 戒子数据 | 85 | +const columns = reactive([[], []]) |
| 109 | -const students = ref([ | 86 | + |
| 110 | - { | 87 | +// 遮罩层相关状态 |
| 111 | - id: 1, | 88 | +const showOverlay = ref(false) |
| 112 | - name: '释慧明', | 89 | +const selectedImage = ref(null) |
| 113 | - temple: '大雄宝殿', | 90 | + |
| 114 | - teacher: '释智慧法师', | 91 | +// 加载数据 |
| 115 | - preceptType: 'bhiksu', | 92 | +const onLoad = async () => { |
| 116 | - status: 'studying', | 93 | + loading.value = true |
| 117 | - entryDate: '2023-03-15', | 94 | + |
| 118 | - progress: 75, | 95 | + // 模拟网络延迟 |
| 119 | - avatar: null | 96 | + await new Promise(resolve => setTimeout(resolve, 1000)) |
| 120 | - }, | 97 | + |
| 121 | - { | 98 | + try { |
| 122 | - id: 2, | 99 | + const newData = generateWaterfallData(currentPage.value, pageSize) |
| 123 | - name: '释德行', | 100 | + |
| 124 | - temple: '观音殿', | 101 | + if (newData.length === 0) { |
| 125 | - teacher: '释慈悲法师', | 102 | + finished.value = true |
| 126 | - preceptType: 'novice', | 103 | + } else { |
| 127 | - status: 'studying', | 104 | + allImages.value.push(...newData) |
| 128 | - entryDate: '2023-06-20', | 105 | + distributeImages(newData) |
| 129 | - progress: 45, | 106 | + currentPage.value++ |
| 130 | - avatar: null | 107 | + } |
| 131 | - }, | 108 | + } catch (error) { |
| 132 | - { | 109 | + console.error('加载数据失败:', error) |
| 133 | - id: 3, | 110 | + } finally { |
| 134 | - name: '释觉悟', | 111 | + loading.value = false |
| 135 | - temple: '文殊殿', | ||
| 136 | - teacher: '释般若法师', | ||
| 137 | - preceptType: 'bodhisattva', | ||
| 138 | - status: 'graduated', | ||
| 139 | - entryDate: '2022-09-10', | ||
| 140 | - progress: 100, | ||
| 141 | - avatar: null | ||
| 142 | - }, | ||
| 143 | - { | ||
| 144 | - id: 4, | ||
| 145 | - name: '释持戒', | ||
| 146 | - temple: '地藏殿', | ||
| 147 | - teacher: '释智慧法师', | ||
| 148 | - preceptType: 'bhiksu', | ||
| 149 | - status: 'studying', | ||
| 150 | - entryDate: '2023-01-05', | ||
| 151 | - progress: 85, | ||
| 152 | - avatar: null | ||
| 153 | - }, | ||
| 154 | - { | ||
| 155 | - id: 5, | ||
| 156 | - name: '释精进', | ||
| 157 | - temple: '药师殿', | ||
| 158 | - teacher: '释慈悲法师', | ||
| 159 | - preceptType: 'novice', | ||
| 160 | - status: 'studying', | ||
| 161 | - entryDate: '2023-08-12', | ||
| 162 | - progress: 30, | ||
| 163 | - avatar: null | ||
| 164 | - }, | ||
| 165 | - { | ||
| 166 | - id: 6, | ||
| 167 | - name: '释忍辱', | ||
| 168 | - temple: '弥勒殿', | ||
| 169 | - teacher: '释般若法师', | ||
| 170 | - preceptType: 'bodhisattva', | ||
| 171 | - status: 'studying', | ||
| 172 | - entryDate: '2023-04-18', | ||
| 173 | - progress: 60, | ||
| 174 | - avatar: null | ||
| 175 | - }, | ||
| 176 | - { | ||
| 177 | - id: 7, | ||
| 178 | - name: '释禅定', | ||
| 179 | - temple: '韦陀殿', | ||
| 180 | - teacher: '释智慧法师', | ||
| 181 | - preceptType: 'bhiksu', | ||
| 182 | - status: 'graduated', | ||
| 183 | - entryDate: '2022-11-30', | ||
| 184 | - progress: 100, | ||
| 185 | - avatar: null | ||
| 186 | - }, | ||
| 187 | - { | ||
| 188 | - id: 8, | ||
| 189 | - name: '释智慧', | ||
| 190 | - temple: '伽蓝殿', | ||
| 191 | - teacher: '释慈悲法师', | ||
| 192 | - preceptType: 'novice', | ||
| 193 | - status: 'studying', | ||
| 194 | - entryDate: '2023-07-08', | ||
| 195 | - progress: 40, | ||
| 196 | - avatar: null | ||
| 197 | - } | ||
| 198 | -]) | ||
| 199 | - | ||
| 200 | -// 过滤后的戒子列表 | ||
| 201 | -const filteredStudents = computed(() => { | ||
| 202 | - if (activeTab.value === 'all') { | ||
| 203 | - return students.value | ||
| 204 | - } | ||
| 205 | - return students.value.filter(student => student.preceptType === activeTab.value) | ||
| 206 | -}) | ||
| 207 | - | ||
| 208 | -// 获取戒律类型样式类 | ||
| 209 | -const getPreceptClass = (type) => { | ||
| 210 | - const classes = { | ||
| 211 | - novice: 'precept-novice', | ||
| 212 | - bhiksu: 'precept-bhiksu', | ||
| 213 | - bodhisattva: 'precept-bodhisattva' | ||
| 214 | } | 112 | } |
| 215 | - return classes[type] || 'precept-novice' | ||
| 216 | } | 113 | } |
| 217 | 114 | ||
| 218 | -// 获取戒律类型文本 | 115 | +// 分配图片到两列 |
| 219 | -const getPreceptText = (type) => { | 116 | +const distributeImages = (images) => { |
| 220 | - const texts = { | 117 | + images.forEach(image => { |
| 221 | - novice: '沙弥', | 118 | + // 计算两列的当前高度 |
| 222 | - bhiksu: '比丘', | 119 | + const leftHeight = columns[0].reduce((sum, item) => sum + item.height + 20, 0) |
| 223 | - bodhisattva: '菩萨' | 120 | + const rightHeight = columns[1].reduce((sum, item) => sum + item.height + 20, 0) |
| 224 | - } | ||
| 225 | - return texts[type] || '沙弥' | ||
| 226 | -} | ||
| 227 | 121 | ||
| 228 | -// 获取状态样式类 | 122 | + // 将图片添加到高度较小的列 |
| 229 | -const getStatusClass = (status) => { | 123 | + if (leftHeight <= rightHeight) { |
| 230 | - const classes = { | 124 | + columns[0].push(image) |
| 231 | - studying: 'status-studying', | 125 | + } else { |
| 232 | - graduated: 'status-graduated', | 126 | + columns[1].push(image) |
| 233 | - suspended: 'status-suspended' | 127 | + } |
| 234 | - } | 128 | + }) |
| 235 | - return classes[status] || 'status-studying' | ||
| 236 | } | 129 | } |
| 237 | 130 | ||
| 238 | -// 获取状态文本 | 131 | +// 图片点击事件 |
| 239 | -const getStatusText = (status) => { | 132 | +const onImageClick = (item) => { |
| 240 | - const texts = { | 133 | + console.log('点击图片:', item) |
| 241 | - studying: '在学', | 134 | + selectedImage.value = item |
| 242 | - graduated: '毕业', | 135 | + showOverlay.value = true |
| 243 | - suspended: '暂停' | ||
| 244 | - } | ||
| 245 | - return texts[status] || '在学' | ||
| 246 | } | 136 | } |
| 247 | 137 | ||
| 248 | -// 处理标签切换 | 138 | +// 关闭遮罩层 |
| 249 | -const handleTabChange = (name) => { | 139 | +const closeOverlay = () => { |
| 250 | - activeTab.value = name | 140 | + showOverlay.value = false |
| 141 | + selectedImage.value = null | ||
| 251 | } | 142 | } |
| 252 | 143 | ||
| 253 | -// 处理戒子点击 | 144 | +// 图片加载成功 |
| 254 | -const handleStudentClick = (student) => { | 145 | +const onImageLoad = (event) => { |
| 255 | - router.push(`/students/${student.id}`) | 146 | + console.log('图片加载成功:', event.target.src) |
| 256 | } | 147 | } |
| 257 | 148 | ||
| 258 | -// 处理搜索 | 149 | +// 图片加载失败 |
| 259 | -const handleSearch = () => { | 150 | +const onImageError = (event) => { |
| 260 | - Toast('搜索功能开发中...') | 151 | + console.error('图片加载失败:', event.target.src) |
| 152 | + // 可以设置默认图片 | ||
| 153 | + event.target.src = 'https://via.placeholder.com/300x400?text=加载失败' | ||
| 261 | } | 154 | } |
| 155 | + | ||
| 156 | +// 组件挂载时初始化 | ||
| 157 | +onMounted(() => { | ||
| 158 | + // 初始加载第一页数据 | ||
| 159 | + onLoad() | ||
| 160 | +}) | ||
| 262 | </script> | 161 | </script> |
| 263 | 162 | ||
| 264 | <style scoped> | 163 | <style scoped> |
| 265 | -.page-container { | 164 | +.students-container { |
| 165 | + background-color: #F2EBDB; | ||
| 266 | min-height: 100vh; | 166 | min-height: 100vh; |
| 267 | - background: #fafafa; | ||
| 268 | -} | ||
| 269 | - | ||
| 270 | -.custom-nav { | ||
| 271 | - background: linear-gradient(135deg, #8b5cf6, #7c3aed); | ||
| 272 | - color: white; | ||
| 273 | -} | ||
| 274 | - | ||
| 275 | -.custom-nav :deep(.van-nav-bar__title) { | ||
| 276 | - color: white; | ||
| 277 | - font-weight: 600; | ||
| 278 | } | 167 | } |
| 279 | 168 | ||
| 280 | -.custom-nav :deep(.van-icon) { | 169 | +.header { |
| 281 | - color: white; | 170 | + position: sticky; |
| 171 | + top: 0; | ||
| 172 | + z-index: 100; | ||
| 173 | + background-color: #fff; | ||
| 282 | } | 174 | } |
| 283 | 175 | ||
| 284 | -.content-container { | 176 | +.waterfall-content { |
| 285 | - padding-top: 46px; | 177 | + padding: 1rem; |
| 286 | } | 178 | } |
| 287 | 179 | ||
| 288 | -.stats-section { | 180 | +.waterfall-container { |
| 289 | display: flex; | 181 | display: flex; |
| 290 | - gap: 12px; | 182 | + gap: 0.75rem; |
| 291 | - padding: 16px; | 183 | + align-items: flex-start; |
| 292 | } | 184 | } |
| 293 | 185 | ||
| 294 | -.stat-card { | 186 | +.waterfall-column { |
| 295 | flex: 1; | 187 | flex: 1; |
| 296 | - background: white; | ||
| 297 | - border-radius: 12px; | ||
| 298 | - padding: 16px; | ||
| 299 | display: flex; | 188 | display: flex; |
| 300 | - align-items: center; | 189 | + flex-direction: column; |
| 301 | - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); | 190 | + gap: 0.75rem; |
| 302 | } | 191 | } |
| 303 | 192 | ||
| 304 | -.stat-icon { | 193 | +.waterfall-item { |
| 305 | - font-size: 24px; | 194 | + background-color: #fff; |
| 306 | - margin-right: 12px; | 195 | + border-radius: 0.5rem; |
| 196 | + overflow: hidden; | ||
| 197 | + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); | ||
| 198 | + transition: transform 0.2s ease, box-shadow 0.2s ease; | ||
| 199 | + cursor: pointer; | ||
| 307 | } | 200 | } |
| 308 | 201 | ||
| 309 | -.stat-info { | 202 | +.waterfall-item:hover { |
| 310 | - flex: 1; | 203 | + transform: translateY(-2px); |
| 204 | + box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15); | ||
| 311 | } | 205 | } |
| 312 | 206 | ||
| 313 | -.stat-number { | 207 | +.image-wrapper { |
| 314 | - font-size: 20px; | 208 | + position: relative; |
| 315 | - font-weight: 700; | 209 | + overflow: hidden; |
| 316 | - color: #8b5cf6; | ||
| 317 | - margin-bottom: 2px; | ||
| 318 | } | 210 | } |
| 319 | 211 | ||
| 320 | -.stat-label { | 212 | +.image-wrapper img { |
| 321 | - font-size: 12px; | 213 | + width: 100%; |
| 322 | - color: #666; | 214 | + display: block; |
| 215 | + object-fit: cover; | ||
| 216 | + transition: transform 0.3s ease; | ||
| 323 | } | 217 | } |
| 324 | 218 | ||
| 325 | -.filter-section { | 219 | +.waterfall-item:hover .image-wrapper img { |
| 326 | - background: white; | 220 | + transform: scale(1.05); |
| 327 | - border-bottom: 1px solid #eee; | ||
| 328 | } | 221 | } |
| 329 | 222 | ||
| 330 | -.custom-tabs :deep(.van-tab) { | 223 | +.image-overlay { |
| 331 | - font-weight: 500; | 224 | + position: absolute; |
| 225 | + bottom: 0; | ||
| 226 | + left: 0; | ||
| 227 | + right: 0; | ||
| 228 | + background: linear-gradient(transparent, rgba(0, 0, 0, 0.7)); | ||
| 229 | + padding: 1rem 0.75rem 0.75rem; | ||
| 230 | + transform: translateY(100%); | ||
| 231 | + transition: transform 0.3s ease; | ||
| 332 | } | 232 | } |
| 333 | 233 | ||
| 334 | -.custom-tabs :deep(.van-tab--active) { | 234 | +.waterfall-item:hover .image-overlay { |
| 335 | - color: #8b5cf6; | 235 | + transform: translateY(0); |
| 336 | } | 236 | } |
| 337 | 237 | ||
| 338 | -.custom-tabs :deep(.van-tabs__line) { | 238 | +.image-title { |
| 339 | - background: #8b5cf6; | 239 | + color: #fff; |
| 240 | + font-size: 0.875rem; | ||
| 241 | + font-weight: 500; | ||
| 242 | + line-height: 1.4; | ||
| 340 | } | 243 | } |
| 341 | 244 | ||
| 342 | -.students-list { | 245 | +/* 加载状态样式 */ |
| 343 | - padding: 16px; | 246 | +:deep(.van-list__loading) { |
| 247 | + padding: 1rem; | ||
| 248 | + text-align: center; | ||
| 249 | + color: #969799; | ||
| 344 | } | 250 | } |
| 345 | 251 | ||
| 346 | -.student-card { | 252 | +:deep(.van-list__finished-text) { |
| 347 | - background: white; | 253 | + padding: 1rem; |
| 348 | - border-radius: 12px; | 254 | + text-align: center; |
| 349 | - padding: 16px; | 255 | + color: #969799; |
| 350 | - margin-bottom: 12px; | 256 | + font-size: 0.875rem; |
| 351 | - display: flex; | ||
| 352 | - align-items: center; | ||
| 353 | - gap: 16px; | ||
| 354 | - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); | ||
| 355 | - cursor: pointer; | ||
| 356 | - transition: all 0.3s ease; | ||
| 357 | } | 257 | } |
| 358 | 258 | ||
| 359 | -.student-card:hover { | 259 | +/* 响应式设计 */ |
| 360 | - transform: translateY(-3px); | 260 | +@media (max-width: 480px) { |
| 361 | - box-shadow: 0 6px 20px rgba(0, 0, 0, 0.15); | 261 | + .waterfall-content { |
| 362 | -} | 262 | + padding: 0.75rem; |
| 263 | + } | ||
| 363 | 264 | ||
| 364 | -.student-card:active { | 265 | + .waterfall-container { |
| 365 | - transform: translateY(-1px); | 266 | + gap: 0.5rem; |
| 366 | - box-shadow: 0 3px 12px rgba(0, 0, 0, 0.12); | 267 | + } |
| 268 | + | ||
| 269 | + .waterfall-column { | ||
| 270 | + gap: 0.5rem; | ||
| 271 | + } | ||
| 272 | + | ||
| 273 | + .image-title { | ||
| 274 | + font-size: 0.8125rem; | ||
| 275 | + } | ||
| 367 | } | 276 | } |
| 368 | 277 | ||
| 369 | -.student-avatar { | 278 | +/* 骨架屏效果 */ |
| 370 | - position: relative; | 279 | +.waterfall-item.loading { |
| 371 | - width: 60px; | 280 | + background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%); |
| 372 | - height: 60px; | 281 | + background-size: 200% 100%; |
| 373 | - border-radius: 50%; | 282 | + animation: loading 1.5s infinite; |
| 374 | - overflow: hidden; | ||
| 375 | - margin-right: 16px; | ||
| 376 | - flex-shrink: 0; | ||
| 377 | } | 283 | } |
| 378 | 284 | ||
| 379 | -.student-avatar img { | 285 | +@keyframes loading { |
| 380 | - width: 100%; | 286 | + 0% { |
| 381 | - height: 100%; | 287 | + background-position: 200% 0; |
| 382 | - object-fit: cover; | 288 | + } |
| 289 | + 100% { | ||
| 290 | + background-position: -200% 0; | ||
| 291 | + } | ||
| 383 | } | 292 | } |
| 384 | 293 | ||
| 385 | -.avatar-placeholder { | 294 | +/* 遮罩层样式 */ |
| 386 | - width: 100%; | 295 | +:deep(.van-overlay) { |
| 387 | - height: 100%; | ||
| 388 | - background: linear-gradient(135deg, #8b5cf6, #7c3aed); | ||
| 389 | display: flex; | 296 | display: flex; |
| 390 | align-items: center; | 297 | align-items: center; |
| 391 | justify-content: center; | 298 | justify-content: center; |
| 392 | - color: white; | 299 | + padding: 1rem; |
| 393 | - font-size: 24px; | ||
| 394 | - font-weight: 600; | ||
| 395 | } | 300 | } |
| 396 | 301 | ||
| 397 | -.precept-badge { | 302 | +.overlay-content { |
| 398 | - position: absolute; | 303 | + background-color: #fff; |
| 399 | - bottom: -2px; | 304 | + border-radius: 1rem; |
| 400 | - right: -2px; | 305 | + max-width: 90vw; |
| 401 | - padding: 2px 6px; | 306 | + max-height: 80vh; |
| 402 | - border-radius: 8px; | 307 | + overflow: hidden; |
| 403 | - font-size: 10px; | 308 | + position: relative; |
| 404 | - font-weight: 500; | 309 | + box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3); |
| 405 | - border: 2px solid white; | ||
| 406 | -} | ||
| 407 | - | ||
| 408 | -.precept-novice { | ||
| 409 | - background: #10b981; | ||
| 410 | - color: white; | ||
| 411 | -} | ||
| 412 | - | ||
| 413 | -.precept-bhiksu { | ||
| 414 | - background: #3b82f6; | ||
| 415 | - color: white; | ||
| 416 | -} | ||
| 417 | - | ||
| 418 | -.precept-bodhisattva { | ||
| 419 | - background: #f59e0b; | ||
| 420 | - color: white; | ||
| 421 | -} | ||
| 422 | - | ||
| 423 | -.student-info { | ||
| 424 | - flex: 1; | ||
| 425 | } | 310 | } |
| 426 | 311 | ||
| 427 | -.student-header { | 312 | +.close-btn { |
| 313 | + position: absolute; | ||
| 314 | + top: 1rem; | ||
| 315 | + right: 1rem; | ||
| 316 | + width: 2.5rem; | ||
| 317 | + height: 2.5rem; | ||
| 318 | + background-color: rgba(0, 0, 0, 0.5); | ||
| 319 | + border-radius: 50%; | ||
| 428 | display: flex; | 320 | display: flex; |
| 429 | align-items: center; | 321 | align-items: center; |
| 430 | - justify-content: space-between; | 322 | + justify-content: center; |
| 431 | - margin-bottom: 8px; | 323 | + cursor: pointer; |
| 432 | -} | 324 | + z-index: 10; |
| 433 | - | 325 | + transition: background-color 0.2s ease; |
| 434 | -.student-name { | ||
| 435 | - font-size: 18px; | ||
| 436 | - font-weight: 600; | ||
| 437 | - color: #333; | ||
| 438 | - margin: 0; | ||
| 439 | } | 326 | } |
| 440 | 327 | ||
| 441 | -.student-status { | 328 | +.close-btn:hover { |
| 442 | - padding: 4px 8px; | 329 | + background-color: rgba(0, 0, 0, 0.7); |
| 443 | - border-radius: 12px; | ||
| 444 | - font-size: 12px; | ||
| 445 | - font-weight: 500; | ||
| 446 | } | 330 | } |
| 447 | 331 | ||
| 448 | -.status-studying { | 332 | +.overlay-image-wrapper { |
| 449 | - background: #dbeafe; | 333 | + width: 100%; |
| 450 | - color: #1d4ed8; | 334 | + max-height: 60vh; |
| 451 | - border: 1px solid #93c5fd; | 335 | + overflow: hidden; |
| 336 | + display: flex; | ||
| 337 | + align-items: center; | ||
| 338 | + justify-content: center; | ||
| 339 | + background-color: #f5f5f5; | ||
| 452 | } | 340 | } |
| 453 | 341 | ||
| 454 | -.status-graduated { | 342 | +.overlay-image { |
| 455 | - background: #dcfce7; | 343 | + width: 100%; |
| 456 | - color: #166534; | 344 | + height: auto; |
| 457 | - border: 1px solid #86efac; | 345 | + max-height: 60vh; |
| 346 | + object-fit: contain; | ||
| 347 | + display: block; | ||
| 458 | } | 348 | } |
| 459 | 349 | ||
| 460 | -.status-suspended { | 350 | +.overlay-description { |
| 461 | - background: #fef3c7; | 351 | + padding: 1.5rem; |
| 462 | - color: #92400e; | 352 | + background-color: #fff; |
| 463 | - border: 1px solid #fcd34d; | ||
| 464 | } | 353 | } |
| 465 | 354 | ||
| 466 | -.student-details { | 355 | +.overlay-title { |
| 467 | - space-y: 4px; | 356 | + font-size: 1.25rem; |
| 357 | + font-weight: 600; | ||
| 358 | + color: #333; | ||
| 359 | + margin: 0 0 1rem 0; | ||
| 360 | + line-height: 1.4; | ||
| 468 | } | 361 | } |
| 469 | 362 | ||
| 470 | -.student-temple { | 363 | +.overlay-text { |
| 471 | - font-size: 16px; | 364 | + font-size: 1rem; |
| 472 | color: #666; | 365 | color: #666; |
| 473 | - margin: 0 0 4px 0; | 366 | + line-height: 1.6; |
| 367 | + margin: 0; | ||
| 368 | + white-space: pre-wrap; | ||
| 474 | } | 369 | } |
| 475 | 370 | ||
| 476 | -.student-teacher { | 371 | +/* 移动端适配 */ |
| 477 | - font-size: 14px; | 372 | +@media (max-width: 480px) { |
| 478 | - color: #999; | 373 | + .overlay-content { |
| 479 | - margin: 0 0 8px 0; | 374 | + max-width: 95vw; |
| 480 | -} | 375 | + max-height: 85vh; |
| 376 | + border-radius: 0.75rem; | ||
| 377 | + } | ||
| 481 | 378 | ||
| 482 | -.student-meta { | 379 | + .close-btn { |
| 483 | - display: flex; | 380 | + top: 0.75rem; |
| 484 | - gap: 16px; | 381 | + right: 0.75rem; |
| 485 | -} | 382 | + width: 2rem; |
| 383 | + height: 2rem; | ||
| 384 | + } | ||
| 486 | 385 | ||
| 487 | -.entry-date, | 386 | + .overlay-description { |
| 488 | -.progress { | 387 | + padding: 1rem; |
| 489 | - font-size: 12px; | 388 | + } |
| 490 | - color: #999; | ||
| 491 | - background: #f5f5f5; | ||
| 492 | - padding: 2px 6px; | ||
| 493 | - border-radius: 4px; | ||
| 494 | -} | ||
| 495 | 389 | ||
| 496 | -.student-actions { | 390 | + .overlay-title { |
| 497 | - margin-left: 12px; | 391 | + font-size: 1.125rem; |
| 498 | - color: #ccc; | 392 | + } |
| 393 | + | ||
| 394 | + .overlay-text { | ||
| 395 | + font-size: 0.875rem; | ||
| 396 | + } | ||
| 499 | } | 397 | } |
| 500 | -</style> | ||
| ... | \ No newline at end of file | ... | \ No newline at end of file |
| 398 | +</style> | ... | ... |
src/views/TeacherDetail.vue
deleted
100644 → 0
| 1 | -<template> | ||
| 2 | - <div class="page-container"> | ||
| 3 | - <!-- 导航栏 --> | ||
| 4 | - <van-nav-bar title="法师详情" left-arrow @click-left="$router.back()" class="custom-nav"> | ||
| 5 | - <template #right> | ||
| 6 | - <van-icon name="share" size="18" /> | ||
| 7 | - </template> | ||
| 8 | - </van-nav-bar> | ||
| 9 | - | ||
| 10 | - <!-- 内容区域 --> | ||
| 11 | - <div class="content-container"> | ||
| 12 | - <!-- 法师基本信息 --> | ||
| 13 | - <div class="teacher-profile"> | ||
| 14 | - <div class="profile-header"> | ||
| 15 | - <div class="teacher-avatar"> | ||
| 16 | - <img v-if="teacher.avatar" :src="teacher.avatar" :alt="teacher.name" /> | ||
| 17 | - <div v-else class="avatar-placeholder"> | ||
| 18 | - <span>{{ teacher.name.charAt(0) }}</span> | ||
| 19 | - </div> | ||
| 20 | - </div> | ||
| 21 | - | ||
| 22 | - <div class="profile-info"> | ||
| 23 | - <h2 class="teacher-name">{{ teacher.name }}</h2> | ||
| 24 | - <div class="teacher-role" :class="getRoleClass(teacher.role)"> | ||
| 25 | - {{ teacher.role }} | ||
| 26 | - </div> | ||
| 27 | - <p class="teacher-title">{{ teacher.title }} · {{ teacher.temple }}</p> | ||
| 28 | - </div> | ||
| 29 | - </div> | ||
| 30 | - | ||
| 31 | - <!-- 统计信息 --> | ||
| 32 | - <div class="stats-section"> | ||
| 33 | - <div class="stat-item"> | ||
| 34 | - <div class="stat-number">{{ teacher.experience }}</div> | ||
| 35 | - <div class="stat-label">戒腊年数</div> | ||
| 36 | - </div> | ||
| 37 | - <div class="stat-divider"></div> | ||
| 38 | - <div class="stat-item"> | ||
| 39 | - <div class="stat-number">{{ teacher.ordinationYear }}</div> | ||
| 40 | - <div class="stat-label">受戒年份</div> | ||
| 41 | - </div> | ||
| 42 | - <div class="stat-divider"></div> | ||
| 43 | - <div class="stat-item"> | ||
| 44 | - <div class="stat-number">{{ teacher.disciples || 0 }}</div> | ||
| 45 | - <div class="stat-label">弟子人数</div> | ||
| 46 | - </div> | ||
| 47 | - </div> | ||
| 48 | - </div> | ||
| 49 | - | ||
| 50 | - <!-- 详细信息 --> | ||
| 51 | - <div class="detail-sections"> | ||
| 52 | - <!-- 个人简介 --> | ||
| 53 | - <div class="detail-section"> | ||
| 54 | - <h3 class="section-title"> | ||
| 55 | - <van-icon name="user-o" /> | ||
| 56 | - 个人简介 | ||
| 57 | - </h3> | ||
| 58 | - <div class="section-content"> | ||
| 59 | - <p>{{ teacher.biography || '暂无个人简介信息' }}</p> | ||
| 60 | - </div> | ||
| 61 | - </div> | ||
| 62 | - | ||
| 63 | - <!-- 修学经历 --> | ||
| 64 | - <div class="detail-section"> | ||
| 65 | - <h3 class="section-title"> | ||
| 66 | - <van-icon name="certificate" /> | ||
| 67 | - 修学经历 | ||
| 68 | - </h3> | ||
| 69 | - <div class="section-content"> | ||
| 70 | - <div class="timeline"> | ||
| 71 | - <div v-for="(experience, index) in teacher.experiences" :key="index" class="timeline-item"> | ||
| 72 | - <div class="timeline-dot"></div> | ||
| 73 | - <div class="timeline-content"> | ||
| 74 | - <div class="timeline-year">{{ experience.year }}</div> | ||
| 75 | - <div class="timeline-event">{{ experience.event }}</div> | ||
| 76 | - <div class="timeline-location">{{ experience.location }}</div> | ||
| 77 | - </div> | ||
| 78 | - </div> | ||
| 79 | - </div> | ||
| 80 | - </div> | ||
| 81 | - </div> | ||
| 82 | - | ||
| 83 | - <!-- 弘法活动 --> | ||
| 84 | - <div class="detail-section"> | ||
| 85 | - <h3 class="section-title"> | ||
| 86 | - <van-icon name="fire-o" /> | ||
| 87 | - 弘法活动 | ||
| 88 | - </h3> | ||
| 89 | - <div class="section-content"> | ||
| 90 | - <div v-if="teacher.activities && teacher.activities.length > 0" class="activities-list"> | ||
| 91 | - <div v-for="activity in teacher.activities" :key="activity.id" class="activity-item"> | ||
| 92 | - <div class="activity-date">{{ activity.date }}</div> | ||
| 93 | - <div class="activity-title">{{ activity.title }}</div> | ||
| 94 | - <div class="activity-location">{{ activity.location }}</div> | ||
| 95 | - </div> | ||
| 96 | - </div> | ||
| 97 | - <p v-else class="no-data">暂无弘法活动记录</p> | ||
| 98 | - </div> | ||
| 99 | - </div> | ||
| 100 | - | ||
| 101 | - <!-- 联系方式 --> | ||
| 102 | - <div class="detail-section"> | ||
| 103 | - <h3 class="section-title"> | ||
| 104 | - <van-icon name="phone-o" /> | ||
| 105 | - 联系方式 | ||
| 106 | - </h3> | ||
| 107 | - <div class="section-content"> | ||
| 108 | - <div class="contact-info"> | ||
| 109 | - <div class="contact-item"> | ||
| 110 | - <span class="contact-label">所在寺院:</span> | ||
| 111 | - <span class="contact-value">{{ teacher.temple }}</span> | ||
| 112 | - </div> | ||
| 113 | - <div class="contact-item" v-if="teacher.phone"> | ||
| 114 | - <span class="contact-label">联系电话:</span> | ||
| 115 | - <span class="contact-value">{{ teacher.phone }}</span> | ||
| 116 | - </div> | ||
| 117 | - <div class="contact-item" v-if="teacher.email"> | ||
| 118 | - <span class="contact-label">电子邮箱:</span> | ||
| 119 | - <span class="contact-value">{{ teacher.email }}</span> | ||
| 120 | - </div> | ||
| 121 | - </div> | ||
| 122 | - </div> | ||
| 123 | - </div> | ||
| 124 | - </div> | ||
| 125 | - </div> | ||
| 126 | - </div> | ||
| 127 | -</template> | ||
| 128 | - | ||
| 129 | -<script setup> | ||
| 130 | -import { ref, onMounted } from 'vue' | ||
| 131 | -import { useRoute, useRouter } from 'vue-router' | ||
| 132 | - | ||
| 133 | -const route = useRoute() | ||
| 134 | -const router = useRouter() | ||
| 135 | - | ||
| 136 | -// 法师详细信息 | ||
| 137 | -const teacher = ref({ | ||
| 138 | - id: 1, | ||
| 139 | - name: '慧明法师', | ||
| 140 | - title: '方丈', | ||
| 141 | - role: '得戒和尚', | ||
| 142 | - temple: '大觉寺', | ||
| 143 | - ordinationYear: 1985, | ||
| 144 | - experience: 39, | ||
| 145 | - disciples: 156, | ||
| 146 | - avatar: null, | ||
| 147 | - biography: '慧明法师,俗姓李,1960年生于江苏南京。1985年在大觉寺依止上慧下觉老和尚剃度出家,同年在宝华山隆昌寺受具足戒。法师戒行清净,学修并重,深得四众弟子敬仰。现任大觉寺方丈,致力于佛法弘扬和寺院建设。', | ||
| 148 | - experiences: [ | ||
| 149 | - { | ||
| 150 | - year: '1985年', | ||
| 151 | - event: '在大觉寺剃度出家', | ||
| 152 | - location: '大觉寺' | ||
| 153 | - }, | ||
| 154 | - { | ||
| 155 | - year: '1985年', | ||
| 156 | - event: '在宝华山隆昌寺受具足戒', | ||
| 157 | - location: '宝华山隆昌寺' | ||
| 158 | - }, | ||
| 159 | - { | ||
| 160 | - year: '1990年', | ||
| 161 | - event: '任大觉寺知客', | ||
| 162 | - location: '大觉寺' | ||
| 163 | - }, | ||
| 164 | - { | ||
| 165 | - year: '1995年', | ||
| 166 | - event: '任大觉寺监院', | ||
| 167 | - location: '大觉寺' | ||
| 168 | - }, | ||
| 169 | - { | ||
| 170 | - year: '2000年', | ||
| 171 | - event: '升座为大觉寺方丈', | ||
| 172 | - location: '大觉寺' | ||
| 173 | - } | ||
| 174 | - ], | ||
| 175 | - activities: [ | ||
| 176 | - { | ||
| 177 | - id: 1, | ||
| 178 | - date: '2024-01-15', | ||
| 179 | - title: '三坛大戒传戒法会', | ||
| 180 | - location: '大觉寺' | ||
| 181 | - }, | ||
| 182 | - { | ||
| 183 | - id: 2, | ||
| 184 | - date: '2023-12-08', | ||
| 185 | - title: '佛成道日法会', | ||
| 186 | - location: '大觉寺' | ||
| 187 | - }, | ||
| 188 | - { | ||
| 189 | - id: 3, | ||
| 190 | - date: '2023-11-20', | ||
| 191 | - title: '佛学讲座:戒律的现代意义', | ||
| 192 | - location: '大觉寺讲堂' | ||
| 193 | - } | ||
| 194 | - ], | ||
| 195 | - phone: '025-12345678', | ||
| 196 | - email: 'huiming@dajuesi.org' | ||
| 197 | -}) | ||
| 198 | - | ||
| 199 | -// 获取角色样式类 | ||
| 200 | -const getRoleClass = (role) => { | ||
| 201 | - if (role.includes('和尚') || role.includes('阿阇梨')) { | ||
| 202 | - return 'role-teacher' | ||
| 203 | - } | ||
| 204 | - return 'role-witness' | ||
| 205 | -} | ||
| 206 | - | ||
| 207 | -// 加载法师详情 | ||
| 208 | -const loadTeacherDetail = async () => { | ||
| 209 | - const teacherId = route.params.id | ||
| 210 | - // 这里应该根据 teacherId 从 API 获取法师详情 | ||
| 211 | - // 现在使用模拟数据 | ||
| 212 | - console.log('Loading teacher detail for ID:', teacherId) | ||
| 213 | -} | ||
| 214 | - | ||
| 215 | -onMounted(() => { | ||
| 216 | - loadTeacherDetail() | ||
| 217 | -}) | ||
| 218 | -</script> | ||
| 219 | - | ||
| 220 | -<style scoped> | ||
| 221 | -.page-container { | ||
| 222 | - min-height: 100vh; | ||
| 223 | - background: #fafafa; | ||
| 224 | -} | ||
| 225 | - | ||
| 226 | -.custom-nav { | ||
| 227 | - background: linear-gradient(135deg, #fbbf24, #f97316); | ||
| 228 | - color: white; | ||
| 229 | -} | ||
| 230 | - | ||
| 231 | -.custom-nav :deep(.van-nav-bar__title) { | ||
| 232 | - color: white; | ||
| 233 | - font-weight: 600; | ||
| 234 | -} | ||
| 235 | - | ||
| 236 | -.custom-nav :deep(.van-icon) { | ||
| 237 | - color: white; | ||
| 238 | -} | ||
| 239 | - | ||
| 240 | -.content-container { | ||
| 241 | - padding-top: 46px; | ||
| 242 | -} | ||
| 243 | - | ||
| 244 | -.teacher-profile { | ||
| 245 | - background: white; | ||
| 246 | - margin: 16px; | ||
| 247 | - border-radius: 12px; | ||
| 248 | - padding: 24px; | ||
| 249 | - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); | ||
| 250 | -} | ||
| 251 | - | ||
| 252 | -.profile-header { | ||
| 253 | - display: flex; | ||
| 254 | - align-items: center; | ||
| 255 | - margin-bottom: 24px; | ||
| 256 | -} | ||
| 257 | - | ||
| 258 | -.teacher-avatar { | ||
| 259 | - width: 80px; | ||
| 260 | - height: 80px; | ||
| 261 | - border-radius: 50%; | ||
| 262 | - overflow: hidden; | ||
| 263 | - margin-right: 20px; | ||
| 264 | - flex-shrink: 0; | ||
| 265 | -} | ||
| 266 | - | ||
| 267 | -.teacher-avatar img { | ||
| 268 | - width: 100%; | ||
| 269 | - height: 100%; | ||
| 270 | - object-fit: cover; | ||
| 271 | -} | ||
| 272 | - | ||
| 273 | -.avatar-placeholder { | ||
| 274 | - width: 100%; | ||
| 275 | - height: 100%; | ||
| 276 | - background: linear-gradient(135deg, #fbbf24, #f97316); | ||
| 277 | - display: flex; | ||
| 278 | - align-items: center; | ||
| 279 | - justify-content: center; | ||
| 280 | - color: white; | ||
| 281 | - font-size: 32px; | ||
| 282 | - font-weight: 600; | ||
| 283 | -} | ||
| 284 | - | ||
| 285 | -.profile-info { | ||
| 286 | - flex: 1; | ||
| 287 | -} | ||
| 288 | - | ||
| 289 | -.teacher-name { | ||
| 290 | - font-size: 24px; | ||
| 291 | - font-weight: 700; | ||
| 292 | - color: #333; | ||
| 293 | - margin: 0 0 8px 0; | ||
| 294 | -} | ||
| 295 | - | ||
| 296 | -.teacher-role { | ||
| 297 | - display: inline-block; | ||
| 298 | - padding: 6px 12px; | ||
| 299 | - border-radius: 16px; | ||
| 300 | - font-size: 14px; | ||
| 301 | - font-weight: 500; | ||
| 302 | - margin-bottom: 8px; | ||
| 303 | -} | ||
| 304 | - | ||
| 305 | -.role-teacher { | ||
| 306 | - background: linear-gradient(135deg, #fbbf24, #f97316); | ||
| 307 | - color: white; | ||
| 308 | -} | ||
| 309 | - | ||
| 310 | -.role-witness { | ||
| 311 | - background: #f0f9ff; | ||
| 312 | - color: #0369a1; | ||
| 313 | - border: 1px solid #bae6fd; | ||
| 314 | -} | ||
| 315 | - | ||
| 316 | -.teacher-title { | ||
| 317 | - font-size: 16px; | ||
| 318 | - color: #666; | ||
| 319 | - margin: 0; | ||
| 320 | -} | ||
| 321 | - | ||
| 322 | -.stats-section { | ||
| 323 | - display: flex; | ||
| 324 | - align-items: center; | ||
| 325 | - justify-content: space-around; | ||
| 326 | - padding-top: 24px; | ||
| 327 | - border-top: 1px solid #f0f0f0; | ||
| 328 | -} | ||
| 329 | - | ||
| 330 | -.stat-item { | ||
| 331 | - text-align: center; | ||
| 332 | -} | ||
| 333 | - | ||
| 334 | -.stat-number { | ||
| 335 | - font-size: 24px; | ||
| 336 | - font-weight: 700; | ||
| 337 | - color: #f59e0b; | ||
| 338 | - margin-bottom: 4px; | ||
| 339 | -} | ||
| 340 | - | ||
| 341 | -.stat-label { | ||
| 342 | - font-size: 12px; | ||
| 343 | - color: #999; | ||
| 344 | -} | ||
| 345 | - | ||
| 346 | -.stat-divider { | ||
| 347 | - width: 1px; | ||
| 348 | - height: 40px; | ||
| 349 | - background: #f0f0f0; | ||
| 350 | -} | ||
| 351 | - | ||
| 352 | -.detail-sections { | ||
| 353 | - padding: 0 16px 16px; | ||
| 354 | -} | ||
| 355 | - | ||
| 356 | -.detail-section { | ||
| 357 | - background: white; | ||
| 358 | - border-radius: 12px; | ||
| 359 | - margin-bottom: 16px; | ||
| 360 | - overflow: hidden; | ||
| 361 | - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); | ||
| 362 | -} | ||
| 363 | - | ||
| 364 | -.section-title { | ||
| 365 | - display: flex; | ||
| 366 | - align-items: center; | ||
| 367 | - padding: 16px 20px; | ||
| 368 | - margin: 0; | ||
| 369 | - font-size: 16px; | ||
| 370 | - font-weight: 600; | ||
| 371 | - color: #333; | ||
| 372 | - background: #fafafa; | ||
| 373 | - border-bottom: 1px solid #f0f0f0; | ||
| 374 | -} | ||
| 375 | - | ||
| 376 | -.section-title .van-icon { | ||
| 377 | - margin-right: 8px; | ||
| 378 | - color: #f59e0b; | ||
| 379 | -} | ||
| 380 | - | ||
| 381 | -.section-content { | ||
| 382 | - padding: 20px; | ||
| 383 | -} | ||
| 384 | - | ||
| 385 | -.section-content p { | ||
| 386 | - font-size: 14px; | ||
| 387 | - line-height: 1.6; | ||
| 388 | - color: #666; | ||
| 389 | - margin: 0; | ||
| 390 | -} | ||
| 391 | - | ||
| 392 | -.timeline { | ||
| 393 | - position: relative; | ||
| 394 | -} | ||
| 395 | - | ||
| 396 | -.timeline::before { | ||
| 397 | - content: ''; | ||
| 398 | - position: absolute; | ||
| 399 | - left: 8px; | ||
| 400 | - top: 0; | ||
| 401 | - bottom: 0; | ||
| 402 | - width: 2px; | ||
| 403 | - background: #f0f0f0; | ||
| 404 | -} | ||
| 405 | - | ||
| 406 | -.timeline-item { | ||
| 407 | - position: relative; | ||
| 408 | - padding-left: 32px; | ||
| 409 | - margin-bottom: 20px; | ||
| 410 | -} | ||
| 411 | - | ||
| 412 | -.timeline-item:last-child { | ||
| 413 | - margin-bottom: 0; | ||
| 414 | -} | ||
| 415 | - | ||
| 416 | -.timeline-dot { | ||
| 417 | - position: absolute; | ||
| 418 | - left: 0; | ||
| 419 | - top: 4px; | ||
| 420 | - width: 16px; | ||
| 421 | - height: 16px; | ||
| 422 | - border-radius: 50%; | ||
| 423 | - background: #f59e0b; | ||
| 424 | - border: 3px solid white; | ||
| 425 | - box-shadow: 0 0 0 2px #f59e0b; | ||
| 426 | -} | ||
| 427 | - | ||
| 428 | -.timeline-year { | ||
| 429 | - font-size: 14px; | ||
| 430 | - font-weight: 600; | ||
| 431 | - color: #f59e0b; | ||
| 432 | - margin-bottom: 4px; | ||
| 433 | -} | ||
| 434 | - | ||
| 435 | -.timeline-event { | ||
| 436 | - font-size: 16px; | ||
| 437 | - font-weight: 500; | ||
| 438 | - color: #333; | ||
| 439 | - margin-bottom: 4px; | ||
| 440 | -} | ||
| 441 | - | ||
| 442 | -.timeline-location { | ||
| 443 | - font-size: 14px; | ||
| 444 | - color: #999; | ||
| 445 | -} | ||
| 446 | - | ||
| 447 | -.activities-list { | ||
| 448 | - space-y: 12px; | ||
| 449 | -} | ||
| 450 | - | ||
| 451 | -.activity-item { | ||
| 452 | - padding: 16px; | ||
| 453 | - background: #fafafa; | ||
| 454 | - border-radius: 8px; | ||
| 455 | - margin-bottom: 12px; | ||
| 456 | -} | ||
| 457 | - | ||
| 458 | -.activity-date { | ||
| 459 | - font-size: 12px; | ||
| 460 | - color: #f59e0b; | ||
| 461 | - font-weight: 500; | ||
| 462 | - margin-bottom: 4px; | ||
| 463 | -} | ||
| 464 | - | ||
| 465 | -.activity-title { | ||
| 466 | - font-size: 16px; | ||
| 467 | - font-weight: 500; | ||
| 468 | - color: #333; | ||
| 469 | - margin-bottom: 4px; | ||
| 470 | -} | ||
| 471 | - | ||
| 472 | -.activity-location { | ||
| 473 | - font-size: 14px; | ||
| 474 | - color: #666; | ||
| 475 | -} | ||
| 476 | - | ||
| 477 | -.contact-info { | ||
| 478 | - space-y: 12px; | ||
| 479 | -} | ||
| 480 | - | ||
| 481 | -.contact-item { | ||
| 482 | - display: flex; | ||
| 483 | - align-items: center; | ||
| 484 | - margin-bottom: 12px; | ||
| 485 | -} | ||
| 486 | - | ||
| 487 | -.contact-label { | ||
| 488 | - font-size: 14px; | ||
| 489 | - color: #666; | ||
| 490 | - width: 80px; | ||
| 491 | - flex-shrink: 0; | ||
| 492 | -} | ||
| 493 | - | ||
| 494 | -.contact-value { | ||
| 495 | - font-size: 14px; | ||
| 496 | - color: #333; | ||
| 497 | - flex: 1; | ||
| 498 | -} | ||
| 499 | - | ||
| 500 | -.no-data { | ||
| 501 | - text-align: center; | ||
| 502 | - color: #999; | ||
| 503 | - font-size: 14px; | ||
| 504 | - margin: 0; | ||
| 505 | -} | ||
| 506 | -</style> | ||
| ... | \ No newline at end of file | ... | \ No newline at end of file |
src/views/Teachers.vue
deleted
100644 → 0
| 1 | -<template> | ||
| 2 | - <div class="page-container"> | ||
| 3 | - <!-- 导航栏 --> | ||
| 4 | - <van-nav-bar title="三师七证" left-arrow @click-left="$router.back()" class="custom-nav"> | ||
| 5 | - <template #right> | ||
| 6 | - <van-icon name="search" size="18" /> | ||
| 7 | - </template> | ||
| 8 | - </van-nav-bar> | ||
| 9 | - | ||
| 10 | - <!-- 内容区域 --> | ||
| 11 | - <div class="content-container"> | ||
| 12 | - <!-- 顶部说明 --> | ||
| 13 | - <div class="intro-section"> | ||
| 14 | - <div class="intro-card"> | ||
| 15 | - <div class="intro-icon">📜</div> | ||
| 16 | - <div class="intro-content"> | ||
| 17 | - <h3>三师七证</h3> | ||
| 18 | - <p>三师:得戒和尚、羯磨阿阇梨、教授阿阇梨<br>七证:七位证明师</p> | ||
| 19 | - </div> | ||
| 20 | - </div> | ||
| 21 | - </div> | ||
| 22 | - | ||
| 23 | - <!-- 筛选栏 --> | ||
| 24 | - <div class="filter-section"> | ||
| 25 | - <van-tabs v-model:active="activeTab" @change="handleTabChange" class="custom-tabs"> | ||
| 26 | - <van-tab title="全部" name="all"></van-tab> | ||
| 27 | - <van-tab title="三师" name="teachers"></van-tab> | ||
| 28 | - <van-tab title="七证" name="witnesses"></van-tab> | ||
| 29 | - </van-tabs> | ||
| 30 | - </div> | ||
| 31 | - | ||
| 32 | - <!-- 法师列表 --> | ||
| 33 | - <div class="teachers-list"> | ||
| 34 | - <div | ||
| 35 | - v-for="teacher in filteredTeachers" | ||
| 36 | - :key="teacher.id" | ||
| 37 | - class="teacher-card" | ||
| 38 | - @click="handleTeacherClick(teacher)" | ||
| 39 | - > | ||
| 40 | - <div class="teacher-avatar"> | ||
| 41 | - <img v-if="teacher.avatar" :src="teacher.avatar" :alt="teacher.name" /> | ||
| 42 | - <div v-else class="avatar-placeholder"> | ||
| 43 | - <span>{{ teacher.name.charAt(0) }}</span> | ||
| 44 | - </div> | ||
| 45 | - </div> | ||
| 46 | - | ||
| 47 | - <div class="teacher-info"> | ||
| 48 | - <div class="teacher-header"> | ||
| 49 | - <h4 class="teacher-name">{{ teacher.name }}</h4> | ||
| 50 | - <div class="teacher-role" :class="getRoleClass(teacher.role)"> | ||
| 51 | - {{ teacher.role }} | ||
| 52 | - </div> | ||
| 53 | - </div> | ||
| 54 | - | ||
| 55 | - <div class="teacher-details"> | ||
| 56 | - <p class="teacher-title">{{ teacher.title }}</p> | ||
| 57 | - <p class="teacher-temple">{{ teacher.temple }}</p> | ||
| 58 | - <div class="teacher-meta"> | ||
| 59 | - <span class="ordination-year">{{ teacher.ordinationYear }}年受戒</span> | ||
| 60 | - <span class="experience">{{ teacher.experience }}年戒腊</span> | ||
| 61 | - </div> | ||
| 62 | - </div> | ||
| 63 | - </div> | ||
| 64 | - | ||
| 65 | - <div class="teacher-actions"> | ||
| 66 | - <van-icon name="arrow" /> | ||
| 67 | - </div> | ||
| 68 | - </div> | ||
| 69 | - </div> | ||
| 70 | - | ||
| 71 | - <!-- 空状态 --> | ||
| 72 | - <van-empty v-if="filteredTeachers.length === 0" description="暂无相关法师信息" /> | ||
| 73 | - </div> | ||
| 74 | - </div> | ||
| 75 | -</template> | ||
| 76 | - | ||
| 77 | -<script setup> | ||
| 78 | -import { ref, computed } from 'vue' | ||
| 79 | -import { useRouter } from 'vue-router' | ||
| 80 | - | ||
| 81 | -const router = useRouter() | ||
| 82 | -const activeTab = ref('all') | ||
| 83 | - | ||
| 84 | -// 法师数据 | ||
| 85 | -const teachers = ref([ | ||
| 86 | - { | ||
| 87 | - id: 1, | ||
| 88 | - name: '慧明法师', | ||
| 89 | - title: '方丈', | ||
| 90 | - role: '得戒和尚', | ||
| 91 | - temple: '大觉寺', | ||
| 92 | - ordinationYear: 1985, | ||
| 93 | - experience: 39, | ||
| 94 | - avatar: null, | ||
| 95 | - type: 'teacher' | ||
| 96 | - }, | ||
| 97 | - { | ||
| 98 | - id: 2, | ||
| 99 | - name: '智慧法师', | ||
| 100 | - title: '首座', | ||
| 101 | - role: '羯磨阿阇梨', | ||
| 102 | - temple: '大觉寺', | ||
| 103 | - ordinationYear: 1990, | ||
| 104 | - experience: 34, | ||
| 105 | - avatar: null, | ||
| 106 | - type: 'teacher' | ||
| 107 | - }, | ||
| 108 | - { | ||
| 109 | - id: 3, | ||
| 110 | - name: '觉悟法师', | ||
| 111 | - title: '监院', | ||
| 112 | - role: '教授阿阇梨', | ||
| 113 | - temple: '大觉寺', | ||
| 114 | - ordinationYear: 1992, | ||
| 115 | - experience: 32, | ||
| 116 | - avatar: null, | ||
| 117 | - type: 'teacher' | ||
| 118 | - }, | ||
| 119 | - { | ||
| 120 | - id: 4, | ||
| 121 | - name: '慈悲法师', | ||
| 122 | - title: '知客', | ||
| 123 | - role: '证明师', | ||
| 124 | - temple: '大觉寺', | ||
| 125 | - ordinationYear: 1995, | ||
| 126 | - experience: 29, | ||
| 127 | - avatar: null, | ||
| 128 | - type: 'witness' | ||
| 129 | - }, | ||
| 130 | - { | ||
| 131 | - id: 5, | ||
| 132 | - name: '般若法师', | ||
| 133 | - title: '维那', | ||
| 134 | - role: '证明师', | ||
| 135 | - temple: '大觉寺', | ||
| 136 | - ordinationYear: 1998, | ||
| 137 | - experience: 26, | ||
| 138 | - avatar: null, | ||
| 139 | - type: 'witness' | ||
| 140 | - }, | ||
| 141 | - { | ||
| 142 | - id: 6, | ||
| 143 | - name: '禅定法师', | ||
| 144 | - title: '典座', | ||
| 145 | - role: '证明师', | ||
| 146 | - temple: '大觉寺', | ||
| 147 | - ordinationYear: 2000, | ||
| 148 | - experience: 24, | ||
| 149 | - avatar: null, | ||
| 150 | - type: 'witness' | ||
| 151 | - }, | ||
| 152 | - { | ||
| 153 | - id: 7, | ||
| 154 | - name: '精进法师', | ||
| 155 | - title: '书记', | ||
| 156 | - role: '证明师', | ||
| 157 | - temple: '大觉寺', | ||
| 158 | - ordinationYear: 2002, | ||
| 159 | - experience: 22, | ||
| 160 | - avatar: null, | ||
| 161 | - type: 'witness' | ||
| 162 | - }, | ||
| 163 | - { | ||
| 164 | - id: 8, | ||
| 165 | - name: '持戒法师', | ||
| 166 | - title: '库头', | ||
| 167 | - role: '证明师', | ||
| 168 | - temple: '大觉寺', | ||
| 169 | - ordinationYear: 2005, | ||
| 170 | - experience: 19, | ||
| 171 | - avatar: null, | ||
| 172 | - type: 'witness' | ||
| 173 | - }, | ||
| 174 | - { | ||
| 175 | - id: 9, | ||
| 176 | - name: '忍辱法师', | ||
| 177 | - title: '僧值', | ||
| 178 | - role: '证明师', | ||
| 179 | - temple: '大觉寺', | ||
| 180 | - ordinationYear: 2008, | ||
| 181 | - experience: 16, | ||
| 182 | - avatar: null, | ||
| 183 | - type: 'witness' | ||
| 184 | - }, | ||
| 185 | - { | ||
| 186 | - id: 10, | ||
| 187 | - name: '布施法师', | ||
| 188 | - title: '衣钵', | ||
| 189 | - role: '证明师', | ||
| 190 | - temple: '大觉寺', | ||
| 191 | - ordinationYear: 2010, | ||
| 192 | - experience: 14, | ||
| 193 | - avatar: null, | ||
| 194 | - type: 'witness' | ||
| 195 | - } | ||
| 196 | -]) | ||
| 197 | - | ||
| 198 | -// 过滤后的法师列表 | ||
| 199 | -const filteredTeachers = computed(() => { | ||
| 200 | - if (activeTab.value === 'all') { | ||
| 201 | - return teachers.value | ||
| 202 | - } else if (activeTab.value === 'teachers') { | ||
| 203 | - return teachers.value.filter(teacher => teacher.type === 'teacher') | ||
| 204 | - } else if (activeTab.value === 'witnesses') { | ||
| 205 | - return teachers.value.filter(teacher => teacher.type === 'witness') | ||
| 206 | - } | ||
| 207 | - return teachers.value | ||
| 208 | -}) | ||
| 209 | - | ||
| 210 | -// 获取角色样式类 | ||
| 211 | -const getRoleClass = (role) => { | ||
| 212 | - if (role.includes('和尚') || role.includes('阿阇梨')) { | ||
| 213 | - return 'role-teacher' | ||
| 214 | - } | ||
| 215 | - return 'role-witness' | ||
| 216 | -} | ||
| 217 | - | ||
| 218 | -// 处理标签切换 | ||
| 219 | -const handleTabChange = (name) => { | ||
| 220 | - activeTab.value = name | ||
| 221 | -} | ||
| 222 | - | ||
| 223 | -// 处理法师点击 | ||
| 224 | -const handleTeacherClick = (teacher) => { | ||
| 225 | - router.push(`/teachers/${teacher.id}`) | ||
| 226 | -} | ||
| 227 | -</script> | ||
| 228 | - | ||
| 229 | -<style scoped> | ||
| 230 | -.page-container { | ||
| 231 | - min-height: 100vh; | ||
| 232 | - background: #fafafa; | ||
| 233 | -} | ||
| 234 | - | ||
| 235 | -.custom-nav { | ||
| 236 | - background: linear-gradient(135deg, #fbbf24, #f97316); | ||
| 237 | - color: white; | ||
| 238 | -} | ||
| 239 | - | ||
| 240 | -.custom-nav :deep(.van-nav-bar__title) { | ||
| 241 | - color: white; | ||
| 242 | - font-weight: 600; | ||
| 243 | -} | ||
| 244 | - | ||
| 245 | -.custom-nav :deep(.van-icon) { | ||
| 246 | - color: white; | ||
| 247 | -} | ||
| 248 | - | ||
| 249 | -.content-container { | ||
| 250 | - padding-top: 46px; | ||
| 251 | -} | ||
| 252 | - | ||
| 253 | -.intro-section { | ||
| 254 | - padding: 16px; | ||
| 255 | -} | ||
| 256 | - | ||
| 257 | -.intro-card { | ||
| 258 | - background: white; | ||
| 259 | - border-radius: 12px; | ||
| 260 | - padding: 20px; | ||
| 261 | - display: flex; | ||
| 262 | - align-items: center; | ||
| 263 | - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); | ||
| 264 | -} | ||
| 265 | - | ||
| 266 | -.intro-icon { | ||
| 267 | - font-size: 32px; | ||
| 268 | - margin-right: 16px; | ||
| 269 | -} | ||
| 270 | - | ||
| 271 | -.intro-content h3 { | ||
| 272 | - font-size: 18px; | ||
| 273 | - font-weight: 600; | ||
| 274 | - color: #333; | ||
| 275 | - margin: 0 0 8px 0; | ||
| 276 | -} | ||
| 277 | - | ||
| 278 | -.intro-content p { | ||
| 279 | - font-size: 14px; | ||
| 280 | - color: #666; | ||
| 281 | - margin: 0; | ||
| 282 | - line-height: 1.5; | ||
| 283 | -} | ||
| 284 | - | ||
| 285 | -.filter-section { | ||
| 286 | - background: white; | ||
| 287 | - border-bottom: 1px solid #eee; | ||
| 288 | -} | ||
| 289 | - | ||
| 290 | -.custom-tabs :deep(.van-tab) { | ||
| 291 | - font-weight: 500; | ||
| 292 | -} | ||
| 293 | - | ||
| 294 | -.custom-tabs :deep(.van-tab--active) { | ||
| 295 | - color: #f59e0b; | ||
| 296 | -} | ||
| 297 | - | ||
| 298 | -.custom-tabs :deep(.van-tabs__line) { | ||
| 299 | - background: #f59e0b; | ||
| 300 | -} | ||
| 301 | - | ||
| 302 | -.teachers-list { | ||
| 303 | - padding: 16px; | ||
| 304 | -} | ||
| 305 | - | ||
| 306 | -.teacher-card { | ||
| 307 | - background: white; | ||
| 308 | - border-radius: 12px; | ||
| 309 | - padding: 16px; | ||
| 310 | - margin-bottom: 12px; | ||
| 311 | - display: flex; | ||
| 312 | - align-items: center; | ||
| 313 | - gap: 16px; | ||
| 314 | - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); | ||
| 315 | - cursor: pointer; | ||
| 316 | - transition: all 0.3s ease; | ||
| 317 | -} | ||
| 318 | - | ||
| 319 | -.teacher-card:hover { | ||
| 320 | - transform: translateY(-3px); | ||
| 321 | - box-shadow: 0 6px 20px rgba(0, 0, 0, 0.15); | ||
| 322 | -} | ||
| 323 | - | ||
| 324 | -.teacher-card:active { | ||
| 325 | - transform: translateY(-1px); | ||
| 326 | - box-shadow: 0 3px 12px rgba(0, 0, 0, 0.12); | ||
| 327 | -} | ||
| 328 | - | ||
| 329 | -.teacher-avatar { | ||
| 330 | - width: 60px; | ||
| 331 | - height: 60px; | ||
| 332 | - border-radius: 50%; | ||
| 333 | - overflow: hidden; | ||
| 334 | - margin-right: 16px; | ||
| 335 | - flex-shrink: 0; | ||
| 336 | -} | ||
| 337 | - | ||
| 338 | -.teacher-avatar img { | ||
| 339 | - width: 100%; | ||
| 340 | - height: 100%; | ||
| 341 | - object-fit: cover; | ||
| 342 | -} | ||
| 343 | - | ||
| 344 | -.avatar-placeholder { | ||
| 345 | - width: 100%; | ||
| 346 | - height: 100%; | ||
| 347 | - background: linear-gradient(135deg, #fbbf24, #f97316); | ||
| 348 | - display: flex; | ||
| 349 | - align-items: center; | ||
| 350 | - justify-content: center; | ||
| 351 | - color: white; | ||
| 352 | - font-size: 24px; | ||
| 353 | - font-weight: 600; | ||
| 354 | -} | ||
| 355 | - | ||
| 356 | -.teacher-info { | ||
| 357 | - flex: 1; | ||
| 358 | -} | ||
| 359 | - | ||
| 360 | -.teacher-header { | ||
| 361 | - display: flex; | ||
| 362 | - align-items: center; | ||
| 363 | - justify-content: space-between; | ||
| 364 | - margin-bottom: 8px; | ||
| 365 | -} | ||
| 366 | - | ||
| 367 | -.teacher-name { | ||
| 368 | - font-size: 18px; | ||
| 369 | - font-weight: 600; | ||
| 370 | - color: #333; | ||
| 371 | - margin: 0; | ||
| 372 | -} | ||
| 373 | - | ||
| 374 | -.teacher-role { | ||
| 375 | - padding: 4px 8px; | ||
| 376 | - border-radius: 12px; | ||
| 377 | - font-size: 12px; | ||
| 378 | - font-weight: 500; | ||
| 379 | -} | ||
| 380 | - | ||
| 381 | -.role-teacher { | ||
| 382 | - background: linear-gradient(135deg, #fbbf24, #f97316); | ||
| 383 | - color: white; | ||
| 384 | -} | ||
| 385 | - | ||
| 386 | -.role-witness { | ||
| 387 | - background: #f0f9ff; | ||
| 388 | - color: #0369a1; | ||
| 389 | - border: 1px solid #bae6fd; | ||
| 390 | -} | ||
| 391 | - | ||
| 392 | -.teacher-details { | ||
| 393 | - space-y: 4px; | ||
| 394 | -} | ||
| 395 | - | ||
| 396 | -.teacher-title { | ||
| 397 | - font-size: 16px; | ||
| 398 | - color: #666; | ||
| 399 | - margin: 0 0 4px 0; | ||
| 400 | -} | ||
| 401 | - | ||
| 402 | -.teacher-temple { | ||
| 403 | - font-size: 14px; | ||
| 404 | - color: #999; | ||
| 405 | - margin: 0 0 8px 0; | ||
| 406 | -} | ||
| 407 | - | ||
| 408 | -.teacher-meta { | ||
| 409 | - display: flex; | ||
| 410 | - gap: 16px; | ||
| 411 | -} | ||
| 412 | - | ||
| 413 | -.ordination-year, | ||
| 414 | -.experience { | ||
| 415 | - font-size: 12px; | ||
| 416 | - color: #999; | ||
| 417 | - background: #f5f5f5; | ||
| 418 | - padding: 2px 6px; | ||
| 419 | - border-radius: 4px; | ||
| 420 | -} | ||
| 421 | - | ||
| 422 | -.teacher-actions { | ||
| 423 | - margin-left: 12px; | ||
| 424 | - color: #ccc; | ||
| 425 | -} | ||
| 426 | -</style> | ||
| ... | \ No newline at end of file | ... | \ No newline at end of file |
| 1 | -<template> | 1 | +<!-- |
| 2 | - <div class="page-container"> | 2 | + * @Date: 2025-01-01 15:20:00 |
| 3 | - <!-- 导航栏 --> | 3 | + * @LastEditors: hookehuyr hookehuyr@gmail.com |
| 4 | - <van-nav-bar title="义工服务" left-arrow @click-left="$router.back()" class="custom-nav"> | 4 | + * @LastEditTime: 2025-10-30 21:15:28 |
| 5 | - <template #right> | 5 | + * @FilePath: /stdj_h5/src/views/Volunteers.vue |
| 6 | - <van-icon name="plus" size="18" @click="handleAddVolunteer" /> | 6 | + * @Description: 义工页面 - 图片瀑布流展示 |
| 7 | - </template> | 7 | +--> |
| 8 | - </van-nav-bar> | ||
| 9 | - | ||
| 10 | - <!-- 内容区域 --> | ||
| 11 | - <div class="content-container"> | ||
| 12 | - <!-- 顶部统计 --> | ||
| 13 | - <div class="stats-section"> | ||
| 14 | - <div class="stat-card"> | ||
| 15 | - <div class="stat-icon">👥</div> | ||
| 16 | - <div class="stat-info"> | ||
| 17 | - <div class="stat-number">{{ totalVolunteers }}</div> | ||
| 18 | - <div class="stat-label">总义工数</div> | ||
| 19 | - </div> | ||
| 20 | - </div> | ||
| 21 | - <div class="stat-card"> | ||
| 22 | - <div class="stat-icon">✅</div> | ||
| 23 | - <div class="stat-info"> | ||
| 24 | - <div class="stat-number">{{ activeVolunteers }}</div> | ||
| 25 | - <div class="stat-label">在岗义工</div> | ||
| 26 | - </div> | ||
| 27 | - </div> | ||
| 28 | - <div class="stat-card"> | ||
| 29 | - <div class="stat-icon">📅</div> | ||
| 30 | - <div class="stat-info"> | ||
| 31 | - <div class="stat-number">{{ todayTasks }}</div> | ||
| 32 | - <div class="stat-label">今日任务</div> | ||
| 33 | - </div> | ||
| 34 | - </div> | ||
| 35 | - </div> | ||
| 36 | 8 | ||
| 37 | - <!-- 筛选栏 --> | 9 | +<template> |
| 38 | - <div class="filter-section"> | 10 | + <div class="volunteers-container"> |
| 39 | - <van-tabs v-model:active="activeTab" @change="handleTabChange" class="custom-tabs"> | 11 | + <!-- 瀑布流内容 --> |
| 40 | - <van-tab title="全部" name="all"></van-tab> | 12 | + <div class="waterfall-content"> |
| 41 | - <van-tab title="在岗" name="active"></van-tab> | 13 | + <van-list |
| 42 | - <van-tab title="休息" name="rest"></van-tab> | 14 | + v-model:loading="loading" |
| 43 | - <van-tab title="请假" name="leave"></van-tab> | 15 | + :finished="finished" |
| 44 | - </van-tabs> | 16 | + finished-text="没有更多了" |
| 45 | - </div> | 17 | + @load="onLoad" |
| 46 | - | 18 | + > |
| 47 | - <!-- 义工列表 --> | 19 | + <div class="waterfall-container"> |
| 48 | - <div class="volunteers-list"> | 20 | + <div class="waterfall-column" v-for="(column, index) in columns" :key="index"> |
| 49 | - <div | 21 | + <div |
| 50 | - v-for="volunteer in filteredVolunteers" | 22 | + class="waterfall-item" |
| 51 | - :key="volunteer.id" | 23 | + v-for="item in column" |
| 52 | - class="volunteer-card" | 24 | + :key="item.id" |
| 53 | - @click="handleVolunteerClick(volunteer)" | 25 | + @click="onImageClick(item)" |
| 54 | - > | 26 | + > |
| 55 | - <div class="volunteer-avatar"> | 27 | + <div class="image-wrapper"> |
| 56 | - <img v-if="volunteer.avatar" :src="volunteer.avatar" :alt="volunteer.name" /> | 28 | + <img |
| 57 | - <div v-else class="avatar-placeholder"> | 29 | + :src="item.url" |
| 58 | - <span>{{ volunteer.name.charAt(0) }}</span> | 30 | + :alt="item.title" |
| 59 | - </div> | 31 | + :style="{ height: item.height + 'px' }" |
| 60 | - <div class="status-badge" :class="getStatusClass(volunteer.status)"> | 32 | + @load="onImageLoad" |
| 61 | - {{ getStatusText(volunteer.status) }} | 33 | + @error="onImageError" |
| 62 | - </div> | 34 | + /> |
| 63 | - </div> | 35 | + <div class="image-overlay"> |
| 64 | - | 36 | + <span class="image-title">{{ item.title }}</span> |
| 65 | - <div class="volunteer-info"> | 37 | + </div> |
| 66 | - <div class="volunteer-header"> | ||
| 67 | - <h4 class="volunteer-name">{{ volunteer.name }}</h4> | ||
| 68 | - <div class="volunteer-level" :class="getLevelClass(volunteer.level)"> | ||
| 69 | - {{ volunteer.level }} | ||
| 70 | - </div> | ||
| 71 | - </div> | ||
| 72 | - | ||
| 73 | - <div class="volunteer-details"> | ||
| 74 | - <p class="volunteer-department">{{ volunteer.department }}</p> | ||
| 75 | - <p class="volunteer-task">当前任务:{{ volunteer.currentTask || '暂无' }}</p> | ||
| 76 | - <div class="volunteer-meta"> | ||
| 77 | - <span class="join-date">{{ volunteer.joinDate }}加入</span> | ||
| 78 | - <span class="service-hours">{{ volunteer.serviceHours }}小时</span> | ||
| 79 | </div> | 38 | </div> |
| 80 | </div> | 39 | </div> |
| 81 | </div> | 40 | </div> |
| 82 | - | ||
| 83 | - <div class="volunteer-actions"> | ||
| 84 | - <van-icon name="arrow" /> | ||
| 85 | - </div> | ||
| 86 | </div> | 41 | </div> |
| 87 | - </div> | 42 | + </van-list> |
| 88 | - | ||
| 89 | - <!-- 空状态 --> | ||
| 90 | - <van-empty v-if="filteredVolunteers.length === 0" description="暂无义工信息" /> | ||
| 91 | </div> | 43 | </div> |
| 92 | 44 | ||
| 93 | - <!-- 浮动按钮 --> | 45 | + <!-- 遮罩层弹窗 --> |
| 94 | - <van-floating-bubble | 46 | + <van-overlay :show="showOverlay" @click="closeOverlay"> |
| 95 | - axis="xy" | 47 | + <div class="overlay-content" @click.stop> |
| 96 | - icon="plus" | 48 | + <!-- 关闭按钮 --> |
| 97 | - @click="handleAddVolunteer" | 49 | + <div class="close-btn" @click="closeOverlay"> |
| 98 | - class="add-button" | 50 | + <van-icon name="cross" size="1.5rem" color="#fff" /> |
| 99 | - /> | 51 | + </div> |
| 52 | + | ||
| 53 | + <!-- 图片展示 --> | ||
| 54 | + <div class="overlay-image-wrapper"> | ||
| 55 | + <img | ||
| 56 | + :src="selectedImage?.url" | ||
| 57 | + :alt="selectedImage?.title" | ||
| 58 | + class="overlay-image" | ||
| 59 | + /> | ||
| 60 | + </div> | ||
| 61 | + | ||
| 62 | + <!-- 描述内容 --> | ||
| 63 | + <div class="overlay-description"> | ||
| 64 | + <h3 class="overlay-title">{{ selectedImage?.title }}</h3> | ||
| 65 | + <p class="overlay-text">{{ selectedImage?.description }}</p> | ||
| 66 | + </div> | ||
| 67 | + </div> | ||
| 68 | + </van-overlay> | ||
| 100 | </div> | 69 | </div> |
| 101 | </template> | 70 | </template> |
| 102 | 71 | ||
| 103 | <script setup> | 72 | <script setup> |
| 104 | -import { ref, computed } from 'vue' | 73 | +import { ref, reactive, onMounted } from 'vue' |
| 105 | -import { useRouter } from 'vue-router' | 74 | +import { generateWaterfallData } from '@/utils/mockData' |
| 106 | -import { Toast } from 'vant' | 75 | +import { useTitle } from '@vueuse/core'; |
| 107 | - | 76 | + |
| 108 | -const router = useRouter() | 77 | +useTitle('义工') |
| 109 | -const activeTab = ref('all') | 78 | + |
| 110 | - | 79 | +// 响应式数据 |
| 111 | -// 统计数据 | 80 | +const loading = ref(false) |
| 112 | -const totalVolunteers = ref(45) | 81 | +const finished = ref(false) |
| 113 | -const activeVolunteers = ref(32) | 82 | +const currentPage = ref(1) |
| 114 | -const todayTasks = ref(18) | 83 | +const pageSize = 10 |
| 115 | - | 84 | +const allImages = ref([]) |
| 116 | -// 义工数据 | 85 | +const columns = reactive([[], []]) |
| 117 | -const volunteers = ref([ | 86 | + |
| 118 | - { | 87 | +// 遮罩层相关状态 |
| 119 | - id: 1, | 88 | +const showOverlay = ref(false) |
| 120 | - name: '张慧敏', | 89 | +const selectedImage = ref(null) |
| 121 | - department: '客堂组', | 90 | + |
| 122 | - level: '资深义工', | 91 | +// 加载数据 |
| 123 | - status: 'active', | 92 | +const onLoad = async () => { |
| 124 | - currentTask: '接待来访信众', | 93 | + loading.value = true |
| 125 | - joinDate: '2022-03-15', | 94 | + |
| 126 | - serviceHours: 520, | 95 | + // 模拟网络延迟 |
| 127 | - avatar: null | 96 | + await new Promise(resolve => setTimeout(resolve, 1000)) |
| 128 | - }, | 97 | + |
| 129 | - { | 98 | + try { |
| 130 | - id: 2, | 99 | + const newData = generateWaterfallData(currentPage.value, pageSize) |
| 131 | - name: '李明德', | 100 | + |
| 132 | - department: '维护组', | 101 | + if (newData.length === 0) { |
| 133 | - level: '普通义工', | 102 | + finished.value = true |
| 134 | - status: 'active', | 103 | + } else { |
| 135 | - currentTask: '大殿清洁维护', | 104 | + allImages.value.push(...newData) |
| 136 | - joinDate: '2023-01-20', | 105 | + distributeImages(newData) |
| 137 | - serviceHours: 280, | 106 | + currentPage.value++ |
| 138 | - avatar: null | 107 | + } |
| 139 | - }, | 108 | + } catch (error) { |
| 140 | - { | 109 | + console.error('加载数据失败:', error) |
| 141 | - id: 3, | 110 | + } finally { |
| 142 | - name: '王慈悲', | 111 | + loading.value = false |
| 143 | - department: '斋堂组', | ||
| 144 | - level: '组长', | ||
| 145 | - status: 'active', | ||
| 146 | - currentTask: '午斋准备工作', | ||
| 147 | - joinDate: '2021-08-10', | ||
| 148 | - serviceHours: 750, | ||
| 149 | - avatar: null | ||
| 150 | - }, | ||
| 151 | - { | ||
| 152 | - id: 4, | ||
| 153 | - name: '陈智慧', | ||
| 154 | - department: '法务组', | ||
| 155 | - level: '资深义工', | ||
| 156 | - status: 'rest', | ||
| 157 | - currentTask: null, | ||
| 158 | - joinDate: '2022-06-05', | ||
| 159 | - serviceHours: 420, | ||
| 160 | - avatar: null | ||
| 161 | - }, | ||
| 162 | - { | ||
| 163 | - id: 5, | ||
| 164 | - name: '刘精进', | ||
| 165 | - department: '安保组', | ||
| 166 | - level: '普通义工', | ||
| 167 | - status: 'leave', | ||
| 168 | - currentTask: null, | ||
| 169 | - joinDate: '2023-04-12', | ||
| 170 | - serviceHours: 150, | ||
| 171 | - avatar: null | ||
| 172 | - }, | ||
| 173 | - { | ||
| 174 | - id: 6, | ||
| 175 | - name: '赵般若', | ||
| 176 | - department: '文宣组', | ||
| 177 | - level: '资深义工', | ||
| 178 | - status: 'active', | ||
| 179 | - currentTask: '活动摄影记录', | ||
| 180 | - joinDate: '2022-11-30', | ||
| 181 | - serviceHours: 380, | ||
| 182 | - avatar: null | ||
| 183 | - }, | ||
| 184 | - { | ||
| 185 | - id: 7, | ||
| 186 | - name: '孙持戒', | ||
| 187 | - department: '客堂组', | ||
| 188 | - level: '普通义工', | ||
| 189 | - status: 'active', | ||
| 190 | - currentTask: '登记来访信息', | ||
| 191 | - joinDate: '2023-07-08', | ||
| 192 | - serviceHours: 95, | ||
| 193 | - avatar: null | ||
| 194 | - }, | ||
| 195 | - { | ||
| 196 | - id: 8, | ||
| 197 | - name: '周忍辱', | ||
| 198 | - department: '斋堂组', | ||
| 199 | - level: '普通义工', | ||
| 200 | - status: 'rest', | ||
| 201 | - currentTask: null, | ||
| 202 | - joinDate: '2023-02-14', | ||
| 203 | - serviceHours: 220, | ||
| 204 | - avatar: null | ||
| 205 | } | 112 | } |
| 206 | -]) | 113 | +} |
| 207 | 114 | ||
| 208 | -// 过滤后的义工列表 | 115 | +// 分配图片到两列 |
| 209 | -const filteredVolunteers = computed(() => { | 116 | +const distributeImages = (images) => { |
| 210 | - if (activeTab.value === 'all') { | 117 | + images.forEach(image => { |
| 211 | - return volunteers.value | 118 | + // 计算两列的当前高度 |
| 212 | - } | 119 | + const leftHeight = columns[0].reduce((sum, item) => sum + item.height + 20, 0) |
| 213 | - return volunteers.value.filter(volunteer => volunteer.status === activeTab.value) | 120 | + const rightHeight = columns[1].reduce((sum, item) => sum + item.height + 20, 0) |
| 214 | -}) | ||
| 215 | 121 | ||
| 216 | -// 获取状态样式类 | 122 | + // 将图片添加到高度较小的列 |
| 217 | -const getStatusClass = (status) => { | 123 | + if (leftHeight <= rightHeight) { |
| 218 | - const classes = { | 124 | + columns[0].push(image) |
| 219 | - active: 'status-active', | 125 | + } else { |
| 220 | - rest: 'status-rest', | 126 | + columns[1].push(image) |
| 221 | - leave: 'status-leave' | 127 | + } |
| 222 | - } | 128 | + }) |
| 223 | - return classes[status] || 'status-rest' | ||
| 224 | } | 129 | } |
| 225 | 130 | ||
| 226 | -// 获取状态文本 | 131 | +// 图片点击事件 |
| 227 | -const getStatusText = (status) => { | 132 | +const onImageClick = (item) => { |
| 228 | - const texts = { | 133 | + console.log('点击图片:', item) |
| 229 | - active: '在岗', | 134 | + selectedImage.value = item |
| 230 | - rest: '休息', | 135 | + showOverlay.value = true |
| 231 | - leave: '请假' | ||
| 232 | - } | ||
| 233 | - return texts[status] || '休息' | ||
| 234 | } | 136 | } |
| 235 | 137 | ||
| 236 | -// 获取等级样式类 | 138 | +// 关闭遮罩层 |
| 237 | -const getLevelClass = (level) => { | 139 | +const closeOverlay = () => { |
| 238 | - if (level === '组长') return 'level-leader' | 140 | + showOverlay.value = false |
| 239 | - if (level === '资深义工') return 'level-senior' | 141 | + selectedImage.value = null |
| 240 | - return 'level-normal' | ||
| 241 | } | 142 | } |
| 242 | 143 | ||
| 243 | -// 处理标签切换 | 144 | +// 图片加载成功 |
| 244 | -const handleTabChange = (name) => { | 145 | +const onImageLoad = (event) => { |
| 245 | - activeTab.value = name | 146 | + console.log('图片加载成功:', event.target.src) |
| 246 | } | 147 | } |
| 247 | 148 | ||
| 248 | -// 处理义工点击 | 149 | +// 图片加载失败 |
| 249 | -const handleVolunteerClick = (volunteer) => { | 150 | +const onImageError = (event) => { |
| 250 | - router.push(`/volunteers/${volunteer.id}`) | 151 | + console.error('图片加载失败:', event.target.src) |
| 152 | + // 可以设置默认图片 | ||
| 153 | + event.target.src = 'https://via.placeholder.com/300x400?text=加载失败' | ||
| 251 | } | 154 | } |
| 252 | 155 | ||
| 253 | -// 处理添加义工 | 156 | +// 组件挂载时初始化 |
| 254 | -const handleAddVolunteer = () => { | 157 | +onMounted(() => { |
| 255 | - Toast('添加义工功能开发中...') | 158 | + // 初始加载第一页数据 |
| 256 | -} | 159 | + onLoad() |
| 160 | +}) | ||
| 257 | </script> | 161 | </script> |
| 258 | 162 | ||
| 259 | <style scoped> | 163 | <style scoped> |
| 260 | -.page-container { | 164 | +.volunteers-container { |
| 165 | + background-color: #F2EBDB; | ||
| 261 | min-height: 100vh; | 166 | min-height: 100vh; |
| 262 | - background: #fafafa; | 167 | + background-color: #f5f5f5; |
| 263 | } | 168 | } |
| 264 | 169 | ||
| 265 | -.custom-nav { | 170 | +.header { |
| 266 | - background: linear-gradient(135deg, #fbbf24, #f97316); | 171 | + position: sticky; |
| 267 | - color: white; | 172 | + top: 0; |
| 173 | + z-index: 100; | ||
| 174 | + background-color: #fff; | ||
| 268 | } | 175 | } |
| 269 | 176 | ||
| 270 | -.custom-nav :deep(.van-nav-bar__title) { | 177 | +.waterfall-content { |
| 271 | - color: white; | 178 | + padding: 1rem; |
| 272 | - font-weight: 600; | ||
| 273 | -} | ||
| 274 | - | ||
| 275 | -.custom-nav :deep(.van-icon) { | ||
| 276 | - color: white; | ||
| 277 | } | 179 | } |
| 278 | 180 | ||
| 279 | -.content-container { | 181 | +.waterfall-container { |
| 280 | - padding-top: 46px; | ||
| 281 | -} | ||
| 282 | - | ||
| 283 | -.stats-section { | ||
| 284 | display: flex; | 182 | display: flex; |
| 285 | - gap: 12px; | 183 | + gap: 0.75rem; |
| 286 | - padding: 16px; | 184 | + align-items: flex-start; |
| 287 | } | 185 | } |
| 288 | 186 | ||
| 289 | -.stat-card { | 187 | +.waterfall-column { |
| 290 | flex: 1; | 188 | flex: 1; |
| 291 | - background: white; | ||
| 292 | - border-radius: 12px; | ||
| 293 | - padding: 16px; | ||
| 294 | display: flex; | 189 | display: flex; |
| 295 | - align-items: center; | 190 | + flex-direction: column; |
| 296 | - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); | 191 | + gap: 0.75rem; |
| 297 | -} | ||
| 298 | - | ||
| 299 | -.stat-icon { | ||
| 300 | - font-size: 24px; | ||
| 301 | - margin-right: 12px; | ||
| 302 | -} | ||
| 303 | - | ||
| 304 | -.stat-info { | ||
| 305 | - flex: 1; | ||
| 306 | -} | ||
| 307 | - | ||
| 308 | -.stat-number { | ||
| 309 | - font-size: 20px; | ||
| 310 | - font-weight: 700; | ||
| 311 | - color: #f59e0b; | ||
| 312 | - margin-bottom: 2px; | ||
| 313 | -} | ||
| 314 | - | ||
| 315 | -.stat-label { | ||
| 316 | - font-size: 12px; | ||
| 317 | - color: #666; | ||
| 318 | -} | ||
| 319 | - | ||
| 320 | -.filter-section { | ||
| 321 | - background: white; | ||
| 322 | - border-bottom: 1px solid #eee; | ||
| 323 | -} | ||
| 324 | - | ||
| 325 | -.custom-tabs :deep(.van-tab) { | ||
| 326 | - font-weight: 500; | ||
| 327 | -} | ||
| 328 | - | ||
| 329 | -.custom-tabs :deep(.van-tab--active) { | ||
| 330 | - color: #f59e0b; | ||
| 331 | -} | ||
| 332 | - | ||
| 333 | -.custom-tabs :deep(.van-tabs__line) { | ||
| 334 | - background: #f59e0b; | ||
| 335 | -} | ||
| 336 | - | ||
| 337 | -.volunteers-list { | ||
| 338 | - padding: 16px; | ||
| 339 | } | 192 | } |
| 340 | 193 | ||
| 341 | -.volunteer-card { | 194 | +.waterfall-item { |
| 342 | - background: white; | 195 | + background-color: #fff; |
| 343 | - border-radius: 12px; | 196 | + border-radius: 0.5rem; |
| 344 | - padding: 16px; | 197 | + overflow: hidden; |
| 345 | - margin-bottom: 12px; | ||
| 346 | - display: flex; | ||
| 347 | - align-items: center; | ||
| 348 | - gap: 16px; | ||
| 349 | box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); | 198 | box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); |
| 199 | + transition: transform 0.2s ease, box-shadow 0.2s ease; | ||
| 350 | cursor: pointer; | 200 | cursor: pointer; |
| 351 | - transition: all 0.3s ease; | ||
| 352 | -} | ||
| 353 | - | ||
| 354 | -.volunteer-card:hover { | ||
| 355 | - transform: translateY(-3px); | ||
| 356 | - box-shadow: 0 6px 20px rgba(0, 0, 0, 0.15); | ||
| 357 | } | 201 | } |
| 358 | 202 | ||
| 359 | -.volunteer-card:active { | 203 | +.waterfall-item:hover { |
| 360 | - transform: translateY(-1px); | 204 | + transform: translateY(-2px); |
| 361 | - box-shadow: 0 3px 12px rgba(0, 0, 0, 0.12); | 205 | + box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15); |
| 362 | } | 206 | } |
| 363 | 207 | ||
| 364 | -.volunteer-avatar { | 208 | +.image-wrapper { |
| 365 | position: relative; | 209 | position: relative; |
| 366 | - width: 60px; | ||
| 367 | - height: 60px; | ||
| 368 | - border-radius: 50%; | ||
| 369 | overflow: hidden; | 210 | overflow: hidden; |
| 370 | - margin-right: 16px; | ||
| 371 | - flex-shrink: 0; | ||
| 372 | } | 211 | } |
| 373 | 212 | ||
| 374 | -.volunteer-avatar img { | 213 | +.image-wrapper img { |
| 375 | width: 100%; | 214 | width: 100%; |
| 376 | - height: 100%; | 215 | + display: block; |
| 377 | object-fit: cover; | 216 | object-fit: cover; |
| 217 | + transition: transform 0.3s ease; | ||
| 378 | } | 218 | } |
| 379 | 219 | ||
| 380 | -.avatar-placeholder { | 220 | +.waterfall-item:hover .image-wrapper img { |
| 381 | - width: 100%; | 221 | + transform: scale(1.05); |
| 382 | - height: 100%; | ||
| 383 | - background: linear-gradient(135deg, #fbbf24, #f97316); | ||
| 384 | - display: flex; | ||
| 385 | - align-items: center; | ||
| 386 | - justify-content: center; | ||
| 387 | - color: white; | ||
| 388 | - font-size: 24px; | ||
| 389 | - font-weight: 600; | ||
| 390 | } | 222 | } |
| 391 | 223 | ||
| 392 | -.status-badge { | 224 | +.image-overlay { |
| 393 | position: absolute; | 225 | position: absolute; |
| 394 | - bottom: -2px; | 226 | + bottom: 0; |
| 395 | - right: -2px; | 227 | + left: 0; |
| 396 | - padding: 2px 6px; | 228 | + right: 0; |
| 397 | - border-radius: 8px; | 229 | + background: linear-gradient(transparent, rgba(0, 0, 0, 0.7)); |
| 398 | - font-size: 10px; | 230 | + padding: 1rem 0.75rem 0.75rem; |
| 399 | - font-weight: 500; | 231 | + transform: translateY(100%); |
| 400 | - border: 2px solid white; | 232 | + transition: transform 0.3s ease; |
| 401 | } | 233 | } |
| 402 | 234 | ||
| 403 | -.status-active { | 235 | +.waterfall-item:hover .image-overlay { |
| 404 | - background: #10b981; | 236 | + transform: translateY(0); |
| 405 | - color: white; | ||
| 406 | } | 237 | } |
| 407 | 238 | ||
| 408 | -.status-rest { | 239 | +.image-title { |
| 409 | - background: #6b7280; | 240 | + color: #fff; |
| 410 | - color: white; | 241 | + font-size: 0.875rem; |
| 242 | + font-weight: 500; | ||
| 243 | + line-height: 1.4; | ||
| 411 | } | 244 | } |
| 412 | 245 | ||
| 413 | -.status-leave { | 246 | +/* 加载状态样式 */ |
| 414 | - background: #ef4444; | 247 | +:deep(.van-list__loading) { |
| 415 | - color: white; | 248 | + padding: 1rem; |
| 249 | + text-align: center; | ||
| 250 | + color: #969799; | ||
| 416 | } | 251 | } |
| 417 | 252 | ||
| 418 | -.volunteer-info { | 253 | +:deep(.van-list__finished-text) { |
| 419 | - flex: 1; | 254 | + padding: 1rem; |
| 255 | + text-align: center; | ||
| 256 | + color: #969799; | ||
| 257 | + font-size: 0.875rem; | ||
| 420 | } | 258 | } |
| 421 | 259 | ||
| 422 | -.volunteer-header { | 260 | +/* 响应式设计 */ |
| 423 | - display: flex; | 261 | +@media (max-width: 480px) { |
| 424 | - align-items: center; | 262 | + .waterfall-content { |
| 425 | - justify-content: space-between; | 263 | + padding: 0.75rem; |
| 426 | - margin-bottom: 8px; | 264 | + } |
| 427 | -} | ||
| 428 | - | ||
| 429 | -.volunteer-name { | ||
| 430 | - font-size: 18px; | ||
| 431 | - font-weight: 600; | ||
| 432 | - color: #333; | ||
| 433 | - margin: 0; | ||
| 434 | -} | ||
| 435 | 265 | ||
| 436 | -.volunteer-level { | 266 | + .waterfall-container { |
| 437 | - padding: 4px 8px; | 267 | + gap: 0.5rem; |
| 438 | - border-radius: 12px; | 268 | + } |
| 439 | - font-size: 12px; | ||
| 440 | - font-weight: 500; | ||
| 441 | -} | ||
| 442 | 269 | ||
| 443 | -.level-leader { | 270 | + .waterfall-column { |
| 444 | - background: linear-gradient(135deg, #fbbf24, #f97316); | 271 | + gap: 0.5rem; |
| 445 | - color: white; | 272 | + } |
| 446 | -} | ||
| 447 | 273 | ||
| 448 | -.level-senior { | 274 | + .image-title { |
| 449 | - background: #dbeafe; | 275 | + font-size: 0.8125rem; |
| 450 | - color: #1d4ed8; | 276 | + } |
| 451 | - border: 1px solid #93c5fd; | ||
| 452 | } | 277 | } |
| 453 | 278 | ||
| 454 | -.level-normal { | 279 | +/* 骨架屏效果 */ |
| 455 | - background: #f3f4f6; | 280 | +.waterfall-item.loading { |
| 456 | - color: #6b7280; | 281 | + background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%); |
| 457 | - border: 1px solid #d1d5db; | 282 | + background-size: 200% 100%; |
| 283 | + animation: loading 1.5s infinite; | ||
| 458 | } | 284 | } |
| 459 | 285 | ||
| 460 | -.volunteer-details { | 286 | +@keyframes loading { |
| 461 | - space-y: 4px; | 287 | + 0% { |
| 288 | + background-position: 200% 0; | ||
| 289 | + } | ||
| 290 | + 100% { | ||
| 291 | + background-position: -200% 0; | ||
| 292 | + } | ||
| 462 | } | 293 | } |
| 463 | 294 | ||
| 464 | -.volunteer-department { | 295 | +/* 遮罩层样式 */ |
| 465 | - font-size: 16px; | 296 | +:deep(.van-overlay) { |
| 466 | - color: #666; | 297 | + display: flex; |
| 467 | - margin: 0 0 4px 0; | 298 | + align-items: center; |
| 299 | + justify-content: center; | ||
| 300 | + padding: 1rem; | ||
| 468 | } | 301 | } |
| 469 | 302 | ||
| 470 | -.volunteer-task { | 303 | +.overlay-content { |
| 471 | - font-size: 14px; | 304 | + background-color: #fff; |
| 472 | - color: #999; | 305 | + border-radius: 1rem; |
| 473 | - margin: 0 0 8px 0; | 306 | + max-width: 90vw; |
| 307 | + max-height: 80vh; | ||
| 308 | + overflow: hidden; | ||
| 309 | + position: relative; | ||
| 310 | + box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3); | ||
| 474 | } | 311 | } |
| 475 | 312 | ||
| 476 | -.volunteer-meta { | 313 | +.close-btn { |
| 314 | + position: absolute; | ||
| 315 | + top: 1rem; | ||
| 316 | + right: 1rem; | ||
| 317 | + width: 2.5rem; | ||
| 318 | + height: 2.5rem; | ||
| 319 | + background-color: rgba(0, 0, 0, 0.5); | ||
| 320 | + border-radius: 50%; | ||
| 477 | display: flex; | 321 | display: flex; |
| 478 | - gap: 16px; | 322 | + align-items: center; |
| 323 | + justify-content: center; | ||
| 324 | + cursor: pointer; | ||
| 325 | + z-index: 10; | ||
| 326 | + transition: background-color 0.2s ease; | ||
| 479 | } | 327 | } |
| 480 | 328 | ||
| 481 | -.join-date, | 329 | +.close-btn:hover { |
| 482 | -.service-hours { | 330 | + background-color: rgba(0, 0, 0, 0.7); |
| 483 | - font-size: 12px; | ||
| 484 | - color: #999; | ||
| 485 | - background: #f5f5f5; | ||
| 486 | - padding: 2px 6px; | ||
| 487 | - border-radius: 4px; | ||
| 488 | } | 331 | } |
| 489 | 332 | ||
| 490 | -.volunteer-actions { | 333 | +.overlay-image-wrapper { |
| 491 | - margin-left: 12px; | 334 | + width: 100%; |
| 492 | - color: #ccc; | 335 | + max-height: 60vh; |
| 336 | + overflow: hidden; | ||
| 337 | + display: flex; | ||
| 338 | + align-items: center; | ||
| 339 | + justify-content: center; | ||
| 340 | + background-color: #f5f5f5; | ||
| 493 | } | 341 | } |
| 494 | 342 | ||
| 495 | -.add-button { | 343 | +.overlay-image { |
| 496 | - background: linear-gradient(135deg, #fbbf24, #f97316) !important; | 344 | + width: 100%; |
| 497 | - transition: all 0.3s ease; | 345 | + height: auto; |
| 498 | - animation: float 3s ease-in-out infinite; | 346 | + max-height: 60vh; |
| 347 | + object-fit: contain; | ||
| 348 | + display: block; | ||
| 499 | } | 349 | } |
| 500 | 350 | ||
| 501 | -.add-button:hover { | 351 | +.overlay-description { |
| 502 | - transform: translateY(-3px) scale(1.1); | 352 | + padding: 1.5rem; |
| 503 | - box-shadow: 0 8px 25px rgba(251, 191, 36, 0.6); | 353 | + background-color: #fff; |
| 504 | } | 354 | } |
| 505 | 355 | ||
| 506 | -.add-button:active { | 356 | +.overlay-title { |
| 507 | - transform: translateY(-1px) scale(1.05); | 357 | + font-size: 1.25rem; |
| 508 | - box-shadow: 0 4px 16px rgba(251, 191, 36, 0.4); | 358 | + font-weight: 600; |
| 359 | + color: #333; | ||
| 360 | + margin: 0 0 1rem 0; | ||
| 361 | + line-height: 1.4; | ||
| 509 | } | 362 | } |
| 510 | 363 | ||
| 511 | -.add-button :deep(.van-floating-bubble__icon) { | 364 | +.overlay-text { |
| 512 | - color: white; | 365 | + font-size: 1rem; |
| 366 | + color: #666; | ||
| 367 | + line-height: 1.6; | ||
| 368 | + margin: 0; | ||
| 369 | + white-space: pre-wrap; | ||
| 513 | } | 370 | } |
| 514 | 371 | ||
| 515 | -@keyframes float { | 372 | +/* 移动端适配 */ |
| 516 | - 0%, 100% { | 373 | +@media (max-width: 480px) { |
| 517 | - transform: translateY(0px); | 374 | + .overlay-content { |
| 375 | + max-width: 95vw; | ||
| 376 | + max-height: 85vh; | ||
| 377 | + border-radius: 0.75rem; | ||
| 378 | + } | ||
| 379 | + | ||
| 380 | + .close-btn { | ||
| 381 | + top: 0.75rem; | ||
| 382 | + right: 0.75rem; | ||
| 383 | + width: 2rem; | ||
| 384 | + height: 2rem; | ||
| 385 | + } | ||
| 386 | + | ||
| 387 | + .overlay-description { | ||
| 388 | + padding: 1rem; | ||
| 389 | + } | ||
| 390 | + | ||
| 391 | + .overlay-title { | ||
| 392 | + font-size: 1.125rem; | ||
| 518 | } | 393 | } |
| 519 | - 50% { | 394 | + |
| 520 | - transform: translateY(-10px); | 395 | + .overlay-text { |
| 396 | + font-size: 0.875rem; | ||
| 521 | } | 397 | } |
| 522 | } | 398 | } |
| 523 | -</style> | ||
| ... | \ No newline at end of file | ... | \ No newline at end of file |
| 399 | +</style> | ... | ... |
-
Please register or login to post a comment