Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
L
learn-online-pc
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
图表
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
EzijingWeb
learn-online-pc
Commits
be659e74
提交
be659e74
authored
6月 03, 2020
作者:
王鹏飞
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
update viewer module
上级
d69faf21
显示空白字符变更
内嵌
并排
正在显示
22 个修改的文件
包含
897 行增加
和
404 行删除
+897
-404
CourseAction.js
client/src/action/CourseAction.js
+26
-8
api.js
client/src/modules/viewer/api.js
+24
-2
chapter.vue
client/src/modules/viewer/components/aside/chapter.vue
+28
-30
index.vue
client/src/modules/viewer/components/aside/index.vue
+9
-2
lecture.vue
client/src/modules/viewer/components/aside/lecture.vue
+2
-2
upload.vue
client/src/modules/viewer/components/common/upload.vue
+30
-4
layout.vue
client/src/modules/viewer/components/layout.vue
+3
-0
chapterPlayer.vue
...nt/src/modules/viewer/components/player/chapterPlayer.vue
+120
-7
pptPlayer.vue
client/src/modules/viewer/components/player/pptPlayer.vue
+18
-11
videoPlayer.vue
client/src/modules/viewer/components/player/videoPlayer.vue
+15
-1
fileList.vue
client/src/modules/viewer/components/read/fileList.vue
+1
-1
chapterExam.vue
client/src/modules/viewer/components/work/chapterExam.vue
+173
-126
chapterTest.vue
client/src/modules/viewer/components/work/chapterTest.vue
+274
-0
chapterWork.vue
client/src/modules/viewer/components/work/chapterWork.vue
+4
-4
courseExam.vue
client/src/modules/viewer/components/work/courseExam.vue
+48
-76
courseWork.vue
client/src/modules/viewer/components/work/courseWork.vue
+1
-1
examItem.vue
client/src/modules/viewer/components/work/examItem.vue
+64
-9
index.vue
client/src/modules/viewer/components/work/index.vue
+3
-3
index.vue
client/src/modules/viewer/index.vue
+11
-3
course.vue
client/src/pages/learn/course.vue
+1
-1
courseDetail.vue
client/src/pages/learn/courseDetail.vue
+39
-110
routes.js
client/src/router/routes.js
+3
-3
没有找到文件。
client/src/action/CourseAction.js
浏览文件 @
be659e74
...
...
@@ -104,8 +104,22 @@ export default class CourseAction extends BaseACTION {
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
=
{
currentChapter
:
findChapter
(
cur
.
latest_play
,
data
.
chapters
),
currentChapterId
:
cur
.
latest_play
||
''
,
currentVideoProvider
:
cur
.
latest_play_type
||
'1'
,
course
:
cur
.
chapters
.
map
((
_
,
i
)
=>
{
...
...
@@ -173,35 +187,39 @@ export default class CourseAction extends BaseACTION {
title
:
'课程大作业'
,
isUp
:
true
,
chapters
:
[],
type
:
'course_work'
,
id
:
'course_work'
,
sid
:
sid
,
cid
:
cid
cid
:
cid
,
type
:
99
})
json
.
tabs1ChapterList
.
course
.
push
({
title
:
'课程资料'
,
isUp
:
true
,
chapters
:
[],
type
:
'course_info'
,
id
:
'course_info'
,
sid
:
sid
,
cid
:
cid
cid
:
cid
,
type
:
100
})
json
.
tabs1ChapterList
.
course
.
push
({
title
:
'教学评估'
,
isUp
:
true
,
chapters
:
[],
type
:
'teach_evaluation'
,
id
:
'teach_evaluation'
,
sid
:
sid
,
cid
:
cid
cid
:
cid
,
type
:
102
})
if
(
cur
.
course_examination
)
{
json
.
tabs1ChapterList
.
course
.
push
({
title
:
'课程考试'
,
isUp
:
true
,
chapters
:
[],
type
:
'
exam'
,
id
:
'course_
exam'
,
sid
:
sid
,
cid
:
cid
,
examId
:
cur
.
course_examination
examId
:
cur
.
course_examination
,
type
:
102
})
}
/* 课程考核 考核标准文案读取 */
...
...
client/src/modules/viewer/api.js
浏览文件 @
be659e74
...
...
@@ -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
...
...
@@ -130,8 +151,9 @@ export function submitCourseExam(semesterId, courseId, examId, data) {
* @param {string} courseId 课程ID
* @param {string} examId 试题ID
*/
export
function
getCourseExamResult
(
semesterId
,
courseId
,
examId
)
{
export
function
getCourseExamResult
(
semesterId
,
courseId
,
examId
,
params
)
{
return
httpRequest
.
get
(
`/v2/education/
${
semesterId
}
/
${
courseId
}
/examination/
${
examId
}
/sheet`
`/v2/education/
${
semesterId
}
/
${
courseId
}
/examination/
${
examId
}
/sheet`
,
params
)
}
client/src/modules/viewer/components/aside/chapter.vue
浏览文件 @
be659e74
<
template
>
<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>
<ul
class=
"chapter-item-list"
>
<li
...
...
@@ -9,7 +9,7 @@
@
click=
"onClick(subItem)"
: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>
</li>
</ul>
...
...
@@ -20,7 +20,14 @@
<
script
>
export
default
{
props
:
{
data
:
{
type
:
Array
,
default
:
()
=>
[]
},
// 课程详情接口返回的数据
data
:
{
type
:
Object
,
default
()
{
return
{}
}
},
chapters
:
{
type
:
Array
,
default
:
()
=>
[]
},
// 当前选中的章节
active
:
{
type
:
Object
,
...
...
@@ -30,26 +37,13 @@ export default {
}
},
data
()
{
return
{
otherList
:
[
{
name
:
'大作业及资料'
,
children
:
[
{
name
:
'课程大作业'
,
id
:
'course_work'
},
{
name
:
'课程资料'
,
id
:
'course_info'
},
{
name
:
'教学评估'
,
id
:
'teach_evaluation'
}
]
}
]
}
},
computed
:
{
list
()
{
return
this
.
data
.
concat
(
this
.
otherList
)
}
return
{}
},
filters
:
{
showName
(
name
,
type
)
{
showName
(
name
,
data
)
{
if
(
data
.
type
===
5
)
{
return
`
${
name
}
(
${
data
.
live
.
start_time
}
)`
}
return
name
}
},
...
...
@@ -63,16 +57,20 @@ export default {
return
map
[
type
]
||
'el-icon-self-cc-book'
},
onClick
(
data
)
{
if
(
data
.
type
===
1
)
{
return
}
// 课程大作业
// if (data.id === 'course_work') {
// this.$router.push({ name: 'viewerCourseWork' })
// return
// }
// 课程资料
// if (data.id === 'course_info') {
// this.$router.push({ name: 'viewerCourseFile' })
// return
// }
if
(
data
.
id
===
'course_work'
&&
!
this
.
data
.
survey
)
{
this
.
$message
(
'请先填写教学评估,然后完成大作业。'
)
return
}
// 教学评估
if
(
data
.
id
===
'teach_evaluation'
)
{
const
{
sid
,
cid
}
=
this
.
$route
.
params
this
.
$router
.
push
({
name
:
'survey'
,
params
:
{
sid
,
cid
}
})
return
}
this
.
$router
.
push
({
name
:
'viewerCourseChapter'
,
params
:
{
id
:
data
.
id
}
...
...
client/src/modules/viewer/components/aside/index.vue
浏览文件 @
be659e74
...
...
@@ -3,12 +3,12 @@
<el-tabs
v-model=
"activeName"
>
<el-tab-pane
label=
"章节"
name=
"0"
>
<div
class=
"tab-pane"
>
<aside-chapter
:data=
"chapters"
:active=
"active"
></aside-chapter>
<aside-chapter
:data=
"
data"
:chapters=
"
chapters"
:active=
"active"
></aside-chapter>
</div>
</el-tab-pane>
<el-tab-pane
label=
"讲义"
name=
"1"
v-if=
"active && active.type === 2"
>
<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>
</el-tab-pane>
</el-tabs>
...
...
@@ -21,6 +21,13 @@ import AsideLecture from './lecture.vue'
export
default
{
props
:
{
// 课程详情接口返回的数据
data
:
{
type
:
Object
,
default
()
{
return
{}
}
},
// 章节
chapters
:
{
type
:
Array
,
default
:
()
=>
[]
},
// 讲义
...
...
client/src/modules/viewer/components/aside/lecture.vue
浏览文件 @
be659e74
<
template
>
<ul
class=
"lecture-list"
>
<li
v-for=
"(item, index) in
data
"
v-for=
"(item, index) in
ppts
"
:key=
"item.id"
@
click=
"onClick(index)"
:class=
"
{'is-active': index === activeIndex}"
...
...
@@ -16,7 +16,7 @@ export default {
props
:
{
// 当前选择的PPT
pptIndex
:
{
type
:
Number
,
default
:
0
},
data
:
{
type
:
Array
,
default
:
()
=>
[]
}
ppts
:
{
type
:
Array
,
default
:
()
=>
[]
}
},
data
()
{
return
{
...
...
client/src/modules/viewer/components/common/upload.vue
浏览文件 @
be659e74
<
template
>
<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>
<el-button
type=
"text"
icon=
"el-icon-upload"
>
点击上传
</el-button>
<template
v-slot:tip
>
...
...
@@ -15,6 +15,17 @@
<i
class=
"el-icon-document"
></i>
{{ fileUrl | fileName }}
</a>
<div>
<a
href=
"javascript:;"
@
click=
"handleRemove(index)"
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>
...
...
@@ -23,6 +34,7 @@
</div>
</div>
</div>
</div>
</template>
<
script
>
...
...
@@ -31,7 +43,8 @@ import * as api from '../../api'
export
default
{
name
:
'VUpload'
,
props
:
{
value
:
{
type
:
[
String
,
Array
]
}
value
:
{
type
:
[
String
,
Array
]
},
disabled
:
{
type
:
Boolean
,
default
:
false
}
},
data
()
{
return
{
...
...
@@ -39,9 +52,18 @@ export default {
}
},
watch
:
{
value
(
value
)
{
value
:
{
immediate
:
true
,
handler
(
value
)
{
if
(
value
)
{
this
.
fileList
=
Array
.
isArray
(
value
)
?
value
:
[
value
]
if
(
Array
.
isArray
(
value
))
{
this
.
fileList
=
value
.
map
(
item
=>
{
return
item
.
url
||
item
})
}
else
{
this
.
fileList
=
[
value
]
}
}
}
}
},
...
...
@@ -63,6 +85,10 @@ export default {
}
}
})
},
handleRemove
(
index
)
{
this
.
fileList
.
splice
(
index
,
1
)
this
.
$emit
(
'input'
,
Array
.
isArray
(
this
.
value
)
?
this
.
fileList
:
''
)
}
}
}
...
...
client/src/modules/viewer/components/layout.vue
浏览文件 @
be659e74
...
...
@@ -13,6 +13,7 @@
// components
import
ChapterPlayer
from
'./player/ChapterPlayer.vue'
// 章节视频
import
ChapterWork
from
'./work/index.vue'
// 章节作业
import
ChapterExam
from
'./work/chapterExam.vue'
// 章节考试
import
ChapterRead
from
'./read/chapterRead.vue'
// 章节资料
import
ChapterLive
from
'./live/chapterLive.vue'
// 章节直播
import
CourseWork
from
'./work/courseWork.vue'
// 课程大作业
...
...
@@ -25,6 +26,7 @@ export default {
ChapterPlayer
,
ChapterWork
,
ChapterRead
,
ChapterExam
,
ChapterLive
,
CourseWork
,
CourseRead
,
...
...
@@ -45,6 +47,7 @@ export default {
3
:
'ChapterWork'
,
// 作业
4
:
'ChapterRead'
,
// 资料
5
:
'ChapterLive'
,
// 直播
9
:
'ChapterExam'
,
// 考试
99
:
'CourseWork'
,
// 课程大作业
100
:
'CourseRead'
,
// 课程资料
101
:
'CourseExam'
// 课程考试
...
...
client/src/modules/viewer/components/player/chapterPlayer.vue
浏览文件 @
be659e74
...
...
@@ -7,15 +7,18 @@
:isSkip=
"isSkip"
:video=
"chatperResources.video"
@
timeupdate=
"onTimeupdate"
@
ready=
"onReady"
ref=
"videoPlayer"
></video-player>
</div>
<div
class=
"player-column"
v-if=
"pptVisible"
>
<!-- ppt -->
<ppt-player
:index=
"pptIndex"
:ppts=
"chatperResources.ppts"
@
close=
"
pptVisible = fal
se"
@
close=
"
onPPTClo
se"
@
fullscreen=
"onPPTFullscreen"
@
videoSyncTime=
"onVideoSyncTime"
></ppt-player>
</div>
</div>
...
...
@@ -30,6 +33,8 @@
</
template
>
<
script
>
import
Cookies
from
'js-cookie'
import
{
throttle
}
from
'lodash'
// api
import
*
as
api
from
'../../api'
// components
...
...
@@ -46,11 +51,23 @@ export default {
pptIndex
:
{
type
:
Number
,
default
:
0
}
},
data
()
{
// 是否跳过片头
const
isSkip
=
window
.
localStorage
.
getItem
(
'isSkip'
)
===
'true'
return
{
videoVisible
:
true
,
pptVisible
:
false
,
isSkip
:
false
,
chatperResources
:
null
isSkip
,
chatperResources
:
null
,
throttled
:
null
,
throttleWait
:
10
,
// 秒
progress
:
{
cpt
:
0
,
// 当前播放时间
mpt
:
0
,
// 视频时长
progress
:
0
,
// 进度
pt
:
0
// 累计播放时间
},
player
:
null
,
watchedTimePoint
:
[]
// 视频观看的时间点
}
},
watch
:
{
...
...
@@ -59,6 +76,14 @@ export default {
}
},
computed
:
{
// 学期ID
sid
()
{
return
this
.
$route
.
params
.
sid
},
// 课程ID
cid
()
{
return
this
.
$route
.
params
.
cid
},
// 视频资源ID
resourceId
()
{
return
this
.
chapter
.
resource_id
...
...
@@ -95,11 +120,29 @@ export default {
// 始终跳过片头
toggleSkip
()
{
this
.
isSkip
=
!
this
.
isSkip
window
.
localStorage
.
setItem
(
'isSkip'
,
this
.
isSkip
)
},
// 关闭PPT
onPPTClose
()
{
this
.
pptVisible
=
false
this
.
videoVisible
=
true
},
// PPT全屏
onPPTFullscreen
(
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
)
{
const
ppts
=
this
.
chatperResources
.
ppts
||
[]
...
...
@@ -108,12 +151,29 @@ export default {
)
index
=
index
!==
-
1
?
index
-
1
:
ppts
.
length
-
1
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
()
{
const
player
=
this
.
$refs
.
videoPlayer
.
player
const
ppt
=
this
.
chatperResources
.
ppts
[
this
.
pptIndex
]
ppt
&&
player
.
seek
(
ppt
.
ppt_point
)
// 增加2秒
ppt
&&
this
.
player
.
seek
(
ppt
.
ppt_point
)
// 增加2秒
},
// 获取章节视频详情
getChapterVideo
()
{
...
...
@@ -125,14 +185,66 @@ export default {
})
}
else
{
api
.
getChapterVideo
(
this
.
resourceId
).
then
(
response
=>
{
this
.
chatperResources
=
response
Array
.
isArray
(
response
.
ppts
)
&&
this
.
$emit
(
'pptupdate'
,
response
.
ppts
)
let
{
video
,
audio
,
ppts
}
=
response
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
()
{
// 获取视频
this
.
getChapterVideo
()
// 获取视频进度
this
.
getChapterVideoProgress
()
}
}
</
script
>
...
...
@@ -148,6 +260,7 @@ export default {
.player-main
{
display
:
flex
;
flex
:
1
;
overflow
:
hidden
;
}
.player-column
{
flex
:
1
;
...
...
client/src/modules/viewer/components/player/pptPlayer.vue
浏览文件 @
be659e74
...
...
@@ -19,10 +19,18 @@
<span>
{{ppts.length}}
</span>
页
</div>
<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-xuexiao', (isSync ? 'active' : '')]"
@
click=
"onToggleSync"
></i>
</el-tooltip>
<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>
</template>
...
...
@@ -34,22 +42,23 @@ export default {
name
:
'ppt-player'
,
props
:
{
ppts
:
{
type
:
Array
},
index
:
{
type
:
Number
,
default
:
0
},
isSync
:
{
type
:
Boolean
,
default
:
false
}
index
:
{
type
:
Number
,
default
:
0
}
},
data
()
{
return
{
currentIndex
:
this
.
index
,
currentSync
:
this
.
isSync
,
isSync
:
true
,
isFullscreen
:
false
}
},
watch
:
{
index
:
{
handler
(
value
)
{
if
(
this
.
isSync
)
{
this
.
currentIndex
=
value
}
}
}
},
computed
:
{
pptUrl
()
{
...
...
@@ -67,20 +76,18 @@ export default {
},
prev
()
{
this
.
currentIndex
=
this
.
getIndex
(
this
.
currentIndex
-
1
)
this
.
current
Sync
=
false
this
.
is
Sync
=
false
},
next
(
e
)
{
this
.
currentIndex
=
this
.
getIndex
(
this
.
currentIndex
+
1
)
this
.
current
Sync
=
false
this
.
is
Sync
=
false
},
onToggleSync
(
e
)
{
this
.
currentSync
=
!
this
.
currentSync
this
.
currentIndex
=
this
.
currentSync
?
this
.
currentIndex
:
this
.
currentIndex
this
.
isSync
=
!
this
.
isSync
},
setVideoTime
(
e
)
{
this
.
$emit
(
'onVideoSyncTime'
,
this
.
ppts
[
this
.
currentIndex
].
ppt_point
)
this
.
isSync
=
true
this
.
$emit
(
'videoSyncTime'
,
this
.
ppts
[
this
.
currentIndex
].
ppt_point
)
},
// 全屏
fullscreen
()
{
...
...
client/src/modules/viewer/components/player/videoPlayer.vue
浏览文件 @
be659e74
...
...
@@ -13,13 +13,22 @@ export default {
createPlayer
()
{
const
_this
=
this
const
{
FD
,
LD
,
SD
}
=
this
.
video
/*
"OD" : "原画"
"FD" : "流畅"
"LD" : "标清"
"SD" : "高清"
"HD" : "超清"
"2K" : "2K"
"4K" : "4K"
*/
this
.
player
=
new
Aliplayer
(
{
id
:
'player'
,
source
:
JSON
.
stringify
({
FD
,
LD
,
SD
}),
width
:
'100%'
,
height
:
'100%'
,
autoplay
:
tru
e
,
autoplay
:
fals
e
,
isLive
:
false
,
controlBarVisibility
:
'always'
,
components
:
[
...
...
@@ -30,6 +39,11 @@ export default {
]
},
function
(
player
)
{
player
.
on
(
'ready'
,
function
()
{
// 跳过片头
_this
.
isSkip
&&
player
.
seek
(
6
)
_this
.
$emit
(
'ready'
,
player
)
})
player
.
on
(
'sourceloaded'
,
function
(
params
)
{
const
paramData
=
params
.
paramData
const
desc
=
paramData
.
desc
...
...
client/src/modules/viewer/components/read/fileList.vue
浏览文件 @
be659e74
...
...
@@ -6,7 +6,7 @@
<i
class=
"el-icon-document"
></i>
{{
file
.
file_name
}}
</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"
>
<el-tooltip
effect=
"dark"
content=
"下载"
>
<i
class=
"el-icon-download"
></i>
...
...
client/src/modules/viewer/components/work/chapterExam.vue
浏览文件 @
be659e74
<
template
>
<container
:title=
"
chapter.nam
e"
v-loading=
"loading"
>
<template
v-slot:header-aside
v-if=
"is
Submited"
>
正确率:
{{
detail
.
score
}}
%
</
template
>
<container
:title=
"
detail.paper_titl
e"
v-loading=
"loading"
>
<template
v-slot:header-aside
v-if=
"is
ExamComplete"
>
分数:
{{
exam
.
score
.
total
}}
分
</
template
>
<div
class=
"exam"
>
<div
class=
"exam-form"
>
<
template
v-if=
"isSubmited && !isExamComplete"
>
<div
class=
"no-exam"
>
试卷批改中,请耐心等待
</div>
</
template
>
<
template
v-else
>
<!-- 考试期间,未开始考试 -->
<div
class=
"exam-welcome"
v-if=
"!isStartExam"
>
<div
v-if=
"detail.paper_deadline"
>
考试截止时间:
{{
detail
.
paper_deadline
}}
</div>
<el-button
type=
"primary"
:disabled=
"!isExamTime"
@
click=
"onStartExam"
>
{{
startExamButtonText
}}
</el-button>
</div>
<!-- 考试试题 -->
<div
class=
"exam-form"
v-if=
"isStartExam"
>
<el-form
:disabled=
"isSubmited"
>
<template
v-for=
"items in questions"
>
<exam-item
v-for=
"(item, index) in unorderedQuestion
s"
v-for=
"(item, index) in item
s"
:index=
"index"
:type=
"item.question_
type"
: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>
...
...
@@ -20,13 +36,14 @@
</div>
</el-form>
</div>
</template>
</div>
</container>
</template>
<
script
>
// libs
import
{
shuffle
}
from
'lodash'
import
Base64
from
'Base64'
// components
import
Container
from
'../common/container.vue'
import
ExamItem
from
'./examItem.vue'
...
...
@@ -44,23 +61,33 @@ export default {
default
()
{
return
{}
}
},
// 课程详情接口返回的数据
data
:
{
type
:
Object
,
default
()
{
return
{}
}
}
},
data
()
{
return
{
loading
:
false
,
detail
:
null
,
questions
:
[],
// 问题列表
startTime
:
new
Date
().
getTime
(),
// 进入时间
messageInstance
:
null
detail
:
{},
questions
:
[],
messageInstance
:
null
,
exam
:
{},
isStartExam
:
false
,
// 是否开始考试
autoSubmitTimer
:
null
// 自动提交定时器
}
},
watch
:
{
chapter
:
{
immediate
:
true
,
handler
(
data
)
{
this
.
questions
=
data
.
homework
?
this
.
genQuenstions
(
data
.
homework
.
questions
)
this
.
detail
=
data
.
paper
this
.
questions
=
data
.
paper
?
this
.
genQuestions
(
data
.
paper
.
examination
)
:
[]
}
}
...
...
@@ -78,19 +105,28 @@ export default {
pid
()
{
return
this
.
$route
.
params
.
id
},
// 资源ID
resourceId
()
{
return
this
.
chapter
.
resource_id
// 是否是考试时间
isExamTime
()
{
if
(
!
this
.
detail
.
paper_deadline
)
{
return
true
}
// 大于开始时间,小于结束时间
const
endTime
=
+
new
Date
(
this
.
exam
.
paper_deadline
)
const
currentTime
=
new
Date
().
getTime
()
return
currentTime
<
endTime
},
// 打乱顺序的问题列表
unorderedQuestions
()
{
const
ids
=
this
.
questions
.
map
(
item
=>
item
.
id
)
const
sortIds
=
shuffle
(
ids
)
return
sortIds
.
map
(
id
=>
this
.
questions
.
find
(
item
=>
item
.
id
===
id
))
// 考试按钮
startExamButtonText
()
{
return
this
.
isExamTime
?
'开始考试'
:
'考试结束'
},
// 考试完成
isExamComplete
()
{
// 考试完成,批改完成并且公布成绩
return
this
.
exam
.
is_published
===
1
&&
this
.
exam
.
type
===
2
},
// 是否提交
isSubmited
()
{
return
this
.
detail
?
!!
this
.
detail
.
work_contents
:
false
return
this
.
exam
.
type
===
1
||
this
.
exam
.
type
===
2
},
// 提交按钮文本
submitText
()
{
...
...
@@ -98,88 +134,80 @@ export default {
}
},
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
})
// 开始考试
onStartExam
()
{
this
.
isStartExam
=
true
// 自动提交答题
this
.
autoSubmit
()
},
// 组装问题数据
genQue
n
stions
(
list
)
{
genQuestions
(
list
)
{
if
(
!
list
)
{
return
[]
}
return
list
.
map
(
item
=>
{
let
temp
=
null
if
(
item
.
question_type
===
1
)
{
return
list
.
map
(
data
=>
{
let
{
radioList
,
checkboxList
,
shortAnswerList
}
=
data
// 单选
temp
=
{
radioList
=
radioList
.
map
(
item
=>
{
const
temp
=
{
type
:
1
,
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
||
[]
}
}
}
else
if
(
item
.
question_type
===
3
)
{
// 简答
temp
=
{
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
)
?
Base64
.
decode
(
item
.
user_answer
.
replace
(
/ /gi
,
'+'
)
)
:
''
,
attachments
:
item
.
attachments
||
''
attachments
:
item
.
attachments
||
[]
}
}
}
return
Object
.
assign
(
{},
item
,
{
content
:
item
.
question_content
,
options
:
item
.
question_options
?
JSON
.
parse
(
item
.
question_options
)
:
[]
return
Object
.
assign
({},
item
,
temp
)
})
return
[...
radioList
,
...
checkboxList
,
...
shortAnswerList
]
})
},
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
()
{
const
quenstions
=
this
.
questions
for
(
let
i
=
0
;
i
<
quenstions
.
length
;
i
++
)
{
const
value
=
quenstions
[
i
].
formModel
.
user_answer
for
(
let
i
=
0
;
i
<
this
.
questions
.
length
;
i
++
)
{
const
questions
=
this
.
questions
[
i
]
for
(
let
k
=
0
;
k
<
questions
.
length
;
k
++
)
{
const
value
=
questions
[
k
].
formModel
.
user_answer
if
(
Array
.
isArray
(
value
)
?
!
value
.
length
:
!
value
)
{
return
false
}
}
}
return
true
},
// 提交
...
...
@@ -190,74 +218,80 @@ export default {
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
)
}
// 提交的答案数据
const
answers
=
this
.
handleSubmitData
()
// 提交参数
const
params
=
{
answers
:
JSON
.
stringify
(
answers
),
type
:
1
}
// 请求接口
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
()
{
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
this
.
questions
.
map
(
questions
=>
{
return
questions
.
reduce
(
(
result
,
item
)
=>
{
// 单选题
if
(
item
.
type
===
1
)
{
result
.
radioList
.
push
(
item
.
formModel
)
}
return
{
id
:
option
.
id
,
checked
:
option
.
checked
,
option
:
option
.
option
,
selected
// 多选题
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
)
})
return
{
question_id
:
item
.
id
,
is_correct
:
isCorrect
?
1
:
0
,
options
result
.
shortAnswerList
.
push
(
formModel
)
}
})
return
result
},
{
radioList
:
[],
checkboxList
:
[],
shortAnswerList
:
[]
}
)
})
},
// 请求提交接口
handleSubmitRequest
(
params
)
{
api
.
sbumitChapterExam
(
params
).
then
(
response
=>
{
if
(
response
.
status
)
{
this
.
getDetail
()
params
.
paper_type
=
0
api
.
submitCourseExam
(
this
.
sid
,
this
.
cid
,
this
.
pid
,
params
)
.
then
(
response
=>
{
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
()
{
this
.
getDetail
()
// 获取考试结果
this
.
getExamResult
()
},
destroyed
()
{
this
.
autoSubmitTimer
&&
clearInterval
(
this
.
autoSubmitTimer
)
}
}
</
script
>
...
...
@@ -271,4 +305,17 @@ export default {
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
>
client/src/modules/viewer/components/work/chapterTest.vue
0 → 100644
浏览文件 @
be659e74
<
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
>
client/src/modules/viewer/components/work/chapterWork.vue
浏览文件 @
be659e74
...
...
@@ -214,12 +214,12 @@ export default {
)
// 提交的答案数据
const
answers
=
this
.
questions
.
map
(
item
=>
{
if
(
item
.
question_type
===
3
)
{
item
.
formModel
.
user_answer
=
Base64
.
encode
(
item
.
formModel
.
user_answer
)
}
return
{
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
,
is_encoded
:
1
}
...
...
client/src/modules/viewer/components/work/courseExam.vue
浏览文件 @
be659e74
<
template
>
<container
:title=
"detail.title"
v-loading=
"loading"
>
<template
v-slot:header-aside
v-if=
"isExamComplete"
>
分数:
{{
exam
.
score
.
total
}}
分
</
template
>
<div
class=
"exam"
>
<
template
v-if=
"status.examination_status === '00'"
>
<div
class=
"no-exam"
>
暂无考试
</div>
...
...
@@ -17,32 +18,12 @@
@
click=
"onStartExam"
>
{{
startExamButtonText
}}
</el-button>
</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"
>
<template
v-for=
"items in questions"
>
<exam-item
v-for=
"(item, index) in question
s"
v-for=
"(item, index) in item
s"
:index=
"index"
:type=
"item.type"
:data=
"item"
...
...
@@ -50,6 +31,7 @@
: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>
...
...
@@ -97,18 +79,11 @@ export default {
detail
:
{},
status
:
{},
questions
:
[],
values
:
[],
// 提交的答案
messageInstance
:
null
,
exam
:
{},
isStartExam
:
false
,
// 是否开始考试
autoSubmitTimer
:
null
,
// 自动提交定时器
checkStatusTimer
:
null
,
// 考试状态定时器
examVisible
:
true
}
},
watch
:
{
isExamComplete
(
value
)
{
this
.
examVisible
=
!
value
checkStatusTimer
:
null
// 考试状态定时器
}
},
computed
:
{
...
...
@@ -163,7 +138,7 @@ export default {
this
.
detail
=
Array
.
isArray
(
response
)
?
null
:
response
// 设置问题列表数据
this
.
questions
=
this
.
detail
?
this
.
genQue
n
stions
(
this
.
detail
.
examination
)
?
this
.
genQuestions
(
this
.
detail
.
examination
)
:
[]
callback
&&
callback
()
})
...
...
@@ -172,10 +147,11 @@ export default {
})
},
// 组装问题数据
genQue
nstions
(
data
)
{
if
(
!
data
)
{
return
genQue
stions
(
list
)
{
if
(
!
list
)
{
return
[]
}
return
list
.
map
(
data
=>
{
let
{
radioList
,
checkboxList
,
shortAnswerList
}
=
data
// 单选
radioList
=
radioList
.
map
(
item
=>
{
...
...
@@ -200,14 +176,15 @@ export default {
formModel
:
{
id
:
item
.
id
,
user_answer
:
item
.
user_answer
?
Base64
.
decode
(
item
.
user_answer
)
?
Base64
.
decode
(
item
.
user_answer
.
replace
(
/ /gi
,
'+'
)
)
:
''
,
attachments
:
[]
attachments
:
item
.
attachments
||
[]
}
}
return
Object
.
assign
({},
item
,
temp
)
})
return
[...
radioList
,
...
checkboxList
,
...
shortAnswerList
]
})
},
// 获取考试状态
getExamStatus
()
{
...
...
@@ -234,7 +211,7 @@ export default {
if
(
response
.
code
!==
8001
)
{
this
.
isStartExam
=
true
this
.
exam
=
response
this
.
questions
=
this
.
genQue
n
stions
(
response
.
sheet
)
this
.
questions
=
this
.
genQuestions
(
response
.
sheet
)
// 自动提交
if
(
this
.
isStartExam
&&
!
this
.
isSubmited
&&
!
this
.
isExamComplete
)
{
this
.
autoSubmit
()
...
...
@@ -244,13 +221,15 @@ export default {
},
// 提交校验
checkSubmit
()
{
const
quenstions
=
this
.
questions
for
(
let
i
=
0
;
i
<
quenstions
.
length
;
i
++
)
{
const
value
=
quenstions
[
i
].
formModel
.
user_answer
for
(
let
i
=
0
;
i
<
this
.
questions
.
length
;
i
++
)
{
const
questions
=
this
.
questions
[
i
]
for
(
let
k
=
0
;
k
<
questions
.
length
;
k
++
)
{
const
value
=
questions
[
k
].
formModel
.
user_answer
if
(
Array
.
isArray
(
value
)
?
!
value
.
length
:
!
value
)
{
return
false
}
}
}
return
true
},
// 提交
...
...
@@ -262,12 +241,7 @@ export default {
return
}
// 提交的答案数据
const
answers
=
this
.
questions
.
map
(
item
=>
{
if
(
item
.
type
===
3
)
{
item
.
formModel
.
user_answer
=
Base64
.
encode
(
item
.
formModel
.
user_answer
)
}
return
item
.
formModel
})
const
answers
=
this
.
handleSubmitData
()
// 提交参数
const
params
=
{
answers
:
JSON
.
stringify
(
answers
),
type
:
1
}
// 请求接口
...
...
@@ -279,19 +253,38 @@ export default {
this
.
autoSubmitTimer
&&
clearInterval
(
this
.
autoSubmitTimer
)
this
.
autoSubmitTimer
=
setInterval
(()
=>
{
// 提交的答案数据
const
answers
=
this
.
questions
.
map
(
item
=>
{
if
(
item
.
type
===
3
)
{
item
.
formModel
.
user_answer
=
Base64
.
encode
(
item
.
formModel
.
user_answer
)
}
return
item
.
formModel
})
const
answers
=
this
.
handleSubmitData
()
const
params
=
{
answers
:
JSON
.
stringify
(
answers
),
type
:
0
}
// 请求接口
this
.
handleSubmitRequest
(
params
)
},
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
)
{
api
...
...
@@ -344,27 +337,6 @@ export default {
font-size
:
30px
;
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
{
padding
:
40px
;
line-height
:
30px
;
...
...
client/src/modules/viewer/components/work/courseWork.vue
浏览文件 @
be659e74
...
...
@@ -109,7 +109,7 @@ export default {
rules
:
{
essay_name
:
[
{
required
:
true
,
message
:
'请输入主题'
,
trigger
:
'blur'
},
{
max
:
5
,
message
:
'最多输入 50 个字符'
,
trigger
:
'blur'
}
{
max
:
5
0
,
message
:
'最多输入 50 个字符'
,
trigger
:
'blur'
}
],
essay_description
:
[
{
required
:
true
,
message
:
'请输入正文'
,
trigger
:
'blur'
}
...
...
client/src/modules/viewer/components/work/examItem.vue
浏览文件 @
be659e74
...
...
@@ -2,8 +2,11 @@
<div
class=
"q-item"
>
<div
class=
"q-item-hd"
>
<div
class=
"q-item-num"
>
{{
index
+
1
}}
.
</div>
<div
class=
"q-item-title"
v-html=
"data.content"
>
{{
data
.
title
}}
</div>
<div
class=
"q-item-aside"
v-if=
"typeText"
>
(
{{
typeText
}}
)
</div>
<div
class=
"q-item-title"
v-html=
"data.content"
></div>
<div
class=
"q-item-aside"
>
<template
v-if=
"typeText"
>
(
{{
typeText
}}
)
</
template
>
<
template
v-if=
"data.hasOwnProperty('score')"
>
(
{{
data
.
score
}}
分)
</
template
>
</div>
</div>
<div
class=
"q-item-bd"
>
<!-- 单选 -->
...
...
@@ -21,17 +24,18 @@
<!-- 简答题 -->
<
template
v-if=
"type === 3"
>
<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
>
</div>
<div
class=
"q-item-ft"
v-if=
"disabled"
>
<
template
v-if=
"type === 3"
>
<p>
<span>
老师
评语:
</span>
<span>
评语:
</span>
<span>
{{
data
.
check_comment
}}
</span>
</p>
</
template
>
<
template
v-else
>
<div
class=
"result"
>
<p>
<span>
学生答案:
</span>
<span
:class=
"isCorrect ? 'is-success' : 'is-error'"
>
{{
submitAnswerText
}}
</span>
...
...
@@ -40,7 +44,24 @@
<span>
正确答案:
</span>
<span>
{{
correctAnswerText
}}
</span>
</p>
</div>
</
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>
</template>
...
...
@@ -77,7 +98,8 @@ export default {
},
data
()
{
return
{
currentValue
:
{}
currentValue
:
{},
showAnalyze
:
false
}
},
watch
:
{
...
...
@@ -116,6 +138,14 @@ export default {
item
.
selected
=
Array
.
isArray
(
value
)
?
value
.
includes
(
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
})
},
...
...
@@ -190,14 +220,16 @@ export default {
}
.q-item-title
{
flex
:
1
;
padding
:
0
10px
;
::v-deep
img
{
max-width
:
100%
;
}
}
.q-item-aside
{
padding-left
:
20px
;
// align-self: flex-end;
}
.q-option-item
{
padding-left
:
3
0px
;
padding-left
:
2
0px
;
margin-bottom
:
14px
;
}
.is-success
{
...
...
@@ -229,13 +261,36 @@ export default {
}
}
.q-item-ft
{
padding
:
10px
0
;
p
{
font-size
:
14px
;
margin
:
0
0
10px
0
;
}
.result
{
display
:
flex
;
justify-content
:
flex-end
;
padding
:
10px
0
;
p
{
padding-left
:
20px
;
}
}
.analyze
{
display
:
flex
;
font-size
:
14px
;
}
.analyze-main
{
flex
:
1
;
overflow
:
hidden
;
}
.analyze-content
{
margin-top
:
10px
;
background-color
:
#c9c9c9
7a
;
border
:
1px
solid
#c9c9c9
7a
;
padding
:
10px
;
::v-deep
*
{
margin
:
0
;
padding-left
:
20px
;
padding
:
0
;
max-width
:
100%
;
}
}
}
</
style
>
client/src/modules/viewer/components/work/index.vue
浏览文件 @
be659e74
...
...
@@ -12,11 +12,11 @@
<
script
>
// componets
import
ChapterWork
from
'./chapterWork.vue'
import
Chapter
Exam
from
'./chapterExam
.vue'
import
Chapter
Test
from
'./ChapterTest
.vue'
export
default
{
name
:
'ViewerWork'
,
components
:
{
ChapterWork
,
Chapter
Exam
},
components
:
{
ChapterWork
,
Chapter
Test
},
props
:
{
// 当前选中的
chapter
:
{
...
...
@@ -36,7 +36,7 @@ export default {
computed
:
{
currentCompoent
()
{
const
componentNames
=
{
1
:
'Chapter
Exam'
,
// 考试
1
:
'Chapter
Test'
,
// 课后测验
2
:
'ChapterWork'
// 作业
}
const
homework
=
this
.
chapter
.
homework
...
...
client/src/modules/viewer/index.vue
浏览文件 @
be659e74
...
...
@@ -9,7 +9,7 @@
<h1
class=
"course-viewer-main-hd__title"
>
{{
detail
.
course_name
}}
</h1>
<!-- 直播的时候显示帮助按钮 -->
<template
v-if=
"isLive"
>
<router-link
to=
"/app/
account/feedbackC
reate"
target=
"_blank"
>
<router-link
to=
"/app/
feedback/feedback-c
reate"
target=
"_blank"
>
<el-tooltip
effect=
"light"
content=
"意见反馈"
>
<i
class=
"el-icon-self-fankuiyijian"
></i>
</el-tooltip>
...
...
@@ -35,6 +35,7 @@
</div>
<!-- 侧边栏 -->
<v-aside
:data=
"detail"
:chapters=
"chapters"
:active=
"activeChapter"
:ppts=
"ppts"
...
...
@@ -92,10 +93,17 @@ export default {
children
:
[
{
name
:
'课程大作业'
,
id
:
'course_work'
,
type
:
99
},
{
name
:
'课程资料'
,
id
:
'course_info'
,
type
:
100
},
{
name
:
'教学评估'
,
id
:
'teach_evaluation'
,
type
:
102
},
{
name
:
'课程考试'
,
id
:
'course_exam'
,
type
:
101
}
{
name
:
'教学评估'
,
id
:
'teach_evaluation'
,
type
:
102
}
]
}
// 课程考试
if
(
this
.
detail
.
course_examination
)
{
customeChapter
.
children
.
push
({
name
:
'课程考试'
,
id
:
'course_exam'
,
type
:
101
})
}
chapters
.
push
(
customeChapter
)
return
chapters
},
...
...
client/src/pages/learn/course.vue
浏览文件 @
be659e74
...
...
@@ -193,7 +193,7 @@ export default {
},
/* 直接进直播 */
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
}
})
}
}
}
...
...
client/src/pages/learn/courseDetail.vue
浏览文件 @
be659e74
...
...
@@ -4,11 +4,11 @@
<div
class=
"detail-box"
>
<div
class=
"box-thd"
>
<div
class=
"title"
@
click=
"noWantThisCourse"
>
{{
headerInfo
.
title
}}
<template
v-if=
'headerInfo.isStart && tabs[1].chapterList.currentChapter
Id
'
>
<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>
<template
v-if=
'headerInfo.isStart && tabs[1].chapterList.currentChapter'
>
<el-button
class=
"rbtn"
type=
"primary"
size=
"mini"
@
click=
'startLearn
(tabs[1].chapterList.currentChapter)
'
>
继续学习
</el-button>
</
template
>
<
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
v-else
>
<el-button
class=
"rbtn"
type=
"primary"
size=
"mini"
@
click=
'wantThisCourse'
>
选课
</el-button>
...
...
@@ -43,12 +43,12 @@
<div
class=
'course-list'
>
<
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
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>
</div>
<template
v-for=
"(item1, index1) in _item.chapters"
>
<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
}}
<template
v-if=
'item1.type === 5'
>
<div
class=
'time'
>
{{
item1
.
live
.
start_time
}}
{{
item1
.
live
.
statusStr
}}
</div>
...
...
@@ -74,28 +74,6 @@
<div
:class=
'["item-order", (sort[1].isShow ? "on" : "")]'
@
click=
'sortFn'
:data-index=
'1'
:data-str=
'sort[1].str'
>
按投票排序
</div>
</div>
<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>
</div>
</
template
>
...
...
@@ -109,7 +87,6 @@
<el-form-item
label=
"标题"
prop=
"title"
>
<el-input
v-model=
"publish.title"
type=
"text"
placeholder=
"请输入标题"
></el-input>
</el-form-item>
<!-- v-model="publish.content" -->
<div
style=
"line-height: 1.5; font-size: 0.16rem; margin-bottom: 0.2rem;"
>
正文内容
</div>
<textarea
id=
"editor"
></textarea>
<div
style=
"height: 0.2rem;"
></div>
...
...
@@ -146,7 +123,7 @@
<div
class=
'tt'
>
{{
item1
.
title
}}
</div>
<template
v-for=
'(item2, index) in item1.arr'
>
<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-td3'
>
{{
item2
.
progress
}}
</div>
</div>
...
...
@@ -214,8 +191,6 @@
</el-row>
</div>
</div>
<!-- v-model="setArtContent.content" -->
<!-- <textarea id="editor"></textarea> -->
</template>
<
script
>
...
...
@@ -375,7 +350,6 @@ export default {
this
.
tabs
[
0
].
content
=
json
.
tabs0Content
this
.
tabs
[
1
].
chapterList
=
json
.
tabs1ChapterList
json
.
tabs3richTest
&&
(
this
.
tabs
[
3
].
richText
=
json
.
tabs3richTest
)
// 设置开始学习的视频
const
courseList
=
json
.
tabs1ChapterList
.
course
for
(
let
i
=
0
;
i
<
courseList
.
length
;
i
++
)
{
...
...
@@ -485,41 +459,28 @@ export default {
/**
* 课程内容 - 列表展开或者跳转
*/
clickJumpOrStatus
(
e
)
{
const
data
=
e
.
currentTarget
.
dataset
const
flag
=
data
.
status
clickJumpOrStatus
(
index
,
data
)
{
const
flag
=
!!
data
.
chapters
.
length
if
(
flag
)
{
const
index
=
data
.
index
const
json
=
this
.
tabs
const
temp
=
json
[
1
].
chapterList
.
course
[
index
]
temp
.
isUp
=
!
temp
.
isUp
}
else
{
/* 进入详情页,不管是哪个,都存localstorage */
window
.
localStorage
.
setItem
(
'headerInfo'
,
JSON
.
stringify
(
this
.
headerInfo
))
const
course
=
this
.
tabs
[
1
].
chapterList
.
course
[
data
.
index
]
const
sid
=
data
.
sid
const
cid
=
data
.
cid
if
(
course
.
type
===
'course_info'
)
{
this
.
$router
.
push
({
path
:
`/player/
${
sid
}
/
${
cid
}
/course-info/course_info`
})
}
else
if
(
course
.
type
===
'course_work'
)
{
if
(
!
this
.
headerInfo
.
survey
)
{
const
{
sid
,
cid
}
=
data
// 课程大作业
if
(
data
.
id
===
'course_work'
&&
!
this
.
headerInfo
.
survey
)
{
this
.
$message
(
'请先填写教学评估,然后完成大作业。'
)
return
false
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
}
`
})
// 教学评估
if
(
data
.
id
===
'teach_evaluation'
)
{
const
{
sid
,
cid
}
=
this
.
$route
.
params
this
.
$router
.
push
({
name
:
'survey'
,
params
:
{
sid
,
cid
}
})
return
}
this
.
$router
.
push
({
name
:
'viewerCourseChapter'
,
params
:
{
sid
,
cid
,
id
:
data
.
id
}
})
}
},
/* 直接跳转打开新页面 */
...
...
@@ -561,84 +522,52 @@ export default {
/**
* 跳转到对应音视频播放页
*/
jumpToOtherVA
(
e
)
{
jumpToOtherVA
(
data
)
{
/* 如果未选课,不能查看课程内容 */
if
(
!
this
.
headerInfo
.
isStart
)
{
this
.
$message
.
error
(
'先选课,才能学习'
)
return
}
let
_data
=
e
.
target
.
dataset
if
(
!
/name/gi
.
test
(
e
.
target
.
className
))
{
_data
=
e
.
target
.
parentElement
.
dataset
}
const
sid
=
_data
.
sid
const
cid
=
_data
.
cid
const
_id
=
_data
.
vid
const
type
=
_data
.
type
if
(
!
_data
.
hasva
)
{
const
{
sid
,
cid
,
vid
,
type
}
=
data
/* 进入详情页,不管是哪个,都存localstorage */
window
.
localStorage
.
setItem
(
'headerInfo'
,
JSON
.
stringify
(
this
.
headerInfo
))
/* 如果存在 - 课后习题类型(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
.
tabs
[
1
].
chapterList
.
course
[
i1
]
if
(
_course
&&
_course
.
chapters
[
i2
])
{
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
].
type
===
5
)
{
const
status
=
_course
.
chapters
[
i2
].
live
.
live_status
if
(
type
===
1
)
{
return
}
// 直播
if
(
type
===
5
)
{
const
live
=
data
.
live
const
status
=
live
.
live_status
if
(
status
!==
0
&&
status
!==
1
&&
status
!==
103
)
{
this
.
$message
.
error
(
_course
.
chapters
[
i2
].
live
.
statusStr
)
this
.
$message
.
error
(
live
.
statusStr
)
return
}
const
enableRecord
=
_course
.
chapters
[
i2
].
live
.
enable_record
const
enableRecord
=
live
.
enable_record
if
(
status
===
103
&&
enableRecord
!==
undefined
&&
enableRecord
!==
null
&&
!
enableRecord
)
{
this
.
$message
.
info
(
'该直播没有回放'
)
return
}
/* 判别如果为 云课堂记录 id 则直接进入 云课堂 */
if
(
this
.
cloudClassUrls
[
_
id
])
{
if
(
this
.
cloudClassUrls
[
v
id
])
{
const
viewerName
=
window
.
G
.
UserInfo
.
student_info
.
personal_name
||
window
.
G
.
UserInfo
.
nickname
const
url
=
this
.
cloudClassUrls
[
_
id
]
+
'&viewername='
+
viewerName
+
'&autoLogin=true'
const
url
=
this
.
cloudClassUrls
[
v
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
}
`
})
}
this
.
openNewTab
(
sid
,
cid
,
vid
)
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
)
{
const
_data
=
e
.
currentTarget
.
dataset
const
sid
=
_data
.
sid
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
}
`
})
startLearn
(
data
)
{
if
(
data
.
id
)
{
this
.
$router
.
push
({
name
:
'viewerCourseChapter'
,
params
:
{
sid
:
this
.
sid
,
cid
:
this
.
cid
,
id
:
data
.
id
}
})
}
else
{
this
.
$message
.
error
(
'当前暂无点播课程'
)
}
...
...
@@ -678,11 +607,11 @@ export default {
const
_cid
=
data
.
cid
const
_vid
=
data
.
vid
const
_duration
=
data
.
duration
const
type
=
data
.
type
const
_id
=
data
.
id
/* 字母 o */
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 */
if
(
e
.
keyCode
===
70
)
{
...
...
client/src/router/routes.js
浏览文件 @
be659e74
//
import viewerRoutes from '@/modules/viewer/routes.js'
import
viewerRoutes
from
'@/modules/viewer/routes.js'
export
default
[
{
path
:
'/'
,
redirect
:
'/app/learn/course'
},
...
...
@@ -291,7 +291,7 @@ export default [
// /* survey-phone 内未找到页面时 - 指向 */
// { 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
//
...viewerRoutes
...
viewerRoutes
]
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论