From 8e003d317da31c555c5c746f62bd74c8dd46638b Mon Sep 17 00:00:00 2001
From: xiangpei <xiangpei@timesnew.cn>
Date: 星期二, 27 五月 2025 13:57:20 +0800
Subject: [PATCH] 视频播放记录完善
---
pages/tabbar/index/home.vue | 290 +++++++++++++++++++++++++++++++++++----------------------
1 files changed, 176 insertions(+), 114 deletions(-)
diff --git a/pages/tabbar/index/home.vue b/pages/tabbar/index/home.vue
index b8f2587..8d25e61 100644
--- a/pages/tabbar/index/home.vue
+++ b/pages/tabbar/index/home.vue
@@ -9,17 +9,28 @@
@change="onSwiperChange"
>
<swiper-item v-for="(item, index) in videoList" :key="item.id">
+ <!-- 鎾斁鎸夐挳锛堜粎褰撹棰戞殏鍋滄椂鏄剧ず锛� -->
+ <view
+ class="play-icon"
+ @click="togglePlay(index)"
+ v-if="currentVideoIsPlaying != null && !currentVideoIsPlaying"
+ >
+ <image src="/static/video/play.png" style="width: 45px;height: 45px" mode="aspectFit"></image>
+ </view>
<video
:id="'video'+index"
- :src="item.url"
+ :ref="'video'+index"
+ :src="item.videoUrl"
:autoplay="currentIndex === index"
:controls="false"
:loop="true"
:object-fit="item.objectFit"
class="video-item"
- @play="onPlay(index)"
+ @play="onPlay(item.id, index)"
@pause="onPause(index)"
@ended="onEnded(index)"
+ @click="togglePlay(index)"
+ @timeupdate="onTimeUpdate($event)"
></video>
<!-- 鎮寕鍟嗗搧閾炬帴灞� -->
@@ -27,7 +38,7 @@
<view class="goods-link">
<view class="goods-container">
<!-- 鍟嗗搧鍥剧墖 -->
- <image class="goods-image" :src="item.goods.image" mode="aspectFill"></image>
+ <image class="goods-image" :src="item.goods.imageUrl" mode="aspectFill"></image>
<!-- 鍟嗗搧淇℃伅 -->
<view class="goods-info">
@@ -36,7 +47,7 @@
<text class="current-price">楼{{item.goods.price}}</text>
<text class="original-price" v-if="item.goods.originalPrice">楼{{item.goods.originalPrice}}</text>
</view>
- <text class="sales-count">{{item.goods.sales}}浜哄凡璐�</text>
+ <text class="sales-count">{{item.goods.saleNum}}浜哄凡璐�</text>
</view>
<!-- 璐拱鎸夐挳 -->
@@ -51,11 +62,11 @@
<!-- 瑙嗛淇℃伅灞� -->
<view class="video-info">
<view>
- <text class="video-author">@{{item.author}}</text>
+ <text class="video-author">@{{item.authorName}}</text>
</view>
<view style="width: 100%;word-wrap: break-word;white-space: normal;overflow-wrap: break-word;">
<text class="video-title">{{item.title}}</text>
- <text class="video-tag" v-for="(tag, index) in item.tags" :key="tag">#{{tag}}</text>
+ <text class="video-tag" v-for="(tag, index) in item.tagList" :key="tag">#{{tag.tagName}}</text>
</view>
</view>
@@ -68,75 +79,63 @@
<text class="iconfont"></text>
</view>
</view>
- <view class="action-item" @click="toggleCollect(item)">
- <!-- <image :src="item.isCollected ? '/static/collected.png' : '/static/collect.png'"></image> -->
+ <view class="action-item" @click="toggleCollect(item, index)">
<text class="iconfont" v-if="item.collected"></text>
<text class="iconfont" v-else></text>
- <text style="font-size: 10px;font-weight: lighter;">{{item.collectCount}}</text>
+ <text style="font-size: 10px;font-weight: lighter;">{{item.collectNum}}</text>
</view>
<view class="action-item" @click="showComments(item)">
<text class="iconfont"></text>
- <text style="font-size: 10px;font-weight: lighter;">{{item.commentCount}}</text>
+ <text style="font-size: 10px;font-weight: lighter;">{{item.commentNum}}</text>
</view>
</view>
</swiper-item>
</swiper>
+ <custom-tabbar bgColor="#333333" selected="index" selectedTextColor="#ffffff"></custom-tabbar>
</view>
</template>
<script>
+import { getRecommendVideos, savePlayRecord } from "@/api/video.js";
+import { changeCollect } from "@/api/collect.js";
export default {
data() {
return {
- isFullScreen: false,
- windowHeight: 0,
- currentIndex: 0, // 褰撳墠鎾斁鐨勮棰戠储寮�
- videoList: [
- {
- url: 'http://vjs.zencdn.net/v/oceans.mp4',
- objectFit: 'contain',
- title: '鎴戜簡涓�',
- author: 'xp',
- authorAvatar: 'https://picsum.photos/200/200?random=2',
- collected: true,
- commentCount: 12,
- collectCount: 45,
- tags: ["浜斾竴", "鐖辩編椋�", "澹ぇ澶�熷害鍜岀矇绾㈣壊鐨勬仮澶嶉�熷害鐨勫彛琚嬬┖绌�"],
- goods: {
- name: '鎺ㄦ祦',
- price: '10',
- originalPrice: '48.9',
- sales: 1988,
- image: 'https://picsum.photos/200/200?random=2'
- }
- },
- {
- url: 'https://videos.pexels.com/video-files/30900524/13210612_1080_1920_30fps.mp4',
- objectFit: 'cover',
- title: '鎴戜簡涓�',
- author: 'xp',
- authorAvatar: 'https://picsum.photos/200/200?random=2',
- collected: false,
- commentCount: 6,
- collectCount: 45,
- tags: ["鎴戝枩娆�"],
- goods: {
- name: '鎺ㄦ祦',
- price: '10',
- originalPrice: '48.9',
- sales: 1988,
- image: 'https://picsum.photos/200/200?random=2'
- }
- },
- ], // 瑙嗛鍒楄〃鏁版嵁
- videoContexts: [], // 瑙嗛涓婁笅鏂囧璞¢泦鍚�
- loading: false, // 鏄惁姝e湪鍔犺浇
- page: 1, // 褰撳墠椤电爜
- pageSize: 10 // 姣忛〉鏁伴噺
+ startHidenTime: 0, // 璁板綍鍒囨崲鑷冲叾瀹冮〉闈㈢殑鏃堕棿锛岀敤浜庤绠楄棰戣鐪嬫椂闂村噺鍘荤殑閮ㄥ垎
+ totalHidenTime: 0, // 鎬诲叡闅愯棌椤甸潰鐨勬椂闂�
+ startPauseTime: 0, // 寮�濮嬫殏鍋滅殑鏃堕棿
+ totalPauseTime: 0, // 鎬诲叡鏆傚仠鐨勬椂闂�
+ playRecord: {
+ videoId: null,
+ viewDuration: 0, // 杩欎釜瑙嗛鎬诲叡瑙傜湅浜嗗涔�
+ playAt: 0 ,// 杩欎釜瑙嗛鎾斁鍒板摢浜�
+ startPlayTime: 0 // 杩欎釜瑙嗛浠庝粈涔堟椂鍊欏紑濮嬫挱鏀剧殑
+ },
+ currentVideoIsPlaying: null, // 褰撳墠瑙嗛鏄惁姝e湪鎾斁
+ isFullScreen: false,
+ windowHeight: 0,
+ currentIndex: 0, // 褰撳墠鎾斁鐨勮棰戠储寮�
+ videoList: [
+
+ ], // 瑙嗛鍒楄〃鏁版嵁
+ videoContexts: [], // 瑙嗛涓婁笅鏂囧璞¢泦鍚�
+ loading: false, // 鏄惁姝e湪鍔犺浇
+ page: 1, // 褰撳墠椤电爜
+ pageSize: 10 // 姣忛〉鏁伴噺
}
},
+ onShow() {
+ // 濡傛灉瑙嗛鎸変笅鏆傚仠鍚庡垏鎹㈤〉闈㈠啀鍥炲埌椤甸潰鏃讹紝鍙畻鏆傚仠鏃堕棿锛堝洜涓烘殏鍋滄椂闂村拰绂诲紑椤甸潰鏃堕棿鏄噸澶嶇殑锛屽彧绠椾竴涓級
+ if(this.startHidenTime !== 0 && this.currentVideoIsPlaying) {
+ const duration = Date.now() - this.startHidenTime
+ this.totalHidenTime += duration
+ }
+ },
+ onHide() {
+ this.startHidenTime = Date.now()
+ },
onLoad() {
- // this.loadVideos();
+ this.loadVideos();
},
onReady() {
// 鍒濆鍖栬棰戜笂涓嬫枃
@@ -147,7 +146,6 @@
initVideoContexts() {
this.videoContexts = this.videoList.map((_, index) => {
let videoContent = uni.createVideoContext(`video${index}`, this);
- // videoContent.requestFullScreen({ direction: 0 });
return videoContent;
});
},
@@ -157,82 +155,136 @@
if (this.loading) return;
this.loading = true;
- try {
- const res = await uni.request({
- url: 'https://your-api.com/videos',
- data: {
- page: this.page,
- pageSize: this.pageSize
- }
- });
-
- if (this.page === 1) {
- this.videoList = res.data.list;
- } else {
- this.videoList = [...this.videoList, ...res.data.list];
- }
-
- this.page++;
- this.$nextTick(() => {
- this.initVideoContexts();
- });
- } catch (e) {
- console.error('鍔犺浇瑙嗛澶辫触', e);
- } finally {
- this.loading = false;
- }
+ getRecommendVideos({pageNumber: this.page, pageSize: this.pageSize}).then(res => {
+ console.log(res, "瑙嗛鏁版嵁");
+ if (this.page === 1) {
+ this.videoList = res.data.data;
+ } else {
+ this.videoList = [...this.videoList, ...res.data.data];
+ }
+
+ this.page++;
+ this.$nextTick(() => {
+ this.initVideoContexts();
+ });
+ this.loading = false;
+ })
},
// 婊戝姩鍒囨崲瑙嗛
onSwiperChange(e) {
- const oldIndex = this.currentIndex;
- this.currentIndex = e.detail.current;
-
- // 鏆傚仠涓婁竴涓棰�
- if (this.videoContexts[oldIndex]) {
- this.videoContexts[oldIndex].pause();
- }
-
- // 鎾斁褰撳墠瑙嗛
- if (this.videoContexts[this.currentIndex]) {
- this.videoContexts[this.currentIndex].play();
- }
+ // 濡傛灉瑙嗛澶勪簬鏆傚仠鐘舵�佸線涓嬪埛瑙嗛锛岄偅涔堥渶瑕佸啀璁$畻涓�娆℃殏鍋滄椂闂�
+ if(!this.currentVideoIsPlaying) {
+ if(this.startPauseTime !== 0) {
+ const duration = Date.now() - this.startPauseTime
+ this.totalPauseTime += duration
+ }
+ }
+ // 淇濆瓨涓婁竴涓棰戠殑鎾斁璁板綍
+ this.savePlayRecord()
+ const oldIndex = this.currentIndex;
+ console.log("瑙嗛涓婁笅鏂�",this.videoContexts[oldIndex]);
+ this.currentIndex = e.detail.current;
+
+ // 鏆傚仠涓婁竴涓棰�
+ if (this.videoContexts[oldIndex]) {
+ this.videoContexts[oldIndex].pause();
+ }
+ this.currentVideoIsPlaying = true;
+ this.startPauseTime = 0;
+ // 鎾斁褰撳墠瑙嗛
+ if (this.videoContexts[this.currentIndex]) {
+ this.videoContexts[this.currentIndex].play();
+ }
},
- // 鐐硅禐/鍙栨秷鐐硅禐
- toggleLike(item) {
- item.isLiked = !item.isLiked;
- item.likeCount += item.isLiked ? 1 : -1;
-
- uni.request({
- url: `https://your-api.com/video/${item.id}/like`,
- method: item.isLiked ? 'POST' : 'DELETE'
- });
+ // 鏀惰棌/鍙栨秷鏀惰棌
+ toggleCollect(item, index) {
+ let data = {
+ refId: item.id,
+ collectType: 'video'
+ }
+ const beforeCollected = item.collected
+ const beforeCollectNum = item.collectNum
+ if(item.collected) {
+ this.videoList[index].collected = false
+ this.videoList[index].collectNum -= 1
+ } else {
+ this.videoList[index].collected = true
+ this.videoList[index].collectNum += 1
+ }
+ changeCollect(data).then(res => {
+ if(res.data.code !== 200) {
+ this.videoList[index].collected = beforeCollected
+ this.videoList[index].collectNum = beforeCollectNum
+ }
+ })
},
-
+ // 鍗曞嚮灞忓箷锛氭殏鍋滄垨缁х画鎾斁
+ togglePlay(index) {
+ if(this.currentVideoIsPlaying) {
+ this.videoContexts[index].pause();
+ } else {
+ this.videoContexts[index].play();
+ }
+ },
// 瑙嗛鎾斁浜嬩欢
- onPlay(index) {
- console.log(`瑙嗛 ${index} 寮�濮嬫挱鏀綻);
+ onPlay(id, index) {
+ this.currentVideoIsPlaying = true;
+ this.playRecord.videoId = id;
+ // 娌″垵濮嬪寲鎵嶈祴鍊硷紝鍥犱负涓�涓棰戦噸澶嶆挱鏀緊nPlay浼氶噸澶嶈Е鍙�
+ if(this.playRecord.startPlayTime === 0) {
+ this.playRecord.startPlayTime = Date.now();
+ }
+ if(this.startPauseTime !== 0) {
+ const duration = Date.now() - this.startPauseTime
+ this.totalPauseTime += duration
+ }
},
// 瑙嗛鏆傚仠浜嬩欢
onPause(index) {
- console.log(`瑙嗛 ${index} 鏆傚仠`);
+ this.currentVideoIsPlaying = false;
+ this.startPauseTime = Date.now()
},
// 瑙嗛缁撴潫浜嬩欢
onEnded(index) {
- console.log(`瑙嗛 ${index} 鎾斁缁撴潫`);
- // 鑷姩鎾斁涓嬩竴涓紙濡傛灉涓嶅湪鏈�鍚庝竴涓級
- if (index < this.videoList.length - 1) {
- this.currentIndex = index + 1;
- }
- }
+ // this.currentVideoIsPlaying = false;
+ },
+
+ // 璁板綍鎾斁鏃堕暱
+ onTimeUpdate(e) {
+ this.playRecord.playAt = e.detail.currentTime
+ },
+
+ // 淇濆瓨鎾斁璁板綍
+ async savePlayRecord() {
+ console.log(Date.now(), this.playRecord.startPlayTime, this.totalHidenTime);
+
+ const data = {
+ videoId: this.playRecord.videoId,
+ viewDuration: Date.now() - this.playRecord.startPlayTime - this.totalHidenTime - this.totalPauseTime,
+ playAt: this.playRecord.playAt
+ }
+ this.playRecord = {
+ videoId: null,
+ viewDuration: 0, // 杩欎釜瑙嗛鎬诲叡瑙傜湅浜嗗涔�
+ playAt: 0 ,// 杩欎釜瑙嗛鎾斁鍒板摢浜�
+ startPlayTime: 0 // 杩欎釜瑙嗛浠庝粈涔堟椂鍊欏紑濮嬫挱鏀剧殑
+ }
+ this.totalHidenTime = 0
+ this.totalPauseTime = 0
+ savePlayRecord(data)
+ }
}
}
</script>
<style scoped>
+ ::v-deep .custom-tabbar {
+ border-top: none !important;
+ }
.video-container {
width: 100%;
height: 100vh;
@@ -249,11 +301,21 @@
height: 100%;
object-fit: cover;
}
+ .play-icon {
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ transform: translate(-50%, -50%);
+ width: 45px;
+ height: 45px;
+ z-index: 10;
+ opacity: 0.6;
+ }
.video-info {
width: 70%;
position: absolute;
- bottom: 50px;
+ bottom: 70px;
left: 20px;
color: #f8f8f8;
z-index: 10;
@@ -320,7 +382,7 @@
/* 鍟嗗搧閾炬帴鎮寕灞傛牱寮� */
.goods-link-warp {
position: absolute;
- bottom: 100px;
+ bottom: 160px;
left: 20px;
color: #f8f8f8;
z-index: 10;
--
Gitblit v1.8.0