Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
S
saas-lab
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
图表
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
EzijingWeb
saas-lab
Commits
ef8d6fc5
提交
ef8d6fc5
authored
6月 19, 2023
作者:
lhh
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
update
上级
be13cd6d
隐藏空白字符变更
内嵌
并排
正在显示
7 个修改的文件
包含
428 行增加
和
10 行删除
+428
-10
api.ts
src/modules/admin/lab/score/api.ts
+20
-0
Question.vue
src/modules/admin/lab/score/components/Question.vue
+237
-0
ScoreDialog.vue
src/modules/admin/lab/score/components/ScoreDialog.vue
+20
-9
StudentInfo.vue
src/modules/admin/lab/score/components/StudentInfo.vue
+27
-0
index.ts
src/modules/admin/lab/score/index.ts
+2
-1
types.ts
src/modules/admin/lab/score/types.ts
+14
-0
Score.vue
src/modules/admin/lab/score/views/Score.vue
+108
-0
没有找到文件。
src/modules/admin/lab/score/api.ts
浏览文件 @
ef8d6fc5
...
...
@@ -78,3 +78,23 @@ export function getExperimentScore(params: { experiment_id: string; student_id:
export
function
updateExperimentScore
(
data
:
{
experiment_id
:
string
;
student_id
:
string
;
score_details
:
string
})
{
return
httpRequest
.
post
(
'/api/lab/v1/teacher/experiment/achievement-check'
,
data
)
}
// 获取学员信息
export
function
getStudentInfo
(
params
:
{
experiment_id
:
string
;
student_id
:
string
})
{
return
httpRequest
.
get
(
'/api/lab/v1/teacher/student/detail'
,
{
params
})
}
// 获取学员信息
export
function
getQuestionList
(
params
:
{
experiment_id
:
string
;
student_id
:
string
})
{
return
httpRequest
.
get
(
'/api/lab/v1/teacher/experiment-question/list'
,
{
params
})
}
// 打分
export
function
updateQuestionScore
(
data
:
{
question_id
:
string
;
student_id
:
string
;
commit_score
:
string
})
{
return
httpRequest
.
post
(
'/api/lab/v1/teacher/experiment-question/check'
,
data
)
}
// 同步学生分数
export
function
asyncStudentResult
(
data
:
{
experiment_id
:
string
;
student_id
:
string
;
})
{
return
httpRequest
.
post
(
'/api/lab/v1/teacher/experiment-question/async-student-result'
,
data
)
}
src/modules/admin/lab/score/components/Question.vue
0 → 100644
浏览文件 @
ef8d6fc5
<
script
setup
lang=
"ts"
>
import
{
getQuestionList
,
updateQuestionScore
,
asyncStudentResult
}
from
'../api'
import
{
ElMessage
}
from
'element-plus'
const
route
=
useRoute
()
onMounted
(()
=>
{
fetchList
()
})
// 序号
let
orderList
=
$ref
<
any
[]
>
([])
// 所有题
let
questionList
=
$ref
([])
// 当前题序
let
currentIndex
=
$ref
(
1
)
// 获取当前题
const
questionDetail
:
any
=
computed
(()
=>
{
return
questionList
.
find
((
item
:
any
)
=>
item
.
order
===
currentIndex
)
})
const
fetchList
=
function
()
{
getQuestionList
({
experiment_id
:
route
.
query
.
id
as
string
,
student_id
:
route
.
query
.
sid
as
string
}).
then
(
res
=>
{
if
(
res
.
data
?.
items
)
{
questionList
=
res
.
data
.
items
.
map
((
item
:
any
,
index
:
number
)
=>
{
item
.
order
=
index
return
item
})
}
orderList
=
res
.
data
.
items
.
reduce
((
a
:
any
,
b
:
any
,
i
:
number
)
=>
{
if
(
b
.
type
===
'101'
||
b
.
type
===
'102'
)
{
setData
(
'1'
,
'用户/事件管理'
)
}
if
(
b
.
type
===
'201'
||
b
.
type
===
'202'
)
{
setData
(
'2'
,
'标签管理'
)
}
if
(
b
.
type
===
'301'
||
b
.
type
===
'302'
)
{
setData
(
'3'
,
'群组管理'
)
}
if
(
b
.
type
===
'401'
||
b
.
type
===
'402'
||
b
.
type
===
'403'
||
b
.
type
===
'404'
||
b
.
type
===
'405'
||
b
.
type
===
'406'
||
b
.
type
===
'407'
||
b
.
type
===
'408'
)
{
setData
(
'4'
,
'资料管理'
)
}
function
setData
(
type
:
string
,
name
:
string
)
{
const
index
=
a
.
findIndex
((
item
:
{
type
:
string
})
=>
item
.
type
===
type
)
b
.
order
=
i
+
1
index
===
-
1
?
a
.
push
({
type
:
type
,
name
:
name
,
q
:
[
b
]
})
:
a
[
index
].
q
.
push
(
b
)
}
return
a
},
[])
})
}
const
hasPrev
=
computed
(()
=>
currentIndex
>
1
)
const
hasNext
=
computed
(()
=>
currentIndex
<
questionList
.
length
)
function
handlePrev
()
{
currentIndex
--
}
function
handleNext
()
{
currentIndex
++
}
const
handleOrder
=
function
(
order
:
number
)
{
currentIndex
=
order
}
// 打分
const
updateScore
=
function
(
item
:
any
)
{
updateQuestionScore
({
question_id
:
item
.
id
,
student_id
:
route
.
query
.
sid
as
string
,
commit_score
:
item
.
commit_score
}).
then
(
res
=>
{
if
(
res
.
data
.
status
)
{
item
.
is_complete_check
=
true
ElMessage
({
message
:
'保存成功'
,
type
:
'success'
})
}
})
}
// 同步分数
const
handleSubmit
=
function
()
{
asyncStudentResult
({
experiment_id
:
route
.
query
.
id
as
string
,
student_id
:
route
.
query
.
sid
as
string
}).
then
(
res
=>
{
if
(
res
.
data
.
status
)
{
ElMessage
({
message
:
'提交成功'
,
type
:
'success'
})
}
})
}
</
script
>
<
template
>
<div
v-if=
"orderList.length"
>
<el-card
shadow=
"never"
class=
"question-number"
>
<dl
v-for=
"group in orderList"
:key=
"group.type"
>
<dt>
{{
group
.
name
}}
</dt>
<dd>
<span
@
click=
"handleOrder(question.order)"
:class=
"
{ 'is-active': question.is_complete_check }"
v-for="question in group.q"
:key="question.id"
>
{{
question
.
order
}}
</span
>
</dd>
</dl>
</el-card>
<el-card
shadow=
"never"
class=
"question-item"
v-if=
"questionDetail"
>
<!--
<h3
class=
"question-item__title"
>
标签管理
</h3>
-->
<p
class=
"question-item__stem"
>
{{
questionDetail
?.
order
}}
、
{{
questionDetail
.
title
}}
<span>
(
{{
questionDetail
.
score
}}
分)
</span>
</p>
<ul
class=
"question-item__files"
v-if=
"questionDetail.files"
>
<li
class=
"question-item__files-item"
v-for=
"file in questionDetail.files"
:key=
"file.url"
>
<div
class=
"question-item__files-item__title"
>
<p>
{{
file
.
name
}}
</p>
<p>
{{
file
.
size
}}
</p>
</div>
</li>
</ul>
<p
class=
"question-item__tip"
>
作答详情:详见系统
</p>
<p
class=
"question-item__content"
>
解析:
{{
questionDetail
.
answer_analysis
}}
</p>
<div
class=
"question-item-score"
>
<span>
本题得分
</span>
<el-input-number
style=
"width: 100px"
v-model=
"questionDetail.commit_score"
:min=
"0"
:max=
"questionDetail.score"
size=
"small"
controls-position=
"right"
/>
</div>
<el-row
justify=
"center"
>
<!--
<el-button>
取消
</el-button>
-->
<el-button
type=
"primary"
@
click=
"updateScore(questionDetail)"
>
保存
</el-button>
</el-row>
</el-card>
<el-row
justify=
"center"
>
<el-button
:disabled=
"!hasPrev"
type=
"primary"
@
click=
"handlePrev"
>
上一题
</el-button>
<el-button
:disabled=
"!hasNext"
type=
"primary"
@
click=
"handleNext"
>
下一题
</el-button>
<el-button
type=
"primary"
@
click=
"handleSubmit()"
>
提交
</el-button>
</el-row>
</div>
<el-empty
description=
"暂无数据"
v-else
/>
</
template
>
<
style
lang=
"scss"
scoped
>
.question-number
{
dt
{
font-size
:
14px
;
margin-bottom
:
10px
;
}
dd
{
span
{
margin-right
:
10px
;
margin-bottom
:
10px
;
display
:
inline-block
;
width
:
28px
;
height
:
28px
;
text-align
:
center
;
font-size
:
14px
;
line-height
:
28px
;
border
:
1px
solid
#bbb
;
border-radius
:
50%
;
cursor
:
pointer
;
&
.is-active
{
color
:
#fff
;
background-color
:
var
(
--
main-color
);
border-color
:
var
(
--
main-color
);
}
}
}
}
.question-item
{
margin-top
:
10px
;
margin-bottom
:
20px
;
}
.question-item__title
{
margin-bottom
:
10px
;
font-size
:
16px
;
font-weight
:
500
;
}
.question-item__stem
{
font-size
:
14px
;
color
:
#101010
;
}
.question-item__content
{
// margin-top: 10px;
font-size
:
13px
;
color
:
#75797b
;
}
.question-item__files-item
{
margin-top
:
10px
;
display
:
flex
;
align-items
:
center
;
padding
:
10px
;
background-color
:
#f2f2f2
;
border-radius
:
6px
;
a
{
margin-left
:
10px
;
font-size
:
14px
;
color
:
var
(
--
main-color
);
}
}
.question-item__files-item__title
{
flex
:
1
;
font-size
:
12px
;
color
:
#75797b
;
}
.question-item__tip
{
margin
:
15px
0
;
font-size
:
14px
;
color
:
#101010
;
}
.question-item-score
{
display
:
flex
;
justify-content
:
center
;
align-items
:
center
;
padding
:
20px
0
;
span
{
margin-right
:
10px
;
font-size
:
14px
;
}
}
</
style
>
src/modules/admin/lab/score/components/ScoreDialog.vue
浏览文件 @
ef8d6fc5
...
...
@@ -164,7 +164,8 @@ function getOperationUrl(type: number) {
title=
"学生实验评分"
:close-on-click-modal=
"false"
width=
"800px"
@
update:modelValue=
"$emit('update:modelValue')"
>
@
update:modelValue=
"$emit('update:modelValue')"
>
<el-form
label-width=
"120px"
label-suffix=
":"
v-if=
"detail"
>
<el-row>
<el-col
:span=
"12"
>
...
...
@@ -207,7 +208,8 @@ function getOperationUrl(type: number) {
:data=
"form.score_details"
stripe
:header-cell-style=
"
{ background: '#ededed' }"
style="margin-top: 20px">
style="margin-top: 20px"
>
<el-table-column
label=
"实验成绩组成项"
prop=
"name"
align=
"center"
></el-table-column>
<el-table-column
label=
"权重"
prop=
"percent"
align=
"center"
>
<template
#
default=
"
{ row }">
{{
row
.
percent
}}
%
</
template
>
...
...
@@ -224,7 +226,8 @@ function getOperationUrl(type: number) {
step-strictly
placeholder=
"请输入成绩"
style=
"width: 100px"
v-if=
"!(row.type === 1 && experiment.report_upload_way === 2)"
></el-input-number>
v-if=
"!(row.type === 1 && experiment.report_upload_way === 2)"
></el-input-number>
<span
v-else
>
{{
row
.
commit_score
}}
</span>
</
template
>
</el-table-column>
...
...
@@ -235,7 +238,8 @@ function getOperationUrl(type: number) {
text
type=
"primary"
@
click=
"$emit('update:modelValue')"
v-if=
"experiment.report_upload_way === 2"
>
v-if=
"experiment.report_upload_way === 2"
>
<a
:href=
"getOperationUrl(row.type)"
target=
"_blank"
>
批改
</a>
</el-button>
<template
v-if=
"experiment.report_upload_way === 1"
>
...
...
@@ -245,9 +249,13 @@ function getOperationUrl(type: number) {
<p
style=
"color: red"
v-else
>
未上传
</p>
</
template
>
</template>
<
template
v-else-if=
"[6, 7, 8, 9].includes(row.type)"
>
<
template
v-else-if=
"[6, 7, 8, 9
, 10
].includes(row.type)"
>
<el-button
text
type=
"primary"
>
<a
:href=
"getOperationUrl(row.type)"
target=
"_blank"
>
查看结果
</a>
<a
:href=
"`/admin/lab/score/score?id=$
{props.data.experiment_id}
&
sid=${props.data.student_id}
&
type=${row.type}`"
target="_blank"
>查看结果
</a
>
</el-button>
</
template
>
</template>
...
...
@@ -267,18 +275,21 @@ function getOperationUrl(type: number) {
v-model=
"prepareVisible"
:experiment_id=
"data.experiment_id"
:student_id=
"data.student_id"
v-if=
"prepareVisible"
></ScoreViewPrepareDialog>
v-if=
"prepareVisible"
></ScoreViewPrepareDialog>
<!-- 实验结果 -->
<ScoreViewResultDialog
v-model=
"resultVisible"
:experiment_id=
"data.experiment_id"
:student_id=
"data.student_id"
v-if=
"resultVisible"
></ScoreViewResultDialog>
v-if=
"resultVisible"
></ScoreViewResultDialog>
<!-- 实验截图 -->
<ScoreViewPicturesDialog
v-model=
"pictureVisible"
:data=
"detail"
v-if=
"pictureVisible && detail"
></ScoreViewPicturesDialog>
v-if=
"pictureVisible && detail"
></ScoreViewPicturesDialog>
</el-dialog>
</template>
...
...
src/modules/admin/lab/score/components/StudentInfo.vue
0 → 100644
浏览文件 @
ef8d6fc5
<
script
setup
lang=
"ts"
>
import
{
getStudentInfo
}
from
'../api'
import
type
{
StudentInfo
}
from
'../types'
const
route
=
useRoute
()
let
info
=
$ref
<
StudentInfo
>
()
onMounted
(()
=>
{
getStudentInfo
({
experiment_id
:
route
.
query
.
id
as
string
,
student_id
:
route
.
query
.
sid
as
string
}).
then
(
(
res
:
{
data
:
{
detail
:
StudentInfo
}
})
=>
{
info
=
res
.
data
?.
detail
}
)
})
</
script
>
<
template
>
<el-form
label-width=
"100px"
>
<el-form-item
label=
"姓名:"
>
{{
info
?.
name
}}
</el-form-item>
<el-form-item
label=
"学号:"
>
{{
info
?.
sno_number
}}
</el-form-item>
<el-form-item
label=
"所属班级:"
>
{{
info
?.
class
.
name
}}
</el-form-item>
<el-form-item
label=
"所属专业:"
>
{{
info
?.
specialty
.
name
}}
</el-form-item>
<el-form-item
label=
"实验名称:"
>
{{
info
?.
experiment
.
name
}}
</el-form-item>
</el-form>
</
template
>
<
style
lang=
"scss"
scoped
></
style
>
src/modules/admin/lab/score/index.ts
浏览文件 @
ef8d6fc5
...
...
@@ -7,7 +7,8 @@ export const routes: Array<RouteRecordRaw> = [
component
:
AppLayout
,
children
:
[
{
path
:
''
,
component
:
()
=>
import
(
'./views/Index.vue'
)
},
{
path
:
'report'
,
component
:
()
=>
import
(
'./views/Report.vue'
)
}
{
path
:
'report'
,
component
:
()
=>
import
(
'./views/Report.vue'
)
},
{
path
:
'score'
,
component
:
()
=>
import
(
'./views/Score.vue'
)
}
]
}
]
src/modules/admin/lab/score/types.ts
浏览文件 @
ef8d6fc5
...
...
@@ -36,3 +36,17 @@ export interface ScoreLog {
check_time
:
string
checker_id_name
:
string
}
export
interface
StudentInfo
{
name
:
string
sno_number
:
string
class
:
{
name
:
string
}
specialty
:
{
name
:
string
}
experiment
:
{
name
:
string
}
}
src/modules/admin/lab/score/views/Score.vue
0 → 100644
浏览文件 @
ef8d6fc5
<
script
setup
lang=
"ts"
>
import
DragPanel
from
'@/components/DragPanel.vue'
const
StudentInfo
=
defineAsyncComponent
(()
=>
import
(
'../components/StudentInfo.vue'
))
const
Question
=
defineAsyncComponent
(()
=>
import
(
'../components/Question.vue'
))
const
route
=
useRoute
()
let
resizeKey
=
$ref
(
0
)
function
handleResize
()
{
resizeKey
=
Date
.
now
()
}
const
getIframeUrl
=
function
()
{
const
type
=
route
.
query
.
type
if
(
type
===
'6'
)
{
// 用户标签
return
`
${
import
.
meta
.
env
.
VITE_DML_URL
}
/label?experiment_id=
${
route
.
query
.
id
}
&student_id=
${
route
.
query
.
sid
}
`
}
else
if
(
type
===
'7'
)
{
// 用户群组
return
`
${
import
.
meta
.
env
.
VITE_DML_URL
}
/group?experiment_id=
${
route
.
query
.
id
}
&student_id=
${
route
.
query
.
sid
}
`
}
else
if
(
type
===
'8'
)
{
// 用户旅程
return
`
${
import
.
meta
.
env
.
VITE_DML_URL
}
/trip/review?experiment_id=
${
route
.
query
.
id
}
&student_id=
${
route
.
query
.
sid
}
`
}
else
if
(
type
===
'9'
)
{
// 营销资料
return
`
${
import
.
meta
.
env
.
VITE_DML_URL
}
/material?experiment_id=
${
route
.
query
.
id
}
&student_id=
${
route
.
query
.
sid
}
`
}
else
if
(
type
===
'10'
)
{
// 用户事件
return
`
${
import
.
meta
.
env
.
VITE_DML_URL
}
/user?experiment_id=
${
route
.
query
.
id
}
&student_id=
${
route
.
query
.
sid
}
`
}
}
</
script
>
<
template
>
<DragPanel
@
resize=
"handleResize"
>
<template
#
left
>
<div
class=
"lab-left"
>
<el-tabs
type=
"border-card"
>
<el-tab-pane
label=
"打分详情"
lazy
>
<Question></Question>
</el-tab-pane>
<el-tab-pane
label=
"基本信息"
lazy
>
<StudentInfo></StudentInfo>
</el-tab-pane>
</el-tabs>
</div>
</
template
>
<
template
#
right
>
<div
class=
"lab-box"
>
<iframe
:src=
"getIframeUrl()"
frameborder=
"0"
class=
"iframe"
ref=
"iframeRef"
></iframe>
</div>
</
template
>
</DragPanel>
</template>
<!-- 上传报告 -->
<
style
lang=
"scss"
scoped
>
.close-btn
{
cursor
:
pointer
;
position
:
absolute
;
top
:
-40px
;
right
:
45px
;
transform
:
rotate
(
270deg
);
transform-origin
:
center
;
}
.lab-left
{
display
:
flex
;
flex-direction
:
column
;
width
:
100%
;
height
:
100%
;
overflow
:
hidden
;
h1
{
margin-bottom
:
20px
;
}
.el-tabs
{
flex
:
1
;
border
:
0
;
overflow
:
hidden
;
}
:deep
(
.el-tabs__header
)
{
background-color
:
#e1e4eb
;
}
:deep
(
.el-tabs__item
)
{
padding
:
0
14px
!
important
;
border
:
0
;
border-radius
:
6px
6px
0px
0px
;
}
:deep
(
.el-tabs__content
)
{
height
:
calc
(
100%
-
40px
);
box-sizing
:
border-box
;
}
:deep
(
.el-tab-pane
)
{
height
:
100%
;
overflow-y
:
auto
;
}
}
.lab-box
{
position
:
relative
;
flex
:
1
;
width
:
100%
;
margin-top
:
20px
;
background
:
#f8f9fa
;
}
.iframe
{
width
:
100%
;
height
:
100%
;
}
</
style
>
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论