Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
L
learn-online-pc
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
图表
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
EzijingWeb
learn-online-pc
Commits
ede512a4
提交
ede512a4
authored
1月 16, 2020
作者:
GOD_ZYX
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
开发 考试exam模块,前端开发完成,后端尚未完成
上级
8a3a33b7
隐藏空白字符变更
内嵌
并排
正在显示
11 个修改的文件
包含
985 行增加
和
0 行删除
+985
-0
exam.vue
client/client/components/player/exam/exam.vue
+468
-0
exam_api.js
client/client/components/services/api/exam_api.js
+25
-0
index.js
client/client/components/services/index.js
+3
-0
elemInfo.md
client/client/components/upload-form/elemInfo.md
+57
-0
index.js
client/client/components/upload-form/index.js
+8
-0
ajax.js
client/client/components/upload-form/src/ajax.js
+125
-0
uploadForm.vue
client/client/components/upload-form/src/uploadForm.vue
+182
-0
ExamAction.js
client/client/project/actions/ExamAction.js
+105
-0
index.js
client/client/project/actions/index.js
+3
-0
main.js
client/client/project/main.js
+3
-0
routes.js
client/client/project/router/routes.js
+6
-0
没有找到文件。
client/client/components/player/exam/exam.vue
0 → 100644
浏览文件 @
ede512a4
<
template
>
<div
class=
"play-paper"
>
<div
class=
"play-paper-body"
>
<div
class=
"play-paper-title"
><div><h3>
{{
chapterName
}}
</h3></div></div>
<div
class=
"play-paper-content play-chapter-exam"
>
<template
v-if=
"exam.id"
>
<div
class=
'exam'
>
<div
style=
'text-align: center;'
>
<div
class=
'topic'
>
<!--
<div
class=
'tit'
>
{{
exam
.
title
}}
</div>
-->
<template
v-if=
'exam.score'
><div
class=
'cur'
>
正确率:
{{
exam
.
score
}}
%
</div></
template
>
</div>
</div>
<!-- 单选题 -->
<
template
v-if=
'exam.radioList.length'
>
<template
v-for=
'(item, index) in exam.radioList'
>
<div
v-bind:key=
"item.id"
class=
'q-group'
:data-index=
'index'
>
<div
class=
'q-num'
>
{{
index
+
1
}}
.
</div><div
class=
'q-title'
v-html=
'item.content'
></div><div
class=
'q-type'
>
(单选题)
</div>
<el-radio-group
class=
'radio-group'
v-model=
"item.user_answer"
>
<template
v-for=
'(item1, index1) in item.options'
>
<el-radio
v-bind:key=
"item1.id"
:label=
'item1.id'
:disabled=
'!!item.right_answer'
:class=
'["radio", (item.right_answer ? (item1.id === item.user_answer ? "success" : "error") : "")]'
>
{{
index1
|
getLetter
()
}}
.
{{
item1
.
option
}}
</el-radio>
</
template
>
</el-radio-group>
<
template
v-if=
'item.right_answer'
><div
class=
'result'
>
学生答案:
<div
:class=
'["stu", (item.right_answer === item.user_answer ? "success" : "error")]'
>
{{
item
.
user_answer
|
getRadioAnswer
(
item
.
options
)
}}
</div>
正确答案:
{{
item
.
right_answer
|
getRadioAnswer
(
item
.
options
)
}}
</div></
template
>
</div>
</template>
</template>
<!-- 多选题 -->
<
template
v-if=
'exam.checkboxList.length'
>
<template
v-for=
'(item, index) in exam.checkboxList'
>
<div
v-bind:key=
"item.id"
class=
'q-group'
:data-index=
'index'
>
<div
class=
'q-num'
>
{{
exam
.
radioList
.
length
+
index
+
1
}}
.
</div><div
class=
'q-title'
v-html=
'item.content'
></div><div
class=
'q-type'
>
(多选题)
</div>
<el-checkbox-group
class=
'checkbox-group'
v-model=
"item.user_answer"
>
<template
v-for=
'(item1, index1) in item.options'
>
<el-checkbox
v-bind:key=
"item1.id"
:label=
'item1.id'
:disabled=
'!!item.right_answer.length'
:class=
'["checkbox", (item.right_answer.length ? (isCheckboxChecked(item1.id, item.right_answer) ? "success" : "error") : "")]'
>
{{
index1
|
getLetter
()
}}
.
{{
item1
.
option
}}
</el-checkbox>
</
template
>
</el-checkbox-group>
<
template
v-if=
'item.right_answer.length'
><div
class=
'result'
>
学生答案:
<div
:class=
'["stu", ((item.right_answer.length && isCheckboxRight(item.user_answer, item.right_answer)) ? "success" : "error")]'
>
{{
item
.
user_answer
|
getCheckboxAnswer
(
item
.
options
)
}}
</div>
正确答案:
{{
item
.
right_answer
|
getCheckboxAnswer
(
item
.
options
)
}}
</div></
template
>
</div>
</template>
</template>
<!-- 简答题 -->
<
template
v-if=
'exam.shortAnswerList.length'
>
<template
v-for=
'(item, index) in exam.shortAnswerList'
>
<div
class=
'q-group'
>
<div
class=
'q-sa-title'
>
{{
exam
.
radioList
.
length
+
exam
.
checkboxList
.
length
+
index
+
1
}}
.
简答题
</div>
<div
class=
"edit_html"
v-html=
"item.content || ''"
></div>
<textarea
:id=
"('editor-exam' + index)"
v-model=
"item.user_answer"
></textarea>
<div
style=
"height: 10px;"
></div>
<component
:is=
"item.upload.type"
v-bind:key=
"item.upload.model"
:item=
"item.upload"
:formData=
"item"
></component>
</div>
</
template
>
</template>
<div
:class=
'["btn", (exam.submitted_time && "on")]'
@
click=
'submitExam'
:data-submit=
'!!exam.submitted_time'
@
mousedown=
'_SubmitMouseLeftDown()'
>
{{exam.submitted_time ? "已提交" : "提交"}}
</div>
<div
class=
'care'
>
(注意:测试只有一次提交机会)
</div>
<!-- <div :class='["btn"]' @click='repeatExam($event, true)' v-if="exam.work_contents">重做</div> -->
</div>
</template>
</div>
</div>
</div>
</template>
<
script
>
import
cAction
from
'@actions'
import
Base64
from
'Base64'
import
CKEDITOR
from
'CKEDITOR'
var
getLetter
=
(
val
)
=>
{
switch
(
val
)
{
case
0
:
return
'A'
case
1
:
return
'B'
case
2
:
return
'C'
case
3
:
return
'D'
case
4
:
return
'E'
case
5
:
return
'F'
case
6
:
return
'G'
case
7
:
return
'H'
case
8
:
return
'I'
case
9
:
return
'J'
case
10
:
return
'K'
case
11
:
return
'L'
case
12
:
return
'M'
}
}
export
default
{
props
:
{
chapterId
:
{
type
:
String
,
require
:
false
},
chapterName
:
{
type
:
String
,
require
:
false
},
chapterExam
:
{
type
:
Object
,
require
:
false
},
sid
:
{
type
:
String
,
require
:
false
},
cid
:
{
type
:
String
,
require
:
false
},
id
:
{
type
:
String
,
require
:
false
}
},
filters
:
{
getLetter
:
getLetter
,
getRadioAnswer
:
(
val
,
arr
)
=>
{
for
(
let
i
=
0
;
i
<
arr
.
length
;
i
++
)
{
if
(
arr
[
i
].
id
===
val
)
{
return
getLetter
(
i
)
}
}
},
getCheckboxAnswer
:
(
val
,
arr
)
=>
{
let
str
=
''
for
(
let
i
=
0
;
i
<
val
.
length
;
i
++
)
{
let
tmpId
=
val
[
i
]
for
(
let
j
=
0
;
j
<
arr
.
length
;
j
++
)
{
if
(
arr
[
j
].
id
===
tmpId
)
{
str
+=
getLetter
(
j
)
+
','
break
}
}
}
return
str
.
substr
(
0
,
str
.
length
-
1
)
}
},
data
()
{
return
{
exam
:
{
id
:
'1'
,
title
:
'标题'
,
radioList
:
[
{
id
:
'6622309081933676544'
,
content
:
'
\
u5047
\
u8bbe
\
u8d27
\
u5e01
\
u9700
\
u6c42
\
u4e3aL=ky-hr
\
uff0c
\
u8d27
\
u5e01
\
u4f9b
\
u7ed9
\
u589e
\
u52a010
\
u4ebf
\
u7f8e
\
u5143
\
u800c
\
u5176
\
u5b83
\
u6761
\
u4ef6
\
u4e0d
\
u53d8
\
uff0c
\
u5219
\
u4f1a
\
u4f7fLM
\
u66f2
\
u7ebf( )'
,
options
:
[
{
id
:
'6622310260604403712'
,
option
:
'
\
u53f3
\
u79fb10
\
u4ebf
\
u7f8e
\
u5143'
},
{
id
:
'6622310260604403713'
,
option
:
'
\
u53f3
\
u79fb k
\
u4e58
\
u4ee510
\
u4ebf
\
u7f8e
\
u5143'
},
{
id
:
'6622310260604403714'
,
option
:
'
\
u53f3
\
u79fb10
\
u4ebf
\
u7f8e
\
u5143
\
u9664
\
u4ee5k'
},
{
id
:
'6622310260604403715'
,
option
:
'
\
u53f3
\
u79fb k
\
u9664
\
u4ee510
\
u4ebf
\
u7f8e
\
u5143'
}
],
user_answer
:
'6622310260604403714'
,
right_answer
:
'6622310260604403714'
,
get_score
:
30
,
score
:
30
}
],
checkboxList
:
[
{
id
:
'6622310510798831616'
,
content
:
'
\
u51ef
\
u6069
\
u65af
\
u5b8f
\
u89c2
\
u7ecf
\
u6d4e
\
u7406
\
u8bba
\
u7684
\
u4e3b
\
u8981
\
u524d
\
u63d0
\
u5305
\
u62ec
\
uff08
\
uff09'
,
options
:
[
{
id
:
'6622310872641437696'
,
option
:
'
\
u8fb9
\
u9645
\
u6d88
\
u8d39
\
u503e
\
u5411
\
u9012
\
u51cf'
},
{
id
:
'6622310872641437697'
,
option
:
'
\
u8d44
\
u672c
\
u8fb9
\
u9645
\
u6548
\
u7387
\
u9012
\
u51cf'
},
{
id
:
'6622310872641437698'
,
option
:
'
\
u4e0d
\
u786e
\
u5b9a
\
u6027
\
u4e0e
\
u6d41
\
u52a8
\
u6027
\
u504f
\
u597d'
},
{
id
:
'6622310872641437699'
,
option
:
'
\
u540d
\
u4e49
\
u5de5
\
u8d44
\
u521a
\
u6027'
}
],
user_answer
:
[
'6622310872641437697'
,
'6622310872641437698'
,
'6622310872641437699'
],
right_answer
:
[
'6622310872641437697'
,
'6622310872641437698'
],
get_score
:
30
,
score
:
30
}
],
shortAnswerList
:
[
{
id
:
'6622311487476072448'
,
content
:
'
\
u8bba
\
u8ff01929
\
u5e74
\
u7f8e
\
u56fd
\
u4e3a
\
u4ec0
\
u4e48
\
u4f1a
\
u51fa
\
u73b0
\
u5927
\
u8427
\
u6761
\
u3002'
,
user_answer
:
'2018
\
u5e74
\
u79ef
\
u6781
\
u7684
\
u8d22
\
u653f
\
u653f
\
u7b56
\
u5bf9
\
u4f9b
\
u7ed9
\
u6027
\
u7ed3
\
u6784
\
u6027
\
u6539
\
u9769
\
u6709
\
u4e00
\
u5b9a
\
u7684
\
u63a8
\
u52a8
\
u4f5c
\
u7528
\
u3002
\
u623f
\
u5730
\
u4ea7
\
u5e02
\
u573a
\
u5f97
\
u5230
\
u4e00
\
u5b9a
\
u7a0b
\
u5ea6
\
u6291
\
u5236
\
u3002
\
u7ecf
\
u6d4e
\
u53d1
\
u5c55
\
u5e73
\
u7a33
\
uff0c
\
u7ecf
\
u6d4e
\
u8fd0
\
u884c
\
u5728
\
u5408
\
u7406
\
u533a
\
u95f4
\
u3002
\
u964d
\
u7a0e
\
u4e3e
\
u52a8
\
u53d6
\
u5f97
\
u6210
\
u6548
\
uff0c
\
u5168
\
u5e74
\
u56fd
\
u5185
\
u589e
\
u503c
\
u7a0e
\
u3001
\
u4f01
\
u4e1a
\
u6240
\
u5f97
\
u7a0e
\
u3001
\
u4e2a
\
u4eba
\
u6240
\
u5f97
\
u7a0e
\
u540c
\
u6bd4
\
u5206
\
u522b
\
u589e
\
u957f9.1%
\
u300110%
\
u300115.9%
\
uff0c
\
u5206
\
u522b
\
u62c9
\
u9ad8
\
u5168
\
u56fd
\
u8d22
\
u653f
\
u6536
\
u5165
\
u589e
\
u5e453
\
u4e2a
\
u30011.9
\
u4e2a
\
u30011.1
\
u4e2a
\
u767e
\
u5206
\
u70b9
\
uff0c
\
u6709
\
u53d1
\
u6325
\
u51fa
\
u5b8f
\
u89c2
\
u8c03
\
u63a7
\
u7684
\
u4f5c
\
u7528
\
u3002
\
u4ece2018
\
u5e74
\
u8d27
\
u5e01
\
u653f
\
u7b56
\
u6574
\
u4f53
\
u6765
\
u770b
\
uff0c
\
u8f83
\
u597d
\
u5730
\
u628a
\
u63e1
\
u4e86
\
u652f
\
u6301
\
u5b9e
\
u4f53
\
u7ecf
\
u6d4e
\
u548c
\
u517c
\
u987e
\
u5185
\
u5916
\
u90e8
\
u5747
\
u8861
\
u4e4b
\
u95f4
\
u7684
\
u5e73
\
u8861
\
uff0c
\
u53d6
\
u5f97
\
u4e86
\
u79ef
\
u6781
\
u6210
\
u6548
\
uff0c
\
u4e5f
\
u5f88
\
u597d
\
u5730
\
u9632
\
u8303
\
u4e86
\
u91d1
\
u878d
\
u98ce
\
u9669
\
u30022018
\
u5e74
\
u603b
\
u4f53
\
u4fdd
\
u6301
\
u4e86
\
u9002
\
u5b9c
\
u7684
\
u8d27
\
u5e01
\
u91d1
\
u878d
\
u73af
\
u5883
\
uff0c
\
u65e0
\
u8bba
\
u662f
\
u5404
\
u9879
\
u8d37
\
u6b3e
\
u8fd8
\
u662f
\
u666e
\
u60e0
\
u53e3
\
u5f84
\
u5c0f
\
u5fae
\
u8d37
\
u6b3e
\
u90fd
\
u540c
\
u6bd4
\
u5927
\
u5e45
\
u591a
\
u589e
\
uff0cM2
\
u548c
\
u793e
\
u4f1a
\
u878d
\
u8d44
\
u89c4
\
u6a21
\
u5b58
\
u91cf
\
u540c
\
u6bd4
\
u589e
\
u901f
\
u4e0e
\
u540d
\
u4e49GDP
\
u589e
\
u901f
\
u57fa
\
u672c
\
u5339
\
u914d
\
uff0c
\
u6709
\
u529b
\
u4fc3
\
u8fdb
\
u4e86
\
u6211
\
u56fd
\
u7ecf
\
u6d4e
\
u6301
\
u7eed
\
u5065
\
u5eb7
\
u53d1
\
u5c55
\
u3002
\
u6211
\
u56fd
\
u5b9e
\
u65bd
\
u79ef
\
u6781
\
u7684
\
u8d22
\
u653f
\
u653f
\
u7b56
\
u548c
\
u7a33
\
u5065
\
u7684
\
u8d27
\
u5e01
\
u653f
\
u7b56
\
uff0c
\
u4e00
\
u65b9
\
u9762
\
u80fd
\
u4ee5
\
u653f
\
u7b56
\
u7684
\
u7a33
\
u5b9a
\
u6765
\
u5e94
\
u5bf9
\
u5916
\
u90e8
\
u73af
\
u5883
\
u7684
\
u4e0d
\
u7a33
\
u5b9a
\
uff0c
\
u5728
\
u9762
\
u5bf9
\
u4e16
\
u754c
\
u73af
\
u5883
\
u53d8
\
u5316
\
u65f6
\
u80fd
\
u968f
\
u65f6
\
u628a
\
u63e1
\
u4f4f
\
u6218
\
u7565
\
u4e3b
\
u52a8
\
u6027
\
uff1b
\
u540c
\
u65f6
\
u80fd
\
u591f
\
u79ef
\
u6781
\
u4fc3
\
u8fdb
\
u6211
\
u56fd
\
u4f9b
\
u7ed9
\
u4fa7
\
u7ed3
\
u6784
\
u6027
\
u6539
\
u9769
\
u8fdb
\
u7a0b
\
uff0c
\
u652f
\
u6301
\
u89e3
\
u51b3
\
u7ecf
\
u6d4e
\
u53d1
\
u5c55
\
u4e2d
\
u7684
\
u6df1
\
u5c42
\
u6b21
\
u7ed3
\
u6784
\
u6027
\
u95ee
\
u9898
\
uff0c
\
u63d0
\
u5347
\
u6211
\
u56fd
\
u7ecf
\
u6d4e
\
u53d1
\
u5c55
\
u8d28
\
u91cf
\
u548c
\
u6548
\
u7387
\
u3002
\
u5b8f
\
u89c2
\
u653f
\
u7b56
\
u7684
\
u5b9e
\
u65bd
\
u4e5f
\
u5de9
\
u56fa
\
u4e86
\
u6211
\
u56fd
\
u5e73
\
u7a33
\
u53d1
\
u5c55
\
u7684
\
u7ecf
\
u6d4e
\
u57fa
\
u7840
\
uff0c
\
u4e3a
\
u5168
\
u9762
\
u5efa
\
u6210
\
u5c0f
\
u5eb7
\
u793e
\
u4f1a
\
u63d0
\
u4f9b
\
u4e86
\
u575a
\
u5f3a
\
u6709
\
u529b
\
u7684
\
u7ecf
\
u6d4e
\
u63aa
\
u65bd
\
u4fdd
\
u969c
\
u3002'
,
check_comment
:
'
\
u5361
\
u5c3c
\
u66fc
\
u8ba4
\
u4e3a
\
u4eba
\
u7684
\
u5927
\
u8111
\
u5b58
\
u5728
\
u4e24
\
u4e2a
\
u7cfb
\
u7edf
\
uff0c
\
u4e24
\
u4e2a
\
u7cfb
\
u7edf
\
u5206
\
u522b
\
u6709
\
u5feb
\
u4e0e
\
u6162
\
u4e24
\
u79cd
\
u4f5c
\
u51b3
\
u5b9a
\
u7684
\
u65b9
\
u5f0f
\
u611f
\
u6027
\
u8ba4
\
u8bc6
\
u548c
\
u7406
\
u6027
\
u8ba4
\
u8bc6
\
u662f
\
u540c
\
u4e00
\
u8ba4
\
u8bc6
\
u8fc7
\
u7a0b
\
u7684
\
u4e24
\
u4e2a
\
u9636
\
u6bb5
\
u3002
\
u4e8c
\
u8005
\
u65e2
\
u76f8
\
u4e92
\
u5bf9
\
u7acb
\
u53c8
\
u76f8
\
u4e92
\
u7edf
\
u4e00
\
u3002
\
u6211
\
u4eec
\
u79f0
\
u4f5c
\
u7cfb
\
u7edf1
\
u548c
\
u7cfb
\
u7edf2
\
uff0c
\
u4ed6
\
u7684
\
u7406
\
u8bba
\
u4e0e
\
u6211
\
u4eec
\
u719f
\
u77e5
\
u7684
\
u611f
\
u6027
\
u8ba4
\
u8bc6
\
u548c
\
u7406
\
u6027
\
u8ba4
\
u8bc6
\
u7684
\
u8fc7
\
u7a0b
\
u7684
\
u4e24
\
u4e2a
\
u9636
\
u6bb5
\
u6709
\
u5f88
\
u76f8
\
u4f3c
\
u7684
\
u7406
\
u8bba
\
u6216
\
u8005
\
u8bf4
\
u662f
\
u4e0d
\
u662f
\
u5c5e
\
u4e8e
\
u540c
\
u4e00
\
u4e2a
\
u7406
\
u8bba
\
u57fa
\
u7840
\
u3002'
,
get_score
:
30
,
score
:
40
,
attachments
:
[],
upload
:
{
type
:
'upload-form'
,
label
:
'附件上传:'
,
model
:
'attachments'
,
action
:
webConf
.
apiBaseURL
+
'/util/upload-file'
,
data
:
{
special
:
'exam'
},
attrs
:
{
multiple
:
true
,
headers
:
{
'tenant'
:
'sofia'
}
},
html
:
`
<div style="color: #72818c; font-size: 14px;">
<p style="margin: 0;">支持doc,docx,ppt,xls,txt,rar,zip,pdf,jpg,pic,png格式的文件,文件小于30M。</p>
</div>
`
}
},
{
id
:
'6622311487476072448'
,
content
:
'
\
u8bba
\
u8ff01929
\
u5e74
\
u7f8e
\
u56fd
\
u4e3a
\
u4ec0
\
u4e48
\
u4f1a
\
u51fa
\
u73b0
\
u5927
\
u8427
\
u6761
\
u3002'
,
user_answer
:
'2018
\
u5e74
\
u79ef
\
u6781
\
u7684
\
u8d22
\
u653f
\
u653f
\
u7b56
\
u5bf9
\
u4f9b
\
u7ed9
\
u6027
\
u7ed3
\
u6784
\
u6027
\
u6539
\
u9769
\
u6709
\
u4e00
\
u5b9a
\
u7684
\
u63a8
\
u52a8
\
u4f5c
\
u7528
\
u3002
\
u623f
\
u5730
\
u4ea7
\
u5e02
\
u573a
\
u5f97
\
u5230
\
u4e00
\
u5b9a
\
u7a0b
\
u5ea6
\
u6291
\
u5236
\
u3002
\
u7ecf
\
u6d4e
\
u53d1
\
u5c55
\
u5e73
\
u7a33
\
uff0c
\
u7ecf
\
u6d4e
\
u8fd0
\
u884c
\
u5728
\
u5408
\
u7406
\
u533a
\
u95f4
\
u3002
\
u964d
\
u7a0e
\
u4e3e
\
u52a8
\
u53d6
\
u5f97
\
u6210
\
u6548
\
uff0c
\
u5168
\
u5e74
\
u56fd
\
u5185
\
u589e
\
u503c
\
u7a0e
\
u3001
\
u4f01
\
u4e1a
\
u6240
\
u5f97
\
u7a0e
\
u3001
\
u4e2a
\
u4eba
\
u6240
\
u5f97
\
u7a0e
\
u540c
\
u6bd4
\
u5206
\
u522b
\
u589e
\
u957f9.1%
\
u300110%
\
u300115.9%
\
uff0c
\
u5206
\
u522b
\
u62c9
\
u9ad8
\
u5168
\
u56fd
\
u8d22
\
u653f
\
u6536
\
u5165
\
u589e
\
u5e453
\
u4e2a
\
u30011.9
\
u4e2a
\
u30011.1
\
u4e2a
\
u767e
\
u5206
\
u70b9
\
uff0c
\
u6709
\
u53d1
\
u6325
\
u51fa
\
u5b8f
\
u89c2
\
u8c03
\
u63a7
\
u7684
\
u4f5c
\
u7528
\
u3002
\
u4ece2018
\
u5e74
\
u8d27
\
u5e01
\
u653f
\
u7b56
\
u6574
\
u4f53
\
u6765
\
u770b
\
uff0c
\
u8f83
\
u597d
\
u5730
\
u628a
\
u63e1
\
u4e86
\
u652f
\
u6301
\
u5b9e
\
u4f53
\
u7ecf
\
u6d4e
\
u548c
\
u517c
\
u987e
\
u5185
\
u5916
\
u90e8
\
u5747
\
u8861
\
u4e4b
\
u95f4
\
u7684
\
u5e73
\
u8861
\
uff0c
\
u53d6
\
u5f97
\
u4e86
\
u79ef
\
u6781
\
u6210
\
u6548
\
uff0c
\
u4e5f
\
u5f88
\
u597d
\
u5730
\
u9632
\
u8303
\
u4e86
\
u91d1
\
u878d
\
u98ce
\
u9669
\
u30022018
\
u5e74
\
u603b
\
u4f53
\
u4fdd
\
u6301
\
u4e86
\
u9002
\
u5b9c
\
u7684
\
u8d27
\
u5e01
\
u91d1
\
u878d
\
u73af
\
u5883
\
uff0c
\
u65e0
\
u8bba
\
u662f
\
u5404
\
u9879
\
u8d37
\
u6b3e
\
u8fd8
\
u662f
\
u666e
\
u60e0
\
u53e3
\
u5f84
\
u5c0f
\
u5fae
\
u8d37
\
u6b3e
\
u90fd
\
u540c
\
u6bd4
\
u5927
\
u5e45
\
u591a
\
u589e
\
uff0cM2
\
u548c
\
u793e
\
u4f1a
\
u878d
\
u8d44
\
u89c4
\
u6a21
\
u5b58
\
u91cf
\
u540c
\
u6bd4
\
u589e
\
u901f
\
u4e0e
\
u540d
\
u4e49GDP
\
u589e
\
u901f
\
u57fa
\
u672c
\
u5339
\
u914d
\
uff0c
\
u6709
\
u529b
\
u4fc3
\
u8fdb
\
u4e86
\
u6211
\
u56fd
\
u7ecf
\
u6d4e
\
u6301
\
u7eed
\
u5065
\
u5eb7
\
u53d1
\
u5c55
\
u3002
\
u6211
\
u56fd
\
u5b9e
\
u65bd
\
u79ef
\
u6781
\
u7684
\
u8d22
\
u653f
\
u653f
\
u7b56
\
u548c
\
u7a33
\
u5065
\
u7684
\
u8d27
\
u5e01
\
u653f
\
u7b56
\
uff0c
\
u4e00
\
u65b9
\
u9762
\
u80fd
\
u4ee5
\
u653f
\
u7b56
\
u7684
\
u7a33
\
u5b9a
\
u6765
\
u5e94
\
u5bf9
\
u5916
\
u90e8
\
u73af
\
u5883
\
u7684
\
u4e0d
\
u7a33
\
u5b9a
\
uff0c
\
u5728
\
u9762
\
u5bf9
\
u4e16
\
u754c
\
u73af
\
u5883
\
u53d8
\
u5316
\
u65f6
\
u80fd
\
u968f
\
u65f6
\
u628a
\
u63e1
\
u4f4f
\
u6218
\
u7565
\
u4e3b
\
u52a8
\
u6027
\
uff1b
\
u540c
\
u65f6
\
u80fd
\
u591f
\
u79ef
\
u6781
\
u4fc3
\
u8fdb
\
u6211
\
u56fd
\
u4f9b
\
u7ed9
\
u4fa7
\
u7ed3
\
u6784
\
u6027
\
u6539
\
u9769
\
u8fdb
\
u7a0b
\
uff0c
\
u652f
\
u6301
\
u89e3
\
u51b3
\
u7ecf
\
u6d4e
\
u53d1
\
u5c55
\
u4e2d
\
u7684
\
u6df1
\
u5c42
\
u6b21
\
u7ed3
\
u6784
\
u6027
\
u95ee
\
u9898
\
uff0c
\
u63d0
\
u5347
\
u6211
\
u56fd
\
u7ecf
\
u6d4e
\
u53d1
\
u5c55
\
u8d28
\
u91cf
\
u548c
\
u6548
\
u7387
\
u3002
\
u5b8f
\
u89c2
\
u653f
\
u7b56
\
u7684
\
u5b9e
\
u65bd
\
u4e5f
\
u5de9
\
u56fa
\
u4e86
\
u6211
\
u56fd
\
u5e73
\
u7a33
\
u53d1
\
u5c55
\
u7684
\
u7ecf
\
u6d4e
\
u57fa
\
u7840
\
uff0c
\
u4e3a
\
u5168
\
u9762
\
u5efa
\
u6210
\
u5c0f
\
u5eb7
\
u793e
\
u4f1a
\
u63d0
\
u4f9b
\
u4e86
\
u575a
\
u5f3a
\
u6709
\
u529b
\
u7684
\
u7ecf
\
u6d4e
\
u63aa
\
u65bd
\
u4fdd
\
u969c
\
u3002'
,
check_comment
:
'
\
u5361
\
u5c3c
\
u66fc
\
u8ba4
\
u4e3a
\
u4eba
\
u7684
\
u5927
\
u8111
\
u5b58
\
u5728
\
u4e24
\
u4e2a
\
u7cfb
\
u7edf
\
uff0c
\
u4e24
\
u4e2a
\
u7cfb
\
u7edf
\
u5206
\
u522b
\
u6709
\
u5feb
\
u4e0e
\
u6162
\
u4e24
\
u79cd
\
u4f5c
\
u51b3
\
u5b9a
\
u7684
\
u65b9
\
u5f0f
\
u611f
\
u6027
\
u8ba4
\
u8bc6
\
u548c
\
u7406
\
u6027
\
u8ba4
\
u8bc6
\
u662f
\
u540c
\
u4e00
\
u8ba4
\
u8bc6
\
u8fc7
\
u7a0b
\
u7684
\
u4e24
\
u4e2a
\
u9636
\
u6bb5
\
u3002
\
u4e8c
\
u8005
\
u65e2
\
u76f8
\
u4e92
\
u5bf9
\
u7acb
\
u53c8
\
u76f8
\
u4e92
\
u7edf
\
u4e00
\
u3002
\
u6211
\
u4eec
\
u79f0
\
u4f5c
\
u7cfb
\
u7edf1
\
u548c
\
u7cfb
\
u7edf2
\
uff0c
\
u4ed6
\
u7684
\
u7406
\
u8bba
\
u4e0e
\
u6211
\
u4eec
\
u719f
\
u77e5
\
u7684
\
u611f
\
u6027
\
u8ba4
\
u8bc6
\
u548c
\
u7406
\
u6027
\
u8ba4
\
u8bc6
\
u7684
\
u8fc7
\
u7a0b
\
u7684
\
u4e24
\
u4e2a
\
u9636
\
u6bb5
\
u6709
\
u5f88
\
u76f8
\
u4f3c
\
u7684
\
u7406
\
u8bba
\
u6216
\
u8005
\
u8bf4
\
u662f
\
u4e0d
\
u662f
\
u5c5e
\
u4e8e
\
u540c
\
u4e00
\
u4e2a
\
u7406
\
u8bba
\
u57fa
\
u7840
\
u3002'
,
get_score
:
30
,
score
:
40
,
attachments
:
[],
upload
:
{
type
:
'upload-form'
,
label
:
'附件上传:'
,
model
:
'attachments'
,
action
:
webConf
.
apiBaseURL
+
'/util/upload-file'
,
data
:
{
special
:
'exam'
},
attrs
:
{
multiple
:
true
},
html
:
`
<div style="color: #72818c; font-size: 14px;">
<p style="margin: 0;">支持doc,docx,ppt,xls,txt,rar,zip,pdf,jpg,pic,png格式的文件,文件小于30M。</p>
</div>
`
}
}
]
}
}
},
mounted
()
{
this
.
loadAjax
()
},
methods
:
{
isCheckboxRight
:
(
val
,
arr
)
=>
{
let
flag
=
true
for
(
let
i
=
0
;
i
<
val
.
length
;
i
++
)
{
let
tmpId
=
val
[
i
]
let
j
=
0
for
(;
j
<
arr
.
length
;
j
++
)
{
if
(
arr
[
j
]
===
tmpId
)
{
break
}
}
if
(
j
===
arr
.
length
)
{
flag
=
false
;
break
}
}
return
flag
},
isCheckboxChecked
:
(
val
,
arr
)
=>
{
let
i
=
0
for
(;
i
<
arr
.
length
;
i
++
)
{
if
(
arr
[
i
].
id
===
val
||
arr
[
i
]
===
val
)
{
return
true
}
}
if
(
i
===
arr
.
length
)
{
return
false
}
},
initckeditor
()
{
for
(
let
i
=
0
;
i
<
this
.
exam
.
shortAnswerList
.
length
;
i
++
)
{
let
tmpEditor
=
CKEDITOR
.
replace
(
'editor-exam'
+
i
,
{
height
:
300
,
uiColor
:
'#eeeeee'
,
filebrowserImageUploadUrl
:
'/api/ckeditor/img/upload'
,
// resize_enabled: typeof this.props.resizable === 'boolean' ? this.props.resizable : true,
toolbar
:
[
// { name: 'document', items: [ 'Source', '-', 'Save', 'NewPage', 'Preview' ] },
{
name
:
'styles'
,
items
:
[
'Styles'
,
'Format'
,
'Font'
,
'FontSize'
]
},
{
name
:
'colors'
,
items
:
[
'TextColor'
,
'BGColor'
]
},
{
name
:
'tools'
,
items
:
[
'Maximize'
,
'ShowBlocks'
]
},
// { name: 'clipboard', items: [ 'Cut', 'Copy', 'Paste', 'PasteText', 'PasteFromWord', '-', 'Undo', 'Redo' ] },
{
name
:
'editing'
,
items
:
[
'Find'
,
'Replace'
]
},
// { name: 'forms', items: [ 'Form', 'Checkbox', 'Radio', 'TextField', 'Textarea', 'Select', 'Button', 'ImageButton', 'HiddenField' ] },
'/'
,
{
name
:
'basicstyles'
,
items
:
[
'Bold'
,
'Italic'
,
'Underline'
,
'Strike'
,
'Subscript'
,
'Superscript'
,
'-'
,
'RemoveFormat'
]
},
{
name
:
'paragraph'
,
items
:
[
'NumberedList'
,
'BulletedList'
,
'-'
,
'Outdent'
,
'Indent'
,
'-'
,
'Blockquote'
,
'CreateDiv'
,
'-'
,
'JustifyLeft'
,
'JustifyCenter'
,
'JustifyRight'
,
'JustifyBlock'
,
'-'
,
'BidiLtr'
,
'BidiRtl'
]
},
{
name
:
'links'
,
items
:
[
'Link'
,
'Unlink'
,
'Anchor'
]
},
{
name
:
'insert'
,
items
:
[
'Image'
,
'Table'
,
'HorizontalRule'
]
}
]
})
this
.
exam
.
shortAnswerList
[
i
].
ckeditor
=
tmpEditor
}
},
/**
* 生命周期函数--监听页面加载
*/
loadAjax
()
{
const
loading
=
this
.
$loading
({
lock
:
true
,
text
:
''
,
spinner
:
''
,
background
:
'rgba(255, 255, 255, 0.9)'
})
if
(
this
.
id
!==
'0'
)
{
cAction
.
examAction
.
getExamAnswer
(
this
.
cid
,
this
.
sid
,
this
.
id
).
then
(
_data
=>
{
this
.
exam
=
_data
}).
catch
(
e
=>
{
this
.
$message
.
error
(
e
.
message
)
}).
finally
(()
=>
{
/* 滚动到头部 */
document
.
querySelector
(
'.play-paper'
).
scrollTop
=
0
loading
.
close
()
this
.
initckeditor
()
})
}
else
{
cAction
.
examAction
.
getExamInfo
(
this
.
cid
,
this
.
sid
).
then
(
_data
=>
{
this
.
exam
=
_data
}).
catch
(
e
=>
{
this
.
$message
.
error
(
e
.
message
)
}).
finally
(()
=>
{
/* 滚动到头部 */
document
.
querySelector
(
'.play-paper'
).
scrollTop
=
0
loading
.
close
()
this
.
initckeditor
()
})
}
},
/**
* 提交试题
*/
submitExam
(
e
)
{
if
(
e
.
currentTarget
.
dataset
.
submit
)
{
this
.
$message
.
error
(
'已做过,不能再提交'
)
return
}
let
body
=
{
answers
:
{},
type
:
0
}
// type: 0 缓存;type: 1 提交
body
.
answers
.
radioList
=
[]
for
(
let
i
=
0
;
i
<
this
.
exam
.
radioList
.
length
;
i
++
)
{
let
tmp
=
this
.
exam
.
radioList
[
i
]
if
(
!
tmp
.
user_answer
)
{
this
.
$message
.
error
(
'还有单选题未做,不能提交'
)
return
}
body
.
answers
.
radioList
.
push
({
id
:
tmp
.
id
,
user_answer
:
tmp
.
user_answer
})
}
body
.
answers
.
checkboxList
=
[]
for
(
let
i
=
0
;
i
<
this
.
exam
.
checkboxList
.
length
;
i
++
)
{
let
tmp
=
this
.
exam
.
checkboxList
[
i
]
if
(
!
tmp
.
user_answer
.
length
)
{
this
.
$message
.
error
(
'还有多选题未做,不能提交'
)
return
}
body
.
answers
.
checkboxList
.
push
({
id
:
tmp
.
id
,
user_answer
:
tmp
.
user_answer
})
}
body
.
answers
.
shortAnswerList
=
[]
for
(
let
i
=
0
;
i
<
this
.
exam
.
shortAnswerList
.
length
;
i
++
)
{
let
tmp
=
this
.
exam
.
shortAnswerList
[
i
]
tmp
.
user_answer
=
tmp
.
ckeditor
.
getData
()
if
(
!
tmp
.
user_answer
)
{
this
.
$message
.
error
(
'还有简答题未做,不能提交'
)
return
}
body
.
answers
.
shortAnswerList
.
push
({
id
:
tmp
.
id
,
user_answer
:
Base64
.
encode
(
tmp
.
user_answer
),
attachments
:
tmp
.
attachments
})
}
body
.
answers
=
JSON
.
stringify
(
body
.
answers
)
const
loading
=
this
.
$loading
({
lock
:
true
,
text
:
''
,
spinner
:
''
,
background
:
'rgba(255, 255, 255, 0.9)'
})
cAction
.
examAction
.
submitExam
(
this
.
cid
,
this
.
sid
,
this
.
exam
.
id
,
body
).
then
(
_res
=>
{
debugger
if
(
_res
.
success
)
{
}
else
{
this
.
$message
.
error
(
_res
.
data
.
error
)
}
}).
catch
(
e
=>
{
this
.
$message
.
error
(
e
.
message
)
}).
finally
(()
=>
{
loading
.
close
()
})
},
_SubmitMouseLeftDown
()
{
let
_fn1
=
this
.
repeatExam
.
bind
(
this
,
false
)
document
.
addEventListener
(
'keydown'
,
_fn1
,
false
)
let
_fn3
=
function
()
{
document
.
removeEventListener
(
'keydown'
,
_fn1
)
document
.
removeEventListener
(
'mouseup'
,
_fn3
)
}
document
.
addEventListener
(
'mouseup'
,
_fn3
,
false
)
},
/**
* 重做
*/
repeatExam
(
e
,
flag
)
{
let
_flag
=
flag
/* 字母 f */
if
(
e
.
keyCode
===
70
)
{
_flag
=
true
}
if
(
!
_flag
)
{
return
}
const
loading
=
this
.
$loading
({
lock
:
true
,
text
:
''
,
spinner
:
''
,
background
:
'rgba(255, 255, 255, 0.9)'
})
cAction
.
chapterAction
.
getExamDetail
(
this
.
sid
,
this
.
cid
,
this
.
id
).
then
(
_data
=>
{
this
.
exam
=
{}
}).
catch
(
e
=>
{
this
.
$message
.
error
(
e
.
message
)
}).
finally
(()
=>
{
this
.
setTime
=
setInterval
(()
=>
{
// console.log(this.chapterExam.work_id, this.id)
if
(
this
.
chapterExam
.
work_id
&&
this
.
chapterExam
.
work_id
===
this
.
id
)
{
if
(
!
this
.
exam
.
id
)
{
this
.
exam
=
this
.
updateData
(
this
.
chapterExam
)
/* 滚动到头部 */
document
.
querySelector
(
'.play-paper'
).
scrollTop
=
0
}
clearInterval
(
this
.
setTime
)
}
},
50
)
loading
.
close
()
})
}
},
watch
:
{
id
:
{
handler
()
{
this
.
loadAjax
()
}
}
}
}
</
script
>
<
style
lang=
"scss"
scoped
>
.play
{
.exam
{
padding
:
0
;
}
.exam
.topic
{
display
:
inline-block
;
margin-bottom
:
0
.1rem
;
}
.exam
.topic
.tit
{
margin
:
0
auto
;
padding
:
0
0
.2rem
;
text-align
:
center
;
font-size
:
0
.24rem
;
color
:
#313131
;
background
:
#fff
;
box-sizing
:
border-box
;
-webkit-box-sizing
:
border-box
;
}
.exam
.topic
.cur
{
text-align
:
center
;
font-size
:
0
.18rem
;
color
:
#313131
;
line-height
:
0
.4rem
;
}
/* 循环 所有选择题 */
.exam
.q-group
{
padding
:
0
.1rem
0
.1rem
;
border-bottom
:
1px
solid
#c9c9c9
7a
;
overflow
:
hidden
;
}
.exam
.q-group
.q-num
{
float
:
left
;
margin-right
:
0
.1rem
;
font-size
:
0
.16rem
;
color
:
#676a6c
;
}
.exam
.q-group
.q-title
{
float
:
left
;
width
:
90%
;
font-size
:
0
.16rem
;
color
:
#676a6c
;
text-align
:
justify
;
}
.exam
.q-group
.q-type
{
float
:
right
;
font-size
:
0
.16rem
;
color
:
#676a6c
;
}
.exam
.q-group
.radio-group
{
float
:
left
;
margin-top
:
0
.1rem
;
width
:
100%
;
}
.exam
.q-group
.radio-group
.radio
{
display
:
block
;
font-size
:
0
.18rem
;
color
:
#3f3b3a
;
line-height
:
0
.3rem
;
margin-bottom
:
0
.1rem
;
}
.exam
.q-group
.checkbox-group
{
float
:
left
;
margin-top
:
0
.1rem
;
width
:
100%
;
}
.exam
.q-group
.checkbox-group
.checkbox
{
display
:
block
;
font-size
:
0
.18rem
;
color
:
#3f3b3a
;
line-height
:
0
.3rem
;
margin-bottom
:
0
.1rem
;
}
.exam
.q-group
.radio-group
.radio.error
,
.exam
.q-group
.checkbox-group
.checkbox.error
{
color
:
#d80000
;
}
.exam
.q-group
.radio-group
.radio.success
,
.exam
.q-group
.checkbox-group
.checkbox.success
{
color
:
#090
;
}
.exam
.q-group
.result
{
float
:
right
;
font-size
:
0
.18rem
;
color
:
#3f3b3a
;
margin-right
:
0
;
}
.exam
.q-group
.result
.stu
{
display
:
inline-block
;
}
.exam
.q-group
.result
.stu.error
{
color
:
#d80000
;
}
.exam
.q-group
.result
.stu.success
{
color
:
#090
;
}
.exam
.q-group
:last-child
{
border-bottom
:
none
;
}
.exam
.btn
{
margin
:
0
.2rem
auto
;
width
:
60%
;
height
:
0
.5rem
;
line-height
:
0
.5rem
;
font-size
:
0
.16rem
;
text-align
:
center
;
font-weight
:
300
;
color
:
#fff
;
border-radius
:
0
.1rem
;
background
:
#b49441
;
cursor
:
pointer
;
}
.exam
.btn.on
{
opacity
:
0
.5
;
}
.exam
.care
{
font-size
:
0
.16rem
;
color
:
#d80000
;
text-align
:
center
;
}
.exam
.q-sa-title
{
float
:
left
;
width
:
100%
;
font-size
:
0
.16rem
;
color
:
#676a6c
;
text-align
:
justify
;
}
}
</
style
>
client/client/components/services/api/exam_api.js
0 → 100644
浏览文件 @
ede512a4
import
BaseAPI
from
'../base_api'
export
default
class
ExamAPI
extends
BaseAPI
{
/**
* 获取考卷信息
* @param {[string]} course_id -> cid
* @param {[string]} semester_id -> sid
*/
getExamInfo
=
(
cid
,
sid
)
=>
this
.
get
(
`/v2/education/
${
sid
}
/
${
cid
}
/examination`
,
{})
/**
* 获取考卷结果
* @param {[string]} course_id -> cid
* @param {[string]} semester_id -> sid
* @param {[string]} exam_id -> eid
*/
getExamAnswer
=
(
cid
,
sid
,
eid
)
=>
this
.
get
(
`/v2/education/
${
sid
}
/
${
cid
}
/examination/
${
eid
}
/sheet`
,
{})
/**
* 提交考卷
* @param {[string]} course_id -> cid
* @param {[string]} semester_id -> sid
* @param {[string]} exam_id -> eid
* @param {[object]} obj -> 提交对象类
*/
submitExam
=
(
cid
,
sid
,
eid
,
obj
=
{})
=>
this
.
post
(
`/v2/education/
${
sid
}
/
${
cid
}
/examination/
${
eid
}
/sheet`
,
obj
,
{
headers
:
{
'Content-Type'
:
'application/x-www-form-urlencoded'
}
})
}
client/client/components/services/index.js
浏览文件 @
ede512a4
import
LoginAPI
from
'./api/login_api'
import
ChapterAPI
from
'./api/chapter_api'
import
ExamAPI
from
'./api/exam_api'
import
CourseAPI
from
'./api/course_api'
import
DiscussAPI
from
'./api/discuss_api'
import
MsgAPI
from
'./api/msg_api'
...
...
@@ -8,6 +9,7 @@ import ReportAPI from './api/report_api'
let
loginApi
=
new
LoginAPI
(
webConf
)
let
chapterApi
=
new
ChapterAPI
(
webConf
)
let
examApi
=
new
ExamAPI
(
webConf
)
let
courseApi
=
new
CourseAPI
(
webConf
)
let
discussApi
=
new
DiscussAPI
(
webConf
)
let
msgApi
=
new
MsgAPI
(
webConf
)
...
...
@@ -17,6 +19,7 @@ let reportApi = new ReportAPI(webConf)
export
{
loginApi
,
chapterApi
,
examApi
,
courseApi
,
discussApi
,
msgApi
,
...
...
client/client/components/upload-form/elemInfo.md
0 → 100644
浏览文件 @
ede512a4
## 组件简介
| 字段值 | 说明 | 字段属性 | 默认值 |
| ------- | ------------------------- | ------- | ----- |
|
`type`
| 类型:
`String`
; 说明:组件类型名 | 自定义字段 |
`upload-form`
|
|
`action`
| 类型:
`String`
; 说明:上传请求接口path | 自定义字段 |
`` |
| `deleteAction` | 类型:`String`; 说明:删除请求接口path | 自定义字段 | ``
|
|
`html`
| 类型:
`String`
; 说明:上传说明,支持html | 自定义字段 |
`` |
| `label` | 类型:`String`; 说明:组件左侧显示名称 | element-ui el-form-item对应字段 | `''` |
| `label-width` | 类型:`String`; 说明:组件左侧显示名称宽度(加单位),父级设置可以子级继承 | element-ui el-form-item对应字段 | `''` |
| `required` | 类型:`Boolean`; 说明:标识是否必填 | element-ui el-form-item对应字段 | `false` |
| `disabled` | 类型:`Boolean`; 说明:标识是否只读 | element-ui el-form-item对应字段 | `false` |
| `model` | 类型:`String`; 说明:表单提交name值和回显对照字段 | 自定义字段 | `''` |
| `placeholder` | 类型:`String`; 说明:组件input框中,默认提示文字 | element-ui el-input对应字段 | `''` |
| `attrs` | 类型:`Object`; 说明:定义标签上Data属性值 | element-ui对应字段 | `{}` |
| `rules` | 类型:`Array`; 说明:组件错误提示规则 | element-ui el-form-item对应字段 | `[]` |
### Demo Example:
``` js
return {
type: 'upload-form',
label: '姓名',
labeWidth: '160px',
required: true,
disabled: false,
model: 'uploadArrs',
action: '',
data: {
},
deleteAction: '',
deleteData: {
},
html: `
<div
style=
"color: #72818c; font-size: 14px;"
>
<p
style=
"margin: 0;"
>
申请者需要将有效身份证件原件扫描或者拍照后提交。
</p>
<p
style=
"margin: 0;"
>
请您提供有效身份证件的扫描件,身份证与台港澳居民大陆通行证应包括正反两面扫描件。
</p>
<p
style=
"margin: 0;"
>
只上传一个文件,多份文件需合并到一个文件后打印出来检查无误后再上传。
</p>
<p
style=
"margin: 0;"
>
上传文件仅限“jpg,jpeg,gif,png”格式,文件小于10MB。
</p>
</div>
`,
attrs: {
multiple: false,
limit: 1
},
rules: [
{
required: true,
message: '请上传',
trigger: 'blur'
}
]
}
`
``
*
其他属性
[
参考文档
](
[https://](https://element.eleme.cn/#/zh-CN/component/input
)
)
client/client/components/upload-form/index.js
0 → 100644
浏览文件 @
ede512a4
import
Upload
from
'./src/uploadForm.vue'
/* istanbul ignore next */
Upload
.
install
=
function
(
Vue
)
{
Vue
.
component
(
Upload
.
name
,
Upload
)
}
export
default
Upload
client/client/components/upload-form/src/ajax.js
0 → 100755
浏览文件 @
ede512a4
function
getError
(
action
,
option
,
xhr
)
{
let
msg
if
(
xhr
.
response
)
{
msg
=
`
${
xhr
.
response
.
error
||
xhr
.
response
}
`
}
else
if
(
xhr
.
responseText
)
{
msg
=
`
${
xhr
.
responseText
}
`
}
else
{
msg
=
`fail to post
${
action
}
${
xhr
.
status
}
`
}
const
err
=
new
Error
(
msg
)
err
.
status
=
xhr
.
status
err
.
method
=
'post'
err
.
url
=
action
return
err
}
function
getBody
(
xhr
)
{
const
text
=
xhr
.
responseText
||
xhr
.
response
if
(
!
text
)
{
return
text
}
try
{
return
JSON
.
parse
(
text
)
}
catch
(
e
)
{
return
text
}
}
export
function
deleteFile
(
option
)
{
if
(
typeof
XMLHttpRequest
===
'undefined'
)
{
return
}
// eslint-disable-next-line no-undef
const
xhr
=
new
XMLHttpRequest
()
let
action
=
option
.
action
xhr
.
onerror
=
function
error
(
e
)
{
option
.
onError
(
e
)
}
xhr
.
onload
=
function
onload
()
{
if
(
xhr
.
status
<
200
||
xhr
.
status
>=
300
)
{
return
option
.
onError
(
getError
(
action
,
option
,
xhr
))
}
option
.
onSuccess
(
getBody
(
xhr
))
}
xhr
.
open
(
'delete'
,
action
,
true
)
if
(
option
.
withCredentials
&&
'withCredentials'
in
xhr
)
{
xhr
.
withCredentials
=
true
}
const
headers
=
option
.
headers
||
{}
for
(
let
item
in
headers
)
{
if
(
headers
.
hasOwnProperty
(
item
)
&&
headers
[
item
]
!==
null
)
{
xhr
.
setRequestHeader
(
item
,
headers
[
item
])
}
}
xhr
.
send
()
return
xhr
}
export
default
function
upload
(
option
)
{
if
(
typeof
XMLHttpRequest
===
'undefined'
)
{
return
}
// eslint-disable-next-line no-undef
const
xhr
=
new
XMLHttpRequest
()
const
action
=
option
.
action
if
(
xhr
.
upload
)
{
xhr
.
upload
.
onprogress
=
function
progress
(
e
)
{
if
(
e
.
total
>
0
)
{
e
.
percent
=
e
.
loaded
/
e
.
total
*
100
}
option
.
onProgress
(
e
)
}
}
// eslint-disable-next-line no-undef
const
formData
=
new
FormData
()
if
(
option
.
data
)
{
Object
.
keys
(
option
.
data
).
forEach
(
key
=>
{
formData
.
append
(
key
,
option
.
data
[
key
])
})
}
formData
.
append
(
option
.
filename
,
option
.
file
,
option
.
file
.
name
)
xhr
.
onerror
=
function
error
(
e
)
{
option
.
onError
(
e
)
}
xhr
.
onload
=
function
onload
()
{
if
(
xhr
.
status
<
200
||
xhr
.
status
>=
300
)
{
return
option
.
onError
(
getError
(
action
,
option
,
xhr
))
}
option
.
onSuccess
(
getBody
(
xhr
))
}
xhr
.
open
(
'post'
,
action
,
true
)
if
(
option
.
withCredentials
&&
'withCredentials'
in
xhr
)
{
xhr
.
withCredentials
=
true
}
const
headers
=
option
.
headers
||
{}
for
(
let
item
in
headers
)
{
if
(
headers
.
hasOwnProperty
(
item
)
&&
headers
[
item
]
!==
null
)
{
xhr
.
setRequestHeader
(
item
,
headers
[
item
])
}
}
xhr
.
send
(
formData
)
return
xhr
}
client/client/components/upload-form/src/uploadForm.vue
0 → 100644
浏览文件 @
ede512a4
<
template
>
<div
class=
"upload-form"
>
<div
class=
"u-babel"
>
{{
item
.
label
}}
</div>
<el-upload
style=
"display: inline-block;"
:action=
"item.action"
:data=
"item.data"
:before-upload=
"beforeUploadFile"
:on-success=
"onSuccessFile"
:with-credentials=
"true"
:show-file-list=
"false"
:disabled=
"item.disabled || false"
v-bind=
"item.attrs ||
{}">
<el-button
type=
"primary"
size=
"small"
>
点击上传
</el-button>
<template
v-if=
"formData[item.model] !== null && formData[item.model] !== '' && formData[item.model] !== undefined"
>
<div
class=
"self-icon el-icon-circle-check"
style=
"color: #237f00;"
></div>
</
template
>
<div
class=
"self-icon el-icon-circle-close"
style=
"color: #b01c40;"
></div>
</el-upload>
<div
style=
"overflow: hidden; padding: 10px 0 0 0;"
>
<
template
v-if=
"filesArr.length"
>
<!-- 遍历显示文件 -->
<template
v-for=
"(item, index) in filesArr"
>
<template
v-if=
"/(jpeg)|(jpg)|(png)|(gif)/gi.test(item.url)"
>
<div
v-bind:key=
"item.id"
class=
"show-file"
>
<template
v-if=
"!(item.disabled || false)"
>
<div
class=
"close"
@
click=
"deleteFiles(index)"
>
X
</div>
</
template
>
<el-avatar
shape=
"square"
:size=
"100"
fit=
"contain"
:src=
"item.url"
></el-avatar>
<span
class=
"title"
>
{{ item.sso_file_name }}
</span>
<div
class=
"hover"
>
<a
target=
"_blank"
:href=
"item.url"
>
下载
</a>
</div>
</div>
</template>
<
template
v-else
>
<div
v-bind:key=
"item.id"
class=
"show-file"
>
<template
v-if=
"!(item.disabled || false)"
>
<div
class=
"close"
@
click=
"deleteFiles(index)"
>
X
</div>
</
template
>
<el-avatar
shape=
"square"
:size=
"100"
fit=
"contain"
:src=
"item.url"
></el-avatar>
<span
class=
"title"
>
{{ item.sso_file_name }}
</span>
<div
class=
"hover"
>
<a
target=
"_blank"
:href=
"item.url"
>
下载
</a>
</div>
</div>
</template>
</template>
</template>
</div>
<div
class=
'info'
style=
"line-height: 1.5;"
v-html=
"item.html"
></div>
</div>
</template>
<
script
>
// import { deleteFile } from './ajax'
export
default
{
name
:
'UploadForm'
,
componentName
:
'UploadForm'
,
props
:
{
item
:
{
type
:
Object
,
default
()
{
return
{}
}
},
formData
:
{
type
:
Object
,
default
()
{
return
{}
}
}
},
data
()
{
let
tmpArr
=
this
.
formData
[
this
.
item
.
model
]
||
[]
this
.
formData
[
this
.
item
.
model
]
=
tmpArr
return
{
'project_id'
:
''
,
filesArr
:
tmpArr
}
},
methods
:
{
beforeUploadFile
(
file
)
{},
onSuccessFile
(
response
,
file
,
fileList
)
{
response
.
url
=
response
.
url
||
response
.
file
||
''
response
.
sso_file_name
=
file
.
name
this
.
filesArr
.
push
(
response
)
// this.$emit('onSubmit')
},
deleteFiles
(
index
)
{
this
.
filesArr
.
splice
(
index
,
1
)
// let temp = this.filesArr[index]
// deleteFile({
// action: this.item.deleteAction + '/' + temp.id + '?project_id=' + this.item.data.project_id,
// onError: () => {},
// onSuccess: (res) => {
// if (res.status === 200) {
// this.filesArr.splice(index, 1)
// }
// }
// })
}
}
}
</
script
>
<
style
lang=
"scss"
>
.u-babel
{
display
:
inline-block
;
margin-right
:
10px
;
}
.self-icon
{
display
:
none
!
important
;
vertical-align
:
middle
;
margin-left
:
10px
;
font-size
:
21px
;
line-height
:
22px
;
}
.is-error
.self-icon.el-icon-circle-close
{
display
:
inline-block
!
important
;
}
.is-success
.self-icon.el-icon-circle-check
{
display
:
inline-block
!
important
;
}
.show-file
{
position
:
relative
;
float
:
left
;
margin-right
:
10px
;
.close
{
position
:
absolute
;
z-index
:
10
;
right
:
-10px
;
top
:
-10px
;
width
:
20px
;
height
:
20px
;
color
:
#fff
;
font-size
:
12px
;
line-height
:
20px
;
text-align
:
center
;
background
:
#efefef
;
border-radius
:
50%
;
cursor
:
pointer
;
}
.el-avatar
{
img
{
width
:
100%
;
}
}
.title
{
position
:
absolute
;
left
:
0
;
bottom
:
8px
;
width
:
100%
;
padding-left
:
5px
;
font-size
:
12px
;
line-height
:
20px
;
background
:
#efefef
;
overflow
:
hidden
;
text-overflow
:
ellipsis
;
white-space
:
nowrap
;
word-break
:
break-all
;
box-sizing
:
border-box
;
}
.hover
{
display
:
none
;
position
:
absolute
;
z-index
:
9
;
top
:
0
;
left
:
0
;
height
:
100px
;
width
:
100%
;
background
:
rgba
(
0
,
0
,
0
,
0
.2
);
line-height
:
100px
;
text-align
:
center
;
a
{
color
:
#f1f1f1
;
}
}
&
:hover
{
.hover
{
display
:
block
;
}
}
}
</
style
>
client/client/project/actions/ExamAction.js
0 → 100644
浏览文件 @
ede512a4
import
{
examApi
}
from
'@services'
export
default
class
ExamAction
{
/* 获取考卷信息 */
getExamInfo
(
cid
,
sid
)
{
return
examApi
.
getExamInfo
(
cid
,
sid
).
then
(
_res
=>
{
let
exam
=
{}
exam
.
id
=
_res
.
id
exam
.
title
=
_res
.
title
exam
.
radioList
=
_res
.
examination
.
radioList
for
(
let
i
=
0
;
i
<
exam
.
radioList
.
length
;
i
++
)
{
exam
.
radioList
[
i
].
user_answer
=
''
exam
.
radioList
[
i
].
right_answer
=
''
exam
.
radioList
[
i
].
get_score
=
-
1
}
exam
.
checkboxList
=
_res
.
examination
.
checkboxList
for
(
let
i
=
0
;
i
<
exam
.
checkboxList
.
length
;
i
++
)
{
exam
.
checkboxList
[
i
].
user_answer
=
[]
exam
.
checkboxList
[
i
].
right_answer
=
[]
exam
.
checkboxList
[
i
].
get_score
=
-
1
}
exam
.
shortAnswerList
=
_res
.
examination
.
shortAnswerList
for
(
let
i
=
0
;
i
<
exam
.
shortAnswerList
.
length
;
i
++
)
{
exam
.
shortAnswerList
[
i
].
user_answer
=
''
exam
.
shortAnswerList
[
i
].
get_score
=
-
1
exam
.
shortAnswerList
[
i
].
attachments
=
[]
exam
.
shortAnswerList
[
i
].
upload
=
{
type
:
'upload-form'
,
label
:
'附件上传:'
,
model
:
'attachments'
,
action
:
webConf
.
apiBaseURL
+
'/util/upload-file'
,
data
:
{
special
:
'exam'
},
attrs
:
{
multiple
:
true
,
headers
:
{
'tenant'
:
'sofia'
}
},
html
:
`
<div style="color: #72818c; font-size: 14px;">
<p style="margin: 0;">支持doc,docx,ppt,xls,txt,rar,zip,pdf,jpg,pic,png格式的文件,文件小于30M。</p>
</div>
`
}
}
return
exam
})
}
/* 获取考卷结果 */
getExamAnswer
(
cid
,
sid
,
eid
)
{
return
examApi
.
getExamAnswer
(
cid
,
sid
,
eid
).
then
(
_res
=>
{
let
exam
=
{}
exam
.
id
=
_res
.
id
exam
.
title
=
_res
.
title
exam
.
radioList
=
_res
.
sheet
.
radioList
for
(
let
i
=
0
;
i
<
exam
.
radioList
.
length
;
i
++
)
{
let
tmp
=
exam
.
radioList
[
i
]
if
(
!
tmp
.
user_answer
)
tmp
.
user_answer
=
''
if
(
!
tmp
.
right_answer
)
tmp
.
right_answer
=
''
if
(
!
tmp
.
get_score
)
tmp
.
get_score
=
-
1
}
exam
.
checkboxList
=
_res
.
sheet
.
checkboxList
for
(
let
i
=
0
;
i
<
exam
.
checkboxList
.
length
;
i
++
)
{
let
tmp
=
exam
.
checkboxList
[
i
]
if
(
!
tmp
.
user_answer
||
!
tmp
.
user_answer
.
length
)
tmp
.
user_answer
=
[]
if
(
!
tmp
.
right_answer
||
!
tmp
.
right_answer
.
length
)
tmp
.
right_answer
=
[]
if
(
!
tmp
.
get_score
)
tmp
.
get_score
=
-
1
}
exam
.
shortAnswerList
=
_res
.
sheet
.
shortAnswerList
for
(
let
i
=
0
;
i
<
exam
.
shortAnswerList
.
length
;
i
++
)
{
let
tmp
=
exam
.
shortAnswerList
[
i
]
if
(
!
tmp
.
attachments
||
!
tmp
.
attachments
.
length
)
tmp
.
attachments
=
[]
tmp
.
upload
=
{
type
:
'upload-form'
,
label
:
'附件上传:'
,
model
:
'attachments'
,
action
:
webConf
.
apiBaseURL
+
'/util/upload-file'
,
data
:
{
special
:
'exam'
,
headers
:
{
'tenant'
:
'sofia'
}
},
attrs
:
{
multiple
:
true
},
html
:
`
<div style="color: #72818c; font-size: 14px;">
<p style="margin: 0;">支持doc,docx,ppt,xls,txt,rar,zip,pdf,jpg,pic,png格式的文件,文件小于30M。</p>
</div>
`
}
}
return
exam
})
}
/* 提交考卷 */
submitExam
(
cid
,
sid
,
eid
,
obj
)
{
return
examApi
.
submitExam
(
cid
,
sid
,
eid
,
obj
).
then
(
_res
=>
{
return
_res
})
}
}
client/client/project/actions/index.js
浏览文件 @
ede512a4
import
LoginAction
from
'./LoginAction'
import
ChapterAction
from
'./ChapterAction'
import
ExamAction
from
'./ExamAction'
import
CourseAction
from
'./CourseAction'
import
DiscussAction
from
'./DiscussAction'
import
MsgAction
from
'./MsgAction'
...
...
@@ -8,6 +9,7 @@ import ReportAction from './ReportAction'
let
loginAction
=
new
LoginAction
()
let
chapterAction
=
new
ChapterAction
()
let
examAction
=
new
ExamAction
()
let
courseAction
=
new
CourseAction
()
let
discussAction
=
new
DiscussAction
()
let
msgAction
=
new
MsgAction
()
...
...
@@ -17,6 +19,7 @@ let reportAction = new ReportAction()
const
cAction
=
{
loginAction
,
chapterAction
,
examAction
,
courseAction
,
discussAction
,
msgAction
,
...
...
client/client/project/main.js
浏览文件 @
ede512a4
...
...
@@ -4,6 +4,7 @@ import './components/style/_com.scss' // 定义 element-ui主题色 + 公共样
import
VueRouter
from
'vue-router'
// 使用 vue-router
import
createRouter
from
'./router'
// router定义
import
Main
from
'./main.vue'
// 初始化 vue页面
import
UploadForm
from
'../components/upload-form'
// import cTool from '@tools'
/* 引入 md5 */
import
md5
from
'js-md5'
...
...
@@ -18,6 +19,8 @@ require('promise.prototype.finally').shim()
Vue
.
use
(
Element
)
Vue
.
use
(
VueRouter
)
Vue
.
use
(
UploadForm
)
Vue
.
component
(
UploadForm
.
name
,
UploadForm
)
const
router
=
createRouter
()
/* 设置全局变量 */
window
.
G
=
Vue
.
prototype
.
$GlobalVariable
=
{
...
...
client/client/project/router/routes.js
浏览文件 @
ede512a4
...
...
@@ -120,6 +120,12 @@ export default [
name
:
'courseWork'
,
component
:
()
=>
import
(
'../../components/player/courseWork/courseWork.vue'
),
props
:
true
},
{
path
:
'exam/:id'
,
name
:
'exam'
,
component
:
()
=>
import
(
'../../components/player/exam/exam.vue'
),
props
:
true
}
]
},
...
...
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论