890 lines
25 KiB
Plaintext
890 lines
25 KiB
Plaintext
|
|
<template>
|
|||
|
|
<!-- #ifdef APP-PLUS -->
|
|||
|
|
<view class="wrap">
|
|||
|
|
<view class="player" v-if="filepath.length > 0&&isOnline">
|
|||
|
|
<plv-player ref="vod" class="vod-player" seekType="0" autoPlay="true" disableScreenCAP="false" rememberLastPosition="true" @onPlayStatus="onPlayStatus" @onPlayError="onPlayError"
|
|||
|
|
@positionChange="positionChange"></plv-player>
|
|||
|
|
|
|||
|
|
</view>
|
|||
|
|
|
|||
|
|
<view class="controls-contain">
|
|||
|
|
<view class="floating-controls">
|
|||
|
|
<view class="abs-box">
|
|||
|
|
<view style="display: flex;align-items: center;justify-content: center;flex-direction: row;margin-bottom: 5px;">
|
|||
|
|
<view @click="togglePlayLow" style="display: flex;flex-direction: row;">
|
|||
|
|
<u-icon name="rewind-left" size="26px" color="#fff"></u-icon>
|
|||
|
|
<text style="color: #fff;font-size: 12px;">5s</text>
|
|||
|
|
</view>
|
|||
|
|
<view @click="togglePlay" class="playing-icon">
|
|||
|
|
<u-icon name="pause-circle" size="26px" color="#fff" v-if="isPlaying"></u-icon>
|
|||
|
|
<u-icon name="play-circle" size="26px" color="#fff" v-else></u-icon>
|
|||
|
|
</view>
|
|||
|
|
<view @click="togglePlayFast">
|
|||
|
|
<u-icon name="rewind-right" size="26px" color="#c4c6c9"></u-icon>
|
|||
|
|
</view>
|
|||
|
|
|
|||
|
|
</view>
|
|||
|
|
|
|||
|
|
<view class="progress-container">
|
|||
|
|
<view class="time-text">
|
|||
|
|
<text style="font-size: 14px;color: #fff;">{{currentTimeText}}</text>
|
|||
|
|
</view>
|
|||
|
|
<view class="progress-bar" @click="seekByProgressBar($event)">
|
|||
|
|
<u-slider v-model="sliderValue " blockSize="12" @change="changeseek"></u-slider>
|
|||
|
|
|
|||
|
|
</view>
|
|||
|
|
<view class="time-text">
|
|||
|
|
<text style="font-size: 14px;color: #fff;">{{totalTime }}</text>
|
|||
|
|
</view>
|
|||
|
|
|
|||
|
|
</view>
|
|||
|
|
</view>
|
|||
|
|
|
|||
|
|
</view>
|
|||
|
|
|
|||
|
|
</view>
|
|||
|
|
|
|||
|
|
<view v-if="isVodeoEnd" style="background-color: #fff;margin: 20px 20px 0px 20px;padding: 20px;border-radius: 5px;flex: 1;">
|
|||
|
|
<scroll-view class="scrollable-content" scroll-y="true" style="flex: 1;" show-scrollbar="false">
|
|||
|
|
<u--form labelPosition="left" labelWidth="auto" labelAlign="center" errorType="border-bottom" ref="sForm" class="demo-ruleForm">
|
|||
|
|
<view v-for="(item, index) in papers" :key="index" style="border-bottom: #ceccca 1px dashed;margin-bottom: 10px;padding-bottom: 10px;">
|
|||
|
|
|
|||
|
|
<!-- <u-form-item> -->
|
|||
|
|
<view style="display: flex;flex: 1;">
|
|||
|
|
<view style="display: flex; word-wrap: break-word; word-break: break-all;margin-bottom: 10px;white-space: normal;">
|
|||
|
|
<text style="font-size: 15px;">
|
|||
|
|
{{(index + 1) + '. ' + item.Nav_Test.NAME + getType(item)}}
|
|||
|
|
</text>
|
|||
|
|
|
|||
|
|
</view>
|
|||
|
|
<view class="operate-radio">
|
|||
|
|
<u-radio-group v-if="item.Nav_Test.TYPE == 0" v-model="item.ANSWER1" placement="column">
|
|||
|
|
<u-radio :customStyle="{marginBottom: '4px',marginTop: '4px'}" v-for="(item1, index1) in radiolist1" :key="index1" :label="item1.name" :name="item1.name"
|
|||
|
|
@change="doOptionChange(index1, item, 1)" :disabled="readonly" />
|
|||
|
|
</u-radio-group>
|
|||
|
|
<u-radio-group v-if="item.Nav_Test.TYPE == 1" v-model="item.ANSWER2" placement="column">
|
|||
|
|
<u-radio :customStyle="{marginBottom: '4px',marginTop: '4px',whiteSpace:'normal',wordBreak: 'break-all'}" v-for="(item2, index2) in radiolist2[item.ID]" :key="index2"
|
|||
|
|
:label="item2.name" :name="item2.name" @change="doOptionChange(index2, item, 1 << index2)" :disabled="readonly" />
|
|||
|
|
</u-radio-group>
|
|||
|
|
<u-checkbox-group v-if="item.Nav_Test.TYPE == 2" v-model="item.ANSWER3" @change="checkboxChange($event, item)" placement="column">
|
|||
|
|
<u-checkbox :customStyle="{marginBottom: '4px',marginTop: '4px',whiteSpace:'normal !important',wordBreak: 'break-all !important'}" v-for="(item3, index3) in radiolist2[item.ID]"
|
|||
|
|
:key="index3" :label="item3.name" :name="item3.name" :disabled="readonly">
|
|||
|
|
</u-checkbox>
|
|||
|
|
</u-checkbox-group>
|
|||
|
|
</view>
|
|||
|
|
</view>
|
|||
|
|
<!-- </u-form-item> -->
|
|||
|
|
</view>
|
|||
|
|
</u--form>
|
|||
|
|
</scroll-view>
|
|||
|
|
</view>
|
|||
|
|
<view v-else style="flex: 1;display: flex;align-items: center;justify-content: center;">
|
|||
|
|
<text style="color: #c4c6c9;font-size: 14px;">视频播放完毕后,开始答题</text>
|
|||
|
|
</view>
|
|||
|
|
<view class="bottom-button-new">
|
|||
|
|
<button type="primary" v-if="tableKey == 1" @click="submit" :disabled="!isVodeoEnd">提交问卷</button>
|
|||
|
|
</view>
|
|||
|
|
</view>
|
|||
|
|
<!-- #endif -->
|
|||
|
|
<!-- #ifndef APP-PLUS -->
|
|||
|
|
<view class="todo-page" style="padding-bottom: 80px;">
|
|||
|
|
<view class="background"></view>
|
|||
|
|
<view class="video" v-if="filepath.length > 0&&isOnline">
|
|||
|
|
<uni-card margin="0" :is-shadow="true">
|
|||
|
|
<u--form labelPosition="left" labelWidth="auto" labelAlign="center" ref="wForm" errorType="border-bottom">
|
|||
|
|
|
|||
|
|
<view style=" position: relative;z-index: 1;" v-if="polyvy">
|
|||
|
|
<webPlayer :src="filepaths" @over="onEnd()"></webPlayer>
|
|||
|
|
</view>
|
|||
|
|
|
|||
|
|
<view v-else>
|
|||
|
|
<video id="myVideo" @ended="onEnd()" @timeupdate="onTimeUpdate" :src="filepathsWeb" controls></video>
|
|||
|
|
</view>
|
|||
|
|
|
|||
|
|
</u--form>
|
|||
|
|
</uni-card>
|
|||
|
|
</view>
|
|||
|
|
<view v-if="isVodeoEnd" class="card">
|
|||
|
|
<u--form labelPosition="left" labelWidth="auto" labelAlign="center" errorType="border-bottom" ref="sForm" class="demo-ruleForm">
|
|||
|
|
<view style="position: relative;">
|
|||
|
|
<view style="position: absolute;left: -10px;color: #3d4b70;top: -3px;">*</view>
|
|||
|
|
</view>
|
|||
|
|
|
|||
|
|
<view style="font-size: 15px; font-weight: bold;color: #3d4b70;margin-bottom: 10px;">培训教育在线答题</view>
|
|||
|
|
<view v-for="(item, index) in papers" :key="index" style="border-bottom: #ceccca 1px dashed;margin-bottom: 10px;padding-bottom: 10px;">
|
|||
|
|
|
|||
|
|
<u-form-item>
|
|||
|
|
<view style="display: flex;flex: 1;">
|
|||
|
|
<view style="display: flex; word-wrap: break-word; word-break: break-all;margin-bottom: 10px;white-space: normal;">{{(index + 1) + '. ' + item.Nav_Test.NAME + getType(item)}}
|
|||
|
|
</view>
|
|||
|
|
<view>
|
|||
|
|
<u-radio-group v-if="item.Nav_Test.TYPE == 0" v-model="item.ANSWER1" placement="column">
|
|||
|
|
<u-radio :customStyle="{marginBottom: '4px',marginTop: '4px',whiteSpace:'normal',wordBreak: 'break-all',}" v-for="(item1, index1) in radiolist1" :key="index1" :label="item1.name"
|
|||
|
|
:name="item1.name" @change="doOptionChange(index1, item, 1)" :disabled="readonly" />
|
|||
|
|
</u-radio-group>
|
|||
|
|
<u-radio-group v-if="item.Nav_Test.TYPE == 1" v-model="item.ANSWER2" placement="column">
|
|||
|
|
<u-radio :customStyle="{marginBottom: '4px',marginTop: '4px',whiteSpace:'normal',wordBreak: 'break-all',}" v-for="(item2, index2) in radiolist2[item.ID]" :key="index2"
|
|||
|
|
:label="item2.name" :name="item2.name" @change="doOptionChange(index2, item, 1 << index2)" :disabled="readonly" />
|
|||
|
|
</u-radio-group>
|
|||
|
|
<u-checkbox-group v-if="item.Nav_Test.TYPE == 2" v-model="item.ANSWER3" @change="checkboxChange($event, item)" placement="column">
|
|||
|
|
<u-checkbox :customStyle="{marginBottom: '4px',marginTop: '4px'}" v-for="(item3, index3) in radiolist2[item.ID]" :key="index3" :label="item3.name" :name="item3.name"
|
|||
|
|
:disabled="readonly" class="checkbox">
|
|||
|
|
</u-checkbox>
|
|||
|
|
</u-checkbox-group>
|
|||
|
|
</view>
|
|||
|
|
</view>
|
|||
|
|
</u-form-item>
|
|||
|
|
</view>
|
|||
|
|
</u--form>
|
|||
|
|
</view>
|
|||
|
|
<view class="bottom-button">
|
|||
|
|
<button type="primary" v-if="tableKey == 1" @click="submit" :disabled="!isVodeoEnd">提交问卷</button>
|
|||
|
|
</view>
|
|||
|
|
</view>
|
|||
|
|
<!-- #endif -->
|
|||
|
|
</template>
|
|||
|
|
|
|||
|
|
<script>
|
|||
|
|
// #ifdef APP-PLUS
|
|||
|
|
var configModule = uni.requireNativePlugin("PLV-VodUniPlugin-ConfigModule")
|
|||
|
|
// #endif
|
|||
|
|
import {
|
|||
|
|
extendFilterGroup,
|
|||
|
|
extendGroupRule,
|
|||
|
|
extendInclude,
|
|||
|
|
extendOrder,
|
|||
|
|
extendRule,
|
|||
|
|
guid,
|
|||
|
|
initFilter,
|
|||
|
|
initFilterGroup,
|
|||
|
|
formatSeconds
|
|||
|
|
} from '../../../../utils/common';
|
|||
|
|
import {
|
|||
|
|
getRequest,
|
|||
|
|
} from '../../../../services/apply/FOServices/FOServices';
|
|||
|
|
import {
|
|||
|
|
GetSource,
|
|||
|
|
SavePapers
|
|||
|
|
} from '../../../../services/apply/subPages/scWB';
|
|||
|
|
import webPlayer from './webPlayer'
|
|||
|
|
import config from '../../../../config/common';
|
|||
|
|
|
|||
|
|
export default {
|
|||
|
|
components: {
|
|||
|
|
webPlayer, // 注册组件
|
|||
|
|
},
|
|||
|
|
data() {
|
|||
|
|
return {
|
|||
|
|
model: {
|
|||
|
|
ORG_ID: "",
|
|||
|
|
},
|
|||
|
|
SOURCE_ID: '',
|
|||
|
|
papers: [],
|
|||
|
|
res: [],
|
|||
|
|
viewAll: false,
|
|||
|
|
filepath: '',
|
|||
|
|
notify: null,
|
|||
|
|
UserList: [],
|
|||
|
|
SelUsrID: null,
|
|||
|
|
config: null,
|
|||
|
|
score: 0,
|
|||
|
|
END_TIME: null,
|
|||
|
|
readonly: true,
|
|||
|
|
loading: true,
|
|||
|
|
tableKey: '0',
|
|||
|
|
isHaseV: true,
|
|||
|
|
isVodeoEnd: false, //是否显示题目
|
|||
|
|
radiolist1: [{
|
|||
|
|
name: '正确',
|
|||
|
|
disabled: false
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
name: '错误',
|
|||
|
|
disabled: false
|
|||
|
|
},
|
|||
|
|
],
|
|||
|
|
radiolist2: {},
|
|||
|
|
radiovalue1: "错误",
|
|||
|
|
checkbox: [],
|
|||
|
|
TaskID: '',
|
|||
|
|
SelUsrNAME: '',
|
|||
|
|
ORG_ID: uni.getStorageSync('orgId'),
|
|||
|
|
JOBID: '',
|
|||
|
|
progress: 0,
|
|||
|
|
currentTime: '',
|
|||
|
|
allTime: '',
|
|||
|
|
lastTime: 0,
|
|||
|
|
playerUrl: '',
|
|||
|
|
vid: '', // 解析后的视频ID,
|
|||
|
|
plvConfig: {
|
|||
|
|
userid: "3cbccb39d9",
|
|||
|
|
readtoken: "4567132a-70d2-4a92-a1e5-5a417fe4ab5b",
|
|||
|
|
writetoken: "007263ef-a7ee-4681-b248-395d1da539b9",
|
|||
|
|
secretkey: "WUAYy8sr4"
|
|||
|
|
},
|
|||
|
|
// 新增状态变量
|
|||
|
|
isPlaying: false, // 是否正在播放
|
|||
|
|
currentTime: 0, // 当前播放时间(秒)
|
|||
|
|
totalTime: 0, // 总时长(秒)
|
|||
|
|
currentTimeText: 0,
|
|||
|
|
progressPercent: 0, // 进度百分比
|
|||
|
|
duration: 0,
|
|||
|
|
sliderValue: 0,
|
|||
|
|
timeShowBlock: true,
|
|||
|
|
now: 'init',
|
|||
|
|
filepaths: '',
|
|||
|
|
filepathsWeb: '',
|
|||
|
|
polyvy: true,
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
onLoad(option) {
|
|||
|
|
this.TaskID = option.taskID ? option.taskID : '';
|
|||
|
|
this.model.ID = option.ID ? option.ID : '';
|
|||
|
|
this.JOBID = option.ID ? option.ID : '';
|
|||
|
|
this.tableKey = option.tableKey ? option.tableKey : '0'
|
|||
|
|
// #ifdef APP-PLUS
|
|||
|
|
|
|||
|
|
if (!configModule) {
|
|||
|
|
this.$emit('onError', '插件初始化失败');
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
configModule.setToken({
|
|||
|
|
userid: "3cbccb39d9",
|
|||
|
|
readtoken: "4567132a-70d2-4a92-a1e5-5a417fe4ab5b",
|
|||
|
|
writetoken: "007263ef-a7ee-4681-b248-395d1da539b9",
|
|||
|
|
secretkey: "WUAYy8sr4"
|
|||
|
|
}, (ret) => {
|
|||
|
|
if (!ret.isSuccess) {
|
|||
|
|
this.$emit('onError', ret.errMsg);
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
this.totalTime = this.formatTime(0);
|
|||
|
|
this.currentTimeText = this.formatTime(0)
|
|||
|
|
// #endif
|
|||
|
|
this.loadData();
|
|||
|
|
},
|
|||
|
|
watch: {
|
|||
|
|
// 监听 filepaths 的变化
|
|||
|
|
filepaths(newVal, oldVal) {
|
|||
|
|
if (newVal) {
|
|||
|
|
const regex = /vid=([^&]+)/;
|
|||
|
|
const match = newVal.match(regex);
|
|||
|
|
this.vid = match ? match[1] : '';
|
|||
|
|
this.now = 'init'
|
|||
|
|
if (oldVal !== '') {
|
|||
|
|
this.togglePlay()
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
},
|
|||
|
|
methods: {
|
|||
|
|
togglePlay() {
|
|||
|
|
if (this.now == 'init') {
|
|||
|
|
this.$refs.vod.setVid({
|
|||
|
|
vid: this.vid,
|
|||
|
|
level: 0
|
|||
|
|
},
|
|||
|
|
(ret) => {
|
|||
|
|
if (ret.errMsg != null) {
|
|||
|
|
uni.showToast({
|
|||
|
|
title: ret.errMsg,
|
|||
|
|
icon: "none"
|
|||
|
|
})
|
|||
|
|
}
|
|||
|
|
})
|
|||
|
|
this.now = 'playing'
|
|||
|
|
} else {
|
|||
|
|
if (this.isPlaying) {
|
|||
|
|
// 调用暂停API(需确认保利威插件实际方法名,可能为pause/stop)
|
|||
|
|
this.$refs.vod.pause();
|
|||
|
|
} else {
|
|||
|
|
this.$refs.vod.start();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
changeseek(e) {
|
|||
|
|
// 将0-100的滑块值转换为对应的视频时间(秒)
|
|||
|
|
const seekTime = Math.round((e / 100) * this.duration);
|
|||
|
|
if (seekTime < this.currentTime) {
|
|||
|
|
this.$refs.vod.seekTo({
|
|||
|
|
seconds: seekTime
|
|||
|
|
},
|
|||
|
|
(ret) => {
|
|||
|
|
if (ret.errMsg != null) {
|
|||
|
|
uni.showToast({
|
|||
|
|
title: ret.errMsg,
|
|||
|
|
icon: "none"
|
|||
|
|
})
|
|||
|
|
}
|
|||
|
|
})
|
|||
|
|
} else {
|
|||
|
|
uni.$showErrorInfo('培训答题视频禁止快进');
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
togglePlayLow() {
|
|||
|
|
this.$refs.vod.rewind({
|
|||
|
|
seconds: 5
|
|||
|
|
},
|
|||
|
|
(ret) => {
|
|||
|
|
if (ret.errMsg != null) {
|
|||
|
|
uni.showToast({
|
|||
|
|
title: ret.errMsg,
|
|||
|
|
icon: "none"
|
|||
|
|
})
|
|||
|
|
}
|
|||
|
|
})
|
|||
|
|
},
|
|||
|
|
togglePlayFast() {
|
|||
|
|
uni.$showErrorInfo('培训答题视频禁止快进');
|
|||
|
|
},
|
|||
|
|
setVid() {
|
|||
|
|
this.$refs.vod.setVid({
|
|||
|
|
vid: this.vid,
|
|||
|
|
level: 0
|
|||
|
|
},
|
|||
|
|
(ret) => {
|
|||
|
|
if (ret.errMsg != null) {
|
|||
|
|
uni.showToast({
|
|||
|
|
title: ret.errMsg,
|
|||
|
|
icon: "none"
|
|||
|
|
})
|
|||
|
|
}
|
|||
|
|
})
|
|||
|
|
},
|
|||
|
|
onPlayStatus(e) {
|
|||
|
|
const status = e.detail.playbackState;
|
|||
|
|
// 根据保利威状态枚举更新播放状态(需参考插件文档,示例值)
|
|||
|
|
this.isPlaying = status == 'start'
|
|||
|
|
|
|||
|
|
// 视频结束时更新状态
|
|||
|
|
if (status == 'complete') {
|
|||
|
|
this.isPlaying = false;
|
|||
|
|
this.isVodeoEnd = true;
|
|||
|
|
}
|
|||
|
|
if (e.detail.preparedToPlay !== null) {
|
|||
|
|
this.updateDuration();
|
|||
|
|
}
|
|||
|
|
this.$forceUpdate()
|
|||
|
|
},
|
|||
|
|
updateDuration() {
|
|||
|
|
this.$refs.vod.getDuration(null, ret => {
|
|||
|
|
this.duration = ret.duration;
|
|||
|
|
this.timeShowBlock = ret.duration >= 3600 ? false : true;
|
|||
|
|
});
|
|||
|
|
},
|
|||
|
|
positionChange(e) {
|
|||
|
|
this.timeUpdate(e.detail.currentPosition);
|
|||
|
|
},
|
|||
|
|
timeUpdate(time) {
|
|||
|
|
this.currentTime = time;
|
|||
|
|
this.updateProgress();
|
|||
|
|
},
|
|||
|
|
updateProgress(precent) {
|
|||
|
|
// this.currentTime = e.detail.currentPosition;
|
|||
|
|
this.totalTime = this.formatTime(this.duration);
|
|||
|
|
this.currentTimeText = this.formatTime(this.currentTime)
|
|||
|
|
// 将当前播放时间(秒)转换为0-100的滑块值
|
|||
|
|
this.sliderValue = (this.currentTime / this.duration) * 100;
|
|||
|
|
// 计算进度百分比
|
|||
|
|
// this.progressPercent = this.duration > 0 ? (this.currentTime / this.duration) * 100 : 0;
|
|||
|
|
this.$forceUpdate()
|
|||
|
|
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
// 格式化时间(秒 -> MM:SS)
|
|||
|
|
formatTime(seconds) {
|
|||
|
|
if (this.timeShowBlock == true) {
|
|||
|
|
const min = Math.floor(seconds / 60);
|
|||
|
|
const sec = Math.floor(seconds % 60);
|
|||
|
|
return `${min.toString().padStart(2, '0')}:${sec.toString().padStart(2, '0')}`;
|
|||
|
|
} else {
|
|||
|
|
const hours = Math.floor(seconds / 3600);
|
|||
|
|
// 计算剩余秒数,再 ÷ 60 得到分钟
|
|||
|
|
const minutes = Math.floor((seconds % 3600) / 60);
|
|||
|
|
// 剩余的秒数
|
|||
|
|
const remainingSeconds = seconds % 60;
|
|||
|
|
|
|||
|
|
// 拼接并补零
|
|||
|
|
return `${this.padZero(hours)}:${this.padZero(minutes)}:${this.padZero(remainingSeconds)}`;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
},
|
|||
|
|
padZero(num) {
|
|||
|
|
return num < 10 ? '0' + num : num;
|
|||
|
|
},
|
|||
|
|
// 点击进度条跳转播放位置
|
|||
|
|
seekByProgressBar(e) {
|
|||
|
|
// const player = this.$refs.vod;
|
|||
|
|
if (this.totalTime <= 0) return;
|
|||
|
|
|
|||
|
|
// 获取进度条宽度和点击位置
|
|||
|
|
const barWidth = e.currentTarget.clientWidth;
|
|||
|
|
const clickX = e.touches[0].clientX - e.currentTarget.getBoundingClientRect().left;
|
|||
|
|
// 计算跳转时间
|
|||
|
|
const seekTime = (clickX / barWidth) * this.totalTime;
|
|||
|
|
// 调用播放器跳转API(需确认方法名,可能为seek/setPosition)
|
|||
|
|
this.$refs.vod.seekTo({
|
|||
|
|
position: seekTime
|
|||
|
|
});
|
|||
|
|
},
|
|||
|
|
loadData() {
|
|||
|
|
let json = initFilter(this.ORG_ID, this.model.ID);
|
|||
|
|
extendRule(json, 'ID', 1, this.model.ID);
|
|||
|
|
GetSource(json).then(ret => {
|
|||
|
|
if (ret) {
|
|||
|
|
this.loading = false
|
|||
|
|
var filepath = ''
|
|||
|
|
var isOnline = false
|
|||
|
|
var papers = []
|
|||
|
|
var SOURCE_ID = ''
|
|||
|
|
var readonly = true
|
|||
|
|
var isVodeoEnd = true
|
|||
|
|
this.res = ret
|
|||
|
|
|
|||
|
|
ret.Nav_ListUserPaper.forEach(ele => {
|
|||
|
|
if ((SOURCE_ID == '') && (ele.ANSWER == null || ele.ANSWER == 0)) {
|
|||
|
|
SOURCE_ID = ele.SOURCE_ID
|
|||
|
|
readonly = false
|
|||
|
|
isVodeoEnd = false
|
|||
|
|
}
|
|||
|
|
if (SOURCE_ID.length > 0 && ele.SOURCE_ID == SOURCE_ID) {
|
|||
|
|
papers.push(ele)
|
|||
|
|
isOnline = ele.IS_ONLINE
|
|||
|
|
if (isOnline == true && filepath == '') {
|
|||
|
|
filepath = ele.FILE_PATH
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
if (SOURCE_ID == "") {
|
|||
|
|
papers = ret.Nav_ListUserPaper
|
|||
|
|
}
|
|||
|
|
if (filepath == null || filepath == "") {
|
|||
|
|
isVodeoEnd = true
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
this.papers = papers
|
|||
|
|
this.isOnline = isOnline
|
|||
|
|
this.readonly = readonly
|
|||
|
|
this.SOURCE_ID = SOURCE_ID
|
|||
|
|
this.filepath = filepath
|
|||
|
|
this.filepathsWeb = config.uni_app_web_source_url + filepath
|
|||
|
|
this.filepaths = filepath
|
|||
|
|
if (this.filepaths.indexOf('vid') !== -1) {
|
|||
|
|
this.polyvy = true
|
|||
|
|
} else {
|
|||
|
|
this.polyvy = false
|
|||
|
|
}
|
|||
|
|
const regex = /vid=([^&]+)/;
|
|||
|
|
const match = this.filepaths.match(regex);
|
|||
|
|
this.vid = match ? match[1] : '';
|
|||
|
|
this.isVodeoEnd = isVodeoEnd
|
|||
|
|
this.papers.forEach(item => {
|
|||
|
|
let test = {}
|
|||
|
|
if (item.Nav_Test.TYPE != 0) {
|
|||
|
|
this.radiolist2[item.ID] = [];
|
|||
|
|
this.radiolist2[item.ID].push({
|
|||
|
|
name: item.Nav_Test.OPTION_A
|
|||
|
|
}, {
|
|||
|
|
name: item.Nav_Test.OPTION_B
|
|||
|
|
})
|
|||
|
|
if (item.Nav_Test.OPTION_C != undefined && item.Nav_Test.OPTION_C != "") {
|
|||
|
|
this.radiolist2[item.ID].push({
|
|||
|
|
name: item.Nav_Test.OPTION_C
|
|||
|
|
})
|
|||
|
|
}
|
|||
|
|
if (item.Nav_Test.OPTION_D != undefined && item.Nav_Test.OPTION_D != "") {
|
|||
|
|
this.radiolist2[item.ID].push({
|
|||
|
|
name: item.Nav_Test.OPTION_D
|
|||
|
|
})
|
|||
|
|
}
|
|||
|
|
if (item.Nav_Test.OPTION_E != undefined && item.Nav_Test.OPTION_E != "") {
|
|||
|
|
this.radiolist2[item.ID].push({
|
|||
|
|
name: item.Nav_Test.OPTION_E
|
|||
|
|
})
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
})
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
},
|
|||
|
|
preventFastForward(e) {
|
|||
|
|
const currentTime = e.detail.currentTime;
|
|||
|
|
if (currentTime > this.lastTime + 1) {
|
|||
|
|
uni.$showErrorInfo('禁止快进');
|
|||
|
|
const videoContext = uni.createVideoContext('myVideo', this)
|
|||
|
|
videoContext.seek(this.lastTime);
|
|||
|
|
} else {
|
|||
|
|
this.lastTime = currentTime;
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
findSelectedOptions(num, OPTION_A, OPTION_B, OPTION_C, OPTION_D, OPTION_E) {
|
|||
|
|
var optionVars = {
|
|||
|
|
'A': {
|
|||
|
|
value: 1,
|
|||
|
|
variable: OPTION_A
|
|||
|
|
},
|
|||
|
|
'B': {
|
|||
|
|
value: 2,
|
|||
|
|
variable: OPTION_B
|
|||
|
|
},
|
|||
|
|
'C': {
|
|||
|
|
value: 4,
|
|||
|
|
variable: OPTION_C
|
|||
|
|
},
|
|||
|
|
'D': {
|
|||
|
|
value: 8,
|
|||
|
|
variable: OPTION_D
|
|||
|
|
},
|
|||
|
|
'E': {
|
|||
|
|
value: 16,
|
|||
|
|
variable: OPTION_E
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
var selectedVars = [];
|
|||
|
|
for (var key in optionVars) {
|
|||
|
|
if ((num & optionVars[key].value) === optionVars[key].value) {
|
|||
|
|
selectedVars.push(optionVars[key].variable);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return selectedVars;
|
|||
|
|
},
|
|||
|
|
getType(paper) {
|
|||
|
|
let ret = '';
|
|||
|
|
let config = this.config;
|
|||
|
|
switch (paper.Nav_Test.TYPE) {
|
|||
|
|
case 0:
|
|||
|
|
ret = `【是非题】(${paper.SCOREVAL}分)`;
|
|||
|
|
break;
|
|||
|
|
case 1:
|
|||
|
|
ret = `【单选题】(${paper.SCOREVAL}分)`;
|
|||
|
|
break;
|
|||
|
|
case 2:
|
|||
|
|
ret = `【多选题】(${paper.SCOREVAL}分)`;
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
return ret;
|
|||
|
|
},
|
|||
|
|
doOptionChange(index, item, mask) {
|
|||
|
|
if (item.Nav_Test.TYPE === 2) {
|
|||
|
|
item.ANSWER |= mask;
|
|||
|
|
} else {
|
|||
|
|
item.ANSWER = mask;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (item.ANSWER == item.Nav_Test.ANSWER) {
|
|||
|
|
item.SCORE = item.SCOREVAL
|
|||
|
|
} else {
|
|||
|
|
item.SCORE = 0
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
checkboxChange(arr, item) {
|
|||
|
|
let indexArr = this.findCommonElementsIndices(arr, this.radiolist2[item.ID])
|
|||
|
|
item.ANSWER3 = arr;
|
|||
|
|
item.ANSWER = 0;
|
|||
|
|
indexArr.forEach(index => {
|
|||
|
|
if (index == 0) {
|
|||
|
|
item.ANSWER += 1;
|
|||
|
|
} else if (index == 1) {
|
|||
|
|
item.ANSWER += 2;
|
|||
|
|
} else if (index == 2) {
|
|||
|
|
item.ANSWER += 4;
|
|||
|
|
} else if (index == 3) {
|
|||
|
|
item.ANSWER += 8;
|
|||
|
|
} else if (index == 4) {
|
|||
|
|
item.ANSWER += 16;
|
|||
|
|
} else if (index == 5) {
|
|||
|
|
item.ANSWER += 32;
|
|||
|
|
}
|
|||
|
|
})
|
|||
|
|
if (item.ANSWER == item.Nav_Test.ANSWER) {
|
|||
|
|
item.SCORE = item.SCOREVAL
|
|||
|
|
} else {
|
|||
|
|
item.SCORE = 0
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
findCommonElementsIndices(arr1, arr2) {
|
|||
|
|
const commonElements = [];
|
|||
|
|
for (let i = 0; i < arr1.length; i++) {
|
|||
|
|
for (let j = 0; j < arr2.length; j++) {
|
|||
|
|
if (arr1[i] === arr2[j].name) {
|
|||
|
|
commonElements.push(j);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return commonElements;
|
|||
|
|
},
|
|||
|
|
onTimeUpdate(e) {
|
|||
|
|
const currentTime = e.detail.currentTime;
|
|||
|
|
if (currentTime > this.lastTime + 1) {
|
|||
|
|
uni.$showErrorInfo('禁止快进');
|
|||
|
|
const videoContext = uni.createVideoContext('myVideo', this)
|
|||
|
|
videoContext.seek(this.lastTime);
|
|||
|
|
} else {
|
|||
|
|
this.lastTime = currentTime;
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
//播放结束
|
|||
|
|
onEnd() {
|
|||
|
|
this.isVodeoEnd = true
|
|||
|
|
},
|
|||
|
|
submit() {
|
|||
|
|
if (this.tableKey != 1) {
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
let data = JSON.parse(JSON.stringify(this.papers));
|
|||
|
|
var ALLSCORE = 0
|
|||
|
|
var PASSSCORE = 0
|
|||
|
|
for (let i = 0; i < data.length; i++) {
|
|||
|
|
if (data[i].ANSWER == 0) {
|
|||
|
|
uni.$showErrorInfo(`第${i + 1}题尚未选择答题,请完成所有答题后再进行提交`)
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
if (data[i].Nav_Test.TYPE === 2 && ([0, 1, 2, 4, 8].indexOf(data[i].ANSWER) !== -1)) {
|
|||
|
|
uni.$showErrorInfo(`第${i + 1}题为多选题,请选择至少两个选项`)
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
ALLSCORE += data[i].SCORE
|
|||
|
|
if (PASSSCORE == 0) {
|
|||
|
|
PASSSCORE = data[i].Nav_Source.PASSSCORE
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//没过线继续考
|
|||
|
|
if (ALLSCORE < PASSSCORE) {
|
|||
|
|
uni.$showErrorInfo(`分数不通过,请检查后再提交(得分${ALLSCORE}通过分数为${PASSSCORE}分)!`)
|
|||
|
|
return false;
|
|||
|
|
} else {
|
|||
|
|
// 判断是静态切换 还是直接提交
|
|||
|
|
let dataS = this.res;
|
|||
|
|
let SOURCE_ID = this.SOURCE_ID;
|
|||
|
|
if (SOURCE_ID != dataS.Nav_ListUserPaper[dataS.Nav_ListUserPaper.length - 1].SOURCE_ID) {
|
|||
|
|
// 切换试题
|
|||
|
|
var filepath = ''
|
|||
|
|
var isOnline = false
|
|||
|
|
var papers = []
|
|||
|
|
var SOURCE_IDNext = ''
|
|||
|
|
var readonly = true
|
|||
|
|
dataS.Nav_ListUserPaper.forEach(ele => {
|
|||
|
|
if ((SOURCE_IDNext == '') && (ele.ANSWER == null || ele.ANSWER == 0)) {
|
|||
|
|
SOURCE_IDNext = ele.SOURCE_ID
|
|||
|
|
readonly = false
|
|||
|
|
}
|
|||
|
|
if (SOURCE_IDNext.length > 0 && ele.SOURCE_ID == SOURCE_IDNext) {
|
|||
|
|
papers.push(ele)
|
|||
|
|
isOnline = ele.IS_ONLINE
|
|||
|
|
if (isOnline == true && filepath == '') {
|
|||
|
|
filepath = ele.FILE_PATH
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
if (filepath && filepath.length > 1) {
|
|||
|
|
this.isVodeoEnd = false //继续看视频
|
|||
|
|
this.filepath = filepath
|
|||
|
|
this.filepathsWeb = config.uni_app_web_source_url + filepath
|
|||
|
|
this.filepaths = filepath
|
|||
|
|
if (this.filepaths.indexOf('vid') !== -1) {
|
|||
|
|
this.polyvy = true
|
|||
|
|
} else {
|
|||
|
|
this.polyvy = false
|
|||
|
|
}
|
|||
|
|
const regex = /vid=([^&]+)/;
|
|||
|
|
const match = this.filepaths.match(regex);
|
|||
|
|
this.vid = match ? match[1] : '';
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
this.papers = papers
|
|||
|
|
this.isOnline = isOnline
|
|||
|
|
this.readonly = readonly
|
|||
|
|
this.SOURCE_ID = SOURCE_IDNext
|
|||
|
|
|
|||
|
|
this.papers.forEach(item => {
|
|||
|
|
let test = {}
|
|||
|
|
if (item.Nav_Test.TYPE != 0) {
|
|||
|
|
this.radiolist2[item.ID] = [];
|
|||
|
|
this.radiolist2[item.ID].push({
|
|||
|
|
name: item.Nav_Test.OPTION_A
|
|||
|
|
}, {
|
|||
|
|
name: item.Nav_Test.OPTION_B
|
|||
|
|
})
|
|||
|
|
if (item.Nav_Test.OPTION_C != undefined && item.Nav_Test.OPTION_C != "") {
|
|||
|
|
this.radiolist2[item.ID].push({
|
|||
|
|
name: item.Nav_Test.OPTION_C
|
|||
|
|
})
|
|||
|
|
}
|
|||
|
|
if (item.Nav_Test.OPTION_D != undefined && item.Nav_Test.OPTION_D != "") {
|
|||
|
|
this.radiolist2[item.ID].push({
|
|||
|
|
name: item.Nav_Test.OPTION_D
|
|||
|
|
})
|
|||
|
|
}
|
|||
|
|
if (item.Nav_Test.OPTION_E != undefined && item.Nav_Test.OPTION_E != "") {
|
|||
|
|
this.radiolist2[item.ID].push({
|
|||
|
|
name: item.Nav_Test.OPTION_E
|
|||
|
|
})
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
} else {
|
|||
|
|
//提交答卷
|
|||
|
|
var modelR = this.res
|
|||
|
|
if (this.TaskID != '')
|
|||
|
|
modelR.TaskID = this.TaskID
|
|||
|
|
SavePapers(modelR).then(ret => {
|
|||
|
|
uni.$showMsgFunc('操作成功!', () => {
|
|||
|
|
uni.navigateBack()
|
|||
|
|
}, 'success', 1000)
|
|||
|
|
}).catch(err => {
|
|||
|
|
if (err.length > 0) {
|
|||
|
|
uni.$showErrorInfo(err[0].message)
|
|||
|
|
} else {
|
|||
|
|
uni.$showErrorInfo('校验失败!')
|
|||
|
|
}
|
|||
|
|
})
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
</script>
|
|||
|
|
|
|||
|
|
<style scoped>
|
|||
|
|
@import url("../../../../style/css/newTemplate.css");
|
|||
|
|
|
|||
|
|
.wrap {
|
|||
|
|
flex: 1;
|
|||
|
|
height: 100%;
|
|||
|
|
|
|||
|
|
/* 关键:width 包含 padding 和 border */
|
|||
|
|
padding-bottom: 80px;
|
|||
|
|
position: relative;
|
|||
|
|
background: #edf1fd;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.bottom-button-new {
|
|||
|
|
position: absolute;
|
|||
|
|
/* 绝对定位覆盖播放器 */
|
|||
|
|
left: 0;
|
|||
|
|
right: 0;
|
|||
|
|
bottom: 0;
|
|||
|
|
/* 靠底部显示 */
|
|||
|
|
padding: 20rpx 30rpx;
|
|||
|
|
background: linear-gradient(transparent, rgba(0, 0, 0, 0.7));
|
|||
|
|
/* 渐变背景提升可读性 */
|
|||
|
|
z-index: 10;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.scrollable-content {
|
|||
|
|
height: 300px;
|
|||
|
|
/* 根据实际需求设置高度 */
|
|||
|
|
overflow-y: auto;
|
|||
|
|
/* 垂直方向滚动 */
|
|||
|
|
overflow-x: hidden;
|
|||
|
|
/* 隐藏水平滚动条 */
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.title {
|
|||
|
|
height: 140rpx;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.player {
|
|||
|
|
height: 200px;
|
|||
|
|
position: relative;
|
|||
|
|
overflow: hidden;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.vod-player {
|
|||
|
|
flex: 1;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.controls-contain {
|
|||
|
|
position: relative;
|
|||
|
|
height: 60px;
|
|||
|
|
background-color: #000;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* 悬浮控件层 */
|
|||
|
|
.floating-controls {
|
|||
|
|
position: absolute;
|
|||
|
|
/* 绝对定位覆盖播放器 */
|
|||
|
|
left: 0;
|
|||
|
|
right: 0;
|
|||
|
|
bottom: 0;
|
|||
|
|
height: 60px;
|
|||
|
|
|
|||
|
|
z-index: 10;
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.abs-box {
|
|||
|
|
display: flex;
|
|||
|
|
flex-direction: column;
|
|||
|
|
justify-content: space-between;
|
|||
|
|
/* align-items: center; */
|
|||
|
|
flex: 1;
|
|||
|
|
/* background-color: aliceblue; */
|
|||
|
|
padding: 5px 10px;
|
|||
|
|
/* width: 100%; */
|
|||
|
|
/* background-color: aqua; */
|
|||
|
|
/* box-sizing: border-box; */
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.playing-icon {
|
|||
|
|
/* width: 50px; */
|
|||
|
|
/* margin-top: 5px; */
|
|||
|
|
margin-right: 40px;
|
|||
|
|
margin-left: 40px;
|
|||
|
|
/* height: 40px; */
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
/* 进度条容器 */
|
|||
|
|
.progress-container {
|
|||
|
|
/* width: 100%; */
|
|||
|
|
height: 30px;
|
|||
|
|
/* margin-top: 20rpx; */
|
|||
|
|
flex: 1;
|
|||
|
|
display: flex;
|
|||
|
|
flex-direction: row;
|
|||
|
|
align-items: center;
|
|||
|
|
justify-content: space-between;
|
|||
|
|
/* box-sizing: border-box; */
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* 时间文本 */
|
|||
|
|
.time-text {
|
|||
|
|
color: #fff;
|
|||
|
|
font-size: 24px;
|
|||
|
|
/* margin-bottom: 10rpx; */
|
|||
|
|
display: flex;
|
|||
|
|
margin: 0px 5px;
|
|||
|
|
justify-content: space-between;
|
|||
|
|
/* margin-left: 10px; */
|
|||
|
|
/* width: 80px; */
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* 进度条背景 */
|
|||
|
|
.progress-bar {
|
|||
|
|
/* height: 20px; */
|
|||
|
|
/* width: 100%; */
|
|||
|
|
flex: 1;
|
|||
|
|
/* background: rgba(255, 255, 255, 0.3); */
|
|||
|
|
border-radius: 4rpx;
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.progress-content {
|
|||
|
|
display: flex;
|
|||
|
|
/* width: 100%; */
|
|||
|
|
height: 100%;
|
|||
|
|
flex: 1;
|
|||
|
|
background-color: aqua;
|
|||
|
|
position: relative;
|
|||
|
|
/* cursor: pointer; */
|
|||
|
|
overflow: hidden;
|
|||
|
|
}
|
|||
|
|
</style>
|