ZhiYeJianKang_PeiXun/Song.Site/Templates/Web/_Public/Scripts/CourseStudy.js
2025-02-20 15:41:53 +08:00

562 lines
24 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

var couid = $api.querystring("couid");
var vdata = new Vue({
data: {
//数据实体
account: {}, //当前账号信息
course: {}, //当前课程
outline: {}, //当前课程章节
subject: {}, //当前专业
outlines: [], //当前课程的章节列表(树形)
access: [], //附件列表
events: [], //视频事件
messages: [], //咨询留言
//当前章节的视频信息
video: {
url: '', //视频路径
total: 0, //总时长
playTime: 0, //当前播放时间,单位:毫秒
playhistime: 0, //历史播放时间
studytime: 0, //累计学习时间
percent: 0 //完成度(百分比)
},
playtime: 0, //当前播放时间,单位:秒
playpercent: 0, //当前播放完成度百分比
//状态
state: {}, //课程状态
couid: $api.querystring("couid"),
olid: $api.querystring("olid"),
median: false, //分隔线折叠状态
titState: 'loading', //左侧选项卡的状态
rightState: 'outline', //右侧选项卡状态章节outline,交流chat
outlineLoaded: false, //右侧章节列表加载中
studylogUpdate: false, //学习记录是否在递交中
studylogState: 0, //学习记录提交状态1为成功-1为失败
switchSubtitle: $api.cookie("switchSubtitle_" + $api.querystring("couid")) == "true" ? true : false, //弹幕开关
//控件
player: null //播放器
},
watch: {
//课程状态
state: function (val) {
if (vdata.state.isNull) vdata.titState = 'isNull';
if (vdata.state.isAccess) vdata.titState = 'isAccess';
if (vdata.state.isQues) vdata.titState = 'isQues';
if (vdata.state.isContext) vdata.titState = 'isContext';
if (vdata.state.isLive) vdata.titState = 'isLive';
if (vdata.state.existVideo) vdata.titState = 'existVideo';
//if (!vdata.state.canStudy) vdata.titState = 'isNull';
if (vdata.state.DeskAllow) return;
//视频播放
if (vdata.state.canStudy && (vdata.state.existVideo || vdata.state.isLive))
vdata.videoPlay(vdata.state);
},
//左侧选项卡切换
titState: function (val) {
if (vdata.playready()) {
vdata.titState == 'existVideo' ? vdata.player.play() : vdata.player.pause();
}
},
//弹幕开关
'switchSubtitle': function (val, old) {
if (val != old)
$api.cookie("switchSubtitle_" + vdata.couid, val);
},
//播放进度时间变化
playtime: function (val) {
vdata.video.studytime++;
//当前视频播放进度百分比
var per = Math.floor(vdata.video.studytime <= 0 ? 0 : vdata.video.studytime / vdata.video.total * 100);
vdata.playpercent = per;
//触发视频事件
vdata.videoEvent(vdata.playtime);
},
//播放进度百分比变化,
playpercent: function (val, oldval) {
//console.log('当前播放进度百分比:'+val);
//学习记录提交
if (val <= 100) vdata.videoLog(val);
}
},
methods: {
//知识库的点击事件
knlClick: function () {
new top.PageBox('课程知识库', 'Knowledges.ashx?couid=' + vdata.couid, 100, 100, null, window.name).Open();
},
//章节列表的点击事件
outlineClick: function (olid, event) {
var url = $api.setpara("olid", olid);
history.pushState({}, null, url);
vdata.olid = olid;
vdata.titState = 'loading';
if (event != null) event.preventDefault();
//获取当前章节状态,和专业信息
$api.bat(
$api.get("Outline/ForID", {
id: olid
}),
$api.get("Outline/state", {
olid: olid
})
).then(axios.spread(function (ol, state) {
if (ol.data.success && state.data.success) {
vdata.outline = ol.data.result;
vdata.state = state.data.result;
if (!vdata.state.isLive && vdata.state.PlayTime / 1000 > 0) {
/*
vdata.$confirm('是否从上次进度播放?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(function() {
vdata.videoSeek(vdata.state.PlayTime / 1000);
window.setTimeout(function() {
if (vdata.playready()) vdata.player.play();
}, 500);
}).catch(function() {
});*/
}
//视频播放记录
var result = state.data.result;
vdata.video.studytime = isNaN(result.StudyTime) ? 0 : result.StudyTime;
vdata.video.playhistime = isNaN(result.PlayTime) ? 0 : result.PlayTime / 1000;
window.setTimeout(function () {
vdata.outlineLoaded = true;
}, 100);
//获取视频事件
if (state.data.result.existVideo && vdata.outline) {
$api.get("Outline/VideoEvents", {
olid: vdata.outline.Ol_ID
}).then(function (req) {
if (req.data.success) {
vdata.events = req.data.result;
} else {
alert("视频事件加载失败!详情:\r" + req.data.message);
}
});
}
} else {
if (!ol.data.success) alert("章节信息加载异常!详情:\r" + ol.data.message);
if (!state.data.success) alert("章节状态加载异常!详情:\r" + state.data.message);
}
}));
//获取留言列表
vdata.msgGet();
},
//播放器是否准备好
playready: function () {
if (vdata.player != null) {
return vdata.player._isReady && vdata.player.engine;
}
return false;
},
//视频开始播放
videoPlay: function (state) {
if (vdata.player != null) {
vdata.player.destroy();
vdata.player = null;
}
if (!vdata.state.isLive) { //点播
vdata.player = new QPlayer({
url: state.urlVideo,
container: document.getElementById("videoplayer"),
autoplay: true,
});
} else { //直播
vdata.player = new QPlayer({
url: state.urlVideo,
container: document.getElementById("livebox"),
isLive: true,
autoplay: true
});
}
if (vdata.player != null) {
vdata.player.on("loading", vdata.videoready);
vdata.player.on("ready", vdata.videoready);
vdata.player.on("timeupdate", function (currentTime, totalTime) {
vdata.video.total = parseInt(totalTime);
vdata.video.playTime = currentTime; //详细时间,精确到毫秒
vdata.playtime = parseInt(currentTime);
//学习完成度,最大为百分百
vdata.video.percent = Math.floor(vdata.video.studytime <= 0 ? 0 : vdata.video.studytime / vdata.video.total * 1000) / 10;
vdata.video.percent = vdata.video.percent > 100 ? 100 : vdata.video.percent;
});
vdata.player.on("seeked", function () {
vdata.playtime = vdata.playready() ? vdata.player.currentTime : 0;
window.setTimeout(function () {
if (vdata.playready()) vdata.player.pause();
}, 50);
});
vdata.player.on("play", function (e) {
if (window.videoFixed) vdata.player.pause();
});
}
},
//播放器加载后的事件
videoready: function () {
//隐藏全屏按钮
var fullbtn = document.getElementsByClassName("qplayer-fullscreen");
for (var i = 0; i < fullbtn.length; i++) {
fullbtn[i].style.display = "none";
}
//隐藏设置按钮(播放倍速也禁用了)
var setbtn = document.getElementsByClassName("qplayer-settings-btn");
for (var i = 0; i < setbtn.length; i++) {
//setbtn[i].style.display = "none";
}
//给video对象增加属性
var video = document.querySelector("video");
video.setAttribute("x5-playsinline", "");
video.setAttribute("playsinline", true);
video.setAttribute("webkit-playsinline", true);
video.setAttribute("x-webkit-airplay", true);
video.setAttribute("x5-video-player-type", "h5");
video.setAttribute("x5-video-player-fullscreen", "");
video.setAttribute("x5-video-orientation", "portraint");
},
//视频播放跳转
videoSeek: function (second) {
if (vdata.playready()) {
vdata.player.seek(second);
}
},
//学习记录记录
videoLog: function (per) {
if (vdata.studylogUpdate) return;
var interval = 1; //间隔百分比多少递交一次记录
if (vdata.video.total <= 5 * 60) interval = 10; //5分钟内的视频
else if (vdata.video.total <= 10 * 60) interval = 5; //10分钟的视频5%递交一次
else if (vdata.video.total <= 30 * 60) interval = 2; //30分钟的视频2%递交一次
if (per > 0 && per < (100 + interval) && per % interval == 0) {
if (!vdata.outline) return;
$api.post("Course/StudyLog", {
couid: vdata.course.Cou_ID,
olid: vdata.outline.Ol_ID,
playTime: vdata.playtime,
studyTime: vdata.video.studytime,
totalTime: vdata.video.total
}, function () {
vdata.studylogUpdate = true;
}, function () {
vdata.studylogUpdate = false;
}).then(function (req) {
if (!req.data.success) {
if (vdata.playready()) {
vdata.player.pause();
vdata.player.destroy();
vdata.player = null;
}
alert(req.data.message);
return;
}
vdata.studylogState = 1;
window.setTimeout(function () {
vdata.studylogState = 0;
}, 2000);
}).catch(function (err) {
vdata.studylogState = -1;
//alert(err);
window.setTimeout(function () {
vdata.studylogState = 0;
}, 2000);
});
}
},
//视频事件的触发
videoEvent: function (playtime) {
if (vdata.events.length < 1) return;
var curr = null;
for (var ev in vdata.events) {
if (vdata.events[ev].Oe_TriggerPoint == playtime) {
curr = vdata.events[ev];
break;
}
}
if (curr == null) return;
//视频暂停
if (vdata.playready()) vdata.player.pause();
var box = new MsgBox();
box.OverEvent = function () {
if (vdata.playready()) vdata.player.play();
}
if (curr.Oe_EventType == 1)
box.Init("提示:" + curr.Oe_Title, curr.Oe_Context, curr.Oe_Width, curr.Oe_Height, "alert").Open();
if (curr.Oe_EventType == 2)
box.Init("知识点:" + curr.Oe_Title, curr.Oe_Context, curr.Oe_Width, curr.Oe_Height, "alert").Open();
if (curr.Oe_EventType == 3) {
var items = eval(curr.Oe_Datatable);
var context = curr.Oe_Context + "<div class='quesBox'>";
for (var i in items) {
if (items[i].item == "") continue;
context += "<div onclick='vdata.videoEventClick(" + items[i].iscorrect + ",-1)'>" +
(Number(i) + 1) + "、" + items[i].item + "</div>";
}
context += "</div>";
context += "<div id='event_error'>回答错误</div>";
box.Init("提问" + curr.Oe_Title, context, curr.Oe_Width, curr.Oe_Height, "null").Open();
}
if (curr.Oe_EventType == 4) {
var items = eval(curr.Oe_Datatable);
var context = curr.Oe_Context + "<div class='quesBox'>";
for (var i in items) {
if (items[i].item == "") continue;
context += "<div onclick='vdata.videoEventClick(null," + items[i].point + ")'>" +
(Number(i) + 1) + "、" + items[i].item + " - (跳转到:" + items[i].point + "秒)</div>";
}
context += "</div>";
box.Init("反馈:" + curr.Oe_Title, context, curr.Oe_Width, curr.Oe_Height, "alert").Open();
}
},
//视频事件的点击操作
videoEventClick: function (iscorrect, seek) {
//视频事件的问题
if (iscorrect != null) {
if (iscorrect) MsgBox.Close();
if (!iscorrect) {
var err = document.getElementById("event_error");
err.style.height = 20 + 'px';
err.style.opacity = 1;
window.setTimeout(function () {
var err = document.getElementById("event_error");
err.style.height = 0 + 'px';
err.style.opacity = 0;
}, 1000);
}
}
//视频跳转
if (iscorrect == null && seek > 0) {
if (!vdata.playready()) return;
vdata.player.seek(seek);
MsgBox.Close();
}
},
//发送消息
msgSend: function () {
var msg = document.getElementById("messageinput").value;
if ($api.trim(msg) == '') return;
var span = Date.now() - Number($api.cookie("msgtime"));
if (span / 1000 < 10) {
vdata.$notify({
message: '不要频繁发消息!',
position: 'bottom-right'
});
return;
}
$api.cookie("msgtime", Date.now());
$api.post("message/add", {
acc: '',
msg: msg,
playtime: vdata.playtime,
couid: vdata.couid,
olid: vdata.olid
}).then(function (req) {
var d = req.data;
if (d.success) {
document.getElementById("messageinput").value = '';
vdata.msgGet();
} else {
alert("信息添加发生异常!详情:\r" + d.message);
}
});
},
//获取当前章节的留言信息
msgGet: function () {
if (!vdata.olid || vdata.olid < 1) return;
$api.post("message/count", {
olid: vdata.olid,
order: 'asc',
count: 100
}).then(function (req) {
var d = req.data;
if (d.success) {
vdata.messages = d.result;
window.setTimeout(function () {
var dl = document.getElementById("chatlistdl");
document.getElementById("chatlist").scrollTop = dl.offsetHeight;
}, 1000);
} else {
alert("留言信息加载异常!详情:\r" + d.message);
}
}).catch(function (err) {
//alert("msgGet方法存在错误"+err);
});
},
init: function () {
}
},
created: function () {
var couid = $api.querystring("couid");
$api.bat(
$api.get("Outline/tree", {
couid: couid
}),
$api.get("Course/ForID", {
id: couid
})).then(axios.spread(function (ol, cur) {
if (ol.data.success && cur.data.success) {
if (ol.data.result.length < 1) throw "没有课程章节";
vdata.outlines = ol.data.result;
if (vdata.olid == '') vdata.olid = ol.data.result[0].Ol_ID;
vdata.outlineClick(vdata.olid, null);
vdata.course = cur.data.result;
document.title = vdata.course.Cou_Name;
$api.get("Subject/ForID", {
id: vdata.course.Sbj_ID
}).then(function (subject) {
if (subject.data.success) {
vdata.subject = subject.data.result;
} else {
if (!subject.data.success) throw "课程所属专业加载异常!详情:\r" + subject.data.message;
}
}).catch(function (err) {
alert(err);
});
vdata.msgGet();
} else {
if (!ol.data.success) throw "章节列表加载异常!详情:\r" + ol.data.message;
if (!cur.data.success) throw "课程信息加载异常!详情:\r" + cur.data.message;
}
})).catch(function (err) {
alert(err);
});
//当前登录学员
$api.get("Account/Current", {}, null, null).then(function (req) {
if (req.data.success) {
vdata.account = req.data.result;
}
});
//定时刷新(加载)咨询留言
window.setInterval('vdata.msgGet()', 1000 * 10);
},
mounted: function () {
//视频上面的漂浮信息(学员姓名和电话),防录屏
window.setInterval(function () {
var acc = document.getElementById("accinfo");
if (acc == null) return;
if (acc.parentNode.offsetHeight == 0 || acc.parentNode.offsetWidth == 0) return;
//移动速度
window.acctop = window.acctop ? window.acctop : Math.ceil(Math.random() * 100) / 10;
window.accleft = window.accleft ? window.accleft : Math.ceil(Math.random() * 100) / 10;
//获取当前坐标
var top = Number(acc.style.top.replace('px', ''));
var left = Number(acc.style.left.replace('px', ''));
//转向
if (top < 0 || top > acc.parentNode.offsetHeight - acc.offsetHeight) window.acctop = -window.acctop;
if (left < 0 || left > acc.parentNode.offsetWidth - acc.offsetWidth) window.accleft = -window.accleft;
//移动
acc.style.top = (top < 0 ? 0 : (top > acc.parentNode.offsetHeight - acc.offsetHeight ? acc.parentNode.offsetHeight - acc.offsetHeight : top + window.acctop)) + "px";
acc.style.left = (left < 0 ? 0 : (left > acc.parentNode.offsetWidth - acc.offsetWidth ? acc.parentNode.offsetWidth - acc.offsetWidth : left + window.accleft)) + "px";
}, 200);
},
});
vdata.$mount('#body');
window.onload = function () {
this.vdata.init();
}
window.onblur = function () {
if (vdata.playready()) {
//if (vdata.state.isLive || vdata.state.existVideo)
if (!vdata.state.SwitchPlay)
vdata.player.pause();
}
}
window.onfocus = function () {
//如果有视频事件弹出,则窗体获取焦点时,视频并不播放
if ($("div[type=MsgBox]").size() > 0) return;
if (vdata.playready()) {
//vdata.titState == 'existVideo' && vdata.state.isLive ? vdata.player.play() : vdata.player.pause();
//只有当处于视频状态时才播放
if (vdata.titState == 'existVideo' || vdata.titState == 'isLive')
vdata.player.play();
}
}
window.onresize = function () {
window.setTimeout(function () {
var str = '';
[22, 9, 4, 5, 15].forEach(x => str += String.fromCharCode(0x60 + x));
var v = document.querySelector(str);
if (!v) return;
var styles = document.defaultView.getComputedStyle(v.parentNode, null);
var posi = styles.getPropertyValue('position');
window.videoFixed = posi == 'fixed';
v.style.display = window.videoFixed ? 'none' : '';
!window.videoFixed && $("div[type=MsgBox]").size() < 1 ? v.play() : v.pause();
}, 100);
}
//全局过滤器,日期格式化
Vue.filter('date', function (value, fmt) {
if ($api.getType(value) != 'Date') return value;
var o = {
"M+": value.getMonth() + 1,
"d+": value.getDate(),
"h+": value.getHours(),
"m+": value.getMinutes(),
"s+": value.getSeconds()
};
if (/(y+)/.test(fmt))
fmt = fmt.replace(RegExp.$1, (value.getFullYear() + "").substr(4 - RegExp.$1.length));
for (var k in o)
if (new RegExp("(" + k + ")").test(fmt))
fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
return fmt;
});
//******* 附件列表
Vue.component('accessory', {
props: ['uid', 'isbuy'],
data: function () {
return {
datas: [], //附件列表
msg: '' //提示信息
}
},
watch: {
'uid': function (val, old) {
var th = this;
th.msg = '';
$api.get("Outline/Accessory", { uid: val }).then(function (acc) {
if (acc.data.success) {
th.datas = acc.data.result;
} else {
th.msg = "附件信息加载异常!详情:\r" + acc.data.message;
}
}).catch(function (err) {
th.msg = err;
});
},
'isbuy': function (val, old) {
}
},
methods: {
//附件的点击事件
accessClick: function (file, tit, event) {
var exist = file.substring(file.lastIndexOf(".") + 1).toLowerCase();
if (exist == "pdf") {
event.preventDefault();
var box = new PageBox(tit, $api.pdfViewer(file), 100, 100, null, window.name);
box.Open();
}
return false;
}
},
template: '<div id="accessory">\
<div v-if="!isbuy" style="color:red;">课程未购买,资料不提供下载或预览</div>\
<a v-if="isbuy" v-for="(item,index) in datas" target="_blank":href="item.As_FileName"\
v-on:click="accessClick(item.As_FileName,item.As_Name,$event)"\
:download="item.As_Name">{{index+1}}、{{item.As_Name}}\
</a>\
<div v-if="!isbuy" v-for="(item,index) in datas" >\
{{index+1}}、{{item.As_Name}}\
</div>\
<div class="noInfo">{{msg}}</div>\
</div>'
});