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 个修改的文件
包含
517 行增加
和
0 行删除
+517
-0
exam.vue
client/client/components/player/exam/exam.vue
+0
-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
差异被折叠。
点击展开。
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
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论