From c9928dd4f6d25e2339ea1400f59ec58674a927a7 Mon Sep 17 00:00:00 2001 From: zxl <763096477@qq.com> Date: 星期四, 19 六月 2025 20:07:42 +0800 Subject: [PATCH] Merge remote-tracking branch 'origin/dev' into dev --- pages/tabbar/index/home.vue | 401 +++++++++++++++++++++++++++++++++++++++++++++++++------- 1 files changed, 349 insertions(+), 52 deletions(-) diff --git a/pages/tabbar/index/home.vue b/pages/tabbar/index/home.vue index e65155f..ade53fe 100644 --- a/pages/tabbar/index/home.vue +++ b/pages/tabbar/index/home.vue @@ -9,52 +9,98 @@ @change="onSwiperChange" > <swiper-item v-for="(item, index) in videoList" :key="item.id"> - <!-- 鎾斁鎸夐挳锛堜粎褰撹棰戞殏鍋滄椂鏄剧ず锛� --> - <view - class="play-icon" - @click="togglePlay(index)" - v-if="!currentVideoIsPlaying" - > - <image src="/static/video/play.png" style="width: 45px;height: 45px" mode="aspectFit"></image> + <view style="width: 100%;height: 100%;" v-if="item.videoContentType === 'video'"> + <!-- 鎾斁鎸夐挳锛堜粎褰撹棰戞殏鍋滄椂鏄剧ず锛� --> + <view + class="play-icon" + @click="togglePlay(index)" + v-if="!currentVideoIsPlaying" + > + <image src="/static/video/play.png" style="width: 45px;height: 45px" mode="aspectFit"></image> + </view> + <video + :id="'video'+index" + :ref="'video'+index" + :src="item.videoUrl" + :autoplay="currentIndex === index" + :controls="false" + :loop="true" + :object-fit="item.objectFit" + :enable-progress-gesture="false" + class="video-item" + @play="onPlay(item.id, index)" + @pause="onPause(index)" + @ended="onEnded(index)" + @click="togglePlay(index)" + @timeupdate="onTimeUpdate($event)" + @loadedmetadata="onLoadedMetadata($event)" + + ></video> + <!-- 鑷畾涔夋帶鍒舵潯 --> + <view + @touchstart="handleTouchStart" + @touchmove="handleTouchMove" + @touchend="handleTouchEnd" + class="container"> + <!-- 杩涘害鏉� - 鏁翠釜鍖哄煙鍙嫋鍔� --> + <view class="process-warp" :style="{ opacity: showProcess ? 1 : 0 }"> + <!-- 鏄剧ず褰撳墠杩涘害 --> + <view class="progress-text">{{ hasPlayTime }}/{{formartDuration}}</view> + <view + class="progress-bar" + id="progressBar" + > + + <!-- 宸插~鍏呴儴鍒� --> + <view class="progress-fill" :style="{ width: progress + '%' }"></view> + </view> + </view> + </view> </view> - <video - :id="'video'+index" - :ref="'video'+index" - :src="item.videoUrl" - :autoplay="currentIndex === index" - :controls="false" - :loop="true" - :object-fit="item.objectFit" - class="video-item" - @play="onPlay(item.id, index)" - @pause="onPause(index)" - @ended="onEnded(index)" - @click="togglePlay(index)" - @timeupdate="onTimeUpdate($event)" - ></video> + <view style="width: 100%; height: 100%;" v-else-if="item.videoContentType === 'img'"> + <uni-swiper-dot + :info="item.imgs" + :current="currentImgIndex" + mode="round" + style="width: 100%;height: 100%;display: flex;justify-content: center;align-items: center;" + :dots-styles="{width: 24, bottom: 24,selectedBackgroundColor: 'green', backgroundColor: 'gray'}" + > + <swiper class="swiper-box" @change="imgChange" :autoplay="true" :interval="3000"> + <swiper-item v-for="img in item.imgs" :key="img"> + <view class="swiper-item"> + <!-- 璋冩暣 image 鏍峰紡锛屼娇鍏跺眳涓笖鎸夋瘮渚嬬缉鏀� --> + <image + :src="img" + mode="aspectFit" + style="width: 100%; height: 100%; display: block; margin: 0 auto;" + ></image> + </view> + </swiper-item> + </swiper> + </uni-swiper-dot> + </view> + <!-- 鎮寕鍟嗗搧閾炬帴灞� --> - <view class="goods-link-warp"> + <view class="goods-link-warp" v-if="item.goodsList.length > 0"> <view class="goods-link"> - <view class="goods-container"> - <!-- 鍟嗗搧鍥剧墖 --> - <image class="goods-image" :src="item.goods.imageUrl" mode="aspectFill"></image> - - <!-- 鍟嗗搧淇℃伅 --> - <view class="goods-info"> - <text class="goods-name">{{item.goods.name}}</text> - <view class="price-section"> - <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.saleNum}}浜哄凡璐�</text> - </view> - - <!-- 璐拱鎸夐挳 --> - <view class="buy-button"> - <text>璐拱</text> - </view> - </view> + <swiper @change="goodsChange" :autoplay="true" :interval="4000" style="height: 120rpx;"> + <swiper-item v-for="goods in item.goodsList" :key="goods.goodsId"> + <view class="goods-container" @click="jumpToPay(item.id)"> + <!-- 鍟嗗搧鍥剧墖 --> + <image class="goods-image" :src="goods.thumbnail" mode="aspectFill"></image> + + <!-- 鍟嗗搧淇℃伅 --> + <view class="goods-info"> + <text class="goods-name">{{goods.goodsName}}</text> + <view class="price-section"> + <text class="current-price">楼{{goods.price}}</text> + <text class="original-price" v-if="goods.originalPrice">楼{{goods.originalPrice}}</text> + </view> + </view> + </view> + </swiper-item> + </swiper> </view> </view> @@ -88,6 +134,12 @@ <text class="iconfont"></text> <text style="font-size: 10px;font-weight: lighter;">{{item.commentNum}}</text> </view> + <view class="action-item"> + <button open-type="share" class="custom-share-btn" :data-obj="item"> + <text class="iconfont"></text> + </button> + + </view> </view> </swiper-item> @@ -180,9 +232,31 @@ <script> import { getRecommendVideos, savePlayRecord, subscribe, getVideoComments, addVideoComment, thubmsUpComment, cancelThubmsUpComment } from "@/api/video.js"; import { changeCollect } from "@/api/collect.js"; +import { saveShare, saveShareClickRecord } from "@/api/share.js"; +import { silentLogin } from "@/api/connect.js"; +import { getUserInfo } from "@/api/members"; +import storage from "@/utils/storage.js"; export default { + computed: { + hasPlayTime() { + return this.sliderFormatTime(this.progress > 0 ? this.duration * this.progress / 100 : 0); + } + }, data() { return { + currentImgIndex: 0, // 鎾斁鍒扮鍑犲紶鍥�--绱㈠紩 + currentGoodsIndex: 0, // 鎾斁鍒扮鍑犱釜鍟嗗搧--绱㈠紩 + currentTime: 0, + formartDuration: '', + duration: 0, + startX: 0, + progress: 0, // 瑙嗛杩涘害 + startProgress : 0, // 寮�濮嬫粦鍔ㄦ椂鐨勮繘搴� + barLeft: 0, // 杩涘害鏉″乏杈圭晫浣嶇疆 + barWidth: 0, // 杩涘害鏉″搴� + isDragging: false, // 鏄惁姝e湪鎷栧姩 + processHidenTimer: null, // 杩涘害鏉¢殣钘忓畾鏃跺櫒 + showProcess: false, // 鏄惁鏄剧ず杩涘害鏉� videoNoMore: false, // 鏄惁杩樻湁鏇村瑙嗛 commentNoMore: false, // 鏄惁杩樻湁鏇村璇勮 commentQuery: { @@ -237,7 +311,14 @@ } }, onShow() { - this.loadVideos() + // const token = storage.getAccessToken(); + // if (! token) { + // this.wxSilentLogin(() => { + // this.loadVideos(); + // }) + // } else { + // this.loadVideos(); + // } // 濡傛灉瑙嗛鎸変笅鏆傚仠鍚庡垏鎹㈤〉闈㈠啀鍥炲埌椤甸潰鏃讹紝鍙畻鏆傚仠鏃堕棿锛堝洜涓烘殏鍋滄椂闂村拰绂诲紑椤甸潰鏃堕棿鏄噸澶嶇殑锛屽彧绠椾竴涓級 if(this.startHidenTime !== 0 && this.currentVideoIsPlaying) { const duration = Date.now() - this.startHidenTime @@ -247,14 +328,95 @@ onHide() { this.startHidenTime = Date.now() }, - onLoad() { - this.loadVideos(); + onLoad(option) { + const token = storage.getAccessToken(); + if (! token) { + this.wxSilentLogin(() => { + this.loadVideos(); + // 鍒ゆ柇鏄笉鏄偣鍑诲垎浜摼鎺ヨ繘鏉ョ殑 + if (option.userId && option.videoId) { + // 淇濆瓨鍒嗕韩鐐瑰嚮璁板綍 + saveShareClickRecord({refId: option.videoId, shareUserId: option.userId}) + } + }) + } else { + this.loadVideos(); + } }, onReady() { // 鍒濆鍖栬棰戜笂涓嬫枃 this.initVideoContexts(); }, + onShareAppMessage(e) { + const userInfo = storage.getUserInfo(); + if(!userInfo) { + console.log("鏈櫥褰曚笉鑳藉垎浜�"); + return + } + const videoInfo = e.target.dataset.obj; + // 淇濆瓨鍒嗕韩璁板綍 + const data = { + shareType: 'video', + refId: videoInfo.id, + shareUser: userInfo.id + } + saveShare(data) + return { + title: videoInfo.title, + path: `/pages/tabbar/index/home?videoId=${videoInfo.id}&userId=${userInfo.id}`, + imageUrl: videoInfo.coverUrl + } + }, methods: { + // 闈欓粯鐧诲綍 + wxSilentLogin(callback) { + //鑾峰彇code + uni.login({ + success: (codeRes) => { + if(codeRes.errMsg === "login:ok") { + // 闈欓粯鐧诲綍 + silentLogin({code: codeRes.code}).then(res => { + storage.setAccessToken(res.data.data.accessToken); + storage.setRefreshToken(res.data.data.refreshToken); + //鑾峰彇鐢ㄦ埛淇℃伅 + getUserInfo().then((user) => { + storage.setUserInfo(user.data.result); + storage.setHasLogin(true); + callback() + }); + }) + } else { + uni.showToast({ + title: "绯荤粺寮傚父锛岃鑱旂郴绠$悊鍛橈紒" + }) + } + }, + }); + }, + // 鐐瑰嚮鍟嗗搧璺宠浆 + jumpToPay(videoId) { + uni.navigateTo({ + url: '/pages/video/video-goods-detail?videoId=' + videoId + }); + }, + // 杞挱鍥惧彉鍖� + imgChange(e) { + this.currentImgIndex = e.detail.current; + }, + // 鍟嗗搧杞挱鍥惧彉鍖� + goodsChange(e) { + this.currentGoodsIndex = e.detail.current; + }, + // 鑾峰彇杩涘害鏉$殑浣嶇疆鍜屽昂瀵� + getBarRect() { + const query = uni.createSelectorQuery().in(this); + query.select('#progressBar').boundingClientRect(rect => { + if (rect) { + this.barLeft = rect.left; + this.barWidth = rect.width; + } + }).exec(); + }, // 璺宠浆涓汉涓婚〉 jumpToHomePage(authorId) { uni.navigateTo({ @@ -323,7 +485,7 @@ const videoId = this.commentForm.videoId; this.commentForm = { // 璇勮琛ㄥ崟鏁版嵁 id: '', - videoId: '', + videoId: videoId, commentContent: '', replyId: '', replyUserId: '', @@ -351,6 +513,12 @@ const input = this.$refs.commentInput; if (input) input.focus(); }); + }, + // 杩涘害鏉℃椂闂存牸寮忓寲 (00:00) + sliderFormatTime(seconds) { + const mins = Math.floor(seconds / 60); + const secs = Math.floor(seconds % 60); + return `${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`; }, // 鏍煎紡鍖栨椂闂� formatTime(time) { @@ -549,6 +717,9 @@ if (this.videoContexts[this.currentIndex]) { this.videoContexts[this.currentIndex].play(); } + // 璁剧疆褰撳墠鎾斁瑙嗛鐨勬�绘椂闀� + this.duration = this.videoList[this.currentIndex].videoDuration; + this.formartDuration = this.sliderFormatTime(this.duration); }, // 鏀惰棌/鍙栨秷鏀惰棌 @@ -584,9 +755,16 @@ }, // 瑙嗛鎾斁浜嬩欢 onPlay(id, index) { + this.getBarRect() + this.progress = 0 console.log(id, index, "瑙﹀彂鎾斁"); if(index === this.currentIndex) { this.currentVideoIsPlaying = true; + if(! this.duration) { + // 璁剧疆褰撳墠鎾斁瑙嗛鐨勬�绘椂闀� + this.duration = this.videoList[this.currentIndex].videoDuration; + this.formartDuration = this.sliderFormatTime(this.duration); + } } else { this.currentVideoIsPlaying = false; return @@ -600,6 +778,7 @@ const duration = Date.now() - this.startPauseTime this.totalPauseTime += duration } + }, // 瑙嗛鏆傚仠浜嬩欢 @@ -613,7 +792,6 @@ } this.startPauseTime = Date.now() }, - // 瑙嗛缁撴潫浜嬩欢 onEnded(index) { // this.currentVideoIsPlaying = false; @@ -621,9 +799,66 @@ // 璁板綍鎾斁鏃堕暱 onTimeUpdate(e) { - this.playRecord.playAt = e.detail.currentTime + this.playRecord.playAt = e.detail.currentTime; + + this.currentTime = e.detail.currentTime; + this.progress = (e.detail.currentTime / this.duration) * 100 + }, + // 瑙︽懜寮�濮� + handleTouchStart(e) { + this.isDragging = true; + this.showProcess = true; + this.startProgress = this.progress; // 璁板綍寮�濮嬫椂鐨勮繘搴� + this.startX = e.touches[0].pageX; + console.log("璁板綍寮�濮嬫椂鐨勮繘搴�", this.startProgress); + this.videoContexts[this.currentIndex].pause() + // this.updateProgress(e); }, + // 瑙︽懜绉诲姩 + handleTouchMove(e) { + if (!this.isDragging || !this.barWidth) return; + clearTimeout(this.processHidenTimer) + this.videoContexts[this.currentIndex].pause() + this.updateProgress(e); + }, + + // 瑙︽懜缁撴潫 + handleTouchEnd() { + this.isDragging = false; + console.log("婊戝姩缁撴潫", this.duration * this.progress); + this.videoContexts[this.currentIndex].seek(this.duration * this.progress / 100) + this.videoContexts[this.currentIndex].play() + this.processHidenTimer = setTimeout(() => { + this.showProcess = false; + }, 1000); + }, + + // 鏇存柊杩涘害 + updateProgress(e) { + // 鑾峰彇褰撳墠瑙︽懜鐐筙鍧愭爣 + const currentX = e.touches[0].pageX; + + // 璁$畻婊戝姩璺濈(鍍忕礌) + const deltaX = currentX - this.startX; + + // 灏嗗儚绱犺窛绂昏浆鎹负杩涘害澧為噺 + const deltaProgress = (deltaX / this.barWidth) * 100; + console.log("杩涘害澧為噺", deltaProgress); + // 璁$畻鏂拌繘搴� = 寮�濮嬫椂鐨勮繘搴� + 婊戝姩澧為噺 + let newProgress = this.startProgress + deltaProgress; + + // 闄愬埗鑼冨洿鍦�0-100涔嬮棿 + newProgress = Math.max(0, Math.min(100, newProgress)); + + this.progress = newProgress; + }, + // 鑾峰彇瑙嗛鎬绘椂闀� + onLoadedMetadata(e) { + // this.duration = e.detail.duration; + // this.formartDuration = this.sliderFormatTime(this.duration); + // console.log("瑙嗛鎬绘椂闀�", this.duration); + }, // 淇濆瓨鎾斁璁板綍 async savePlayRecord() { console.log(Date.now(), this.playRecord.startPlayTime, this.totalHidenTime); @@ -659,7 +894,7 @@ .video-swiper { width: 100%; - height: 100%; + height: calc(100% - 50px); } .video-item { @@ -681,7 +916,7 @@ .video-info { width: 70%; position: absolute; - bottom: 70px; + bottom: 20px; left: 20px; color: #f8f8f8; z-index: 10; @@ -755,6 +990,7 @@ } .goods-link { position: relative; + width: 450rpx; margin: 20rpx 0; padding: 12rpx; background-color: rgba(255, 255, 255, 0.9); @@ -763,6 +999,7 @@ } .goods-container { + width: 100%; display: flex; align-items: center; } @@ -785,11 +1022,13 @@ font-size: 28rpx; color: #333; font-weight: bold; - display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; - overflow: hidden; margin-bottom: 8rpx; + width: 280rpx; /* 闇�瑕佹寚瀹氬搴� */ + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; } .price-section { @@ -1015,4 +1254,62 @@ .thumbs-num { margin-left: 4rpx; } + .container { + display: flex; + flex-direction: column; + align-items: center; + position: absolute; + bottom: 0; + width: 100%; + } + + .progress-bar { + position: relative; + width: 100%; + height: 16px; + background-color: #eee; + overflow: hidden; + } + + .progress-fill { + position: absolute; + left: 0; + top: 0; + height: 100%; + background-color: lightgray; + transition: width 0.1s; + } + .process-warp { + width: 100%; + display: flex; + flex-direction: column; + align-items: center; + } + .progress-text { + margin-top: 10px; + font-size: 14px; + color: #666; + } + .swiper-box { + width: 100%; + height: 1400rpx; + } + .swiper-item { + display: flex; + justify-content: center; + align-items: center; + width: 100%; + height: 100%; + } + .custom-share-btn { + font-size: unset; + background: none; + padding: 0; + margin: 0; + line-height: normal; + border: none; + } + .custom-share-btn::after { + border: none; + } </style> \ No newline at end of file -- Gitblit v1.8.0