银耀uniapp
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

309 lines
8.1 KiB

<template>
<view>
<video :custom-cache="false" @loadedmetadata="onLoadedmetadata" id="nodeVideo" @timeupdate="onVideoTimeupdate" :src="currentNode.videoUrl" :title="currentNode.nodeName" play-btn-position="center" show-mute-btn show-center-play-btn controls autoplay enable-play-gesture class="video" ></video>
<view class="subject">
<view class="subject-name u-line-2">
{{subject.subjectName}}
</view>
<view class="subject-introduce u-line-2">
{{subject.introduce}}
</view>
</view>
<u-gap v-if="subject.product" bg-color="#efefef" height="8"></u-gap>
<view v-if="subject.product" class="product">
<view @click="toProductDetail" class="volume">
<u--image :src="subject.product.image" width="168.75rpx" height="168.75rpx" mode="aspectFill" radius="8rpx"></u--image>
<view style="width: 500rpx;" class="volume-info">
<view class="volume-title">{{subject.product.storeName}}</view>
<view class="volume-level">{{subject.product.storeInfo}}</view>
<view class="volume-price">
<view style="height: 30rpx;"><text style="font-size: 16rpx;">¥</text>{{subject.product.price}}</view>
<view class="btn-pay"><u-button type="primary" size="mini">查看</u-button> </view>
</view>
</view>
</view>
</view>
<u-gap bg-color="#efefef" height="8"></u-gap>
<u-tabs @change=onTabChange :list="tabLIst" :current="currentTabIndex" :activeStyle="{color: '#eb3729','font-weight': 'bold'}" lineColor="#eb3729" :scrollable="false" itemStyle="width: 33.33%;height: 100rpx;font-size: 32rpx !important;"></u-tabs>
<view v-show="currentTabIndex == 0">
<view @click="onVolumeChange(item.id, index)" class="volume" v-for="(item ,index) in subject.volumeList" :key="index">
<u--image :src="item.poster" width="300rpx" height="168.75rpx" mode="aspectFill" radius="8rpx"></u--image>
<view class="volume-info">
<view class="volume-title">{{item.volumeName}}</view>
<view class="volume-level">{{item.level}} | {{item.nodeList?item.nodeList.length: 0}}小节</view>
<view class="volume-price">
<view style="height: 30rpx;"><text v-if="!item.isPaid" style="font-size: 16rpx;">¥</text>{{item.isSpike?item.spikePrice:item.price}}</view>
<view v-if="!item.isPaid" @click.stop="onBuy(item.id)" class="btn-pay"><u-button type="primary" size="mini">立即报名</u-button> </view>
<view v-if="item.isPaid" class="btn-pay"><u-button type="success" size="mini">学习</u-button> </view>
</view>
</view>
</view>
</view>
<view v-show="currentTabIndex == 1">
<u-cell-group>
<u-cell @click="onPlayNode(item)" :label="`${(item.duration / 60).toFixed(0)}分钟`" :title="item.nodeName"
v-for="(item, index) in subject.volumeList[volumeIndex].nodeList" :key="index">
<view slot="value" style="padding-right: 20rpx;display: flex; align-items: center;">
<template v-if="item.isFree || subject.volumeList[volumeIndex].isPaid">
<u-icon size="50rpx" name="play-right"></u-icon>立即播放
</template>
<template v-else>
<u-icon size="50rpx" name="lock"></u-icon>解锁专栏
</template>
</view>
</u-cell>
</u-cell-group>
</view>
<view v-show="currentTabIndex == 2">
<view class="subject-detail">
<rich-text :nodes="subject.detail"></rich-text>
</view>
</view>
</view>
</template>
<script>
import { mapState, mapGetters, mapMutations, mapActions } from 'vuex'
import {
getProductDetail,
postCartAdd,
getCartCount,
getProductCode
} from '@/api/store'
import * as SubjectApi from '@/api/subject.js'
import parseHtml from '@/utils/html-parser.js'
let videoContext = null
let timer;
export default {
data() {
return {
tabLIst: [{name:'专栏'},{name:'目录'},{name: '介绍'}],
currentTabIndex: 0,
currentNode: {},
subjectId: undefined,
volumeId: undefined,
nodeId: undefined,
volumeIndex: 0,
nodeIndex: undefined,
volume: {},
subject: {
subjectName: '',
introduce:'',
}
}
},
computed: mapGetters(['userInfo']),
onLoad(options) {
const {sid, vid, nid} = options
this.subjectId = sid
this.volumeId = vid
this.nodeId = nid
this.getSubjectInfo()
uni.$on('VolumePaid', (volumeId) => {
console.log('volumeId: ',volumeId);
this.getSubjectInfo()
})
timer = setInterval(() => {
this.now += 1000
})
},
onReady() {
videoContext = uni.createVideoContext("nodeVideo", this)
},
onUnload() {
uni.$off('VolumePaid')
},
destroyed() {
if(timer) {
clearInterval(timer);
timer = null
}
},
methods: {
toProductDetail() {
this.$yrouter.push({
path: '/pages/shop/GoodsCon/index',
query: { id: this.subject.product.id },
})
},
onTabChange({index, name}) {
this.currentTabIndex = index
},
onLoadedmetadata() {
if(this.currentNode.position) {
console.log("改变进度");
videoContext.seek(this.currentNode.position)
}
videoContext.play()
},
onVideoTimeupdate(e) {
const {currentTime, duration} = e.detail
if(currentTime < 20) {
return
}
// 30秒保存一次记录
uni.$u.throttle(()=>{
console.log('currentTime: ',currentTime);
SubjectApi.saveNodeViews({
nodeId: this.currentNode.id,
volumeId: this.currentNode.volumeId,
subjectId: this.subjectId,
position: currentTime,
duration: duration
})
}, 30000)
},
async getSubjectInfo() {
const res = await SubjectApi.getSubject(this.subjectId)
this.subject = res.data
res.data.detail = res.data.detail.replace(/\<img/gi,
'<img style="max-width:100%;height:auto;"')
res.data.detail = res.data.detail.replace(/\<video/gi,
'<video style="max-width:100%;height:auto;"')
res.data.detail = res.data.detail.replace(/style=""/gi,
'')
this.subject.detail = parseHtml(res.data.detail);
uni.setNavigationBarTitle({
title: this.subject.subjectName
})
if(res.data.videoUrl){
this.currentVideo = res.data.videoUrl
}
if(!this.volumeId) {
this.volumeId = this.subject.volumeList[0].id
}
this.volumeIndex = this.subject.volumeList.findIndex(item => item.id == this.volumeId)
this.onVolumeChange(this.volumeId, this.volumeIndex)
if(this.nodeId) {
const node = this.subject.volumeList[this.volumeIndex].nodeList.find(item => item.id == this.nodeId)
this.onPlayNode(node)
}
},
onVolumeChange(volumeId, index) {
this.volumeId = volumeId
this.volumeIndex = index
this.currentTabIndex = 1
},
async onPlayNode(node) {
const volume = this.subject.volumeList[this.volumeIndex]
if(volume.isPaid || node.isFree) {
if(node.id != this.currentNode.id) {
// 获取进度
const res = await SubjectApi.getNodeViews(node.id)
node.position = 0
if(res.data) {
node.position = res.data.position
}
this.currentNode = node
videoContext.stop()
}
}else {
this.onBuy(volume.id)
}
},
async onBuy(volumeId) {
this.$yrouter.push({
path: '/pages/subject/OrderSubmission/index',
query: {
volumeId: volumeId
},
})
}
}
}
</script>
<style lang="scss" scoped>
.video{
width: 750rpx;
height: 420rpx;
}
.subject{
position: relative;
padding: 20rpx 0;
&-name {
// width: 400rpx ;
color: #333333;
font-size: 36rpx;
padding-left: 30rpx;
}
&-introduce{
// width: 400rpx;
color: #6c6c6c;
font-size: 24rpx;
padding-left: 30rpx;
margin-top: 10rpx;
}
}
.volume{
display: flex;
padding: 30rpx;
justify-content: space-between;
&-info {
width: 350rpx;
}
&-title {
font-size: 32rpx;
height: 70rpx;
}
&-level {
font-size: 24rpx;
color: #6c6c6c;
margin-bottom: 10rpx;
}
&-price {
font-size: 26rpx;
color: #eb3729;
display: flex;
align-items: center;
justify-content: space-between;
}
.btn-pay{
width: 130rpx;
}
}
.node {
padding: 30rpx 0;
margin: 0 30rpx;
border-bottom: #e8e8e8 solid 1px;
&-title {
}
}
.subject-detail{
padding: 30rpx;
}
</style>