增加推荐页面

This commit is contained in:
YeMingfei666 2025-01-09 17:28:30 +08:00
parent 8572bebabb
commit f6d386e793
5 changed files with 348 additions and 102 deletions

View File

@ -52,3 +52,17 @@ export function getJinbiBili(data) {
data data
}) })
} }
//获取推荐视频
export function tuijianVideo(data){
const randomNum=5+ Math.ceil(Math.random()*30)
return http.request({
url: 'course/selectCourseDetailsList',
method:'GET',
data:{
page: 1,
limit: 5,
randomNum: randomNum
}
})
}

View File

@ -1,16 +1,17 @@
<template> <template>
<view class="item" @appear="appear" @disappear="disappear"> <view class="item" @appear="appear" @disappear="disappear" @click.stop>
<video class="u-flex-1 video" :show-fullscreen-btn="false" @controlstoggle="controlstoggles" <video class="u-flex-1 video" :show-fullscreen-btn="false" @controlstoggle="controlstoggles" v-if="showVideo"
v-if="showVideo" @waiting="waiting()" object-fit="cover" @waiting="waiting()" object-fit="cover"
@play="videoPlay('myVideo'+item.courseDetailsId,item.courseDetailsId)" :play-strategy="2" @play="videoPlay('myVideo'+item.courseDetailsId,item.courseDetailsId)" :play-strategy="2"
:show-loading="true" codec="software" :muted="false" :show-center-play-btn="true" :loop="false" :show-loading="true" codec="software" :muted="false" :show-center-play-btn="true" :loop="false"
:enable-progress-gesture="false" :poster="item.titleImg" :ref="'myVideo'+item.courseDetailsId" :enable-progress-gesture="false" :poster="item.titleImg" :ref="'myVideo'+item.courseDetailsId"
:autoplay="autoplay" @ended="ended" :id="'myVideo'+item.courseDetailsId" :src="item.videoUrl"></video> :autoplay="autoplay" @ended="ended" :id="'myVideo'+item.courseDetailsId" :src="item.videoUrl"></video>
<image class="poster" v-else @click="popupShow('pay')" :src="item.titleImg" mode="aspectFill"></image> <image class="poster" v-else @click="!item.videoUrl?popupShow('pay'):''" :src="item.titleImg" mode="aspectFill">
</image>
<view class="info"> <view class="info" v-if="!isCommand">
<text class="color-fff" v-if="item.courseDetailsName">{{item.courseDetailsName}}</text> <text class="color-fff" v-if="item.courseDetailsName">{{item.courseDetailsName}}</text>
<view v-if="item.content" v-html="item.content"></view> <view v-if="item.content" v-html="item.content"></view>
<view class="u-m-t-20 color-fff" @click="popupShow('show')"> <view class="u-m-t-20 color-fff" @click="popupShow('show')">
@ -19,21 +20,31 @@
</text> </text>
</view> </view>
</view>
<view class="info" v-if="isCommand">
<text class="color-fff" v-if="item.courseDetailsName">{{item.courseDetailsName}}</text>
<view v-if="item.content" v-html="item.content"></view>
<view class="u-m-t-20 color-fff" @click="toDetail">
<text class="color-fff">
查看更多续集 >
</text>
</view>
</view> </view>
<view class="right"> <view class="right">
<view class="love u-flex u-flex-xy-center u-flex-col u-m-b-40 u-text-center" @click="dianzanClick"> <view class="love u-flex u-flex-xy-center u-flex-col u-m-b-40 u-text-center" @click="dianzanClick">
<up-icon name="heart-fill" v-if="item.isGood==1" color="red" size="30"></up-icon> <up-icon name="heart-fill" v-if="item.isGood==1" color="red" size="30"></up-icon>
<up-icon name="heart-fill" v-else color="#ffffff" size="30"></up-icon> <up-icon name="heart-fill" v-else color="#ffffff" size="30"></up-icon>
<text class="text color-fff">{{item.goodNum}}</text> <text class="text color-fff u-font-24">{{item.goodNum}}</text>
</view> </view>
<view class="share u-m-b-40 u-flex u-flex-xy-center u-flex-col u-text-center" @click="share"> <view class="share u-m-b-40 u-flex u-flex-xy-center u-flex-col u-text-center" @click="share">
<image class="icon" src="@/static/images/share.png" mode=""></image> <image class="icon" src="@/static/images/share.png" mode=""></image>
<text class="text color-fff">分享</text> <text class="text color-fff u-font-24">分享</text>
</view> </view>
<view class="zhuiju u-m-b-40 u-flex u-flex-xy-center u-flex-col u-text-center" @click="zhuijuClick"> <view class="zhuiju u-m-b-40 u-flex u-flex-xy-center u-flex-col u-text-center" @click="zhuijuClick">
<image class="icon" v-if="isCollect" src="@/static/images/shuqian.png" mode=""></image> <image class="icon" v-if="isCollect" src="@/static/images/shuqian.png" mode=""></image>
<image class="icon" v-else src="@/static/images/shuqian_s.png" mode=""></image> <image class="icon" v-else src="@/static/images/shuqian_s.png" mode=""></image>
<text class="text color-fff">{{isCollect?'已追':'追剧'}}</text> <text class="text color-fff u-font-24">{{isCollect?'已追':'追剧'}}</text>
</view> </view>
</view> </view>
@ -43,16 +54,24 @@
<script setup> <script setup>
import { import {
computed, computed,
nextTick,
onMounted, onMounted,
ref ref,
watch
} from 'vue' } from 'vue'
const props = defineProps({ const props = defineProps({
item: { item: {
type: Object, type: Object,
defaulr: () => { defaulr: () => {
return {videoUrl:''} return {
videoUrl: ''
} }
}
},
isCommand: {
type: Boolean,
default: false
}, },
instance: { instance: {
type: Object, type: Object,
@ -83,16 +102,27 @@
isCollect: { isCollect: {
type: [Number, Boolean], type: [Number, Boolean],
default: 0 default: 0
},
playSpeeds: {
type: Number,
default: 1
} }
}) })
let autoplay = ref(props.item.videoUrl ? true : false) let autoplay = ref(props.item.videoUrl ? true : false)
const emits = defineEmits(['controlstoggles', 'disappear', 'appear', 'waiting', 'videoPlay', 'ended', 'dianzanClick', const emits = defineEmits(['controlstoggles', 'disappear', 'appear', 'waiting', 'videoPlay', 'ended', 'dianzanClick',
'share', 'zhuijuClick', 'popupShow' 'share', 'zhuijuClick', 'popupShow', 'itemMounted', 'toDetail'
]) ])
function controlstoggles() { function controlstoggles(e) {
emits('controlstoggles', e)
}
function toDetail() {
if (video) {
video.pause()
}
emits('toDetail')
} }
function waiting() { function waiting() {
@ -123,15 +153,25 @@
emits('popupShow', key) emits('popupShow', key)
} }
let first = true
function appear() { function appear() {
video && video.play() if (video) {
emits('appear') video.playbackRate(props.playSpeeds)
video.play()
}
emits('appear', first)
if (first) {
first = false
}
} }
let video = null let video = null
function disappear() { function disappear() {
video && video.pause() if (video) {
video.pause()
}
emits('disappear') emits('disappear')
} }
const showVideo = computed(() => { const showVideo = computed(() => {
@ -143,15 +183,33 @@
// #endif // #endif
}) })
onMounted(() => { onMounted(() => {
console.log('onMounted'); init()
emits('itemMounted', props.index)
})
function init() {
try { try {
if(props.item.videoUrl){ if (props.item.videoUrl && showVideo.value) {
video = uni.createVideoContext('myVideo' + props.item.courseDetailsId) video = uni.createVideoContext('myVideo' + props.item.courseDetailsId)
video.playbackRate(props.playSpeeds)
} }
} catch (error) { } catch (error) {
console.error('------') console.error('------')
//TODO handle the exception //TODO handle the exception
} }
}
watch(() => props.playSpeeds, (newval) => {
console.log('speed' + newval);
if (video) {
video.playbackRate(newval)
}
})
watch(() => showVideo.value, (newval) => {
if (newval) {
init()
} else {
video = null
}
}) })
</script> </script>

View File

@ -1,13 +1,19 @@
<template> <template>
<!-- #ifdef H5 --> <!-- #ifdef H5 -->
<view class=" w-full box" style="width: 100vw;"> <view class=" w-full box" style="width: 100vw;">
<swiper v-if="videoList.length" @change="swiperChange" :current="current" :circular="true" vertical <swiper @longpress="popupShow('speed')"
class="u-flex-1" @transition="transition" :indicator-dots="false" :autoplay="false" :interval="0" :style="{height:wHeight+'px'}"
:duration="200"> v-if="videoList.length" @change="swiperChange" :current="current"
:circular="true" vertical class="u-flex-1" @transition="transition" :indicator-dots="false"
:autoplay="false" :interval="0" :duration="200">
<swiper-item v-for="(item,index) in videoList" :key="index"> <swiper-item v-for="(item,index) in videoList" :key="index">
<list-item-vue :total="list.length" :item="item" :current="current" :isCollect="isCollect" <list-item-vue :total="list.length" :item="item"
:index="index" :nowIndex="nowIndex" @dianzanClick="dianzanClick(item,index)" @share="share(item)" :isCommand="isCommand"
@zhuijuClick="zhuijuClick(item)" @popupShow="popupShow"></list-item-vue> :current="current" :isCollect="isCollect"
@toDetail="toDetail(item,index)"
@controlstoggles="controlstoggles" :playSpeeds="playSpeeds" :index="index" :nowIndex="nowIndex"
@dianzanClick="dianzanClick(item,index)" @share="share(item)" @zhuijuClick="zhuijuClick(item)"
@popupShow="popupShow"></list-item-vue>
</swiper-item> </swiper-item>
</swiper> </swiper>
</view> </view>
@ -17,9 +23,12 @@
<list :bounce="false" :loadmoreoffset="wHeight*3" :show-scrollbar="false" ref="listBox" :pagingEnabled="true" <list :bounce="false" :loadmoreoffset="wHeight*3" :show-scrollbar="false" ref="listBox" :pagingEnabled="true"
@loadmore="loadmore" :scrollable="true"> @loadmore="loadmore" :scrollable="true">
<cell v-for="(item,index) in list" :key="item.courseDetailsId" :ref="setRefList(index)"> <cell v-for="(item,index) in list" :key="item.courseDetailsId" :ref="setRefList(index)">
<view class="swipers-items" :style="boxStyle"> <view class="swipers-items" :style="boxStyle" @longpress="popupShow('speed')">
<list-item-vue :total="list.length" :item="item" :current="current" :isCollect="isCollect" <list-item-vue :total="list.length" :item="item" :current="current" :isCollect="isCollect"
:index="index" :instance="instance" :nowIndex="nowIndex" @appear="appear(item,index)" :isCommand="isCommand"
@toDetail="toDetail(item,index)"
@itemMounted="itemMounted" @controlstoggles="controlstoggles" :index="index" :instance="instance"
:nowIndex="nowIndex" @appear="appear($event,item,index)" :playSpeeds="playSpeeds"
@disappear="disappear(item,index)" @dianzanClick="dianzanClick(item,index)" @share="share(item)" @disappear="disappear(item,index)" @dianzanClick="dianzanClick(item,index)" @share="share(item)"
@zhuijuClick="zhuijuClick(item)" @popupShow="popupShow"></list-item-vue> @zhuijuClick="zhuijuClick(item)" @popupShow="popupShow"></list-item-vue>
</view> </view>
@ -28,8 +37,13 @@
<!-- #endif --> <!-- #endif -->
<!-- 返回按钮 -->
<view class="back-icon" v-if="!isTabbar&&control.showBack">
<u-icon name="arrow-left" color="#fff" :size="28" @click="back"></u-icon>
</view>
<!-- 选集 --> <!-- 选集 -->
<up-popup :show="popup.show" :round="10" @close="popupClose('show')"> <up-popup :show="popup.show" :round="10" @close="popupClose('show')" :customStyle="customStyle">
<view class="u-p-30"> <view class="u-p-30">
<view class="u-flex u-flex-row u-row-between"> <view class="u-flex u-flex-row u-row-between">
<view class="u-flex u-flex-row" style="align-items: baseline;"> <view class="u-flex u-flex-row" style="align-items: baseline;">
@ -57,7 +71,7 @@
</view> </view>
</up-popup> </up-popup>
<!-- 支付 --> <!-- 支付 -->
<up-popup :show="popup.pay" :round="10" @close="popupClose('pay')"> <up-popup :show="popup.pay" :round="10" @close="popupClose('pay')" :customStyle="customStyle">
<view class="u-p-30"> <view class="u-p-30">
<view class="u-flex u-flex-row u-row-between"> <view class="u-flex u-flex-row u-row-between">
<view class="u-flex u-flex-row" style="align-items: baseline;"> <view class="u-flex u-flex-row" style="align-items: baseline;">
@ -85,7 +99,7 @@
</view> </view>
</up-popup> </up-popup>
<!-- 支付确认 --> <!-- 支付确认 -->
<up-popup :show="popup.payTips" :round="10" @close="popupClose('payTips')"> <up-popup :show="popup.payTips" :round="10" @close="popupClose('payTips')" :customStyle="customStyle">
<view class="u-p-30"> <view class="u-p-30">
<view class="u-flex u-flex-row u-row-between"> <view class="u-flex u-flex-row u-row-between">
<view class="u-flex u-flex-row" style="align-items: baseline;"> <view class="u-flex u-flex-row" style="align-items: baseline;">
@ -125,13 +139,13 @@
</up-popup> </up-popup>
<!-- 倍速 --> <!-- 倍速 -->
<up-popup :show="popup.speed" :round="0" @close="popupClose('speed')"> <up-popup :show="popup.speed" :round="0" @close="popupClose('speed')" :customStyle="customStyle">
<view class="u-p-20 u-flex u-flex-row u-row-between u-flex-y-center"> <view class="u-p-20 u-flex u-flex-row u-row-between u-flex-y-center">
<text class="font-bold color-333 u-font-28">倍速:</text> <text class="font-bold color-333 u-font-28">倍速:</text>
<view class="u-flex u-flex-row speed-list"> <view class="u-flex u-flex-row speed-list">
<text class="speed-list-item u-font-28" @click="changeSpeed(index)" :class="{active:index==speeds.active}" <text class="speed-list-item u-font-28" @click="changeSpeed(index)"
v-for="(item,index) in speeds.list">{{item.num}}x</text> :class="{active:index==speeds.active}" v-for="(item,index) in speeds.list">{{item.num}}x</text>
</view> </view>
</view> </view>
</up-popup> </up-popup>
@ -163,6 +177,56 @@
onMounted, onMounted,
getCurrentInstance getCurrentInstance
} from 'vue'; } from 'vue';
const props = defineProps({
list: {
type: Array,
default: () => {
[]
}
},
isCommand:{
type:Boolean,
default:false
},
isTabbar:{
type:Boolean,
default:false
},
info: {
tpye: Object,
default: () => {
return {
collect: 0,
current: {},
list: [],
price: 0,
title: ''
}
}
}
})
const control = reactive({
showBack: true,
showControls: true
})
const customStyle=computed(()=>{
// #ifdef H5
return {
bottom:props.isTabbar?'50px':'0'
}
// #endif
// #ifndef H5
return {}
// #endif
})
function controlstoggles(e) {
control.showControls = e.detail.show
control.showBack = control.showControls
console.log(control);
}
const speeds = reactive({ const speeds = reactive({
list: [{ list: [{
name: '0.5x', name: '0.5x',
@ -178,16 +242,35 @@
num: 1.5 num: 1.5
}], }],
active: 1 active: 1
}) })
const $mountedComponents={}
function itemMounted(index) {
// $mountedComponents[index]=true
}
function back() {
const arr = getCurrentPages()
if (arr.length < 2) {
uni.switchTab({
url: '/pages/index/index'
})
return
}
uni.navigateBack()
}
function changeSpeed(index) { function changeSpeed(index) {
speeds.active = index speeds.active = index
uni.showToast({ uni.showToast({
title: '已切换' + speeds[index].num + '倍播放', title: '已切换' + speeds.list[index].num + '倍播放',
icon: 'none', icon: 'none',
duration: 2000 duration: 2000
}) })
} }
const playSpeeds = computed(() => {
return speeds.list[speeds.active].num
})
const instance = getCurrentInstance() const instance = getCurrentInstance()
let isAgree = ref(false); let isAgree = ref(false);
@ -210,17 +293,24 @@
let cacheIndex = null let cacheIndex = null
function appear(item, index) { function appear(isFirst,item, index) {
console.log(item.courseDetailsName + 'appear'); if(isFirst){
$mountedComponents[index]=true
}
if (!initing) {
cacheIndex = index cacheIndex = index
} }
}
function disappear(item, index) { function disappear(item, index) {
console.log('disappear');
if (index == nowIndex.value && cacheIndex != null) { if (index == nowIndex.value && cacheIndex != null && !initing) {
console.log('disappear' + index);
console.log('disappear nowIndex' + nowIndex.value);
console.log('cacheIndex' + cacheIndex);
nowIndex.value = cacheIndex nowIndex.value = cacheIndex
console.log(nowIndex.value);
cacheIndex = null cacheIndex = null
console.log('disappear,nowIndex=' + nowIndex.value);
} }
} }
@ -261,15 +351,21 @@
} }
// //
function goListPosition(index) { function goListPosition(index) {
console.log('index'); console.log('goListPosition:' + index)
console.log(index);
const el = refList.value[index] const el = refList.value[index]
if($mountedComponents[props.list.length-1]){
domModule.scrollToElement(el, { domModule.scrollToElement(el, {
animated: false animated: false
}) })
initing = false;
const item = props.list[index] const item = props.list[index]
setVideoList(item) setVideoList(item)
insertHistory() insertHistory()
}else{
setTimeout(()=>{
goListPosition(index)
},30)
}
} }
@ -287,26 +383,7 @@
function popupShow(key = 'show') { function popupShow(key = 'show') {
popup[key] = true popup[key] = true
} }
const props = defineProps({
list: {
type: Array,
default: () => {
[]
}
},
info: {
tpye: Object,
default: () => {
return {
collect: 0,
current: {},
list: [],
price: 0,
title: ''
}
}
}
})
let jinbiBili = ref(0) let jinbiBili = ref(0)
let wHeight = ref(0) let wHeight = ref(0)
@ -315,7 +392,8 @@
jinbiBili.value = res.value jinbiBili.value = res.value
const sysInfo = uni.getSystemInfoSync() const sysInfo = uni.getSystemInfoSync()
wHeight.value = sysInfo.screenHeight wHeight.value = sysInfo.windowHeight
// wHeight.value = sysInfo.screenHeight
} }
let isCollect = ref(props.info.collect) let isCollect = ref(props.info.collect)
@ -323,6 +401,11 @@
isCollect.value = newval isCollect.value = newval
}) })
function toDetail(item,index){
uni.navigateTo({
url:'/pages/video/detail?courseId='+item.courseId
})
}
function posterError() { function posterError() {
@ -359,9 +442,10 @@
setVideoList(props.info.current) setVideoList(props.info.current)
// #endif // #endif
// #ifdef APP // #ifdef APP
nextTick(() => {
const index = props.list.findIndex(v => v.courseDetailsId == props.info.current.courseDetailsId) const index = props.list.findIndex(v => v.courseDetailsId == props.info.current.courseDetailsId)
console.log('index' + index);
goListPosition(index) goListPosition(index)
})
// #endif // #endif
} }
} }
@ -413,9 +497,6 @@
} }
function controlstoggles() {
}
function videoPlay(videoId, courseDetailsId) { function videoPlay(videoId, courseDetailsId) {
@ -448,6 +529,7 @@
}, 1000) }, 1000)
function swiperChange(e) { function swiperChange(e) {
console.log('e.detail.current');
console.log(e.detail.current); console.log(e.detail.current);
current.value = e.detail.current current.value = e.detail.current
const item = videoList.value[e.detail.current] const item = videoList.value[e.detail.current]
@ -461,6 +543,7 @@
const lastIndex = listLen - 1 const lastIndex = listLen - 1
const index = props.list.findIndex(v => v.courseDetailsId == item.courseDetailsId) const index = props.list.findIndex(v => v.courseDetailsId == item.courseDetailsId)
nowIndex.value = index nowIndex.value = index
console.log('setVideoList nowIndex' + index);
let position = '' let position = ''
if (index === 0) { if (index === 0) {
position = 'start' position = 'start'
@ -468,7 +551,6 @@
if (index === props.list.length - 1) { if (index === props.list.length - 1) {
position = 'end' position = 'end'
} }
console.log(position);
if (current.value == 0) { if (current.value == 0) {
if (position === 'start') { if (position === 'start') {
videoList.value = [item, props.list[index + 1], props.list[lastIndex]] videoList.value = [item, props.list[index + 1], props.list[lastIndex]]
@ -498,7 +580,7 @@
} }
console.log(videoList.value); console.log(videoList.value);
if (!item.videoUrl) { if (!item.videoUrl) {
// popupShow('pay') popupShow('pay')
} }
} }
@ -513,11 +595,12 @@
function waiting() { function waiting() {
} }
let initing = true
configInit() configInit()
onMounted(() => { onMounted(() => {
nextTick(() => {
init() init()
}) // setTimeout(()=>{
// },500)
}) })
watch(() => props.list.length, (newval) => { watch(() => props.list.length, (newval) => {
// #ifdef H5 // #ifdef H5
@ -695,6 +778,13 @@
height: 40rpx; height: 40rpx;
} }
.back-icon {
position: fixed;
z-index: 9999;
left: 30rpx;
top: 100rpx;
}
.pay-list { .pay-list {
.pay-list-item { .pay-list-item {
flex-direction: row; flex-direction: row;

100
pages/video/index.nvue Normal file
View File

@ -0,0 +1,100 @@
<template>
<view class="min-page " :style="comStyle">
<!-- <up-button @click="toDetail">toDetail</up-button> -->
<my-video-list isCommand isTabbar v-if="state.list.length" @swiperChange="swiperChange" :list="state.list" @update="update"
:info="state"
></my-video-list>
</view>
</template>
<script setup>
import {
onLoad,
onShow
} from '@dcloudio/uni-app'
import * as Api from '@/api/video/index.js'
import {
computed,
reactive,
ref
} from 'vue'
import {
slice
} from 'lodash'
let height = ref(0)
const sysInfo = uni.getSystemInfoSync()
height.value = sysInfo.screenHeight - 50
const comStyle = computed(() => {
return {
// height: height.value + 'px'
}
})
function toDetail() {
uni.navigateTo({
url: '/pages/video/detail?courseId=1208'
})
}
let options = {}
const state = reactive({
collect: 0,
current: {},
list: [],
price: 0,
title: ''
})
async function init() {
const res = await Api.tuijianVideo(options)
state.current = res.list[0]
Object.assign(state, res)
state.list = res.list
}
function update({
index,
item
}) {
state.list[index] = item
}
onLoad((opt) => {
Object.assign(options, opt)
init()
})
function swiperChange({
current,
direction,
data
}) {}
onShow(() => {
})
</script>
<style>
page{
height: calc(100vh - 50px);
overflow: hidden;
}
</style>
<style lang="scss" scoped>
.min-page {
/* #ifdef H5 */
height: calc(100vh - 50px);
/* #endif */
/* #ifdef APP */
height: 100vh;
/* #endif */
background-color: #000;
overflow: hidden;
}
.u-popup {
position: fixed;
}
</style>

View File

@ -1,16 +0,0 @@
<template>
<view class="u-p-60">
<up-button @click="toDetail">toDetail</up-button>
</view>
</template>
<script setup>
function toDetail(){
uni.navigateTo({
url:'/pages/video/detail?courseId=1208'
})
}
</script>
<style>
</style>