Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
L
learn-online-pc
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
图表
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
EzijingWeb
learn-online-pc
Commits
01c48e8f
提交
01c48e8f
authored
5月 09, 2020
作者:
王鹏飞
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
chore: 修改课程考试页面
上级
523bbbb5
全部展开
隐藏空白字符变更
内嵌
并排
正在显示
9 个修改的文件
包含
545 行增加
和
2 行删除
+545
-2
PlayerAction.js
client/src/action/PlayerAction.js
+122
-0
base_api.js
client/src/api/base_api.js
+2
-2
player_api.js
client/src/api/player_api.js
+28
-0
elemInfo.md
client/src/components/upload-form/elemInfo.md
+57
-0
index.js
client/src/components/upload-form/index.js
+8
-0
ajax.js
client/src/components/upload-form/src/ajax.js
+125
-0
uploadForm.vue
client/src/components/upload-form/src/uploadForm.vue
+200
-0
main.js
client/src/main.js
+3
-0
exam.vue
client/src/pages/player/exam/exam.vue
+0
-0
没有找到文件。
client/src/action/PlayerAction.js
浏览文件 @
01c48e8f
...
...
@@ -284,4 +284,126 @@ export default class PlayerAction extends BaseACTION {
getLiveList
()
{
return
Player
.
getLiveList
().
then
(
res
=>
res
)
}
/* 获取云课堂 url */
getCloudUrl
()
{
return
Player
.
getCloudUrl
().
then
(
res
=>
res
)
}
/* 获取考卷信息 */
getExamInfo
(
cid
,
sid
)
{
return
Player
.
getExamInfo
(
cid
,
sid
).
then
(
_res
=>
{
const
exam
=
{}
exam
.
id
=
_res
.
id
exam
.
title
=
_res
.
title
exam
.
score
=
{}
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
Player
.
getExamAnswer
(
cid
,
sid
,
eid
).
then
(
_res
=>
{
if
(
_res
.
code
)
{
return
_res
}
const
exam
=
{}
let
tmp
=
null
exam
.
id
=
_res
.
id
exam
.
title
=
_res
.
title
exam
.
type
=
_res
.
type
exam
.
score
=
_res
.
score
exam
.
isPublished
=
_res
.
is_published
||
''
exam
.
submitted_time
=
_res
.
submitted_time
exam
.
radioList
=
_res
.
sheet
.
radioList
for
(
let
i
=
0
;
i
<
exam
.
radioList
.
length
;
i
++
)
{
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
++
)
{
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
++
)
{
tmp
=
exam
.
shortAnswerList
[
i
]
tmp
.
user_answer
=
Base64
.
decode
(
tmp
.
user_answer
.
replace
(
/ /gi
,
'+'
))
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'
},
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
})
}
/* 获取考试状态 */
getExamStatus
(
cid
,
sid
,
eid
)
{
return
Player
.
getExamStatus
(
cid
,
sid
,
eid
).
then
(
_res
=>
{
/* 00: 考场未开放,不允许进入
10:考场开放,允许进入
20:开始答题
90:考试已结束 */
return
_res
})
}
/* 提交考卷 */
submitExam
(
cid
,
sid
,
eid
,
obj
)
{
return
Player
.
submitExam
(
cid
,
sid
,
eid
,
obj
).
then
(
_res
=>
{
return
_res
})
}
}
client/src/api/base_api.js
浏览文件 @
01c48e8f
...
...
@@ -100,9 +100,9 @@ export default class API {
if
(
data
&&
data
.
code
!==
undefined
)
{
if
(
data
.
code
!==
0
)
{
if
(
!
/account
\/
get-user-info/gi
.
test
(
res
.
config
.
url
))
{
Message
({
type
:
'error'
,
message
:
data
.
msg
})
data
.
msg
&&
Message
({
type
:
'error'
,
message
:
data
.
msg
})
}
return
null
return
data
}
else
if
(
data
.
code
===
0
)
{
return
data
.
data
}
...
...
client/src/api/player_api.js
浏览文件 @
01c48e8f
...
...
@@ -101,4 +101,32 @@ export default class PlayerAPI extends BaseAPI {
* 跨域接口请求 - 直接获取云课堂设置
*/
getCloudUrl
=
(
obj
=
{})
=>
this
.
get
(
'https://node-server.ezijing.com/get/cloud-class'
,
obj
)
/**
* 获取考卷信息
* @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
*/
getExamStatus
=
(
cid
,
sid
,
eid
)
=>
this
.
get
(
`/v2/education/
${
sid
}
/
${
cid
}
/examination/
${
eid
}
/status`
,
{})
/**
* 提交考卷
* @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/src/components/upload-form/elemInfo.md
0 → 100644
浏览文件 @
01c48e8f
## 组件简介
| 字段值 | 说明 | 字段属性 | 默认值 |
| ------- | ------------------------- | ------- | ----- |
|
`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/src/components/upload-form/index.js
0 → 100644
浏览文件 @
01c48e8f
import
Upload
from
'./src/uploadForm.vue'
/* istanbul ignore next */
Upload
.
install
=
function
(
Vue
)
{
Vue
.
component
(
Upload
.
name
,
Upload
)
}
export
default
Upload
client/src/components/upload-form/src/ajax.js
0 → 100755
浏览文件 @
01c48e8f
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/src/components/upload-form/src/uploadForm.vue
0 → 100644
浏览文件 @
01c48e8f
<
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) || !isUpload"
v-bind=
"item.attrs ||
{}"
>
<el-button
type=
"primary"
size=
"small"
:disabled=
"!isUpload"
>
点击上传
</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) && isUpload"
>
<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) && isUpload"
>
<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
{}
}
},
isUpload
:
{
type
:
Boolean
,
default
()
{
return
true
}
}
},
data
()
{
const
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)
// }
// }
// })
}
},
watch
:
{
filesArr
:
{
immediate
:
true
,
deep
:
true
,
handler
(
value
)
{
if
(
this
.
formData
[
this
.
item
.
model
].
length
!==
value
.
length
)
{
this
.
formData
[
this
.
item
.
model
]
=
value
}
}
}
}
}
</
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/src/main.js
浏览文件 @
01c48e8f
...
...
@@ -5,6 +5,7 @@ import VueI18n from 'vue-i18n' // 使用 国际化
import
createI18n
from
'./assets/languages'
// 国际化定义
import
App
from
'./app.vue'
// 初始化 vue页面
import
UploadForm
from
'./components/upload-form'
import
'./style.scss'
// 公共样式
import
MetaInfo
from
'vue-meta-info'
import
Element
from
'element-ui'
...
...
@@ -19,6 +20,8 @@ require('promise.prototype.finally').shim()
/* 兼容处理 end */
Vue
.
use
(
VueRouter
)
Vue
.
use
(
UploadForm
)
Vue
.
component
(
UploadForm
.
name
,
UploadForm
)
const
router
=
createRouter
()
Vue
.
use
(
VueI18n
)
const
i18n
=
createI18n
()
...
...
client/src/pages/player/exam/exam.vue
浏览文件 @
01c48e8f
差异被折叠。
点击展开。
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论