|
|
@@ -5,24 +5,164 @@
|
|
|
<p class="top-1-p">开始学习</p>
|
|
|
<p class="top-2-p" @click="backPage()">返回</p>
|
|
|
</div>
|
|
|
- <div class="content-box scrollbar-box">
|
|
|
-
|
|
|
+ <div class="content-box">
|
|
|
+ <div class="left-max-big-box">
|
|
|
+ <coursewareComponent ref="coursewareComponent"></coursewareComponent>
|
|
|
+ </div>
|
|
|
+ <div class="right-max-big-box">
|
|
|
+ <p class="title-p">{{learningData.data1}}</p>
|
|
|
+ <div class="text-p" style="color:#666;">{{learningData.data2}}分钟丨{{learningData.data3}}学时丨{{learningData.data4}}积分</div>
|
|
|
+ <div class="text-p">已学 {{learningData.data5}} / 总 {{learningData.data6}} 课件</div>
|
|
|
+ <div class="progress-box">
|
|
|
+ <p class="progress-title-box">学习进度</p>
|
|
|
+ <div class="progress-min-box">
|
|
|
+ <el-progress :stroke-width="12" :percentage="learningData.data7"></el-progress>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="learning-for-max-big-box scrollbar-box">
|
|
|
+ <div class="for-max-big-box"
|
|
|
+ v-for="(item,index) in learningData.dataList" :key="index">
|
|
|
+ <div class="for-big-box" @click="checkLearningButton(index)"
|
|
|
+ :class="checkLearningIndex == index ?'check-for-box':''">
|
|
|
+ <p>{{item.listData1}}</p>
|
|
|
+ <p>已学习:{{formatTime(item.listData3)}} / {{formatTime(item.listData4)}}</p>
|
|
|
+ <p :class="item.listData5 ==1 ?'colorA':''">{{item.listData5==1?'已学完':'未学完'}}</p>
|
|
|
+ </div>
|
|
|
+ <p class="for-button" @click="finishStudying(index)"
|
|
|
+ v-if="item.listData5 == 0 && item.listData3 == item.listData4 && checkLearningIndex == index">
|
|
|
+ 若已完成学习,请点此确认
|
|
|
+ </p>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
+ <el-dialog
|
|
|
+ title="请完成安全验证"
|
|
|
+ :visible.sync="dialogVisible"
|
|
|
+ width="340px"
|
|
|
+ :close-on-click-modal="false"
|
|
|
+ :show-close="false"
|
|
|
+ append-to-body
|
|
|
+ center>
|
|
|
+ <div class="verify-container">
|
|
|
+ <VerifySlider
|
|
|
+ v-if="dialogVisible"
|
|
|
+ tips="请按住滑块,拖动到最后边"
|
|
|
+ success-tips="验证通过"
|
|
|
+ @success="onVerifySuccess" />
|
|
|
+ </div>
|
|
|
+ </el-dialog>
|
|
|
</div>
|
|
|
</template>
|
|
|
<script>
|
|
|
+ import StudyTimer from '@/utils/timerUtils/StudyTimer';
|
|
|
+ import CountdownTimer from '@/utils/timerUtils/CountdownTimer';
|
|
|
+ import { VerifySlider } from 'vue-verify-slider';
|
|
|
+ import coursewareComponent from "@/views/safetyEducationExaminationNew/components/coursewareComponent.vue";
|
|
|
export default {
|
|
|
name: 'index',
|
|
|
+ components: {
|
|
|
+ VerifySlider,
|
|
|
+ coursewareComponent,
|
|
|
+ },
|
|
|
data() {
|
|
|
return {
|
|
|
-
|
|
|
+ learningData:{
|
|
|
+ data1:"课程名称",
|
|
|
+ data2:"20",
|
|
|
+ data3:"1",
|
|
|
+ data4:"3",
|
|
|
+ data5:"0",
|
|
|
+ data6:"2",
|
|
|
+ data7:20,
|
|
|
+ dataList:[
|
|
|
+ {
|
|
|
+ listData1:'视频课件名称',
|
|
|
+ listData2:1,
|
|
|
+ listData3:590,
|
|
|
+ listData4:600,
|
|
|
+ listData5:0,
|
|
|
+ listData6:'http://192.168.1.8/statics/bigFile/20260801/0731dbcb-622b-4468-ade2-e20820b122eb.mp4',
|
|
|
+ listData7:'mp4',
|
|
|
+ materialType:'1',
|
|
|
+ articleContent:'',
|
|
|
+ },
|
|
|
+ {
|
|
|
+ listData1:'docx课件名称',
|
|
|
+ listData2:1,
|
|
|
+ listData3:600,
|
|
|
+ listData4:600,
|
|
|
+ listData5:0,
|
|
|
+ listData6:'http://192.168.1.8/statics/2026/08/01/b68f1b1d-99ea-44e0-94b5-4bad4ac3ff1f.docx',
|
|
|
+ listData7:'.docx',
|
|
|
+ materialType:'3',
|
|
|
+ articleContent:'',
|
|
|
+ },
|
|
|
+ {
|
|
|
+ listData1:'xlsx课件名称',
|
|
|
+ listData2:1,
|
|
|
+ listData3:600,
|
|
|
+ listData4:600,
|
|
|
+ listData5:1,
|
|
|
+ listData6:'http://192.168.1.8/statics/2026/08/01/270eb79e-627b-4fdf-9f1a-397bd9784d39.xlsx',
|
|
|
+ listData7:'.xlsx',
|
|
|
+ materialType:'3',
|
|
|
+ articleContent:'',
|
|
|
+ },
|
|
|
+ {
|
|
|
+ listData1:'pdf课件名称',
|
|
|
+ listData2:1,
|
|
|
+ listData3:600,
|
|
|
+ listData4:600,
|
|
|
+ listData5:1,
|
|
|
+ listData6:'http://192.168.1.8/statics/2026/08/01/b251bd69-120c-48d5-b662-c28e308cd61b.pdf',
|
|
|
+ listData7:'.pdf',
|
|
|
+ materialType:'3',
|
|
|
+ articleContent:'',
|
|
|
+ },
|
|
|
+ {
|
|
|
+ listData1:'富文本课件名称',
|
|
|
+ listData2:1,
|
|
|
+ listData3:600,
|
|
|
+ listData4:600,
|
|
|
+ listData5:1,
|
|
|
+ listData6:'',
|
|
|
+ listData7:'',
|
|
|
+ materialType:'4',
|
|
|
+ articleContent:"<p><img style=\"max-width: 100%;\" src=\"../statics/2026/08/01/e2788e82-745c-4b49-82e0-ebb6f2a30713.jpeg\" alt=\"1.jpeg\"> </p>"
|
|
|
+ },
|
|
|
+ {
|
|
|
+ listData1:'xlsx课件名称',
|
|
|
+ listData2:1,
|
|
|
+ listData3:600,
|
|
|
+ listData4:600,
|
|
|
+ listData5:1,
|
|
|
+ listData6:'http://192.168.1.8/statics/2026/08/01/270eb79e-627b-4fdf-9f1a-397bd9784d39.xlsx',
|
|
|
+ listData7:'.xlsx',
|
|
|
+ materialType:'3',
|
|
|
+ articleContent:'',
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ },
|
|
|
+ //当前选中
|
|
|
+ checkLearningIndex:0,
|
|
|
+ //学习计时器
|
|
|
+ studyTimer: null,
|
|
|
+ //验证计时器
|
|
|
+ countdownTimer:null,
|
|
|
+ //验证器弹窗状态
|
|
|
+ dialogVisible:false,
|
|
|
+ //验证器弹窗间隔时间
|
|
|
+ verificationTime:120,
|
|
|
+ //心跳回报时间
|
|
|
+ heartbeatValue:30,
|
|
|
}
|
|
|
},
|
|
|
created() {
|
|
|
|
|
|
},
|
|
|
mounted() {
|
|
|
-
|
|
|
+ this.initialization();
|
|
|
},
|
|
|
methods: {
|
|
|
/*
|
|
|
@@ -35,11 +175,194 @@
|
|
|
})
|
|
|
this.$route.params.title
|
|
|
*/
|
|
|
+ //初始化
|
|
|
+ initialization(){
|
|
|
+
|
|
|
+ this.initTimer();
|
|
|
+ this.startCountdown();
|
|
|
+ this.courseRendering(0);
|
|
|
+ },
|
|
|
//返回
|
|
|
backPage() {
|
|
|
this.$router.back()
|
|
|
},
|
|
|
- }
|
|
|
+ //完成课件学习
|
|
|
+ finishStudying(index){
|
|
|
+ let self = this;
|
|
|
+ this.$confirm('确认完成课件学习?', "警告", {
|
|
|
+ confirmButtonText: "确认",
|
|
|
+ cancelButtonText: "取消",
|
|
|
+ type: "warning"
|
|
|
+ }).then(function() {
|
|
|
+ }).then(() => {
|
|
|
+
|
|
|
+ }).catch(() => {});
|
|
|
+ },
|
|
|
+ //切换课件
|
|
|
+ checkLearningButton(index){
|
|
|
+ let self = this;
|
|
|
+ self.handleToggle();
|
|
|
+ self.verificationHandleToggle();
|
|
|
+ if(this.checkLearningIndex != index){
|
|
|
+ this.$confirm('确认切换课件?', "警告", {
|
|
|
+ confirmButtonText: "确认",
|
|
|
+ cancelButtonText: "取消",
|
|
|
+ type: "warning"
|
|
|
+ }).then(function() {
|
|
|
+ }).then(() => {
|
|
|
+ self.$set(self,'checkLearningIndex',index);
|
|
|
+ self.initTimer();
|
|
|
+ self.verificationHandleToggle();
|
|
|
+ self.courseRendering(index);
|
|
|
+ }).catch(() => {
|
|
|
+ self.handleToggle();
|
|
|
+ self.verificationHandleToggle();
|
|
|
+ });
|
|
|
+ }
|
|
|
+ },
|
|
|
+ //课件渲染
|
|
|
+ courseRendering(index){
|
|
|
+ let name = this.learningData.dataList[index].listData1;
|
|
|
+ let url = '';
|
|
|
+ let type = '';
|
|
|
+ if(this.learningData.dataList[index].materialType == 1){
|
|
|
+ //视频
|
|
|
+ type = 'video'
|
|
|
+ url = this.learningData.dataList[index].listData6;
|
|
|
+ }else if(this.learningData.dataList[index].materialType == 3){
|
|
|
+ //文档
|
|
|
+ if(this.learningData.dataList[index].listData7 == '.docx'){
|
|
|
+ type = 'docx'
|
|
|
+ }else if(this.learningData.dataList[index].listData7 == '.xlsx'){
|
|
|
+ type = 'excel'
|
|
|
+ }else if(this.learningData.dataList[index].listData7 == '.pdf'){
|
|
|
+ type = 'pdf'
|
|
|
+ }
|
|
|
+ url = this.learningData.dataList[index].listData6;
|
|
|
+ }else if(this.learningData.dataList[index].materialType == 4){
|
|
|
+ //文章
|
|
|
+ type = 'text'
|
|
|
+ url = this.learningData.dataList[index].articleContent;
|
|
|
+ }
|
|
|
+ this.$refs['coursewareComponent'].initialize(name,url,type);
|
|
|
+ },
|
|
|
+ //时间换算
|
|
|
+ formatTime(totalSeconds) {
|
|
|
+ if (typeof totalSeconds !== 'number' || totalSeconds <= 0) {
|
|
|
+ return '0秒';
|
|
|
+ }
|
|
|
+ const minutes = Math.floor(totalSeconds / 60);
|
|
|
+ const seconds = totalSeconds % 60;
|
|
|
+ if (minutes > 0 && seconds > 0) {
|
|
|
+ return `${minutes}分${seconds}秒`;
|
|
|
+ } else if (minutes > 0 && seconds === 0) {
|
|
|
+ return `${minutes}分`;
|
|
|
+ } else {
|
|
|
+ return `${seconds}秒`;
|
|
|
+ }
|
|
|
+ },
|
|
|
+ /*=================================== 验证器 ===================================*/
|
|
|
+ onVerifySuccess() {
|
|
|
+ this.$message.success('验证成功');
|
|
|
+ this.$set(this,'dialogVisible',false);
|
|
|
+ this.handleToggle();
|
|
|
+ this.startCountdown();
|
|
|
+ //如果是视频课件 则继续播放视频
|
|
|
+ if(this.learningData.dataList[this.checkLearningIndex].materialType == 1){
|
|
|
+ this.$refs['coursewareComponent'].resumeVideo();
|
|
|
+ }
|
|
|
+ },
|
|
|
+ /*=================================== 学习定时器 ===================================*/
|
|
|
+ // 初始化定时器
|
|
|
+ initTimer() {
|
|
|
+ let self = this;
|
|
|
+ if(this.learningData.dataList[this.checkLearningIndex].listData3 == this.learningData.dataList[this.checkLearningIndex].listData4){
|
|
|
+ return
|
|
|
+ }
|
|
|
+ this.studyTimer = new StudyTimer({
|
|
|
+ initialSeconds: self.learningData.dataList[self.checkLearningIndex].listData3,
|
|
|
+ maxSeconds: self.learningData.dataList[self.checkLearningIndex].listData4,
|
|
|
+ onTick: (elapsedSeconds) => {
|
|
|
+ //每次计时
|
|
|
+ this.$set(self.learningData.dataList[self.checkLearningIndex],'listData3',elapsedSeconds);
|
|
|
+ //心跳判断
|
|
|
+ if (elapsedSeconds % this.heartbeatValue === 0) {
|
|
|
+ //调用心跳方法
|
|
|
+
|
|
|
+ }
|
|
|
+ },
|
|
|
+ onMaxTimeReached: (elapsedSeconds) => {
|
|
|
+ //达到最大值
|
|
|
+ this.$set(self.learningData.dataList[self.checkLearningIndex],'listData3',elapsedSeconds);
|
|
|
+ //调用心跳方法
|
|
|
+
|
|
|
+ }
|
|
|
+ });
|
|
|
+ this.studyTimer.resume();
|
|
|
+ },
|
|
|
+ // 切换暂停/继续
|
|
|
+ handleToggle() {
|
|
|
+ if (!this.studyTimer) return;
|
|
|
+ if (this.studyTimer.isRunning) {
|
|
|
+ this.studyTimer.pause();
|
|
|
+ } else {
|
|
|
+ this.studyTimer.resume();
|
|
|
+ }
|
|
|
+ },
|
|
|
+ // 清除定时器
|
|
|
+ clearTimer() {
|
|
|
+ if (this.studyTimer) {
|
|
|
+ this.studyTimer.clear();
|
|
|
+ this.studyTimer = null;
|
|
|
+ }
|
|
|
+ },
|
|
|
+ /*=================================== 验证定时器 ===================================*/
|
|
|
+ // 1. 启动倒计时
|
|
|
+ startCountdown() {
|
|
|
+ if(this.verificationTime == 0){
|
|
|
+ return
|
|
|
+ }
|
|
|
+ this.countdown = new CountdownTimer({
|
|
|
+ targetSeconds: this.verificationTime,
|
|
|
+ // 达到目标值时触发的回调
|
|
|
+ onTargetReached: (elapsedSeconds) => {
|
|
|
+ //倒计时结束 开启弹窗
|
|
|
+ this.handleToggle();
|
|
|
+ this.verificationHandleToggle();
|
|
|
+ this.$set(this,'dialogVisible',true);
|
|
|
+ //如果是视频课件 则暂停播放视频
|
|
|
+ if(this.learningData.dataList[this.checkLearningIndex].materialType == 1){
|
|
|
+ this.$refs['coursewareComponent'].pauseVideo();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+ if (this.countdown) {
|
|
|
+ this.countdown.start();
|
|
|
+ }
|
|
|
+ },
|
|
|
+ // 2. 暂停/继续
|
|
|
+ verificationHandleToggle() {
|
|
|
+ if (!this.countdown) return;
|
|
|
+ this.countdown.toggle();
|
|
|
+ },
|
|
|
+ // 3. 清除倒计时
|
|
|
+ clearCountdown() {
|
|
|
+ if (this.countdown) {
|
|
|
+ this.countdown.clear();
|
|
|
+ this.countdown = null;
|
|
|
+ }
|
|
|
+ },
|
|
|
+ },
|
|
|
+ beforeDestroy() {
|
|
|
+ if (this.studyTimer) {
|
|
|
+ this.studyTimer.destroy();
|
|
|
+ this.studyTimer = null;
|
|
|
+ }
|
|
|
+ if (this.countdownTimer) {
|
|
|
+ this.countdownTimer.destroy();
|
|
|
+ this.countdownTimer = null;
|
|
|
+ }
|
|
|
+ },
|
|
|
}
|
|
|
</script>
|
|
|
<style scoped lang="scss">
|
|
|
@@ -53,5 +376,122 @@
|
|
|
padding:0;
|
|
|
box-shadow: 0 0 8px 1px rgba(0, 0, 0, 0.1);
|
|
|
margin:10px;
|
|
|
+ .content-box{
|
|
|
+ flex: 1;
|
|
|
+ display: flex;
|
|
|
+ overflow: hidden;
|
|
|
+ .left-max-big-box{
|
|
|
+ flex:1;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ background-color: #dedede;
|
|
|
+ margin:20px 20px;
|
|
|
+ border-radius:10px;
|
|
|
+ overflow: hidden;
|
|
|
+ box-shadow: 0 0 15px rgba(0, 0, 0, 0.4);
|
|
|
+ border:1px solid #dedede;
|
|
|
+ }
|
|
|
+ .right-max-big-box{
|
|
|
+ padding:20px 0;
|
|
|
+ width:400px;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ overflow: hidden;
|
|
|
+ border-left: 1px solid #dedede;
|
|
|
+ .title-p{
|
|
|
+ font-size:16px;
|
|
|
+ font-weight:700;
|
|
|
+ line-height:30px;
|
|
|
+ padding:0 20px;
|
|
|
+ }
|
|
|
+ .text-p{
|
|
|
+ font-size:14px;
|
|
|
+ line-height:20px;
|
|
|
+ margin-bottom:20px;
|
|
|
+ padding:0 20px;
|
|
|
+ }
|
|
|
+ .progress-box{
|
|
|
+ width:400px;
|
|
|
+ height:20px;
|
|
|
+ display: flex;
|
|
|
+ padding:0 20px;
|
|
|
+ .progress-title-box{
|
|
|
+ font-size:14px;
|
|
|
+ line-height:20px;
|
|
|
+ font-weight:700;
|
|
|
+ }
|
|
|
+ .progress-min-box{
|
|
|
+ flex:1;
|
|
|
+ padding:0 0 0 20px;
|
|
|
+ .el-progress{
|
|
|
+ margin-top:1px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .learning-for-max-big-box{
|
|
|
+ flex:1;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ padding:0 20px;
|
|
|
+ .for-max-big-box{
|
|
|
+ margin-top:40px;
|
|
|
+ .for-big-box{
|
|
|
+ cursor: pointer;
|
|
|
+ border-radius:6px;
|
|
|
+ border:1px solid #666;
|
|
|
+ padding:15px 10px;
|
|
|
+ position: relative;
|
|
|
+ p{
|
|
|
+ line-height:30px;
|
|
|
+ }
|
|
|
+ p:nth-child(1){
|
|
|
+ font-size:16px;
|
|
|
+ font-weight:700;
|
|
|
+ /*单行省略号*/
|
|
|
+ display:block;
|
|
|
+ overflow:hidden;
|
|
|
+ text-overflow:ellipsis;
|
|
|
+ white-space:nowrap;
|
|
|
+ }
|
|
|
+ p:nth-child(2){
|
|
|
+ font-size:14px;
|
|
|
+ }
|
|
|
+ p:nth-child(3){
|
|
|
+ font-size:14px;
|
|
|
+ position: absolute;
|
|
|
+ bottom: 16px;
|
|
|
+ right: 16px;
|
|
|
+ color:#fff!important;
|
|
|
+ background-color: #999;
|
|
|
+ border-radius:4px;
|
|
|
+ width:60px;
|
|
|
+ line-height:24px;
|
|
|
+ text-align: center;
|
|
|
+ }
|
|
|
+ .colorA{
|
|
|
+ background-color: #0183fa!important;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .for-button{
|
|
|
+ margin-top:20px;
|
|
|
+ background-color: #13CE66;
|
|
|
+ color:#fff;
|
|
|
+ text-align: center;
|
|
|
+ line-height:30px;
|
|
|
+ border-radius:4px;
|
|
|
+ cursor: pointer;
|
|
|
+ font-size:14px;
|
|
|
+ }
|
|
|
+ .check-for-box{
|
|
|
+ background-color: rgba(1,131,250,0.1);
|
|
|
+ border:1px solid #0183fa!important;
|
|
|
+ p{
|
|
|
+ color:#0183fa!important;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
</style>
|