Files
ks-app-employment-service/packageB/train/video/videoDetail.vue
2025-11-04 14:31:37 +08:00

339 lines
8.6 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<AppLayout :title="title" :show-bg-image="false">
<!-- <template #headerleft>
<view class="btnback">
<image src="@/static/icon/back.png" @click="navBack"></image>
</view>
</template> -->
<view class="video-box">
<view class="video-detail-container">
<!-- 视频播放组件 -->
<view class="video-wrapper">
<video id="myVideo" :src="videoInfo.currentUrl" :poster="trainVideoImgUrl+ videoInfo.cover"
enable-danmu controls style="width: 100%;"></video>
</view>
</view>
<view class="video-info" :style="getItemBackgroundStyle('video-bj2.png')">
<view class="video-title">
<text>视频详情</text>
<view class="title-line"></view>
</view>
<view class="info-detail">
<view class="info-left">
<view class="info-item">
<image class="icon-img" src="../../../static/images/train/zs.png" mode=""></image>
<view class="info-label">
分类
</view>
<view class="info-value">
{{getCategoryLabelByValue(videoInfo.category)}}
</view>
</view>
</view>
<view class="info-right">
<view class="info-item">
<image class="icon-img" src="../../../static/images/train/zs.png" mode=""></image>
<view class="info-label">
等级
</view>
<view class="info-value">
{{getLevelLabelByValue(videoInfo.level)}}
</view>
</view>
<view class="info-item">
<image class="icon-img" src="../../../static/images/train/zs.png" mode=""></image>
<view class="info-label">
讲师
</view>
<view class="info-value">
{{videoInfo.teacherName}}
</view>
</view>
</view>
</view>
<view class="info-detail">
<view class="info-left">
<view class="info-item">
<image class="icon-img" src="../../../static/images/train/zs.png" mode=""></image>
<view class="info-label">
时长
</view>
<view class="info-value">
{{videoInfo.hour}}分钟
</view>
</view>
</view>
<view class="info-right">
<view class="info-item">
<image class="icon-img" src="../../../static/images/train/zs.png" mode=""></image>
<view class="info-label">
发布时间
</view>
<view class="info-value">
{{videoInfo.uploadTime}}
</view>
</view>
</view>
</view>
<view class="video-intro" :style="videoIntroBackgroundStyle('video-bj.png')">
<view class="intro-title">
<image class="intro-img1" src="../../../static/images/train/video-kc.png" mode=""></image>
<view class="title1">
课程
</view>
<view class="title2">
简介
</view>
<image class="intro-img2" src="../../../static/images/train/video-sc.png" mode=""></image>
</view>
<view class="intro-content">
{{videoInfo.introduce}}
</view>
</view>
<view class="video-title">
<text>学习进度</text>
<view class="title-line"></view>
</view>
<view class="progress-box">
<progress :percent="videoInfo.percentage" activeColor="#30A0FF" backgroundColor="#B0DBFF" stroke-width="6" border-radius="10" />
<view class="progress-info">
<view class="progress-left">
已观看
</view>
<view class="progress-right">
{{videoInfo.percentage}}%
</view>
</view>
</view>
</view>
</view>
</AppLayout>
</template>
<script setup>
import { inject, reactive,ref, onMounted, onUnmounted, nextTick } from 'vue';
import { onLoad } from '@dcloudio/uni-app';
const { $api, navTo, navBack } = inject('globalFunction');
import config from "@/config.js"
// state
const title = ref('');
const videoId=ref('')
const userId=ref('')
const videoInfo=ref({})
const trainVideoImgUrl=config.trainVideoImgUrl
const categories=ref([])
const levalLabels=ref([])
const videoContext = ref(null);
const videoUrl = ref('');
const posterUrl = ref('');
const videoTitle = ref('');
const baseUrl = config.imgBaseUrl
const getItemBackgroundStyle = (imageName) => ({
backgroundImage: `url(${baseUrl}/train/${imageName})`,
backgroundSize: '100% 100%', // 覆盖整个容器
backgroundPosition: 'center', // 居中
backgroundRepeat: 'no-repeat'
});
const videoIntroBackgroundStyle = (imageName) => ({
backgroundImage: `url(${baseUrl}/train/${imageName})`,
backgroundSize: '100% 100%', // 覆盖整个容器
backgroundPosition: 'center', // 居中
backgroundRepeat: 'no-repeat'
});
const params = reactive({
videoId: '',
userId: ''
})
onLoad((options) => {
console.log("options",options)
videoId.value=options.id
userId.value=uni.getStorageSync('userInfo').userId
getDictionary()
getData()
});
onMounted(() => {
// 初始化视频上下文
// nextTick(() => {
// videoContext.value = uni.createVideoContext('videoPlayer');
// });
});
function getData() {
params.videoId=videoId.value
params.userId=userId.value
$api.myRequest('/train/public/trainVideo/updateWatchCount',{videoId:videoId.value}).then((resData) => {
console.log("视频更新次数成功")
});
let header={
'Authorization':uni.getStorageSync('Padmin-Token'),
'Content-Type': "application/x-www-form-urlencoded"
}
$api.myRequest('/train/public/trainVideo/model', params,'post',9100,header).then((resData) => {
console.log("resData",resData)
videoInfo.value=resData
videoInfo.value.currentUrl=trainVideoImgUrl+videoInfo.value.trainClassList[0].url
console.log("videoInfo.value.currentUrl",videoInfo.value.currentUrl)
videoInfo.value.percentage=(videoInfo.value.process/(videoInfo.value.hour*60))*100
console.log("videoInfo",videoInfo.value)
});
}
function getDictionary(){
$api.myRequest('/system/public/dict/data/type/train_category', {},'get',9100).then((resData) => {
categories.value=resData.data
});
$api.myRequest('/system/public/dict/data/type/train_level', {},'get',9100).then((resData) => {
levalLabels.value=resData.data
});
}
function getCategoryLabelByValue(value) {
if (!Array.isArray(categories.value)) {
console.warn('categories 不是数组:', categories.value)
return ''
}
const item = categories.value.find(item => item.dictValue === String(value))
return item ? item.dictLabel : '暂无分类'
}
function getLevelLabelByValue(value) {
if (!Array.isArray(levalLabels.value)) {
console.warn('levalLabels 不是数组:', levalLabels.value)
return ''
}
const item = levalLabels.value.find(item => item.dictValue === String(value))
return item ? item.dictLabel : '暂无等级'
}
onUnmounted(() => {
// 组件卸载时停止播放并退出全屏
if (videoContext.value) {
videoContext.value.pause();
videoContext.value.exitFullScreen();
}
});
</script>
<style lang="stylus" scoped>
.video-box{
padding: 10rpx 20rpx;
}
.video-detail-container{
width: 100%;
background-color: #ffffff;
}
.video-wrapper{
position: relative;
width: 100%;
background-color: #000000;
height: auto;
}
.video-info{
width:100%;
margin-top:30rpx;
padding: 20rpx 30rpx;
box-sizing: border-box;
}
.video-title{
font-size: 32rpx;
color: #404040;
font-weight: bold;
position: relative;
margin-bottom: 40rpx;
}
.title-line{
position: absolute;
bottom: -10rpx;
left: 36rpx;
width: 60rpx;
height: 8rpx;
background: linear-gradient(90deg, #FFAD58 0%, #FF7A5B 100%);
border-radius: 4rpx;
}
.info-detail{
display: flex;
flex-wrap: nowrap;
align-items: center;
margin-bottom: 30rpx;
}
.info-left{
width: 35%;
}
.info-right{
width: 65%;
display: flex;
align-items: center;
justify-content: space-between;
}
.info-item{
display: flex;
align-items: center;
}
.icon-img{
width: 24rpx;
height: 28rpx;
}
.info-label{
font-weight: bold;
font-size: 28rpx;
color: #0068C8;
}
.info-value{
font-size: 28rpx;
color: #404040;
}
.video-intro{
padding: 20rpx;
margin-bottom: 30rpx;
}
.intro-title{
display: flex;
align-items: center;
margin-bottom: 10rpx;
}
.intro-img1{
width: 36rpx;
height: 30rpx;
margin-right: 10rpx;
}
.intro-img2{
width: 30rpx;
height: 30rpx;
margin-left: 10rpx;
}
.title1{
font-size: 26rpx;
font-weight: bold;
color: #333333;
}
.title2{
color: #077DF5;
font-size: 26rpx;
font-weight: bold;
}
.intro-content{
font-size: 24rpx;
color: #333333;
line-height: 1.5;
}
.progress-box{
background: linear-gradient(0deg, #DFEDFF 0%, #F8FCFF 100%);
box-shadow: 0px 0px 10px 0px rgba(0,48,107,0.1);
border-radius: 16rpx;
padding: 40rpx 30rpx;
}
.progress-info{
display: flex;
align-items: center;
justify-content: space-between;
font-size: 24rpx;
color: #333333;
margin-top: 20rpx;
}
</style>