feat(打卡): 新增打卡首页功能
- 添加打卡首页路由和页面组件 - 实现日历打卡展示、目标进度和团队动态功能 - 扩展AppLayout组件支持无标题模式 - 新增Vant组件类型声明 ``` 这个提交消息遵循了以下原则: 1. 使用`feat`类型表示新增功能 2. 添加了`(打卡)`范围明确修改领域 3. 简要描述主要变更内容 4. 在消息体中列出关键修改点,保持简洁 5. 使用中文简体符合要求 6. 每个条目使用动词开头保持一致性
Showing
4 changed files
with
437 additions
and
3 deletions
| ... | @@ -30,8 +30,11 @@ declare module 'vue' { | ... | @@ -30,8 +30,11 @@ declare module 'vue' { |
| 30 | UploadVideoPopup: typeof import('./components/ui/UploadVideoPopup.vue')['default'] | 30 | UploadVideoPopup: typeof import('./components/ui/UploadVideoPopup.vue')['default'] |
| 31 | VanActionSheet: typeof import('vant/es')['ActionSheet'] | 31 | VanActionSheet: typeof import('vant/es')['ActionSheet'] |
| 32 | VanButton: typeof import('vant/es')['Button'] | 32 | VanButton: typeof import('vant/es')['Button'] |
| 33 | + VanCalendar: typeof import('vant/es')['Calendar'] | ||
| 33 | VanCellGroup: typeof import('vant/es')['CellGroup'] | 34 | VanCellGroup: typeof import('vant/es')['CellGroup'] |
| 34 | VanCheckbox: typeof import('vant/es')['Checkbox'] | 35 | VanCheckbox: typeof import('vant/es')['Checkbox'] |
| 36 | + VanCol: typeof import('vant/es')['Col'] | ||
| 37 | + VanConfigProvider: typeof import('vant/es')['ConfigProvider'] | ||
| 35 | VanDatePicker: typeof import('vant/es')['DatePicker'] | 38 | VanDatePicker: typeof import('vant/es')['DatePicker'] |
| 36 | VanDialog: typeof import('vant/es')['Dialog'] | 39 | VanDialog: typeof import('vant/es')['Dialog'] |
| 37 | VanEmpty: typeof import('vant/es')['Empty'] | 40 | VanEmpty: typeof import('vant/es')['Empty'] |
| ... | @@ -47,6 +50,7 @@ declare module 'vue' { | ... | @@ -47,6 +50,7 @@ declare module 'vue' { |
| 47 | VanPopup: typeof import('vant/es')['Popup'] | 50 | VanPopup: typeof import('vant/es')['Popup'] |
| 48 | VanProgress: typeof import('vant/es')['Progress'] | 51 | VanProgress: typeof import('vant/es')['Progress'] |
| 49 | VanRate: typeof import('vant/es')['Rate'] | 52 | VanRate: typeof import('vant/es')['Rate'] |
| 53 | + VanRow: typeof import('vant/es')['Row'] | ||
| 50 | VanSwipe: typeof import('vant/es')['Swipe'] | 54 | VanSwipe: typeof import('vant/es')['Swipe'] |
| 51 | VanSwipeItem: typeof import('vant/es')['SwipeItem'] | 55 | VanSwipeItem: typeof import('vant/es')['SwipeItem'] |
| 52 | VanTab: typeof import('vant/es')['Tab'] | 56 | VanTab: typeof import('vant/es')['Tab'] | ... | ... |
| 1 | <!-- | 1 | <!-- |
| 2 | * @Date: 2025-03-20 20:36:36 | 2 | * @Date: 2025-03-20 20:36:36 |
| 3 | * @LastEditors: hookehuyr hookehuyr@gmail.com | 3 | * @LastEditors: hookehuyr hookehuyr@gmail.com |
| 4 | - * @LastEditTime: 2025-03-24 14:05:01 | 4 | + * @LastEditTime: 2025-05-29 15:46:57 |
| 5 | * @FilePath: /mlaj/src/components/layout/AppLayout.vue | 5 | * @FilePath: /mlaj/src/components/layout/AppLayout.vue |
| 6 | * @Description: 文件描述 | 6 | * @Description: 文件描述 |
| 7 | --> | 7 | --> |
| ... | @@ -14,7 +14,7 @@ | ... | @@ -14,7 +14,7 @@ |
| 14 | :onBack="handleBack" | 14 | :onBack="handleBack" |
| 15 | :rightContent="rightContent" | 15 | :rightContent="rightContent" |
| 16 | /> | 16 | /> |
| 17 | - <main :class="{ 'pb-16': title, 'py-4': !title && route.path !== '/profile' }"> | 17 | + <main :class="{ 'pb-16': title, 'py-4': (!title && route.path !== '/profile') && hasTitle }"> |
| 18 | <slot></slot> | 18 | <slot></slot> |
| 19 | </main> | 19 | </main> |
| 20 | <BottomNav v-if="!hideBottomNav" /> | 20 | <BottomNav v-if="!hideBottomNav" /> |
| ... | @@ -48,6 +48,10 @@ const props = defineProps({ | ... | @@ -48,6 +48,10 @@ const props = defineProps({ |
| 48 | hideBottomNav: { | 48 | hideBottomNav: { |
| 49 | type: Boolean, | 49 | type: Boolean, |
| 50 | default: false | 50 | default: false |
| 51 | + }, | ||
| 52 | + hasTitle: { | ||
| 53 | + type: Boolean, | ||
| 54 | + default: true | ||
| 51 | } | 55 | } |
| 52 | }) | 56 | }) |
| 53 | 57 | ... | ... |
| 1 | /* | 1 | /* |
| 2 | * @Date: 2025-03-21 13:28:30 | 2 | * @Date: 2025-03-21 13:28:30 |
| 3 | * @LastEditors: hookehuyr hookehuyr@gmail.com | 3 | * @LastEditors: hookehuyr hookehuyr@gmail.com |
| 4 | - * @LastEditTime: 2025-03-21 13:33:06 | 4 | + * @LastEditTime: 2025-05-29 15:36:20 |
| 5 | * @FilePath: /mlaj/src/router/checkin.js | 5 | * @FilePath: /mlaj/src/router/checkin.js |
| 6 | * @Description: 文件描述 | 6 | * @Description: 文件描述 |
| 7 | */ | 7 | */ |
| ... | @@ -41,5 +41,14 @@ export default [ | ... | @@ -41,5 +41,14 @@ export default [ |
| 41 | title: '反思打卡', | 41 | title: '反思打卡', |
| 42 | requiresAuth: true | 42 | requiresAuth: true |
| 43 | } | 43 | } |
| 44 | + }, | ||
| 45 | + { | ||
| 46 | + path: '/checkin/index', | ||
| 47 | + name: 'IndexCheckIn', | ||
| 48 | + component: () => import('@/views/checkin/IndexCheckInPage.vue'), | ||
| 49 | + meta: { | ||
| 50 | + title: '打卡首页', | ||
| 51 | + requiresAuth: true | ||
| 52 | + } | ||
| 44 | } | 53 | } |
| 45 | ] | 54 | ] | ... | ... |
src/views/checkin/IndexCheckInPage.vue
0 → 100644
| 1 | +<!-- | ||
| 2 | + * @Date: 2025-05-29 15:34:17 | ||
| 3 | + * @LastEditors: hookehuyr hookehuyr@gmail.com | ||
| 4 | + * @LastEditTime: 2025-05-30 15:07:29 | ||
| 5 | + * @FilePath: /mlaj/src/views/checkin/IndexCheckInPage.vue | ||
| 6 | + * @Description: 文件描述 | ||
| 7 | +--> | ||
| 8 | +<template> | ||
| 9 | + <AppLayout :hasTitle="false"> | ||
| 10 | + <van-config-provider :theme-vars="themeVars"> | ||
| 11 | + <van-calendar | ||
| 12 | + title="每日打卡" | ||
| 13 | + :poppable="false" | ||
| 14 | + :show-confirm="false" | ||
| 15 | + :style="{ height: '24rem' }" | ||
| 16 | + switch-mode="year-month" | ||
| 17 | + color="#4caf50" | ||
| 18 | + :formatter="formatter" | ||
| 19 | + row-height="42" | ||
| 20 | + :show-mark="false" | ||
| 21 | + @click-subtitle="onClickSubtitle" | ||
| 22 | + > | ||
| 23 | + </van-calendar> | ||
| 24 | + | ||
| 25 | + <div class="text-wrapper"> | ||
| 26 | + <div class="text-header">目标进度</div> | ||
| 27 | + <div class="grade-percentage-main"> | ||
| 28 | + <van-row justify="space-between" style="margin: 0.5rem 0; font-size: 0.9rem;"> | ||
| 29 | + <van-col span="12"> | ||
| 30 | + <span>年级目标</span> | ||
| 31 | + </van-col> | ||
| 32 | + <van-col span="12" style="text-align: right;"> | ||
| 33 | + <span style="font-weight: bold;">{{ progress1 }}%</span> | ||
| 34 | + </van-col> | ||
| 35 | + </van-row> | ||
| 36 | + <van-progress :percentage="progress1" color="#4caf50" :show-pivot="false" /> | ||
| 37 | + </div> | ||
| 38 | + <div class="class-percentage-main"> | ||
| 39 | + <van-row justify="space-between" style="margin: 0.5rem 0; font-size: 0.9rem;"> | ||
| 40 | + <van-col span="12"> | ||
| 41 | + <span>班级目标</span> | ||
| 42 | + </van-col> | ||
| 43 | + <van-col span="12" style="text-align: right;"> | ||
| 44 | + <span style="font-weight: bold;">{{ progress2 }}%</span> | ||
| 45 | + </van-col> | ||
| 46 | + </van-row> | ||
| 47 | + <van-progress :percentage="progress2" color="#4caf50" :show-pivot="false" /> | ||
| 48 | + </div> | ||
| 49 | + <div style="padding: 0.75rem 1rem;"> | ||
| 50 | + <van-image round width="2.8rem" height="2.8rem" src="https://fastly.jsdelivr.net/npm/@vant/assets/cat.jpeg" v-for="(item, index) in teamAvatars" :key="index" :style="{ marginLeft: index > 0 ? '-0.5rem' : '', border: '2px solid #FFF' }" /> | ||
| 51 | + </div> | ||
| 52 | + </div> | ||
| 53 | + | ||
| 54 | + <div class="text-wrapper"> | ||
| 55 | + <div class="text-header">上传附件</div> | ||
| 56 | + <div style="display: flex; margin: 1rem 0; gap: 1rem;"> | ||
| 57 | + <div style="text-align: center; border: 1px solid #a2d8a3; border-radius: 5px; padding: 1rem 0; flex: 1;"> | ||
| 58 | + <div><van-icon name="photo" size="2.5rem" /></div> | ||
| 59 | + <div style="font-size: 0.85rem;">图文上传</div> | ||
| 60 | + </div> | ||
| 61 | + <div style="text-align: center; border: 1px solid #a2d8a3; border-radius: 5px; padding: 1rem 0; flex: 1;"> | ||
| 62 | + <div><van-icon name="video" size="2.5rem" /></div> | ||
| 63 | + <div style="font-size: 0.85rem;">视频/语音</div> | ||
| 64 | + </div> | ||
| 65 | + </div> | ||
| 66 | + </div> | ||
| 67 | + | ||
| 68 | + <div class="text-wrapper"> | ||
| 69 | + <div class="text-header">团队动态</div> | ||
| 70 | + <div class="post-card" v-for="post in mockPosts" :key="post.id"> | ||
| 71 | + <div class="post-header"> | ||
| 72 | + <van-row> | ||
| 73 | + <van-col span="3"> | ||
| 74 | + <van-image round width="2.5rem" height="2.5rem" :src="post.user.avatar" /> | ||
| 75 | + </van-col> | ||
| 76 | + <van-col span="20"> | ||
| 77 | + <div class="user-info"> | ||
| 78 | + <div class="username">{{ post.user.name }}</div> | ||
| 79 | + <div class="post-time">{{ post.user.time }}</div> | ||
| 80 | + </div> | ||
| 81 | + </van-col> | ||
| 82 | + </van-row> | ||
| 83 | + </div> | ||
| 84 | + <div class="post-content"> | ||
| 85 | + <div class="post-text">{{ post.content }}</div> | ||
| 86 | + <div class="post-media"> | ||
| 87 | + <div v-if="post.images.length" class="post-images"> | ||
| 88 | + <van-image | ||
| 89 | + width="100" | ||
| 90 | + height="100" | ||
| 91 | + v-for="(image, index) in post.images" | ||
| 92 | + :key="index" | ||
| 93 | + :src="image" | ||
| 94 | + @click="openImagePreview(index, post)" | ||
| 95 | + /> | ||
| 96 | + </div> | ||
| 97 | + <van-image-preview | ||
| 98 | + v-if="currentPost" | ||
| 99 | + v-model:show="showImagePreview" | ||
| 100 | + :images="currentPost.images" | ||
| 101 | + :start-position="startPosition" | ||
| 102 | + :show-index="true" | ||
| 103 | + @change="onChange" | ||
| 104 | + /> | ||
| 105 | + <!-- 视频封面和播放按钮 --> | ||
| 106 | + <div v-if="post.video && !post.isPlaying" class="relative w-full rounded-lg overflow-hidden" style="aspect-ratio: 16/9;"> | ||
| 107 | + <img :src="post.videoCover || 'https://fastly.jsdelivr.net/npm/@vant/assets/cat.jpeg'" :alt="post.content" class="w-full h-full object-cover" /> | ||
| 108 | + <div class="absolute inset-0 flex items-center justify-center cursor-pointer bg-black/20" | ||
| 109 | + @click="startPlay(post)"> | ||
| 110 | + <div class="w-16 h-16 rounded-full bg-black/50 flex items-center justify-center hover:bg-black/70 transition-colors"> | ||
| 111 | + <van-icon name="play-circle-o" class="text-white" size="30" /> | ||
| 112 | + </div> | ||
| 113 | + </div> | ||
| 114 | + </div> | ||
| 115 | + <!-- 视频播放器 --> | ||
| 116 | + <VideoPlayer | ||
| 117 | + v-if="post.video && post.isPlaying" | ||
| 118 | + :video-url="post.video" | ||
| 119 | + class="post-video rounded-lg overflow-hidden" | ||
| 120 | + ref="(el) => { if(el) videoPlayers.value.push(el) }" | ||
| 121 | + @onPlay="(player) => handleVideoPlay(player, post)" | ||
| 122 | + @onPause="() => handleVideoPause(post)" | ||
| 123 | + /> | ||
| 124 | + <AudioPlayer v-if="post.audio.length" :songs="post.audio" class="post-audio" /> | ||
| 125 | + </div> | ||
| 126 | + </div> | ||
| 127 | + <div class="post-footer"> | ||
| 128 | + <van-icon name="like" class="like-icon" /> | ||
| 129 | + <span class="like-count">{{ post.likes }}</span> | ||
| 130 | + </div> | ||
| 131 | + </div> | ||
| 132 | + </div> | ||
| 133 | + | ||
| 134 | + <div style="height: 5rem;"></div> | ||
| 135 | + </van-config-provider> | ||
| 136 | + </AppLayout> | ||
| 137 | +</template> | ||
| 138 | + | ||
| 139 | +<script setup> | ||
| 140 | +import { ref } from 'vue' | ||
| 141 | +import { useRoute, useRouter } from 'vue-router' | ||
| 142 | +import AppLayout from "@/components/layout/AppLayout.vue"; | ||
| 143 | +import FrostedGlass from "@/components/ui/FrostedGlass.vue"; | ||
| 144 | +import VideoPlayer from "@/components/ui/VideoPlayer.vue"; | ||
| 145 | +import AudioPlayer from "@/components/ui/AudioPlayer.vue"; | ||
| 146 | + | ||
| 147 | +// 存储所有视频播放器的引用 | ||
| 148 | +const videoPlayers = ref([]); | ||
| 149 | + | ||
| 150 | +/** | ||
| 151 | + * 开始播放指定帖子的视频 | ||
| 152 | + * @param {Object} post - 要播放视频的帖子对象 | ||
| 153 | + */ | ||
| 154 | +const startPlay = (post) => { | ||
| 155 | + // 先暂停所有其他视频 | ||
| 156 | + mockPosts.value.forEach(p => { | ||
| 157 | + if (p.id !== post.id) { | ||
| 158 | + p.isPlaying = false; | ||
| 159 | + } | ||
| 160 | + }); | ||
| 161 | + | ||
| 162 | + // 设置当前视频为播放状态 | ||
| 163 | + post.isPlaying = true; | ||
| 164 | +}; | ||
| 165 | + | ||
| 166 | +/** | ||
| 167 | + * 处理视频播放事件 | ||
| 168 | + * @param {Object} player - 视频播放器实例 | ||
| 169 | + * @param {Object} post - 包含视频的帖子对象 | ||
| 170 | + */ | ||
| 171 | +const handleVideoPlay = (player, post) => { | ||
| 172 | + // 停止其他视频播放 | ||
| 173 | + stopOtherVideos(player, post); | ||
| 174 | +}; | ||
| 175 | + | ||
| 176 | +/** | ||
| 177 | + * 处理视频暂停事件 | ||
| 178 | + * @param {Object} post - 包含视频的帖子对象 | ||
| 179 | + */ | ||
| 180 | +const handleVideoPause = (post) => { | ||
| 181 | + // 视频暂停时不改变isPlaying状态,保持播放器可见 | ||
| 182 | + // 这样用户可以继续从暂停处播放 | ||
| 183 | +}; | ||
| 184 | + | ||
| 185 | +/** | ||
| 186 | + * 停止除当前播放器外的所有其他视频 | ||
| 187 | + * @param {Object} currentPlayer - 当前播放的视频播放器实例 | ||
| 188 | + * @param {Object} currentPost - 当前播放的帖子对象 | ||
| 189 | + */ | ||
| 190 | +const stopOtherVideos = (currentPlayer, currentPost) => { | ||
| 191 | + // 暂停其他视频播放器 | ||
| 192 | + videoPlayers.value.forEach(player => { | ||
| 193 | + if (player !== currentPlayer && player.pause) { | ||
| 194 | + player.pause(); | ||
| 195 | + } | ||
| 196 | + }); | ||
| 197 | + | ||
| 198 | + // 更新其他帖子的播放状态 | ||
| 199 | + mockPosts.value.forEach(post => { | ||
| 200 | + if (post.id !== currentPost.id) { | ||
| 201 | + post.isPlaying = false; | ||
| 202 | + } | ||
| 203 | + }); | ||
| 204 | +}; | ||
| 205 | + | ||
| 206 | +// Mock数据 | ||
| 207 | +const mockPosts = ref([ | ||
| 208 | + { | ||
| 209 | + id: 1, | ||
| 210 | + user: { | ||
| 211 | + name: '小林', | ||
| 212 | + avatar: 'https://fastly.jsdelivr.net/npm/@vant/assets/cat.jpeg', | ||
| 213 | + time: '2小时前' | ||
| 214 | + }, | ||
| 215 | + content: '今天完成了React基础课程的学习,收获满满!', | ||
| 216 | + images: [ | ||
| 217 | + 'https://cdn.ipadbiz.cn/space/816560/大国少年_FhnF8lsFMPnTDNTBlM6hYa-UFBlW.jpg', | ||
| 218 | + 'https://cdn.ipadbiz.cn/space/816560/大国少年_FhnF8lsFMPnTDNTBlM6hYa-UFBlW.jpg', | ||
| 219 | + 'https://cdn.ipadbiz.cn/space/816560/大国少年_FhnF8lsFMPnTDNTBlM6hYa-UFBlW.jpg', | ||
| 220 | + 'https://cdn.ipadbiz.cn/space/816560/大国少年_FhnF8lsFMPnTDNTBlM6hYa-UFBlW.jpg', | ||
| 221 | + ], | ||
| 222 | + video: '', | ||
| 223 | + videoCover: '', | ||
| 224 | + isPlaying: false, | ||
| 225 | + audio: [], | ||
| 226 | + likes: 12 | ||
| 227 | + }, | ||
| 228 | + { | ||
| 229 | + id: 2, | ||
| 230 | + user: { | ||
| 231 | + name: '小林', | ||
| 232 | + avatar: 'https://fastly.jsdelivr.net/npm/@vant/assets/cat.jpeg', | ||
| 233 | + time: '2小时前' | ||
| 234 | + }, | ||
| 235 | + content: '今天完成了React基础课程的学习,收获满满!', | ||
| 236 | + images: [], | ||
| 237 | + video: 'https://cdn.ipadbiz.cn/space/lk3DmvLO02dUC2zPiFwiClDe3nKL.mp4', | ||
| 238 | + videoCover: 'https://fastly.jsdelivr.net/npm/@vant/assets/cat.jpeg', | ||
| 239 | + isPlaying: false, | ||
| 240 | + audio: [], | ||
| 241 | + likes: 12 | ||
| 242 | + }, | ||
| 243 | + { | ||
| 244 | + id: 3, | ||
| 245 | + user: { | ||
| 246 | + name: '小林', | ||
| 247 | + avatar: 'https://fastly.jsdelivr.net/npm/@vant/assets/cat.jpeg', | ||
| 248 | + time: '2小时前' | ||
| 249 | + }, | ||
| 250 | + content: '今天完成了React基础课程的学习,收获满满!', | ||
| 251 | + images: [], | ||
| 252 | + video: '', | ||
| 253 | + videoCover: '', | ||
| 254 | + isPlaying: false, | ||
| 255 | + audio: [ | ||
| 256 | + { | ||
| 257 | + title: '学习心得分享', | ||
| 258 | + artist: '小林', | ||
| 259 | + url: 'https://example.com/audio.mp3', | ||
| 260 | + cover: 'https://fastly.jsdelivr.net/npm/@vant/assets/cat.jpeg' | ||
| 261 | + } | ||
| 262 | + ], | ||
| 263 | + likes: 12 | ||
| 264 | + }, | ||
| 265 | + { | ||
| 266 | + id: 4, | ||
| 267 | + user: { | ||
| 268 | + name: '小林', | ||
| 269 | + avatar: 'https://fastly.jsdelivr.net/npm/@vant/assets/cat.jpeg', | ||
| 270 | + time: '2小时前' | ||
| 271 | + }, | ||
| 272 | + content: '今天完成了React基础课程的学习,收获满满!', | ||
| 273 | + images: [], | ||
| 274 | + video: 'https://cdn.ipadbiz.cn/space/lk3DmvLO02dUC2zPiFwiClDe3nKL.mp4', | ||
| 275 | + videoCover: 'https://fastly.jsdelivr.net/npm/@vant/assets/cat.jpeg', | ||
| 276 | + isPlaying: false, | ||
| 277 | + audio: [], | ||
| 278 | + likes: 12 | ||
| 279 | + }, | ||
| 280 | +]); | ||
| 281 | + | ||
| 282 | +const themeVars = { | ||
| 283 | + calendarSelectedDayBackground: '#4caf50' | ||
| 284 | +} | ||
| 285 | + | ||
| 286 | +const progress1 = ref(50); | ||
| 287 | +const progress2 = ref(76); | ||
| 288 | + | ||
| 289 | +const teamAvatars = ref([ | ||
| 290 | + 'https://fastly.jsdelivr.net/npm/@vant/assets/cat.jpeg', | ||
| 291 | + 'https://fastly.jsdelivr.net/npm/@vant/assets/cat.jpeg', | ||
| 292 | + 'https://fastly.jsdelivr.net/npm/@vant/assets/cat.jpeg', | ||
| 293 | + 'https://fastly.jsdelivr.net/npm/@vant/assets/cat.jpeg' | ||
| 294 | +]) | ||
| 295 | + | ||
| 296 | +// 图片预览相关 | ||
| 297 | +const showImagePreview = ref(false); | ||
| 298 | +const startPosition = ref(0); | ||
| 299 | +const currentPost = ref(null); | ||
| 300 | + | ||
| 301 | +// 打开图片预览 | ||
| 302 | +const openImagePreview = (index, post) => { | ||
| 303 | + currentPost.value = post; | ||
| 304 | + startPosition.value = index; | ||
| 305 | + showImagePreview.value = true; | ||
| 306 | +} | ||
| 307 | + | ||
| 308 | +// 图片切换事件处理 | ||
| 309 | +const onChange = (index) => { | ||
| 310 | + startPosition.value = index; | ||
| 311 | +} | ||
| 312 | +const formatter = (day) => { | ||
| 313 | + const month = day.date.getMonth() + 1; | ||
| 314 | + const date = day.date.getDate(); | ||
| 315 | + | ||
| 316 | + let checkin_days = [1, 3, 5, 7]; | ||
| 317 | + | ||
| 318 | + if (month === 5) { | ||
| 319 | + if (checkin_days.includes(date)) { | ||
| 320 | + day.className = 'calendar-checkin'; | ||
| 321 | + day.type ='selected'; | ||
| 322 | + } | ||
| 323 | + } | ||
| 324 | + | ||
| 325 | + return day; | ||
| 326 | +} | ||
| 327 | + | ||
| 328 | +const onClickSubtitle = (evt) => { | ||
| 329 | + console.warn('点击了日期标题'); | ||
| 330 | +} | ||
| 331 | +</script> | ||
| 332 | + | ||
| 333 | +<style lang="less"> | ||
| 334 | + .calendar-checkin { | ||
| 335 | + .van-calendar__selected-day { | ||
| 336 | + background: #a2d8a3 !important; | ||
| 337 | + } | ||
| 338 | + } | ||
| 339 | + | ||
| 340 | + .text-wrapper { | ||
| 341 | + padding: 1rem; | ||
| 342 | + color: #4caf50; | ||
| 343 | + .text-header { | ||
| 344 | + font-size: 1.15rem; | ||
| 345 | + } | ||
| 346 | + | ||
| 347 | + .grade-percentage-main { | ||
| 348 | + padding: 0.75rem 1rem; | ||
| 349 | + } | ||
| 350 | + .class-percentage-main { | ||
| 351 | + padding: 0.75rem 1rem; | ||
| 352 | + } | ||
| 353 | + } | ||
| 354 | +</style> | ||
| 355 | + | ||
| 356 | +.post-card { | ||
| 357 | + margin: 1rem 0; | ||
| 358 | + padding: 1rem; | ||
| 359 | + background-color: #FFF; | ||
| 360 | + border-radius: 5px; | ||
| 361 | + | ||
| 362 | + .post-header { | ||
| 363 | + margin-bottom: 1rem; | ||
| 364 | + } | ||
| 365 | + | ||
| 366 | + .user-info { | ||
| 367 | + margin-left: 0.5rem; | ||
| 368 | + | ||
| 369 | + .username { | ||
| 370 | + font-weight: 500; | ||
| 371 | + } | ||
| 372 | + | ||
| 373 | + .post-time { | ||
| 374 | + color: gray; | ||
| 375 | + font-size: 0.8rem; | ||
| 376 | + } | ||
| 377 | + } | ||
| 378 | + | ||
| 379 | + .post-content { | ||
| 380 | + .post-text { | ||
| 381 | + margin-bottom: 1rem; | ||
| 382 | + } | ||
| 383 | + | ||
| 384 | + .post-media { | ||
| 385 | + .post-images { | ||
| 386 | + display: flex; | ||
| 387 | + flex-wrap: wrap; | ||
| 388 | + gap: 0.5rem; | ||
| 389 | + } | ||
| 390 | + | ||
| 391 | + .post-video { | ||
| 392 | + margin: 1rem 0; | ||
| 393 | + width: 100%; | ||
| 394 | + border-radius: 8px; | ||
| 395 | + overflow: hidden; | ||
| 396 | + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); | ||
| 397 | + } | ||
| 398 | + | ||
| 399 | + .post-audio { | ||
| 400 | + margin: 1rem 0; | ||
| 401 | + } | ||
| 402 | + } | ||
| 403 | + } | ||
| 404 | + | ||
| 405 | + .post-footer { | ||
| 406 | + margin-top: 1rem; | ||
| 407 | + color: #666; | ||
| 408 | + | ||
| 409 | + .like-icon { | ||
| 410 | + margin-right: 0.25rem; | ||
| 411 | + } | ||
| 412 | + | ||
| 413 | + .like-count { | ||
| 414 | + font-size: 0.9rem; | ||
| 415 | + } | ||
| 416 | + } | ||
| 417 | +} |
-
Please register or login to post a comment