提交 eeb75178 authored 作者: zyx's avatar zyx

update

上级 c2eb9cc1
...@@ -6771,6 +6771,24 @@ ...@@ -6771,6 +6771,24 @@
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
"integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==" "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A=="
}, },
"lodash.assign": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-4.2.0.tgz",
"integrity": "sha1-DZnzzNem0mHRm9rrkkUAXShYCOc=",
"dev": true
},
"lodash.clonedeep": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz",
"integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=",
"dev": true
},
"lodash.mergewith": {
"version": "4.6.2",
"resolved": "https://registry.npmjs.org/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz",
"integrity": "sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ==",
"dev": true
},
"loglevel": { "loglevel": {
"version": "1.6.7", "version": "1.6.7",
"resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.6.7.tgz", "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.6.7.tgz",
...@@ -7422,9 +7440,9 @@ ...@@ -7422,9 +7440,9 @@
"dev": true "dev": true
}, },
"node-sass": { "node-sass": {
"version": "4.13.1", "version": "4.5.3",
"resolved": "https://registry.npmjs.org/node-sass/-/node-sass-4.13.1.tgz", "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-4.5.3.tgz",
"integrity": "sha512-TTWFx+ZhyDx1Biiez2nB0L3YrCZ/8oHagaDalbuBSlqXgUPsdkUSzJsVxeDO9LtPB49+Fh3WQl3slABo6AotNw==", "integrity": "sha1-0JydEXlkEjnRuX/8YjH9zsU+FWg=",
"dev": true, "dev": true,
"requires": { "requires": {
"async-foreach": "0.1.3", "async-foreach": "0.1.3",
...@@ -7434,7 +7452,9 @@ ...@@ -7434,7 +7452,9 @@
"get-stdin": "4.0.1", "get-stdin": "4.0.1",
"glob": "7.1.6", "glob": "7.1.6",
"in-publish": "2.0.1", "in-publish": "2.0.1",
"lodash": "4.17.15", "lodash.assign": "4.2.0",
"lodash.clonedeep": "4.5.0",
"lodash.mergewith": "4.6.2",
"meow": "3.7.0", "meow": "3.7.0",
"mkdirp": "0.5.5", "mkdirp": "0.5.5",
"nan": "2.14.0", "nan": "2.14.0",
...@@ -7442,8 +7462,7 @@ ...@@ -7442,8 +7462,7 @@
"npmlog": "4.1.2", "npmlog": "4.1.2",
"request": "2.88.2", "request": "2.88.2",
"sass-graph": "2.2.4", "sass-graph": "2.2.4",
"stdout-stream": "1.4.1", "stdout-stream": "1.4.1"
"true-case-path": "1.0.3"
}, },
"dependencies": { "dependencies": {
"ansi-styles": { "ansi-styles": {
...@@ -10413,15 +10432,6 @@ ...@@ -10413,15 +10432,6 @@
"integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=", "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=",
"dev": true "dev": true
}, },
"true-case-path": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/true-case-path/-/true-case-path-1.0.3.tgz",
"integrity": "sha512-m6s2OdQe5wgpFMC+pAJ+q9djG82O2jcHPOI6RNg1yy9rCYR+WD6Nbpl32fDpfC56nirdRy+opFa/Vk7HYhqaew==",
"dev": true,
"requires": {
"glob": "7.1.6"
}
},
"tslib": { "tslib": {
"version": "1.11.1", "version": "1.11.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.11.1.tgz", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.11.1.tgz",
......
...@@ -52,7 +52,7 @@ ...@@ -52,7 +52,7 @@
"file-loader": "^6.0.0", "file-loader": "^6.0.0",
"html-webpack-plugin": "^4.0.4", "html-webpack-plugin": "^4.0.4",
"mini-css-extract-plugin": "^0.9.0", "mini-css-extract-plugin": "^0.9.0",
"node-sass": "^4.13.1", "node-sass": "^4.5.3",
"postcss-loader": "^3.0.0", "postcss-loader": "^3.0.0",
"sass-loader": "^7.3.1", "sass-loader": "^7.3.1",
"style-loader": "^1.1.3", "style-loader": "^1.1.3",
......
...@@ -4,8 +4,8 @@ import { Other } from '@api' ...@@ -4,8 +4,8 @@ import { Other } from '@api'
export default class OtherAction extends BaseACTION { export default class OtherAction extends BaseACTION {
/* 获取我的消息信息 */ /* 获取我的消息信息 */
getMyMsg () { getMyMsg () {
return msgApi.getMyMsg().then(res => { return Other.getMyMsg().then(res => {
let json = res.map(function (_, i) { const json = res.map(function (_, i) {
return { return {
isRead: false, isRead: false,
id: _.id, id: _.id,
...@@ -17,8 +17,9 @@ export default class OtherAction extends BaseACTION { ...@@ -17,8 +17,9 @@ export default class OtherAction extends BaseACTION {
return json return json
}) })
} }
/** /**
* 文件上传 * 文件上传
*/ */
uploadFile (obj) { return chapterApi.uploadFile(obj).then(res => res) } uploadFile (obj) { return Other.uploadFile(obj).then(res => res) }
} }
差异被折叠。
import OtherAction from './OtherAction'
import CourseAction from './CourseAction' import CourseAction from './CourseAction'
import GradeAction from './GradeAction' import GradeAction from './GradeAction'
import ReportAction from './ReportAction' import ReportAction from './ReportAction'
import PlayerAction from './PlayerAction'
const Other = new OtherAction()
const Course = new CourseAction() const Course = new CourseAction()
const Grade = new GradeAction() const Grade = new GradeAction()
const Report = new ReportAction() const Report = new ReportAction()
const Player = new PlayerAction()
const cAction = { const cAction = {
Other,
Course, Course,
Grade, Grade,
Report Report,
Player
} }
export default cAction export default cAction
...@@ -2,15 +2,18 @@ import OtherAPI from './other_api' ...@@ -2,15 +2,18 @@ import OtherAPI from './other_api'
import CourseAPI from './course_api' import CourseAPI from './course_api'
import GradeAPI from './grade_api' import GradeAPI from './grade_api'
import ReportAPI from './report_api' import ReportAPI from './report_api'
import PlayerAPI from './player_api'
const Other = new OtherAPI(webConf) const Other = new OtherAPI(webConf)
const Course = new CourseAPI(webConf) const Course = new CourseAPI(webConf)
const Grade = new GradeAPI(webConf) const Grade = new GradeAPI(webConf)
const Report = new ReportAPI(webConf) const Report = new ReportAPI(webConf)
const Player = new PlayerAPI(webConf)
export { export {
Other, Other,
Course, Course,
Grade, Grade,
Report Report,
Player
} }
import BaseAPI from './base_api'
export default class PlayerAPI extends BaseAPI {
/**
* 获取章节列表信息
* @param {[string]} cur_course_id -> cid
* @param {[string]} cur_semester_id -> sid
* @param {[string]} cur_video_id -> vid
*/
getChapterList = (cid, sid, vid) => this.get(`/v2/education/courses/${sid}/${cid}`, {})
/**
* 获取对应某个章节的详细信息
* @param {[string]} vid
*/
getCurrentChapterDetail = (vid) => this.post('/v2/education/video-streaming', { vid })
/**
* 获取对应某个章节的详细信息
* @param {[string]} vid
*/
getCurrentChapterDetailAliyun = (vid) => this.post('/v2/education/aliyun-video-streaming', { vid })
/**
* 获取进度信息
* @param {[string]} vid
* @param {[string]} did
* @param {[string]} sid
*/
getProgress = (vid, did, sid) => this.get(`/v2/education/video/${sid}/${vid}/device`, { device_id: did })
/**
* 提交进度信息
* @param {[object]} obj
* d: obj.did,
i: obj.did,
c: obj.cid,
s: obj.sid,
v: obj.vid,
_p: obj.pt, // 累计时间
_m: obj.mpt, // 当前播放最大时间
_c: obj.cpt // 当前播放位置
*/
updateProgress = (obj = {}) => this.get('/v2/analytics/upload-video', obj)
/**
* 获取试题信息
* @param {[string]} eid
* @param {[string]} cid
* @param {[string]} sid
*/
getExamDetail = (sid, cid, eid) => this.get(`/v2/education/homeworks/${sid}/${cid}/${eid}`, {})
/**
* 提交考试信息
* @param {[object]} param
*/
submitExamDetail = (param) => this.post('/v2/education/homeworks', param)
/**
* 获取对应 作业或问题 回答
* @param {[string]} sid
* @param {[string]} cid
* @param {[string]} id resource_id
*/
getHomework = (sid, cid, id) => this.get(`/v2/education/homeworks/${sid}/${cid}/${id}`, {})
/**
* 文件提交
* @param {[object]} obj
*/
uploadFile = (obj = {}) => this.post('/util/upload-file', obj, { headers: { 'Content-Type': 'multipart/form-data' } })
/**
* 提交课程 作业或问题
*/
updateHomework = (obj = {}) => this.post('/v2/education/homeworks', obj, { headers: { 'Content-Type': 'multipart/form-data' } })
/**
* 课程作业截止时间
*/
getHomeworkStopTime = (sid, cid, chapterId) => this.get(`/v2/education/homeworks/${sid}/${cid}/${chapterId}/deadline`, {})
/**
* 获取对应 大作业 回答
* @param {[string]} sid
* @param {[string]} cid
*/
getCourseHomework = (sid, cid) => this.get(`/v2/education/courses/${sid}/${cid}/essay`, {})
/**
* 提交课程 大作业
* @param {[string]} sid
* @param {[string]} cid
*/
updateCourseHomework = (sid, cid, obj = {}) => this.post(`/v2/education/courses/${sid}/${cid}/essay`, obj, { headers: { 'Content-Type': 'multipart/form-data' } })
/**
* 提交 课程考核
* @param {[string]} obj.sid
* @param {[string]} obj.cid
* @param {[string]} obj.raw (base64)
*/
updateSurveyAnswer = (obj) => this.post('/v2/education/survey/answer', obj)
/**
* 手机端 获取实时最新直播接口
*/
getNewLiveMsg = (obj = {}) => this.get('/v2/education/lives/latest', obj)
/**
* 手机端 获取列表接口
*/
getLiveList = (obj = {}) => this.get('/v2/education/lives/courses', obj)
}
<template>
<div class="play-paper">
<div class="play-paper-body">
<div class="play-paper-title"><div><h3>{{chapterName}}</h3></div></div>
<div class="play-paper-content">
<ul class="play-read-files">
<li><a :href="chapterRead.reading_attachment" target="_blank">{{chapterRead.reading_content}}</a></li>
</ul>
</div>
</div>
</div>
</template>
<script>
export default {
props: {
chapterRead: { type: Object, require: false },
chapterName: { type: String, require: false }
}
}
</script>
<template>
<div class="play-ppt" ref="wrap">
<template v-if="ppts.length">
<div class="play-preview" ref="preview">
<template v-if="ppts[state.index] && ppts[state.index].ppt_url">
<img :src="ppts[state.index].ppt_url" class="play-ppt-img" style='vertical-align: middle' />
</template>
</div>
<div class="play-controls cl">
<div style="float: left;">
<template v-if="state.index >= 0">
<a href="#" @click="prev" style='margin: 0 20px 0 0; color: #fff;'><i class="el-icon-arrow-left"></i></a>
</template>
<template v-if="state.index + 1 < ppts.length">
<a href="#" @click="next"><i class="el-icon-arrow-right" style="color: #fff;"></i></a>
</template>
</div>
<div class="play-page">
<span class="play-now">{{state.index + 1}}</span>
/
<span class="play-total">{{ppts.length}}</span>
</div>
<div class="play-amazing">
<i :class="['el-icon-self-xuexiao', (state.sync ? 'active' : '')]" @click="onToggleSync"></i>
<i class="el-icon-self-quanping" @click="() => { this.$emit('onPptOnly') }"></i>
<i class="el-icon-self-shipin" @click="onSetVideoTime"></i>
<i class="el-icon-self-guanbi" @click="() => { this.$emit('onClose') }"></i>
</div>
</div>
</template>
</div>
</template>
<script>
/**
* ppt播放框
* 如果同步显示,则同步props.currentIndex到state.index,否则,仅使用state.index
*/
export default {
props: {
ppts: { type: Array, require: false },
currentIndex: { type: Number, require: false, default: 0 }
},
data () {
return {
state: {
index: this.currentIndex, // ppt展示序号
sync: true // 视频播放时,同步调整ppt展示
}
}
},
watch: {
currentIndex: {
handler () {
if (this.state.sync) {
this.state.index = this.currentIndex
}
}
}
},
methods: {
gotoIndex (index) {
this.state.index = index
},
getIndex (index) {
return Math.min(this.ppts.length - 1, Math.max(0, index))
},
prev (e) {
this.state.index = this.getIndex(this.state.index - 1)
this.state.sync = false
},
next (e) {
this.state.index = this.getIndex(this.state.index + 1)
this.state.sync = false
},
onToggleSync (e) {
this.state.sync = !this.state.sync
this.state.index = this.state.sync ? this.currentIndex : this.state.index
},
onSetVideoTime (e) {
this.$emit('onVideoSyncTime', this.ppts[this.state.index].ppt_point)
},
setSize (w, h) {
this.$refs.wrap.style.width = w + 'px'
this.$refs.wrap.style.height = h + 'px'
this.$refs.preview.style.lineHeight = (h - 44) + 'px'
}
}
}
</script>
<template>
<div id="playerWrap">
<div id="player">
<p>您还没有安装flash播放器,请 <a href="http://www.adobe.com/go/getflash" target="_blank">点击这里安装</a></p>
</div>
</div>
</template>
<style lang="scss" scoped>
#player p { color: #fff; text-align: center; padding: 50px 0; }
#player p a { color: #b01c40; text-decoration: underline; }
</style>
<script>
import swfobject from 'VideoJs'
// 播放器ID
const PLAYER_WRAP_ID = 'playerWrap'
const PLAYER_ID = 'player'
const SKIP_BEGIN_TIME = 7 // 跳过片头设置片头时间
let continueStart = 0 // 继续学习初始值
export default {
props: {
lastTime: { type: Number, require: false },
videoId: { type: String, require: false },
width: { type: Number, require: false },
height: { type: Number, require: false },
username: { type: String, require: false },
videoSrt: { type: String, require: false },
autoPlay: { type: Boolean, require: false, default: true },
chapterVideo: { type: Object, require: false }
},
mounted () {
this.definWindowFun()
// console.log(PLAYER_ID, this.videoId, this.autoPlay, this.videoSrt, this.username, this.width, this.height)
// this.renderPlayer(PLAYER_ID, this.videoId, this.autoPlay, this.videoSrt, this.username, this.width, this.height)
},
watch: {
videoId: {
handler () {
if (this.videoId) {
/* 注意 flash 初始化时,需要页面DOM存在 + videoId存在 */
continueStart = this.lastTime || 0 // 如果传递有上次播放时间,则记录缓存,以便player.start时使用
this.renderPlayer(PLAYER_ID, this.videoId, this.autoPlay, this.videoSrt, this.username, this.width, this.height)
}
}
}
},
methods: {
/* 定义windows下,播放事件和初始化回调 */
definWindowFun () {
const that = this
// 开始播放,如果设置了跳过片头则设置播放时间
window._playerStart = function () {
if (/skip=1/.test(document.cookie)) {
that.getPlayer().callAction('setCurrentTime', Math.max(continueStart, SKIP_BEGIN_TIME)) // 跳到第6秒开始播放
} else if (continueStart) {
that.getPlayer().callAction('setCurrentTime', continueStart)
}
}
// 播放过程中不断触发,传递当前播放到的时间
window._playerIng = function (time) {
$('#' + PLAYER_WRAP_ID).trigger('player.time', { time, duration: that.getPlayer().callAction('getDuration'), quality: that.getPlayer().callAction('getQuality'), isSeek: false })
}
// 拖动播放进度条
window._playerSeek = function () {
$('#' + PLAYER_WRAP_ID).trigger('player.seek', { time: that.getPlayer().callAction('getCurrentTime'), duration: that.getPlayer().callAction('getDuration'), quality: that.getPlayer().callAction('getQuality'), isSeek: true })
}
// 视频播放结束
window._playerFinish = function () {
that.$emit('handlePlayfinish', { time: that.getPlayer().callAction('getDuration') })
}
// 播放控件 - 初始化完成时,注册播放事件
window._playerCallback = function () {
const player = that.getPlayer()
if (player) {
// player.register('onLoadStart', '') // 开始loading加载
player.callAction('register', 'onCanplay', '_playerStart') // 开始播放视频内容
player.callAction('register', 'onPlaying', '_playerIng') // 播放中触发,300ms一次
// player.register('onPause', '') // 暂停
// player.register('onResume', '') // 恢复播放
player.callAction('register', 'onSeekComplete', '_playerSeek') // 拖动进度条
player.callAction('register', 'onEnded', '_playerFinish') // 结束
}
}
},
/* flash swf视频 对象渲染 采用 VideoJs插件渲染 */
renderPlayer (domId, vid, autoPlay, srt, username, width, height) {
autoPlay = typeof autoPlay === 'undefined' ? 1 : autoPlay - 0
// For version detection, set to min. required Flash Player version, or 0 (or 0.0.0), for no version detection.
const swfVersionStr = '11.1.0'
// To use express install, set to playerProductInstall.swf, otherwise the empty string.
const xiSwfUrlStr = 'playerProductInstall.swf'
const flashvars = {
autoStart: autoPlay,
vid: vid,
isShowSpeeder: 1,
videoType: 1, // 0为mp4模式 1为cc模式
callback: '_playerCallback'
}
if (srt) { flashvars.srtUrl = srt }
if (username) { flashvars.username = username }
// flashvars.videoType = 1; // 0为mp4模式 1为cc模式
const params = {
quality: 'high',
bgcolor: '#000000',
allowscriptaccess: 'always',
allowfullscreen: 'true'
}
const attributes = {
id: domId,
name: domId,
align: 'middle',
wmode: 'opaque'
}
// render
swfobject.embedSWF(
// require('player'),
'/static/videoJs/swf/Player1705192.swf',
domId,
parseInt(width),
parseInt(height),
swfVersionStr,
xiSwfUrlStr,
flashvars,
params,
attributes
)
// 绑定事件监听
this.listenPlayerEvents()
},
listenPlayerEvents () {
$('#' + PLAYER_WRAP_ID).off('player.time player.seek').on('player.time player.seek', (e, data) => {
this.$emit('handlePlayTime', data)
})
},
// ========= 提供播放后,其他组件可使用控制播放的方法 ===========
// 获取视频对象
getPlayer () {
return document.getElementById(PLAYER_ID)
},
getTime () {
const player = this.getPlayer()
if (player) {
return player.callAction('getCurrentTime')
} else {
return 0
}
},
// 设置视频跳转时间
setTimeTo (time) {
const player = this.getPlayer()
if (player) {
player.callAction('setCurrentTime', time + 2) // flash实际播放值会大概小个一两秒,因此添加偏移
}
},
// 执行“跳过片头”操作
skipBegin () {
const player = this.getPlayer()
if (player && player.callAction('getCurrentTime') < SKIP_BEGIN_TIME) {
player.callAction('setCurrentTime', SKIP_BEGIN_TIME)
}
},
// 设置视频尺寸
setSize (w, h) {
const player = this.getPlayer()
if (player) {
player.width = w
player.height = h
}
}
}
}
</script>
<template>
<div class="play-paper">
<div class="play-paper-body">
<div class="play-paper-title"><div><h3>{{chapterName}}</h3></div></div>
<div class="play-paper-content play-chapter-work">
<template v-if="chapterWork.questions && chapterWork.questions.length" >
<ul>
<template v-for="(item, index) in chapterWork.questions">
<li v-bind:key="index">
<div class="work-number">{{index + 1}}.</div>
<div class="work-title">
<div class="edit_html" v-html="item.question_content"></div>
</div>
<textarea id="editor-chapterWork"></textarea>
<div style="height: 20px;"></div>
<!-- <el-upload
ref="upFile"
class="upload-demo"
action=""
:multiple="false"
:limit="1"
:show-file-list="false"
:on-change="handleChange"
:http-request="uploadFile"
:file-list="filesArr">
请上传对应的文件附件:<el-button type="text">点击上传</el-button>
<template v-if="successFileUrl">
{{successFileUrl.replace(/.*\/([^\/]*\.docx)$/gi, '$1')}}
</template>
</el-upload> -->
<template v-if="successFileUrl">
<a :href="successFileUrl">下载已上传文件</a>
</template>
<!-- <div style="height: 20px;"></div> -->
<!-- <p class="help help-file">只支持docx格式的文件,文件小于10M</p> -->
<!-- {answer.file_url && <a style={{display: 'block', marginBottom: '20px', color: 'blue'}} href={answer.file_url} >下载附件</a> } -->
</li>
</template>
</ul>
</template>
<template v-else>
<!-- <p class="no-data">暂无数据</p> -->
</template>
<!-- <p class="text-danger">{this.state.error}</p> -->
<template v-if="this.deadLine">
<p style="color: red">请于截止日期 {{this.deadLine}} 前提交</p>
</template>
<div class="area-btns">
<el-button type="primary" @click="submitWork" :disabled="!!homeData.checker_time || deadLineFlag">{{homeData.checker_time ? '已批改' : '提交'}}</el-button>
<span class="help-info">&emsp;&emsp;在获老师批改之前,可以多次提交,将以最后一次提交为准</span>
<template v-if="homeData.checker_time">
<div class="play-paper-check">
<h4>已获批改 <small>批改于{{homeData.checker_time}}</small></h4>
<div class="play-paper-check-item"><b>评分:</b>{{homeData.score}}</div>
<div class="play-paper-check-item">
<b>评语:</b>
<div class="edit_html" v-html="homeData.check_comments"></div>
</div>
</div>
</template>
<template v-else-if="homeData.created_time">
<p class="help">已于 {{homeData.created_time}} 提交,等待批改中</p>
</template>
</div>
</div>
</div>
</div>
</template>
<script>
import cAction from '@action'
import Base64 from 'Base64'
import CKEDITOR from 'CKEDITOR'
export default {
props: {
chapterId: { type: String, require: false },
chapterWork: { type: Object, require: false },
chapterName: { type: String, require: false },
sid: { type: String, require: false },
cid: { type: String, require: false },
id: { type: String, require: false }
},
data () {
return {
ckeditor: null,
successFileUrl: '',
filesArr: [],
file: {
id: 'WU_FILE_0',
name: '',
type: '',
lastModifiedDate: '',
size: '',
file: ''
},
homeData: {},
/* 设置是否可以初始化 ckeditor */
setTime: null,
isInit: false,
deadLine: '',
deadLineFlag: false
}
},
/* 本组件 仅支持 单个 ckeditor 存在 */
mounted () {
this.loadAjax()
},
updated () {},
destroyed () {
/* 清空 ckeditor 需要调用方法删除 并 在DOM结构中也移除 */
this.ckeditor && this.ckeditor.destroy(true)
this.ckeditor = null
},
methods: {
handleChange (file, filelist) {
this.file.name = file.raw.name
this.file.type = file.raw.type
this.file.lastModifiedDate = file.raw.lastModifiedDate
this.file.size = file.raw.size
this.file.file = file.raw
},
loadAjax () {
const loading = this.$loading({ lock: true, text: '', spinner: '', background: 'rgba(255, 255, 255, 0.9)' })
cAction.Player.getHomework(this.sid, this.cid, this.id).then(data => {
this.homeData = data
}).catch(e => { this.filesArr.pop(); this.$message.error(e.message) }).finally(() => {
this.setTime = setInterval(() => {
if (document.querySelector('#editor-chapterWork')) {
this.initckeditor()
if (this.homeData.work_contents) {
let json = JSON.parse(this.homeData.work_contents)
if (json[0].is_encoded) {
json[0].descreption = Base64.decode(json[0].descreption)
}
this.successFileUrl = json[0].file_url
this.ckeditor.setData(json[0].descreption)
} else {
this.successFileUrl = ''
this.ckeditor.setData('')
}
/* 滚动到头部 */
document.querySelector('.play-paper').scrollTop = 0
clearInterval(this.setTime)
}
}, 50)
loading.close()
})
setTimeout(() => {
cAction.Player.getHomeworkStopTime(this.sid, this.cid, this.chapterId).then(data => {
this.deadLine = data.dead_line || ''
let deadLine = data.dead_line ? new Date(data.dead_line).getTime() : ''
// deadLine = new Date().getTime() - 100
this.deadLineFlag = ((new Date().getTime() > deadLine) && !!deadLine)
// console.log(this.deadLine)
}).catch(e => { this.$message.error(e.message) }).finally(() => {})
}, 500)
},
submitWork () {
if (!this.ckeditor.getData()) {
this.$message.error('请填写内容')
return
}
/* 只能提交 单个问题 */
const loading = this.$loading({ lock: true, text: '', spinner: '', background: 'rgba(255, 255, 255, 0.9)' })
let str = JSON.stringify([{
question_id: this.chapterWork.questions[0].id,
descreption: Base64.encode(this.ckeditor.getData()),
file_url: this.successFileUrl,
is_encoded: 1
}])
cAction.Player.updateHomework({
semester_id: this.sid,
course_id: this.cid,
chapter_id: this.chapterId,
work_id: this.id,
work_contents: str,
duration: 30 + Math.floor(Math.random() * 1000)
}).then(data => {
if (data.status) {
this.$message({ type: 'success', message: '提交成功,等待批改' })
this.loadAjax()
}
}).catch(e => { this.filesArr.pop(); this.$message.error(e.message) }).finally(() => { loading.close() })
},
uploadFile () {
if (!/\.(docx)$/gi.test(this.file.name)) {
this.$message.error('文件格式不对,请重新上传')
this.filesArr.pop()
return
}
const loading = this.$loading({ lock: true, text: '', spinner: '', background: 'rgba(255, 255, 255, 0.9)' })
cAction.Player.uploadFile(this.file).then(data => {
this.successFileUrl = data.url
this.filesArr.pop()
}).catch(e => { this.filesArr.pop(); this.$message.error(e.message) }).finally(() => { loading.close() })
},
/* 初始化 ckeditor */
initckeditor () {
!this.ckeditor && (this.ckeditor = CKEDITOR.replace('editor-chapterWork', {
height: 300,
uiColor: '#eeeeee',
filebrowserImageUploadUrl: '/api/ckeditor/img/upload',
// resize_enabled: typeof this.props.resizable === 'boolean' ? this.props.resizable : true,
toolbar: [
// { name: 'document', items: [ 'Source', '-', 'Save', 'NewPage', 'Preview' ] },
{ name: 'styles', items: [ 'Styles', 'Format', 'Font', 'FontSize' ] },
{ name: 'colors', items: [ 'TextColor', 'BGColor' ] },
{ name: 'tools', items: [ 'Maximize', 'ShowBlocks' ] },
// { name: 'clipboard', items: [ 'Cut', 'Copy', 'Paste', 'PasteText', 'PasteFromWord', '-', 'Undo', 'Redo' ] },
{ name: 'editing', items: [ 'Find', 'Replace' ] },
// { name: 'forms', items: [ 'Form', 'Checkbox', 'Radio', 'TextField', 'Textarea', 'Select', 'Button', 'ImageButton', 'HiddenField' ] },
'/',
{ name: 'basicstyles', items: [ 'Bold', 'Italic', 'Underline', 'Strike', 'Subscript', 'Superscript', '-', 'RemoveFormat' ] },
{ name: 'paragraph', items: [ 'NumberedList', 'BulletedList', '-', 'Outdent', 'Indent', '-', 'Blockquote', 'CreateDiv', '-', 'JustifyLeft', 'JustifyCenter', 'JustifyRight', 'JustifyBlock', '-', 'BidiLtr', 'BidiRtl' ] },
{ name: 'links', items: [ 'Link', 'Unlink', 'Anchor' ] },
{ name: 'insert', items: [ 'Image', 'Table', 'HorizontalRule' ] }
]
}))
}
},
watch: {
id: {
handler () {
this.loadAjax()
}
}
}
}
</script>
<template>
<div class="play-paper">
<div class="play-paper-body">
<div class="play-paper-title"><div><h3>课程资料</h3></div></div>
<div class="play-paper-content">
<template v-if="courseInfo.length">
<ul class="play-read-files">
<template v-for="(item, index) in courseInfo">
<li v-bind:key="index"><a :href="item.file_url" target="_blank">{{item.file_name}}</a></li>
</template>
</ul>
</template>
<template v-else>
<p class="no-data">暂无课程资料</p>
</template>
</div>
</div>
</div>
</template>
<script>
export default {
props: {
courseInfo: { type: Array, require: false }
}
}
</script>
<template>
<div class="play-paper">
<div class="play-paper-body">
<div class="play-paper-title"><div><h3>课程大作业</h3></div></div>
<div class="play-paper-content">
<div class="play-paper-step">&#9312; 阅读大作业要求</div>
<div class="edit_html" v-html="courseWork.curriculum_essay || ''"></div>
<p>截止日期:{{courseWork.essay_date || ''}}</p>
<div class="play-paper-step">&#9313; 填写作业主题、正文,上传附件(点击“提交”保存)</div>
<template v-if="courseWork.curriculum_name">
<div style="font-size: 20px;">主题<em style="font-size: 12px;">(最长不超过50个字)</em></div>
<el-input v-model="title" type="text" placeholder="主题" maxlength='100'></el-input>
<div style="font-size: 20px;">正文</div>
<textarea id="editor-courseWork"></textarea>
<div style="height: 20px;"></div>
<el-upload
ref="upFile"
class="upload-demo"
action=""
:multiple="false"
:limit="1"
:show-file-list="false"
:on-change="handleChange"
:http-request="uploadFile"
:file-list="filesArr">
请上传对应的文件附件:<el-button type="text">点击上传</el-button>
<template v-if="successFileUrl">
{{successFileUrl.replace(/.*\/([^\/]*\.docx)$/gi, '$1')}}
</template>
</el-upload>
<template v-if="successFileUrl">
<a :href="successFileUrl">下载已上传文件</a>
</template>
<div style="height: 20px;"></div>
<p class="help help-file">只支持docx格式的文件,文件小于10M</p>
<!-- {answer.file_url && <a style={{display: 'block', marginBottom: '20px', color: 'blue'}} href={answer.file_url} >下载附件</a> } -->
</template>
<template v-else>
<!-- <p class="no-data">暂无数据</p> -->
</template>
<!-- <p class="text-danger">{this.state.error}</p> -->
<div class="area-btns">
<div class="play-paper-step">&#9314; 截止日期前提交</div>
<el-button type="primary" @click="submitWork" :disabled="homeData.check_date">{{homeData.check_date ? '已批改' : '提交'}}</el-button>
<span class="help-info">&emsp;&emsp;在获老师批改之前,可以多次提交,将以最后一次提交为准</span>
<template v-if="homeData.check_date">
<div class="play-paper-check">
<h4>已获批改 <small>批改于{{homeData.check_date}}</small></h4>
<div class="play-paper-check-item"><b>评分:</b>{{homeData.score}}</div>
<div class="play-paper-check-item">
<b>评语:</b>
<!-- <div class="edit_html" dangerouslySetInnerHTML={{__html:work.check_comments}}></div>-->
<div class="edit_html" v-html="homeData.check_comments"></div>
</div>
</div>
</template>
<template v-else-if="homeData.created_time">
<p class="help">已于 {{homeData.created_time}} 提交,等待批改中</p>
<template v-if="homeData.updated_time !== homeData.created_time">
<p class="help">(最后一次提交时间: {{homeData.updated_time}}</p>
</template>
</template>
</div>
</div>
</div>
</div>
</template>
<script>
import cAction from '@action'
import Base64 from 'Base64'
import CKEDITOR from 'CKEDITOR'
export default {
props: {
courseWork: { type: Object, require: false },
sid: { type: String, require: false },
cid: { type: String, require: false },
id: { type: String, require: false }
},
data () {
return {
ckeditor: null,
successFileUrl: '',
successData: '', // 上传后,解析过来的 base64字符串
title: '',
filesArr: [],
file: {
id: 'WU_FILE_0',
name: '',
type: '',
lastModifiedDate: '',
size: '',
file: '',
special: 'course-work' // 标识 是从 大作业上传的
},
homeData: {},
/* 设置是否可以初始化 ckeditor */
setTime: null,
isInit: false
}
},
/* 本组件 仅支持 单个 ckeditor 存在 */
mounted () {
this.loadAjax()
},
updated () {},
destroyed () {
/* 清空 ckeditor 需要调用方法删除 并 在DOM结构中也移除 */
this.ckeditor && this.ckeditor.destroy(true)
this.ckeditor = null
},
methods: {
handleChange (file, filelist) {
this.file.name = file.raw.name
this.file.type = file.raw.type
this.file.lastModifiedDate = file.raw.lastModifiedDate
this.file.size = file.raw.size
this.file.file = file.raw
},
loadAjax () {
const loading = this.$loading({ lock: true, text: '', spinner: '', background: 'rgba(255, 255, 255, 0.9)' })
cAction.Player.getCourseHomework(this.sid, this.cid).then(data => {
this.homeData = data
}).catch(e => { this.filesArr.pop(); this.$message.error(e.message) }).finally(() => {
this.setTime = setInterval(() => {
if (document.querySelector('#editor-courseWork')) {
this.initckeditor()
if (this.homeData.course_id) {
let json = this.homeData
this.successFileUrl = json.file_url
this.ckeditor.setData(json.essay_description)
this.title = json.essay_name
}
clearInterval(this.setTime)
}
}, 50)
loading.close()
})
},
submitWork () {
if (!this.title) {
this.$message.error('请输入主题')
return
}
// if (!this.successFileUrl) {
// this.$message.error('请上传附件')
// return
// }
if (!this.ckeditor.getData()) {
this.$message.error('请填写内容')
return
}
/* 只能提交 单个问题 */
const loading = this.$loading({ lock: true, text: '', spinner: '', background: 'rgba(255, 255, 255, 0.9)' })
let _strContent = this.ckeditor.getData()
.replace(/<(a|b|p|em|span|strong|table|tbody|thead|th|tr|td|div).*?>/gi, '')
.replace(/<\/.*?>/gi, '')
cAction.Player.updateCourseHomework(this.sid, this.cid, {
essay_name: this.title,
essay_description: this.ckeditor.getData(),
url: this.successFileUrl,
course_id: this.cid,
semester_id: this.sid,
raw: this.successData || Base64.encode(_strContent) // 新增 docx解析字段,必传,论文查重字段,再把内容改成base64 传入
}).then(data => {
if (data.status) {
this.$message({ type: 'success', message: '提交成功,等待批改' })
this.loadAjax()
}
}).catch(e => { this.filesArr.pop(); this.$message.error(e.message) }).finally(() => { loading.close() })
},
uploadFile () {
if (!/\.(docx)$/gi.test(this.file.name)) {
this.$message.error('文件格式不对,请重新上传')
this.filesArr.pop()
return
}
const loading = this.$loading({ lock: true, text: '', spinner: '', background: 'rgba(255, 255, 255, 0.9)' })
cAction.Player.uploadFile(this.file).then(data => {
if (data.error) {
this.$message.error('提示待定!!!!!')
} else {
this.successFileUrl = data.url
this.successData = data.dataStr || '' // 新增base64字符串 解析docx文档
this.filesArr.pop()
}
}).catch(e => { this.filesArr.pop(); this.$message.error(e.message) }).finally(() => { loading.close() })
},
/* 初始化 ckeditor */
initckeditor () {
!this.ckeditor && (this.ckeditor = CKEDITOR.replace('editor-courseWork', {
height: 600,
uiColor: '#eeeeee',
filebrowserImageUploadUrl: '/api/ckeditor/img/upload',
// resize_enabled: typeof this.props.resizable === 'boolean' ? this.props.resizable : true,
toolbar: [
// { name: 'document', items: [ 'Source', '-', 'Save', 'NewPage', 'Preview' ] },
{ name: 'styles', items: [ 'Styles', 'Format', 'Font', 'FontSize' ] },
{ name: 'colors', items: [ 'TextColor', 'BGColor' ] },
{ name: 'tools', items: [ 'Maximize', 'ShowBlocks' ] },
// { name: 'clipboard', items: [ 'Cut', 'Copy', 'Paste', 'PasteText', 'PasteFromWord', '-', 'Undo', 'Redo' ] },
{ name: 'editing', items: [ 'Find', 'Replace' ] },
// { name: 'forms', items: [ 'Form', 'Checkbox', 'Radio', 'TextField', 'Textarea', 'Select', 'Button', 'ImageButton', 'HiddenField' ] },
'/',
{ name: 'basicstyles', items: [ 'Bold', 'Italic', 'Underline', 'Strike', 'Subscript', 'Superscript', '-', 'RemoveFormat' ] },
{ name: 'paragraph', items: [ 'NumberedList', 'BulletedList', '-', 'Outdent', 'Indent', '-', 'Blockquote', 'CreateDiv', '-', 'JustifyLeft', 'JustifyCenter', 'JustifyRight', 'JustifyBlock', '-', 'BidiLtr', 'BidiRtl' ] },
{ name: 'links', items: [ 'Link', 'Unlink', 'Anchor' ] },
{ name: 'insert', items: [ 'Image', 'Table', 'HorizontalRule' ] }
]
}))
}
}
}
</script>
差异被折叠。
.play{overflow:hidden; position: fixed;top:0; z-index: 800; width: 100%; height: 100%; background-color:#3f3f3f;color:#a0a0a0;}
.play .left-content{ position: absolute; right: 350px; top: 0; left: 0; bottom: 0; min-width: 705px;height:100%;}
.play.sidebar-hide .left-content{right:0;}
.play .play-top{ line-height: 56px;}
.play .play-top p{font-size:1.5em;text-align:center;margin:0;}
.play .play-back{position:absolute;top:6px;left:10px;width:40px;height:40px;overflow:hidden;color: #fff;font-size: 24px;line-height: 40px;text-align: center;}
.play .play-content{position:absolute;top:56px;bottom:0;left:0;right:0;}
.play .play-content-video{height:100%;}
.play .play-center .text-error{ font-size:0.875em;line-height:1.5em; }
.play .play-video-hide{visibility:hidden;overflow:hidden;width:0}
.play .play-video-init-center{position:absolute;top:50%;left:50%;margin:-180px 0 0 -275px;}
/* ppt控制 样式 */
.play .play-ppt { position: relative;width: 550px; height: 363.375px;background-color:#000;}
.play .play-ppt-img { width: 100%; height: 100%;}
.play .play-controls {position: absolute;bottom:0;left:0;right:0;height: 44px; line-height: 42px; padding: 0 14px;background-color: #000;}
.play .play-controls .fl i{ color: #8c8c8b}
.play .play-page{ position: absolute; left: 50%; margin-left: -75px; color: #fff; width: 150px; text-align: center; font-size: 0.875em;}
.play .play-page .play-now { color: #d29f29;}
.play .play-amazing { float: right; }
.play .play-amazing i{ color: #fff; margin: 0 10px; cursor: pointer; }
.play .play-amazing i.active,
.play .play-amazing i:hover{ color: #d29f29;}
.play .play-amazing .icon-rotate{ font-size: 1.125em;}
/* 整个视频 底部控制 上一章、下一章 同步、下载、跳过 */
.play .play-footer{ position: absolute; bottom: 0; left: 0;right:0; z-index: 200;padding:18px 20px 15px;}
.play .play-footer a:hover{color:#a0a0a0;}
/* 底部控制 按钮样式 */
.play .play-state{display:inline-block;color:#a0a0a0;padding-left: 25px;font-size:14px;line-height:18px;margin:0 20px;background:url(./play-icons.png) no-repeat 0 0;cursor:pointer}
.play .play-state a { color: #a0a0a0; text-decoration: none; }
.play .play-state-prev{background-position:0 2px;}
.play .play-state-prev-disable{background-position:0 -78px;color:#666;}
.play .play-state-next{background-position:0 -38px;}
.play .play-state-next-disable{background-position:0 -118px;color:#666;}
.play .play-state-check{background-position:0 -160px;}
.play .play-state-check-active{background-position:0 -200px;color: #b19241; }
.play .play-state-ppt{background-position:0 -240px;}
.play .play-state-ppt-active{background-position:0 -280px;color: #b19241; }
.play .play-state-prev-disable:hover,
.play .play-state-next-disable:hover {color:#666!important;}
/* 收起右侧,出现的 按钮样式 */
.play .switch { display: block; width: 36px; height: 125px; position: absolute; right: 0px; top: 50%; text-align: center; margin: -63px 0 0; z-index: 998; cursor: pointer;}
.play .switch a { color: #a0a0a0; text-decoration: none; font-size: 14px; line-height: 2; margin-bottom: 20px; }
.play .switch a i { font-size: 24px; padding: 5px; background: #666; border-radius: 4px; }
/*作业类页*/
.play .play-paper{position:absolute;top:0;bottom:0;left:0;right:0;overflow:auto;background-color:#e5e5e5;}
.play .play-paper-body{min-height:500px;margin:25px;padding:15px 45px 25px;color:#313131;box-shadow:0 0 2px rgba(0,0,0,.05);background-color:#f2f2f2;}
.play .play-paper-title{margin:0 10px;text-align:center;}
.play .play-paper-title div{padding-bottom:3px;display:inline-block;border-bottom:1px solid #707070;}
.play .play-paper-title h3{padding:0 0 5px;margin:0;display:inline-block;font-size:20px;border-bottom:3px solid #707070;}
.play .play-paper-body .help{color:#999;font-size:12px;}
.play .play-paper-body .help-file{margin-top:-10px;}
.play .play-paper-body .area-btns{margin:20px 0;}
.play .play-paper-body .area-btns .btn{padding:6px 25px;}
.play .play-paper-body .area-btns .help{margin-top:10px; font-size: 14px}
.play .play-paper-body .area-btns .help-info{display:inline-block;vertical-align:middle;}
.play .play-paper-body .webuploader-btn .upbtn{color:#b49441;text-decoration:underline;padding:3px 15px;font-size:.9em;display:inline-block;}
.play .play-paper-body .webuploader-btn .loading .fa-spin{font-size:1.2em!important;}
.play .play-paper-body label{font-weight:normal;}
.play .play-paper-body input{vertical-align:middle;}
.play .play-paper-check{margin-top:20px;padding:20px;border:1px solid #dedede;}
.play .play-paper-check h4{font-size:16px;margin:0 0 10px;}
.play .play-paper-check-item{padding-left:3em;}
.play .play-paper-check-item b{margin-left:-3em;margin-top:1px;display:inline-block;vertical-align:top;}
.play .play-paper-check-item .edit_html{display:inline-block;vertical-align:top;}
/*阅读材料*/
.play .play-read-files{padding:30px;margin: 0;}
.play .play-read-files li{font-size:16px;padding:20px 30px;margin-bottom:10px;background-color:#fff;list-style: none;}
.play .play-read-files li a { color: #333; text-decoration: none; }
.play .play-read-files li a:hover { color: #b49441; }
/*章节作业*/
.play .play-chapter-work{padding:25px;}
.play .play-chapter-work .work-number{margin-left:-25px;}
.play .play-chapter-work .work-title{margin-top:-20px;margin-bottom:10px;}
.play .play-chapter-work .area-btns{margin:20px -25px 0;border-top:1px solid #eaeaea;padding-top:20px;}
.play .play-chapter-exam{padding:25px;}
.play .play-chapter-exam li{position:relative;margin-top:15px;border-bottom:1px solid #b49441;}
.play .play-chapter-exam .exam-title{margin: -20px 0 10px 25px;}
.play .play-chapter-exam .wrong{color:#d80000;}
.play .play-chapter-exam .correct{color:#090;}
.play .play-chapter-exam .answer{position:absolute;right:25px;bottom:10px;}
.play .play-chapter-exam .result{float:right;margin-top:-20px;margin-right:-20px;font-size:16px;font-weight:bold;}
/* 统一默认 common样式 */
.play dd,
.play dl,
.play dt,
.play li,
.play ol,
.play ul { margin: 0; padding: 0; list-style: none; }
.play .edit_html p {padding: 0; margin: 0; margin-bottom: 15px;}
.play .play-paper-step{font-weight:bold;font-size:16px;margin:30px -20px 15px;padding-bottom:10px;border-bottom:1px dashed #cecece;}
.play .no-data {
color: #c9c9c9;
font-size: 36px;
padding: 160px 0;
text-align: center;
}
/* 视频播放样式 */
.play .hide { display: none; }
.play .play-video { float: left }
.play .play-jiangyi { float: left }
/* 视频播放 是 flash */
@media (max-width:768px){
.play .left-content {min-width:0;right:0;}
.play .play-back{margin:0;}
.play .play-chapter-work{padding:25px 0;margin-right:-20px;}
.play .play-read-files{padding:30px 0;margin:0 -20px;}
.play .switch{top:80%;}
.play .play-paper-body{ padding: 15px 25px 25px; }
.play .play-paper-step{ margin: 30px 0 15px; }
}
/* OK 样式 */
.exam .q-group .q-title p { padding: 0; margin: 0; }
.exam .el-radio + .el-radio { margin-left: 0; }
.exam .el-radio__input.is-disabled + span.el-radio__label { color: inherit; }
.exam .el-checkbox + .el-checkbox { margin-left: 0; }
.exam .el-checkbox__input.is-disabled + span.el-checkbox__label { color: inherit; }
.exam .el-radio__label, .exam .el-checkbox__label { white-space: normal; }
/* aliyun 播放器 样式修改 */
#player .prism-setting-btn { display: none; }
#player .prism-cc-btn { display: none; }
#player.prism-player .prism-progress { z-index: 99; }
差异被折叠。
<template>
<iframe id="myIframe" :src="live.url" frameborder="0" width="100%" height="100%" allow="autoplay;geolocation;microphone;camera;midi;encrypted-media;"></iframe>
</template>
<script>
import cAction from '@action'
export default {
props: {
sid: { type: String, require: false },
cid: { type: String, require: false },
id: { type: String, require: false }
},
data () {
return {
live: {},
ccLive: null
}
},
mounted () {
this.loadAjax()
},
destroyed () {
if (window.document.getElementById('switch-btn')) {
window.document.getElementById('switch-btn').style.display = 'block'
window.document.getElementById('sys-help').style.display = 'none'
window.document.getElementById('sys-callback').style.display = 'none'
}
if (this.ccLive) {
this.ccLive.logout({
success: function (res) {
},
error: function (res) {
}
})
}
},
methods: {
loadAjax () {
/* 只能清除本域名下的cookie,不能清除其他域名下的cookie */
// cAction.loginAction.clearCookie({
// cookies: [{
// name: 'sessionid',
// obj: { path: '/', domain: '.csslcloud.net' }
// }, {
// name: 'TGC',
// obj: { path: '/', domain: '.ezijing.com' }
// }]
// }).then().finally(() => {})
const loading = this.$loading({ lock: true, text: '', spinner: '', background: 'rgba(255, 255, 255, 0.9)' })
cAction.Player.getChapterList(this.cid, this.sid, this.id).then(json => {
this.live = (json.curJson && json.curJson.live) || {}
if (this.live.id) {
if (this.live.record_id && this.live.live_status === 103) {
this.live.url = 'https://view.csslcloud.net/api/view/callback?recordid=' + this.live.record_id + '&roomid=' + this.live.room_id + '&userid=' + this.live.user_id + '&autoLogin=true&viewername=' + this.live.viewer_name + '&viewertoken=' + this.live.viewer_token // + '&groupid=xxx'
} else {
this.$emit('changeSideBar', '')
setTimeout(() => {
if (window.document.getElementById('switch-btn')) {
window.document.getElementById('switch-btn').style.display = 'none'
window.document.getElementById('sys-help').style.display = 'block'
window.document.getElementById('sys-callback').style.display = 'block'
}
}, 1000)
this.live.viewer_name = window.G.UserInfo.student_info.personal_name || window.G.UserInfo.nickname
this.live.url = 'https://view.csslcloud.net/api/view/index?roomid=' + this.live.room_id + '&userid=' + this.live.user_id + '&autoLogin=true&viewername=' + this.live.viewer_name + '&viewertoken=' + this.live.viewer_token // + '&groupid=xxx'
}
this.CCLiveInit(this.live)
}
loading.close()
}).catch(e => { this.$message.error(e.message) }).finally(() => { })
},
CCLiveInit (live) {
window.DWLive.init({
userid: live.user_id, // 必须参数
roomid: live.room_id, // 必须参数
// groupid: "groupid", // 可选
viewername: live.viewer_name, // 可选
viewertoken: live.viewer_token // 如果直播间设置为密码验证,必选
// viewercustomua: 'android', // 可选
// language: 'en', // 可选
// viewercustominfo: '{"exportInfos": [ {"key": "城市", "value": "北京"}, {"key": "姓名", "value": "哈哈"}]}', // 可选
// fastMode:true // 可选参数,默认为true
})
this.ccLive = window.DWLive
}
},
watch: {
id: {
handler () {
this.loadAjax()
}
}
}
}
</script>
<style lang="scss" scoped>
</style>
<template>
<div class="tab-pane">
<ul class="chapter-list">
<template v-for="(item, index) in list.course">
<li v-bind:key="index" class="chapter-item">
<h4>{{item.title}}</h4>
<ul class="knot-list">
<template v-for="(_item, _index) in item.chapters">
<li v-bind:key="_index" :class="['knob-item', (_item.id === list.currentChapterId ? 'on' : '')]">
<a :data-vid="_item.id" :data-type="_item.video_provider" :data-hasVA='_item.time' @click='jumpToOtherVA' :data-index='index' :data-count='_index' class="knot-name">
{{_item.name + (_item.type === 5 ? ("(" + _item.live.statusStr + ")") : "") }}
</a>
<template v-if="_item.type !== 5">
<i :class="['el-icon', (_item.time ? 'el-icon-self-iconset0481' : (_item.type === 3 ? 'el-icon-edit-outline' : 'el-icon-self-cc-book'))]"></i>
</template>
</li>
</template>
</ul>
</li>
</template>
</ul>
</div>
</template>
<script>
export default {
props: {
list: { type: Object, require: false },
sid: { type: String, require: false },
cid: { type: String, require: false }
},
methods: {
/**
* 跳转到对应音视频播放页
*/
jumpToOtherVA (e) {
const _data = e.target.dataset
const sid = this.sid
const cid = this.cid
const _id = _data.vid
const type = _data.type
if (!_data.hasva) {
/* 如果存在 - 课后习题类型(chapterExam), type:3、work_type:1 */
/* 如果存在 - 课后问题类型(chapterWork), type:3、work_type:2 */
/* 如果存在 - 课后阅读类型(chapterRead), type:4 */
const i1 = _data.index
const i2 = _data.count
const _course = this.list.course[i1]
if (_course && _course.chapters[i2]) {
if (_course.chapters[i2].id === 'course_info') {
this.$router.push({ path: `/player/${sid}/${cid}/course-info/course_info` })
} else if (_course.chapters[i2].id === 'course_work') {
if (!this.list.survey) {
this.$message('请先填写教学评估,然后完成大作业。')
return
}
this.$router.push({ path: `/player/${sid}/${cid}/course-work/course_work` })
} else if (_course.chapters[i2].type === 3) {
if (_course.chapters[i2].work_type === 1) {
this.$router.push({ path: `/player/${sid}/${cid}/chapter-exam/${_id}` })
} else if (_course.chapters[i2].work_type === 2) {
this.$router.push({ path: `/player/${sid}/${cid}/chapter-work/${_id}` })
}
} else if (_course.chapters[i2].type === 4) {
this.$router.push({ path: `/player/${sid}/${cid}/chapter-read/${_id}` })
} else if (_course.chapters[i2].id === 'teach_evaluation') {
// window.localStorage.setItem('headerInfo', JSON.stringify(this.headerInfo))
this.$router.push({ path: `/survey/${sid}/${cid}` })
} else if (_course.chapters[i2].type === 'exam') {
this.$router.push({ path: `/player/${sid}/${cid}/exam/${_id}` })
} else if (_course.chapters[i2].type === 5) {
const status = _course.chapters[i2].live.live_status
if (status !== 0 && status !== 1 && status !== 103) {
this.$message.error(_course.chapters[i2].live.statusStr)
return
}
const enableRecord = _course.chapters[i2].live.enable_record
if (status === 103 && enableRecord !== undefined && enableRecord !== null && !enableRecord) {
this.$message.info('该直播没有回放')
return
}
this.$router.push({ path: `/player/${sid}/${cid}/live/${_id}` })
}
return
}
this.$message.error('系统未知错误,002')
return
}
this.$router.push({ path: `/player/${sid}/${cid}/chapter-video/${_id}/${type}` })
}
}
}
</script>
<style lang="scss" scoped>
.tab-pane {
display: block;
height: 100%;
overflow: auto;
/* 章列表样式 */
.chapter-list {
margin: 0;
padding: 0;
line-height: 1.6;
overflow: hidden;
.chapter-item {
h4 {
padding: 10px 22px;
margin: 0;
font-size: 15px;
color: #b0b0b0;
background-color: #2f2f2f;
}
/* 节列表样式 */
.knot-list {
margin: 0;
padding: 0;
line-height: 1.6;
overflow: hidden;
li {
position: relative;
&.on {
background: #3c3c3c;
a {
color: #b49441;
}
}
&:hover {
background: #3c3c3c;
}
&:before {
display: block;
content: "";
position: absolute;
left: 13px;
top: 16px;
z-index: 10;
width: 18px;
height: 18px;
background: #5b5b5b;
border: 2px solid #5b5b5b;
border-radius: 50%;
}
&:after {
display: block;
content: "";
position: absolute;
left: 22px;
top: 0;
z-index: 5;
width: 1px;
height: 100px;
background: #616161;
}
}
.knot-name {
display: block;
padding: 15px 35px 15px 40px;
font-size: 14px;
color: #909090;
text-decoration: none;
cursor: pointer;
}
}
/* 章节后面小图标的样式 */
.el-icon {
position: absolute;
font-size: 16px;
right: 10px;
top: 50%;
transform: translateY(-50%);
}
}
}
}
</style>
<template>
<div class="tab-pane">
<ul class="lecture-list">
<template v-for="(item, index) in ppt.imgUrls">
<li v-bind:key="index" @click="onClickPpt" :data-index="index" :class="[(index === ppt.selectIndex ? 'on' : '')]">
<img :src="item" alt=""/>
</li>
</template>
</ul>
</div>
</template>
<script>
export default {
props: {
ppt: { type: Object, require: false }
},
methods: {
// 根据播放时间同步展示ppt
// @param time 播放时间
setIndexByPoint (time) {
const ppts = this.ppt.imgUrls || []
const len = ppts.length
let i = 0
for (; i < len; i++) {
if (time < this.ppt.timeArr[i]) {
break
}
}
if (this.ppt.selectIndex !== i - 1) {
this.ppt.selectIndex = i - 1
}
},
// 点击ppt跳转对应的播放时间
// 点击某个ppt
onClickPpt (e) {
const toIndex = e.currentTarget.dataset.index - 0
if (this.ppt.selectIndex === toIndex) { return }
this.ppt.selectIndex = toIndex
this.$emit('handleClickPpt', toIndex)
}
}
}
</script>
<style lang="scss" scoped>
.tab-pane {
display: block;
height: 100%;
overflow: auto;
/* 讲义列表样式 */
.lecture-list {
padding: 8px 16px;
li {
padding: 8px 16px;
cursor: pointer;
list-style: none;
&.on {
background: #888;
}
img {
width: 100%;
}
}
}
}
</style>
...@@ -89,6 +89,64 @@ export default [ ...@@ -89,6 +89,64 @@ export default [
} }
] ]
}, },
/* 学习系统 - player */
// {
// path: '/player/:sid/:cid',
// redirect: '/player/0/0/error/404',
// component: () => import('@/pages/player/index.vue'),
// props: true,
// children: [
// { path: 'error/404', component: () => import('@/components/errorPages/404.vue') },
// {
// path: 'chapter-video/:id/:videoType',
// name: 'video',
// component: () => import('@/pages/player/chapterVideo/chapterVideo.vue'),
// props: true
// },
// {
// path: 'chapter-exam/:id',
// name: 'chapterExam',
// component: () => import('@/pages/player/chapterExam/chapterExam.vue'),
// props: true
// },
// {
// path: 'chapter-read/:id',
// name: 'chapterRead',
// component: () => import('@/pages/player/chapterRead/chapterRead.vue'),
// props: true
// },
// {
// path: 'chapter-work/:id',
// name: 'chapterWork',
// component: () => import('@/pages/player/chapterWork/chapterWork.vue'),
// props: true
// },
// {
// path: 'course-info/:id',
// name: 'courseInfo',
// component: () => import('@/pages/player/courseInfo/courseInfo.vue'),
// props: true
// },
// {
// path: 'course-work/:id',
// name: 'courseWork',
// component: () => import('@/pages/player/courseWork/courseWork.vue'),
// props: true
// },
// {
// path: 'exam/:id',
// name: 'exam',
// component: () => import('@/pages/player/exam/exam.vue'),
// props: true
// },
// {
// path: 'live/:id',
// name: 'live',
// component: () => import('@/pages/player/live/live.vue'),
// props: true
// }
// ]
// },
/* 如果所有页面都没找到 - 指向 */ /* 如果所有页面都没找到 - 指向 */
{ path: '*', component: () => import('@/components/errorPages/404.vue') } { path: '*', component: () => import('@/components/errorPages/404.vue') }
] ]
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论