提交 be659e74 authored 作者: 王鹏飞's avatar 王鹏飞

update viewer module

上级 d69faf21
...@@ -104,8 +104,22 @@ export default class CourseAction extends BaseACTION { ...@@ -104,8 +104,22 @@ export default class CourseAction extends BaseACTION {
unit: item.lecturer_title || '' unit: item.lecturer_title || ''
}) })
} }
const findChapter = function (id, list) {
for (const item of list) {
if (item.resource_id === id) {
return item
}
if (item.children && item.children.length) {
const found = findChapter(id, item.children)
if (found) {
return found
}
}
}
}
/* 课程内容 */ /* 课程内容 */
json.tabs1ChapterList = { json.tabs1ChapterList = {
currentChapter: findChapter(cur.latest_play, data.chapters),
currentChapterId: cur.latest_play || '', currentChapterId: cur.latest_play || '',
currentVideoProvider: cur.latest_play_type || '1', currentVideoProvider: cur.latest_play_type || '1',
course: cur.chapters.map((_, i) => { course: cur.chapters.map((_, i) => {
...@@ -173,35 +187,39 @@ export default class CourseAction extends BaseACTION { ...@@ -173,35 +187,39 @@ export default class CourseAction extends BaseACTION {
title: '课程大作业', title: '课程大作业',
isUp: true, isUp: true,
chapters: [], chapters: [],
type: 'course_work', id: 'course_work',
sid: sid, sid: sid,
cid: cid cid: cid,
type: 99
}) })
json.tabs1ChapterList.course.push({ json.tabs1ChapterList.course.push({
title: '课程资料', title: '课程资料',
isUp: true, isUp: true,
chapters: [], chapters: [],
type: 'course_info', id: 'course_info',
sid: sid, sid: sid,
cid: cid cid: cid,
type: 100
}) })
json.tabs1ChapterList.course.push({ json.tabs1ChapterList.course.push({
title: '教学评估', title: '教学评估',
isUp: true, isUp: true,
chapters: [], chapters: [],
type: 'teach_evaluation', id: 'teach_evaluation',
sid: sid, sid: sid,
cid: cid cid: cid,
type: 102
}) })
if (cur.course_examination) { if (cur.course_examination) {
json.tabs1ChapterList.course.push({ json.tabs1ChapterList.course.push({
title: '课程考试', title: '课程考试',
isUp: true, isUp: true,
chapters: [], chapters: [],
type: 'exam', id: 'course_exam',
sid: sid, sid: sid,
cid: cid, cid: cid,
examId: cur.course_examination examId: cur.course_examination,
type: 102
}) })
} }
/* 课程考核 考核标准文案读取 */ /* 课程考核 考核标准文案读取 */
......
...@@ -35,6 +35,27 @@ export function getChapterVideoAliyun(vid) { ...@@ -35,6 +35,27 @@ export function getChapterVideoAliyun(vid) {
) )
} }
/**
* 获取章节视频播放进度
* @param {string} semesterId 学期ID
* @param {string} resourseId 章节的资源ID
* @param {Object} params
*/
export function getChapterVideoProgress(semesterId, resourseId, params) {
return httpRequest.get(
`/v2/education/video/${semesterId}/${resourseId}/device`,
params
)
}
/**
* 更新章节视频播放进度
* @param {Object} params
*/
export function updateChapterVideoProgress(params) {
return httpRequest.get('/v2/analytics/upload-video', params)
}
/** /**
* 获取答题信息 * 获取答题信息
* @param {string} semesterId 学期ID * @param {string} semesterId 学期ID
...@@ -130,8 +151,9 @@ export function submitCourseExam(semesterId, courseId, examId, data) { ...@@ -130,8 +151,9 @@ export function submitCourseExam(semesterId, courseId, examId, data) {
* @param {string} courseId 课程ID * @param {string} courseId 课程ID
* @param {string} examId 试题ID * @param {string} examId 试题ID
*/ */
export function getCourseExamResult(semesterId, courseId, examId) { export function getCourseExamResult(semesterId, courseId, examId, params) {
return httpRequest.get( return httpRequest.get(
`/v2/education/${semesterId}/${courseId}/examination/${examId}/sheet` `/v2/education/${semesterId}/${courseId}/examination/${examId}/sheet`,
params
) )
} }
<template> <template>
<ul class="chapter-list"> <ul class="chapter-list">
<li class="chapter-item" v-for="item in data" :key="item.id"> <li class="chapter-item" v-for="item in chapters" :key="item.id">
<h4>{{item.name}}</h4> <h4>{{item.name}}</h4>
<ul class="chapter-item-list"> <ul class="chapter-item-list">
<li <li
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
@click="onClick(subItem)" @click="onClick(subItem)"
:class="{'is-active': subItem.id === (active ? active.id : '')}" :class="{'is-active': subItem.id === (active ? active.id : '')}"
> >
<span class="chapter-item-list__name">{{subItem.name | showName(subItem.type)}}</span> <span class="chapter-item-list__name">{{subItem.name | showName(subItem)}}</span>
<i class="el-icon" :class="genIconClass(subItem.type)"></i> <i class="el-icon" :class="genIconClass(subItem.type)"></i>
</li> </li>
</ul> </ul>
...@@ -20,7 +20,14 @@ ...@@ -20,7 +20,14 @@
<script> <script>
export default { export default {
props: { props: {
data: { type: Array, default: () => [] }, // 课程详情接口返回的数据
data: {
type: Object,
default() {
return {}
}
},
chapters: { type: Array, default: () => [] },
// 当前选中的章节 // 当前选中的章节
active: { active: {
type: Object, type: Object,
...@@ -30,26 +37,13 @@ export default { ...@@ -30,26 +37,13 @@ export default {
} }
}, },
data() { data() {
return { return {}
otherList: [
{
name: '大作业及资料',
children: [
{ name: '课程大作业', id: 'course_work' },
{ name: '课程资料', id: 'course_info' },
{ name: '教学评估', id: 'teach_evaluation' }
]
}
]
}
},
computed: {
list() {
return this.data.concat(this.otherList)
}
}, },
filters: { filters: {
showName(name, type) { showName(name, data) {
if (data.type === 5) {
return `${name}(${data.live.start_time})`
}
return name return name
} }
}, },
...@@ -63,16 +57,20 @@ export default { ...@@ -63,16 +57,20 @@ export default {
return map[type] || 'el-icon-self-cc-book' return map[type] || 'el-icon-self-cc-book'
}, },
onClick(data) { onClick(data) {
if (data.type === 1) {
return
}
// 课程大作业 // 课程大作业
// if (data.id === 'course_work') { if (data.id === 'course_work' && !this.data.survey) {
// this.$router.push({ name: 'viewerCourseWork' }) this.$message('请先填写教学评估,然后完成大作业。')
// return return
// } }
// 课程资料 // 教学评估
// if (data.id === 'course_info') { if (data.id === 'teach_evaluation') {
// this.$router.push({ name: 'viewerCourseFile' }) const { sid, cid } = this.$route.params
// return this.$router.push({ name: 'survey', params: { sid, cid } })
// } return
}
this.$router.push({ this.$router.push({
name: 'viewerCourseChapter', name: 'viewerCourseChapter',
params: { id: data.id } params: { id: data.id }
......
...@@ -3,12 +3,12 @@ ...@@ -3,12 +3,12 @@
<el-tabs v-model="activeName"> <el-tabs v-model="activeName">
<el-tab-pane label="章节" name="0"> <el-tab-pane label="章节" name="0">
<div class="tab-pane"> <div class="tab-pane">
<aside-chapter :data="chapters" :active="active"></aside-chapter> <aside-chapter :data="data" :chapters="chapters" :active="active"></aside-chapter>
</div> </div>
</el-tab-pane> </el-tab-pane>
<el-tab-pane label="讲义" name="1" v-if="active && active.type === 2"> <el-tab-pane label="讲义" name="1" v-if="active && active.type === 2">
<div class="tab-pane"> <div class="tab-pane">
<aside-lecture :data="ppts" :pptIndex="pptIndex" v-on="$listeners"></aside-lecture> <aside-lecture :ppts="ppts" :pptIndex="pptIndex" v-on="$listeners"></aside-lecture>
</div> </div>
</el-tab-pane> </el-tab-pane>
</el-tabs> </el-tabs>
...@@ -21,6 +21,13 @@ import AsideLecture from './lecture.vue' ...@@ -21,6 +21,13 @@ import AsideLecture from './lecture.vue'
export default { export default {
props: { props: {
// 课程详情接口返回的数据
data: {
type: Object,
default() {
return {}
}
},
// 章节 // 章节
chapters: { type: Array, default: () => [] }, chapters: { type: Array, default: () => [] },
// 讲义 // 讲义
......
<template> <template>
<ul class="lecture-list"> <ul class="lecture-list">
<li <li
v-for="(item, index) in data" v-for="(item, index) in ppts"
:key="item.id" :key="item.id"
@click="onClick(index)" @click="onClick(index)"
:class="{'is-active': index === activeIndex}" :class="{'is-active': index === activeIndex}"
...@@ -16,7 +16,7 @@ export default { ...@@ -16,7 +16,7 @@ export default {
props: { props: {
// 当前选择的PPT // 当前选择的PPT
pptIndex: { type: Number, default: 0 }, pptIndex: { type: Number, default: 0 },
data: { type: Array, default: () => [] } ppts: { type: Array, default: () => [] }
}, },
data() { data() {
return { return {
......
<template> <template>
<div class="upload"> <div class="upload">
<el-upload action :show-file-list="false" :http-request="httpRequest"> <el-upload action :disabled="disabled" :show-file-list="false" :http-request="httpRequest">
<slot></slot> <slot></slot>
<el-button type="text" icon="el-icon-upload">点击上传</el-button> <el-button type="text" icon="el-icon-upload">点击上传</el-button>
<template v-slot:tip> <template v-slot:tip>
...@@ -15,11 +15,23 @@ ...@@ -15,11 +15,23 @@
<i class="el-icon-document"></i> <i class="el-icon-document"></i>
{{ fileUrl | fileName }} {{ fileUrl | fileName }}
</a> </a>
<a :href="fileUrl" :download="fileUrl | fileName" target="_blank"> <div>
<el-tooltip effect="dark" content="下载"> <a
<i class="el-icon-download"></i> href="javascript:;"
</el-tooltip> @click="handleRemove(index)"
</a> style="margin-right:10px;"
v-if="!disabled"
>
<el-tooltip effect="dark" content="删除">
<i class="el-icon-delete"></i>
</el-tooltip>
</a>
<a :href="fileUrl" :download="fileUrl | fileName" target="_blank">
<el-tooltip effect="dark" content="下载">
<i class="el-icon-download"></i>
</el-tooltip>
</a>
</div>
</div> </div>
</div> </div>
</div> </div>
...@@ -31,7 +43,8 @@ import * as api from '../../api' ...@@ -31,7 +43,8 @@ import * as api from '../../api'
export default { export default {
name: 'VUpload', name: 'VUpload',
props: { props: {
value: { type: [String, Array] } value: { type: [String, Array] },
disabled: { type: Boolean, default: false }
}, },
data() { data() {
return { return {
...@@ -39,9 +52,18 @@ export default { ...@@ -39,9 +52,18 @@ export default {
} }
}, },
watch: { watch: {
value(value) { value: {
if (value) { immediate: true,
this.fileList = Array.isArray(value) ? value : [value] handler(value) {
if (value) {
if (Array.isArray(value)) {
this.fileList = value.map(item => {
return item.url || item
})
} else {
this.fileList = [value]
}
}
} }
} }
}, },
...@@ -63,6 +85,10 @@ export default { ...@@ -63,6 +85,10 @@ export default {
} }
} }
}) })
},
handleRemove(index) {
this.fileList.splice(index, 1)
this.$emit('input', Array.isArray(this.value) ? this.fileList : '')
} }
} }
} }
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
// components // components
import ChapterPlayer from './player/ChapterPlayer.vue' // 章节视频 import ChapterPlayer from './player/ChapterPlayer.vue' // 章节视频
import ChapterWork from './work/index.vue' // 章节作业 import ChapterWork from './work/index.vue' // 章节作业
import ChapterExam from './work/chapterExam.vue' // 章节考试
import ChapterRead from './read/chapterRead.vue' // 章节资料 import ChapterRead from './read/chapterRead.vue' // 章节资料
import ChapterLive from './live/chapterLive.vue' // 章节直播 import ChapterLive from './live/chapterLive.vue' // 章节直播
import CourseWork from './work/courseWork.vue' // 课程大作业 import CourseWork from './work/courseWork.vue' // 课程大作业
...@@ -25,6 +26,7 @@ export default { ...@@ -25,6 +26,7 @@ export default {
ChapterPlayer, ChapterPlayer,
ChapterWork, ChapterWork,
ChapterRead, ChapterRead,
ChapterExam,
ChapterLive, ChapterLive,
CourseWork, CourseWork,
CourseRead, CourseRead,
...@@ -45,6 +47,7 @@ export default { ...@@ -45,6 +47,7 @@ export default {
3: 'ChapterWork', // 作业 3: 'ChapterWork', // 作业
4: 'ChapterRead', // 资料 4: 'ChapterRead', // 资料
5: 'ChapterLive', // 直播 5: 'ChapterLive', // 直播
9: 'ChapterExam', // 考试
99: 'CourseWork', // 课程大作业 99: 'CourseWork', // 课程大作业
100: 'CourseRead', // 课程资料 100: 'CourseRead', // 课程资料
101: 'CourseExam' // 课程考试 101: 'CourseExam' // 课程考试
......
...@@ -7,15 +7,18 @@ ...@@ -7,15 +7,18 @@
:isSkip="isSkip" :isSkip="isSkip"
:video="chatperResources.video" :video="chatperResources.video"
@timeupdate="onTimeupdate" @timeupdate="onTimeupdate"
@ready="onReady"
ref="videoPlayer" ref="videoPlayer"
></video-player> ></video-player>
</div> </div>
<div class="player-column" v-if="pptVisible"> <div class="player-column" v-if="pptVisible">
<!-- ppt --> <!-- ppt -->
<ppt-player <ppt-player
:index="pptIndex"
:ppts="chatperResources.ppts" :ppts="chatperResources.ppts"
@close="pptVisible = false" @close="onPPTClose"
@fullscreen="onPPTFullscreen" @fullscreen="onPPTFullscreen"
@videoSyncTime="onVideoSyncTime"
></ppt-player> ></ppt-player>
</div> </div>
</div> </div>
...@@ -30,6 +33,8 @@ ...@@ -30,6 +33,8 @@
</template> </template>
<script> <script>
import Cookies from 'js-cookie'
import { throttle } from 'lodash'
// api // api
import * as api from '../../api' import * as api from '../../api'
// components // components
...@@ -46,11 +51,23 @@ export default { ...@@ -46,11 +51,23 @@ export default {
pptIndex: { type: Number, default: 0 } pptIndex: { type: Number, default: 0 }
}, },
data() { data() {
// 是否跳过片头
const isSkip = window.localStorage.getItem('isSkip') === 'true'
return { return {
videoVisible: true, videoVisible: true,
pptVisible: false, pptVisible: false,
isSkip: false, isSkip,
chatperResources: null chatperResources: null,
throttled: null,
throttleWait: 10, // 秒
progress: {
cpt: 0, // 当前播放时间
mpt: 0, // 视频时长
progress: 0, // 进度
pt: 0 // 累计播放时间
},
player: null,
watchedTimePoint: [] // 视频观看的时间点
} }
}, },
watch: { watch: {
...@@ -59,6 +76,14 @@ export default { ...@@ -59,6 +76,14 @@ export default {
} }
}, },
computed: { computed: {
// 学期ID
sid() {
return this.$route.params.sid
},
// 课程ID
cid() {
return this.$route.params.cid
},
// 视频资源ID // 视频资源ID
resourceId() { resourceId() {
return this.chapter.resource_id return this.chapter.resource_id
...@@ -95,11 +120,29 @@ export default { ...@@ -95,11 +120,29 @@ export default {
// 始终跳过片头 // 始终跳过片头
toggleSkip() { toggleSkip() {
this.isSkip = !this.isSkip this.isSkip = !this.isSkip
window.localStorage.setItem('isSkip', this.isSkip)
},
// 关闭PPT
onPPTClose() {
this.pptVisible = false
this.videoVisible = true
}, },
// PPT全屏 // PPT全屏
onPPTFullscreen(value) { onPPTFullscreen(value) {
this.videoVisible = !value this.videoVisible = !value
}, },
// 设置视频时间为当前PPT时间
onVideoSyncTime(time) {
this.player.seek(time)
},
// 播放器ready
onReady(player) {
this.player = player
// 跳转播放进度
if (this.progress.cpt) {
this.player.seek(this.progress.cpt)
}
},
// 当前播放时间更新 // 当前播放时间更新
onTimeupdate(time) { onTimeupdate(time) {
const ppts = this.chatperResources.ppts || [] const ppts = this.chatperResources.ppts || []
...@@ -108,12 +151,29 @@ export default { ...@@ -108,12 +151,29 @@ export default {
) )
index = index !== -1 ? index - 1 : ppts.length - 1 index = index !== -1 ? index - 1 : ppts.length - 1
this.$emit('change-ppt', index) this.$emit('change-ppt', index)
const durations = this.player.getDuration()
// 更新视频时间
this.progress.cpt = parseInt(time)
// 更新视频时长
this.progress.mpt = parseInt(durations)
const hasTimePoint = this.watchedTimePoint.includes(this.progress.cpt)
if (!hasTimePoint) {
this.watchedTimePoint.push(this.progress.cpt)
}
// 更新视频进度,10秒更新一次
if (this.throttled) {
this.throttled(time, durations)
} else {
this.throttled = throttle(
this.updateChapterVideoProgress,
this.throttleWait * 1000
)
}
}, },
// 更新视频当前播放时间 // 更新视频当前播放时间
updateVideoCurrentTime() { updateVideoCurrentTime() {
const player = this.$refs.videoPlayer.player
const ppt = this.chatperResources.ppts[this.pptIndex] const ppt = this.chatperResources.ppts[this.pptIndex]
ppt && player.seek(ppt.ppt_point) // 增加2秒 ppt && this.player.seek(ppt.ppt_point) // 增加2秒
}, },
// 获取章节视频详情 // 获取章节视频详情
getChapterVideo() { getChapterVideo() {
...@@ -125,14 +185,66 @@ export default { ...@@ -125,14 +185,66 @@ export default {
}) })
} else { } else {
api.getChapterVideo(this.resourceId).then(response => { api.getChapterVideo(this.resourceId).then(response => {
this.chatperResources = response let { video, audio, ppts } = response
Array.isArray(response.ppts) && this.$emit('pptupdate', response.ppts) video = video.reduce(
(result, item) => {
if (item.quality === '10') {
result.LD = item.playurl
}
if (item.quality === '20') {
result.SD = item.playurl
}
return result
},
{ LD: '', SD: '' }
)
this.chatperResources = { video, audio, ppts }
Array.isArray(ppts) && this.$emit('pptupdate', ppts)
})
}
},
// 获取章节视频进度
getChapterVideoProgress() {
api
.getChapterVideoProgress(this.sid, this.resourceId, {
device_id: Cookies.get('_idt')
}) })
.then(response => {
this.progress = response
// 跳转播放进度
if (this.player && response.cpt) {
this.player.seek(response.cpt)
}
})
},
// 更新章节视频进度
updateChapterVideoProgress(time, durations) {
this.progress.pt += this.throttleWait
// 登录用户信息
const user = window.G.UserInfo
const params = {
sid: user.student_info.id,
uid: user.uid,
d: Cookies.get('_idt'),
i: Cookies.get('_idt'),
c: this.cid, // 课程ID
s: this.sid, // 学期ID
v: this.resourceId, // 视频资源ID
_p: this.progress.pt, // 累计时间
_m: this.progress.mpt, // 当前播放最大时间
_c: this.progress.cpt, // 当前播放位置
ps: this.watchedTimePoint.join(',') // 播放时,统计帧
} }
api.updateChapterVideoProgress(params)
// 清空已经上传过的观看时间点
this.watchedTimePoint = []
} }
}, },
beforeMount() { beforeMount() {
// 获取视频
this.getChapterVideo() this.getChapterVideo()
// 获取视频进度
this.getChapterVideoProgress()
} }
} }
</script> </script>
...@@ -148,6 +260,7 @@ export default { ...@@ -148,6 +260,7 @@ export default {
.player-main { .player-main {
display: flex; display: flex;
flex: 1; flex: 1;
overflow: hidden;
} }
.player-column { .player-column {
flex: 1; flex: 1;
......
...@@ -19,10 +19,18 @@ ...@@ -19,10 +19,18 @@
<span>{{ppts.length}}</span> <span>{{ppts.length}}</span>
</div> </div>
<div class="ppt-player-controls__tools"> <div class="ppt-player-controls__tools">
<i :class="['el-icon-self-xuexiao', (currentSync ? 'active' : '')]" @click="onToggleSync"></i> <el-tooltip content="PPT同步视频播放">
<i class="el-icon-self-quanping" @click="fullscreen"></i> <i :class="['el-icon-self-xuexiao', (isSync ? 'active' : '')]" @click="onToggleSync"></i>
<i class="el-icon-self-shipin" @click="setVideoTime"></i> </el-tooltip>
<i class="el-icon-self-guanbi" @click="$emit('close')"></i> <el-tooltip content="放大PPT">
<i class="el-icon-self-quanping" @click="fullscreen"></i>
</el-tooltip>
<el-tooltip content="切换视频到当前PPT页">
<i class="el-icon-self-shipin" @click="setVideoTime"></i>
</el-tooltip>
<el-tooltip content="关闭PPT">
<i class="el-icon-self-guanbi" @click="$emit('close')"></i>
</el-tooltip>
</div> </div>
</div> </div>
</template> </template>
...@@ -34,20 +42,21 @@ export default { ...@@ -34,20 +42,21 @@ export default {
name: 'ppt-player', name: 'ppt-player',
props: { props: {
ppts: { type: Array }, ppts: { type: Array },
index: { type: Number, default: 0 }, index: { type: Number, default: 0 }
isSync: { type: Boolean, default: false }
}, },
data() { data() {
return { return {
currentIndex: this.index, currentIndex: this.index,
currentSync: this.isSync, isSync: true,
isFullscreen: false isFullscreen: false
} }
}, },
watch: { watch: {
index: { index: {
handler(value) { handler(value) {
this.currentIndex = value if (this.isSync) {
this.currentIndex = value
}
} }
} }
}, },
...@@ -67,20 +76,18 @@ export default { ...@@ -67,20 +76,18 @@ export default {
}, },
prev() { prev() {
this.currentIndex = this.getIndex(this.currentIndex - 1) this.currentIndex = this.getIndex(this.currentIndex - 1)
this.currentSync = false this.isSync = false
}, },
next(e) { next(e) {
this.currentIndex = this.getIndex(this.currentIndex + 1) this.currentIndex = this.getIndex(this.currentIndex + 1)
this.currentSync = false this.isSync = false
}, },
onToggleSync(e) { onToggleSync(e) {
this.currentSync = !this.currentSync this.isSync = !this.isSync
this.currentIndex = this.currentSync
? this.currentIndex
: this.currentIndex
}, },
setVideoTime(e) { setVideoTime(e) {
this.$emit('onVideoSyncTime', this.ppts[this.currentIndex].ppt_point) this.isSync = true
this.$emit('videoSyncTime', this.ppts[this.currentIndex].ppt_point)
}, },
// 全屏 // 全屏
fullscreen() { fullscreen() {
......
...@@ -13,13 +13,22 @@ export default { ...@@ -13,13 +13,22 @@ export default {
createPlayer() { createPlayer() {
const _this = this const _this = this
const { FD, LD, SD } = this.video const { FD, LD, SD } = this.video
/*
"OD" : "原画"
"FD" : "流畅"
"LD" : "标清"
"SD" : "高清"
"HD" : "超清"
"2K" : "2K"
"4K" : "4K"
*/
this.player = new Aliplayer( this.player = new Aliplayer(
{ {
id: 'player', id: 'player',
source: JSON.stringify({ FD, LD, SD }), source: JSON.stringify({ FD, LD, SD }),
width: '100%', width: '100%',
height: '100%', height: '100%',
autoplay: true, autoplay: false,
isLive: false, isLive: false,
controlBarVisibility: 'always', controlBarVisibility: 'always',
components: [ components: [
...@@ -30,6 +39,11 @@ export default { ...@@ -30,6 +39,11 @@ export default {
] ]
}, },
function(player) { function(player) {
player.on('ready', function() {
// 跳过片头
_this.isSkip && player.seek(6)
_this.$emit('ready', player)
})
player.on('sourceloaded', function(params) { player.on('sourceloaded', function(params) {
const paramData = params.paramData const paramData = params.paramData
const desc = paramData.desc const desc = paramData.desc
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
<i class="el-icon-document"></i> <i class="el-icon-document"></i>
{{ file.file_name }} {{ file.file_name }}
</a> </a>
<span v-if="file.file_size">{{ file.file_size }}</span> <!-- <span v-if="file.file_size">{{ file.file_size }}K</span> -->
<a :href="file.file_url" :download="file.file_name" target="_blank"> <a :href="file.file_url" :download="file.file_name" target="_blank">
<el-tooltip effect="dark" content="下载"> <el-tooltip effect="dark" content="下载">
<i class="el-icon-download"></i> <i class="el-icon-download"></i>
......
<template> <template>
<container :title="chapter.name" v-loading="loading"> <container :title="detail.paper_title" v-loading="loading">
<template v-slot:header-aside v-if="isSubmited">正确率:{{detail.score}}%</template> <template v-slot:header-aside v-if="isExamComplete">分数:{{exam.score.total}}</template>
<div class="exam"> <div class="exam">
<div class="exam-form"> <template v-if="isSubmited && !isExamComplete">
<el-form :disabled="isSubmited"> <div class="no-exam">试卷批改中,请耐心等待</div>
<exam-item </template>
v-for="(item, index) in unorderedQuestions" <template v-else>
:index="index" <!-- 考试期间,未开始考试 -->
:type="item.question_type" <div class="exam-welcome" v-if="!isStartExam">
:data="item" <div v-if="detail.paper_deadline">考试截止时间:{{detail.paper_deadline}}</div>
:value="item.formModel" <el-button
:disabled="isSubmited" type="primary"
:key="item.id" :disabled="!isExamTime"
></exam-item> @click="onStartExam"
<div class="exam-buttons"> >{{startExamButtonText}}</el-button>
<el-tooltip effect="dark" content="提交之后就不能修改了哦" placement="right"> </div>
<el-button type="primary" @click="onSubmit">{{submitText}}</el-button> <!-- 考试试题 -->
</el-tooltip> <div class="exam-form" v-if="isStartExam">
</div> <el-form :disabled="isSubmited">
</el-form> <template v-for="items in questions">
</div> <exam-item
v-for="(item, index) in items"
:index="index"
:type="item.type"
:data="item"
:value="item.formModel"
:disabled="isSubmited"
:key="item.id"
></exam-item>
</template>
<div class="exam-buttons">
<el-tooltip effect="dark" content="提交之后就不能修改了哦" placement="right">
<el-button type="primary" @click="onSubmit">{{submitText}}</el-button>
</el-tooltip>
</div>
</el-form>
</div>
</template>
</div> </div>
</container> </container>
</template> </template>
<script> <script>
// libs import Base64 from 'Base64'
import { shuffle } from 'lodash'
// components // components
import Container from '../common/container.vue' import Container from '../common/container.vue'
import ExamItem from './examItem.vue' import ExamItem from './examItem.vue'
...@@ -44,23 +61,33 @@ export default { ...@@ -44,23 +61,33 @@ export default {
default() { default() {
return {} return {}
} }
},
// 课程详情接口返回的数据
data: {
type: Object,
default() {
return {}
}
} }
}, },
data() { data() {
return { return {
loading: false, loading: false,
detail: null, detail: {},
questions: [], // 问题列表 questions: [],
startTime: new Date().getTime(), // 进入时间 messageInstance: null,
messageInstance: null exam: {},
isStartExam: false, // 是否开始考试
autoSubmitTimer: null // 自动提交定时器
} }
}, },
watch: { watch: {
chapter: { chapter: {
immediate: true, immediate: true,
handler(data) { handler(data) {
this.questions = data.homework this.detail = data.paper
? this.genQuenstions(data.homework.questions) this.questions = data.paper
? this.genQuestions(data.paper.examination)
: [] : []
} }
} }
...@@ -78,19 +105,28 @@ export default { ...@@ -78,19 +105,28 @@ export default {
pid() { pid() {
return this.$route.params.id return this.$route.params.id
}, },
// 资源ID // 是否是考试时间
resourceId() { isExamTime() {
return this.chapter.resource_id if (!this.detail.paper_deadline) {
return true
}
// 大于开始时间,小于结束时间
const endTime = +new Date(this.exam.paper_deadline)
const currentTime = new Date().getTime()
return currentTime < endTime
}, },
// 打乱顺序的问题列表 // 考试按钮
unorderedQuestions() { startExamButtonText() {
const ids = this.questions.map(item => item.id) return this.isExamTime ? '开始考试' : '考试结束'
const sortIds = shuffle(ids) },
return sortIds.map(id => this.questions.find(item => item.id === id)) // 考试完成
isExamComplete() {
// 考试完成,批改完成并且公布成绩
return this.exam.is_published === 1 && this.exam.type === 2
}, },
// 是否提交 // 是否提交
isSubmited() { isSubmited() {
return this.detail ? !!this.detail.work_contents : false return this.exam.type === 1 || this.exam.type === 2
}, },
// 提交按钮文本 // 提交按钮文本
submitText() { submitText() {
...@@ -98,86 +134,78 @@ export default { ...@@ -98,86 +134,78 @@ export default {
} }
}, },
methods: { methods: {
// 获取测试答题详情 // 开始考试
getDetail() { onStartExam() {
this.loading = true this.isStartExam = true
api // 自动提交答题
.getChapterExam(this.sid, this.cid, this.resourceId) this.autoSubmit()
.then(response => {
this.detail = Array.isArray(response) ? null : response
if (this.detail) {
const parseAnswers = JSON.parse(this.detail.work_contents)
// 设置答案
this.questions = this.questions.map(item => {
const found = parseAnswers.find(
answer => answer.question_id === item.id
)
if (found) {
const selectedIds = found.options.reduce((result, item) => {
item.selected && result.push(item.id)
return result
}, [])
item.user_answer =
item.question_type === 2 ? selectedIds : selectedIds[0]
}
return item
})
this.questions = this.genQuenstions(this.questions)
}
})
.finally(() => {
this.loading = false
})
}, },
// 组装问题数据 // 组装问题数据
genQuenstions(list) { genQuestions(list) {
if (!list) { if (!list) {
return [] return []
} }
return list.map(item => { return list.map(data => {
let temp = null let { radioList, checkboxList, shortAnswerList } = data
if (item.question_type === 1) { // 单选
// 单选 radioList = radioList.map(item => {
temp = { const temp = {
type: 1,
formModel: { id: item.id, user_answer: item.user_answer || '' } formModel: { id: item.id, user_answer: item.user_answer || '' }
} }
} else if (item.question_type === 2) { return Object.assign({}, item, temp)
// 多选 })
temp = { // 多选
checkboxList = checkboxList.map(item => {
const temp = {
type: 2,
formModel: { id: item.id, user_answer: item.user_answer || [] } formModel: { id: item.id, user_answer: item.user_answer || [] }
} }
} else if (item.question_type === 3) { return Object.assign({}, item, temp)
// 简答 })
temp = { // 问答
shortAnswerList = shortAnswerList.map(item => {
const temp = {
type: 3,
formModel: { formModel: {
id: item.id, id: item.id,
user_answer: item.user_answer user_answer: item.user_answer
? Base64.decode(item.user_answer) ? Base64.decode(item.user_answer.replace(/ /gi, '+'))
: '', : '',
attachments: item.attachments || '' attachments: item.attachments || []
} }
} }
} return Object.assign({}, item, temp)
return Object.assign( })
{}, return [...radioList, ...checkboxList, ...shortAnswerList]
item,
{
content: item.question_content,
options: item.question_options
? JSON.parse(item.question_options)
: []
},
temp
)
}) })
}, },
// 获取考试结果
getExamResult() {
api
.getCourseExamResult(this.sid, this.cid, this.pid, { paper_type: 0 })
.then(response => {
// 设置问题列表数据
if (response.code !== 8001) {
this.isStartExam = true
this.exam = response
this.questions = this.genQuestions(response.sheet)
// 自动提交
if (this.isStartExam && !this.isSubmited && !this.isExamComplete) {
this.autoSubmit()
}
}
})
},
// 提交校验 // 提交校验
checkSubmit() { checkSubmit() {
const quenstions = this.questions for (let i = 0; i < this.questions.length; i++) {
for (let i = 0; i < quenstions.length; i++) { const questions = this.questions[i]
const value = quenstions[i].formModel.user_answer for (let k = 0; k < questions.length; k++) {
if (Array.isArray(value) ? !value.length : !value) { const value = questions[k].formModel.user_answer
return false if (Array.isArray(value) ? !value.length : !value) {
return false
}
} }
} }
return true return true
...@@ -190,74 +218,80 @@ export default { ...@@ -190,74 +218,80 @@ export default {
this.messageInstance = this.$message.error('还有题目未做,不能提交') this.messageInstance = this.$message.error('还有题目未做,不能提交')
return return
} }
// 计算答题时间 // 提交的答案数据
const duration = Math.floor( const answers = this.handleSubmitData()
(new Date().getTime() - this.startTime) / 1000 // 提交参数
) const params = { answers: JSON.stringify(answers), type: 1 }
// 答案数据
const data = this.handleSubmitData()
// 计算分数
const score = data.reduce((result, item) => {
item.is_correct && result++
return result
}, 0)
const total = this.questions.length
const params = {
semester_id: this.sid,
course_id: this.cid,
chapter_id: this.pid,
work_id: this.resourceId,
work_contents: JSON.stringify(data),
duration,
score: ((score / total) * 100).toFixed(1)
}
// 请求接口 // 请求接口
this.handleSubmitRequest(params) this.handleSubmitRequest(params)
}, },
// 提交的答案数据 // 自动提交
autoSubmit() {
// 10秒提交一次
this.autoSubmitTimer && clearInterval(this.autoSubmitTimer)
this.autoSubmitTimer = setInterval(() => {
// 提交的答案数据
const answers = this.handleSubmitData()
const params = { answers: JSON.stringify(answers), type: 0 }
// 请求接口
this.handleSubmitRequest(params)
}, 10000)
},
// 处理请求接口答案数据
handleSubmitData() { handleSubmitData() {
const result = this.questions.map(item => { return this.questions.map(questions => {
// 设置提交选中状态 return questions.reduce(
let isCorrect = true (result, item) => {
const options = item.options.map(option => { // 单选题
// 选择的项 if (item.type === 1) {
const answers = item.formModel.user_answer result.radioList.push(item.formModel)
// 是否选中该项 }
const selected = Array.isArray(answers) // 多选题
? answers.includes(option.id) if (item.type === 2) {
: option.id === answers result.checkboxList.push(item.formModel)
// 是否选择正确 }
if (option.checked !== selected && isCorrect) { // 简答题
isCorrect = false if (item.type === 3) {
} const formModel = Object.assign({}, item.formModel, {
return { user_answer: Base64.encode(item.formModel.user_answer)
id: option.id, })
checked: option.checked, result.shortAnswerList.push(formModel)
option: option.option, }
selected return result
} },
}) { radioList: [], checkboxList: [], shortAnswerList: [] }
return { )
question_id: item.id,
is_correct: isCorrect ? 1 : 0,
options
}
}) })
return result
}, },
// 请求提交接口 // 请求提交接口
handleSubmitRequest(params) { handleSubmitRequest(params) {
api.sbumitChapterExam(params).then(response => { params.paper_type = 0
if (response.status) { api
this.getDetail() .submitCourseExam(this.sid, this.cid, this.pid, params)
} else { .then(response => {
this.$message.error(response.data.error) if (params.type === 0) {
} console.log('暂存成功')
}) return
}
if (response.code === 200) {
this.$message.success('考试答卷提交成功')
this.autoSubmitTimer && clearInterval(this.autoSubmitTimer)
this.getExamResult()
} else {
this.$message.error(response.data.error)
}
})
.catch(error => {
this.$message.error(error.message)
})
} }
}, },
beforeMount() { beforeMount() {
this.getDetail() // 获取考试结果
this.getExamResult()
},
destroyed() {
this.autoSubmitTimer && clearInterval(this.autoSubmitTimer)
} }
} }
</script> </script>
...@@ -271,4 +305,17 @@ export default { ...@@ -271,4 +305,17 @@ export default {
margin: 40px auto; margin: 40px auto;
} }
} }
.no-exam {
padding: 100px;
font-size: 30px;
text-align: center;
}
.exam-welcome {
padding: 40px;
line-height: 30px;
text-align: center;
::v-deep .el-button {
margin-top: 30px;
}
}
</style> </style>
<template>
<container :title="chapter.name" v-loading="loading">
<template v-slot:header-aside v-if="isSubmited">正确率:{{detail.score}}%</template>
<div class="exam">
<div class="exam-form">
<el-form :disabled="isSubmited">
<exam-item
v-for="(item, index) in unorderedQuestions"
:index="index"
:type="item.question_type"
:data="item"
:value="item.formModel"
:disabled="isSubmited"
:key="item.id"
></exam-item>
<div class="exam-buttons">
<el-tooltip effect="dark" content="提交之后就不能修改了哦" placement="right">
<el-button type="primary" @click="onSubmit">{{submitText}}</el-button>
</el-tooltip>
</div>
</el-form>
</div>
</div>
</container>
</template>
<script>
// libs
import { shuffle } from 'lodash'
// components
import Container from '../common/container.vue'
import ExamItem from './examItem.vue'
// api
import * as api from '../../api'
// 章节测试题
export default {
name: 'ChapterTest',
components: { Container, ExamItem },
props: {
// 当前选中的章节
chapter: {
type: Object,
default() {
return {}
}
}
},
data() {
return {
loading: false,
detail: null,
questions: [], // 问题列表
startTime: new Date().getTime(), // 进入时间
messageInstance: null
}
},
watch: {
chapter: {
immediate: true,
handler(data) {
this.questions = data.homework
? this.genQuenstions(data.homework.questions)
: []
}
}
},
computed: {
// 学期ID
sid() {
return this.$route.params.sid
},
// 课程ID
cid() {
return this.$route.params.cid
},
// 当前页面的ID
pid() {
return this.$route.params.id
},
// 资源ID
resourceId() {
return this.chapter.resource_id
},
// 打乱顺序的问题列表
unorderedQuestions() {
const ids = this.questions.map(item => item.id)
const sortIds = shuffle(ids)
return sortIds.map(id => this.questions.find(item => item.id === id))
},
// 是否提交
isSubmited() {
return this.detail ? !!this.detail.work_contents : false
},
// 提交按钮文本
submitText() {
return this.isSubmited ? '已提交' : '提交'
}
},
methods: {
// 获取测试答题详情
getDetail() {
this.loading = true
api
.getChapterExam(this.sid, this.cid, this.resourceId)
.then(response => {
this.detail = Array.isArray(response) ? null : response
if (this.detail) {
const parseAnswers = JSON.parse(this.detail.work_contents)
// 设置答案
this.questions = this.questions.map(item => {
const found = parseAnswers.find(
answer => answer.question_id === item.id
)
if (found) {
const selectedIds = found.options.reduce((result, item) => {
item.selected && result.push(item.id)
return result
}, [])
item.user_answer =
item.question_type === 2 ? selectedIds : selectedIds[0]
}
return item
})
this.questions = this.genQuenstions(this.questions)
}
})
.finally(() => {
this.loading = false
})
},
// 组装问题数据
genQuenstions(list) {
if (!list) {
return []
}
return list.map(item => {
let temp = null
if (item.question_type === 1) {
// 单选
temp = {
formModel: { id: item.id, user_answer: item.user_answer || '' }
}
} else if (item.question_type === 2) {
// 多选
temp = {
formModel: { id: item.id, user_answer: item.user_answer || [] }
}
} else if (item.question_type === 3) {
// 简答
temp = {
formModel: {
id: item.id,
user_answer: item.user_answer
? Base64.decode(item.user_answer)
: '',
attachments: item.attachments || ''
}
}
}
return Object.assign(
{},
item,
{
content: item.question_content,
options: item.question_options
? JSON.parse(item.question_options)
: []
},
temp
)
})
},
// 提交校验
checkSubmit() {
const quenstions = this.questions
for (let i = 0; i < quenstions.length; i++) {
const value = quenstions[i].formModel.user_answer
if (Array.isArray(value) ? !value.length : !value) {
return false
}
}
return true
},
// 提交
onSubmit() {
// 校验
if (!this.checkSubmit()) {
this.messageInstance && this.messageInstance.close()
this.messageInstance = this.$message.error('还有题目未做,不能提交')
return
}
// 计算答题时间
const duration = Math.floor(
(new Date().getTime() - this.startTime) / 1000
)
// 答案数据
const data = this.handleSubmitData()
// 计算分数
const score = data.reduce((result, item) => {
item.is_correct && result++
return result
}, 0)
const total = this.questions.length
const params = {
semester_id: this.sid,
course_id: this.cid,
chapter_id: this.pid,
work_id: this.resourceId,
work_contents: JSON.stringify(data),
duration,
score: ((score / total) * 100).toFixed(1)
}
// 请求接口
this.handleSubmitRequest(params)
},
// 提交的答案数据
handleSubmitData() {
const result = this.questions.map(item => {
// 设置提交选中状态
let isCorrect = true
const options = item.options.map(option => {
// 选择的项
const answers = item.formModel.user_answer
// 是否选中该项
const selected = Array.isArray(answers)
? answers.includes(option.id)
: option.id === answers
// 是否选择正确
if (option.checked !== selected && isCorrect) {
isCorrect = false
}
return {
id: option.id,
checked: option.checked,
option: option.option,
selected
}
})
return {
question_id: item.id,
is_correct: isCorrect ? 1 : 0,
options
}
})
return result
},
// 请求提交接口
handleSubmitRequest(params) {
api.sbumitChapterExam(params).then(response => {
if (response.status) {
this.getDetail()
} else {
this.$message.error(response.data.error)
}
})
}
},
beforeMount() {
this.getDetail()
}
}
</script>
<style lang="scss" scoped>
.exam-buttons {
padding: 40px 0;
text-align: center;
.el-button {
width: 240px;
margin: 40px auto;
}
}
</style>
...@@ -214,12 +214,12 @@ export default { ...@@ -214,12 +214,12 @@ export default {
) )
// 提交的答案数据 // 提交的答案数据
const answers = this.questions.map(item => { const answers = this.questions.map(item => {
if (item.question_type === 3) {
item.formModel.user_answer = Base64.encode(item.formModel.user_answer)
}
return { return {
question_id: item.id, question_id: item.id,
descreption: item.formModel.user_answer, descreption:
item.question_type === 3
? Base64.encode(item.formModel.user_answer)
: item.formModel.user_answer,
file_url: item.formModel.attachments, file_url: item.formModel.attachments,
is_encoded: 1 is_encoded: 1
} }
......
<template> <template>
<container :title="detail.title" v-loading="loading"> <container :title="detail.title" v-loading="loading">
<template v-slot:header-aside v-if="isExamComplete">分数:{{exam.score.total}}</template>
<div class="exam"> <div class="exam">
<template v-if="status.examination_status === '00'"> <template v-if="status.examination_status === '00'">
<div class="no-exam">暂无考试</div> <div class="no-exam">暂无考试</div>
...@@ -17,39 +18,20 @@ ...@@ -17,39 +18,20 @@
@click="onStartExam" @click="onStartExam"
>{{startExamButtonText}}</el-button> >{{startExamButtonText}}</el-button>
</div> </div>
<!-- 考试完成 -->
<div class="exam-finish" v-if="isExamComplete">
<table class="exam-table">
<tr>
<th>单选</th>
<th>多选</th>
<th>简答</th>
</tr>
<tr>
<td>{{exam.score.radio}}</td>
<td>{{exam.score.checkbox}}</td>
<td>{{exam.score.shortAnswer}}</td>
</tr>
<tr>
<td colspan="3">
<div class="exam-total">总分:{{exam.score.total}}</div>
</td>
</tr>
</table>
<el-button type="text" @click="examVisible = !examVisible">查看试卷</el-button>
</div>
<!-- 考试试题 --> <!-- 考试试题 -->
<div class="exam-form" v-if="isStartExam" v-show="examVisible"> <div class="exam-form" v-if="isStartExam">
<el-form :disabled="isSubmited"> <el-form :disabled="isSubmited">
<exam-item <template v-for="items in questions">
v-for="(item, index) in questions" <exam-item
:index="index" v-for="(item, index) in items"
:type="item.type" :index="index"
:data="item" :type="item.type"
:value="item.formModel" :data="item"
:disabled="isSubmited" :value="item.formModel"
:key="item.id" :disabled="isSubmited"
></exam-item> :key="item.id"
></exam-item>
</template>
<div class="exam-buttons"> <div class="exam-buttons">
<el-tooltip effect="dark" content="提交之后就不能修改了哦" placement="right"> <el-tooltip effect="dark" content="提交之后就不能修改了哦" placement="right">
<el-button type="primary" @click="onSubmit">{{submitText}}</el-button> <el-button type="primary" @click="onSubmit">{{submitText}}</el-button>
...@@ -97,18 +79,11 @@ export default { ...@@ -97,18 +79,11 @@ export default {
detail: {}, detail: {},
status: {}, status: {},
questions: [], questions: [],
values: [], // 提交的答案
messageInstance: null, messageInstance: null,
exam: {}, exam: {},
isStartExam: false, // 是否开始考试 isStartExam: false, // 是否开始考试
autoSubmitTimer: null, // 自动提交定时器 autoSubmitTimer: null, // 自动提交定时器
checkStatusTimer: null, // 考试状态定时器 checkStatusTimer: null // 考试状态定时器
examVisible: true
}
},
watch: {
isExamComplete(value) {
this.examVisible = !value
} }
}, },
computed: { computed: {
...@@ -163,7 +138,7 @@ export default { ...@@ -163,7 +138,7 @@ export default {
this.detail = Array.isArray(response) ? null : response this.detail = Array.isArray(response) ? null : response
// 设置问题列表数据 // 设置问题列表数据
this.questions = this.detail this.questions = this.detail
? this.genQuenstions(this.detail.examination) ? this.genQuestions(this.detail.examination)
: [] : []
callback && callback() callback && callback()
}) })
...@@ -172,42 +147,44 @@ export default { ...@@ -172,42 +147,44 @@ export default {
}) })
}, },
// 组装问题数据 // 组装问题数据
genQuenstions(data) { genQuestions(list) {
if (!data) { if (!list) {
return return []
} }
let { radioList, checkboxList, shortAnswerList } = data return list.map(data => {
// 单选 let { radioList, checkboxList, shortAnswerList } = data
radioList = radioList.map(item => { // 单选
const temp = { radioList = radioList.map(item => {
type: 1, const temp = {
formModel: { id: item.id, user_answer: item.user_answer || '' } type: 1,
} formModel: { id: item.id, user_answer: item.user_answer || '' }
return Object.assign({}, item, temp)
})
// 多选
checkboxList = checkboxList.map(item => {
const temp = {
type: 2,
formModel: { id: item.id, user_answer: item.user_answer || [] }
}
return Object.assign({}, item, temp)
})
// 问答
shortAnswerList = shortAnswerList.map(item => {
const temp = {
type: 3,
formModel: {
id: item.id,
user_answer: item.user_answer
? Base64.decode(item.user_answer)
: '',
attachments: []
} }
} return Object.assign({}, item, temp)
return Object.assign({}, item, temp) })
// 多选
checkboxList = checkboxList.map(item => {
const temp = {
type: 2,
formModel: { id: item.id, user_answer: item.user_answer || [] }
}
return Object.assign({}, item, temp)
})
// 问答
shortAnswerList = shortAnswerList.map(item => {
const temp = {
type: 3,
formModel: {
id: item.id,
user_answer: item.user_answer
? Base64.decode(item.user_answer.replace(/ /gi, '+'))
: '',
attachments: item.attachments || []
}
}
return Object.assign({}, item, temp)
})
return [...radioList, ...checkboxList, ...shortAnswerList]
}) })
return [...radioList, ...checkboxList, ...shortAnswerList]
}, },
// 获取考试状态 // 获取考试状态
getExamStatus() { getExamStatus() {
...@@ -234,7 +211,7 @@ export default { ...@@ -234,7 +211,7 @@ export default {
if (response.code !== 8001) { if (response.code !== 8001) {
this.isStartExam = true this.isStartExam = true
this.exam = response this.exam = response
this.questions = this.genQuenstions(response.sheet) this.questions = this.genQuestions(response.sheet)
// 自动提交 // 自动提交
if (this.isStartExam && !this.isSubmited && !this.isExamComplete) { if (this.isStartExam && !this.isSubmited && !this.isExamComplete) {
this.autoSubmit() this.autoSubmit()
...@@ -244,11 +221,13 @@ export default { ...@@ -244,11 +221,13 @@ export default {
}, },
// 提交校验 // 提交校验
checkSubmit() { checkSubmit() {
const quenstions = this.questions for (let i = 0; i < this.questions.length; i++) {
for (let i = 0; i < quenstions.length; i++) { const questions = this.questions[i]
const value = quenstions[i].formModel.user_answer for (let k = 0; k < questions.length; k++) {
if (Array.isArray(value) ? !value.length : !value) { const value = questions[k].formModel.user_answer
return false if (Array.isArray(value) ? !value.length : !value) {
return false
}
} }
} }
return true return true
...@@ -262,12 +241,7 @@ export default { ...@@ -262,12 +241,7 @@ export default {
return return
} }
// 提交的答案数据 // 提交的答案数据
const answers = this.questions.map(item => { const answers = this.handleSubmitData()
if (item.type === 3) {
item.formModel.user_answer = Base64.encode(item.formModel.user_answer)
}
return item.formModel
})
// 提交参数 // 提交参数
const params = { answers: JSON.stringify(answers), type: 1 } const params = { answers: JSON.stringify(answers), type: 1 }
// 请求接口 // 请求接口
...@@ -279,19 +253,38 @@ export default { ...@@ -279,19 +253,38 @@ export default {
this.autoSubmitTimer && clearInterval(this.autoSubmitTimer) this.autoSubmitTimer && clearInterval(this.autoSubmitTimer)
this.autoSubmitTimer = setInterval(() => { this.autoSubmitTimer = setInterval(() => {
// 提交的答案数据 // 提交的答案数据
const answers = this.questions.map(item => { const answers = this.handleSubmitData()
if (item.type === 3) {
item.formModel.user_answer = Base64.encode(
item.formModel.user_answer
)
}
return item.formModel
})
const params = { answers: JSON.stringify(answers), type: 0 } const params = { answers: JSON.stringify(answers), type: 0 }
// 请求接口 // 请求接口
this.handleSubmitRequest(params) this.handleSubmitRequest(params)
}, 10000) }, 10000)
}, },
// 处理请求接口答案数据
handleSubmitData() {
return this.questions.map(questions => {
return questions.reduce(
(result, item) => {
// 单选题
if (item.type === 1) {
result.radioList.push(item.formModel)
}
// 多选题
if (item.type === 2) {
result.checkboxList.push(item.formModel)
}
// 简答题
if (item.type === 3) {
const formModel = Object.assign({}, item.formModel, {
user_answer: Base64.encode(item.formModel.user_answer)
})
result.shortAnswerList.push(formModel)
}
return result
},
{ radioList: [], checkboxList: [], shortAnswerList: [] }
)
})
},
// 请求提交接口 // 请求提交接口
handleSubmitRequest(params) { handleSubmitRequest(params) {
api api
...@@ -344,27 +337,6 @@ export default { ...@@ -344,27 +337,6 @@ export default {
font-size: 30px; font-size: 30px;
text-align: center; text-align: center;
} }
.exam-finish {
margin: 40px 0;
}
.exam-table {
width: 100%;
border-collapse: collapse;
th {
background-color: #ccc;
}
td,
th {
padding: 10px;
border: 1px solid #999;
text-align: center;
}
}
.exam-total {
font-size: 18px;
text-align: right;
padding: 0 40px;
}
.exam-welcome { .exam-welcome {
padding: 40px; padding: 40px;
line-height: 30px; line-height: 30px;
......
...@@ -109,7 +109,7 @@ export default { ...@@ -109,7 +109,7 @@ export default {
rules: { rules: {
essay_name: [ essay_name: [
{ required: true, message: '请输入主题', trigger: 'blur' }, { required: true, message: '请输入主题', trigger: 'blur' },
{ max: 5, message: '最多输入 50 个字符', trigger: 'blur' } { max: 50, message: '最多输入 50 个字符', trigger: 'blur' }
], ],
essay_description: [ essay_description: [
{ required: true, message: '请输入正文', trigger: 'blur' } { required: true, message: '请输入正文', trigger: 'blur' }
......
...@@ -2,8 +2,11 @@ ...@@ -2,8 +2,11 @@
<div class="q-item"> <div class="q-item">
<div class="q-item-hd"> <div class="q-item-hd">
<div class="q-item-num">{{index + 1}}.</div> <div class="q-item-num">{{index + 1}}.</div>
<div class="q-item-title" v-html="data.content">{{data.title}}</div> <div class="q-item-title" v-html="data.content"></div>
<div class="q-item-aside" v-if="typeText">({{typeText}})</div> <div class="q-item-aside">
<template v-if="typeText">({{typeText}})</template>
<template v-if="data.hasOwnProperty('score')">({{data.score}}分)</template>
</div>
</div> </div>
<div class="q-item-bd"> <div class="q-item-bd">
<!-- 单选 --> <!-- 单选 -->
...@@ -21,26 +24,44 @@ ...@@ -21,26 +24,44 @@
<!-- 简答题 --> <!-- 简答题 -->
<template v-if="type === 3"> <template v-if="type === 3">
<v-editor v-model="currentValue.user_answer" :disabled="disabled"></v-editor> <v-editor v-model="currentValue.user_answer" :disabled="disabled"></v-editor>
<v-upload v-model="currentValue.attachments">请上传对应的文件附件:</v-upload> <v-upload :disabled="disabled" v-model="currentValue.attachments">请上传对应的文件附件:</v-upload>
</template> </template>
</div> </div>
<div class="q-item-ft" v-if="disabled"> <div class="q-item-ft" v-if="disabled">
<template v-if="type === 3"> <template v-if="type === 3">
<p> <p>
<span>老师评语:</span> <span>评语:</span>
<span>{{data.check_comment}}</span> <span>{{data.check_comment}}</span>
</p> </p>
</template> </template>
<template v-else> <template v-else>
<p> <div class="result">
<span>学生答案:</span> <p>
<span :class="isCorrect ? 'is-success' : 'is-error'">{{submitAnswerText}}</span> <span>学生答案:</span>
</p> <span :class="isCorrect ? 'is-success' : 'is-error'">{{submitAnswerText}}</span>
<p> </p>
<span>正确答案:</span> <p>
<span>{{correctAnswerText}}</span> <span>正确答案:</span>
</p> <span>{{correctAnswerText}}</span>
</p>
</div>
</template> </template>
<p v-if="data.hasOwnProperty('get_score')">
<span>评分:</span>
<span>{{data.get_score}}分</span>
</p>
<div class="analyze" v-if="data.analysis">
<span>解析:</span>
<div class="analyze-main">
<span style="color:blue;cursor:pointer;" @click="showAnalyze = !showAnalyze">查看解析</span>
<div
v-html="data.analysis"
v-if="data.analysis"
v-show="showAnalyze"
class="analyze-content"
></div>
</div>
</div>
</div> </div>
</div> </div>
</template> </template>
...@@ -77,7 +98,8 @@ export default { ...@@ -77,7 +98,8 @@ export default {
}, },
data() { data() {
return { return {
currentValue: {} currentValue: {},
showAnalyze: false
} }
}, },
watch: { watch: {
...@@ -116,6 +138,14 @@ export default { ...@@ -116,6 +138,14 @@ export default {
item.selected = Array.isArray(value) item.selected = Array.isArray(value)
? value.includes(item.id) ? value.includes(item.id)
: value === item.id : value === item.id
// 处理正确的选中状态
const hasChecked = Object.prototype.hasOwnProperty.call(item, 'checked')
const rightAnswer = this.data.right_answer || ''
if (!hasChecked && rightAnswer) {
item.checked = Array.isArray(rightAnswer)
? rightAnswer.includes(item.id)
: rightAnswer === item.id
}
return item return item
}) })
}, },
...@@ -190,14 +220,16 @@ export default { ...@@ -190,14 +220,16 @@ export default {
} }
.q-item-title { .q-item-title {
flex: 1; flex: 1;
padding: 0 10px; ::v-deep img {
max-width: 100%;
}
} }
.q-item-aside { .q-item-aside {
padding-left: 20px; padding-left: 20px;
// align-self: flex-end; // align-self: flex-end;
} }
.q-option-item { .q-option-item {
padding-left: 30px; padding-left: 20px;
margin-bottom: 14px; margin-bottom: 14px;
} }
.is-success { .is-success {
...@@ -229,13 +261,36 @@ export default { ...@@ -229,13 +261,36 @@ export default {
} }
} }
.q-item-ft { .q-item-ft {
display: flex;
justify-content: flex-end;
padding: 10px 0; padding: 10px 0;
p { p {
font-size: 14px; font-size: 14px;
margin: 0; margin: 0 0 10px 0;
padding-left: 20px; }
.result {
display: flex;
justify-content: flex-end;
p {
padding-left: 20px;
}
}
.analyze {
display: flex;
font-size: 14px;
}
.analyze-main {
flex: 1;
overflow: hidden;
}
.analyze-content {
margin-top: 10px;
background-color: #c9c9c97a;
border: 1px solid #c9c9c97a;
padding: 10px;
::v-deep * {
margin: 0;
padding: 0;
max-width: 100%;
}
} }
} }
</style> </style>
...@@ -12,11 +12,11 @@ ...@@ -12,11 +12,11 @@
<script> <script>
// componets // componets
import ChapterWork from './chapterWork.vue' import ChapterWork from './chapterWork.vue'
import ChapterExam from './chapterExam.vue' import ChapterTest from './ChapterTest.vue'
export default { export default {
name: 'ViewerWork', name: 'ViewerWork',
components: { ChapterWork, ChapterExam }, components: { ChapterWork, ChapterTest },
props: { props: {
// 当前选中的 // 当前选中的
chapter: { chapter: {
...@@ -36,7 +36,7 @@ export default { ...@@ -36,7 +36,7 @@ export default {
computed: { computed: {
currentCompoent() { currentCompoent() {
const componentNames = { const componentNames = {
1: 'ChapterExam', // 考试 1: 'ChapterTest', // 课后测验
2: 'ChapterWork' // 作业 2: 'ChapterWork' // 作业
} }
const homework = this.chapter.homework const homework = this.chapter.homework
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
<h1 class="course-viewer-main-hd__title">{{ detail.course_name }}</h1> <h1 class="course-viewer-main-hd__title">{{ detail.course_name }}</h1>
<!-- 直播的时候显示帮助按钮 --> <!-- 直播的时候显示帮助按钮 -->
<template v-if="isLive"> <template v-if="isLive">
<router-link to="/app/account/feedbackCreate" target="_blank"> <router-link to="/app/feedback/feedback-create" target="_blank">
<el-tooltip effect="light" content="意见反馈"> <el-tooltip effect="light" content="意见反馈">
<i class="el-icon-self-fankuiyijian"></i> <i class="el-icon-self-fankuiyijian"></i>
</el-tooltip> </el-tooltip>
...@@ -35,6 +35,7 @@ ...@@ -35,6 +35,7 @@
</div> </div>
<!-- 侧边栏 --> <!-- 侧边栏 -->
<v-aside <v-aside
:data="detail"
:chapters="chapters" :chapters="chapters"
:active="activeChapter" :active="activeChapter"
:ppts="ppts" :ppts="ppts"
...@@ -92,10 +93,17 @@ export default { ...@@ -92,10 +93,17 @@ export default {
children: [ children: [
{ name: '课程大作业', id: 'course_work', type: 99 }, { name: '课程大作业', id: 'course_work', type: 99 },
{ name: '课程资料', id: 'course_info', type: 100 }, { name: '课程资料', id: 'course_info', type: 100 },
{ name: '教学评估', id: 'teach_evaluation', type: 102 }, { name: '教学评估', id: 'teach_evaluation', type: 102 }
{ name: '课程考试', id: 'course_exam', type: 101 }
] ]
} }
// 课程考试
if (this.detail.course_examination) {
customeChapter.children.push({
name: '课程考试',
id: 'course_exam',
type: 101
})
}
chapters.push(customeChapter) chapters.push(customeChapter)
return chapters return chapters
}, },
......
...@@ -193,7 +193,7 @@ export default { ...@@ -193,7 +193,7 @@ export default {
}, },
/* 直接进直播 */ /* 直接进直播 */
goLive () { goLive () {
this.$router.push({ path: `/player/${this.newLiveMsg.semester_id}/${this.newLiveMsg.course_id}/live/${this.newLiveMsg.live.id}` }) this.$router.push({ name: 'viewerCourseChapter', params: { sid: this.newLiveMsg.semester_id, cid: this.newLiveMsg.course_id, id: this.newLiveMsg.chapter_id } })
} }
} }
} }
......
...@@ -4,11 +4,11 @@ ...@@ -4,11 +4,11 @@
<div class="detail-box"> <div class="detail-box">
<div class="box-thd"> <div class="box-thd">
<div class="title" @click="noWantThisCourse">{{headerInfo.title}} <div class="title" @click="noWantThisCourse">{{headerInfo.title}}
<template v-if='headerInfo.isStart && tabs[1].chapterList.currentChapterId'> <template v-if='headerInfo.isStart && tabs[1].chapterList.currentChapter'>
<el-button class="rbtn" type="primary" size="mini" @click='startLearn' :data-cid='cid' :data-sid='sid' :data-type='tabs[1].chapterList.currentVideoProvider' :data-vid='tabs[1].chapterList.currentChapterId'>继续学习</el-button> <el-button class="rbtn" type="primary" size="mini" @click='startLearn(tabs[1].chapterList.currentChapter)'>继续学习</el-button>
</template> </template>
<template v-else-if='headerInfo.isStart'> <template v-else-if='headerInfo.isStart'>
<el-button class="rbtn" type="primary" size="mini" @click='startLearn' :data-cid='cid' :data-sid='sid' :data-type='firstVideo.video_provider' :data-vid='firstVideo.vid'>开始学习</el-button> <el-button class="rbtn" type="primary" size="mini" @click='startLearn(firstVideo)'>开始学习</el-button>
</template> </template>
<template v-else> <template v-else>
<el-button class="rbtn" type="primary" size="mini" @click='wantThisCourse'>选课</el-button> <el-button class="rbtn" type="primary" size="mini" @click='wantThisCourse'>选课</el-button>
...@@ -43,12 +43,12 @@ ...@@ -43,12 +43,12 @@
<div class='course-list'> <div class='course-list'>
<template v-for="(_item, index) in tabs[1].chapterList.course"> <template v-for="(_item, index) in tabs[1].chapterList.course">
<div v-bind:key="index" :class='["content-group", (!_item.chapters.length ? "no-child" : ""), (_item.isUp ? "up" : "")]'> <div v-bind:key="index" :class='["content-group", (!_item.chapters.length ? "no-child" : ""), (_item.isUp ? "up" : "")]'>
<div class='title' @click='clickJumpOrStatus($event)' :data-index='index' :data-cid='_item.cid' :data-sid='_item.sid' :data-status='!!_item.chapters.length'>{{_item.title}} <div class='title' @click='clickJumpOrStatus(index, _item)'>{{_item.title}}
<i :class="['side', (_item.chapters.length ? '' : 'none'), (_item.isUp ? 'el-icon-arrow-down' : 'el-icon-arrow-up')]"></i> <i :class="['side', (_item.chapters.length ? '' : 'none'), (_item.isUp ? 'el-icon-arrow-down' : 'el-icon-arrow-up')]"></i>
</div> </div>
<template v-for="(item1, index1) in _item.chapters"> <template v-for="(item1, index1) in _item.chapters">
<div v-bind:key="index1" :class='["body", (item1.id === tabs[1].chapterList.currentChapterId && "on")]'> <div v-bind:key="index1" :class='["body", (item1.id === tabs[1].chapterList.currentChapterId && "on")]'>
<div class='name' :data-vid='item1.vid' :data-cid='item1.cid' :data-sid='item1.sid' :data-hasVA='item1.time' :data-type="item1.video_provider" :data-name='item1.name' :data-index='index' :data-count='index1' @click='jumpToOtherVA'> <div class='name' :data-vid='item1.vid' :data-cid='item1.cid' :data-sid='item1.sid' :data-hasVA='item1.time' :data-type="item1.video_provider" :data-name='item1.name' :data-index='index' :data-count='index1' @click='jumpToOtherVA(item1)'>
{{item1.name}} {{item1.name}}
<template v-if='item1.type === 5'> <template v-if='item1.type === 5'>
<div class='time'>{{ item1.live.start_time }} {{ item1.live.statusStr }}</div> <div class='time'>{{ item1.live.start_time }} {{ item1.live.statusStr }}</div>
...@@ -74,28 +74,6 @@ ...@@ -74,28 +74,6 @@
<div :class='["item-order", (sort[1].isShow ? "on" : "")]' @click='sortFn' :data-index='1' :data-str='sort[1].str'>按投票排序</div> <div :class='["item-order", (sort[1].isShow ? "on" : "")]' @click='sortFn' :data-index='1' :data-str='sort[1].str'>按投票排序</div>
</div> </div>
<div class='discuss-scroll' bindscrolltolower='loadmore' bindscrolltoupper='updatenew'> <div class='discuss-scroll' bindscrolltolower='loadmore' bindscrolltoupper='updatenew'>
<!-- <template v-for='(item, index) in discussList'>
<div v-bind:key="index" class='item-list' @click='goDiscussDetail' :data-id='item.id' :data-sid='item.sid' :data-index='index'>
<div class='user'>
<template v-if="item.user.url">
<img class='img' :src='item.user.url' />
</template>
<template v-else>
<img class='img' src='@/assets/images/person-default.jpg' />
</template>
<div class='right'>
<div class='name'>{{item.user.name}}</div>
<div class='time'>{{item.user.time}}</div>
</div>
</div>
<div class='title'>{{item.title}}</div>
<div :class='["text"]' v-html="item.text"></div><div :class='["ellipsis", (item.isShow ? "on" : "")]'>....</div>
<div class='result'>{{item.askCnt}} 回答<div style='display: inline-block; width: 20px;'></div>{{item.TouCnt}} 投票</div>
</div>
</template>
<template v-if='!discussList.length'>
<div class='no-data'>暂无相关讨论</div>
</template> -->
<discuss :params="params"></discuss> <discuss :params="params"></discuss>
</div> </div>
</template> </template>
...@@ -109,7 +87,6 @@ ...@@ -109,7 +87,6 @@
<el-form-item label="标题" prop="title"> <el-form-item label="标题" prop="title">
<el-input v-model="publish.title" type="text" placeholder="请输入标题"></el-input> <el-input v-model="publish.title" type="text" placeholder="请输入标题"></el-input>
</el-form-item> </el-form-item>
<!-- v-model="publish.content" -->
<div style="line-height: 1.5; font-size: 0.16rem; margin-bottom: 0.2rem;">正文内容</div> <div style="line-height: 1.5; font-size: 0.16rem; margin-bottom: 0.2rem;">正文内容</div>
<textarea id="editor"></textarea> <textarea id="editor"></textarea>
<div style="height: 0.2rem;"></div> <div style="height: 0.2rem;"></div>
...@@ -146,7 +123,7 @@ ...@@ -146,7 +123,7 @@
<div class='tt'>{{item1.title}}</div> <div class='tt'>{{item1.title}}</div>
<template v-for='(item2, index) in item1.arr'> <template v-for='(item2, index) in item1.arr'>
<div v-bind:key="index" class='rd'> <div v-bind:key="index" class='rd'>
<div class='col3-td1' :data-sid='item1.sid' :data-cid='item1.cid' :data-vid='item2.vid' :data-type='item2.type' :data-duration='item2.duration' @mousedown="jumpVAOrfinishVA($event)">{{item2.name}}</div> <div class='col3-td1' :data-sid='item1.sid' :data-cid='item1.cid' :data-vid='item2.vid' :data-id='item2.id' :data-type='item2.type' :data-duration='item2.duration' @mousedown="jumpVAOrfinishVA($event)">{{item2.name}}</div>
<div class='col3-td2'>{{item2.time}}</div> <div class='col3-td2'>{{item2.time}}</div>
<div class='col3-td3'>{{item2.progress}}</div> <div class='col3-td3'>{{item2.progress}}</div>
</div> </div>
...@@ -214,8 +191,6 @@ ...@@ -214,8 +191,6 @@
</el-row> </el-row>
</div> </div>
</div> </div>
<!-- v-model="setArtContent.content" -->
<!-- <textarea id="editor"></textarea> -->
</template> </template>
<script> <script>
...@@ -375,7 +350,6 @@ export default { ...@@ -375,7 +350,6 @@ export default {
this.tabs[0].content = json.tabs0Content this.tabs[0].content = json.tabs0Content
this.tabs[1].chapterList = json.tabs1ChapterList this.tabs[1].chapterList = json.tabs1ChapterList
json.tabs3richTest && (this.tabs[3].richText = json.tabs3richTest) json.tabs3richTest && (this.tabs[3].richText = json.tabs3richTest)
// 设置开始学习的视频 // 设置开始学习的视频
const courseList = json.tabs1ChapterList.course const courseList = json.tabs1ChapterList.course
for (let i = 0; i < courseList.length; i++) { for (let i = 0; i < courseList.length; i++) {
...@@ -485,41 +459,28 @@ export default { ...@@ -485,41 +459,28 @@ export default {
/** /**
* 课程内容 - 列表展开或者跳转 * 课程内容 - 列表展开或者跳转
*/ */
clickJumpOrStatus (e) { clickJumpOrStatus (index, data) {
const data = e.currentTarget.dataset const flag = !!data.chapters.length
const flag = data.status
if (flag) { if (flag) {
const index = data.index
const json = this.tabs const json = this.tabs
const temp = json[1].chapterList.course[index] const temp = json[1].chapterList.course[index]
temp.isUp = !temp.isUp temp.isUp = !temp.isUp
} else { } else {
/* 进入详情页,不管是哪个,都存localstorage */ /* 进入详情页,不管是哪个,都存localstorage */
window.localStorage.setItem('headerInfo', JSON.stringify(this.headerInfo)) window.localStorage.setItem('headerInfo', JSON.stringify(this.headerInfo))
const { sid, cid } = data
const course = this.tabs[1].chapterList.course[data.index] // 课程大作业
const sid = data.sid if (data.id === 'course_work' && !this.headerInfo.survey) {
const cid = data.cid this.$message('请先填写教学评估,然后完成大作业。')
if (course.type === 'course_info') { return
this.$router.push({ path: `/player/${sid}/${cid}/course-info/course_info` }) }
} else if (course.type === 'course_work') { // 教学评估
if (!this.headerInfo.survey) { if (data.id === 'teach_evaluation') {
this.$message('请先填写教学评估,然后完成大作业。') const { sid, cid } = this.$route.params
return false this.$router.push({ name: 'survey', params: { sid, cid } })
} return
this.$router.push({ path: `/player/${sid}/${cid}/course-work/course_work` })
} else if (course.type === 'teach_evaluation') {
/* 暂时 不增加 手机端 */
// let w = document.documentElement.clientWidth
this.$router.push({ path: `/survey/${sid}/${cid}` })
// if (w > 767) {
// this.$router.push({ path: `/survey/${sid}/${cid}` })
// } else {
// this.$router.push({ path: `/survey-phone/${sid}/${cid}` })
// }
} else if (course.type === 'exam') {
this.$router.push({ path: `/player/${sid}/${cid}/exam/${course.examId}` })
} }
this.$router.push({ name: 'viewerCourseChapter', params: { sid, cid, id: data.id } })
} }
}, },
/* 直接跳转打开新页面 */ /* 直接跳转打开新页面 */
...@@ -561,84 +522,52 @@ export default { ...@@ -561,84 +522,52 @@ export default {
/** /**
* 跳转到对应音视频播放页 * 跳转到对应音视频播放页
*/ */
jumpToOtherVA (e) { jumpToOtherVA (data) {
/* 如果未选课,不能查看课程内容 */ /* 如果未选课,不能查看课程内容 */
if (!this.headerInfo.isStart) { if (!this.headerInfo.isStart) {
this.$message.error('先选课,才能学习') this.$message.error('先选课,才能学习')
return return
} }
let _data = e.target.dataset const { sid, cid, vid, type } = data
if (!/name/gi.test(e.target.className)) { /* 进入详情页,不管是哪个,都存localstorage */
_data = e.target.parentElement.dataset window.localStorage.setItem('headerInfo', JSON.stringify(this.headerInfo))
if (type === 1) {
return
} }
const sid = _data.sid // 直播
const cid = _data.cid if (type === 5) {
const _id = _data.vid const live = data.live
const type = _data.type const status = live.live_status
if (!_data.hasva) { if (status !== 0 && status !== 1 && status !== 103) {
/* 进入详情页,不管是哪个,都存localstorage */ this.$message.error(live.statusStr)
window.localStorage.setItem('headerInfo', JSON.stringify(this.headerInfo)) return
/* 如果存在 - 课后习题类型(chapterExam), type:3、work_type:1 */ }
/* 如果存在 - 课后问题类型(chapterWork), type:3、work_type:2 */ const enableRecord = live.enable_record
/* 如果存在 - 课后阅读类型(chapterRead), type:4 */ if (status === 103 && enableRecord !== undefined && enableRecord !== null && !enableRecord) {
const i1 = _data.index this.$message.info('该直播没有回放')
const i2 = _data.count return
const _course = this.tabs[1].chapterList.course[i1] }
if (_course && _course.chapters[i2]) { /* 判别如果为 云课堂记录 id 则直接进入 云课堂 */
if (_course.chapters[i2].type === 3) { if (this.cloudClassUrls[vid]) {
if (_course.chapters[i2].work_type === 1) { const viewerName = window.G.UserInfo.student_info.personal_name || window.G.UserInfo.nickname
this.$router.push({ path: `/player/${sid}/${cid}/chapter-exam/${_id}` }) const url = this.cloudClassUrls[vid] + '&viewername=' + viewerName + '&autoLogin=true'
} else if (_course.chapters[i2].work_type === 2) { window.open(url)
this.$router.push({ path: `/player/${sid}/${cid}/chapter-work/${_id}` }) return
} }
} else if (_course.chapters[i2].type === 4) { // 新窗口打开
this.$router.push({ path: `/player/${sid}/${cid}/chapter-read/${_id}` }) if (this.isOpenNewTabFlag) {
} else if (_course.chapters[i2].type === 5) { this.openNewTab(sid, cid, vid)
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
}
/* 判别如果为 云课堂记录 id 则直接进入 云课堂 */
if (this.cloudClassUrls[_id]) {
const viewerName = window.G.UserInfo.student_info.personal_name || window.G.UserInfo.nickname
const url = this.cloudClassUrls[_id] + '&viewername=' + viewerName + '&autoLogin=true'
window.open(url)
return
}
if (this.isOpenNewTabFlag) {
this.openNewTab(sid, cid, _id)
} else {
this.$router.push({ path: `/player/${sid}/${cid}/live/${_id}` })
}
} else if (_course.chapters[i2].type === 9) {
this.$router.push({ path: `/player/${sid}/${cid}/chapter-exam2/${_course.chapters[i2].id}` })
}
return return
} }
this.$message.error('点击频率过快,系统反应不过来,请稍后再试,003')
return
} }
this.$router.push({ path: `/player/${sid}/${cid}/chapter-video/${_id}/${type}` }) this.$router.push({ name: 'viewerCourseChapter', params: { sid, cid, id: data.id } })
}, },
/** /**
* 开始学习或继续学习 - 跳转到对应音视频播放页 * 开始学习或继续学习 - 跳转到对应音视频播放页
*/ */
startLearn (e) { startLearn (data) {
const _data = e.currentTarget.dataset if (data.id) {
const sid = _data.sid this.$router.push({ name: 'viewerCourseChapter', params: { sid: this.sid, cid: this.cid, id: data.id } })
const cid = _data.cid
const vid = _data.vid
const type = _data.type
if (vid && type !== '') {
this.$router.push({ path: `/player/${sid}/${cid}/chapter-video/${vid}/${type}` })
} else { } else {
this.$message.error('当前暂无点播课程') this.$message.error('当前暂无点播课程')
} }
...@@ -678,11 +607,11 @@ export default { ...@@ -678,11 +607,11 @@ export default {
const _cid = data.cid const _cid = data.cid
const _vid = data.vid const _vid = data.vid
const _duration = data.duration const _duration = data.duration
const type = data.type const _id = data.id
/* 字母 o */ /* 字母 o */
if (e.keyCode === 79) { if (e.keyCode === 79) {
/* 直接跳转 进入 继续学习 */ /* 直接跳转 进入 继续学习 */
this.$router.push({ path: `/player/${_sid}/${_cid}/chapter-video/${_vid}/${type}` }) this.$router.push({ name: 'viewerCourseChapter', params: { sid: _sid, cid: _cid, id: _id } })
} }
/* 字母 f */ /* 字母 f */
if (e.keyCode === 70) { if (e.keyCode === 70) {
......
// import viewerRoutes from '@/modules/viewer/routes.js' import viewerRoutes from '@/modules/viewer/routes.js'
export default [ export default [
{ path: '/', redirect: '/app/learn/course' }, { path: '/', redirect: '/app/learn/course' },
...@@ -291,7 +291,7 @@ export default [ ...@@ -291,7 +291,7 @@ export default [
// /* survey-phone 内未找到页面时 - 指向 */ // /* survey-phone 内未找到页面时 - 指向 */
// { path: '/survey-phone/*', redirect: '/learn-error/learn-error' }, // { path: '/survey-phone/*', redirect: '/learn-error/learn-error' },
/* 如果所有页面都没找到 - 指向 */ /* 如果所有页面都没找到 - 指向 */
{ path: '*', component: () => import('@/components/errorPages/404.vue') } { path: '*', component: () => import('@/components/errorPages/404.vue') },
// viewer module routes // viewer module routes
// ...viewerRoutes ...viewerRoutes
] ]
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论