保利视频

This commit is contained in:
zoujiandong 2026-02-04 10:12:59 +08:00
parent a7b2a673a9
commit db9ca707ae
11 changed files with 2089 additions and 19 deletions

View File

@ -0,0 +1,97 @@
/**
* @file 拖动进度提示组件
*/
<template>
<view class="plv-player-drag-tips">
<view class="plv-player-drag-tips__box">
<image class="plv-player-drag-tips__direction-img" :src="imgSrc"
@error="imageError">
</image>
<text class="plv-player-drag-tips__time">
{{changeTimeFormat}} / {{durationFormat}}
</text>
</view>
</view>
</template>
<script>
import utils from '@/common/util.js';
import backImg from '@/static/skin/back.png';
import forwardImg from '@/static/skin/forward.png'
export default {
props: {
currentTime: {
type: Number
},
duration: {
type: Number
},
changeTime: {
type: Number
}
},
data() {
return {
isForward: false
}
},
watch: {
changeTime(newValue, oldValue){
this.isForward = newValue > oldValue;
}
},
computed: {
timeFormatType() {
this.duration >= 3600 ? 2 : 1;
},
changeTimeFormat() {
return utils.formatTimeByDuration(this.changeTime, this.timeFormatType);
},
durationFormat() {
return utils.formatTimeByDuration(this.duration, this.timeFormatType)
},
imgSrc() {
return this.isForward ? forwardImg : backImg;
}
}
}
</script>
<style>
.plv-player-drag-tips {
width: 250rpx;
height: 160rpx;
background: rgba(0,0,0,.7);
border-radius: 10rpx;
}
.plv-player-drag-tips__box {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
justify-content: center;
align-items: center;
}
.plv-player-drag-tips__direction-img {
width: 100rpx;
height: 100rpx;
}
.plv-player-drag-tips__time {
font-size: 24rpx;
color: #FFFFFF;
}
</style>

View File

@ -0,0 +1,271 @@
<template>
<view class="plv-player-gesture"
@touchstart="touchstart"
@touchmove="touchmove"
@longpress="handleLongPress"
@touchcancel="handleTouchCancel"
@touchend="touchend">
</view>
</template>
<script>
export default {
props: {
// 屏幕宽度(物理像素)
holeWidth: Number,
// 视频总时长
duration: Number,
// 视频当前播放时间
currentTime: Number
},
computed: {
halfWidth() {
return parseInt(this.holeWidth / 2);
}
},
data() {
return {
// 是否在左区域按下手势
downLeft: false,
// 滑动方向
swipeDir: null
}
},
mounted() {
this.addHandler();
},
methods:{
addHandler() {
// 增加父容器左右滑动监听
let finalTime = -1;
// 计算左右滑动seek进度
const countTime = (position) => {
const { holeWidth, duration, currentTime } = this;
const precent = Math.abs(position) / holeWidth;
const nowTime = currentTime || 0;
const constSecond = duration < 60 ? duration : 60;
let plusTime = parseInt(Math.abs(precent * constSecond));
if (position < 0) plusTime = plusTime * -1;
finalTime = nowTime + plusTime;
finalTime = this.limit(finalTime, 0, duration);
return finalTime;
};
this.addGesture((type, position) => {
switch (type) {
// 下滑
case -1:
// console.log('//下滑');
this.$emit('onGestureEvent', {
type: this.downLeft ? 'LEFT_DOWN' : 'RIGHT_DOWN',
position
});
break;
// 上滑
case -2:
// console.log('//上滑');
this.$emit('onGestureEvent', {
type: this.downLeft ? 'LEFT_UP' : 'RIGHT_UP',
position
});
break;
// 左滑
case 0:
// console.log('//左滑');
this.swipeDir = type;
countTime(position);
this.$emit('onGestureEvent', {
type: 'SEEK_TIME_UPDATE',
finalTime
});
break;
// 右滑
case 1:
// console.log('//右滑');
this.swipeDir = type;
countTime(position);
this.$emit('onGestureEvent', {
type: 'SEEK_TIME_UPDATE',
finalTime
});
break;
// touchend for swipe
case 3:
if (this.swipeDir > -1) {
this.$emit('onGestureEvent', {
type: this.swipeDir ? 'SWIPE_RIGHT' : 'SWIPE_LEFT'
});
this.swipeDir = -1;
}
if (finalTime > -1) {
this.$emit('onGestureSeekTo', finalTime);
finalTime = -1;
}
break;
// doubleTap
case 4:
// console.log('>>>> 双击');
this.$emit('onGestureEvent', {
type: 'DOUBLE_CLICK'
});
break;
// tap
case 5:
// console.log('>>>> 单击');
this.handleClick();
break;
// longTap
case 6:
break;
}
});
},
addGesture(callback) {
const { options } = this;
let startX, startY, moveEndX, moveEndY, X, Y, position, hasType;
let T, lastTap, isJustTouch = true;
const excuteCb = (type) => {
// type 手势类型 -2 上滑 -1 下滑 0 左滑 1 右滑 2 just touch 3 touchend 4 doubleTap 5 tap 6 longTap
if (callback && typeof callback === 'function')
callback(type, position);
};
const YPlus = 20;
const YReduce = YPlus * -1;
const XPlus = 50;
const XReduce = XPlus * -1;
const isXchange = () => {
if (X > XPlus || X < XReduce) {
position = X;
hasType = 'X';
isJustTouch = false;
}
if (X > XPlus) excuteCb(1);
// 左滑
else if (X < XReduce) excuteCb(0);
};
const isYchange = () => {
if (Y > YPlus || Y < YReduce) {
position = Y;
hasType = 'Y';
isJustTouch = false;
}
if (Y > YPlus) excuteCb(-1);
// 上滑
else if (Y < YReduce) excuteCb(-2);
};
const countDirect = () => {
if (hasType) {
hasType === 'X' ? isXchange() : isYchange();
return;
}
isXchange();
isYchange();
};
this.handleTouch = (type, e) => {
switch(type) {
case 'start':
startX = e.changedTouches[0].pageX;
startY = e.changedTouches[0].pageY;
T = Date.now();
hasType = '';
isJustTouch = true;
this.downLeft = startX < this.halfWidth ? true : false;
break;
case 'move':
moveEndX = e.changedTouches[0].pageX;
moveEndY = e.changedTouches[0].pageY;
X = moveEndX - startX;
Y = moveEndY - startY;
countDirect();
break;
case 'end':
if (isJustTouch)
if (lastTap && Date.now() - lastTap <= 300)
excuteCb(4);
else if (Date.now() - T < 1000)
excuteCb(5);
else
excuteCb(6);
else
excuteCb(3);
lastTap = Date.now();
isJustTouch = true;
break;
}
};
},
handleClick() {
this.$emit('onGestureClick');
},
touchstart(e) {
this.handleTouch('start', e);
},
touchmove(e) {
this.handleTouch('move', e);
},
touchend(e) {
this.handleTouch('end', e);
this.$emit('onTouchEnd');
},
handleTouchCancel() {
this.$emit('onTouchCancel');
},
handleLongPress() {
this.$emit('onLongPress');
},
/**
* 控制最小值,最大值
* @param num
* @param min
* @param max
* @returns {*}
*/
limit(num, min, max) {
if (num < min) return min;
if (num > max) return max;
return num;
}
}
}
</script>
<style>
.plv-player-gesture {
flex: 1;
flex-direction: row;
}
.plv-player-gesture__left {
flex: 5;
}
.plv-player-gesture__right {
flex: 5;
}
</style>

View File

@ -0,0 +1,68 @@
<template>
<view v-if="isShow" class="plv-player-icon">
<image class="plv-player-icon__img" :src="imgUrl"></image>
<text class="plv-player-icon__text">{{ precent + '%' }}</text>
</view>
</template>
<script>
export default {
props: {
imgUrl: {
type: 'string',
required: true
},
precent: {
type: 'Number',
default: 100,
required: true
}
},
watch: {
precent(num) {
if (!this.isShow) this.isShow = true;
this.startClock();
}
},
data() {
return {
isShow: false
}
},
methods: {
startClock() {
this.clearClock();
this.clock = setTimeout(() => {
this.isShow = false;
}, 1500);
},
clearClock() {
if (this.clock) clearTimeout(this.clock);
this.clock = null;
}
}
}
</script>
<style>
.plv-player-icon {
align-items: center;
justify-content: center;
}
.plv-player-icon__img {
width: 80rpx;
height: 80rpx;
}
.plv-player-icon__text {
color: #FFFFFF;
text-align: center;
}
</style>

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,92 @@
<template>
<view v-if="isShow" class="plv-player-volume-wrap">
<image class="plv-player-volume__img" :src="value === 0 ? muteImgUrl : imgUrl "></image>
<view class="plv-player-volume__progress">
<view class="plv-player-volume__progress__played" :style="'flex:' + value"></view>
<view class="plv-player-volume__progress_surplus" :style="'flex:' + valueLeft"></view>
</view>
</view>
</template>
<script>
export default {
props: {
imgUrl: {
type: 'string',
required: true
},
muteImgUrl: {
type: 'string',
required: true
},
value: {
type: 'Number',
default: 0.5,
required: true
}
},
watch: {
value(num) {
if (!this.isShow) this.isShow = true;
this.startClock();
}
},
computed: {
valueLeft() {
return 1 - this.value;
}
},
data() {
return {
isShow: false
}
},
methods: {
startClock() {
this.clearClock();
this.clock = setTimeout(() => {
this.isShow = false;
}, 1500);
},
clearClock() {
if (this.clock) clearTimeout(this.clock);
this.clock = null;
}
}
}
</script>
<style>
.plv-player-volume-wrap {
flex-direction: row;
align-items: center;
justify-content: center;
}
.plv-player-volume__img {
width: 40rpx;
height: 40rpx;
margin-right: 10rpx;
}
.plv-player-volume__progress {
width: 260rpx;
height: 8rpx;
flex-direction: row;
background-color: #09BB07;
}
.plv-player-volume__progress__played {
background-color: #007AFF;
}
.plv-player-volume__progress_surplus {
background-color: #FFFFFF;
}
</style>

View File

@ -9,16 +9,16 @@
}
},
"pages": [
// {
// "path": "pages/upload/upload",
// "style": {
// "navigationBarTitleText": "",
// "navigationStyle": "custom",
// "app": {
// "bounce": "none"
// }
// }
// },
{
"path": "pages/upload/upload2",
"style": {
"navigationBarTitleText": "",
"navigationStyle": "custom",
"app": {
"bounce": "none"
}
}
},
{
"path": "pages/loading/loading",
"style": {

337
pages/upload/upload2.nvue Normal file
View File

@ -0,0 +1,337 @@
<template>
<view class="wrap">
<view :class="isFull ? 'player-full' : 'player'">
<plv-player
ref="vod"
class="vod-player"
seekType=1
autoPlay=true
disableScreenCAP=false
rememberLastPosition=false
@onPlayStatus="onPlayStatus"
@onPlayError="onPlayError"
@positionChange="positionChange"
@onEnableSubtitle="onEnableSubtitle"
@onSRTTextConfig="onSRTTextConfig"
@onSRTTitle="onSRTTitle">
</plv-player>
<Skin ref="skin"
class="skin-control"
:defaultVolume="defaultVolume"
@onPlayBtnClick="onPlayBtnClick"
@onToSeek="onToSeek"
@onFullBtnClick="onFullBtnClick"
@onHdBtnClick="onHdBtnClick"
@onRateBtnClick="onRateBtnClick"
@onVolumeChanged="onVolumeChanged"
@onScalingBtnClick="onScalingBtnClick"
@onScreenShot="onScreenShot"
@onChangeSRTBtnClick="onChangeSRTBtnClick"
@onChangeSRTSingleMode="onChangeSRTSingleMode"
@onOpenSRT="onOpenSRT">
</Skin>
</view>
<view v-if="!isFull" style="padding: 20rpx;">
<input class="uni-input" style="min-height: 35px; height: 35px; border: 1px solid #cccccc;font-size: 14px;" :value="videoVid"
@input="onVidInput" placeholder="请输入视频vid" />
<button type="primary" @click="setVid()">播放</button>
</view>
</view>
</template>
<script>
//import Head from '../../components/page-head.nvue';
import Skin from '@/components/plv-player-skin2/skin.nvue';
//import DragTips from '@/components/plv-player-skin/drag-tips.nvue';
const dom = weex.requireModule('dom');
var configModule = uni.requireNativePlugin("PLV-VodUniPlugin-ConfigModule")
export default {
components: {
Skin,
//Head
},
onReady() {
configModule.setConfig({
'config': "dDzXiPJ8psA/7LvtlPgpNfdOjzKVVEYvca1QBOp2MqCVKC93YiligqqfzOzETkDmolLNBUF4vAykBuUnn+U4V9NoK9vaofwESluIMO9WSB0eWhrw+fBkn+h+OZAmwmYgHQ6fCtsggZKN6cW/FhjWAQ==", //加密串配置
},
(ret) => {
if (ret.isSuccess == true) {
uni.showToast({
title: '设置加密串成功',
icon: "none"
})
} else {
let errMsg = ret.errMsg;
uni.showToast({
title: '设置加密串失败:' + errMsg,
icon: "none"
})
}
})
this.vodPlayer = this.$refs.vod;
this.skin = this.$refs.skin;
// plus.screen.lockOrientation('portrait-primary');
},
data() {
return {
title: '播放器Demo',
// 播放器组件
vodPlayer: null,
// 控制栏组件
skin: null,
//是否全屏
isFull: false,
// 默认音量
defaultVolume: 0.5,
videoVid: '4ae3fe3ab5a2009a8d6605d81b2e3c9b_4'
};
},
methods: {
//输入vid
onVidInput: function(event) {
this.videoVid = event.detail.value;
},
setVid() {
if(!this.videoVid) {
uni.showToast({
title: "请输入视频Vid",
icon: "none"
})
return;
}
const { vodPlayer } = this;
vodPlayer.setVid({
vid:this.videoVid,
level:0
}, (ret) => {
console.log(12)
console.log(ret)
this.text = JSON.stringify(ret);
if (ret.errMsg != null) {
uni.showToast({
title: ret.errMsg,
icon: "none"
})
}
});
},
onPlayError(e){
console.log(e);
if (e.detail.errEvent != null) {
uni.showToast({
title:'playErrorEvent - '+e.detail.errEvent,
icon: "none"
})
}
},
positionChange(e){
this.skin.timeUpdate(e.detail.currentPosition);
},
onEnableSubtitle(e){
console.log("===1" + e.detail);
this.skin.setEnableSubtitle(e.detail.isEnableSubtitle, e.detail.isEnableDoubleSubtitle);
},
onSRTTextConfig(e) {
console.log("===1 fontColor: " + e.detail.fontColor);
this.skit.setSRTTextConfig(e.detail);
},
onSRTTitle(e) {
console.log("===1 onSRTTitle" + e.detail);
},
onPlayStatus(e){
const { skin, vodPlayer } = this;
const state = e.detail.playbackState;
const preparedToPlay = e.detail.preparedToPlay;
if (state != null) {
this.skin.changePlayStatus(state === 'start');
} else if (preparedToPlay != null) {
this.updateDuration();
this.updateLevels();
this.updateScaling();
}
},
updateDuration() {
const { vodPlayer } = this;
if (!vodPlayer) return;
vodPlayer.getDuration(null, ret => {
this.skin.updateDuration(ret.duration);
});
},
updateLevels() {
const { vodPlayer } = this;
if (!vodPlayer) return;
vodPlayer.getLevelNum(null, ret => {
this.skin.updateLevels(ret.levelNum);
});
vodPlayer.getCurrentLevel(null, ret => {
this.skin.updateCurrentLevel(ret.currentLevel);
});
},
updateScaling() {
const { vodPlayer } = this;
if (!vodPlayer) return;
vodPlayer.getScalingMode({}, ret => {
this.skin.updateScaling(ret.scalingMode);
});
},
onPlayBtnClick(isPlaying) {
const { vodPlayer } = this;
if (!vodPlayer) return;
isPlaying ? vodPlayer.start() : vodPlayer.pause();
},
onHdBtnClick(level) {
const { vodPlayer } = this;
if (!vodPlayer) return;
vodPlayer.changeLevel({level});
},
onRateBtnClick(speed) {
const { vodPlayer } = this;
if (!vodPlayer) return;
vodPlayer.setSpeed({speed});
},
onScalingBtnClick(scalingMode) {
const { vodPlayer } = this;
if (!vodPlayer) return;
vodPlayer.setScalingMode({scalingMode});
},
onChangeSRTBtnClick(srt) {
console.log("===1 " + srt);
const { vodPlayer } = this;
if (!vodPlayer) return;
vodPlayer.changeSRT(srt);
},
onChangeSRTSingleMode(isSingle) {
const { vodPlayer } = this;
if (!vodPlayer) return;
vodPlayer.changeSRTSingleMode(isSingle);
},
onOpenSRT(isOpen) {
const { vodPlayer } = this;
if (!vodPlayer) return;
vodPlayer.setOpenSRT({
openSrt: isOpen
});
},
onFullBtnClick(isFull) {
// plus.screen.unlockOrientation();
plus.navigator.setFullscreen(isFull);
//通过h5+实现横竖屏
// isFull ? plus.screen.lockOrientation('landscape-primary') : plus.screen.lockOrientation('portrait-primary');
//通过原生实现横竖屏切换
const { vodPlayer } = this;
if (!vodPlayer) return;
isFull ? vodPlayer.changeToLandscape() : vodPlayer.changeToPortrait();
this.isFull = isFull;
},
onToSeek(time) {
const { vodPlayer } = this;
if (!vodPlayer) return;
vodPlayer.seekTo({seconds: time});
},
onVolumeChanged(value) {
const { vodPlayer, skin } = this;
if (!vodPlayer) return;
vodPlayer.getVolume(null, ret => {
const changedValue = ret.volume + value;
const realValue = this.limit(changedValue, 0, 1);
vodPlayer.setVolume({volume: realValue});
skin.updateVolumeValue(realValue);
});
},
onScreenShot() {
const { vodPlayer } = this;
if (!vodPlayer) return;
vodPlayer.snapshot(null, result =>{
if(result.errMsg != null){
console.log(result.errMsg)
}
});
},
/**
* 控制最小值,最大值
* @param num
* @param min
* @param max
* @returns {*}
*/
limit(num, min, max) {
if (num < min) return min;
if (num > max) return max;
return num;
}
}
}
</script>
<style>
.wrap {
flex: 1;
}
.title {
height: 140rpx;
}
.player {
height: 400rpx;
}
.player-full {
flex: 1;
}
.vod-player {
flex: 1;
}
.skin-control {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 1;
}
.hide {
height: 0;
}
</style>

View File

@ -19,7 +19,7 @@
<view class="top-banner" @click="goWelfare" v-if="hasCard">
<image :src="bgImg" mode="widthFix" class="bg-img"></image>
<view class="banner-text">
<view class="line1">已兑换{{ cardInfo.length }}</view>
<view class="line1">已兑换{{ totalCount}}</view>
<view class="line2" @click.stop="goWelfare">查看现有权益</view>
</view>
<view class="help-btn" @click.stop="showRules">帮助说明</view>
@ -129,7 +129,7 @@
import rightImg from '@/static/right_selsect_big.png'
import empty from '@/components/empty/empty.vue'
import { onLoad,onBackPress } from '@dcloudio/uni-app'
const totalCount = ref(0);
const from=ref('');
onBackPress(() => {
if(!from.value){
@ -171,6 +171,7 @@
} else {
cardInfo.value = pageNum.value === 1 ? list : cardInfo.value.concat(list)
}
totalCount.value = res.data.total;
hasCard.value = list.length > 0 || cardInfo.value.length > 0
isLastPage.value = !!res.data.isLastPage
}
@ -221,7 +222,7 @@
const goPointsDetail = () => {
console.log('goPointsDetail')
uni.navigateTo({ url: '/pages_app/myWelfareCard/exchange?num='+cardInfo.value.length })
uni.navigateTo({ url: '/pages_app/myWelfareCard/exchange?num='+totalCount.value })
};
const goMyWelfare = () => {

View File

@ -1,4 +1,4 @@
//let BASE_URL='https://dev-app.igandan.com/app';
let BASE_URL='https://app.igandan.com/app'
let BASE_URL='https://dev-app.igandan.com/app';
//let BASE_URL='https://app.igandan.com/app'
export default BASE_URL

View File

@ -1,5 +1,5 @@
//let DOC_URL='https://dev-doc.igandan.com/app/';
let DOC_URL='https://doc.igandan.com/app/'
let DOC_URL='https://dev-doc.igandan.com/app/';
//let DOC_URL='https://doc.igandan.com/app/'
// if(app.globalData.apiHost.indexOf('dev')>-1){
// DOC_URL='https://dev-doc.igandan.com/app/'
// }else{

View File

@ -1,5 +1,5 @@
//let OTHER_HOST='https://dev-wx.igandan.com'
let OTHER_HOST='https://wx.igandan.com'
let OTHER_HOST='https://dev-wx.igandan.com'
//let OTHER_HOST='https://wx.igandan.com'
//const app = getApp({allowDefault: true});
// if(app.globalData.apiHost && app.globalData.apiHost.indexOf('dev')>-1){
// OTHER_HOST='https://dev-wx.igandan.com'