hookehuyr

feat(打卡页面): 支持多视频播放并优化媒体显示

- 将"团队动态"标题改为"打卡动态"以更符合场景
- 重构视频播放逻辑,支持每个帖子包含多个视频
- 优化图片显示宽度为30%并保持比例
- 完善视频播放控制,确保同时只播放一个视频
- 更新mock数据以支持多视频测试
1 <!-- 1 <!--
2 * @Date: 2025-05-29 15:34:17 2 * @Date: 2025-05-29 15:34:17
3 * @LastEditors: hookehuyr hookehuyr@gmail.com 3 * @LastEditors: hookehuyr hookehuyr@gmail.com
4 - * @LastEditTime: 2025-05-30 18:31:25 4 + * @LastEditTime: 2025-05-30 20:27:29
5 * @FilePath: /mlaj/src/views/checkin/IndexCheckInPage.vue 5 * @FilePath: /mlaj/src/views/checkin/IndexCheckInPage.vue
6 * @Description: 文件描述 6 * @Description: 文件描述
7 --> 7 -->
...@@ -59,7 +59,7 @@ ...@@ -59,7 +59,7 @@
59 </div> 59 </div>
60 60
61 <div class="text-wrapper"> 61 <div class="text-wrapper">
62 - <div class="text-header">团队动态</div> 62 + <div class="text-header">打卡动态</div>
63 <div class="post-card" v-for="post in mockPosts" :key="post.id"> 63 <div class="post-card" v-for="post in mockPosts" :key="post.id">
64 <div class="post-header"> 64 <div class="post-header">
65 <van-row> 65 <van-row>
...@@ -78,26 +78,39 @@ ...@@ -78,26 +78,39 @@
78 <div class="post-text">{{ post.content }}</div> 78 <div class="post-text">{{ post.content }}</div>
79 <div class="post-media"> 79 <div class="post-media">
80 <div v-if="post.images.length" class="post-images"> 80 <div v-if="post.images.length" class="post-images">
81 - <van-image width="100" height="100" v-for="(image, index) in post.images" :key="index" :src="image" 81 + <van-image width="30%" fit="cover" v-for="(image, index) in post.images" :key="index" :src="image"
82 @click="openImagePreview(index, post)" /> 82 @click="openImagePreview(index, post)" />
83 </div> 83 </div>
84 <van-image-preview v-if="currentPost" v-model:show="showImagePreview" :images="currentPost.images" 84 <van-image-preview v-if="currentPost" v-model:show="showImagePreview" :images="currentPost.images"
85 :start-position="startPosition" :show-index="true" @change="onChange" /> 85 :start-position="startPosition" :show-index="true" @change="onChange" />
86 +
87 + <div v-for="(v, idx) in post.videoList" :key="idx">
86 <!-- 视频封面和播放按钮 --> 88 <!-- 视频封面和播放按钮 -->
87 - <div v-if="post.video && !post.isPlaying" class="relative w-full rounded-lg overflow-hidden" 89 + <div v-if="v.video && !v.isPlaying" class="relative w-full rounded-lg overflow-hidden" style="aspect-ratio: 16/9; margin-bottom: 1rem;">
88 - style="aspect-ratio: 16/9;"> 90 + <img :src="v.videoCover || 'https://cdn.ipadbiz.cn/space/816560/大国少年_FhnF8lsFMPnTDNTBlM6hYa-UFBlW.jpg'"
89 - <img :src="post.videoCover || 'https://cdn.ipadbiz.cn/space/816560/大国少年_FhnF8lsFMPnTDNTBlM6hYa-UFBlW.jpg'" 91 + :alt="v.content" class="w-full h-full object-cover" />
90 - :alt="post.content" class="w-full h-full object-cover" /> 92 + <div class="absolute inset-0 flex items-center justify-center cursor-pointer bg-black/20"
91 - <div class="absolute inset-0 flex items-center justify-center cursor-pointer bg-black/20" 93 + @click="startPlay(v)">
92 - @click="startPlay(post)"> 94 + <div
93 - <div 95 + class="w-16 h-16 rounded-full bg-black/50 flex items-center justify-center hover:bg-black/70 transition-colors">
94 - class="w-16 h-16 rounded-full bg-black/50 flex items-center justify-center hover:bg-black/70 transition-colors"> 96 + <van-icon name="play-circle-o" class="text-white" size="30" />
95 - <van-icon name="play-circle-o" class="text-white" size="30" /> 97 + </div>
96 </div> 98 </div>
97 </div> 99 </div>
100 + <!-- 视频播放器 -->
101 + <VideoPlayer v-if="v.video && v.isPlaying" :video-url="v.video" class="post-video rounded-lg overflow-hidden"
102 + :ref="el => {
103 + if(el) {
104 + // 确保不重复添加
105 + if (!videoPlayers?.includes(el)) {
106 + videoPlayers?.push(el);
107 + }
108 + }
109 + }"
110 + @onPlay="handleVideoPlay(player, post)"
111 + @onPause="handleVideoPause(post)" />
98 </div> 112 </div>
99 - <!-- 视频播放器 --> 113 + <!-- <VideoPlayer v-if="post.video && post.isPlaying" :video-url="post.video"
100 - <VideoPlayer v-if="post.video && post.isPlaying" :video-url="post.video"
101 class="post-video rounded-lg overflow-hidden" 114 class="post-video rounded-lg overflow-hidden"
102 :ref="el => { 115 :ref="el => {
103 if(el) { 116 if(el) {
...@@ -108,7 +121,7 @@ ...@@ -108,7 +121,7 @@
108 } 121 }
109 }" 122 }"
110 @onPlay="handleVideoPlay(player, post)" 123 @onPlay="handleVideoPlay(player, post)"
111 - @onPause="handleVideoPause(post)" /> 124 + @onPause="handleVideoPause(post)" /> -->
112 <AudioPlayer 125 <AudioPlayer
113 v-if="post.audio.length" 126 v-if="post.audio.length"
114 :songs="post.audio" 127 :songs="post.audio"
...@@ -181,9 +194,11 @@ const startPlay = (post) => { ...@@ -181,9 +194,11 @@ const startPlay = (post) => {
181 if (mockPosts.value) { 194 if (mockPosts.value) {
182 // 先暂停所有其他视频 195 // 先暂停所有其他视频
183 mockPosts.value.forEach(p => { 196 mockPosts.value.forEach(p => {
184 - if (p.id !== post.id) { 197 + p.videoList.forEach(v => {
185 - p.isPlaying = false; 198 + if (v.id !== post.id) {
186 - } 199 + v.isPlaying = false;
200 + }
201 + });
187 }); 202 });
188 } 203 }
189 204
...@@ -226,10 +241,12 @@ const stopOtherVideos = (currentPlayer, currentPost) => { ...@@ -226,10 +241,12 @@ const stopOtherVideos = (currentPlayer, currentPost) => {
226 } 241 }
227 242
228 // 更新其他帖子的播放状态 243 // 更新其他帖子的播放状态
229 - mockPosts.value.forEach(post => { 244 + mockPosts.value.forEach(p => {
230 - if (post.id !== currentPost.id) { 245 + p.videoList.forEach(v => {
231 - post.isPlaying = false; 246 + if (v.id !== currentPost.id) {
232 - } 247 + v.isPlaying = false;
248 + }
249 + });
233 }); 250 });
234 }; 251 };
235 252
...@@ -259,6 +276,8 @@ const stopOtherAudio = (currentPlayer, currentPost) => { ...@@ -259,6 +276,8 @@ const stopOtherAudio = (currentPlayer, currentPost) => {
259 post.isPlaying = false; 276 post.isPlaying = false;
260 } 277 }
261 }); 278 });
279 + // 停止所有视频播放
280 + stopAllVideos();
262 } 281 }
263 282
264 const stopAllAudio = () => { 283 const stopAllAudio = () => {
...@@ -293,8 +312,10 @@ const stopAllVideos = () => { ...@@ -293,8 +312,10 @@ const stopAllVideos = () => {
293 }); 312 });
294 313
295 // 更新所有帖子的播放状态 314 // 更新所有帖子的播放状态
296 - mockPosts.value.forEach(post => { 315 + mockPosts.value.forEach(p => {
297 - post.isPlaying = false; 316 + p.videoList.forEach(v => {
317 + v.isPlaying = false;
318 + });
298 }); 319 });
299 }; 320 };
300 321
...@@ -310,11 +331,12 @@ const mockPosts = ref([ ...@@ -310,11 +331,12 @@ const mockPosts = ref([
310 content: '今天完成了React基础课程的学习,收获满满!', 331 content: '今天完成了React基础课程的学习,收获满满!',
311 images: [ 332 images: [
312 'https://cdn.ipadbiz.cn/space/816560/大国少年_FhnF8lsFMPnTDNTBlM6hYa-UFBlW.jpg', 333 'https://cdn.ipadbiz.cn/space/816560/大国少年_FhnF8lsFMPnTDNTBlM6hYa-UFBlW.jpg',
313 - 'https://cdn.ipadbiz.cn/space/816560/大国少年_FhnF8lsFMPnTDNTBlM6hYa-UFBlW.jpg', 334 + 'https://cdn.ipadbiz.cn/mlaj/images/_6HzPU9Hyfg (2).jpg',
314 'https://cdn.ipadbiz.cn/space/816560/大国少年_FhnF8lsFMPnTDNTBlM6hYa-UFBlW.jpg', 335 'https://cdn.ipadbiz.cn/space/816560/大国少年_FhnF8lsFMPnTDNTBlM6hYa-UFBlW.jpg',
315 'https://cdn.ipadbiz.cn/space/816560/大国少年_FhnF8lsFMPnTDNTBlM6hYa-UFBlW.jpg', 336 'https://cdn.ipadbiz.cn/space/816560/大国少年_FhnF8lsFMPnTDNTBlM6hYa-UFBlW.jpg',
316 ], 337 ],
317 video: '', 338 video: '',
339 + videoList: [],
318 videoCover: '', 340 videoCover: '',
319 isPlaying: false, 341 isPlaying: false,
320 audio: [], 342 audio: [],
...@@ -330,7 +352,18 @@ const mockPosts = ref([ ...@@ -330,7 +352,18 @@ const mockPosts = ref([
330 content: '今天完成了React基础课程的学习,收获满满!', 352 content: '今天完成了React基础课程的学习,收获满满!',
331 images: [], 353 images: [],
332 video: 'https://cdn.ipadbiz.cn/space/lk3DmvLO02dUC2zPiFwiClDe3nKL.mp4', 354 video: 'https://cdn.ipadbiz.cn/space/lk3DmvLO02dUC2zPiFwiClDe3nKL.mp4',
333 - videoCover: 'https://cdn.ipadbiz.cn/space/816560/大国少年_FhnF8lsFMPnTDNTBlM6hYa-UFBlW.jpg', 355 + videoList: [{
356 + id: 1,
357 + video: 'https://cdn.ipadbiz.cn/space/lk3DmvLO02dUC2zPiFwiClDe3nKL.mp4',
358 + videoCover: '',
359 + isPlaying: false,
360 + }, {
361 + id: 2,
362 + video: 'https://cdn.ipadbiz.cn/space/lk3DmvLO02dUC2zPiFwiClDe3nKL.mp4',
363 + videoCover: '',
364 + isPlaying: false,
365 + }],
366 + videoCover: '',
334 isPlaying: false, 367 isPlaying: false,
335 audio: [], 368 audio: [],
336 likes: 12 369 likes: 12
...@@ -345,6 +378,7 @@ const mockPosts = ref([ ...@@ -345,6 +378,7 @@ const mockPosts = ref([
345 content: '今天完成了React基础课程的学习,收获满满!', 378 content: '今天完成了React基础课程的学习,收获满满!',
346 images: [], 379 images: [],
347 video: '', 380 video: '',
381 + videoList: [],
348 videoCover: '', 382 videoCover: '',
349 isPlaying: false, 383 isPlaying: false,
350 audio: [ 384 audio: [
...@@ -373,7 +407,18 @@ const mockPosts = ref([ ...@@ -373,7 +407,18 @@ const mockPosts = ref([
373 content: '今天完成了React基础课程的学习,收获满满!', 407 content: '今天完成了React基础课程的学习,收获满满!',
374 images: [], 408 images: [],
375 video: 'https://cdn.ipadbiz.cn/space/lk3DmvLO02dUC2zPiFwiClDe3nKL.mp4', 409 video: 'https://cdn.ipadbiz.cn/space/lk3DmvLO02dUC2zPiFwiClDe3nKL.mp4',
376 - videoCover: 'https://cdn.ipadbiz.cn/space/816560/大国少年_FhnF8lsFMPnTDNTBlM6hYa-UFBlW.jpg', 410 + videoList: [{
411 + id: 3,
412 + video: 'https://cdn.ipadbiz.cn/space/lk3DmvLO02dUC2zPiFwiClDe3nKL.mp4',
413 + videoCover: '',
414 + isPlaying: false,
415 + }, {
416 + id: 4,
417 + video: 'https://cdn.ipadbiz.cn/space/lk3DmvLO02dUC2zPiFwiClDe3nKL.mp4',
418 + videoCover: '',
419 + isPlaying: false,
420 + }],
421 + videoCover: '',
377 isPlaying: false, 422 isPlaying: false,
378 audio: [], 423 audio: [],
379 likes: 12 424 likes: 12
...@@ -388,6 +433,7 @@ const mockPosts = ref([ ...@@ -388,6 +433,7 @@ const mockPosts = ref([
388 content: '今天完成了React基础课程的学习,收获满满!', 433 content: '今天完成了React基础课程的学习,收获满满!',
389 images: [], 434 images: [],
390 video: '', 435 video: '',
436 + videoList: [],
391 videoCover: '', 437 videoCover: '',
392 isPlaying: false, 438 isPlaying: false,
393 audio: [ 439 audio: [
......