11.21提交

This commit is contained in:
zoujiandong
2025-11-21 17:49:39 +08:00
parent 6b37f0899d
commit 91726b87c5
18 changed files with 2483 additions and 119 deletions
+306 -119
View File
@@ -10,7 +10,7 @@
backgroundColor="#eeeeee"
>
<template #right>
<view class="nav-actions">
<view class="nav-actions" v-if="from != 'download'">
<view class="collect-img" @click="shareToggle">
<image class="share-img-icon" :src="shareIcon" mode="aspectFill" />
</view>
@@ -26,35 +26,42 @@
</uni-nav-bar>
</view>
<video
<!-- <video
v-if="showVideo"
class="player-wrapper"
:style="{width: videoWidth + 'px'}"
:src="videoSrc"
controls
object-fit="contain"
:autoplay="false"
></video>
<!-- 标签切换 -->
<cover-view class="tabs">
<cover-view
class="tab"
:class="{ active: activeTab === 'info' }"
@click="switchTab('info')"
>
视频简介
<view-cover class="tab-line" v-if="activeTab === 'info'"></view-cover>
</cover-view>
<cover-view
class="tab"
:class="{ active: activeTab === 'comment' }"
@click="switchTab('comment')"
>
评论
<view-cover class="tab-line" v-if="activeTab === 'comment'"></view-cover>
</cover-view
>
</cover-view>
<view class="video-detail-page">
></video> -->
<sunny-video
v-if="showVideo"
class="player-wrapper"
:src="videoSrc"
:videoHeight="220"
:seekTime="0"
/>
<!-- 标签切换 -->
<cover-view class="tabs" v-if="from != 'download'">
<cover-view
class="tab"
:class="{ active: activeTab === 'info' }"
@click="switchTab('info')"
>
视频简介
<view-cover class="tab-line" v-if="activeTab === 'info'"></view-cover>
</cover-view>
<cover-view
class="tab"
:class="{ active: activeTab === 'comment' }"
@click="switchTab('comment')"
>
评论
<view-cover class="tab-line" v-if="activeTab === 'comment'"></view-cover>
</cover-view>
</cover-view>
<view class="video-detail-page" v-if="from != 'download'">
<!-- <scroll-view
class="content-scroll"
scroll-y
@@ -115,11 +122,20 @@
</view>
<!-- 底部区域:信息页为下载条,评论页为上传图片+输入+发送 -->
<view v-if="activeTab === 'info'" class="bottom-download" @click="onDownload">
<text class="download-text" v-if="!hasDownload">点击下载<text v-if="!isVideoDownloadRecord">(限时<text class="discount">5</text>折,仅需{{videoInfo.point}}积分)</text></text>
<text class="download-text" v-else>查看缓存</text>
</view>
<view v-if="activeTab !== 'info'" class="bottom-comment">
<view v-if="activeTab === 'info' && from != 'download'" class="bottom-download" @click="onDownload">
<text class="download-text" v-if="!hasDownload"
>点击下载<text v-if="!isVideoDownloadRecord && welfareNum <= 0"
>(限时<text class="discount">5</text>折,仅需{{
videoInfo.point
}}积分)</text
>
<text v-if="!isVideoDownloadRecord && welfareNum > 0">(剩余免费下载{{ welfareNum }}次数)</text>
</text
>
<text class="download-text" v-else-if="downLoadStatus === 'loading'">视频缓存中</text>
<text class="download-text" v-else-if="downLoadStatus === 'completed'">查看缓存</text>
</view>
<view v-if="activeTab !== 'info' && from != 'download'" class="bottom-comment">
<input
class="comment-input"
v-model="commentText"
@@ -148,7 +164,7 @@
@confirm="notEnoughConfirm"
></unidialog>
<!-- 分享弹窗 -->
<uni-popup ref="shareRef" type="bottom" safeArea backgroundColor="#fff" >
<uni-popup ref="shareRef" type="bottom" safeArea backgroundColor="#fff">
<view class="share-popup">
<view class="share-title">分享到</view>
<view class="share-content">
@@ -179,7 +195,7 @@
</template>
<script setup>
import { ref,nextTick } from "vue";
import { ref, nextTick } from "vue";
import uniVideo from "@/components/uniVideo/uniVideo.vue";
import { onLoad, onShow } from "@dcloudio/uni-app";
import unidialog from "@/components/dialog/dialog.vue";
@@ -207,10 +223,106 @@ const welfareNum = ref(0);
const showVideo = ref(false);
const videoWidth = ref(375);
const hasDownload = ref(false);
let downList = uni.getStorageSync('downLoadVideo') || [];
const downLoadStatus = ref('start');
let downList = uni.getStorageSync("downLoadVideo") || [];
const downLoadList = ref(downList);
//import DomVideoPlayer from 'uniapp-video-player'
import sunnyVideo from "@/uni_modules/sunny-video/components/sunny-video/sunny-video.vue";
import downloadStore from "@/store/downloadStoreVideo.js";
const downloadTasks = ref([]);
// 添加下载任务
const addDownloadTask = (item) => {
// 使用store添加任务
const taskIndex = downloadStore.addTask(item);
// 同步任务列表
syncTasksFromStore();
// 开始下载
startDownload(taskIndex);
};
// 开始下载
const startDownload = (index) => {
const taskItem = downloadStore.getTask(index);
if (!taskItem) return;
hasDownload.value = true;
downLoadStatus.value = 'loading';
const task = uni.downloadFile({
url: taskItem.url,
success: (res1) => {
//console.log("res1:"+JSON.stringify(res1));
if (res1.statusCode === 200) {
downloadStore.updateTask(index, {
status: "completed",
filePath: res1.tempFilePath,
});
downLoadStatus.value = 'completed';
uni.showToast({
title: "下载成功",
icon: "none",
});
downLoadStatus.value = 'completed';
uni.saveFile({
tempFilePath: res1.tempFilePath,
success: function (res2) {
console.log("res2:"+JSON.stringify(res2));
uni.getSavedFileInfo({
filePath: res2.savedFilePath,
success: function (res) {
console.log("res:"+JSON.stringify(res));
console.log("size:"+res.size);
downloadStore.updateTask(index, {
status: "completed",
localPath: res2.savedFilePath,
size: res.size,
});
},
});
},
});
} else {
downloadStore.updateTask(index, {
status: "failed",
});
uni.showToast({
title: "下载失败",
icon: "none",
});
}
},
fail: (err) => {
downloadStore.updateTask(index, {
status: "failed",
});
uni.showToast({
title: "下载失败: " + (err.errMsg || "未知错误"),
icon: "none",
duration: 2000,
});
},
});
// 监听下载进度
task.onProgressUpdate((update) => {
const currentTask = downloadStore.getTask(index);
if (currentTask && currentTask.status === "downloading") {
downloadStore.updateTask(index, {
progress: update.progress,
downloadSize: update.totalBytesWritten,
totalSize: update.totalBytesExpectedToWrite,
});
}
});
// 保存task对象到store(用于暂停/继续)
downloadStore.updateTask(index, {
task: task,
});
};
const syncTasksFromStore = () => {
downloadTasks.value = downloadStore.getTasks();
};
const notEnoughConfirm = () => {
notEnoughVisible.value = false;
navTo({
@@ -231,7 +343,18 @@ const toCollection = () => {
const networkConfirm = () => {
networkVisible.value = false;
pointVisible.value = true;
downAndSave(videoSrc.value,video_uuid.value);
if(welfareNum.value > 0) {
useWelfareNum();
}else{
addDownloadTask({
url: videoSrc.value,
id: video_uuid.value,
imgpath: videoInfo.value.imgpath,
author: videoInfo.value.public_name,
name: videoInfo.value.name,
});
}
};
const addVideoWatchRecord = async () => {
const res = await api.addVideoWatchRecord({
@@ -241,25 +364,54 @@ const addVideoWatchRecord = async () => {
}
};
const onLoadedmetadata = (e) => {
un.showModal({
content: '加载完成:'+JSON.stringify(e),
showCancel: false
})
un.showModal({
content: "加载完成:" + JSON.stringify(e),
showCancel: false,
});
};
const onVideoError = (e) => {
uni.showModal({
content: JSON.stringify(e),
showCancel: false
})
content: JSON.stringify(e),
showCancel: false,
});
};
// 接收页面参数
const pageParams = ref({});
const useWelfareNum = async () => {
const res = await api.useWelfareNum({
type: 1,
other_uuid:video_uuid.value,
});
if (res.code == 1) {
uni.showToast({ title: "使用次数成功", icon: "none" });
welfareNum.value--;
addDownloadTask({
url: videoSrc.value,
id: video_uuid.value,
imgpath: videoInfo.value.imgpath,
author: videoInfo.value.public_name,
name: videoInfo.value.name,
});
}
};
const videoDetail = async () => {
const res = await api.videoDetail({ video_uuid: video_uuid.value });
if (res.code == 200) {
const userInfo = uni.getStorageSync("userInfo");
videoInfo.value = res.video;
hasDownload.value = downLoadList.value.includes(video_uuid.value);
downloadTasks.value.forEach(item => {
if (item.id == video_uuid.value) {
uni.getSavedFileInfo({
filePath: item.localPath, //仅做示例用,非真正的文件路径
success: function (res) {
hasDownload.value = true;
downLoadStatus.value = 'completed';
}
});
}
});
//hasDownload.value = downLoadList.value.includes(video_uuid.value);
let vid = res.video.polyv_uuid;
let uuid = vid.substring(0, 10);
let index = vid.lastIndexOf("_");
@@ -300,27 +452,9 @@ const VideoDownloadRecord = async () => {
const res = await api.isVideoDownloadRecord({ video_uuid: video_uuid.value });
if (res.code == 200) {
isVideoDownloadRecord.value = res.result == 0 ? false : true;
console.log(isVideoDownloadRecord.value);
}
};
const downAndSave = (url,uuid) => {
//let url='https://view.xdocin.com/view?src='+encodeURIComponent(pdfUrl);
uni.downloadFile({
url: url,
success: (res) => {
if (res.statusCode === 200) {
let index = downLoadList.value.find(cell => uuid == cell);
if (!index) {
downLoadList.value.push(item.uuid);
uni.setStorageSync('downLoadVideo', downLoadList.value);
};
}
},
});
};
const getWelfareNum = async () => {
const res = await api.getWelfareNum({
type: 1,
@@ -347,13 +481,34 @@ const videoCommentListV2 = async () => {
loading.value = false;
}
};
// 恢复正在下载的任务
const resumeDownloadingTasks = () => {
// 使用 nextTick 确保在页面渲染后再恢复下载任务
nextTick(() => {
downloadStore.resumeDownloadingTasks((index) => {
// 重新开始下载(uni.downloadFile不支持断点续传,所以从0开始)
console.log("恢复下载任务:", downloadStore.getTask(index)?.url);
startDownload(index);
});
});
};
onShow(() => {
hasDownload.value = false;
downLoadStatus.value = 'start';
syncTasksFromStore();
// 监听store变化
downloadStore.addListener((tasks) => {
downloadTasks.value = tasks;
});
// 恢复正在下载的任务
resumeDownloadingTasks();
if (activeTab.value == "comment") {
videoCommentListV2();
}
videoDetail();
uni.hideLoading();
});
const shareRef = ref();
@@ -381,10 +536,10 @@ const shareToWechat = () => {
href: shareLink.value,
imageUrl: docUrl + videoInfo.value.imgpath,
success: function (res) {
console.log("success:" + JSON.stringify(res));
//console.log("success:" + JSON.stringify(res));
},
fail: function (err) {
console.log("fail:" + JSON.stringify(err));
//console.log("fail:" + JSON.stringify(err));
},
});
// #endif
@@ -449,10 +604,10 @@ const shareToMoments = () => {
href: shareLink.value,
imageUrl: docUrl + videoInfo.value.imgpath,
success: function (res) {
console.log("success:" + JSON.stringify(res));
//console.log("success:" + JSON.stringify(res));
},
fail: function (err) {
console.log("fail:" + JSON.stringify(err));
//console.log("fail:" + JSON.stringify(err));
},
});
// #endif
@@ -491,10 +646,10 @@ const shareToWeibo = () => {
href: shareLink.value,
imageUrl: logoImg,
success: function (res) {
console.log("分享成功");
//console.log("分享成功");
},
fail: function (err) {
console.log("fail:" + JSON.stringify(err));
//console.log("fail:" + JSON.stringify(err));
},
});
// plus.share.sendWithSystem({
@@ -529,19 +684,31 @@ const shareToWeibo = () => {
closeShare();
};
const from = ref('');
// 使用uni-app的onLoad生命周期
onLoad((options) => {
console.log(options);
uni.getSystemInfo({
success: function (res) {
videoWidth.value = res.windowWidth; // 窗口宽度
}
});
success: function (res) {
videoWidth.value = res.windowWidth; // 窗口宽度
},
});
video_uuid.value = options.id;
from.value = options.from;
addVideoWatchRecord();
VideoDownloadRecord();
getWelfareNum();
// 从store同步任务列表
syncTasksFromStore();
// 监听store变化
downloadStore.addListener((tasks) => {
downloadTasks.value = tasks;
});
// 恢复正在下载的任务
resumeDownloadingTasks();
// navTo({
// url: "/pages_app/downLoadVideo/downLoadVideo",
// });
});
const videoSrc = ref("");
@@ -562,8 +729,12 @@ const switchTab = (tab) => {
const payVideoDownload = async () => {
const res = await api.payVideoDownload({ video_uuid: video_uuid.value });
if (res.code == 200) {
navTo({
url: "/pages_app/myDownLoad/myDownLoad",
addDownloadTask({
url: videoSrc.value,
id: video_uuid.value,
imgpath: videoInfo.value.imgpath,
author: videoInfo.value.public_name,
name: videoInfo.value.name,
});
} else if (res.code == 106) {
notEnoughVisible.value = true;
@@ -572,31 +743,47 @@ const payVideoDownload = async () => {
};
const onDownload = () => {
console.log(isVideoDownloadRecord.value);
if (!isVideoDownloadRecord.value) {
pointContent.value = `当前需要${videoInfo.value.point}积分兑换,若删除可以再次缓存`;
uni.getNetworkType({
success: function (res) {
console.log(res);
if (res.networkType != "none") {
networkVisible.value = true;
networkContent.value = `当前为${res.networkType}网络,确定下载?`;
if(welfareNum.value <= 0) {
pointContent.value = `当前需要${videoInfo.value.point}积分兑换,若删除可以再次缓存`;
uni.getNetworkType({
success: function (res) {
if (res.networkType != "none") {
networkVisible.value = true;
networkContent.value = `当前为${res.networkType}网络,确定下载?`;
} else {
uni.showToast({ title: "当前未联网,请检查网络", icon: "none" });
}
},
});
}else{
uni.getNetworkType({
success: function (res) {
if (res.networkType != "none") {
networkVisible.value = true;
networkContent.value = `当前为${res.networkType}网络,确定下载?`;
} else {
uni.showToast({ title: "当前未联网,请检查网络", icon: "none" });
}
},
});
}
console.log(11111);
} else {
uni.showToast({ title: "当前未联网,请检查网络", icon: "none" });
}
},
});
} else {
if(hasDownload.value) {
navTo({
url: "/pages_app/myDownLoad/myDownLoad",
if (hasDownload.value) {
navTo({
url: "/pages_app/downLoadVideo/downLoadVideo",
});
} else {
downAndSave(videoSrc.value,video_uuid.value);
addDownloadTask({
url: videoSrc.value,
id: video_uuid.value,
imgpath: videoInfo.value.imgpath,
author: videoInfo.value.public_name,
name: videoInfo.value.name,
});
}
}
};
@@ -674,13 +861,13 @@ $theme-color: #8b2316;
.collect-img {
/* margin-top:50rpx; */
}
.navbox{
:deep(.uni-navbar__header-btns-right){
width: 100px!important;
.navbox {
:deep(.uni-navbar__header-btns-right) {
width: 100px !important;
}
:deep(.uni-navbar__header-btns-left){
min-width: 100px;
width: 100px!important;
:deep(.uni-navbar__header-btns-left) {
min-width: 100px;
width: 100px !important;
}
}
.share-img-icon {
@@ -708,11 +895,10 @@ $theme-color: #8b2316;
.player-wrapper {
background: #fff;
position: fixed;
top:calc(var(--status-bar-height) + 44px);
left: 0;
z-index:0;
height: 220px!important;
position: relative;
top: calc(var(--status-bar-height) + 44px);
z-index: 0;
overflow: hidden;
}
.share-img {
@@ -733,7 +919,7 @@ $theme-color: #8b2316;
z-index: 99;
.tab {
width:120rpx;
width: 120rpx;
position: relative;
display: flex;
justify-content: center;
@@ -741,19 +927,20 @@ $theme-color: #8b2316;
padding: 16rpx 0 24rpx;
color: $text-secondary;
font-size: 28rpx;
.tab-line{
.tab-line {
position: absolute;
bottom: 0;
left: 50%;
transform: translateX(-50%);
width: 64rpx;
height: 6rpx;
z-index: 2;
border-radius: 6rpx;
background: $theme-color;
}
&:nth-child(2){
margin-left: 200rpx;
}
&:nth-child(2) {
margin-left: 200rpx;
}
&.active {
color: $theme-color;
}
@@ -771,15 +958,15 @@ $theme-color: #8b2316;
// }
}
}
.video-detail-page{
position: fixed;
width: 100%;
background: #fff;
// padding: 24rpx 28rpx 40rpx;
top: calc(var(--status-bar-height) + 44px + 220px + 88rpx);
height: calc(100vh - var(--status-bar-height) - 44px - 220px - 90rpx);
overflow-y: scroll;
// background: red;
.video-detail-page {
position: fixed;
width: 100%;
background: #fff;
// padding: 24rpx 28rpx 40rpx;
top: calc(var(--status-bar-height) + 44px + 220px + 88rpx);
height: calc(100vh - var(--status-bar-height) - 44px - 220px - 90rpx);
overflow-y: scroll;
// background: red;
}
.intro {
// background: #fff;