Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
L
learn-online-pc
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
图表
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
EzijingWeb
learn-online-pc
Commits
bb3b7053
提交
bb3b7053
authored
5月 12, 2020
作者:
王鹏飞
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
update viewer module
上级
c54eb22e
全部展开
隐藏空白字符变更
内嵌
并排
正在显示
27 个修改的文件
包含
552 行增加
和
902 行删除
+552
-902
api.js
client/src/modules/viewer/api.js
+28
-5
chapter.vue
client/src/modules/viewer/components/aside/chapter.vue
+6
-1
index.vue
client/src/modules/viewer/components/aside/index.vue
+6
-1
container.vue
client/src/modules/viewer/components/common/container.vue
+0
-0
editor.vue
client/src/modules/viewer/components/common/editor.vue
+0
-0
fileList.vue
client/src/modules/viewer/components/common/fileList.vue
+8
-1
upload.vue
client/src/modules/viewer/components/common/upload.vue
+32
-23
layout.vue
client/src/modules/viewer/components/layout.vue
+14
-7
chapterLive.vue
client/src/modules/viewer/components/live/chapterLive.vue
+55
-0
chapterPlayer.vue
...nt/src/modules/viewer/components/player/chapterPlayer.vue
+1
-1
pptPlayer.vue
client/src/modules/viewer/components/player/pptPlayer.vue
+0
-0
videoPlayer.vue
client/src/modules/viewer/components/player/videoPlayer.vue
+0
-0
chapterRead.vue
client/src/modules/viewer/components/read/chapterRead.vue
+14
-4
courseRead.vue
client/src/modules/viewer/components/read/courseRead.vue
+14
-4
fileList.vue
client/src/modules/viewer/components/read/fileList.vue
+0
-0
chapterExam.vue
client/src/modules/viewer/components/work/chapterExam.vue
+110
-65
chapterWork.vue
client/src/modules/viewer/components/work/chapterWork.vue
+146
-54
courseExam.vue
client/src/modules/viewer/components/work/courseExam.vue
+0
-0
courseWork.vue
client/src/modules/viewer/components/work/courseWork.vue
+21
-10
examItem.vue
client/src/modules/viewer/components/work/examItem.vue
+66
-59
index.vue
client/src/modules/viewer/components/work/index.vue
+12
-2
index.vue
client/src/modules/viewer/index.vue
+18
-15
routes.js
client/src/modules/viewer/routes.js
+1
-1
chapterLive.vue
client/src/modules/viewer/src/live/chapterLive.vue
+0
-8
chapterExamItem.vue
client/src/modules/viewer/src/work/chapterExamItem.vue
+0
-228
courseExam.vue
client/src/modules/viewer/src/work/courseExam.vue
+0
-215
courseExamItem.vue
client/src/modules/viewer/src/work/courseExamItem.vue
+0
-198
没有找到文件。
client/src/modules/viewer/api
/index
.js
→
client/src/modules/viewer/api.js
浏览文件 @
bb3b7053
...
...
@@ -90,13 +90,23 @@ export function updateCourseWork(semesterId, courseId, data) {
}
/**
* 获取课程考试
详情
* 获取课程考试
试题
* @param {string} semesterId 学期ID
* @param {string} courseId 课程ID
*/
export
function
getCourseExam
(
semesterId
,
courseId
)
{
return
httpRequest
.
get
(
`/v2/education/
${
semesterId
}
/
${
courseId
}
/examination`
)
}
/**
* 获取课程考试状态
* @param {string} semesterId 学期ID
* @param {string} courseId 课程ID
* @param {string} examId 试题ID
*/
export
function
getCourseExamStatus
(
semesterId
,
courseId
,
examId
)
{
return
httpRequest
.
get
(
`/v2/education/
${
semesterId
}
/
${
courseId
}
/examination`
`/v2/education/
${
semesterId
}
/
${
courseId
}
/examination
/
${
examId
}
/status
`
)
}
...
...
@@ -104,11 +114,24 @@ export function getCourseExam(semesterId, courseId) {
* 提交课程考试
* @param {string} semesterId 学期ID
* @param {string} courseId 课程ID
* @param {string} examId 试题ID
*/
export
function
updateCourseExam
(
semesterId
,
course
Id
,
data
)
{
export
function
submitCourseExam
(
semesterId
,
courseId
,
exam
Id
,
data
)
{
return
httpRequest
.
post
(
`/v2/education/
${
semesterId
}
/
${
courseId
}
/e
ssay
`
,
`/v2/education/
${
semesterId
}
/
${
courseId
}
/e
xamination/
${
examId
}
/sheet
`
,
data
,
{
headers
:
{
'Content-Type'
:
'multipart/form-data'
}
}
{
headers
:
{
'Content-Type'
:
'application/x-www-form-urlencoded'
}
}
)
}
/**
* 获取课程考试结果
* @param {string} semesterId 学期ID
* @param {string} courseId 课程ID
* @param {string} examId 试题ID
*/
export
function
getCourseExamResult
(
semesterId
,
courseId
,
examId
)
{
return
httpRequest
.
get
(
`/v2/education/
${
semesterId
}
/
${
courseId
}
/examination/
${
examId
}
/sheet`
)
}
client/src/modules/viewer/components/aside/chapter.vue
浏览文件 @
bb3b7053
...
...
@@ -22,7 +22,12 @@ export default {
props
:
{
data
:
{
type
:
Array
,
default
:
()
=>
[]
},
// 当前选中的章节
active
:
{
type
:
Object
,
default
:
()
=>
{}
}
active
:
{
type
:
Object
,
default
()
{
return
{}
}
}
},
data
()
{
return
{
...
...
client/src/modules/viewer/components/aside/index.vue
浏览文件 @
bb3b7053
...
...
@@ -26,7 +26,12 @@ export default {
// 讲义
ppts
:
{
type
:
Array
,
default
:
()
=>
[]
},
// 当前选中的章节
active
:
{
type
:
Object
,
default
:
()
=>
{}
},
active
:
{
type
:
Object
,
default
()
{
return
{}
}
},
// 当前选择的PPT
pptIndex
:
{
type
:
Number
,
default
:
0
}
},
...
...
client/src/modules/viewer/components/container.vue
→
client/src/modules/viewer/components/co
mmon/co
ntainer.vue
浏览文件 @
bb3b7053
File moved
client/src/modules/viewer/components/editor.vue
→
client/src/modules/viewer/components/
common/
editor.vue
浏览文件 @
bb3b7053
File moved
client/src/modules/viewer/
src/read
/fileList.vue
→
client/src/modules/viewer/
components/common
/fileList.vue
浏览文件 @
bb3b7053
...
...
@@ -4,7 +4,7 @@
<li
class=
"file-list-item"
v-for=
"file in files"
:key=
"file.id"
>
<a
:href=
"file.file_url"
target=
"_blank"
>
<i
class=
"el-icon-document"
></i>
{{
file
.
file_name
}}
<div
v-html=
"file.file_name"
></div>
</a>
<span
v-if=
"file.file_size"
>
{{
file
.
file_size
}}
</span>
<a
:href=
"file.file_url"
:download=
"file.file_name"
target=
"_blank"
>
...
...
@@ -46,11 +46,18 @@ export default {
border-radius
:
32px
;
justify-content
:
space-between
;
a
{
display
:
flex
;
align-items
:
center
;
text-decoration
:
none
;
color
:
#333
;
white-space
:
nowrap
;
&
:hover
{
color
:
#b49441
;
}
::v-deep
*
{
margin
:
0
;
padding
:
0
;
}
}
}
.empty
{
...
...
client/src/modules/viewer/components/upload.vue
→
client/src/modules/viewer/components/
common/
upload.vue
浏览文件 @
bb3b7053
<
template
>
<div
class=
"upload"
>
<el-upload
action
:show-file-list=
"false"
:http-request=
"httpRequest"
>
<el-button
size=
"small"
icon=
"el-icon-upload"
>
点击上传
</el-button>
<slot></slot>
<el-button
type=
"text"
icon=
"el-icon-upload"
>
点击上传
</el-button>
<template
v-slot:tip
>
<div
class=
"el-upload__tips"
>
<slot
name=
"tip"
></slot>
</div>
</
template
>
</el-upload>
<div
class=
"file-list"
v-if=
"
value
"
>
<div
class=
"file-list-item"
>
<a
:href=
"
value
"
target=
"_blank"
>
<div
class=
"file-list"
v-if=
"
fileList.length
"
>
<div
class=
"file-list-item"
v-for=
"(fileUrl, index) in fileList"
:key=
"index"
>
<a
:href=
"
fileUrl
"
target=
"_blank"
>
<i
class=
"el-icon-document"
></i>
{{ fileName }}
{{ file
Url | file
Name }}
</a>
<a
:href=
"
value"
:download=
"
fileName"
target=
"_blank"
>
<a
:href=
"
fileUrl"
:download=
"fileUrl |
fileName"
target=
"_blank"
>
<el-tooltip
effect=
"dark"
content=
"下载"
>
<i
class=
"el-icon-download"
></i>
</el-tooltip>
...
...
@@ -25,36 +26,43 @@
</template>
<
script
>
import
*
as
api
from
'../
api/index
'
import
*
as
api
from
'../
../api
'
export
default
{
name
:
'VUpload'
,
props
:
{
value
:
{
type
:
String
}
value
:
{
type
:
[
String
,
Array
]
}
},
data
()
{
return
{}
return
{
fileList
:
[]
}
},
watch
:
{
value
(
value
)
{
if
(
value
)
{
this
.
fileList
=
Array
.
isArray
(
value
)
?
value
:
[
value
]
}
}
},
computed
:
{
fileName
()
{
return
this
.
value
?
this
.
value
.
split
(
'/'
).
pop
()
:
''
filters
:
{
fileName
(
value
)
{
return
value
?
value
.
split
(
'/'
).
pop
()
:
''
}
},
methods
:
{
httpRequest
(
xhr
)
{
api
.
uploadFile
({
file
:
xhr
.
file
})
.
then
(
response
=>
{
if
(
response
.
success
)
{
api
.
uploadFile
({
file
:
xhr
.
file
}).
then
(
response
=>
{
if
(
response
.
success
)
{
if
(
Array
.
isArray
(
this
.
value
))
{
this
.
fileList
.
push
(
response
.
url
)
this
.
$emit
(
'input'
,
this
.
fileList
)
}
else
{
this
.
fileList
=
[
response
.
url
]
this
.
$emit
(
'input'
,
response
.
url
)
}
})
.
catch
(
error
=>
{
console
.
log
(
error
)
})
},
handleRemove
()
{
this
.
$emit
(
'input'
,
''
)
}
})
}
}
}
...
...
@@ -66,6 +74,7 @@ export default {
margin-bottom
:
10px
;
padding
:
0
10px
;
justify-content
:
space-between
;
line-height
:
30px
;
background-color
:
#fff
;
border-radius
:
4px
;
...
...
client/src/modules/viewer/components/layout.vue
浏览文件 @
bb3b7053
...
...
@@ -11,12 +11,13 @@
<
script
>
// components
import
ChapterPlayer
from
'../src/player/ChapterPlayer.vue'
// 章节视频
import
ChapterWork
from
'../src/work/index.vue'
// 章节作业
import
ChapterRead
from
'../src/read/chapterRead.vue'
// 章节资料
import
CourseWork
from
'../src/work/courseWork.vue'
// 课程大作业
import
CourseRead
from
'../src/read/courseRead.vue'
// 课程资料
import
CourseExam
from
'../src/work/courseExam.vue'
// 课程资料
import
ChapterPlayer
from
'./player/ChapterPlayer.vue'
// 章节视频
import
ChapterWork
from
'./work/index.vue'
// 章节作业
import
ChapterRead
from
'./read/chapterRead.vue'
// 章节资料
import
ChapterLive
from
'./live/chapterLive.vue'
// 章节直播
import
CourseWork
from
'./work/courseWork.vue'
// 课程大作业
import
CourseRead
from
'./read/courseRead.vue'
// 课程资料
import
CourseExam
from
'./work/courseExam.vue'
// 课程考试
export
default
{
name
:
'ViewerLayout'
,
...
...
@@ -24,12 +25,18 @@ export default {
ChapterPlayer
,
ChapterWork
,
ChapterRead
,
ChapterLive
,
CourseWork
,
CourseRead
,
CourseExam
},
props
:
{
chapter
:
{
type
:
Object
,
default
:
()
=>
{}
}
chapter
:
{
type
:
Object
,
default
()
{
return
{}
}
}
},
computed
:
{
currentCompoent
()
{
...
...
client/src/modules/viewer/components/live/chapterLive.vue
0 → 100644
浏览文件 @
bb3b7053
<
template
>
<div
style=
"width:100%;height:100%;"
>
<iframe
:src=
"iframeUrl"
frameborder=
"0"
width=
"100%"
height=
"100%"
allow=
"autoplay;geolocation;microphone;camera;midi;encrypted-media;"
></iframe>
</div>
</
template
>
<
script
>
// 章节视频
export
default
{
name
:
'ChapterLive'
,
props
:
{
// 当前选中的
chapter
:
{
type
:
Object
,
default
()
{
return
{}
}
},
// 课程详情接口返回的数据
data
:
{
type
:
Object
,
default
()
{
return
{}
}
}
},
computed
:
{
user
()
{
return
window
.
G
.
UserInfo
?
window
.
G
.
UserInfo
.
student_info
:
{}
},
nickName
()
{
return
this
.
user
.
personal_name
||
'匿名'
},
iframeUrl
()
{
const
live
=
this
.
chapter
.
live
const
liveStatus
=
live
.
live_status
live
.
viewer_name
=
live
.
viewer_name
||
this
.
nickName
if
(
liveStatus
===
103
&&
live
.
enable_record
===
1
)
{
// enable_record 0:不启用回放 1:开启回放
// 查看回放
return
`https://view.csslcloud.net/api/view/callback?recordid=
${
live
.
record_id
}
&roomid=
${
live
.
room_id
}
&userid=
${
live
.
user_id
}
&autoLogin=true&viewername=
${
live
.
viewer_name
}
&viewertoken=
${
live
.
viewer_token
}
`
}
else
{
// 直播
return
`https://view.csslcloud.net/api/view/index?roomid=
${
live
.
room_id
}
&userid=
${
live
.
user_id
}
&autoLogin=true&viewername=
${
live
.
viewer_name
}
&viewertoken=
${
live
.
viewer_token
}
`
}
}
}
}
</
script
>
client/src/modules/viewer/
src
/player/chapterPlayer.vue
→
client/src/modules/viewer/
components
/player/chapterPlayer.vue
浏览文件 @
bb3b7053
...
...
@@ -31,7 +31,7 @@
<
script
>
// api
import
*
as
api
from
'../../api
/index
'
import
*
as
api
from
'../../api'
// components
import
videoPlayer
from
'./videoPlayer.vue'
import
pptPlayer
from
'./pptPlayer.vue'
...
...
client/src/modules/viewer/
src
/player/pptPlayer.vue
→
client/src/modules/viewer/
components
/player/pptPlayer.vue
浏览文件 @
bb3b7053
File moved
client/src/modules/viewer/
src
/player/videoPlayer.vue
→
client/src/modules/viewer/
components
/player/videoPlayer.vue
浏览文件 @
bb3b7053
File moved
client/src/modules/viewer/
src
/read/chapterRead.vue
→
client/src/modules/viewer/
components
/read/chapterRead.vue
浏览文件 @
bb3b7053
...
...
@@ -7,8 +7,8 @@
<
script
>
// components
import
Container
from
'../
../components
/container.vue'
import
FileList
from
'../
../components
/fileList.vue'
import
Container
from
'../
common
/container.vue'
import
FileList
from
'../
common
/fileList.vue'
// 章节阅读资料
export
default
{
...
...
@@ -16,9 +16,19 @@ export default {
components
:
{
Container
,
FileList
},
props
:
{
// 当前选中的
chapter
:
{
type
:
Object
,
default
:
()
=>
{}
},
chapter
:
{
type
:
Object
,
default
()
{
return
{}
}
},
// 课程详情接口返回的数据
data
:
{
type
:
Object
,
default
:
()
=>
{}
}
data
:
{
type
:
Object
,
default
()
{
return
{}
}
}
},
computed
:
{
files
()
{
...
...
client/src/modules/viewer/
src
/read/courseRead.vue
→
client/src/modules/viewer/
components
/read/courseRead.vue
浏览文件 @
bb3b7053
...
...
@@ -7,8 +7,8 @@
<
script
>
// components
import
Container
from
'../
../components
/container.vue'
import
FileList
from
'../
../components
/fileList.vue'
import
Container
from
'../
common
/container.vue'
import
FileList
from
'../
common
/fileList.vue'
// 课程阅读资料
export
default
{
...
...
@@ -16,9 +16,19 @@ export default {
components
:
{
Container
,
FileList
},
props
:
{
// 当前选中的
chapter
:
{
type
:
Object
,
default
:
()
=>
{}
},
chapter
:
{
type
:
Object
,
default
()
{
return
{}
}
},
// 课程详情接口返回的数据
data
:
{
type
:
Object
,
default
:
()
=>
{}
}
data
:
{
type
:
Object
,
default
()
{
return
{}
}
}
},
computed
:
{
files
()
{
...
...
client/src/modules/viewer/components/fileList.vue
→
client/src/modules/viewer/components/
read/
fileList.vue
浏览文件 @
bb3b7053
File moved
client/src/modules/viewer/
src
/work/chapterExam.vue
→
client/src/modules/viewer/
components
/work/chapterExam.vue
浏览文件 @
bb3b7053
<
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"
size=
"medium"
>
<
chapter-
exam-item
<el-form
:disabled=
"isSubmited"
>
<exam-item
v-for=
"(item, index) in unorderedQuestions"
:disabled=
"isSubmited"
:data=
"item"
:value=
"findAnswerById(item.id)"
:index=
"index"
:type=
"item.question_type"
:data=
"item"
:value=
"item.formModel"
:disabled=
"isSubmited"
:key=
"item.id"
@
change=
"onChange(item.id, ...arguments)"
></chapter-exam-item>
></exam-item>
<div
class=
"exam-buttons"
>
<el-tooltip
effect=
"dark"
content=
"提交之后就不能修改了哦"
placement=
"right"
>
<el-button
type=
"primary"
@
click=
"onSubmit"
>
{{submitText}}
</el-button>
...
...
@@ -27,36 +28,51 @@
// libs
import
{
shuffle
}
from
'lodash'
// components
import
Container
from
'../
../components
/container.vue'
import
ChapterExamItem
from
'./chapterE
xamItem.vue'
import
Container
from
'../
common
/container.vue'
import
ExamItem
from
'./e
xamItem.vue'
// api
import
*
as
api
from
'../../api
/index
'
import
*
as
api
from
'../../api'
// 章节测试题
export
default
{
name
:
'ChapterExam'
,
components
:
{
Container
,
Chapter
ExamItem
},
components
:
{
Container
,
ExamItem
},
props
:
{
// 当前选中的章节
chapter
:
{
type
:
Object
,
default
:
()
=>
{}
}
chapter
:
{
type
:
Object
,
default
()
{
return
{}
}
}
},
data
()
{
return
{
loading
:
false
,
detail
:
null
,
values
:
[],
// 提交的答案
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
'6552021107166150656'
return
this
.
$route
.
params
.
sid
},
// 课程ID
cid
()
{
return
'6568035374902280192'
return
this
.
$route
.
params
.
cid
},
// 当前页面的ID
pid
()
{
...
...
@@ -66,33 +82,12 @@ export default {
resourceId
()
{
return
this
.
chapter
.
resource_id
},
// 问题列表
questions
()
{
const
homework
=
this
.
chapter
.
homework
return
homework
?
homework
.
questions
:
[]
},
// 打乱顺序的问题列表
unorderedQuestions
()
{
const
ids
=
this
.
questions
.
map
(
item
=>
item
.
id
)
const
sortIds
=
shuffle
(
ids
)
return
sortIds
.
map
(
id
=>
this
.
questions
.
find
(
item
=>
item
.
id
===
id
))
},
/**
* 解析用户提交的数据
* @return [{{ question_id: 'xxx', value: ['xxx', 'xxx'] }}]
*/
answers
()
{
const
answers
=
this
.
isSubmited
?
JSON
.
parse
(
this
.
detail
.
work_contents
)
:
[]
return
answers
.
map
(
item
=>
{
const
ids
=
item
.
options
.
reduce
((
result
,
subitem
)
=>
{
subitem
.
selected
&&
result
.
push
(
subitem
.
id
)
return
result
},
[])
return
{
question_id
:
item
.
question_id
,
value
:
ids
}
})
},
// 是否提交
isSubmited
()
{
return
this
.
detail
?
!!
this
.
detail
.
work_contents
:
false
...
...
@@ -110,33 +105,78 @@ export default {
.
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
})
},
// 通过问题ID查找答案
findAnswerById
(
id
)
{
const
found
=
this
.
answers
.
find
(
item
=>
item
.
question_id
===
id
)
return
found
?
found
.
value
:
[]
},
onChange
(
qid
,
value
)
{
const
index
=
this
.
values
.
findIndex
(
item
=>
item
.
question_id
===
qid
)
if
(
index
===
-
1
)
{
this
.
values
.
push
({
question_id
:
qid
,
value
})
}
else
{
this
.
values
.
splice
(
index
,
1
,
{
question_id
:
qid
,
value
})
// 组装问题数据
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
()
{
if
(
this
.
values
.
length
!==
this
.
questions
.
length
)
{
return
false
}
const
values
=
this
.
values
for
(
let
i
=
0
;
i
<
values
.
length
;
i
++
)
{
const
options
=
values
[
i
].
value
if
(
!
options
.
length
)
{
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
}
}
...
...
@@ -144,6 +184,7 @@ export default {
},
// 提交
onSubmit
()
{
// 校验
if
(
!
this
.
checkSubmit
())
{
this
.
messageInstance
&&
this
.
messageInstance
.
close
()
this
.
messageInstance
=
this
.
$message
.
error
(
'还有题目未做,不能提交'
)
...
...
@@ -176,21 +217,25 @@ export default {
// 提交的答案数据
handleSubmitData
()
{
const
result
=
this
.
questions
.
map
(
item
=>
{
// 查找提交的option id
const
found
=
this
.
values
.
find
(
subitem
=>
subitem
.
question_id
===
item
.
id
)
const
ids
=
found
?
found
.
value
:
[]
// 解析
const
parseOptions
=
JSON
.
parse
(
item
.
question_options
)
// 设置提交选中状态
let
isCorrect
=
true
const
options
=
parseOptions
.
map
(
option
=>
{
option
.
selected
=
ids
.
includes
(
option
.
id
)
?
1
:
0
if
(
option
.
checked
!==
!!
option
.
selected
&&
isCorrect
)
{
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
option
return
{
id
:
option
.
id
,
checked
:
option
.
checked
,
option
:
option
.
option
,
selected
}
})
return
{
question_id
:
item
.
id
,
...
...
client/src/modules/viewer/
src
/work/chapterWork.vue
→
client/src/modules/viewer/
components
/work/chapterWork.vue
浏览文件 @
bb3b7053
<
template
>
<container
:title=
"chapter.name"
v-loading=
"loading"
>
<chapter-work-item
v-for=
"(item, index) in questions"
:disabled=
"isSubmited"
:data=
"item"
:index=
"index"
:key=
"item.id"
@
change=
"onChange(item.id, ...arguments)"
></chapter-work-item>
<div
class=
"exam-form"
>
<el-form
:disabled=
"isRevised"
>
<exam-item
v-for=
"(item, index) in questions"
:index=
"index"
:type=
"item.question_type"
:data=
"item"
:value=
"item.formModel"
:disabled=
"isRevised"
:key=
"item.id"
></exam-item>
</el-form>
</div>
<div
class=
"work-bottom"
v-if=
"detail"
>
<div
class=
"info"
>
<template
v-if=
"isRevised"
>
...
...
@@ -26,7 +31,7 @@
</
template
>
<
template
v-else-if=
"detail.created_time"
>
<p
class=
"help"
>
已于
{{
detail
.
created_time
}}
提交,等待老师批改中。
</p>
<template
v-if=
"detail.updated_time !== detail.created_time"
>
<template
v-if=
"detail.updated_time
&& detail.updated_time
!== detail.created_time"
>
<p
class=
"help"
>
最近提交时间:
{{
detail
.
updated_time
}}
</p>
</
template
>
</template>
...
...
@@ -41,52 +46,61 @@
</template>
<
script
>
import
Base64
from
'Base64'
// componets
import
Container
from
'../
../components
/container.vue'
import
ChapterWorkItem
from
'./chapterWork
Item.vue'
import
Container
from
'../
common
/container.vue'
import
ExamItem
from
'./exam
Item.vue'
// api
import
*
as
api
from
'../../api
/index
'
import
*
as
api
from
'../../api'
// 章节作业
export
default
{
name
:
'ChapterWork'
,
components
:
{
Container
,
ChapterWork
Item
},
components
:
{
Container
,
Exam
Item
},
props
:
{
// 当前选中的
chapter
:
{
type
:
Object
,
default
:
()
=>
{}
},
chapter
:
{
type
:
Object
,
default
()
{
return
{}
}
},
// 课程详情接口返回的数据
data
:
{
type
:
Object
,
default
:
()
=>
{}
}
data
:
{
type
:
Object
,
default
()
{
return
{}
}
}
},
data
()
{
return
{
ruleForm
:
{
essay_name
:
''
,
essay_description
:
''
,
url
:
''
},
rules
:
{
essay_name
:
[
{
required
:
true
,
message
:
'请输入主题'
,
trigger
:
'blur'
},
{
max
:
5
,
message
:
'最多输入 50 个字符'
,
trigger
:
'blur'
}
],
essay_description
:
[
{
required
:
true
,
message
:
'请输入正文'
,
trigger
:
'blur'
}
],
url
:
[{
required
:
true
,
message
:
'请上传附件'
,
trigger
:
'change'
}]
},
detail
:
null
,
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
'6552021107166150656'
return
this
.
$route
.
params
.
sid
},
// 课程ID
cid
()
{
return
'6568035374902280192'
return
this
.
$route
.
params
.
cid
},
// 当前页面的ID
pid
()
{
...
...
@@ -96,11 +110,6 @@ export default {
resourceId
()
{
return
this
.
chapter
.
resource_id
},
// 问题列表
questions
()
{
const
homework
=
this
.
chapter
.
homework
return
homework
?
homework
.
questions
:
[]
},
// 是否批改
isRevised
()
{
return
this
.
detail
?
!!
this
.
detail
.
check_date
:
false
...
...
@@ -119,30 +128,113 @@ export default {
.
then
(
response
=>
{
this
.
detail
=
Array
.
isArray
(
response
)
?
null
:
response
if
(
this
.
detail
)
{
this
.
ruleForm
.
essay_name
=
this
.
detail
.
essay_name
this
.
ruleForm
.
essay_description
=
this
.
detail
.
essay_description
this
.
ruleForm
.
url
=
this
.
detail
.
file_url
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
)
{
item
.
user_answer
=
found
.
descreption
item
.
attachments
=
found
.
file_url
}
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
()
{
this
.
$refs
.
ruleForm
.
validate
()
.
then
(
response
=>
{
const
params
=
Object
.
assign
(
this
.
ruleForm
,
{
semester_id
:
this
.
sid
,
course_id
:
this
.
cid
})
this
.
handleSubmitRequest
(
params
)
})
.
catch
(()
=>
{
this
.
messageInstance
&&
this
.
messageInstance
.
close
()
this
.
messageInstance
=
this
.
$message
.
error
(
'还有题目未做,不能提交'
)
})
// 校验
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
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
,
file_url
:
item
.
formModel
.
attachments
,
is_encoded
:
1
}
})
// 提交参数
const
params
=
{
semester_id
:
this
.
sid
,
course_id
:
this
.
cid
,
chapter_id
:
this
.
pid
,
work_id
:
this
.
resourceId
,
work_contents
:
JSON
.
stringify
(
answers
),
duration
}
// 请求接口
this
.
handleSubmitRequest
(
params
)
},
// 请求提交接口
handleSubmitRequest
(
params
)
{
...
...
client/src/modules/viewer/components/work/courseExam.vue
0 → 100644
浏览文件 @
bb3b7053
差异被折叠。
点击展开。
client/src/modules/viewer/
src
/work/courseWork.vue
→
client/src/modules/viewer/
components
/work/courseWork.vue
浏览文件 @
bb3b7053
...
...
@@ -25,9 +25,10 @@
<!-- 编辑器 -->
<v-editor
:disabled=
"isRevised"
v-model=
"ruleForm.essay_description"
></v-editor>
</el-form-item>
<el-form-item
label=
"附件"
prop=
"url"
>
<el-form-item
prop=
"url"
>
<!-- 文件上传 -->
<v-upload
v-model=
"ruleForm.url"
>
请上传对应的文件附件:
<!--
<template
v-slot:tip
>
只支持docx格式的文件,文件小于10M
</
template
>
-->
</v-upload>
</el-form-item>
...
...
@@ -53,7 +54,7 @@
</
template
>
<
template
v-else-if=
"detail.created_time"
>
<p
class=
"help"
>
已于
{{
detail
.
created_time
}}
提交,等待老师批改中。
</p>
<template
v-if=
"detail.updated_time !== detail.created_time"
>
<template
v-if=
"detail.updated_time
&& detail.updated_time
!== detail.created_time"
>
<p
class=
"help"
>
最近提交时间:
{{
detail
.
updated_time
}}
</p>
</
template
>
</template>
...
...
@@ -72,11 +73,11 @@
<
script
>
// componets
import
Container
from
'../
../components
/container.vue'
import
VEditor
from
'../
../components
/editor.vue'
import
VUpload
from
'../
../components
/upload.vue'
import
Container
from
'../
common
/container.vue'
import
VEditor
from
'../
common
/editor.vue'
import
VUpload
from
'../
common
/upload.vue'
// api
import
*
as
api
from
'../../api
/index
'
import
*
as
api
from
'../../api'
// 课程大作业
export
default
{
...
...
@@ -84,9 +85,19 @@ export default {
components
:
{
Container
,
VEditor
,
VUpload
},
props
:
{
// 当前选中的
chapter
:
{
type
:
Object
,
default
:
()
=>
{}
},
chapter
:
{
type
:
Object
,
default
()
{
return
{}
}
},
// 课程详情接口返回的数据
data
:
{
type
:
Object
,
default
:
()
=>
{}
}
data
:
{
type
:
Object
,
default
()
{
return
{}
}
}
},
data
()
{
return
{
...
...
@@ -113,11 +124,11 @@ export default {
computed
:
{
// 学期ID
sid
()
{
return
'6552021107166150656'
return
this
.
$route
.
params
.
sid
},
// 课程ID
cid
()
{
return
'6568035374902280192'
return
this
.
$route
.
params
.
cid
},
// 是否批改
isRevised
()
{
...
...
client/src/modules/viewer/
src/work/chapterWork
Item.vue
→
client/src/modules/viewer/
components/work/exam
Item.vue
浏览文件 @
bb3b7053
<
template
>
<div
class=
"q-item"
>
<div
class=
"q-item-hd"
>
<div
class=
"q-item-num"
>
{{
currentIndex
}}
.
</div>
<div
class=
"q-item-title"
v-html=
"data.
question_content"
>
</div>
<div
class=
"q-item-aside"
v-if=
"
currentTypeText"
>
(
{{
currentT
ypeText
}}
)
</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-aside"
v-if=
"
typeText"
>
(
{{
t
ypeText
}}
)
</div>
</div>
<div
class=
"q-item-bd"
>
<!-- 单选 -->
<el-radio-group
v-model=
"
radioValue"
@
change=
"onRadioChange"
v-if=
"currentT
ype === 1"
>
<el-radio-group
v-model=
"
currentValue.user_answer"
v-if=
"t
ype === 1"
>
<div
class=
"q-option-item"
v-for=
"item in currentOptions"
:key=
"item.id"
>
<el-radio
:class=
"genClass(item)"
:label=
"item.id"
>
{{
item
.
abc_option
}}
</el-radio>
</div>
</el-radio-group>
<!-- 多选 -->
<el-checkbox-group
v-model=
"checkboxValue"
@
change=
"onCheckboxChange"
v-if=
"currentType === 2"
>
<el-checkbox-group
v-model=
"currentValue.user_answer"
v-if=
"type === 2"
>
<div
class=
"q-option-item"
v-for=
"item in currentOptions"
:key=
"item.id"
>
<el-checkbox
:class=
"genClass(item)"
:label=
"item.id"
>
{{
item
.
abc_option
}}
</el-checkbox>
</div>
</el-checkbox-group>
<!-- 简答题 -->
<v-editor></v-editor>
<v-upload></v-upload>
<template
v-if=
"type === 3"
>
<v-editor
v-model=
"currentValue.user_answer"
:disabled=
"disabled"
></v-editor>
<v-upload
v-model=
"currentValue.attachments"
>
请上传对应的文件附件:
</v-upload>
</
template
>
</div>
<div
class=
"q-item-ft"
v-if=
"disabled"
>
<p>
<span>
学生答案:
</span>
<span
:class=
"isCorrect ? 'is-success' : 'is-error'"
>
{{
submitAnswerText
}}
</span>
</p>
<p>
<span>
正确答案:
</span>
<span>
{{
correctAnswerText
}}
</span>
</p>
<
template
v-if=
"type === 3"
>
<p>
<span>
老师评语:
</span>
<span>
{{
data
.
check_comment
}}
</span>
</p>
</
template
>
<
template
v-else
>
<p>
<span>
学生答案:
</span>
<span
:class=
"isCorrect ? 'is-success' : 'is-error'"
>
{{
submitAnswerText
}}
</span>
</p>
<p>
<span>
正确答案:
</span>
<span>
{{
correctAnswerText
}}
</span>
</p>
</
template
>
</div>
</div>
</template>
<
script
>
import
VEditor
from
'../../components/editor.vue'
import
VUpload
from
'../../components/upload.vue'
// components
import
VEditor
from
'../common/editor.vue'
import
VUpload
from
'../common/upload.vue'
export
default
{
name
:
'
Chapter
ExamItem'
,
name
:
'ExamItem'
,
components
:
{
VEditor
,
VUpload
},
props
:
{
// 索引
index
:
{
type
:
Number
},
// 问题类型
type
:
{
type
:
Number
},
// 单条数据
data
:
{
type
:
Object
,
default
:
()
=>
{}
},
data
:
{
type
:
Object
,
default
()
{
return
{}
}
},
// 提交的答案
value
:
{
type
:
Array
,
default
:
()
=>
[]
},
value
:
{
type
:
Object
,
default
()
{
return
{}
}
},
// 是否禁用,提交过的是禁用状态
disabled
:
{
type
:
Boolean
,
default
:
false
}
},
data
()
{
return
{
radioValue
:
''
,
checkboxValue
:
[]
currentValue
:
{}
}
},
watch
:
{
value
:
{
immediate
:
true
,
handler
(
value
)
{
if
(
this
.
currentType
===
1
)
{
this
.
radioValue
=
value
[
0
]
||
''
}
else
{
this
.
checkboxValue
=
value
}
this
.
currentValue
=
value
}
}
},
...
...
@@ -82,33 +97,25 @@ export default {
}
return
result
},
// 序号
currentIndex
()
{
return
this
.
index
+
1
},
// 当前类型
currentType
()
{
return
this
.
data
.
question_type
},
// 选项类型
currentT
ypeText
()
{
t
ypeText
()
{
const
map
=
{
1
:
'单选题'
,
2
:
'多选题'
}
return
map
[
this
.
currentType
]
},
// 接口返回的options数据
options
()
{
return
this
.
data
.
question_options
?
JSON
.
parse
(
this
.
data
.
question_options
)
:
[]
return
map
[
this
.
type
]
},
// 处理后的options数据
currentOptions
()
{
return
this
.
options
.
map
((
item
,
index
)
=>
{
if
(
!
this
.
data
.
options
)
{
return
[]
}
return
this
.
data
.
options
.
map
((
item
,
index
)
=>
{
// 英文字母 + 名称
item
.
abc
=
this
.
A_Z
[
index
]
item
.
abc_option
=
`
${
this
.
A_Z
[
index
]}
.
${
item
.
option
}
`
// 提交时的选中状态
item
.
selected
=
this
.
value
.
includes
(
item
.
id
)
const
value
=
this
.
value
.
user_answer
||
''
item
.
selected
=
Array
.
isArray
(
value
)
?
value
.
includes
(
item
.
id
)
:
value
===
item
.
id
return
item
})
},
...
...
@@ -146,17 +153,9 @@ export default {
return
null
}
return
{
'is-error'
:
item
.
selected
!==
item
.
check
ed
,
'is-success'
:
item
.
check
ed
'is-error'
:
!
this
.
isCorrect
&&
item
.
select
ed
,
'is-success'
:
this
.
isCorrect
&&
item
.
select
ed
}
},
// 单选
onRadioChange
(
value
)
{
this
.
$emit
(
'change'
,
[
value
])
},
// 多选
onCheckboxChange
(
value
)
{
this
.
$emit
(
'change'
,
value
)
}
}
}
...
...
@@ -167,6 +166,9 @@ export default {
font-size
:
16px
;
padding
:
10px
0
;
border-bottom
:
1px
solid
#c9c9c9
7a
;
.upload
{
font-size
:
14px
;
}
}
.q-item-hd
{
display
:
flex
;
...
...
@@ -176,6 +178,11 @@ export default {
margin
:
0
;
padding
:
0
;
}
::v-deep
ul
{
margin
:
0
;
padding
:
0
;
list-style
:
none
;
}
}
.q-item-num
{
width
:
20px
;
...
...
client/src/modules/viewer/
src
/work/index.vue
→
client/src/modules/viewer/
components
/work/index.vue
浏览文件 @
bb3b7053
...
...
@@ -19,9 +19,19 @@ export default {
components
:
{
ChapterWork
,
ChapterExam
},
props
:
{
// 当前选中的
chapter
:
{
type
:
Object
,
default
:
()
=>
{}
},
chapter
:
{
type
:
Object
,
default
()
{
return
{}
}
},
// 课程详情接口返回的数据
data
:
{
type
:
Object
,
default
:
()
=>
{}
}
data
:
{
type
:
Object
,
default
()
{
return
{}
}
}
},
computed
:
{
currentCompoent
()
{
...
...
client/src/modules/viewer/index.vue
浏览文件 @
bb3b7053
...
...
@@ -3,7 +3,7 @@
<div
class=
"course-viewer-main"
>
<!-- 顶部区域 -->
<div
class=
"course-viewer-main-hd"
>
<router-link
to=
"/mobile/help/student
"
>
<router-link
:to=
"`/app/learn/course-detail/$
{sid}/${cid}`
">
<i
class=
"el-icon-arrow-left"
></i>
</router-link>
<h1
class=
"course-viewer-main-hd__title"
>
{{
detail
.
course_name
}}
</h1>
...
...
@@ -48,7 +48,7 @@
<
script
>
// api
import
*
as
api
from
'./api
/index
'
import
*
as
api
from
'./api'
// components
import
VAside
from
'./components/aside/index.vue'
...
...
@@ -71,11 +71,11 @@ export default {
computed
:
{
// 学期ID
sid
()
{
return
'6552021107166150656'
return
this
.
$route
.
params
.
sid
},
// 课程ID
cid
()
{
return
'6568035374902280192'
return
this
.
$route
.
params
.
cid
},
// 当前页面的ID
pid
()
{
...
...
@@ -84,17 +84,20 @@ export default {
// 章节列表
chapters
()
{
const
chapters
=
this
.
detail
.
chapters
||
[]
return
chapters
.
concat
([
{
name
:
'大作业及资料'
,
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
}
]
}
])
if
(
!
chapters
.
length
)
{
return
[]
}
const
customeChapter
=
{
name
:
'大作业及资料'
,
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
}
]
}
chapters
.
push
(
customeChapter
)
return
chapters
},
// 当前选中的章节
activeChapter
()
{
...
...
client/src/modules/viewer/routes.js
浏览文件 @
bb3b7053
export
default
[
{
path
:
'/viewer'
,
path
:
'/viewer
/:sid/:cid
'
,
component
:
()
=>
import
(
'./index.vue'
),
children
:
[
{
...
...
client/src/modules/viewer/src/live/chapterLive.vue
deleted
100644 → 0
浏览文件 @
c54eb22e
<
template
></
template
>
<
script
>
// 章节视频
export
default
{
name
:
'ChapterPlayer'
}
</
script
>
client/src/modules/viewer/src/work/chapterExamItem.vue
deleted
100644 → 0
浏览文件 @
c54eb22e
<
template
>
<div
class=
"q-item"
>
<div
class=
"q-item-hd"
>
<div
class=
"q-item-num"
>
{{
currentIndex
}}
.
</div>
<div
class=
"q-item-title"
v-html=
"data.question_content"
></div>
<div
class=
"q-item-aside"
>
(
{{
currentTypeText
}}
)
</div>
</div>
<div
class=
"q-item-bd"
>
<!-- 单选 -->
<el-radio-group
v-model=
"radioValue"
@
change=
"onRadioChange"
v-if=
"currentType === 1"
>
<div
class=
"q-option-item"
v-for=
"item in currentOptions"
:key=
"item.id"
>
<el-radio
:class=
"genClass(item)"
:label=
"item.id"
>
{{
item
.
abc_option
}}
</el-radio>
</div>
</el-radio-group>
<!-- 多选 -->
<el-checkbox-group
v-model=
"checkboxValue"
@
change=
"onCheckboxChange"
v-if=
"currentType === 2"
>
<div
class=
"q-option-item"
v-for=
"item in currentOptions"
:key=
"item.id"
>
<el-checkbox
:class=
"genClass(item)"
:label=
"item.id"
>
{{
item
.
abc_option
}}
</el-checkbox>
</div>
</el-checkbox-group>
</div>
<div
class=
"q-item-ft"
v-if=
"disabled"
>
<p>
<span>
学生答案:
</span>
<span
:class=
"isCorrect ? 'is-success' : 'is-error'"
>
{{
submitAnswerText
}}
</span>
</p>
<p>
<span>
正确答案:
</span>
<span>
{{
correctAnswerText
}}
</span>
</p>
</div>
</div>
</
template
>
<
script
>
export
default
{
name
:
'ChapterExamItem'
,
props
:
{
// 索引
index
:
{
type
:
Number
},
// 单条数据
data
:
{
type
:
Object
,
default
:
()
=>
{}
},
// 提交的答案
value
:
{
type
:
Array
,
default
:
()
=>
[]
},
// 是否禁用,提交过的是禁用状态
disabled
:
{
type
:
Boolean
,
default
:
false
}
},
data
()
{
return
{
radioValue
:
''
,
checkboxValue
:
[]
}
},
watch
:
{
value
:
{
immediate
:
true
,
handler
(
value
)
{
if
(
this
.
currentType
===
1
)
{
this
.
radioValue
=
value
[
0
]
||
''
}
else
{
this
.
checkboxValue
=
value
}
}
}
},
computed
:
{
// 26个英文字母
A_Z
()
{
const
result
=
[]
for
(
let
i
=
0
;
i
<
26
;
i
++
)
{
result
.
push
(
String
.
fromCharCode
(
65
+
i
))
}
return
result
},
// 序号
currentIndex
()
{
return
this
.
index
+
1
},
// 当前类型
currentType
()
{
return
this
.
data
.
question_type
},
// 选项类型
currentTypeText
()
{
const
map
=
{
1
:
'单选题'
,
2
:
'多选题'
}
return
map
[
this
.
currentType
]
},
// 接口返回的options数据
options
()
{
return
this
.
data
.
question_options
?
JSON
.
parse
(
this
.
data
.
question_options
)
:
[]
},
// 处理后的options数据
currentOptions
()
{
return
this
.
options
.
map
((
item
,
index
)
=>
{
// 英文字母 + 名称
item
.
abc
=
this
.
A_Z
[
index
]
item
.
abc_option
=
`
${
this
.
A_Z
[
index
]}
.
${
item
.
option
}
`
// 提交时的选中状态
item
.
selected
=
this
.
value
.
includes
(
item
.
id
)
return
item
})
},
// 正确答案显示的英文字母
correctAnswerText
()
{
const
result
=
this
.
currentOptions
.
reduce
((
result
,
item
)
=>
{
item
.
checked
&&
result
.
push
(
item
.
abc
)
return
result
},
[])
return
result
.
join
(
'、'
)
},
// 提交答案显示的英文字母
submitAnswerText
()
{
const
result
=
this
.
currentOptions
.
reduce
((
result
,
item
)
=>
{
item
.
selected
&&
result
.
push
(
item
.
abc
)
return
result
},
[])
return
result
.
join
(
'、'
)
},
// 是否回答正确
isCorrect
()
{
const
options
=
this
.
currentOptions
for
(
let
i
=
0
;
i
<
options
.
length
;
i
++
)
{
if
(
options
[
i
].
checked
!==
!!
options
[
i
].
selected
)
{
return
false
}
}
return
true
}
},
methods
:
{
// 生成class
genClass
(
item
)
{
if
(
!
this
.
disabled
)
{
return
null
}
return
{
'is-error'
:
item
.
selected
!==
item
.
checked
,
'is-success'
:
item
.
checked
}
},
// 单选
onRadioChange
(
value
)
{
this
.
$emit
(
'change'
,
[
value
])
},
// 多选
onCheckboxChange
(
value
)
{
this
.
$emit
(
'change'
,
value
)
}
}
}
</
script
>
<
style
lang=
"scss"
scoped
>
.q-item
{
font-size
:
16px
;
padding
:
10px
0
;
border-bottom
:
1px
solid
#c9c9c9
7a
;
}
.q-item-hd
{
display
:
flex
;
padding
:
10px
0
20px
;
::v-deep
p
{
margin
:
0
;
padding
:
0
;
}
}
.q-item-num
{
width
:
20px
;
text-align
:
center
;
}
.q-item-title
{
flex
:
1
;
padding
:
0
10px
;
}
.q-item-aside
{
padding-left
:
20px
;
// align-self: flex-end;
}
.q-option-item
{
padding-left
:
30px
;
margin-bottom
:
14px
;
}
.is-success
{
color
:
#090
;
}
.is-error
{
color
:
#d80000
;
}
::v-deep
.el-radio
{
&
.is-disabled
.el-radio__label
{
color
:
#3c3c3c
;
}
&
.is-error
.el-radio__label
{
color
:
#d80000
;
}
&
.is-success
.el-radio__label
{
color
:
#090
;
}
}
::v-deep
.el-checkbox
{
&
.is-disabled
.el-checkbox__label
{
color
:
#3c3c3c
;
}
&
.is-error
.el-checkbox__label
{
color
:
#d80000
;
}
&
.is-success
.el-checkbox__label
{
color
:
#090
;
}
}
.q-item-ft
{
display
:
flex
;
justify-content
:
flex-end
;
padding
:
10px
0
;
p
{
font-size
:
14px
;
margin
:
0
;
padding-left
:
20px
;
}
}
</
style
>
client/src/modules/viewer/src/work/courseExam.vue
deleted
100644 → 0
浏览文件 @
c54eb22e
<
template
>
<container
:title=
"detail.title"
v-loading=
"loading"
>
<div
class=
"exam"
>
<div
class=
"exam-form"
>
<el-form
:disabled=
"isSubmited"
size=
"medium"
>
<course-exam-item
v-for=
"(item, index) in questions"
:index=
"index"
:type=
"item.type"
:data=
"item"
:key=
"item.id"
></course-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
>
// components
import
Container
from
'../../components/container.vue'
import
CourseExamItem
from
'./courseExamItem.vue'
// api
import
*
as
api
from
'../../api/index'
// 章节测试题
export
default
{
name
:
'CourseExam'
,
components
:
{
Container
,
CourseExamItem
},
props
:
{
// 当前选中的章节
chapter
:
{
type
:
Object
,
default
:
()
=>
{}
}
},
data
()
{
return
{
loading
:
false
,
detail
:
{},
// questions: [],
values
:
[],
// 提交的答案
startTime
:
new
Date
().
getTime
(),
// 进入时间
messageInstance
:
null
}
},
computed
:
{
// 学期ID
sid
()
{
return
'6552021107166150656'
},
// 课程ID
cid
()
{
return
'6568035374902280192'
},
// 当前页面的ID
pid
()
{
return
this
.
$route
.
params
.
id
},
// 问题列表
questions
()
{
if
(
!
this
.
detail
.
examination
)
{
return
[]
}
const
addKey
=
function
(
array
,
key
,
value
)
{
return
array
.
map
(
item
=>
{
item
[
key
]
=
value
return
item
})
}
let
{
radioList
,
checkboxList
,
shortAnswerList
}
=
this
.
detail
.
examination
// 单选
radioList
=
addKey
(
radioList
,
'type'
,
1
)
// 多选
checkboxList
=
addKey
(
checkboxList
,
'type'
,
2
)
// 问答
shortAnswerList
=
addKey
(
shortAnswerList
,
'type'
,
3
)
return
[...
radioList
,
...
checkboxList
,
...
shortAnswerList
]
},
// 是否提交
isSubmited
()
{
return
this
.
detail
?
!!
this
.
detail
.
work_contents
:
false
},
// 提交按钮文本
submitText
()
{
return
this
.
isSubmited
?
'已提交'
:
'提交'
}
},
methods
:
{
// 获取测试答题详情
getDetail
()
{
this
.
loading
=
true
api
.
getCourseExam
(
this
.
sid
,
this
.
cid
)
.
then
(
response
=>
{
this
.
detail
=
Array
.
isArray
(
response
)
?
null
:
response
})
.
finally
(()
=>
{
this
.
loading
=
false
})
},
// 通过问题ID查找答案
findAnswerById
(
id
)
{
const
found
=
this
.
answers
.
find
(
item
=>
item
.
question_id
===
id
)
return
found
?
found
.
value
:
[]
},
onChange
(
qid
,
value
)
{
const
index
=
this
.
values
.
findIndex
(
item
=>
item
.
question_id
===
qid
)
if
(
index
===
-
1
)
{
this
.
values
.
push
({
question_id
:
qid
,
value
})
}
else
{
this
.
values
.
splice
(
index
,
1
,
{
question_id
:
qid
,
value
})
}
},
// 提交校验
checkSubmit
()
{
if
(
this
.
values
.
length
!==
this
.
questions
.
length
)
{
return
false
}
const
values
=
this
.
values
for
(
let
i
=
0
;
i
<
values
.
length
;
i
++
)
{
const
options
=
values
[
i
].
value
if
(
!
options
.
length
)
{
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
=>
{
// 查找提交的option id
const
found
=
this
.
values
.
find
(
subitem
=>
subitem
.
question_id
===
item
.
id
)
const
ids
=
found
?
found
.
value
:
[]
// 解析
const
parseOptions
=
JSON
.
parse
(
item
.
question_options
)
// 设置提交选中状态
let
isCorrect
=
true
const
options
=
parseOptions
.
map
(
option
=>
{
option
.
selected
=
ids
.
includes
(
option
.
id
)
?
1
:
0
if
(
option
.
checked
!==
!!
option
.
selected
&&
isCorrect
)
{
isCorrect
=
false
}
return
option
})
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/src/work/courseExamItem.vue
deleted
100644 → 0
浏览文件 @
c54eb22e
<
template
>
<div
class=
"q-item"
>
<div
class=
"q-item-hd"
>
<div
class=
"q-item-num"
>
{{
currentIndex
}}
.
</div>
<div
class=
"q-item-title"
v-html=
"data.content"
>
{{
data
.
title
}}
</div>
<div
class=
"q-item-aside"
v-if=
"currentTypeText"
>
(
{{
currentTypeText
}}
)
</div>
</div>
<div
class=
"q-item-bd"
>
<!-- 单选 -->
<el-radio-group
v-model=
"radioValue"
@
change=
"onRadioChange"
v-if=
"currentType === 1"
>
<div
class=
"q-option-item"
v-for=
"item in currentOptions"
:key=
"item.id"
>
<el-radio
:class=
"genClass(item)"
:label=
"item.id"
>
{{
item
.
abc_option
}}
</el-radio>
</div>
</el-radio-group>
<!-- 多选 -->
<el-checkbox-group
v-model=
"checkboxValue"
@
change=
"onCheckboxChange"
v-if=
"currentType === 2"
>
<div
class=
"q-option-item"
v-for=
"item in currentOptions"
:key=
"item.id"
>
<el-checkbox
:class=
"genClass(item)"
:label=
"item.id"
>
{{
item
.
abc_option
}}
</el-checkbox>
</div>
</el-checkbox-group>
<!-- 简答题 -->
<template
v-if=
"currentType === 3"
>
<v-editor></v-editor>
<v-upload></v-upload>
</
template
>
</div>
</div>
</template>
<
script
>
// components
import
VEditor
from
'../../components/editor.vue'
import
VUpload
from
'../../components/upload.vue'
export
default
{
name
:
'CourseExamItem'
,
components
:
{
VEditor
,
VUpload
},
props
:
{
// 索引
index
:
{
type
:
Number
},
// 问题类型
type
:
{
type
:
Number
},
// 单条数据
data
:
{
type
:
Object
,
default
:
()
=>
{}
},
// 提交的答案
value
:
{
type
:
Array
,
default
:
()
=>
[]
},
// 是否禁用,提交过的是禁用状态
disabled
:
{
type
:
Boolean
,
default
:
false
}
},
data
()
{
return
{
radioValue
:
''
,
checkboxValue
:
[]
}
},
watch
:
{
value
:
{
immediate
:
true
,
handler
(
value
)
{
if
(
this
.
currentType
===
1
)
{
this
.
radioValue
=
value
[
0
]
||
''
}
else
{
this
.
checkboxValue
=
value
}
}
}
},
computed
:
{
// 26个英文字母
A_Z
()
{
const
result
=
[]
for
(
let
i
=
0
;
i
<
26
;
i
++
)
{
result
.
push
(
String
.
fromCharCode
(
65
+
i
))
}
return
result
},
// 序号
currentIndex
()
{
return
this
.
index
+
1
},
// 当前类型
currentType
()
{
return
this
.
type
||
this
.
data
.
question_type
},
// 选项类型
currentTypeText
()
{
const
map
=
{
1
:
'单选题'
,
2
:
'多选题'
}
return
map
[
this
.
currentType
]
},
// 处理后的options数据
currentOptions
()
{
return
this
.
data
.
options
.
map
((
item
,
index
)
=>
{
// 英文字母 + 名称
item
.
abc
=
this
.
A_Z
[
index
]
item
.
abc_option
=
`
${
this
.
A_Z
[
index
]}
.
${
item
.
option
}
`
// 提交时的选中状态
item
.
selected
=
this
.
value
.
includes
(
item
.
id
)
return
item
})
}
},
methods
:
{
// 生成class
genClass
(
item
)
{
if
(
!
this
.
disabled
)
{
return
null
}
return
{
'is-error'
:
item
.
selected
!==
item
.
checked
,
'is-success'
:
item
.
checked
}
},
// 单选
onRadioChange
(
value
)
{
this
.
$emit
(
'change'
,
[
value
])
},
// 多选
onCheckboxChange
(
value
)
{
this
.
$emit
(
'change'
,
value
)
}
}
}
</
script
>
<
style
lang=
"scss"
scoped
>
.q-item
{
font-size
:
16px
;
padding
:
10px
0
;
border-bottom
:
1px
solid
#c9c9c9
7a
;
}
.q-item-hd
{
display
:
flex
;
padding
:
10px
0
20px
;
::v-deep
p
{
margin
:
0
;
padding
:
0
;
}
}
.q-item-num
{
width
:
20px
;
text-align
:
center
;
}
.q-item-title
{
flex
:
1
;
padding
:
0
10px
;
}
.q-item-aside
{
padding-left
:
20px
;
// align-self: flex-end;
}
.q-option-item
{
padding-left
:
30px
;
margin-bottom
:
14px
;
}
.is-success
{
color
:
#090
;
}
.is-error
{
color
:
#d80000
;
}
::v-deep
.el-radio
{
&
.is-disabled
.el-radio__label
{
color
:
#3c3c3c
;
}
&
.is-error
.el-radio__label
{
color
:
#d80000
;
}
&
.is-success
.el-radio__label
{
color
:
#090
;
}
}
::v-deep
.el-checkbox
{
&
.is-disabled
.el-checkbox__label
{
color
:
#3c3c3c
;
}
&
.is-error
.el-checkbox__label
{
color
:
#d80000
;
}
&
.is-success
.el-checkbox__label
{
color
:
#090
;
}
}
.q-item-ft
{
display
:
flex
;
justify-content
:
flex-end
;
padding
:
10px
0
;
p
{
font-size
:
14px
;
margin
:
0
;
padding-left
:
20px
;
}
}
</
style
>
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论