Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
S
saas-lab
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
图表
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
EzijingWeb
saas-lab
Commits
718c4ccf
提交
718c4ccf
authored
9月 20, 2022
作者:
王鹏飞
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
chore: update
上级
f1368d8f
显示空白字符变更
内嵌
并排
正在显示
23 个修改的文件
包含
1416 行增加
和
3 行删除
+1416
-3
api.ts
src/modules/teacher/contest/discuss/api.ts
+26
-0
DiscussDialog.vue
...ules/teacher/contest/discuss/components/DiscussDialog.vue
+124
-0
DiscussItem.vue
...odules/teacher/contest/discuss/components/DiscussItem.vue
+150
-0
useFilterList.ts
...ules/teacher/contest/discuss/composables/useFilterList.ts
+15
-0
index.ts
src/modules/teacher/contest/discuss/index.ts
+10
-0
types.ts
src/modules/teacher/contest/discuss/types.ts
+48
-0
Index.vue
src/modules/teacher/contest/discuss/views/Index.vue
+87
-0
api.ts
src/modules/teacher/contest/record/api.ts
+42
-0
ImportDialog.vue
...odules/teacher/contest/record/components/ImportDialog.vue
+59
-0
ScoreDialog.vue
...modules/teacher/contest/record/components/ScoreDialog.vue
+196
-0
useFilterList.ts
...dules/teacher/contest/record/composables/useFilterList.ts
+21
-0
index.ts
src/modules/teacher/contest/record/index.ts
+10
-0
types.ts
src/modules/teacher/contest/record/types.ts
+27
-0
Index.vue
src/modules/teacher/contest/record/views/Index.vue
+154
-0
detail.vue
src/modules/teacher/contest/record/views/detail.vue
+1
-0
api.ts
src/modules/teacher/contest/score/api.ts
+42
-0
ImportDialog.vue
...modules/teacher/contest/score/components/ImportDialog.vue
+59
-0
ScoreDialog.vue
src/modules/teacher/contest/score/components/ScoreDialog.vue
+196
-0
useFilterList.ts
...odules/teacher/contest/score/composables/useFilterList.ts
+15
-0
index.ts
src/modules/teacher/contest/score/index.ts
+10
-0
types.ts
src/modules/teacher/contest/score/types.ts
+27
-0
Index.vue
src/modules/teacher/contest/score/views/Index.vue
+94
-0
menu.ts
src/stores/menu.ts
+3
-3
没有找到文件。
src/modules/teacher/contest/discuss/api.ts
0 → 100644
浏览文件 @
718c4ccf
import
httpRequest
from
'@/utils/axios'
// 获取讨论交流列表
export
function
getDiscussList
(
params
?:
{
competition_id
?:
string
student_name
?:
string
page
?:
number
page_size
?:
number
})
{
return
httpRequest
.
get
(
'/api/lab/v1/teacher/train-discussion/list'
,
{
params
})
}
// 获取筛选条件
export
function
getFilterList
()
{
return
httpRequest
.
get
(
'/api/lab/v1/teacher/train-discussion/competitions'
)
}
// 获取讨论交流详情
export
function
getDiscuss
(
params
:
{
id
:
string
;
page
?:
number
;
page_size
?:
number
})
{
return
httpRequest
.
get
(
'/api/lab/v1/teacher/train-discussion/view'
,
{
params
})
}
// 获取讨论交流详情
export
function
submitDiscussComment
(
data
:
{
id
:
string
;
content
:
string
})
{
return
httpRequest
.
post
(
'/api/lab/v1/teacher/train-discussion/comment'
,
data
)
}
src/modules/teacher/contest/discuss/components/DiscussDialog.vue
0 → 100644
浏览文件 @
718c4ccf
<
script
setup
lang=
"ts"
>
import
type
{
FormInstance
,
FormRules
}
from
'element-plus'
import
type
{
DiscussListItem
,
DiscussInfo
,
DiscussCommentItem
}
from
'../types'
import
{
Loading
}
from
'@element-plus/icons-vue'
import
{
ElMessage
}
from
'element-plus'
import
{
useInfiniteScroll
}
from
'@vueuse/core'
import
DiscussItem
from
'./DiscussItem.vue'
import
{
getDiscuss
,
submitDiscussComment
}
from
'../api'
interface
Props
{
data
:
DiscussListItem
}
const
props
=
defineProps
<
Props
>
()
const
emit
=
defineEmits
<
{
(
e
:
'update'
):
void
(
e
:
'update:modelValue'
,
visible
:
boolean
):
void
}
>
()
const
params
=
reactive
({
id
:
props
.
data
.
id
,
page
:
1
,
'per-page'
:
10
})
let
hasMore
=
$ref
(
false
)
let
isLoading
=
$ref
(
false
)
const
detail
=
reactive
<
{
info
?:
DiscussInfo
;
list
:
DiscussCommentItem
[]
}
>
({
info
:
undefined
,
list
:
[]
})
function
fetchInfo
(
isForce
=
false
)
{
if
(
!
props
.
data
.
id
)
return
if
(
isForce
)
{
params
.
page
=
1
}
isLoading
=
true
getDiscuss
(
params
)
.
then
(
res
=>
{
detail
.
info
=
res
.
data
.
info
detail
.
list
=
isForce
?
res
.
data
.
list
:
[...
detail
.
list
,
...
res
.
data
.
list
]
hasMore
=
!!
res
.
data
.
list
.
length
})
.
finally
(()
=>
{
isLoading
=
false
})
}
watch
(
()
=>
props
.
data
.
id
,
()
=>
{
fetchInfo
(
true
)
},
{
immediate
:
true
}
)
// 滚动加载
const
scrollRef
=
ref
<
HTMLElement
>
()
useInfiniteScroll
(
scrollRef
,
()
=>
{
if
(
!
hasMore
||
isLoading
)
return
params
.
page
++
fetchInfo
()
},
{
distance
:
10
}
)
const
formRef
=
$ref
<
FormInstance
>
()
const
form
=
reactive
<
{
content
:
string
}
>
({
content
:
''
})
const
rules
=
ref
<
FormRules
>
({
content
:
[{
required
:
true
,
message
:
'请输入回复内容'
}]
})
// 提交
function
handleSubmit
()
{
formRef
?.
validate
().
then
(()
=>
{
const
params
=
{
...
form
,
id
:
props
.
data
.
id
}
submitDiscussComment
(
params
).
then
(()
=>
{
ElMessage
({
message
:
'回复成功'
,
type
:
'success'
})
emit
(
'update'
)
fetchInfo
(
true
)
formRef
?.
resetFields
()
})
})
}
</
script
>
<
template
>
<el-dialog
title=
"大赛训练答疑"
:close-on-click-modal=
"false"
@
update:modelValue=
"$emit('update:modelValue')"
>
<div
class=
"discuss-scroll"
ref=
"scrollRef"
>
<DiscussItem
:info=
"detail.info"
:list=
"detail.list"
v-if=
"detail.info"
></DiscussItem>
<div
class=
"tips"
v-if=
"isLoading"
>
<el-icon
class=
"is-loading"
>
<Loading
/>
</el-icon>
加载中...
</div>
<div
class=
"tips"
v-if=
"!hasMore"
>
没有更多了
</div>
</div>
<el-form
ref=
"formRef"
:rules=
"rules"
:model=
"form"
style=
"margin-top: 40px"
v-permission=
"'v1-teacher-discussion-comment'"
>
<el-form-item
prop=
"content"
>
<el-input
type=
"textarea"
v-model=
"form.content"
:autosize=
"
{ minRows: 4, maxRows: 6 }" :maxlength="200" />
</el-form-item>
<el-row
justify=
"end"
>
<el-button
round
auto-insert-space
@
click=
"$emit('update:modelValue', false)"
>
取消
</el-button>
<el-button
type=
"primary"
round
auto-insert-space
@
click=
"handleSubmit"
>
保存回复
</el-button>
</el-row>
</el-form>
</el-dialog>
</
template
>
<
style
lang=
"scss"
scoped
>
.discuss-scroll
{
max-height
:
400px
;
overflow-y
:
auto
;
}
.tips
{
padding
:
20px
;
color
:
#555
;
text-align
:
center
;
}
.el-icon.is-loading
{
animation
:
rotating
2s
linear
infinite
;
}
</
style
>
src/modules/teacher/contest/discuss/components/DiscussItem.vue
0 → 100644
浏览文件 @
718c4ccf
<
script
setup
lang=
"ts"
>
import
type
{
DiscussInfo
,
DiscussCommentItem
}
from
'../types'
import
{
ChatLineRound
}
from
'@element-plus/icons-vue'
import
Avatar
from
'@/components/Avatar.vue'
interface
Props
{
info
:
DiscussInfo
list
:
DiscussCommentItem
[]
}
defineProps
<
Props
>
()
defineEmits
<
{
(
e
:
'update'
):
void
}
>
()
</
script
>
<
template
>
<div
class=
"discuss-item"
>
<div
class=
"discuss-box"
>
<div
class=
"discuss-box-user"
>
<div
class=
"discuss-box-user__avatar"
><Avatar
:src=
"info.created_operator_avatar"
/></div>
<div
class=
"discuss-box-user__content"
>
<h3>
{{
info
.
student_id_name
}}
</h3>
<p>
{{
info
.
created_time
}}
</p>
</div>
<div
class=
"button-comment"
>
<el-icon><ChatLineRound></ChatLineRound></el-icon>
{{
info
.
replies_num
}}
</div>
</div>
<div
class=
"discuss-box-main"
>
<h3>
{{
info
.
title
}}
</h3>
<div
class=
"discuss-box-content"
v-html=
"info.content"
></div>
</div>
</div>
<div
class=
"discuss-comment"
v-for=
"item in list"
:key=
"item.id"
>
<div
class=
"discuss-comment__avatar"
>
<Avatar
:src=
"item.sso_id_avatar"
/>
</div>
<div
class=
"discuss-comment-content"
>
<span
class=
"discuss-comment__username"
>
{{
item
.
sso_id_name
}}
</span
>
:
<span
v-html=
"item.content"
></span>
<p
class=
"discuss-comment-time"
>
{{
item
.
created_time
}}
</p>
</div>
</div>
</div>
</
template
>
<
style
lang=
"scss"
scoped
>
.discuss-box
{
padding-bottom
:
20px
;
border-bottom
:
1px
solid
#e6e6e6
;
}
.discuss-box-user
{
display
:
flex
;
align-items
:
center
;
.button-comment
{
display
:
flex
;
align-items
:
center
;
justify-content
:
center
;
color
:
#333333
;
cursor
:
pointer
;
&
.is-active
{
color
:
var
(
--
main-color
);
}
}
.el-icon
{
font-size
:
16px
;
margin-left
:
10px
;
margin-right
:
5px
;
}
}
.discuss-box-user__avatar
{
width
:
40px
;
height
:
40px
;
border-radius
:
50%
;
overflow
:
hidden
;
img
{
width
:
100%
;
height
:
100%
;
object-fit
:
cover
;
}
}
.discuss-box-user__content
{
flex
:
1
;
margin-left
:
10px
;
overflow
:
hidden
;
h3
{
font-size
:
16px
;
font-weight
:
500
;
line-height
:
20px
;
color
:
#333333
;
}
p
{
font-size
:
14px
;
font-weight
:
400
;
line-height
:
20px
;
color
:
#999999
;
}
}
.discuss-box-main
{
margin-left
:
50px
;
h3
{
padding
:
16px
0
;
font-size
:
16px
;
font-weight
:
500
;
line-height
:
20px
;
color
:
#333333
;
}
}
.discuss-box-content
{
font-size
:
16px
;
font-weight
:
400
;
line-height
:
24px
;
color
:
#333333
;
}
.discuss-comment
{
display
:
flex
;
margin-top
:
20px
;
}
.discuss-comment__avatar
{
width
:
32px
;
height
:
32px
;
border-radius
:
50%
;
overflow
:
hidden
;
img
{
width
:
100%
;
height
:
100%
;
object-fit
:
cover
;
}
}
.discuss-comment-content
{
flex
:
1
;
margin-left
:
10px
;
color
:
#333
;
overflow
:
hidden
;
}
.discuss-comment__username
{
font-size
:
16px
;
line-height
:
20px
;
color
:
var
(
--
main-color
);
}
.discuss-comment-time
{
margin-top
:
10px
;
font-size
:
14px
;
line-height
:
20px
;
color
:
#999999
;
text-align
:
right
;
}
</
style
>
src/modules/teacher/contest/discuss/composables/useFilterList.ts
0 → 100644
浏览文件 @
718c4ccf
import
{
getFilterList
}
from
'../api'
export
interface
FilterItem
{
id
:
string
name
:
string
}
// 赛项
const
competitions
=
ref
<
FilterItem
[]
>
([])
export
function
useFilterList
()
{
getFilterList
().
then
(
res
=>
{
competitions
.
value
=
res
.
data
})
return
{
competitions
}
}
src/modules/teacher/contest/discuss/index.ts
0 → 100644
浏览文件 @
718c4ccf
import
type
{
RouteRecordRaw
}
from
'vue-router'
import
AppLayout
from
'@/components/layout/Index.vue'
export
const
routes
:
Array
<
RouteRecordRaw
>
=
[
{
path
:
'/teacher/contest/discuss'
,
component
:
AppLayout
,
children
:
[{
path
:
''
,
component
:
()
=>
import
(
'./views/Index.vue'
)
}]
}
]
src/modules/teacher/contest/discuss/types.ts
0 → 100644
浏览文件 @
718c4ccf
export
interface
DiscussListItem
{
class_id
:
string
class_id_name
:
string
course_id
:
string
course_id_name
:
string
created_time
:
string
experiment_id
:
string
experiment_id_name
:
string
id
:
string
is_reply
:
string
is_reply_name
:
string
replies_num
:
number
sno_number
:
string
specialty_id
:
string
specialty_id_name
:
string
student_id
:
string
student_name
:
string
title
:
string
}
export
interface
DiscussInfo
{
content
:
string
created_operator
:
string
created_operator_avatar
:
string
created_time
:
string
delete_time
:
string
experiment_id
:
string
id
:
string
is_reply
:
string
replies_num
:
number
status
:
string
student_id
:
string
student_id_name
:
string
title
:
string
updated_operator
:
string
updated_time
:
string
}
export
interface
DiscussCommentItem
{
content
:
string
created_time
:
string
discussion_id
:
string
id
:
string
role
:
string
sso_id
:
string
sso_id_avatar
:
string
sso_id_name
:
string
}
src/modules/teacher/contest/discuss/views/Index.vue
0 → 100644
浏览文件 @
718c4ccf
<
script
setup
lang=
"ts"
>
import
type
{
DiscussListItem
}
from
'../types'
import
AppList
from
'@/components/base/AppList.vue'
import
{
getDiscussList
}
from
'../api'
import
{
useFilterList
}
from
'../composables/useFilterList'
const
DiscussDialog
=
defineAsyncComponent
(()
=>
import
(
'../components/DiscussDialog.vue'
))
const
{
competitions
}
=
useFilterList
()
const
appList
=
$ref
<
InstanceType
<
typeof
AppList
>
|
null
>
(
null
)
// 列表配置
const
listOptions
=
$computed
(()
=>
{
return
{
remote
:
{
httpRequest
:
getDiscussList
,
params
:
{
competition_id
:
''
,
student_name
:
''
}
},
filters
:
[
{
type
:
'select'
,
prop
:
'competition_id'
,
label
:
'赛项'
,
placeholder
:
'请选择赛项'
,
options
:
competitions
.
value
,
labelKey
:
'name'
,
valueKey
:
'id'
},
{
type
:
'input'
,
prop
:
'student_name'
,
label
:
'选手姓名'
,
placeholder
:
'请输入选手姓名'
}
],
columns
:
[
{
label
:
'序号'
,
type
:
'index'
,
width
:
60
},
{
label
:
'赛项名称'
,
prop
:
'competition_name'
},
{
label
:
'专业'
,
prop
:
'specialty_id_name'
},
{
label
:
'班级'
,
prop
:
'class_id_name'
},
{
label
:
'姓名'
,
prop
:
'student_name'
},
{
label
:
'学号'
,
prop
:
'sno_number'
},
{
label
:
'标题'
,
prop
:
'title'
},
{
label
:
'评论数量'
,
prop
:
'replies_num'
,
slots
:
'table-replies-num'
},
{
label
:
'更新时间'
,
prop
:
'created_time'
},
{
label
:
'操作'
,
slots
:
'table-x'
,
width
:
100
}
]
}
})
let
dialogVisible
=
$ref
(
false
)
const
rowData
=
ref
<
DiscussListItem
>
()
// 评论
function
handleComment
(
row
:
DiscussListItem
)
{
rowData
.
value
=
row
dialogVisible
=
true
}
function
onUpdateSuccess
()
{
appList
?.
refetch
()
}
</
script
>
<
template
>
<AppCard
title=
"训练答疑"
>
<AppList
v-bind=
"listOptions"
ref=
"appList"
>
<template
#
table-replies-num=
"
{ row }">
<span
:class=
"
{ 'is-info': !!row.replies_num }">
{{
row
.
replies_num
}}
</span>
</
template
>
<
template
#
table-x=
"{ row }"
>
<el-button
text
type=
"primary"
@
click=
"handleComment(row)"
v-permission=
"'v1-teacher-discussion-view'"
>
答疑
</el-button
>
</
template
>
</AppList>
</AppCard>
<DiscussDialog
v-model=
"dialogVisible"
:data=
"rowData"
@
update=
"onUpdateSuccess"
v-if=
"dialogVisible && rowData"
></DiscussDialog>
</template>
<
style
lang=
"scss"
scoped
>
.is-success
{
color
:
#63a103
;
}
.is-info
{
color
:
#b18862
;
}
</
style
>
src/modules/teacher/contest/record/api.ts
0 → 100644
浏览文件 @
718c4ccf
import
httpRequest
from
'@/utils/axios'
// 获取实验记录列表
export
function
getExperimentRecordList
(
params
?:
{
course_id
?:
string
experiment_id
?:
string
specialty_id
?:
string
class_id
?:
string
student_name
?:
string
page
?:
number
page_size
?:
number
})
{
return
httpRequest
.
get
(
'/api/lab/v1/expert/check/list'
,
{
params
})
}
// 获取筛选条件
export
function
getFilterList
(
params
?:
{
leader
?:
number
})
{
return
httpRequest
.
get
(
'/api/lab/v1/expert/check/condition'
,
{
params
})
}
// 获取实验记录详情
export
function
getExperimentRecord
(
params
:
{
experiment_id
:
string
;
student_id
:
string
})
{
return
httpRequest
.
get
(
'/api/lab/v1/teacher/record/view'
,
{
params
})
}
// 实验记录评分
export
function
checkExperimentRecord
(
data
:
{
experiment_id
:
string
student_id
:
string
operate
:
number
result
:
number
file
:
number
})
{
return
httpRequest
.
post
(
'/api/lab/v1/teacher/record/check'
,
data
)
}
// 批量导入实验记录评分
export
function
uploadCheckExperimentRecord
(
data
:
{
file
:
File
})
{
return
httpRequest
.
post
(
'/api/lab/v1/teacher/record/upload'
,
data
,
{
headers
:
{
'Content-Type'
:
'multipart/form-data'
}
})
}
src/modules/teacher/contest/record/components/ImportDialog.vue
0 → 100644
浏览文件 @
718c4ccf
<
script
setup
lang=
"ts"
>
import
{
Upload
}
from
'@element-plus/icons-vue'
import
{
useFileDialog
}
from
'@vueuse/core'
import
{
ElMessage
}
from
'element-plus'
import
{
uploadCheckExperimentRecord
}
from
'../api'
const
emit
=
defineEmits
<
{
(
e
:
'update'
):
void
}
>
()
// 批量导入
const
{
files
,
open
}
=
useFileDialog
()
function
handleImport
()
{
open
({
accept
:
'.csv,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel'
,
multiple
:
false
})
}
watchEffect
(()
=>
{
if
(
!
files
.
value
?.
length
)
return
const
[
file
]
=
files
.
value
uploadCheckExperimentRecord
({
file
}).
then
(()
=>
{
ElMessage
({
message
:
'导入成功'
,
type
:
'success'
})
emit
(
'update'
)
})
})
</
script
>
<
template
>
<el-dialog
title=
"批量导入"
:close-on-click-modal=
"false"
width=
"400px"
>
<div
class=
"box"
>
<el-button
type=
"primary"
round
:icon=
"Upload"
@
click=
"handleImport"
>
本地上传
</el-button>
<p>
<a
href=
"https://webapp-pub.ezijing.com/project/saas-lab/%E5%AE%9E%E9%AA%8C%E6%88%90%E7%BB%A9%E5%AF%BC%E5%85%A5%E6%A8%A1%E6%9D%BF.xlsx"
download
>
下载模板
</a
>
</p>
</div>
</el-dialog>
</
template
>
<
style
lang=
"scss"
scoped
>
.box
{
padding
:
20px
0
;
display
:
flex
;
align-items
:
center
;
justify-content
:
center
;
.el-button
{
width
:
220px
;
}
p
{
color
:
#999
;
margin-left
:
20px
;
}
}
</
style
>
src/modules/teacher/contest/record/components/ScoreDialog.vue
0 → 100644
浏览文件 @
718c4ccf
<
script
setup
lang=
"ts"
>
import
type
{
FormInstance
,
FormRules
}
from
'element-plus'
import
type
{
RecordItem
,
FileItem
}
from
'../types'
import
{
Document
}
from
'@element-plus/icons-vue'
import
{
ElMessage
,
ElMessageBox
}
from
'element-plus'
import
{
getExperimentRecord
,
checkExperimentRecord
}
from
'../api'
interface
Props
{
data
:
RecordItem
}
const
props
=
defineProps
<
Props
>
()
const
emit
=
defineEmits
<
{
(
e
:
'update'
):
void
(
e
:
'update:modelValue'
,
visible
:
boolean
):
void
}
>
()
let
detail
=
$ref
<
RecordItem
>
()
function
fetchInfo
()
{
getExperimentRecord
({
experiment_id
:
props
.
data
.
experiment_id
,
student_id
:
props
.
data
.
student_id
}).
then
(
res
=>
{
detail
=
res
.
data
})
}
watchEffect
(()
=>
{
fetchInfo
()
})
// 实验报告文件
const
file
=
$computed
<
FileItem
>
(()
=>
{
try
{
return
detail
?.
file
?
JSON
.
parse
(
detail
.
file
)
:
null
}
catch
(
error
)
{
console
.
log
(
error
)
}
return
null
})
// 实验过程截图
const
pictures
=
$computed
<
FileItem
[]
>
(()
=>
{
try
{
return
detail
?.
pictures
?
JSON
.
parse
(
detail
.
pictures
)
:
[]
}
catch
(
error
)
{
console
.
log
(
error
)
}
return
[]
})
const
formRef
=
$ref
<
FormInstance
>
()
const
form
=
reactive
<
{
operate
?:
number
;
result
?:
number
;
file
?:
number
}
>
({
operate
:
undefined
,
result
:
undefined
,
file
:
undefined
})
const
score
=
$computed
<
number
>
(()
=>
{
const
result
=
((
form
.
operate
||
0
)
+
(
form
.
result
||
0
)
+
(
form
.
file
||
0
))
/
3
return
parseFloat
(
result
.
toFixed
(
2
))
})
const
rules
=
ref
<
FormRules
>
({
operate
:
[{
required
:
true
,
message
:
'请输入1~100数字'
}],
result
:
[{
required
:
true
,
message
:
'请输入1~100数字'
}],
file
:
[{
required
:
true
,
message
:
'请输入1~100数字'
}]
})
// 提交
function
handleSubmit
()
{
formRef
?.
validate
().
then
(()
=>
{
ElMessageBox
.
confirm
(
'成绩评分不能修改,确认要保存该成绩吗?'
,
'提示'
).
then
(()
=>
{
const
params
:
any
=
{
...
form
,
experiment_id
:
props
.
data
.
experiment_id
,
student_id
:
props
.
data
.
student_id
}
checkExperimentRecord
(
params
).
then
(()
=>
{
ElMessage
({
message
:
'保存成功'
,
type
:
'success'
})
emit
(
'update'
)
emit
(
'update:modelValue'
,
false
)
})
})
})
}
</
script
>
<
template
>
<el-dialog
title=
"学生实验评分"
:close-on-click-modal=
"false"
width=
"700px"
@
update:modelValue=
"$emit('update:modelValue')"
>
<el-form
:rules=
"rules"
label-width=
"120px"
label-suffix=
":"
v-if=
"detail"
>
<el-row>
<el-col
:span=
"12"
>
<el-form-item
label=
"实验名称"
>
{{
detail
.
experiment_name
}}
</el-form-item>
</el-col>
<el-col
:span=
"12"
>
<el-form-item
label=
"实验课程名称"
>
{{
detail
.
course_name
}}
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col
:span=
"12"
>
<el-form-item
label=
"学生姓名"
>
{{
detail
.
student_name
}}
</el-form-item>
</el-col>
<el-col
:span=
"12"
>
<el-form-item
label=
"学生学号"
>
{{
detail
.
sno_number
}}
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col
:span=
"12"
>
<el-form-item
label=
"所属专业"
>
{{
detail
.
specialty_name
}}
</el-form-item>
</el-col>
<el-col
:span=
"12"
>
<el-form-item
label=
"所属班级"
>
{{
detail
.
class_name
}}
</el-form-item>
</el-col>
</el-row>
<el-form-item
label=
"实验成绩"
class=
"form-item-score"
>
<el-form
ref=
"formRef"
:model=
"form"
:rules=
"rules"
hide-required-asterisk
inline
label-position=
"top"
style=
"padding: 5px 0 20px"
>
<el-form-item
label=
"实验操作"
prop=
"operate"
>
<el-input-number
:min=
"1"
:max=
"100"
:controls=
"false"
step-strictly
v-model=
"form.operate"
/>
</el-form-item>
<el-form-item
label=
"实验结果"
prop=
"result"
>
<el-input-number
:min=
"1"
:max=
"100"
:controls=
"false"
step-strictly
v-model=
"form.result"
/>
</el-form-item>
<el-form-item
label=
"实验报告"
prop=
"file"
>
<el-input-number
:min=
"1"
:max=
"100"
:controls=
"false"
step-strictly
v-model=
"form.file"
/>
</el-form-item>
<el-form-item
label=
"综合实验成绩"
>
<el-input-number
:min=
"0"
:max=
"100"
:controls=
"false"
disabled
v-model=
"score"
/>
</el-form-item>
</el-form>
</el-form-item>
<el-form-item
label=
"实验报告文件"
>
<div
v-if=
"file"
>
<a
:href=
"file.url"
target=
"_blank"
class=
"file-item"
>
<el-icon><Document
/></el-icon>
{{
file
.
name
}}
</a>
</div>
</el-form-item>
<el-form-item
label=
"实验过程截图"
>
<ul
class=
"picture-list"
>
<li
v-for=
"item in pictures"
:key=
"item.url"
>
<p
class=
"t1"
>
<a
:href=
"item.url"
target=
"_blank"
>
{{
item
.
name
}}
</a>
</p>
<p
class=
"t2"
>
截图时间:
{{
item
.
upload_time
}}
</p>
</li>
</ul>
</el-form-item>
<el-row
justify=
"center"
>
<el-button
type=
"primary"
round
auto-insert-space
@
click=
"handleSubmit"
>
保存
</el-button>
<el-button
round
auto-insert-space
@
click=
"$emit('update:modelValue', false)"
>
取消
</el-button>
</el-row>
</el-form>
</el-dialog>
</
template
>
<
style
lang=
"scss"
scoped
>
.file-item
{
display
:
flex
;
align-items
:
center
;
color
:
var
(
--
main-color
);
.el-icon
{
margin-right
:
5px
;
}
}
.picture-list
{
width
:
100%
;
li
{
display
:
flex
;
justify-content
:
space-between
;
}
a
{
color
:
var
(
--
main-color
);
}
.t1
{
flex
:
1
;
white-space
:
nowrap
;
text-overflow
:
ellipsis
;
overflow
:
hidden
;
}
}
.form-item-score
{
padding-top
:
10px
;
background-color
:
#f8f9fb
;
border-radius
:
16px
;
:deep
(
.el-form-item__label
)
{
text-align
:
center
;
}
.el-input-number
{
width
:
100px
;
}
}
</
style
>
src/modules/teacher/contest/record/composables/useFilterList.ts
0 → 100644
浏览文件 @
718c4ccf
import
{
getFilterList
}
from
'../api'
export
interface
FilterItem
{
id
:
string
name
:
string
}
// 赛项
const
competitions
=
ref
<
FilterItem
[]
>
([])
// 学校
const
schools
=
ref
<
FilterItem
[]
>
([])
// 状态
const
status
=
ref
<
FilterItem
[]
>
([])
export
function
useFilterList
()
{
getFilterList
().
then
(
res
=>
{
competitions
.
value
=
res
.
data
.
competition
schools
.
value
=
res
.
data
.
school
status
.
value
=
res
.
data
.
status
})
return
{
competitions
,
schools
,
status
}
}
src/modules/teacher/contest/record/index.ts
0 → 100644
浏览文件 @
718c4ccf
import
type
{
RouteRecordRaw
}
from
'vue-router'
import
AppLayout
from
'@/components/layout/Index.vue'
export
const
routes
:
Array
<
RouteRecordRaw
>
=
[
{
path
:
'/teacher/contest/record'
,
component
:
AppLayout
,
children
:
[{
path
:
''
,
component
:
()
=>
import
(
'./views/Index.vue'
)
}]
}
]
src/modules/teacher/contest/record/types.ts
0 → 100644
浏览文件 @
718c4ccf
export
interface
RecordItem
{
check_time
:
string
checker_id
?:
string
class_id
:
string
class_name
:
string
commit_time
:
string
course_name
?:
string
experiment_id
:
string
experiment_name
:
string
file
?:
string
pictures
?:
string
score
:
string
score_details
?:
string
sno_number
:
string
specialty_id
:
string
specialty_name
:
string
status
:
0
|
1
|
2
status_name
:
string
student_id
:
string
student_name
:
string
}
export
interface
FileItem
{
name
:
string
url
:
string
upload_time
:
string
}
src/modules/teacher/contest/record/views/Index.vue
0 → 100644
浏览文件 @
718c4ccf
<
script
setup
lang=
"ts"
>
import
type
{
RecordItem
}
from
'../types'
import
{
Refresh
,
Upload
}
from
'@element-plus/icons-vue'
import
AppList
from
'@/components/base/AppList.vue'
import
{
getExperimentRecordList
}
from
'../api'
import
{
useFilterList
}
from
'../composables/useFilterList'
const
ScoreDialog
=
defineAsyncComponent
(()
=>
import
(
'../components/ScoreDialog.vue'
))
const
ImportDialog
=
defineAsyncComponent
(()
=>
import
(
'../components/ImportDialog.vue'
))
const
{
competitions
,
schools
,
status
}
=
useFilterList
()
const
appList
=
$ref
<
InstanceType
<
typeof
AppList
>
|
null
>
(
null
)
// 列表配置
const
listOptions
=
$computed
(()
=>
{
return
{
remote
:
{
httpRequest
:
getExperimentRecordList
,
params
:
{
competition_id
:
''
,
check_status
:
''
,
organ_id
:
''
,
login_id
:
''
,
student_name
:
''
}
},
filters
:
[
{
type
:
'select'
,
prop
:
'competition_id'
,
label
:
'赛项'
,
placeholder
:
'请选择赛项'
,
options
:
competitions
.
value
,
labelKey
:
'name'
,
valueKey
:
'id'
},
{
type
:
'select'
,
prop
:
'check_status'
,
label
:
'状态'
,
placeholder
:
'请选择是否评分'
,
options
:
status
.
value
,
labelKey
:
'name'
,
valueKey
:
'id'
},
{
type
:
'select'
,
prop
:
'organ_id'
,
label
:
'学校'
,
placeholder
:
'请选择学校'
,
options
:
schools
.
value
,
labelKey
:
'name'
,
valueKey
:
'id'
},
{
type
:
'input'
,
prop
:
'student_name'
,
label
:
'考生姓名'
,
placeholder
:
'请输入考生姓名'
},
{
type
:
'input'
,
prop
:
'login_id'
,
label
:
'考生ID'
,
placeholder
:
'请输入考生ID'
}
],
columns
:
[
{
label
:
'序号'
,
type
:
'index'
,
width
:
60
},
{
label
:
'赛项名称'
,
prop
:
'competition_id_name'
},
{
label
:
'选手姓名'
,
prop
:
'student_name'
},
{
label
:
'参赛ID'
,
prop
:
'login_id'
},
{
label
:
'性别'
,
prop
:
'gender'
},
{
label
:
'所在学校'
,
prop
:
'organ_id_name'
},
{
label
:
'所在专业'
,
prop
:
'specialty_id_name'
},
{
label
:
'所在班级'
,
prop
:
'class_id_name'
},
{
label
:
'训练次数'
,
prop
:
'train_count'
},
{
label
:
'评分规则'
,
prop
:
'competition_is_more_status'
},
{
label
:
'已评分人数'
,
prop
:
'experiment_name'
,
slots
:
'table-count'
},
{
label
:
'已评分'
,
prop
:
'checked_flag_name'
},
{
label
:
'得分'
,
prop
:
'score'
,
slots
:
'table-score'
},
{
label
:
'更新时间'
,
prop
:
'updated_time'
},
{
label
:
'操作'
,
slots
:
'table-x'
,
width
:
100
}
]
}
})
const
importVisible
=
$ref
(
false
)
let
dialogVisible
=
$ref
(
false
)
const
rowData
=
ref
<
RecordItem
>
()
// 评分
function
handleScore
(
row
:
RecordItem
)
{
rowData
.
value
=
row
dialogVisible
=
true
}
function
onUpdateSuccess
()
{
appList
?.
refetch
()
}
</
script
>
<
template
>
<AppCard
title=
"大赛评分"
>
<AppList
v-bind=
"listOptions"
ref=
"appList"
>
<template
#
header-buttons
>
<el-button
type=
"primary"
round
:icon=
"Refresh"
@
click=
"importVisible = true"
v-permission=
"'v1-teacher-record-upload'"
>
系统同步考试成绩
</el-button
>
<el-button
type=
"primary"
round
:icon=
"Upload"
@
click=
"importVisible = true"
v-permission=
"'v1-teacher-record-upload'"
>
批量导入考试成绩
</el-button
>
<el-button
type=
"primary"
round
:icon=
"Upload"
@
click=
"importVisible = true"
v-permission=
"'v1-teacher-record-upload'"
>
批量导入完整评分
</el-button
>
</
template
>
<
template
#
table-count=
"{ row }"
>
{{
row
.
checked_count
}}
/
{{
row
.
need_check_count
}}
</
template
>
<
template
#
table-score=
"{ row }"
>
<span
:class=
"
{ 'is-info': row.score !== '--' }">
{{
row
.
score
}}
</span>
</
template
>
<
template
#
table-x=
"{ row }"
>
<el-button
text
type=
"primary"
v-if=
"row.checked_flag"
@
click=
"handleScore(row)"
v-permission=
"'v1-teacher-record-check'"
>
评分
</el-button
>
</
template
>
</AppList>
</AppCard>
<!-- 评分 -->
<ScoreDialog
v-model=
"dialogVisible"
:data=
"rowData"
@
update=
"onUpdateSuccess"
v-if=
"dialogVisible && rowData"
></ScoreDialog>
<!-- 批量导入 -->
<ImportDialog
v-model=
"importVisible"
@
update=
"onUpdateSuccess"
v-if=
"importVisible"
></ImportDialog>
</template>
<
style
lang=
"scss"
scoped
>
.is-success
{
color
:
#63a103
;
}
.is-info
{
color
:
#b18862
;
}
</
style
>
src/modules/teacher/contest/record/views/detail.vue
0 → 100644
浏览文件 @
718c4ccf
src/modules/teacher/contest/score/api.ts
0 → 100644
浏览文件 @
718c4ccf
import
httpRequest
from
'@/utils/axios'
// 获取实验记录列表
export
function
getExperimentRecordList
(
params
?:
{
course_id
?:
string
experiment_id
?:
string
specialty_id
?:
string
class_id
?:
string
student_name
?:
string
page
?:
number
page_size
?:
number
})
{
return
httpRequest
.
get
(
'/api/lab/v1/expert/score/list'
,
{
params
})
}
// 获取筛选条件
export
function
getFilterList
()
{
return
httpRequest
.
get
(
'/api/lab/v1/expert/score/condition'
)
}
// 获取实验记录详情
export
function
getExperimentRecord
(
params
:
{
experiment_id
:
string
;
student_id
:
string
})
{
return
httpRequest
.
get
(
'/api/lab/v1/teacher/record/view'
,
{
params
})
}
// 实验记录评分
export
function
checkExperimentRecord
(
data
:
{
experiment_id
:
string
student_id
:
string
operate
:
number
result
:
number
file
:
number
})
{
return
httpRequest
.
post
(
'/api/lab/v1/teacher/record/check'
,
data
)
}
// 批量导入实验记录评分
export
function
uploadCheckExperimentRecord
(
data
:
{
file
:
File
})
{
return
httpRequest
.
post
(
'/api/lab/v1/teacher/record/upload'
,
data
,
{
headers
:
{
'Content-Type'
:
'multipart/form-data'
}
})
}
src/modules/teacher/contest/score/components/ImportDialog.vue
0 → 100644
浏览文件 @
718c4ccf
<
script
setup
lang=
"ts"
>
import
{
Upload
}
from
'@element-plus/icons-vue'
import
{
useFileDialog
}
from
'@vueuse/core'
import
{
ElMessage
}
from
'element-plus'
import
{
uploadCheckExperimentRecord
}
from
'../api'
const
emit
=
defineEmits
<
{
(
e
:
'update'
):
void
}
>
()
// 批量导入
const
{
files
,
open
}
=
useFileDialog
()
function
handleImport
()
{
open
({
accept
:
'.csv,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel'
,
multiple
:
false
})
}
watchEffect
(()
=>
{
if
(
!
files
.
value
?.
length
)
return
const
[
file
]
=
files
.
value
uploadCheckExperimentRecord
({
file
}).
then
(()
=>
{
ElMessage
({
message
:
'导入成功'
,
type
:
'success'
})
emit
(
'update'
)
})
})
</
script
>
<
template
>
<el-dialog
title=
"批量导入"
:close-on-click-modal=
"false"
width=
"400px"
>
<div
class=
"box"
>
<el-button
type=
"primary"
round
:icon=
"Upload"
@
click=
"handleImport"
>
本地上传
</el-button>
<p>
<a
href=
"https://webapp-pub.ezijing.com/project/saas-lab/%E5%AE%9E%E9%AA%8C%E6%88%90%E7%BB%A9%E5%AF%BC%E5%85%A5%E6%A8%A1%E6%9D%BF.xlsx"
download
>
下载模板
</a
>
</p>
</div>
</el-dialog>
</
template
>
<
style
lang=
"scss"
scoped
>
.box
{
padding
:
20px
0
;
display
:
flex
;
align-items
:
center
;
justify-content
:
center
;
.el-button
{
width
:
220px
;
}
p
{
color
:
#999
;
margin-left
:
20px
;
}
}
</
style
>
src/modules/teacher/contest/score/components/ScoreDialog.vue
0 → 100644
浏览文件 @
718c4ccf
<
script
setup
lang=
"ts"
>
import
type
{
FormInstance
,
FormRules
}
from
'element-plus'
import
type
{
RecordItem
,
FileItem
}
from
'../types'
import
{
Document
}
from
'@element-plus/icons-vue'
import
{
ElMessage
,
ElMessageBox
}
from
'element-plus'
import
{
getExperimentRecord
,
checkExperimentRecord
}
from
'../api'
interface
Props
{
data
:
RecordItem
}
const
props
=
defineProps
<
Props
>
()
const
emit
=
defineEmits
<
{
(
e
:
'update'
):
void
(
e
:
'update:modelValue'
,
visible
:
boolean
):
void
}
>
()
let
detail
=
$ref
<
RecordItem
>
()
function
fetchInfo
()
{
getExperimentRecord
({
experiment_id
:
props
.
data
.
experiment_id
,
student_id
:
props
.
data
.
student_id
}).
then
(
res
=>
{
detail
=
res
.
data
})
}
watchEffect
(()
=>
{
fetchInfo
()
})
// 实验报告文件
const
file
=
$computed
<
FileItem
>
(()
=>
{
try
{
return
detail
?.
file
?
JSON
.
parse
(
detail
.
file
)
:
null
}
catch
(
error
)
{
console
.
log
(
error
)
}
return
null
})
// 实验过程截图
const
pictures
=
$computed
<
FileItem
[]
>
(()
=>
{
try
{
return
detail
?.
pictures
?
JSON
.
parse
(
detail
.
pictures
)
:
[]
}
catch
(
error
)
{
console
.
log
(
error
)
}
return
[]
})
const
formRef
=
$ref
<
FormInstance
>
()
const
form
=
reactive
<
{
operate
?:
number
;
result
?:
number
;
file
?:
number
}
>
({
operate
:
undefined
,
result
:
undefined
,
file
:
undefined
})
const
score
=
$computed
<
number
>
(()
=>
{
const
result
=
((
form
.
operate
||
0
)
+
(
form
.
result
||
0
)
+
(
form
.
file
||
0
))
/
3
return
parseFloat
(
result
.
toFixed
(
2
))
})
const
rules
=
ref
<
FormRules
>
({
operate
:
[{
required
:
true
,
message
:
'请输入1~100数字'
}],
result
:
[{
required
:
true
,
message
:
'请输入1~100数字'
}],
file
:
[{
required
:
true
,
message
:
'请输入1~100数字'
}]
})
// 提交
function
handleSubmit
()
{
formRef
?.
validate
().
then
(()
=>
{
ElMessageBox
.
confirm
(
'成绩评分不能修改,确认要保存该成绩吗?'
,
'提示'
).
then
(()
=>
{
const
params
:
any
=
{
...
form
,
experiment_id
:
props
.
data
.
experiment_id
,
student_id
:
props
.
data
.
student_id
}
checkExperimentRecord
(
params
).
then
(()
=>
{
ElMessage
({
message
:
'保存成功'
,
type
:
'success'
})
emit
(
'update'
)
emit
(
'update:modelValue'
,
false
)
})
})
})
}
</
script
>
<
template
>
<el-dialog
title=
"学生实验评分"
:close-on-click-modal=
"false"
width=
"700px"
@
update:modelValue=
"$emit('update:modelValue')"
>
<el-form
:rules=
"rules"
label-width=
"120px"
label-suffix=
":"
v-if=
"detail"
>
<el-row>
<el-col
:span=
"12"
>
<el-form-item
label=
"实验名称"
>
{{
detail
.
experiment_name
}}
</el-form-item>
</el-col>
<el-col
:span=
"12"
>
<el-form-item
label=
"实验课程名称"
>
{{
detail
.
course_name
}}
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col
:span=
"12"
>
<el-form-item
label=
"学生姓名"
>
{{
detail
.
student_name
}}
</el-form-item>
</el-col>
<el-col
:span=
"12"
>
<el-form-item
label=
"学生学号"
>
{{
detail
.
sno_number
}}
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col
:span=
"12"
>
<el-form-item
label=
"所属专业"
>
{{
detail
.
specialty_name
}}
</el-form-item>
</el-col>
<el-col
:span=
"12"
>
<el-form-item
label=
"所属班级"
>
{{
detail
.
class_name
}}
</el-form-item>
</el-col>
</el-row>
<el-form-item
label=
"实验成绩"
class=
"form-item-score"
>
<el-form
ref=
"formRef"
:model=
"form"
:rules=
"rules"
hide-required-asterisk
inline
label-position=
"top"
style=
"padding: 5px 0 20px"
>
<el-form-item
label=
"实验操作"
prop=
"operate"
>
<el-input-number
:min=
"1"
:max=
"100"
:controls=
"false"
step-strictly
v-model=
"form.operate"
/>
</el-form-item>
<el-form-item
label=
"实验结果"
prop=
"result"
>
<el-input-number
:min=
"1"
:max=
"100"
:controls=
"false"
step-strictly
v-model=
"form.result"
/>
</el-form-item>
<el-form-item
label=
"实验报告"
prop=
"file"
>
<el-input-number
:min=
"1"
:max=
"100"
:controls=
"false"
step-strictly
v-model=
"form.file"
/>
</el-form-item>
<el-form-item
label=
"综合实验成绩"
>
<el-input-number
:min=
"0"
:max=
"100"
:controls=
"false"
disabled
v-model=
"score"
/>
</el-form-item>
</el-form>
</el-form-item>
<el-form-item
label=
"实验报告文件"
>
<div
v-if=
"file"
>
<a
:href=
"file.url"
target=
"_blank"
class=
"file-item"
>
<el-icon><Document
/></el-icon>
{{
file
.
name
}}
</a>
</div>
</el-form-item>
<el-form-item
label=
"实验过程截图"
>
<ul
class=
"picture-list"
>
<li
v-for=
"item in pictures"
:key=
"item.url"
>
<p
class=
"t1"
>
<a
:href=
"item.url"
target=
"_blank"
>
{{
item
.
name
}}
</a>
</p>
<p
class=
"t2"
>
截图时间:
{{
item
.
upload_time
}}
</p>
</li>
</ul>
</el-form-item>
<el-row
justify=
"center"
>
<el-button
type=
"primary"
round
auto-insert-space
@
click=
"handleSubmit"
>
保存
</el-button>
<el-button
round
auto-insert-space
@
click=
"$emit('update:modelValue', false)"
>
取消
</el-button>
</el-row>
</el-form>
</el-dialog>
</
template
>
<
style
lang=
"scss"
scoped
>
.file-item
{
display
:
flex
;
align-items
:
center
;
color
:
var
(
--
main-color
);
.el-icon
{
margin-right
:
5px
;
}
}
.picture-list
{
width
:
100%
;
li
{
display
:
flex
;
justify-content
:
space-between
;
}
a
{
color
:
var
(
--
main-color
);
}
.t1
{
flex
:
1
;
white-space
:
nowrap
;
text-overflow
:
ellipsis
;
overflow
:
hidden
;
}
}
.form-item-score
{
padding-top
:
10px
;
background-color
:
#f8f9fb
;
border-radius
:
16px
;
:deep
(
.el-form-item__label
)
{
text-align
:
center
;
}
.el-input-number
{
width
:
100px
;
}
}
</
style
>
src/modules/teacher/contest/score/composables/useFilterList.ts
0 → 100644
浏览文件 @
718c4ccf
import
{
getFilterList
}
from
'../api'
export
interface
FilterItem
{
id
:
string
name
:
string
}
// 赛项
const
competitions
=
ref
<
FilterItem
[]
>
([])
export
function
useFilterList
()
{
getFilterList
().
then
(
res
=>
{
competitions
.
value
=
res
.
data
})
return
{
competitions
}
}
src/modules/teacher/contest/score/index.ts
0 → 100644
浏览文件 @
718c4ccf
import
type
{
RouteRecordRaw
}
from
'vue-router'
import
AppLayout
from
'@/components/layout/Index.vue'
export
const
routes
:
Array
<
RouteRecordRaw
>
=
[
{
path
:
'/teacher/contest/score'
,
component
:
AppLayout
,
children
:
[{
path
:
''
,
component
:
()
=>
import
(
'./views/Index.vue'
)
}]
}
]
src/modules/teacher/contest/score/types.ts
0 → 100644
浏览文件 @
718c4ccf
export
interface
RecordItem
{
check_time
:
string
checker_id
?:
string
class_id
:
string
class_name
:
string
commit_time
:
string
course_name
?:
string
experiment_id
:
string
experiment_name
:
string
file
?:
string
pictures
?:
string
score
:
string
score_details
?:
string
sno_number
:
string
specialty_id
:
string
specialty_name
:
string
status
:
0
|
1
|
2
status_name
:
string
student_id
:
string
student_name
:
string
}
export
interface
FileItem
{
name
:
string
url
:
string
upload_time
:
string
}
src/modules/teacher/contest/score/views/Index.vue
0 → 100644
浏览文件 @
718c4ccf
<
script
setup
lang=
"ts"
>
import
type
{
RecordItem
}
from
'../types'
import
AppList
from
'@/components/base/AppList.vue'
import
{
getExperimentRecordList
}
from
'../api'
import
{
useFilterList
}
from
'../composables/useFilterList'
const
ScoreDialog
=
defineAsyncComponent
(()
=>
import
(
'../components/ScoreDialog.vue'
))
const
ImportDialog
=
defineAsyncComponent
(()
=>
import
(
'../components/ImportDialog.vue'
))
const
{
competitions
}
=
useFilterList
()
const
appList
=
$ref
<
InstanceType
<
typeof
AppList
>
|
null
>
(
null
)
// 列表配置
const
listOptions
=
$computed
(()
=>
{
return
{
remote
:
{
httpRequest
:
getExperimentRecordList
,
params
:
{
competition_id
:
''
}
},
filters
:
[
{
type
:
'select'
,
prop
:
'competition_id'
,
label
:
'赛项'
,
placeholder
:
'请选择赛项'
,
options
:
competitions
.
value
,
labelKey
:
'name'
,
valueKey
:
'id'
}
],
columns
:
[
{
label
:
'序号'
,
type
:
'index'
,
width
:
60
},
{
label
:
'赛项名称'
,
prop
:
'name'
},
{
label
:
'主办单位'
,
prop
:
'host_unit_id_name'
},
{
label
:
'赛项类型'
,
prop
:
'type_name'
},
{
label
:
'指导老师'
,
prop
:
'teachers'
,
slots
:
'table-teachers'
},
{
label
:
'报名人数'
,
prop
:
'all_competitor_count'
},
{
label
:
'专家人数'
,
prop
:
'expert_count'
},
{
label
:
'完赛人数'
,
prop
:
'complete_competitor_count'
},
{
label
:
'已评分人数'
,
prop
:
'checked_competitor_count'
},
{
label
:
'更新时间'
,
prop
:
'updated_time'
},
{
label
:
'操作'
,
slots
:
'table-x'
,
width
:
240
}
]
}
})
const
importVisible
=
$ref
(
false
)
let
dialogVisible
=
$ref
(
false
)
const
rowData
=
ref
<
RecordItem
>
()
// 评分
function
handleScore
(
row
:
RecordItem
)
{
rowData
.
value
=
row
dialogVisible
=
true
}
function
onUpdateSuccess
()
{
appList
?.
refetch
()
}
</
script
>
<
template
>
<AppCard
title=
"发布成绩"
>
<AppList
v-bind=
"listOptions"
ref=
"appList"
>
<template
#
table-teachers=
"
{ row }">
{{
row
.
teachers
.
join
()
}}
</
template
>
<
template
#
table-x=
"{ row }"
>
<el-button
round
type=
"primary"
@
click=
"handleScore(row)"
v-permission=
"'v1-teacher-record-check'"
>
查看成绩
</el-button
>
<el-button
round
type=
"primary"
@
click=
"handleScore(row)"
v-permission=
"'v1-teacher-record-check'"
>
发布赛项成绩
</el-button
>
</
template
>
</AppList>
</AppCard>
<!-- 评分 -->
<ScoreDialog
v-model=
"dialogVisible"
:data=
"rowData"
@
update=
"onUpdateSuccess"
v-if=
"dialogVisible && rowData"
></ScoreDialog>
<!-- 批量导入 -->
<ImportDialog
v-model=
"importVisible"
@
update=
"onUpdateSuccess"
v-if=
"importVisible"
></ImportDialog>
</template>
<
style
lang=
"scss"
scoped
>
.is-success
{
color
:
#63a103
;
}
.is-info
{
color
:
#b18862
;
}
</
style
>
src/stores/menu.ts
浏览文件 @
718c4ccf
...
@@ -54,15 +54,15 @@ const teacherMenus: IMenuItem[] = [
...
@@ -54,15 +54,15 @@ const teacherMenus: IMenuItem[] = [
children
:
[
children
:
[
{
{
name
:
'训练答疑'
,
name
:
'训练答疑'
,
path
:
'/teacher/contest/
item
s'
path
:
'/teacher/contest/
discus
s'
},
},
{
{
name
:
'大赛评分'
,
name
:
'大赛评分'
,
path
:
'/teacher/contest/
contestants
'
path
:
'/teacher/contest/
record
'
},
},
{
{
name
:
'发布成绩'
,
name
:
'发布成绩'
,
path
:
'/teacher/contest/
judges
'
path
:
'/teacher/contest/
score
'
}
}
]
]
}
}
...
...
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论