Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
S
saas-lab
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
图表
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
EzijingWeb
saas-lab
Commits
5dabc6d8
提交
5dabc6d8
authored
6月 23, 2025
作者:
王鹏飞
浏览文件
操作
浏览文件
下载
差异文件
Merge branch 'master' into 202412
上级
48cc2d24
af8147cb
全部展开
隐藏空白字符变更
内嵌
并排
正在显示
37 个修改的文件
包含
1449 行增加
和
605 行删除
+1449
-605
.env
.env
+1
-0
dml_home_teacher_bg.png
src/assets/images/dml_home_teacher_bg.png
+0
-0
dml_home_teacher_bg2.png
src/assets/images/dml_home_teacher_bg2.png
+0
-0
DragPanel.vue
src/components/DragPanel.vue
+3
-3
api.ts
src/modules/admin/lab/experiment/api.ts
+40
-9
DMLFormDialog.vue
...modules/admin/lab/experiment/components/DMLFormDialog.vue
+59
-32
FormDialog.vue
src/modules/admin/lab/experiment/components/FormDialog.vue
+16
-14
GradeRulesDialog.vue
...ules/admin/lab/experiment/components/GradeRulesDialog.vue
+13
-17
EventQuestion.vue
...min/lab/experiment/components/Questions/EventQuestion.vue
+177
-0
GroupQuestion.vue
...min/lab/experiment/components/Questions/GroupQuestion.vue
+49
-34
JourneyQuestion.vue
...n/lab/experiment/components/Questions/JourneyQuestion.vue
+24
-22
MaterialQuestion.vue
.../lab/experiment/components/Questions/MaterialQuestion.vue
+76
-96
PreviewDialog.vue
...min/lab/experiment/components/Questions/PreviewDialog.vue
+5
-9
QuestionsOrder.vue
...in/lab/experiment/components/Questions/QuestionsOrder.vue
+7
-6
TagQuestion.vue
...admin/lab/experiment/components/Questions/TagQuestion.vue
+47
-37
UserQuestion.vue
...dmin/lab/experiment/components/Questions/UserQuestion.vue
+115
-88
useQuestion.ts
src/modules/admin/lab/experiment/composables/useQuestion.ts
+83
-0
types.ts
src/modules/admin/lab/experiment/types.ts
+1
-0
Index.vue
src/modules/admin/lab/experiment/views/Index.vue
+13
-15
Questions.vue
src/modules/admin/lab/experiment/views/Questions.vue
+88
-82
View.vue
src/modules/admin/lab/experiment/views/View.vue
+19
-20
api.ts
src/modules/admin/lab/score/api.ts
+19
-3
ScoreDialog.vue
src/modules/admin/lab/score/components/ScoreDialog.vue
+93
-54
ScoreViewAutoDialog.vue
...odules/admin/lab/score/components/ScoreViewAutoDialog.vue
+133
-0
Index.vue
src/modules/admin/lab/score/views/Index.vue
+56
-19
api.ts
src/modules/student/lab/api.ts
+23
-3
Book.vue
src/modules/student/lab/components/Book.vue
+6
-2
Case.vue
src/modules/student/lab/components/Case.vue
+6
-2
Exam.vue
src/modules/student/lab/components/Exam.vue
+24
-11
Question.vue
src/modules/student/lab/components/Question.vue
+21
-11
ResultScoreDialog.vue
src/modules/student/lab/components/ResultScoreDialog.vue
+81
-8
ResultScoreViewAutoDialog.vue
...ules/student/lab/components/ResultScoreViewAutoDialog.vue
+131
-0
Video.vue
src/modules/student/lab/components/Video.vue
+6
-3
types.ts
src/modules/student/lab/types.ts
+1
-0
Index.vue
src/modules/student/lab/views/Index.vue
+0
-0
dictionary.ts
src/utils/dictionary.ts
+7
-5
upload.ts
src/utils/upload.ts
+6
-0
没有找到文件。
.env
浏览文件 @
5dabc6d8
...
@@ -9,3 +9,4 @@ VITE_EXAM_SHOW_URL=https://exam-show.zijing.chat
...
@@ -9,3 +9,4 @@ VITE_EXAM_SHOW_URL=https://exam-show.zijing.chat
VITE_SWSJFXS_LOGIN_URL=http://172.16.3.203:1001/swsjfxs/login/index
VITE_SWSJFXS_LOGIN_URL=http://172.16.3.203:1001/swsjfxs/login/index
VITE_SYS_FLAG=chat
VITE_SYS_FLAG=chat
VITE_STATIC_URL=https://saas-lab-api
VITE_STATIC_URL=https://saas-lab-api
VITE_SAAS_BI_URL=https://saas-bi.ezijing.com/data/dashboard
src/assets/images/dml_home_teacher_bg.png
查看替换文件 @
48cc2d24
浏览文件 @
5dabc6d8
差异被折叠。
点击展开。
src/assets/images/dml_home_teacher_bg2.png
0 → 100644
浏览文件 @
5dabc6d8
差异被折叠。
点击展开。
src/components/DragPanel.vue
浏览文件 @
5dabc6d8
...
@@ -5,7 +5,7 @@ const emit = defineEmits<{
...
@@ -5,7 +5,7 @@ const emit = defineEmits<{
(
e
:
'resize'
):
void
(
e
:
'resize'
):
void
}
>
()
}
>
()
defineProps
<
{
isLeftShow
?:
number
}
>
()
defineProps
<
{
isLeftShow
?:
boolean
}
>
()
const
leftPanelVisible
=
$ref
<
boolean
>
(
true
)
const
leftPanelVisible
=
$ref
<
boolean
>
(
true
)
const
leftPanelWidth
=
useStorage
(
'leftPanelWidth'
,
400
)
const
leftPanelWidth
=
useStorage
(
'leftPanelWidth'
,
400
)
...
@@ -42,7 +42,7 @@ onMounted(() => {
...
@@ -42,7 +42,7 @@ onMounted(() => {
<
template
>
<
template
>
<section
class=
"drag-panel"
>
<section
class=
"drag-panel"
>
<div
v-
show=
"isLeftShow !== 1
"
class=
"drag-panel-left"
:class=
"
{ 'is-hidden': !leftPanelVisible }">
<div
v-
if=
"!isLeftShow
"
class=
"drag-panel-left"
:class=
"
{ 'is-hidden': !leftPanelVisible }">
<div
class=
"drag-cover"
v-if=
"dragFlag"
></div>
<div
class=
"drag-cover"
v-if=
"dragFlag"
></div>
<slot
name=
"left"
></slot>
<slot
name=
"left"
></slot>
<div
class=
"panel-resize"
id=
"panel-resize"
></div>
<div
class=
"panel-resize"
id=
"panel-resize"
></div>
...
@@ -73,6 +73,7 @@ onMounted(() => {
...
@@ -73,6 +73,7 @@ onMounted(() => {
.drag-panel
{
.drag-panel
{
display
:
flex
;
display
:
flex
;
height
:
calc
(
100vh
-
110px
);
height
:
calc
(
100vh
-
110px
);
gap
:
20px
;
}
}
.drag-panel-left
{
.drag-panel-left
{
position
:
relative
;
position
:
relative
;
...
@@ -123,7 +124,6 @@ onMounted(() => {
...
@@ -123,7 +124,6 @@ onMounted(() => {
display
:
flex
;
display
:
flex
;
flex-direction
:
column
;
flex-direction
:
column
;
height
:
100%
;
height
:
100%
;
margin-left
:
20px
;
}
}
.drag-cover
{
.drag-cover
{
width
:
100%
;
width
:
100%
;
...
...
src/modules/admin/lab/experiment/api.ts
浏览文件 @
5dabc6d8
...
@@ -86,7 +86,11 @@ export function getExperimentReportRule(params: { experiment_id: string }) {
...
@@ -86,7 +86,11 @@ export function getExperimentReportRule(params: { experiment_id: string }) {
return
httpRequest
.
get
(
'/api/resource/v1/backend/experiment-report/detail'
,
{
params
})
return
httpRequest
.
get
(
'/api/resource/v1/backend/experiment-report/detail'
,
{
params
})
}
}
// 更新实验报告规则
// 更新实验报告规则
export
function
updateExperimentReportRule
(
data
:
{
experiment_id
:
string
;
report_upload_way
:
number
;
detail_list
:
string
})
{
export
function
updateExperimentReportRule
(
data
:
{
experiment_id
:
string
report_upload_way
:
number
detail_list
:
string
})
{
return
httpRequest
.
post
(
'/api/resource/v1/backend/experiment-report/save'
,
data
)
return
httpRequest
.
post
(
'/api/resource/v1/backend/experiment-report/save'
,
data
)
}
}
...
@@ -98,7 +102,7 @@ export function getTripConfig(params: { experiment_id: string }) {
...
@@ -98,7 +102,7 @@ export function getTripConfig(params: { experiment_id: string }) {
// 更新旅程配置
// 更新旅程配置
export
function
updateTripConfig
(
data
:
{
experiment_id
:
string
})
{
export
function
updateTripConfig
(
data
:
{
experiment_id
:
string
})
{
return
httpRequest
.
post
(
'/api/lab/v1/experiment/itinerary-config/save'
,
data
,
{
return
httpRequest
.
post
(
'/api/lab/v1/experiment/itinerary-config/save'
,
data
,
{
headers
:
{
'Content-Type'
:
'application/json'
}
headers
:
{
'Content-Type'
:
'application/json'
}
,
})
})
}
}
...
@@ -141,22 +145,50 @@ export function getQuestions(data: { experiment_id: string; types?: any }) {
...
@@ -141,22 +145,50 @@ export function getQuestions(data: { experiment_id: string; types?: any }) {
return
httpRequest
.
post
(
'/api/resource/v1/backend/experiment-question/list'
,
data
)
return
httpRequest
.
post
(
'/api/resource/v1/backend/experiment-question/list'
,
data
)
}
}
// 获取老师创建的标签
//
试题
获取老师创建的标签
export
function
getQuestionTags
(
params
:
{
experiment_id
:
string
})
{
export
function
getQuestionTags
(
params
:
{
experiment_id
:
string
})
{
return
httpRequest
.
get
(
'/api/resource/v1/backend/experiment-question/tags'
,
{
params
})
return
httpRequest
.
get
(
'/api/resource/v1/backend/experiment-question/tags
2
'
,
{
params
})
}
}
// 获取群组
//
试题
获取群组
export
function
getQuestionGroup
(
params
:
{
experiment_id
:
string
})
{
export
function
getQuestionGroup
(
params
:
{
experiment_id
:
string
})
{
return
httpRequest
.
get
(
'/api/resource/v1/backend/experiment-question/groups'
,
{
params
})
return
httpRequest
.
get
(
'/api/resource/v1/backend/experiment-question/groups'
,
{
params
})
}
}
// 试题获取营销资料
export
function
getQuestionMaterials
(
params
:
{
experiment_id
:
string
;
type
:
string
})
{
return
httpRequest
.
get
(
'/api/resource/v1/backend/experiment-question/materials'
,
{
params
})
}
// 试题获取事件
export
function
getQuestionEvents
(
params
:
{
experiment_id
:
string
})
{
return
httpRequest
.
get
(
'/api/resource/v1/backend/experiment-question/events'
,
{
params
})
}
// 获取Excel总条数
export
function
getExcelTotalLine
(
data
:
{
file
:
File
})
{
return
httpRequest
.
post
(
'/api/lab/v1/common/file/get-excel-total-line'
,
data
,
{
headers
:
{
'Content-Type'
:
'multipart/form-data'
},
})
}
// 判断是否维护了自动生成数据
export
function
checkAutoGenerateData
(
params
:
{
experiment_id
:
string
;
event_id
?:
string
})
{
return
httpRequest
.
get
(
'/api/resource/v1/backend/experiment-question/check-auto-generate-data'
,
{
params
})
}
// 获取实验下的所有理论考试
// 获取实验下的所有理论考试
export
function
getAllExamList
(
params
:
{
project
:
string
;
q
?:
string
;
name
?:
string
;
page
?:
number
;
'per-page'
?:
number
})
{
export
function
getAllExamList
(
params
:
{
project
:
string
q
?:
string
name
?:
string
page
?:
number
'per-page'
?:
number
})
{
return
httpRequest
.
get
(
'/api/resource/v1/backend/exam/search-all-exam'
,
{
params
})
return
httpRequest
.
get
(
'/api/resource/v1/backend/exam/search-all-exam'
,
{
params
})
}
}
// 获取实验的理论考试列表
// 获取实验的理论考试列表
export
function
getExamList
(
params
:
{
experiment_id
:
string
,
type
:
string
})
{
export
function
getExamList
(
params
:
{
experiment_id
:
string
;
type
:
string
})
{
return
httpRequest
.
get
(
'/api/resource/v1/backend/experiment/exam-list'
,
{
params
})
return
httpRequest
.
get
(
'/api/resource/v1/backend/experiment/exam-list'
,
{
params
})
}
}
// 更新实验的理论考试
// 更新实验的理论考试
...
@@ -185,4 +217,4 @@ export function deleteExperiment(data: { experiment_id: string }) {
...
@@ -185,4 +217,4 @@ export function deleteExperiment(data: { experiment_id: string }) {
// 获取实验成绩规则
// 获取实验成绩规则
export
function
getLiveCommodity
(
params
:
{
experiment_id
:
string
})
{
export
function
getLiveCommodity
(
params
:
{
experiment_id
:
string
})
{
return
httpRequest
.
get
(
'/api/lab/v1/experiment/live-commodity/all'
,
{
params
})
return
httpRequest
.
get
(
'/api/lab/v1/experiment/live-commodity/all'
,
{
params
})
}
}
\ No newline at end of file
src/modules/admin/lab/experiment/components/DMLFormDialog.vue
浏览文件 @
5dabc6d8
...
@@ -38,22 +38,22 @@ const experimentConfig: any = [
...
@@ -38,22 +38,22 @@ const experimentConfig: any = [
children
:
[
children
:
[
{
id
:
2
,
name
:
'连接管理'
,
is_checked
:
false
,
pid
:
1
,
children
:
[]
},
{
id
:
2
,
name
:
'连接管理'
,
is_checked
:
false
,
pid
:
1
,
children
:
[]
},
{
id
:
3
,
name
:
'用户属性管理'
,
is_checked
:
false
,
pid
:
1
,
children
:
[]
},
{
id
:
3
,
name
:
'用户属性管理'
,
is_checked
:
false
,
pid
:
1
,
children
:
[]
},
{
id
:
4
,
name
:
'事件属性管理'
,
is_checked
:
false
,
pid
:
1
,
children
:
[]
}
{
id
:
4
,
name
:
'事件属性管理'
,
is_checked
:
false
,
pid
:
1
,
children
:
[]
}
,
]
]
,
},
},
{
{
id
:
5
,
id
:
5
,
name
:
'营销策划'
,
name
:
'营销策划'
,
is_checked
:
false
,
is_checked
:
false
,
pid
:
0
,
pid
:
0
,
children
:
[]
children
:
[]
,
},
},
{
{
id
:
6
,
id
:
6
,
name
:
'用户画像'
,
name
:
'用户画像'
,
is_checked
:
false
,
is_checked
:
false
,
pid
:
0
,
pid
:
0
,
children
:
[]
children
:
[]
,
},
},
{
{
id
:
7
,
id
:
7
,
...
@@ -62,8 +62,9 @@ const experimentConfig: any = [
...
@@ -62,8 +62,9 @@ const experimentConfig: any = [
pid
:
0
,
pid
:
0
,
children
:
[
children
:
[
{
id
:
8
,
name
:
'标签管理'
,
is_checked
:
false
,
pid
:
7
,
children
:
[]
},
{
id
:
8
,
name
:
'标签管理'
,
is_checked
:
false
,
pid
:
7
,
children
:
[]
},
{
id
:
9
,
name
:
'群组管理'
,
is_checked
:
false
,
pid
:
7
,
children
:
[]
}
{
id
:
9
,
name
:
'群组管理'
,
is_checked
:
false
,
pid
:
7
,
children
:
[]
},
]
{
id
:
71
,
name
:
'运营策略管理'
,
is_checked
:
false
,
pid
:
7
,
children
:
[]
},
],
},
},
{
{
id
:
10
,
id
:
10
,
...
@@ -78,15 +79,15 @@ const experimentConfig: any = [
...
@@ -78,15 +79,15 @@ const experimentConfig: any = [
{
id
:
15
,
name
:
'H5资料管理'
,
is_checked
:
false
,
pid
:
10
,
children
:
[]
},
{
id
:
15
,
name
:
'H5资料管理'
,
is_checked
:
false
,
pid
:
10
,
children
:
[]
},
{
id
:
16
,
name
:
'二维码资料管理'
,
is_checked
:
false
,
pid
:
10
,
children
:
[]
},
{
id
:
16
,
name
:
'二维码资料管理'
,
is_checked
:
false
,
pid
:
10
,
children
:
[]
},
{
id
:
17
,
name
:
'语言资料管理'
,
is_checked
:
false
,
pid
:
10
,
children
:
[]
},
{
id
:
17
,
name
:
'语言资料管理'
,
is_checked
:
false
,
pid
:
10
,
children
:
[]
},
{
id
:
18
,
name
:
'小程序资料管理'
,
is_checked
:
false
,
pid
:
10
,
children
:
[]
}
{
id
:
18
,
name
:
'小程序资料管理'
,
is_checked
:
false
,
pid
:
10
,
children
:
[]
}
,
]
]
,
},
},
{
{
id
:
19
,
id
:
19
,
name
:
'自动化营销'
,
name
:
'自动化营销'
,
is_checked
:
false
,
is_checked
:
false
,
pid
:
0
,
pid
:
0
,
children
:
[]
children
:
[]
,
},
},
{
{
id
:
20
,
id
:
20
,
...
@@ -98,8 +99,9 @@ const experimentConfig: any = [
...
@@ -98,8 +99,9 @@ const experimentConfig: any = [
{
id
:
22
,
name
:
'商品属性管理'
,
is_checked
:
false
,
pid
:
20
,
children
:
[]
},
{
id
:
22
,
name
:
'商品属性管理'
,
is_checked
:
false
,
pid
:
20
,
children
:
[]
},
{
id
:
23
,
name
:
'商品管理'
,
is_checked
:
false
,
pid
:
20
,
children
:
[]
},
{
id
:
23
,
name
:
'商品管理'
,
is_checked
:
false
,
pid
:
20
,
children
:
[]
},
{
id
:
24
,
name
:
'直播练习'
,
is_checked
:
false
,
pid
:
20
,
children
:
[]
},
{
id
:
24
,
name
:
'直播练习'
,
is_checked
:
false
,
pid
:
20
,
children
:
[]
},
{
id
:
25
,
name
:
'直播话术管理'
,
is_checked
:
false
,
pid
:
20
,
children
:
[]
}
{
id
:
25
,
name
:
'直播话术管理'
,
is_checked
:
false
,
pid
:
20
,
children
:
[]
},
]
{
id
:
201
,
name
:
'订单管理'
,
is_checked
:
false
,
pid
:
20
,
children
:
[]
},
],
},
},
{
{
id
:
26
,
id
:
26
,
...
@@ -110,9 +112,9 @@ const experimentConfig: any = [
...
@@ -110,9 +112,9 @@ const experimentConfig: any = [
{
id
:
27
,
name
:
'用户分析'
,
is_checked
:
false
,
pid
:
26
,
children
:
[]
},
{
id
:
27
,
name
:
'用户分析'
,
is_checked
:
false
,
pid
:
26
,
children
:
[]
},
{
id
:
28
,
name
:
'标签群组分析'
,
is_checked
:
false
,
pid
:
26
,
children
:
[]
},
{
id
:
28
,
name
:
'标签群组分析'
,
is_checked
:
false
,
pid
:
26
,
children
:
[]
},
{
id
:
29
,
name
:
'事件分析'
,
is_checked
:
false
,
pid
:
26
,
children
:
[]
},
{
id
:
29
,
name
:
'事件分析'
,
is_checked
:
false
,
pid
:
26
,
children
:
[]
},
{
id
:
30
,
name
:
'营销分析'
,
is_checked
:
false
,
pid
:
26
,
children
:
[]
}
{
id
:
30
,
name
:
'营销分析'
,
is_checked
:
false
,
pid
:
26
,
children
:
[]
}
,
]
]
,
}
}
,
]
]
const
formRef
=
$ref
<
FormInstance
>
()
const
formRef
=
$ref
<
FormInstance
>
()
...
@@ -132,7 +134,7 @@ const form = reactive({
...
@@ -132,7 +134,7 @@ const form = reactive({
material_ids
:
[],
material_ids
:
[],
auth_config
:
experimentConfig
,
auth_config
:
experimentConfig
,
is_use_common_live_commodities
:
0
,
is_use_common_live_commodities
:
0
,
live_commodity_ids
:
[]
live_commodity_ids
:
[]
,
})
})
// 模板列表
// 模板列表
...
@@ -141,7 +143,7 @@ let templateList = $ref<{ id: string; name: string }[]>([])
...
@@ -141,7 +143,7 @@ let templateList = $ref<{ id: string; name: string }[]>([])
const
checked
=
ref
(
false
)
const
checked
=
ref
(
false
)
function
fetchInfo
()
{
function
fetchInfo
()
{
getTripConfig
({
experiment_id
:
props
.
data
.
id
}).
then
(
res
=>
{
getTripConfig
({
experiment_id
:
props
.
data
.
id
}).
then
(
(
res
)
=>
{
const
data
=
res
.
data
const
data
=
res
.
data
if
(
data
.
itinerary
?.
id
)
{
if
(
data
.
itinerary
?.
id
)
{
templateList
=
[
data
.
itinerary
]
templateList
=
[
data
.
itinerary
]
...
@@ -153,15 +155,46 @@ function fetchInfo() {
...
@@ -153,15 +155,46 @@ function fetchInfo() {
}
}
const
user_attr_config
=
{
const
user_attr_config
=
{
is_all
:
data
.
user_attr_config
.
is_all
,
is_all
:
data
.
user_attr_config
.
is_all
,
items
:
data
.
user_attr_config
.
items
.
map
((
item
:
any
)
=>
item
.
id
)
items
:
data
.
user_attr_config
.
items
.
map
((
item
:
any
)
=>
item
.
id
)
,
}
}
const
event_config
=
{
const
event_config
=
{
is_all
:
data
.
event_config
.
is_all
,
is_all
:
data
.
event_config
.
is_all
,
items
:
data
.
event_config
.
items
.
map
((
item
:
any
)
=>
item
.
id
)
items
:
data
.
event_config
.
items
.
map
((
item
:
any
)
=>
item
.
id
)
,
}
}
const
tag_ids
=
data
.
tags
.
map
((
item
:
any
)
=>
item
.
id
)
const
tag_ids
=
data
.
tags
.
map
((
item
:
any
)
=>
item
.
id
)
const
group_ids
=
data
.
groups
.
map
((
item
:
any
)
=>
item
.
id
)
const
group_ids
=
data
.
groups
.
map
((
item
:
any
)
=>
item
.
id
)
const
material_ids
=
data
.
marketing_materials
.
map
((
item
:
any
)
=>
item
.
id
)
const
material_ids
=
data
.
marketing_materials
.
map
((
item
:
any
)
=>
item
.
id
)
// 递归合并配置
interface
MenuItem
{
id
:
number
name
:
string
is_checked
:
boolean
pid
:
number
children
:
MenuItem
[]
}
const
mergeConfig
=
(
defaultItems
:
MenuItem
[],
backendItems
:
MenuItem
[]):
MenuItem
[]
=>
{
return
defaultItems
.
map
((
defaultItem
)
=>
{
const
backendItem
=
backendItems
.
find
((
item
:
MenuItem
)
=>
item
.
id
===
defaultItem
.
id
)
if
(
backendItem
)
{
return
{
...
defaultItem
,
is_checked
:
backendItem
.
is_checked
,
children
:
defaultItem
.
children
.
length
>
0
?
mergeConfig
(
defaultItem
.
children
,
backendItem
.
children
||
[])
:
[],
}
}
return
defaultItem
})
}
// Ensure auth_config structure is maintained
let
authConfig
=
experimentConfig
if
(
data
.
auth_config
&&
data
.
auth_config
.
length
>
0
)
{
authConfig
=
mergeConfig
(
experimentConfig
,
data
.
auth_config
)
}
Object
.
assign
(
form
,
{
Object
.
assign
(
form
,
{
itinerary_id
:
data
.
itinerary
.
id
,
itinerary_id
:
data
.
itinerary
.
id
,
connect_ids
,
connect_ids
,
...
@@ -174,18 +207,17 @@ function fetchInfo() {
...
@@ -174,18 +207,17 @@ function fetchInfo() {
tag_ids
,
tag_ids
,
group_ids
,
group_ids
,
material_ids
,
material_ids
,
auth_config
:
data
.
auth_config
&&
data
.
auth_config
.
length
>
0
?
data
.
auth_config
:
experiment
Config
,
auth_config
:
auth
Config
,
live_commodity_ids
:
data
?.
live_commodities
.
reduce
((
a
:
any
,
b
:
any
)
=>
{
live_commodity_ids
:
data
?.
live_commodities
.
reduce
((
a
:
any
,
b
:
any
)
=>
{
a
.
push
(
b
.
id
)
a
.
push
(
b
.
id
)
return
a
return
a
},
[]),
},
[]),
is_use_common_live_commodities
:
data
.
is_use_common_live_commodities
is_use_common_live_commodities
:
data
.
is_use_common_live_commodities
,
})
})
// checked
// checked
if
(
data
.
auth_config
.
length
)
{
if
(
data
.
auth_config
.
length
)
{
checked
.
value
=
data
.
auth_config
.
find
((
item
:
any
)
=>
item
.
is_checked
===
false
)
?
false
:
true
checked
.
value
=
data
.
auth_config
.
find
((
item
:
any
)
=>
item
.
is_checked
===
false
)
?
false
:
true
}
}
// form.auth_config = data.auth_config.length > 0 ? data.auth_config : experimentConfig
})
})
}
}
watchEffect
(()
=>
fetchInfo
())
watchEffect
(()
=>
fetchInfo
())
...
@@ -217,7 +249,7 @@ function handleSubmit() {
...
@@ -217,7 +249,7 @@ function handleSubmit() {
group_ids
:
JSON
.
stringify
(
form
.
group_ids
),
group_ids
:
JSON
.
stringify
(
form
.
group_ids
),
material_ids
:
JSON
.
stringify
(
form
.
material_ids
),
material_ids
:
JSON
.
stringify
(
form
.
material_ids
),
auth_config
:
JSON
.
stringify
(
form
.
auth_config
),
auth_config
:
JSON
.
stringify
(
form
.
auth_config
),
live_commodity_ids
:
JSON
.
stringify
(
form
.
live_commodity_ids
)
live_commodity_ids
:
JSON
.
stringify
(
form
.
live_commodity_ids
)
,
}
}
params
.
itinerary_id
=
params
.
itinerary_id
===
''
?
(
params
.
itinerary_id
=
'0'
)
:
params
.
itinerary_id
params
.
itinerary_id
=
params
.
itinerary_id
===
''
?
(
params
.
itinerary_id
=
'0'
)
:
params
.
itinerary_id
updateTripConfig
(
params
).
then
(()
=>
{
updateTripConfig
(
params
).
then
(()
=>
{
...
@@ -292,8 +324,7 @@ const handleSelectAll = () => {
...
@@ -292,8 +324,7 @@ const handleSelectAll = () => {
title=
"配置数字营销实验"
title=
"配置数字营销实验"
:close-on-click-modal=
"false"
:close-on-click-modal=
"false"
width=
"1000px"
width=
"1000px"
@
update:modelValue=
"value => $emit('update:modelValue', value)"
@
update:modelValue=
"(value) => $emit('update:modelValue', value)"
>
>
<el-form
ref=
"formRef"
:model=
"form"
label-suffix=
":"
>
<el-form
ref=
"formRef"
:model=
"form"
label-suffix=
":"
>
<el-row
justify=
"space-between"
>
<el-row
justify=
"space-between"
>
<el-form-item
label=
"实验名称"
>
{{
data
.
name
}}
</el-form-item>
<el-form-item
label=
"实验名称"
>
{{
data
.
name
}}
</el-form-item>
...
@@ -314,8 +345,7 @@ const handleSelectAll = () => {
...
@@ -314,8 +345,7 @@ const handleSelectAll = () => {
@
change=
"handleItemCheck(item)"
@
change=
"handleItemCheck(item)"
v-model=
"cItem.is_checked"
v-model=
"cItem.is_checked"
:label=
"cItem.name"
:label=
"cItem.name"
size=
"large"
size=
"large"
/>
/>
</
template
>
</
template
>
</div>
</div>
<el-divider
/>
<el-divider
/>
...
@@ -343,8 +373,7 @@ const handleSelectAll = () => {
...
@@ -343,8 +373,7 @@ const handleSelectAll = () => {
:label=
"item.name"
:label=
"item.name"
:value=
"item.id"
:value=
"item.id"
:key=
"item.id"
:key=
"item.id"
disabled
disabled
></el-option>
></el-option>
</el-select>
</el-select>
</el-form-item>
</el-form-item>
</el-tab-pane>
</el-tab-pane>
...
@@ -358,8 +387,7 @@ const handleSelectAll = () => {
...
@@ -358,8 +387,7 @@ const handleSelectAll = () => {
v-model=
"form.user_attr_config.items"
v-model=
"form.user_attr_config.items"
multiple
multiple
style=
"margin-left: 40px"
style=
"margin-left: 40px"
v-if=
"!form.user_attr_config.is_all"
v-if=
"!form.user_attr_config.is_all"
>
>
<el-option
v-for=
"item in userAttrList"
:label=
"item.name"
:value=
"item.id"
:key=
"item.id"
></el-option>
<el-option
v-for=
"item in userAttrList"
:label=
"item.name"
:value=
"item.id"
:key=
"item.id"
></el-option>
</el-select>
</el-select>
</el-form-item>
</el-form-item>
...
@@ -372,8 +400,7 @@ const handleSelectAll = () => {
...
@@ -372,8 +400,7 @@ const handleSelectAll = () => {
v-model=
"form.event_config.items"
v-model=
"form.event_config.items"
multiple
multiple
style=
"margin-left: 40px"
style=
"margin-left: 40px"
v-if=
"!form.event_config.is_all"
v-if=
"!form.event_config.is_all"
>
>
<el-option
v-for=
"item in metaEventList"
:label=
"item.name"
:value=
"item.id"
:key=
"item.id"
></el-option>
<el-option
v-for=
"item in metaEventList"
:label=
"item.name"
:value=
"item.id"
:key=
"item.id"
></el-option>
</el-select>
</el-select>
</el-form-item>
</el-form-item>
...
...
src/modules/admin/lab/experiment/components/FormDialog.vue
浏览文件 @
5dabc6d8
...
@@ -44,13 +44,14 @@ const form = reactive<ExperimentCreateItem>({
...
@@ -44,13 +44,14 @@ const form = reactive<ExperimentCreateItem>({
requirements
:
''
,
requirements
:
''
,
content
:
''
,
content
:
''
,
procedure
:
''
,
procedure
:
''
,
exam_status
:
'0'
exam_status
:
'0'
,
can_repeat_commit
:
'0'
,
})
})
watchEffect
(()
=>
{
watchEffect
(()
=>
{
if
(
!
props
.
data
)
return
if
(
!
props
.
data
)
return
const
score
=
parseFloat
(
props
.
data
.
score
)
const
score
=
parseFloat
(
props
.
data
.
score
)
const
length
=
parseFloat
(
props
.
data
.
length
)
const
length
=
parseFloat
(
props
.
data
.
length
)
const
teachers_ids
=
props
.
data
.
teacher
.
map
(
item
=>
item
.
id
)
const
teachers_ids
=
props
.
data
.
teacher
.
map
(
(
item
)
=>
item
.
id
)
Object
.
assign
(
form
,
props
.
data
,
{
score
,
length
,
teachers_ids
})
Object
.
assign
(
form
,
props
.
data
,
{
score
,
length
,
teachers_ids
})
})
})
...
@@ -72,7 +73,7 @@ const rules = ref<FormRules>({
...
@@ -72,7 +73,7 @@ const rules = ref<FormRules>({
length
:
[{
required
:
true
,
message
:
'请输入实验学时'
}],
length
:
[{
required
:
true
,
message
:
'请输入实验学时'
}],
type
:
[{
required
:
true
,
message
:
'请选择实验类型'
}],
type
:
[{
required
:
true
,
message
:
'请选择实验类型'
}],
teachers_ids
:
[{
type
:
'array'
,
required
:
true
,
message
:
'请选择指导教师'
,
trigger
:
'change'
}],
teachers_ids
:
[{
type
:
'array'
,
required
:
true
,
message
:
'请选择指导教师'
,
trigger
:
'change'
}],
score
:
[{
required
:
true
,
message
:
'请输入实验总成绩'
}]
score
:
[{
required
:
true
,
message
:
'请输入实验总成绩'
}]
,
})
})
const
isUpdate
=
$computed
(()
=>
{
const
isUpdate
=
$computed
(()
=>
{
return
!!
form
.
id
return
!!
form
.
id
...
@@ -90,7 +91,7 @@ function handleSubmit() {
...
@@ -90,7 +91,7 @@ function handleSubmit() {
formRef
?.
validate
().
then
(()
=>
{
formRef
?.
validate
().
then
(()
=>
{
const
params
=
{
const
params
=
{
...
form
,
...
form
,
teachers_id
:
form
.
teachers_ids
?.
join
(
','
)
||
''
teachers_id
:
form
.
teachers_ids
?.
join
(
','
)
||
''
,
}
}
isUpdate
?
handleUpdate
(
params
)
:
handleCreate
(
params
)
isUpdate
?
handleUpdate
(
params
)
:
handleCreate
(
params
)
})
})
...
@@ -118,8 +119,7 @@ function handleUpdate(params: ExperimentCreateItem) {
...
@@ -118,8 +119,7 @@ function handleUpdate(params: ExperimentCreateItem) {
:title=
"title"
:title=
"title"
:close-on-click-modal=
"false"
:close-on-click-modal=
"false"
width=
"600px"
width=
"600px"
@
update:modelValue=
"value => $emit('update:modelValue', value)"
@
update:modelValue=
"(value) => $emit('update:modelValue', value)"
>
>
<el-form
ref=
"formRef"
:model=
"form"
:rules=
"rules"
label-width=
"145px"
>
<el-form
ref=
"formRef"
:model=
"form"
:rules=
"rules"
label-width=
"145px"
>
<el-form-item
label=
"实验所属部门/学校"
prop=
"organ_id"
>
<el-form-item
label=
"实验所属部门/学校"
prop=
"organ_id"
>
<el-select
v-model=
"form.organ_id"
style=
"width: 100%"
:disabled=
"isUpdate"
@
change=
"handleOrgChange"
>
<el-select
v-model=
"form.organ_id"
style=
"width: 100%"
:disabled=
"isUpdate"
@
change=
"handleOrgChange"
>
...
@@ -164,8 +164,7 @@ function handleUpdate(params: ExperimentCreateItem) {
...
@@ -164,8 +164,7 @@ function handleUpdate(params: ExperimentCreateItem) {
type="textarea"
type="textarea"
maxlength="200"
maxlength="200"
show-word-limit
show-word-limit
placeholder="请输入实验目的"
placeholder="请输入实验目的" />
/>
</el-form-item>
</el-form-item>
<el-form-item
label=
"实验要求"
prop=
"requirements"
>
<el-form-item
label=
"实验要求"
prop=
"requirements"
>
<el-input
<el-input
...
@@ -174,8 +173,7 @@ function handleUpdate(params: ExperimentCreateItem) {
...
@@ -174,8 +173,7 @@ function handleUpdate(params: ExperimentCreateItem) {
type="textarea"
type="textarea"
maxlength="200"
maxlength="200"
show-word-limit
show-word-limit
placeholder="请输入实验要求"
placeholder="请输入实验要求" />
/>
</el-form-item>
</el-form-item>
<el-form-item
label=
"实验内容及原理"
prop=
"content"
>
<el-form-item
label=
"实验内容及原理"
prop=
"content"
>
<el-input
<el-input
...
@@ -184,8 +182,7 @@ function handleUpdate(params: ExperimentCreateItem) {
...
@@ -184,8 +182,7 @@ function handleUpdate(params: ExperimentCreateItem) {
type="textarea"
type="textarea"
maxlength="200"
maxlength="200"
show-word-limit
show-word-limit
placeholder="请输入实验内容及原理"
placeholder="请输入实验内容及原理" />
/>
</el-form-item>
</el-form-item>
<el-form-item
label=
"实验步骤及过程"
prop=
"procedure"
>
<el-form-item
label=
"实验步骤及过程"
prop=
"procedure"
>
<el-input
<el-input
...
@@ -194,14 +191,19 @@ function handleUpdate(params: ExperimentCreateItem) {
...
@@ -194,14 +191,19 @@ function handleUpdate(params: ExperimentCreateItem) {
type="textarea"
type="textarea"
maxlength="200"
maxlength="200"
show-word-limit
show-word-limit
placeholder="请输入实验步骤及过程"
placeholder="请输入实验步骤及过程" />
/>
</el-form-item>
</el-form-item>
<el-form-item
label=
"有效状态"
prop=
"status"
>
<el-form-item
label=
"有效状态"
prop=
"status"
>
<el-radio-group
v-model=
"form.status"
>
<el-radio-group
v-model=
"form.status"
>
<el-radio
v-for=
"item in status"
:key=
"item.id"
:label=
"item.value"
>
{{
item
.
label
}}
</el-radio>
<el-radio
v-for=
"item in status"
:key=
"item.id"
:label=
"item.value"
>
{{
item
.
label
}}
</el-radio>
</el-radio-group>
</el-radio-group>
</el-form-item>
</el-form-item>
<el-form-item
label=
"是否支持重复提交"
prop=
"can_repeat_commit"
>
<el-radio-group
v-model=
"form.can_repeat_commit"
>
<el-radio
label=
"0"
>
否
</el-radio>
<el-radio
label=
"1"
>
是
</el-radio>
</el-radio-group>
</el-form-item>
<el-row
justify=
"center"
>
<el-row
justify=
"center"
>
<el-button
type=
"primary"
round
auto-insert-space
@
click=
"handleSubmit"
>
保存
</el-button>
<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-button
round
auto-insert-space
@
click=
"$emit('update:modelValue', false)"
>
取消
</el-button>
...
...
src/modules/admin/lab/experiment/components/GradeRulesDialog.vue
浏览文件 @
5dabc6d8
...
@@ -144,7 +144,7 @@ function currentRuleNames(value: number) {
...
@@ -144,7 +144,7 @@ function currentRuleNames(value: number) {
})
})
if
(
props
.
data
.
type
===
'4'
)
{
if
(
props
.
data
.
type
===
'4'
)
{
// 数字营销实验
// 数字营销实验
return
tempList
.
filter
((
item
)
=>
[
1
,
5
,
6
,
7
,
8
,
9
,
1
0
].
includes
(
item
.
value
as
number
))
return
tempList
.
filter
((
item
)
=>
[
1
,
5
,
6
,
7
,
8
,
9
,
1
1
,
12
].
includes
(
item
.
value
as
number
))
}
else
{
}
else
{
return
tempList
.
filter
((
item
:
any
)
=>
item
.
value
<=
5
)
return
tempList
.
filter
((
item
:
any
)
=>
item
.
value
<=
5
)
}
}
...
@@ -181,10 +181,12 @@ function rowScore(percent = 0) {
...
@@ -181,10 +181,12 @@ function rowScore(percent = 0) {
}
}
// 编辑题
// 编辑题
const
handleEdit
=
function
(
type
:
number
)
{
const
handleEdit
=
function
(
row
:
any
)
{
handleSubmit
(
function
()
{
handleSubmit
(
function
()
{
window
.
open
(
window
.
open
(
`/admin/lab/experiment/questions?id=
${
props
.
data
.
id
}
&type=
${
type
}
&name=
${
props
.
data
.
name
}
&type_name=
${
props
.
data
.
type_name
}
&score=
${
props
.
data
.
score
}
`
`/admin/lab/experiment/questions?id=
${
props
.
data
.
id
}
&type=
${
row
.
type
}
&name=
${
props
.
data
.
name
}
&type_name=
${
props
.
data
.
type_name
}
&score=
${
props
.
data
.
score
}
&percent=
${
row
.
percent
}
&row_score=
${
rowScore
(
row
.
percent
)}
`
)
)
})
})
}
}
...
@@ -283,7 +285,7 @@ onMounted(() => {
...
@@ -283,7 +285,7 @@ onMounted(() => {
<el-divider></el-divider>
<el-divider></el-divider>
<el-form-item>
<el-form-item>
<el-row
justify=
"space-between"
style=
"width: 100%"
>
<el-row
justify=
"space-between"
style=
"width: 100%"
>
<p>
理论
考试
:
</p>
<p>
理论
成绩规则
:
</p>
<el-button
type=
"primary"
:icon=
"Plus"
@
click=
"handleAddExamRule"
:disabled=
"form.exam_rules.length >= 1"
>
<el-button
type=
"primary"
:icon=
"Plus"
@
click=
"handleAddExamRule"
:disabled=
"form.exam_rules.length >= 1"
>
</el-button>
</el-button>
</el-row>
</el-row>
...
@@ -309,7 +311,7 @@ onMounted(() => {
...
@@ -309,7 +311,7 @@ onMounted(() => {
</
template
>
</
template
>
</el-table-column>
</el-table-column>
<el-table-column
width=
"90"
>
<el-table-column
width=
"90"
>
<
template
#
default=
"{ row }"
>
满分:
{{
100
||
rowScore
(
row
.
percent
)
}}
</
template
>
<
template
#
default=
"{ row }"
>
满分:
{{
rowScore
(
row
.
percent
)
}}
</
template
>
</el-table-column>
</el-table-column>
<el-table-column
align=
"right"
>
<el-table-column
align=
"right"
>
<
template
#
default=
"{ $index, row }"
>
<
template
#
default=
"{ $index, row }"
>
...
@@ -327,19 +329,14 @@ onMounted(() => {
...
@@ -327,19 +329,14 @@ onMounted(() => {
</el-form-item>
</el-form-item>
<el-form-item>
<el-form-item>
<el-row
justify=
"space-between"
style=
"width: 100%"
>
<el-row
justify=
"space-between"
style=
"width: 100%"
>
<p>
实操
考试
:
</p>
<p>
实操
成绩规则
:
</p>
<el-button
type=
"primary"
:icon=
"Plus"
@
click=
"handleAdd"
></el-button>
<el-button
type=
"primary"
:icon=
"Plus"
@
click=
"handleAdd"
></el-button>
</el-row>
</el-row>
<el-table
:data=
"form.rule_list"
row-key=
"id"
>
<el-table
:data=
"form.rule_list"
row-key=
"id"
>
<el-table-column
prop=
"name"
width=
"170"
>
<el-table-column
prop=
"name"
width=
"170"
>
<
template
#
default=
"{ row }"
>
<
template
#
default=
"{ row }"
>
<el-input
v-model=
"row.name"
:maxlength=
"20"
style=
"width: 100%"
v-if=
"row.type === 5"
/>
<el-input
v-model=
"row.name"
:maxlength=
"20"
style=
"width: 100%"
v-if=
"row.type === 5"
/>
<el-select
<el-select
v-model=
"row.type"
style=
"width: 100%"
@
change=
"handleTypeChange(row)"
v-else
>
v-model=
"row.type"
:disabled=
"row.type === 1"
style=
"width: 100%"
@
change=
"handleTypeChange(row)"
v-else
>
<el-option
v-for=
"item in currentRuleNames(row.type)"
:key=
"item.value"
v-bind=
"item"
></el-option>
<el-option
v-for=
"item in currentRuleNames(row.type)"
:key=
"item.value"
v-bind=
"item"
></el-option>
</el-select>
</el-select>
</
template
>
</
template
>
...
@@ -354,24 +351,23 @@ onMounted(() => {
...
@@ -354,24 +351,23 @@ onMounted(() => {
<el-radio-group
v-model=
"row.rule_mode"
size=
"small"
>
<el-radio-group
v-model=
"row.rule_mode"
size=
"small"
>
<el-radio
:label=
"1"
>
人工评分
</el-radio>
<el-radio
:label=
"1"
>
人工评分
</el-radio>
<!--
<el-radio
:label=
"2"
v-if=
"[2, 3].includes(row.type)"
>
自动评分
</el-radio>
-->
<!--
<el-radio
:label=
"2"
v-if=
"[2, 3].includes(row.type)"
>
自动评分
</el-radio>
-->
<el-radio
:label=
"2"
:disabled=
"row.type === 1 || row.type === 8"
>
自动评分
</el-radio>
<el-radio
:label=
"2"
:disabled=
"row.type === 1 || row.type ===
5 || row.type ===
8"
>
自动评分
</el-radio>
</el-radio-group>
</el-radio-group>
</
template
>
</
template
>
</el-table-column>
</el-table-column>
<el-table-column
width=
"90"
>
<el-table-column
width=
"90"
>
<
template
#
default=
"{ row }"
>
满分:
{{
100
||
rowScore
(
row
.
percent
)
}}
</
template
>
<
template
#
default=
"{ row }"
>
满分:
{{
rowScore
(
row
.
percent
)
}}
</
template
>
</el-table-column>
</el-table-column>
<el-table-column
align=
"right"
>
<el-table-column
align=
"right"
>
<
template
#
default=
"{ $index, row }"
>
<
template
#
default=
"{ $index, row }"
>
<div
class=
"btn-box"
>
<div
class=
"btn-box"
>
<!-- || row.type === 8 -->
<el-button
<el-button
:disabled=
"row.type === 1"
:disabled=
"row.type === 1"
style=
"padding: 0"
style=
"padding: 0"
text
text
type=
"primary"
type=
"primary"
@
click=
"handleEdit(row
.type
)"
@
click=
"handleEdit(row)"
v-if=
"row.type !== 1"
v-if=
"row.type !== 1
&& row.type !== 5
"
>
编辑
</el-button
>
编辑
</el-button
>
>
<el-button
style=
"padding: 0"
text
type=
"primary"
@
click=
"handleRemove($index)"
>
删除
</el-button>
<el-button
style=
"padding: 0"
text
type=
"primary"
@
click=
"handleRemove($index)"
>
删除
</el-button>
...
...
src/modules/admin/lab/experiment/components/Questions/EventQuestion.vue
0 → 100644
浏览文件 @
5dabc6d8
<
script
setup
lang=
"ts"
>
import
type
{
FormInstance
}
from
'element-plus'
import
{
Plus
,
CircleCloseFilled
}
from
'@element-plus/icons-vue'
import
{
useFileDialog
}
from
'@vueuse/core'
import
{
upload
}
from
'@/utils/upload'
import
{
getExcelTotalLine
,
checkAutoGenerateData
}
from
'../../api'
import
{
useAppConfig
}
from
'@/composables/useAppConfig'
import
{
useEvent
}
from
'../../composables/useQuestion'
const
appConfig
=
useAppConfig
()
defineEmits
([
'remove'
])
const
route
=
useRoute
()
const
modelValue
:
any
=
defineModel
()
const
formRef
=
ref
<
FormInstance
>
()
const
form
=
reactive
({
questions
:
modelValue
,
})
const
{
eventList
}
=
useEvent
(
route
.
query
.
id
as
string
)
const
{
files
,
open
,
reset
}
=
useFileDialog
({
accept
:
'.csv, .xls, .xlsx, text/csv, application/csv,text/comma-separated-values, application/csv, application/excel,application/vnd.msexcel, text/anytext, application/vnd. ms-excel,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
,
multiple
:
false
,
})
let
currentItem
:
any
=
null
function
handleUpload
(
item
:
any
)
{
currentItem
=
item
open
()
}
watchEffect
(
async
()
=>
{
if
(
!
files
.
value
?.
length
)
return
const
[
file
]
=
files
.
value
const
url
=
await
upload
(
file
)
const
res
=
await
getExcelTotalLine
({
file
})
const
total
=
res
.
data
.
row_count
||
0
if
(
currentItem
)
{
currentItem
.
answer
.
data
.
file
=
{
name
:
file
.
name
,
size
:
file
.
size
,
type
:
file
.
type
,
is_download
:
false
,
total
,
url
,
}
}
reset
()
})
const
href
=
computed
(()
=>
{
const
dmlURL
=
appConfig
.
dmlURL
||
import
.
meta
.
env
.
VITE_DML_URL
return
`
${
dmlURL
}
/connect?experiment_id=
${
route
.
query
.
id
}
`
})
async
function
handleEventChange
(
item
:
any
)
{
if
(
item
.
answer
.
data
.
type
!=
2
)
return
const
res
=
await
checkAutoGenerateData
({
experiment_id
:
route
.
query
.
id
as
string
,
event_id
:
item
.
answer
.
choose
})
item
.
answer
.
data
.
exists
=
res
.
data
.
exists
}
function
handleDataTypeChange
(
item
:
any
)
{
item
.
answer
.
rule
.
type
=
item
.
answer
.
data
.
type
==
2
?
'3'
:
'1'
}
defineExpose
({
formRef
})
</
script
>
<
template
>
<el-form
ref=
"formRef"
label-width=
"120px"
:model=
"form"
scroll-to-error
>
<el-card
shadow=
"hover"
:id=
"`site-card$
{index}`" class="box-card" v-for="(item, index) in modelValue" :key="item">
<el-icon
@
click=
"$emit('remove', index)"
v-if=
"modelValue.length > 1"
class=
"close"
size=
"28"
color=
"#c01c40"
><CircleCloseFilled
/></el-icon>
<div
class=
"head-box"
>
<el-form-item
label=
"本题分值"
class=
"head-r"
:prop=
"`questions.$
{index}.score`"
:rules="{ required: true, message: '请输入' }">
<el-input-number
v-model=
"item.score"
:min=
"0"
:max=
"100"
controls-position=
"right"
/>
</el-form-item>
</div>
<el-form-item
label=
"题目标题"
:prop=
"`questions.$
{index}.title`" :rules="{ required: true, message: '请输入' }">
<el-input
v-model=
"item.title"
placeholder=
"请输入"
/>
</el-form-item>
<el-form-item
label=
"题干内容"
>
<el-input
v-model=
"item.content"
:rows=
"5"
type=
"textarea"
placeholder=
"请输入"
/>
</el-form-item>
<el-form-item
label=
"选择事件"
:prop=
"`questions.$
{index}.answer.choose`"
:rules="{ required: true, message: '请输入' }">
<el-select
v-model=
"item.answer.choose"
@
change=
"handleEventChange(item)"
>
<el-option
v-for=
"item in eventList"
:key=
"item.id"
:label=
"item.name"
:value=
"item.id"
/>
</el-select>
</el-form-item>
<el-form-item
label=
"事件数据集"
>
<div>
<el-radio-group
v-model=
"item.answer.data.type"
@
change=
"handleDataTypeChange(item)"
>
<el-radio
label=
"1"
>
指定文件
</el-radio>
<el-radio
label=
"2"
>
自动生成
</el-radio>
</el-radio-group>
<div
class=
"form-item-box"
>
<template
v-if=
"item.answer.data.type == 1"
>
<el-button
:icon=
"Plus"
size=
"large"
@
click=
"handleUpload(item)"
></el-button>
<template
v-if=
"item.answer.data.file.url"
>
<div
class=
"file-info"
>
<p>
{{
item
.
answer
.
data
.
file
.
name
}}
</p>
<p>
总数据量:
{{
item
.
answer
.
data
.
file
.
total
}}
条
</p>
</div>
<el-button
type=
"primary"
plain
@
click=
"item.answer.data.file =
{}">删除数据集
</el-button>
</
template
>
</template>
<
template
v-else
>
<a
:href=
"href"
target=
"_blank"
>
<el-button
type=
"primary"
>
查看自动生成规则
</el-button>
</a>
<el-alert
title=
"该事件尚未维护自动生成数据规则,请维护!"
type=
"info"
style=
"margin-left: 40px"
v-if=
"!item.answer.data.exists"
/>
</
template
>
</div>
</div>
</el-form-item>
<el-form-item
label=
"评分规则"
>
<el-radio-group
v-model=
"item.answer.rule.type"
>
<
template
v-if=
"item.answer.data.type == 1"
>
<el-radio
label=
"1"
>
上传成功+数据量匹配
</el-radio>
<el-radio
label=
"2"
>
仅上传成功
</el-radio>
</
template
>
<el-radio
label=
"3"
>
仅数据量匹配
</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item
label=
"答案解析"
v-if=
"false"
>
<el-input
v-model=
"item.answer_analysis"
:rows=
"5"
type=
"textarea"
placeholder=
"请输入"
/>
</el-form-item>
</el-card>
</el-form>
</template>
<
style
lang=
"scss"
scoped
>
.close
{
position
:
absolute
;
top
:
-10px
;
right
:
-10px
;
cursor
:
pointer
;
}
.box-card
{
padding-top
:
20px
;
position
:
relative
;
margin-bottom
:
30px
;
overflow
:
visible
;
}
.head-box
{
display
:
flex
;
margin-bottom
:
30px
;
.head-r
{
margin-left
:
auto
;
}
}
.form-item-box
{
display
:
flex
;
align-items
:
center
;
p
{
font-size
:
13px
;
margin
:
0
20px
0
10px
;
line-height
:
1
.4
;
}
}
</
style
>
src/modules/admin/lab/experiment/components/Questions/GroupQuestion.vue
浏览文件 @
5dabc6d8
<
script
setup
lang=
"ts"
>
<
script
setup
lang=
"ts"
>
import
type
{
FormInstance
}
from
'element-plus'
import
type
{
FormInstance
}
from
'element-plus'
import
{
CircleCloseFilled
}
from
'@element-plus/icons-vue'
import
{
CircleCloseFilled
}
from
'@element-plus/icons-vue'
import
{
getQuestionGroup
}
from
'../../api'
import
{
useGroup
}
from
'../../composables/useQuestion'
defineEmits
([
'remove'
])
const
route
=
useRoute
()
const
route
=
useRoute
()
const
modelValue
:
any
=
defineModel
()
const
modelValue
:
any
=
defineModel
()
const
ruleFormRef
=
ref
<
FormInstance
>
()
const
formRef
=
ref
<
FormInstance
>
()
const
form
=
reactive
({
questions
:
modelValue
,
})
const
{
groupList
}
=
useGroup
(
route
.
query
.
id
as
string
)
const
removeQuestion
=
(
index
:
number
)
=>
{
function
getGroupCount
(
id
:
string
)
{
modelValue
.
value
.
splice
(
index
,
1
)
return
groupList
.
value
.
find
((
item
)
=>
item
.
id
===
id
)?.
count
||
'未计算'
}
}
let
options
=
$ref
<
{
id
:
string
;
name
:
string
}[]
>
()
defineExpose
({
formRef
})
onMounted
(()
=>
{
const
dom
:
any
=
document
.
querySelectorAll
(
'.app-main'
)[
0
]
dom
.
style
.
overflow
=
'visible'
getQuestionGroup
({
experiment_id
:
route
.
query
.
id
as
string
}).
then
(
res
=>
{
options
=
res
.
data
.
items
})
})
</
script
>
</
script
>
<
template
>
<
template
>
<el-card
:id=
"`site-card$
{index}`" class="box-card" v-for="(item, index) in modelValue" :key="item">
<el-form
ref=
"formRef"
label-width=
"120px"
:model=
"form"
scroll-to-error
>
<el-icon
@
click=
"removeQuestion(index)"
v-if=
"modelValue.length > 1"
class=
"close"
size=
"28"
color=
"#c01c40"
<el-card
shadow=
"hover"
:id=
"`site-card$
{index}`" class="box-card" v-for="(item, index) in modelValue" :key="item">
><CircleCloseFilled
<el-icon
@
click=
"$emit('remove', index)"
v-if=
"modelValue.length > 1"
class=
"close"
size=
"28"
color=
"#c01c40"
>
/></el-icon>
<CircleCloseFilled
/>
<div
class=
"head-box"
>
</el-icon>
<el-tabs
v-model=
"item.type"
type=
"card"
class=
"demo-tabs"
>
<div
class=
"head-box"
>
<el-tab-pane
label=
"静态群组"
:name=
"301"
></el-tab-pane>
<el-tabs
v-model=
"item.type"
type=
"card"
>
<el-tab-pane
label=
"动态群组"
:name=
"302"
></el-tab-pane>
<el-tab-pane
label=
"静态群组"
:name=
"301"
></el-tab-pane>
</el-tabs>
<el-tab-pane
label=
"动态群组"
:name=
"302"
></el-tab-pane>
<el-form-item
label=
"本题分值"
class=
"head-r"
>
</el-tabs>
<el-input-number
v-model=
"item.score"
:min=
"1"
:max=
"100"
controls-position=
"right"
/>
<el-form-item
</el-form-item>
label=
"本题分值"
</div>
class=
"head-r"
<el-form
ref=
"ruleFormRef"
label-width=
"120px"
class=
"demo-ruleForm"
status-icon
>
:prop=
"`questions.$
{index}.score`"
<el-form-item
label=
"题目标题"
:required=
"true"
>
:rules="{ required: true, message: '请输入' }">
<el-input-number
v-model=
"item.score"
:min=
"0"
:max=
"100"
controls-position=
"right"
/>
</el-form-item>
</div>
<el-form-item
label=
"题目标题"
:prop=
"`questions.$
{index}.title`" :rules="{ required: true, message: '请输入' }">
<el-input
v-model=
"item.title"
placeholder=
"请输入"
/>
<el-input
v-model=
"item.title"
placeholder=
"请输入"
/>
</el-form-item>
</el-form-item>
<el-form-item
label=
"题干内容"
>
<el-form-item
label=
"题干内容"
>
<el-input
v-model=
"item.content"
:rows=
"5"
type=
"textarea"
placeholder=
"请输入"
/>
<el-input
v-model=
"item.content"
:rows=
"5"
type=
"textarea"
placeholder=
"请输入"
/>
</el-form-item>
</el-form-item>
<el-form-item
label=
"正确答案"
:required=
"true"
>
<el-form-item
label=
"评分规则"
>
<span
v-if=
"item.type === 301"
>
创建静态群组成功
</span>
<el-radio-group
v-model=
"item.answer.rule.type"
>
<el-select
v-else
v-model=
"item.answer"
class=
"m-2"
placeholder=
"请选择"
size=
"large"
>
<el-radio
label=
"1"
>
群组规则+计算结果
</el-radio>
<el-option
v-for=
"item in options"
:key=
"item.id"
:label=
"item.name"
:value=
"item.id"
/>
<el-radio
label=
"2"
>
仅群组规则
</el-radio>
<el-radio
label=
"3"
>
仅计算结果
</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item
label=
"正确群组规则"
:prop=
"`questions.$
{index}.answer.choose`"
:rules="{ required: true, message: '请输入' }">
<el-select
v-model=
"item.answer.choose"
placeholder=
"请选择"
>
<el-option
v-for=
"item in groupList"
:key=
"item.id"
:label=
"item.name"
:value=
"item.id"
/>
</el-select>
</el-select>
<p
style=
"margin-left: 10px"
>
满足该群组的用户数量:
{{
getGroupCount
(
item
.
answer
.
choose
)
}}
</p>
</el-form-item>
</el-form-item>
<el-form-item
label=
"答案解析"
>
<el-form-item
label=
"答案解析"
v-if=
"false"
>
<el-input
v-model=
"item.answer_analysis"
:rows=
"5"
type=
"textarea"
placeholder=
"请输入"
/>
<el-input
v-model=
"item.answer_analysis"
:rows=
"5"
type=
"textarea"
placeholder=
"请输入"
/>
</el-form-item>
</el-form-item>
</el-
form
>
</el-
card
>
</el-
card
>
</el-
form
>
</
template
>
</
template
>
<
style
lang=
"scss"
scoped
>
<
style
lang=
"scss"
scoped
>
.close
{
.close
{
...
...
src/modules/admin/lab/experiment/components/Questions/JourneyQuestion.vue
浏览文件 @
5dabc6d8
...
@@ -2,39 +2,41 @@
...
@@ -2,39 +2,41 @@
import
type
{
FormInstance
}
from
'element-plus'
import
type
{
FormInstance
}
from
'element-plus'
import
{
CircleCloseFilled
}
from
'@element-plus/icons-vue'
import
{
CircleCloseFilled
}
from
'@element-plus/icons-vue'
const
modelValue
:
any
=
defineModel
()
defineEmits
([
'remove'
])
const
ruleFormRef
=
ref
<
FormInstance
>
()
const
removeQuestion
=
(
index
:
number
)
=>
{
const
modelValue
:
any
=
defineModel
()
modelValue
.
value
.
splice
(
index
,
1
)
}
onMounted
(()
=>
{
const
formRef
=
ref
<
FormInstance
>
()
const
dom
:
any
=
document
.
querySelectorAll
(
'.app-main'
)[
0
]
const
form
=
reactive
({
dom
.
style
.
overflow
=
'visible'
questions
:
modelValue
,
})
})
defineExpose
({
formRef
})
</
script
>
</
script
>
<
template
>
<
template
>
<el-card
:id=
"`site-card$
{index}`" class="box-card" v-for="(item, index) in modelValue" :key="item">
<el-form
ref=
"formRef"
label-width=
"120px"
:model=
"form"
scroll-to-error
>
<el-icon
@
click=
"removeQuestion(index)"
v-if=
"modelValue.length > 1"
class=
"close"
size=
"28"
color=
"#c01c40"
<el-card
:id=
"`site-card$
{index}`" class="box-card" v-for="(item, index) in modelValue" :key="item">
><CircleCloseFilled
<el-icon
@
click=
"$emit('remove', index)"
v-if=
"modelValue.length > 1"
class=
"close"
size=
"28"
color=
"#c01c40"
>
/></el-icon>
<CircleCloseFilled
/>
<div
class=
"head-box"
>
</el-icon>
<el-form-item
label=
"本题分值"
class=
"head-r"
>
<div
class=
"head-box"
>
<el-input-number
v-model=
"item.score"
:min=
"1"
:max=
"100"
controls-position=
"right"
/>
<el-form-item
</el-form-item>
label=
"本题分值"
</div>
class=
"head-r"
<el-form
ref=
"ruleFormRef"
label-width=
"120px"
class=
"demo-ruleForm"
status-icon
>
:prop=
"`questions.$
{index}.score`"
<el-form-item
label=
"题目标题"
:required=
"true"
>
:rules="{ required: true, message: '请输入' }">
<el-input-number
v-model=
"item.score"
:min=
"1"
:max=
"100"
controls-position=
"right"
/>
</el-form-item>
</div>
<el-form-item
label=
"题目标题"
:prop=
"`questions.$
{index}.title`" :rules="{ required: true, message: '请输入' }">
<el-input
v-model=
"item.title"
placeholder=
"请输入"
/>
<el-input
v-model=
"item.title"
placeholder=
"请输入"
/>
</el-form-item>
</el-form-item>
<el-form-item
label=
"题干内容"
>
<el-form-item
label=
"题干内容"
>
<el-input
v-model=
"item.content"
:rows=
"5"
type=
"textarea"
placeholder=
"请输入"
/>
<el-input
v-model=
"item.content"
:rows=
"5"
type=
"textarea"
placeholder=
"请输入"
/>
</el-form-item>
</el-form-item>
</el-
form
>
</el-
card
>
</el-
card
>
</el-
form
>
</
template
>
</
template
>
<
style
lang=
"scss"
scoped
>
<
style
lang=
"scss"
scoped
>
.close
{
.close
{
...
...
src/modules/admin/lab/experiment/components/Questions/MaterialQuestion.vue
浏览文件 @
5dabc6d8
<
script
setup
lang=
"ts"
>
<
script
setup
lang=
"ts"
>
import
type
{
FormInstance
}
from
'element-plus'
import
type
{
FormInstance
}
from
'element-plus'
import
{
Document
,
CircleCheck
,
CircleClose
,
CircleCloseFilled
}
from
'@element-plus/icons-vue'
import
{
CircleCloseFilled
}
from
'@element-plus/icons-vue'
import
AppUpload
from
'@/components/base/AppUpload.vue'
import
type
{
UploadFile
}
from
'element-plus'
const
modelValue
:
any
=
defineModel
()
import
{
useMaterial
}
from
'../../composables/useQuestion'
const
ruleFormRef
=
ref
<
FormInstance
>
(
)
defineEmits
([
'remove'
]
)
// 移除上传文件
const
route
=
useRoute
()
const
handleRemove
=
(
file
:
UploadFile
)
=>
{
if
(
file
)
{
modelValue
.
value
.
forEach
((
item
:
any
)
=>
{
const
index
=
item
.
files
.
findIndex
((
cItem
:
{
url
:
string
})
=>
cItem
.
url
===
file
.
url
)
item
.
files
.
splice
(
index
,
1
)
})
}
}
const
handleDownload
=
(
file
:
any
)
=>
{
const
modelValue
:
any
=
defineModel
()
if
(
file
)
{
modelValue
.
value
.
forEach
((
i
:
any
)
=>
{
const
item
:
any
=
i
.
files
.
find
((
item
:
any
)
=>
item
.
url
===
file
.
url
)
if
(
item
)
item
.
is_download
=
file
.
is_download
})
}
}
const
removeQuestion
=
(
index
:
number
)
=>
{
const
formRef
=
ref
<
FormInstance
>
()
modelValue
.
value
.
splice
(
index
,
1
)
const
form
=
reactive
({
questions
:
modelValue
})
}
const
options
=
$ref
<
{
id
:
number
;
name
:
string
}[]
>
([
const
options
=
[
{
id
:
401
,
name
:
'文本资料'
},
{
id
:
401
,
name
:
'文本'
,
type
:
'1'
},
{
id
:
402
,
name
:
'图片资料'
},
{
id
:
402
,
name
:
'图片'
,
type
:
'2'
},
{
id
:
403
,
name
:
'语音资料'
},
{
id
:
403
,
name
:
'语音'
,
type
:
'3'
},
{
id
:
404
,
name
:
'视频资料'
},
{
id
:
404
,
name
:
'视频'
,
type
:
'4'
},
{
id
:
405
,
name
:
'H5资料'
},
{
id
:
405
,
name
:
'H5'
,
type
:
'5'
},
{
id
:
406
,
name
:
'二维码资料'
},
{
id
:
406
,
name
:
'二维码'
,
type
:
'6'
},
{
id
:
407
,
name
:
'小程序资料'
},
{
id
:
407
,
name
:
'小程序'
,
type
:
'7'
},
{
id
:
408
,
name
:
'卡券资料'
},
{
id
:
408
,
name
:
'卡券'
,
type
:
'8'
},
])
]
onMounted
(()
=>
{
const
dom
:
any
=
document
.
querySelectorAll
(
'.app-main'
)[
0
]
dom
.
style
.
overflow
=
'visible'
})
const
getTips
=
function
(
n
:
number
)
{
const
aiOptions
=
[
const
tipText
:
any
=
{
{
label
:
'文心一言'
,
value
:
'1'
},
402
:
'试题文件支持格式包含:png jpg jpeg ,大小不超过5M'
,
{
label
:
'DeepSeek'
,
value
:
'2'
},
403
:
'试题文件支持格式包含:mp3 wav,大小不超过5M'
,
{
label
:
'通义千问'
,
value
:
'3'
},
404
:
'试题文件支持格式包含:帧率为25fps/输出码率为4M/输出格式为mp4,建议采用格式工厂等工具处理后上传。'
,
{
label
:
'天工'
,
value
:
'4'
},
405
:
'试题文件支持格式包含:png jpg jpeg ,大小不超过5M'
,
]
406
:
'试题文件支持格式包含:png jpg jpeg ,大小不超过5M'
,
407
:
'试题文件支持格式包含:png jpg jpeg ,大小不超过5M'
,
const
{
materialList
}
=
useMaterial
(
route
.
query
.
id
as
string
)
508
:
'试题文件支持格式包含:png jpg jpeg ,大小不超过5M'
,
}
function
filterMateriaList
(
id
:
number
)
{
return
tipText
[
n
]
const
option
=
options
.
find
((
item
)
=>
item
.
id
===
id
)
return
materialList
.
value
.
filter
((
item
)
=>
item
.
type
===
option
?.
type
)
}
}
defineExpose
({
formRef
})
</
script
>
</
script
>
<
template
>
<
template
>
<el-card
:id=
"`site-card$
{index}`" class="box-card" v-for="(item, index) in modelValue" :key="item">
<el-form
ref=
"formRef"
label-width=
"120px"
:model=
"form"
scroll-to-error
>
<el-icon
@
click=
"removeQuestion(index)"
v-if=
"modelValue.length > 1"
class=
"close"
size=
"28"
color=
"#c01c40"
<el-card
:id=
"`site-card$
{index}`" class="box-card" v-for="(item, index) in modelValue" :key="item">
><CircleCloseFilled
<el-icon
@
click=
"$emit('remove', index)"
v-if=
"modelValue.length > 1"
class=
"close"
size=
"28"
color=
"#c01c40"
>
/></el-icon>
<CircleCloseFilled
/>
<div
class=
"head-box"
>
</el-icon>
<el-select
v-model=
"item.type"
class=
"m-2"
placeholder=
"请选择"
size=
"large"
>
<div
class=
"head-box"
>
<el-option
v-for=
"item in options"
:key=
"item.id"
:label=
"item.name"
:value=
"item.id"
/>
<el-form-item
</el-select>
label=
"本题分值"
<el-form-item
label=
"本题分值"
class=
"head-r"
>
class=
"head-r"
<el-input-number
v-model=
"item.score"
:min=
"1"
:max=
"100"
controls-position=
"right"
/>
:prop=
"`questions.$
{index}.score`"
</el-form-item>
:rules="{ required: true, message: '请输入' }">
</div>
<el-input-number
v-model=
"item.score"
:min=
"0"
:max=
"100"
controls-position=
"right"
/>
<el-form
ref=
"ruleFormRef"
label-width=
"120px"
class=
"demo-ruleForm"
status-icon
>
</el-form-item>
<el-form-item
label=
"题目标题"
:required=
"true"
>
</div>
<el-form-item
label=
"题目标题"
:prop=
"`questions.$
{index}.title`" :rules="{ required: true, message: '请输入' }">
<el-input
v-model=
"item.title"
placeholder=
"请输入"
/>
<el-input
v-model=
"item.title"
placeholder=
"请输入"
/>
</el-form-item>
</el-form-item>
<el-form-item
label=
"题干内容"
>
<el-form-item
label=
"题干内容"
>
<el-input
v-model=
"item.content"
:rows=
"5"
type=
"textarea"
placeholder=
"请输入"
/>
<el-input
v-model=
"item.content"
:rows=
"5"
type=
"textarea"
placeholder=
"请输入"
/>
</el-form-item>
</el-form-item>
<el-form-item
label=
"正确答案"
:required=
"true"
>
<el-form-item
<span>
上传成功
</span>
label=
"营销物料类别"
:prop=
"`questions.$
{index}.type`"
:rules="{ required: true, message: '请选择' }">
<el-radio-group
v-model=
"item.type"
placeholder=
"请选择"
>
<el-radio
v-for=
"item in options"
:key=
"item.id"
:label=
"item.id"
>
{{
item
.
name
}}
</el-radio>
</el-radio-group>
</el-form-item>
</el-form-item>
<el-form-item
label=
"答案解析"
>
<el-form-item
<el-input
v-model=
"item.answer_analysis"
:rows=
"5"
type=
"textarea"
placeholder=
"请输入"
/>
label=
"参考答案"
:prop=
"`questions.$
{index}.answer.choose`"
:rules="{ required: true, message: '请选择' }">
<el-select
v-model=
"item.answer.choose"
placeholder=
"请选择"
clearable
>
<el-option
v-for=
"materia in filterMateriaList(item.type)"
:key=
"materia.id"
:label=
"materia.name"
:value=
"materia.id"
></el-option>
</el-select>
</el-form-item>
<el-form-item
label=
"评分AI"
:prop=
"`questions.$
{index}.answer.ai`"
:rules="{ required: true, message: '请选择' }">
<el-select
v-model=
"item.answer.ai"
placeholder=
"请选择"
>
<el-option
v-for=
"item in aiOptions"
:key=
"item.value"
:label=
"item.label"
:value=
"item.value"
/>
</el-select>
</el-form-item>
</el-form-item>
<el-form-item
label=
"试题文件"
v-if=
"item.type !== 401"
>
<el-form-item
label=
"答案解析"
v-if=
"false"
>
<AppUpload
v-model=
"item.files"
>
<el-input
v-model=
"item.answer_analysis"
:rows=
"5"
type=
"textarea"
placeholder=
"请输入"
/>
<template
#
tip
>
{{
getTips
(
item
.
type
)
}}
</
template
>
<
template
#
file=
"{ file }"
>
<div
class=
"upload-box"
>
<div
class=
"upload-loading"
>
<el-icon
style=
"margin-right: 5px"
><Document
/></el-icon>
<p
style=
"margin-right: 5px"
>
{{
file
.
name
}}
</p>
<p
v-if=
"file.status === 'uploading'"
>
{{
file
.
percentage
}}
%
</p>
<template
v-if=
"file.status === 'success'"
>
<el-icon
class=
"succ-icon1"
color=
"#67c23a"
size=
"18"
style=
"margin-left: 30px"
><CircleCheck
/></el-icon>
<el-icon
class=
"succ-icon2"
size=
"18"
style=
"margin-left: 30px"
@
click=
"handleRemove(file)"
><CircleClose
/></el-icon>
</
template
>
</div>
<el-switch
@
change=
"handleDownload(file)"
v-model=
"file.is_download"
size=
"large"
active-text=
"能否下载"
/>
</div>
</template>
</AppUpload>
</el-form-item>
</el-form-item>
</el-
form
>
</el-
card
>
</el-
card
>
</el-
form
>
</
template
>
</
template
>
<
style
lang=
"scss"
scoped
>
<
style
lang=
"scss"
scoped
>
.close
{
.close
{
...
...
src/modules/admin/lab/experiment/components/Questions/PreviewDialog.vue
浏览文件 @
5dabc6d8
<
script
setup
lang=
"ts"
>
<
script
setup
>
import
{
getQuestions
}
from
'../../api'
import
{
getQuestions
}
from
'../../api'
const
route
:
any
=
useRoute
()
const
route
=
useRoute
()
onMounted
(()
=>
{
onMounted
(()
=>
{
getCurrentQuestions
()
getCurrentQuestions
()
})
})
// 获取题
// 获取题
let
list
:
any
=
$ref
(
)
const
list
=
ref
([]
)
const
getCurrentQuestions
=
function
()
{
const
getCurrentQuestions
=
function
()
{
getQuestions
({
experiment_id
:
route
.
query
.
id
}).
then
((
res
)
=>
{
getQuestions
({
experiment_id
:
route
.
query
.
id
}).
then
((
res
)
=>
{
list
=
res
.
data
.
items
list
.
value
=
res
.
data
.
items
})
})
}
}
</
script
>
</
script
>
<
template
>
<
template
>
<el-dialog
<el-dialog
title=
"
2023商业数据分析大赛决赛
试题"
title=
"试题"
:close-on-click-modal=
"false"
:close-on-click-modal=
"false"
width=
"50%"
width=
"50%"
@
update:modelValue=
"(value) => $emit('update:modelValue', value)"
>
@
update:modelValue=
"(value) => $emit('update:modelValue', value)"
>
...
@@ -46,10 +46,6 @@ const getCurrentQuestions = function () {
...
@@ -46,10 +46,6 @@ const getCurrentQuestions = function () {
font-size
:
14px
;
font-size
:
14px
;
}
}
.item
{
// margin-bottom: 18px;
}
.box-card
{
.box-card
{
margin-bottom
:
20px
;
margin-bottom
:
20px
;
}
}
...
...
src/modules/admin/lab/experiment/components/Questions/QuestionsOrder.vue
浏览文件 @
5dabc6d8
...
@@ -37,11 +37,13 @@ window.onscroll = function () {
...
@@ -37,11 +37,13 @@ window.onscroll = function () {
const
typeName
=
computed
(()
=>
{
const
typeName
=
computed
(()
=>
{
const
name
:
any
=
{
const
name
:
any
=
{
'10'
:
'用户/事件数据'
,
'6'
:
'标签管理'
,
'6'
:
'标签管理'
,
'7'
:
'群组管理'
,
'7'
:
'群组管理'
,
'8'
:
'用户旅程'
,
'9'
:
'营销资料管理'
,
'9'
:
'营销资料管理'
,
'8'
:
'用户旅程'
'10'
:
'用户/事件数据'
,
'11'
:
'用户数据导入/生成'
,
'12'
:
'事件数据导入/生成'
,
}
}
return
name
[(
route
.
query
?.
type
as
string
)
||
'10'
]
return
name
[(
route
.
query
?.
type
as
string
)
||
'10'
]
})
})
...
@@ -52,10 +54,10 @@ const typeName = computed(() => {
...
@@ -52,10 +54,10 @@ const typeName = computed(() => {
<div
class=
"order-score"
>
<div
class=
"order-score"
>
<div
class=
"order-score_flex"
>
<div
class=
"order-score_flex"
>
<span
class=
"el-tooltip question-total-number"
>
{{
score
}}
</span>
<span
class=
"el-tooltip question-total-number"
>
{{
score
}}
</span>
<span
class=
"el-tooltip paper-total-score"
>
/
100
</span>
<span
class=
"el-tooltip paper-total-score"
>
/
{{
route
.
query
.
row_score
}}
</span>
<em>
分
</em>
<em>
分
</em>
</div>
</div>
<
div
class=
"tip"
>
注:每模块满分为100,请注意每题分值。
</div
>
<
!--
<div
class=
"tip"
>
注:每模块满分为100,请注意每题分值。
</div>
--
>
</div>
</div>
<div
class=
"order-list"
>
<div
class=
"order-list"
>
<div
class=
"title"
>
{{
typeName
}}
</div>
<div
class=
"title"
>
{{
typeName
}}
</div>
...
@@ -64,8 +66,7 @@ const typeName = computed(() => {
...
@@ -64,8 +66,7 @@ const typeName = computed(() => {
@
click=
"handleOrder(index)"
@
click=
"handleOrder(index)"
:class=
"orderSite === index ? 'li active' : 'li'"
:class=
"orderSite === index ? 'li active' : 'li'"
v-for=
"(item, index) in props.data"
v-for=
"(item, index) in props.data"
:key=
"item"
:key=
"item"
>
>
{{
index
+
1
}}
{{
index
+
1
}}
</div>
</div>
</div>
</div>
...
...
src/modules/admin/lab/experiment/components/Questions/TagQuestion.vue
浏览文件 @
5dabc6d8
<
script
setup
lang=
"ts"
>
<
script
setup
lang=
"ts"
>
import
type
{
FormInstance
}
from
'element-plus'
import
type
{
FormInstance
}
from
'element-plus'
import
{
CircleCloseFilled
}
from
'@element-plus/icons-vue'
import
{
CircleCloseFilled
}
from
'@element-plus/icons-vue'
import
{
getQuestionTags
}
from
'../../api'
import
{
useAppConfig
}
from
'@/composables/useAppConfig'
import
{
useTag
}
from
'../../composables/useQuestion'
const
appConfig
=
useAppConfig
()
defineEmits
([
'remove'
])
const
route
=
useRoute
()
const
route
=
useRoute
()
const
modelValue
:
any
=
defineModel
()
const
modelValue
:
any
=
defineModel
()
const
ruleFormRef
=
ref
<
FormInstance
>
()
const
formRef
=
ref
<
FormInstance
>
()
const
form
=
reactive
({
questions
:
modelValue
,
})
const
removeQuestion
=
(
index
:
number
)
=>
{
const
{
tagList
}
=
useTag
(
route
.
query
.
id
as
string
)
modelValue
.
value
.
splice
(
index
,
1
)
}
let
options
=
$ref
<
{
id
:
string
;
name
:
string
}[]
>
()
function
getTagCount
(
id
:
string
)
{
onMounted
(()
=>
{
return
tagList
.
value
.
find
((
item
)
=>
item
.
id
===
id
)?.
count
||
'未计算'
const
dom
:
any
=
document
.
querySelectorAll
(
'.app-main'
)[
0
]
}
dom
.
style
.
overflow
=
'visible'
getQuestionTags
({
experiment_id
:
route
.
query
.
id
as
string
}).
then
(
res
=>
{
options
=
res
.
data
.
items
})
})
const
labelTitle
=
computed
(()
=>
{
defineExpose
({
formRef
})
return
appConfig
.
system
===
'dml'
?
'标签目录'
:
'标签类型'
})
</
script
>
</
script
>
<
template
>
<
template
>
<el-card
:id=
"`site-card$
{index}`" class="box-card" v-for="(item, index) in modelValue" :key="item">
<el-form
ref=
"formRef"
label-width=
"120px"
:model=
"form"
scroll-to-error
>
<el-icon
@
click=
"removeQuestion(index)"
v-if=
"modelValue.length > 1"
class=
"close"
size=
"28"
color=
"#c01c40"
><CircleCloseFilled
/></el-icon>
<el-card
<div
class=
"head-box"
>
shadow=
"hover"
<el-tabs
v-model=
"item.type"
type=
"card"
class=
"demo-tabs"
>
:id=
"`site-card$
{index}`"
<el-tab-pane
:label=
"labelTitle"
:name=
"201"
></el-tab-pane>
class="box-card"
<el-tab-pane
label=
"标签"
:name=
"202"
></el-tab-pane>
v-for="(item, index) in form.questions"
</el-tabs>
:key="item">
<el-form-item
label=
"本题分值"
class=
"head-r"
>
<el-icon
@
click=
"$emit('remove', index)"
v-if=
"form.questions.length > 1"
class=
"close"
size=
"28"
color=
"#c01c40"
>
<el-input-number
v-model=
"item.score"
:min=
"1"
:max=
"100"
controls-position=
"right"
/>
<CircleCloseFilled
/>
</el-icon>
<el-form-item
label=
"本题分值"
class=
"head-r"
:prop=
"`questions.$
{index}.score`"
:rules="{ required: true, message: '请输入' }">
<el-input-number
v-model=
"item.score"
:min=
"0"
:max=
"100"
controls-position=
"right"
/>
</el-form-item>
</el-form-item>
</div>
<el-form-item
label=
"题目标题"
:prop=
"`questions.$
{index}.title`" :rules="{ required: true, message: '请输入' }">
<el-form
ref=
"ruleFormRef"
label-width=
"120px"
class=
"demo-ruleForm"
status-icon
>
<el-form-item
label=
"题目标题"
:required=
"true"
>
<el-input
v-model=
"item.title"
placeholder=
"请输入"
/>
<el-input
v-model=
"item.title"
placeholder=
"请输入"
/>
</el-form-item>
</el-form-item>
<el-form-item
label=
"题干内容"
>
<el-form-item
label=
"题干内容"
>
<el-input
v-model=
"item.content"
:rows=
"5"
type=
"textarea"
placeholder=
"请输入"
/>
<el-input
v-model=
"item.content"
:rows=
"5"
type=
"textarea"
placeholder=
"请输入"
/>
</el-form-item>
</el-form-item>
<el-form-item
label=
"正确答案"
:required=
"true"
>
<el-form-item
label=
"评分规则"
>
<span
v-if=
"item.type === 201"
>
创建
{{
labelTitle
}}
成功
</span>
<el-radio-group
v-model=
"item.answer.rule.type"
>
<el-select
v-else
v-model=
"item.answer"
class=
"m-2"
placeholder=
"请选择"
size=
"large"
>
<el-radio
label=
"1"
>
标签规则+计算结果
</el-radio>
<el-option
v-for=
"item in options"
:key=
"item.id"
:label=
"item.name"
:value=
"item.id"
/>
<el-radio
label=
"2"
>
仅标签规则
</el-radio>
<el-radio
label=
"3"
>
仅计算结果
</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item
label=
"正确标签规则"
:prop=
"`questions.$
{index}.answer.choose`"
:rules="{ required: true, message: '请输入' }">
<el-select
v-model=
"item.answer.choose"
>
<el-option
v-for=
"item in tagList"
:key=
"item.id"
:label=
"item.name"
:value=
"item.id"
/>
</el-select>
</el-select>
<p
style=
"margin-left: 10px"
>
满足该标签的用户数量:
{{
getTagCount
(
item
.
answer
.
choose
)
}}
</p>
</el-form-item>
</el-form-item>
<el-form-item
label=
"答案解析"
>
<el-form-item
label=
"答案解析"
v-if=
"false"
>
<el-input
v-model=
"item.answer_analysis"
:rows=
"5"
type=
"textarea"
placeholder=
"请输入"
/>
<el-input
v-model=
"item.answer_analysis"
:rows=
"5"
type=
"textarea"
placeholder=
"请输入"
/>
</el-form-item>
</el-form-item>
</el-
form
>
</el-
card
>
</el-
card
>
</el-
form
>
</
template
>
</
template
>
<
style
lang=
"scss"
scoped
>
<
style
lang=
"scss"
scoped
>
.close
{
.close
{
...
...
src/modules/admin/lab/experiment/components/Questions/UserQuestion.vue
浏览文件 @
5dabc6d8
<
script
setup
lang=
"ts"
>
<
script
setup
lang=
"ts"
>
import
type
{
FormInstance
}
from
'element-plus'
import
type
{
FormInstance
}
from
'element-plus'
import
{
Document
,
CircleCheck
,
CircleClose
,
CircleCloseFilled
}
from
'@element-plus/icons-vue'
import
{
Plus
,
CircleCloseFilled
}
from
'@element-plus/icons-vue'
import
AppUpload
from
'@/components/base/AppUpload.vue'
import
{
useFileDialog
}
from
'@vueuse/core'
import
type
{
UploadFile
}
from
'element-plus'
import
{
upload
}
from
'@/utils/upload'
import
{
getExcelTotalLine
,
checkAutoGenerateData
}
from
'../../api'
import
{
useAppConfig
}
from
'@/composables/useAppConfig'
const
appConfig
=
useAppConfig
()
defineEmits
([
'remove'
])
const
route
=
useRoute
()
const
modelValue
:
any
=
defineModel
()
const
modelValue
:
any
=
defineModel
()
const
ruleFormRef
=
ref
<
FormInstance
>
()
const
formRef
=
ref
<
FormInstance
>
()
const
form
=
reactive
({
questions
:
modelValue
,
})
// 移除上传文件
const
{
files
,
open
,
reset
}
=
useFileDialog
({
const
handleRemove
=
(
file
:
UploadFile
)
=>
{
accept
:
if
(
file
)
{
'.csv, .xls, .xlsx, text/csv, application/csv,text/comma-separated-values, application/csv, application/excel,application/vnd.msexcel, text/anytext, application/vnd. ms-excel,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
,
modelValue
.
value
.
forEach
((
item
:
any
)
=>
{
multiple
:
false
,
const
index
=
item
.
files
.
findIndex
((
cItem
:
{
url
:
string
})
=>
cItem
.
url
===
file
.
url
)
})
item
.
files
.
splice
(
index
,
1
)
})
let
currentItem
:
any
=
null
}
function
handleUpload
(
item
:
any
)
{
currentItem
=
item
open
()
}
}
const
handleDownload
=
(
file
:
any
)
=>
{
watchEffect
(
async
()
=>
{
if
(
file
)
{
if
(
!
files
.
value
?.
length
)
return
modelValue
.
value
.
forEach
((
i
:
any
)
=>
{
const
[
file
]
=
files
.
value
const
item
:
any
=
i
.
files
.
find
((
item
:
any
)
=>
item
.
url
===
file
.
url
)
const
url
=
await
upload
(
file
)
if
(
item
)
item
.
is_download
=
file
.
is_download
const
res
=
await
getExcelTotalLine
({
file
})
})
const
total
=
res
.
data
.
row_count
||
0
if
(
currentItem
)
{
currentItem
.
answer
.
data
.
file
=
{
name
:
file
.
name
,
size
:
file
.
size
,
type
:
file
.
type
,
is_download
:
false
,
total
,
url
,
}
}
}
}
reset
()
})
const
removeQuestion
=
(
index
:
number
)
=>
{
const
href
=
computed
(()
=>
{
modelValue
.
value
.
splice
(
index
,
1
)
const
dmlURL
=
appConfig
.
dmlURL
||
import
.
meta
.
env
.
VITE_DML_URL
return
`
${
dmlURL
}
/connect?experiment_id=
${
route
.
query
.
id
}
`
})
async
function
handleDataTypeChange
(
item
:
any
)
{
item
.
answer
.
rule
.
type
=
item
.
answer
.
data
.
type
==
2
?
'3'
:
'1'
if
(
item
.
answer
.
data
.
type
!=
2
)
return
const
res
=
await
checkAutoGenerateData
({
experiment_id
:
route
.
query
.
id
as
string
})
item
.
answer
.
data
.
exists
=
res
.
data
.
exists
}
}
onMounted
(()
=>
{
defineExpose
({
formRef
})
const
dom
:
any
=
document
.
querySelectorAll
(
'.app-main'
)[
0
]
dom
.
style
.
overflow
=
'visible'
})
</
script
>
</
script
>
<
template
>
<
template
>
<el-
card
:id=
"`site-card$
{index}`" class="box-card" v-for="(item, index) in modelValue" :key="item"
>
<el-
form
ref=
"formRef"
label-width=
"120px"
:model=
"form"
scroll-to-error
>
<el-
icon
@
click=
"removeQuestion(index)"
v-if=
"modelValue.length > 1"
class=
"close"
size=
"28"
color=
"#c01c40"
<el-
card
shadow=
"hover"
:id=
"`site-card$
{index}`" class="box-card" v-for="(item, index) in modelValue" :key="item">
><CircleCloseFilled
<el-icon
@
click=
"$emit('remove', index)"
v-if=
"modelValue.length > 1"
class=
"close"
size=
"28"
color=
"#c01c40"
/></el-icon>
><CircleCloseFilled
<div
class=
"head-box"
>
/></el-icon
>
<
el-tabs
v-model=
"item.type"
type=
"card"
class=
"demo-tabs
"
>
<
div
class=
"head-box
"
>
<el-
tab-pane
label=
"用户数据"
:name=
"101"
></el-tab-pane>
<el-
form-item
<el-tab-pane
label=
"事件数据"
:name=
"102"
></el-tab-pane>
label=
"本题分值"
</el-tabs>
class=
"head-r"
<el-form-item
label=
"本题分值"
class=
"head-r"
>
:prop=
"`questions.$
{index}.score`"
<el-input-number
v-model=
"item.score"
:min=
"1"
:max=
"100"
controls-position=
"right"
/
>
:rules="{ required: true, message: '请输入' }"
>
</el-form-item
>
<el-input-number
v-model=
"item.score"
:min=
"0"
:max=
"100"
controls-position=
"right"
/
>
</div
>
</el-form-item
>
<el-form
ref=
"ruleFormRef"
label-width=
"120px"
class=
"demo-ruleForm"
status-icon
>
</div
>
<el-form-item
label=
"题目标题"
:
required=
"true
"
>
<el-form-item
label=
"题目标题"
:
prop=
"`questions.$
{index}.title`" :rules="{ required: true, message: '请输入' }
">
<el-input
v-model=
"item.title"
placeholder=
"请输入"
/>
<el-input
v-model=
"item.title"
placeholder=
"请输入"
/>
</el-form-item>
</el-form-item>
<el-form-item
label=
"题干内容"
>
<el-form-item
label=
"题干内容"
>
<el-input
v-model=
"item.content"
:rows=
"5"
type=
"textarea"
placeholder=
"请输入"
/>
<el-input
v-model=
"item.content"
:rows=
"5"
type=
"textarea"
placeholder=
"请输入"
/>
</el-form-item>
</el-form-item>
<el-form-item
label=
"正确答案"
:required=
"true"
>
导入成功
</el-form-item>
<el-form-item
label=
"用户数据集"
>
<el-form-item
label=
"答案解析"
>
<div>
<el-input
v-model=
"item.answer_analysis"
:rows=
"5"
type=
"textarea"
placeholder=
"请输入"
/>
<el-radio-group
v-model=
"item.answer.data.type"
@
change=
"handleDataTypeChange(item)"
>
<el-radio
label=
"1"
>
指定文件
</el-radio>
<el-radio
label=
"2"
>
自动生成
</el-radio>
</el-radio-group>
<div
class=
"form-item-box"
>
<template
v-if=
"item.answer.data.type == 1"
>
<el-button
:icon=
"Plus"
size=
"large"
@
click=
"handleUpload(item)"
></el-button>
<template
v-if=
"item.answer.data.file.url"
>
<div
class=
"file-info"
>
<p>
{{
item
.
answer
.
data
.
file
.
name
}}
</p>
<p>
总数据量:
{{
item
.
answer
.
data
.
file
.
total
}}
条
</p>
</div>
<el-button
type=
"primary"
plain
@
click=
"item.answer.data.file =
{}">删除数据集
</el-button>
</
template
>
</template>
<
template
v-else
>
<a
:href=
"href"
target=
"_blank"
>
<el-button
type=
"primary"
>
查看自动生成规则
</el-button>
</a>
<el-alert
title=
"该实验尚未维护自动生成数据规则,请维护!"
type=
"info"
style=
"margin-left: 40px"
v-if=
"!item.answer.data.exists"
/>
</
template
>
</div>
</div>
</el-form-item>
</el-form-item>
<el-form-item
label=
"试题文件"
>
<el-form-item
label=
"评分规则"
>
<AppUpload
v-model=
"item.files"
>
<el-radio-group
v-model=
"item.answer.rule.type"
>
<template
#
tip
>
试题文件支持格式包含:png jpg doc docx xls xlsx pdf ppt pptx,大小不超过50M
</
template
>
<
template
v-if=
"item.answer.data.type == 1"
>
<
template
#
file=
"{ file }"
>
<el-radio
label=
"1"
>
上传成功+数据量匹配
</el-radio>
<div
class=
"upload-box"
>
<el-radio
label=
"2"
>
仅上传成功
</el-radio>
<div
class=
"upload-loading"
>
<el-icon
style=
"margin-right: 5px"
><Document
/></el-icon>
<p
style=
"margin-right: 5px"
>
{{
file
.
name
}}
</p>
<p
v-if=
"file.status === 'uploading'"
>
{{
file
.
percentage
}}
%
</p>
<template
v-if=
"file.status === 'success'"
>
<el-icon
class=
"succ-icon1"
color=
"#67c23a"
size=
"18"
style=
"margin-left: 30px"
><CircleCheck
/></el-icon>
<el-icon
class=
"succ-icon2"
size=
"18"
style=
"margin-left: 30px"
@
click=
"handleRemove(file)"
><CircleClose
/></el-icon>
</
template
>
</div>
<el-switch
@
change=
"handleDownload(file)"
v-model=
"file.is_download"
size=
"large"
active-text=
"能否下载"
/>
</div>
</
template
>
</
template
>
</AppUpload>
<el-radio
label=
"3"
>
仅数据量匹配
</el-radio>
</el-radio-group>
</el-form-item>
</el-form-item>
</el-form>
<el-form-item
label=
"答案解析"
v-if=
"false"
>
</el-card>
<el-input
v-model=
"item.answer_analysis"
:rows=
"5"
type=
"textarea"
placeholder=
"请输入"
/>
</el-form-item>
</el-card>
</el-form>
</template>
</template>
<
style
lang=
"scss"
scoped
>
<
style
lang=
"scss"
scoped
>
.close
{
.close
{
...
@@ -113,24 +150,14 @@ onMounted(() => {
...
@@ -113,24 +150,14 @@ onMounted(() => {
margin-left
:
auto
;
margin-left
:
auto
;
}
}
}
}
.upload-box
{
.form-item-box
{
display
:
flex
;
display
:
flex
;
.upload-loading
{
align-items
:
center
;
width
:
300px
;
p
{
display
:
flex
;
font-size
:
13px
;
align-items
:
center
;
margin
:
0
20px
0
10px
;
&
:hover
{
line-height
:
1
.4
;
.succ-icon2
{
display
:
block
;
}
.succ-icon1
{
display
:
none
;
}
}
.succ-icon2
{
display
:
none
;
cursor
:
pointer
;
}
}
}
}
}
</
style
>
</
style
>
src/modules/admin/lab/experiment/composables/useQuestion.ts
0 → 100644
浏览文件 @
5dabc6d8
import
{
getQuestionTags
,
getQuestionGroup
,
getQuestionMaterials
,
getQuestionEvents
}
from
'../api'
// 标签类型
export
interface
TagType
{
id
:
string
name
:
string
count
:
string
}
// 群组类型
export
interface
GroupType
{
id
:
string
name
:
string
count
:
string
}
export
interface
MaterialType
{
id
:
string
name
:
string
type
:
string
}
// 事件类型
interface
EventType
{
id
:
string
name
:
string
}
// 所有标签
const
tagList
=
ref
<
TagType
[]
>
([])
export
function
useTag
(
experiment_id
:
string
)
{
function
fetchTagList
()
{
getQuestionTags
({
experiment_id
}).
then
((
res
:
any
)
=>
{
tagList
.
value
=
res
.
data
.
items
})
}
onMounted
(()
=>
{
if
(
!
tagList
.
value
?.
length
)
fetchTagList
()
})
return
{
fetchTagList
,
tagList
}
}
// 所有群组
const
groupList
=
ref
<
GroupType
[]
>
([])
export
function
useGroup
(
experiment_id
:
string
)
{
function
fetchGroupList
()
{
getQuestionGroup
({
experiment_id
}).
then
((
res
:
any
)
=>
{
groupList
.
value
=
res
.
data
.
items
})
}
onMounted
(()
=>
{
if
(
!
groupList
.
value
?.
length
)
fetchGroupList
()
})
return
{
fetchGroupList
,
groupList
}
}
// 所有资料
const
materialList
=
ref
<
MaterialType
[]
>
([])
export
function
useMaterial
(
experiment_id
:
string
,
type
=
''
)
{
function
fetchMaterialList
()
{
getQuestionMaterials
({
experiment_id
,
type
}).
then
((
res
:
any
)
=>
{
materialList
.
value
=
res
.
data
.
items
})
}
onMounted
(()
=>
{
if
(
!
materialList
.
value
?.
length
)
fetchMaterialList
()
})
return
{
fetchMaterialList
,
materialList
}
}
// 所有事件
const
eventList
=
ref
<
EventType
[]
>
([])
export
function
useEvent
(
experiment_id
:
string
)
{
function
fetchMetaEventList
()
{
getQuestionEvents
({
experiment_id
}).
then
((
res
:
any
)
=>
{
eventList
.
value
=
res
.
data
.
items
})
}
onMounted
(()
=>
{
if
(
!
eventList
.
value
?.
length
)
fetchMetaEventList
()
})
return
{
fetchMetaEventList
,
eventList
}
}
src/modules/admin/lab/experiment/types.ts
浏览文件 @
5dabc6d8
...
@@ -50,6 +50,7 @@ export interface ExperimentCreateItem {
...
@@ -50,6 +50,7 @@ export interface ExperimentCreateItem {
content
:
string
content
:
string
procedure
:
string
procedure
:
string
exam_status
:
string
exam_status
:
string
can_repeat_commit
:
'0'
|
'1'
}
}
export
interface
ClassItem
{
export
interface
ClassItem
{
...
...
src/modules/admin/lab/experiment/views/Index.vue
浏览文件 @
5dabc6d8
...
@@ -27,7 +27,7 @@ const params = reactive({
...
@@ -27,7 +27,7 @@ const params = reactive({
id
:
''
,
id
:
''
,
course_id
:
''
,
course_id
:
''
,
name
:
''
,
name
:
''
,
status
:
''
status
:
''
,
})
})
watch
(
watch
(
()
=>
params
.
course_id
,
()
=>
params
.
course_id
,
...
@@ -50,12 +50,12 @@ const listOptions = $computed(() => {
...
@@ -50,12 +50,12 @@ const listOptions = $computed(() => {
},
},
callback
(
data
:
{
total
:
number
;
list
:
ExperimentItem
[]
})
{
callback
(
data
:
{
total
:
number
;
list
:
ExperimentItem
[]
})
{
const
{
list
,
total
}
=
data
const
{
list
,
total
}
=
data
const
dataList
=
list
.
map
(
item
=>
{
const
dataList
=
list
.
map
(
(
item
)
=>
{
const
teacher_names
=
item
.
teacher
.
map
(
teacher
=>
teacher
.
name
).
join
(
'、'
)
const
teacher_names
=
item
.
teacher
.
map
(
(
teacher
)
=>
teacher
.
name
).
join
(
'、'
)
return
{
...
item
,
teacher_names
}
return
{
...
item
,
teacher_names
}
})
})
return
{
list
:
dataList
,
total
}
return
{
list
:
dataList
,
total
}
}
}
,
},
},
filters
:
[
filters
:
[
{
{
...
@@ -65,7 +65,7 @@ const listOptions = $computed(() => {
...
@@ -65,7 +65,7 @@ const listOptions = $computed(() => {
placeholder
:
'请选择实验课程'
,
placeholder
:
'请选择实验课程'
,
options
:
courses
.
value
,
options
:
courses
.
value
,
labelKey
:
'name'
,
labelKey
:
'name'
,
valueKey
:
'id'
valueKey
:
'id'
,
},
},
{
{
type
:
'select'
,
type
:
'select'
,
...
@@ -74,15 +74,15 @@ const listOptions = $computed(() => {
...
@@ -74,15 +74,15 @@ const listOptions = $computed(() => {
placeholder
:
'请选择实验'
,
placeholder
:
'请选择实验'
,
options
:
courseExperiments
.
value
,
options
:
courseExperiments
.
value
,
labelKey
:
'name'
,
labelKey
:
'name'
,
valueKey
:
'id'
valueKey
:
'id'
,
},
},
{
{
type
:
'select'
,
type
:
'select'
,
prop
:
'status'
,
prop
:
'status'
,
label
:
'生效状态'
,
label
:
'生效状态'
,
placeholder
:
'请选择生效状态'
,
placeholder
:
'请选择生效状态'
,
options
:
status
options
:
status
,
}
}
,
],
],
columns
:
[
columns
:
[
{
label
:
'序号'
,
type
:
'index'
,
width
:
60
},
{
label
:
'序号'
,
type
:
'index'
,
width
:
60
},
...
@@ -95,8 +95,8 @@ const listOptions = $computed(() => {
...
@@ -95,8 +95,8 @@ const listOptions = $computed(() => {
{
label
:
'生效状态'
,
prop
:
'status_name'
},
{
label
:
'生效状态'
,
prop
:
'status_name'
},
{
label
:
'更新人'
,
prop
:
'updated_operator_name'
},
{
label
:
'更新人'
,
prop
:
'updated_operator_name'
},
{
label
:
'更新时间'
,
prop
:
'updated_time'
},
{
label
:
'更新时间'
,
prop
:
'updated_time'
},
{
label
:
'操作'
,
slots
:
'table-x'
,
width
:
250
}
{
label
:
'操作'
,
slots
:
'table-x'
,
width
:
250
}
,
]
]
,
}
}
})
})
...
@@ -162,7 +162,7 @@ async function handleDelete(row: ExperimentItem) {
...
@@ -162,7 +162,7 @@ async function handleDelete(row: ExperimentItem) {
<el-button
type=
"primary"
round
@
click=
"handleUpdate(row)"
v-permission=
"'v1-backend-experiment-update'"
<el-button
type=
"primary"
round
@
click=
"handleUpdate(row)"
v-permission=
"'v1-backend-experiment-update'"
>
编辑
</el-button
>
编辑
</el-button
>
>
<el-button
type=
"primary"
round
:icon=
"Delete"
@
click=
"handleDelete(row)"
>
删除
</el-button>
<el-button
type=
"primary"
round
@
click=
"handleDelete(row)"
>
删除
</el-button>
<!-- 功能按钮移入详情里 s v-if="false" -->
<!-- 功能按钮移入详情里 s v-if="false" -->
<el-dropdown
style=
"margin-left: 12px"
v-if=
"false"
>
<el-dropdown
style=
"margin-left: 12px"
v-if=
"false"
>
...
@@ -226,14 +226,12 @@ async function handleDelete(row: ExperimentItem) {
...
@@ -226,14 +226,12 @@ async function handleDelete(row: ExperimentItem) {
v-model=
"gradeRulesDialogVisible"
v-model=
"gradeRulesDialogVisible"
:data=
"rowData"
:data=
"rowData"
@
update=
"onUpdateSuccess"
@
update=
"onUpdateSuccess"
v-if=
"gradeRulesDialogVisible && rowData"
v-if=
"gradeRulesDialogVisible && rowData"
></GradeRulesDialog>
></GradeRulesDialog>
<!-- 配置数字营销实验 -->
<!-- 配置数字营销实验 -->
<DMLFormDialog
v-model=
"dmlDialogVisible"
:data=
"rowData"
v-if=
"dmlDialogVisible && rowData"
></DMLFormDialog>
<DMLFormDialog
v-model=
"dmlDialogVisible"
:data=
"rowData"
v-if=
"dmlDialogVisible && rowData"
></DMLFormDialog>
<CopyDialog
<CopyDialog
v-model=
"copyDialogVisible"
v-model=
"copyDialogVisible"
:data=
"rowData"
:data=
"rowData"
@
update=
"onUpdateSuccess"
@
update=
"onUpdateSuccess"
v-if=
"copyDialogVisible && rowData"
v-if=
"copyDialogVisible && rowData"
></CopyDialog>
></CopyDialog>
</template>
</template>
src/modules/admin/lab/experiment/views/Questions.vue
浏览文件 @
5dabc6d8
<
script
setup
lang=
"ts"
>
<
script
setup
>
import
{
updateQuestions
,
getQuestions
}
from
'../api'
import
{
updateQuestions
,
getQuestions
}
from
'../api'
import
{
ElMessage
}
from
'element-plus'
import
{
ElMessage
}
from
'element-plus'
const
PreviewDialog
=
defineAsyncComponent
(()
=>
import
(
'../components/Questions/PreviewDialog.vue'
))
const
PreviewDialog
=
defineAsyncComponent
(()
=>
import
(
'../components/Questions/PreviewDialog.vue'
))
const
QuestionsOrder
=
defineAsyncComponent
(()
=>
import
(
'../components/Questions/QuestionsOrder.vue'
))
const
QuestionsOrder
=
defineAsyncComponent
(()
=>
import
(
'../components/Questions/QuestionsOrder.vue'
))
const
UserQuestion
=
defineAsyncComponent
(()
=>
import
(
'../components/Questions/UserQuestion.vue'
))
const
UserQuestion
=
defineAsyncComponent
(()
=>
import
(
'../components/Questions/UserQuestion.vue'
))
const
EventQuestion
=
defineAsyncComponent
(()
=>
import
(
'../components/Questions/EventQuestion.vue'
))
const
TagQuestion
=
defineAsyncComponent
(()
=>
import
(
'../components/Questions/TagQuestion.vue'
))
const
TagQuestion
=
defineAsyncComponent
(()
=>
import
(
'../components/Questions/TagQuestion.vue'
))
const
GroupQuestion
=
defineAsyncComponent
(()
=>
import
(
'../components/Questions/GroupQuestion.vue'
))
const
GroupQuestion
=
defineAsyncComponent
(()
=>
import
(
'../components/Questions/GroupQuestion.vue'
))
const
MaterialQuestion
=
defineAsyncComponent
(()
=>
import
(
'../components/Questions/MaterialQuestion.vue'
))
const
MaterialQuestion
=
defineAsyncComponent
(()
=>
import
(
'../components/Questions/MaterialQuestion.vue'
))
const
JourneyQuestion
=
defineAsyncComponent
(()
=>
import
(
'../components/Questions/JourneyQuestion.vue'
))
const
JourneyQuestion
=
defineAsyncComponent
(()
=>
import
(
'../components/Questions/JourneyQuestion.vue'
))
const
route
:
any
=
useRoute
()
const
route
=
useRoute
()
const
router
=
useRouter
()
const
getQuestionTypeInitValue
=
function
()
{
/*
const
type
:
any
=
{
10
:
101
,
6
:
201
,
7
:
301
,
9
:
401
,
8
:
501
}
101实验用户数据题 102实验事件数据题
return
type
[
parseInt
(
route
.
query
?.
type
||
'10'
)]
201实验标签类型题 202实验标签题
}
301实验静态群组题 302动态群组题
401实验营销文本资料题 402验营销图片资料题 403验营销语音资料题 404验营销视频资料题 405验营销H5资料题 406验营销二维码资料题 407验营销小程序资料题 408验营销卡券资料题
let
data
=
$ref
([
501用户旅程题
{
601实验报告题
type
:
getQuestionTypeInitValue
(),
*/
score
:
1
,
const
types
=
computed
(()
=>
{
title
:
''
,
const
typesJson
=
{
content
:
''
,
6
:
[
201
,
202
],
answer_analysis
:
''
,
7
:
[
301
,
302
],
answer
:
''
,
8
:
[
501
],
files
:
[]
9
:
[
401
,
402
,
403
,
404
,
405
,
406
,
407
,
408
],
10
:
[
101
,
102
],
11
:
[
101
],
12
:
[
102
],
}
}
])
return
typesJson
[
route
.
query
.
type
]
||
route
.
query
.
type
})
const
addQuestion
=
()
=>
{
const
type
=
computed
(()
=>
{
data
.
push
({
const
type
=
{
6
:
202
,
7
:
301
,
8
:
501
,
9
:
401
,
10
:
101
,
11
:
101
,
12
:
102
}
type
:
getQuestionTypeInitValue
(),
return
type
[
route
.
query
.
type
]
||
101
score
:
1
,
})
const
hasAdd
=
computed
(()
=>
{
return
route
.
query
.
type
!=
11
})
const
createDefaultQuestion
=
()
=>
{
return
{
type
:
type
.
value
,
score
:
0
,
title
:
''
,
title
:
''
,
content
:
''
,
content
:
''
,
answer_analysis
:
''
,
answer_analysis
:
''
,
answer
:
''
,
answer
:
{
files
:
[]
choose
:
''
,
})
data
:
{
type
:
'1'
,
file
:
{}
},
rule
:
{
type
:
'1'
},
ai
:
'1'
,
},
}
}
}
const
previewDialogVisible
=
$ref
(
false
)
const
questionRef
=
ref
(
)
const
handleSubmit
=
function
()
{
const
questions
=
ref
([{
...
createDefaultQuestion
()
}])
const
type
:
any
=
{
10
:
'1'
,
6
:
'2'
,
7
:
'3'
,
9
:
'4'
,
8
:
'5'
}
console
.
log
(
data
,
'data'
)
const
params
=
{
experiment_id
:
route
.
query
.
id
,
module
:
type
[
route
.
query
.
type
],
questions
:
data
}
//判断必填不能为空
const
previewDialogVisible
=
ref
(
false
)
function
findItem
(
value
:
string
)
{
return
data
.
findIndex
((
item
:
any
)
=>
item
[
value
]
===
''
)
async
function
getQuestion
()
{
}
const
resp
=
await
getQuestions
({
experiment_id
:
route
.
query
.
id
,
types
:
types
.
value
})
if
(
findItem
(
'title'
)
!==
-
1
)
{
if
(
resp
.
data
.
items
.
length
)
{
ElMessage
.
error
(
`第
${
findItem
(
'title'
)
+
1
}
题,题目不能为空`
)
questions
.
value
=
resp
.
data
.
items
.
map
((
item
)
=>
{
return
false
return
{
...
item
,
answer
:
JSON
.
parse
(
item
.
answer
),
score
:
parseInt
(
item
.
score
)
||
0
,
type
:
parseInt
(
item
.
type
)
}
})
}
}
updateQuestions
(
params
).
then
(
res
=>
{
if
(
res
.
data
.
status
)
{
ElMessage
({
message
:
'保存成功'
,
type
:
'success'
})
router
.
go
(
0
)
}
})
}
}
onMounted
(()
=>
{
onMounted
(()
=>
{
get
CurrentQuestions
()
get
Question
()
})
})
// 获取题
// 添加试题
const
getCurrentQuestions
=
function
()
{
const
typesJson
:
any
=
{
const
addQuestion
=
()
=>
{
10
:
[
101
,
102
],
questions
.
value
.
push
({
...
createDefaultQuestion
()
})
6
:
[
201
,
202
],
}
7
:
[
301
,
302
],
9
:
[
401
,
402
,
403
,
404
,
405
,
406
,
407
,
408
],
const
removeQuestion
=
(
index
)
=>
{
8
:
[
501
]
questions
.
value
.
splice
(
index
,
1
)
}
}
getQuestions
({
experiment_id
:
route
.
query
.
id
,
types
:
typesJson
[
route
.
query
.
type
]
}).
then
(
res
=>
{
// 保存
if
(
res
.
data
?.
items
)
{
if
(
res
.
data
.
items
?.
length
)
{
const
handleSubmit
=
async
()
=>
{
data
=
res
.
data
.
items
.
reduce
((
a
:
any
,
b
:
any
)
=>
{
await
unref
(
questionRef
.
value
?.
formRef
).
validate
()
b
.
type
=
parseInt
(
b
.
type
)
await
updateQuestions
({
b
.
files
.
map
((
item
:
any
)
=>
{
experiment_id
:
route
.
query
.
id
,
item
.
is_download
===
'true'
?
(
item
.
is_download
=
true
)
:
(
item
.
is_download
=
false
)
module
:
route
.
query
.
type
,
return
item
questions
:
questions
.
value
.
map
((
item
)
=>
{
})
return
{
...
item
,
answer
:
JSON
.
stringify
(
item
.
answer
)
}
a
.
push
(
b
)
}),
return
a
},
[])
}
}
})
})
ElMessage
({
message
:
'保存成功'
,
type
:
'success'
})
}
}
</
script
>
</
script
>
...
@@ -108,31 +109,36 @@ const getCurrentQuestions = function () {
...
@@ -108,31 +109,36 @@ const getCurrentQuestions = function () {
<p>
实验类型:
{{
route
.
query
.
type_name
}}
</p>
<p>
实验类型:
{{
route
.
query
.
type_name
}}
</p>
<p>
实验总成绩:
{{
route
.
query
.
score
}}
</p>
<p>
实验总成绩:
{{
route
.
query
.
score
}}
</p>
</div>
</div>
<el-button
@
click=
"previewDialogVisible = true"
>
预览
</el-button>
<el-button
@
click=
"previewDialogVisible = true"
v-if=
"false"
>
预览
</el-button>
</div>
</div>
</AppCard>
</AppCard>
<div
class=
"content-bottom"
>
<div
class=
"content-bottom"
>
<AppCard
class=
"l-card"
>
<AppCard
class=
"l-card"
>
<UserQuestion
v-model=
"data"
v-if=
"route.query.type === '10'"
></UserQuestion>
<TagQuestion
v-model=
"questions"
ref=
"questionRef"
@
remove=
"removeQuestion"
v-if=
"route.query.type === '6'"
/>
<TagQuestion
v-model=
"data"
v-if=
"route.query.type === '6'"
></TagQuestion>
<GroupQuestion
v-model=
"questions"
ref=
"questionRef"
@
remove=
"removeQuestion"
v-if=
"route.query.type === '7'"
/>
<GroupQuestion
v-model=
"data"
v-if=
"route.query.type === '7'"
></GroupQuestion>
<JourneyQuestion
v-model=
"questions"
ref=
"questionRef"
@
remove=
"removeQuestion"
v-if=
"route.query.type === '8'"
/>
<MaterialQuestion
v-model=
"data"
v-if=
"route.query.type === '9'"
></MaterialQuestion>
<MaterialQuestion
<JourneyQuestion
v-model=
"data"
v-if=
"route.query.type === '8'"
></JourneyQuestion>
v-model=
"questions"
ref=
"questionRef"
@
remove=
"removeQuestion"
v-if=
"route.query.type === '9'"
/>
<UserQuestion
v-model=
"questions"
ref=
"questionRef"
@
remove=
"removeQuestion"
v-if=
"route.query.type === '11'"
/>
<EventQuestion
v-model=
"questions"
ref=
"questionRef"
@
remove=
"removeQuestion"
v-if=
"route.query.type === '12'"
/>
<div
class=
"btn-box"
>
<div
class=
"btn-box"
>
<div
class=
"btn-l"
>
<div
class=
"btn-l"
>
<el-button
type=
"primary"
@
click=
"addQuestion"
>
添加试题
</el-button>
<el-button
type=
"primary"
@
click=
"addQuestion"
v-if=
"hasAdd"
>
添加试题
</el-button>
<!--
<el-button>
取消
</el-button>
-->
<!--
<el-button>
取消
</el-button>
-->
</div>
</div>
<div
class=
"btn-r"
>
<div
class=
"btn-r"
>
<el-button
type=
"primary"
@
click=
"handleSubmit"
>
保存
</el-button>
<el-button
type=
"primary"
@
click=
"handleSubmit"
>
保存
</el-button>
</div>
</div>
</div>
</div>
</AppCard>
</AppCard>
<AppCard
class=
"r-card"
>
<AppCard
class=
"r-card"
>
<QuestionsOrder
:data=
"
data
"
></QuestionsOrder>
<QuestionsOrder
:data=
"
questions
"
></QuestionsOrder>
</AppCard>
</AppCard>
</div>
</div>
<PreviewDialog
v-model=
"previewDialogVisible"
></PreviewDialog>
<PreviewDialog
v-model=
"previewDialogVisible"
v-if=
"previewDialogVisible"
></PreviewDialog>
</
template
>
</
template
>
<
style
lang=
"scss"
scoped
>
<
style
lang=
"scss"
scoped
>
.btn-box
{
.btn-box
{
...
...
src/modules/admin/lab/experiment/views/View.vue
浏览文件 @
5dabc6d8
<
script
setup
lang=
"ts"
>
<
script
setup
lang=
"ts"
>
import
type
{
ExperimentItem
,
ClassItem
}
from
'../types'
import
type
{
ExperimentItem
,
ClassItem
}
from
'../types'
import
{
CirclePlus
,
CopyDocument
,
Setting
,
Edit
,
EditPen
}
from
'@element-plus/icons-vue'
import
{
CirclePlus
}
from
'@element-plus/icons-vue'
import
{
ElMessage
,
ElMessageBox
}
from
'element-plus'
import
{
ElMessage
,
ElMessageBox
}
from
'element-plus'
import
AppList
from
'@/components/base/AppList.vue'
import
AppList
from
'@/components/base/AppList.vue'
...
@@ -28,7 +28,7 @@ provide('detail', $$(detail))
...
@@ -28,7 +28,7 @@ provide('detail', $$(detail))
const
teacherText
=
$computed
(()
=>
{
const
teacherText
=
$computed
(()
=>
{
if
(
!
detail
)
return
''
if
(
!
detail
)
return
''
return
detail
.
teacher
.
map
(
item
=>
item
.
name
).
join
(
'、'
)
return
detail
.
teacher
.
map
(
(
item
)
=>
item
.
name
).
join
(
'、'
)
})
})
const
appList
=
$ref
<
InstanceType
<
typeof
AppList
>
|
null
>
(
null
)
const
appList
=
$ref
<
InstanceType
<
typeof
AppList
>
|
null
>
(
null
)
...
@@ -41,7 +41,7 @@ const listOptions = {
...
@@ -41,7 +41,7 @@ const listOptions = {
const
{
total
,
list
,
info
}
=
data
const
{
total
,
list
,
info
}
=
data
detail
=
info
detail
=
info
return
{
list
,
total
}
return
{
list
,
total
}
}
}
,
},
},
columns
:
[
columns
:
[
{
label
:
'序号'
,
type
:
'index'
,
width
:
60
},
{
label
:
'序号'
,
type
:
'index'
,
width
:
60
},
...
@@ -51,8 +51,8 @@ const listOptions = {
...
@@ -51,8 +51,8 @@ const listOptions = {
{
label
:
'已完成人数'
,
prop
:
'complete_nums'
},
{
label
:
'已完成人数'
,
prop
:
'complete_nums'
},
{
label
:
'未完成人数'
,
prop
:
'not_complete_nums'
},
{
label
:
'未完成人数'
,
prop
:
'not_complete_nums'
},
{
label
:
'更新时间'
,
prop
:
'updated_time'
},
{
label
:
'更新时间'
,
prop
:
'updated_time'
},
{
label
:
'操作'
,
slots
:
'table-x'
,
width
:
300
}
{
label
:
'操作'
,
slots
:
'table-x'
,
width
:
300
}
,
]
]
,
}
}
// 刷新
// 刷新
function
handleRefetch
()
{
function
handleRefetch
()
{
...
@@ -120,16 +120,18 @@ function handleUpdateGradeRules() {
...
@@ -120,16 +120,18 @@ function handleUpdateGradeRules() {
</el-button>
</el-button>
<el-button
type=
"primary"
@
click=
"gradeRulesVisible = true"
>
查看成绩规则
</el-button>
<el-button
type=
"primary"
@
click=
"gradeRulesVisible = true"
>
查看成绩规则
</el-button>
<el-button
type=
"primary"
@
click=
"reportRulesVisible = true"
>
查看报告规则
</el-button>
<el-button
type=
"primary"
@
click=
"reportRulesVisible = true"
>
查看报告规则
</el-button>
<el-button
type=
"primary"
:icon=
"CopyDocument"
@
click=
"handleCopy()"
>
复制实验
</el-button>
<el-button
type=
"primary"
@
click=
"handleCopy()"
>
复制实验
</el-button>
<el-button
type=
"primary"
:icon=
"Setting"
@
click=
"handleUpdateDML()"
:disabled=
"detail?.type !== '4'"
<el-button
type=
"primary"
@
click=
"handleUpdateDML()"
v-if=
"detail?.type === '4'"
>
配置数字营销
</el-button>
>
配置数字营销
</el-button
<el-button
type=
"primary"
>
>
<router-link
:to=
"
{ path: '/admin/lab/score', query: { course_id: detail?.course_id, experiment_id: detail?.id } }"
target="_blank"
>实验评分
</router-link
>
</el-button>
<template
v-if=
"!detail?.stu_commit_count"
>
<template
v-if=
"!detail?.stu_commit_count"
>
<el-button
type=
"primary"
:icon=
"Edit"
@
click=
"handleUpdateGradeRules()"
>
编辑成绩规则
</el-button>
<el-button
type=
"primary"
@
click=
"handleUpdateGradeRules()"
>
编辑成绩规则
</el-button>
<!--
<el-dropdown-item
:icon=
"EditPen"
>
<el-button
type=
"primary"
>
<router-link
:to=
"`/admin/lab/experiment/report/$
{row.id}`" target="_blank">编辑报告规则
</router-link>
</el-dropdown-item>
-->
<el-button
type=
"primary"
:icon=
"EditPen"
>
<router-link
:to=
"`/admin/lab/experiment/report/$
{detail?.id}`" target="_blank">编辑报告规则
</router-link>
<router-link
:to=
"`/admin/lab/experiment/report/$
{detail?.id}`" target="_blank">编辑报告规则
</router-link>
</el-button>
</el-button>
</
template
>
</
template
>
...
@@ -197,15 +199,13 @@ function handleUpdateGradeRules() {
...
@@ -197,15 +199,13 @@ function handleUpdateGradeRules() {
<StudentGroupDialog
<StudentGroupDialog
v-model=
"studentGroupVisible"
v-model=
"studentGroupVisible"
:data=
"rowData"
:data=
"rowData"
v-if=
"studentGroupVisible && rowData"
v-if=
"studentGroupVisible && rowData"
></StudentGroupDialog>
></StudentGroupDialog>
<!-- 查看学生 -->
<!-- 查看学生 -->
<StudentListDialog
<StudentListDialog
v-model=
"studentListVisible"
v-model=
"studentListVisible"
:data=
"rowData"
:data=
"rowData"
:experimentId=
"id"
:experimentId=
"id"
v-if=
"studentListVisible && rowData"
v-if=
"studentListVisible && rowData"
></StudentListDialog>
></StudentListDialog>
<ViewGradeRules
v-model=
"gradeRulesVisible"
:data=
"detail"
v-if=
"gradeRulesVisible && detail"
></ViewGradeRules>
<ViewGradeRules
v-model=
"gradeRulesVisible"
:data=
"detail"
v-if=
"gradeRulesVisible && detail"
></ViewGradeRules>
<ViewReportRules
v-model=
"reportRulesVisible"
:experiment_id=
"id"
v-if=
"reportRulesVisible"
></ViewReportRules>
<ViewReportRules
v-model=
"reportRulesVisible"
:experiment_id=
"id"
v-if=
"reportRulesVisible"
></ViewReportRules>
<CopyDialog
v-model=
"copyDialogVisible"
:data=
"detail"
v-if=
"copyDialogVisible && detail"
></CopyDialog>
<CopyDialog
v-model=
"copyDialogVisible"
:data=
"detail"
v-if=
"copyDialogVisible && detail"
></CopyDialog>
...
@@ -215,6 +215,5 @@ function handleUpdateGradeRules() {
...
@@ -215,6 +215,5 @@ function handleUpdateGradeRules() {
<GradeRulesDialog
<GradeRulesDialog
v-model=
"gradeRulesDialogVisible"
v-model=
"gradeRulesDialogVisible"
:data=
"detail"
:data=
"detail"
v-if=
"gradeRulesDialogVisible && detail"
v-if=
"gradeRulesDialogVisible && detail"
></GradeRulesDialog>
></GradeRulesDialog>
</template>
</template>
src/modules/admin/lab/score/api.ts
浏览文件 @
5dabc6d8
...
@@ -24,14 +24,20 @@ export function getExperimentRecord(params: { experiment_id: string; student_id:
...
@@ -24,14 +24,20 @@ export function getExperimentRecord(params: { experiment_id: string; student_id:
}
}
// 实验记录评分
// 实验记录评分
export
function
checkExperimentRecord
(
data
:
{
experiment_id
:
string
;
student_id
:
string
;
operate
:
number
;
result
:
number
;
file
:
number
})
{
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
)
return
httpRequest
.
post
(
'/api/lab/v1/teacher/record/check'
,
data
)
}
}
// 批量导入实验记录评分
// 批量导入实验记录评分
export
function
uploadCheckExperimentRecord
(
data
:
{
file
:
File
})
{
export
function
uploadCheckExperimentRecord
(
data
:
{
file
:
File
})
{
return
httpRequest
.
post
(
'/api/lab/v1/teacher/record/upload'
,
data
,
{
return
httpRequest
.
post
(
'/api/lab/v1/teacher/record/upload'
,
data
,
{
headers
:
{
'Content-Type'
:
'multipart/form-data'
}
headers
:
{
'Content-Type'
:
'multipart/form-data'
}
,
})
})
}
}
...
@@ -50,7 +56,12 @@ export function getExperimentReport(params: { experiment_id: string; student_id:
...
@@ -50,7 +56,12 @@ export function getExperimentReport(params: { experiment_id: string; student_id:
return
httpRequest
.
get
(
'/api/lab/v1/teacher/experiment/report-achievement'
,
{
params
})
return
httpRequest
.
get
(
'/api/lab/v1/teacher/experiment/report-achievement'
,
{
params
})
}
}
// 批改学员实验报告成绩
// 批改学员实验报告成绩
export
function
updateExperimentReport
(
data
:
{
experiment_id
:
string
;
student_id
:
string
;
score_detail
:
string
;
comment
:
string
})
{
export
function
updateExperimentReport
(
data
:
{
experiment_id
:
string
student_id
:
string
score_detail
:
string
comment
:
string
})
{
return
httpRequest
.
post
(
'/api/lab/v1/teacher/experiment/report-check'
,
data
)
return
httpRequest
.
post
(
'/api/lab/v1/teacher/experiment/report-check'
,
data
)
}
}
...
@@ -106,3 +117,8 @@ export function syncExperimentExam(params: { experiment_id: string }) {
...
@@ -106,3 +117,8 @@ export function syncExperimentExam(params: { experiment_id: string }) {
export
function
recordReject
(
params
:
{
experiment_id
:
string
;
student_id
:
string
})
{
export
function
recordReject
(
params
:
{
experiment_id
:
string
;
student_id
:
string
})
{
return
httpRequest
.
get
(
'/api/lab/v1/teacher/record/reject'
,
{
params
})
return
httpRequest
.
get
(
'/api/lab/v1/teacher/record/reject'
,
{
params
})
}
}
// 教师查看分数详情页面
export
function
getExperimentScoreDetail
(
params
:
{
experiment_id
:
string
;
student_id
:
string
;
type
:
string
})
{
return
httpRequest
.
get
(
'/api/lab/v1/teacher/experiment/score-detail'
,
{
params
})
}
src/modules/admin/lab/score/components/ScoreDialog.vue
浏览文件 @
5dabc6d8
...
@@ -9,6 +9,7 @@ const appConfig = useAppConfig()
...
@@ -9,6 +9,7 @@ const appConfig = useAppConfig()
const
ScoreViewPicturesDialog
=
defineAsyncComponent
(()
=>
import
(
'./ScoreViewPicturesDialog.vue'
))
const
ScoreViewPicturesDialog
=
defineAsyncComponent
(()
=>
import
(
'./ScoreViewPicturesDialog.vue'
))
const
ScoreViewPrepareDialog
=
defineAsyncComponent
(()
=>
import
(
'./ScoreViewPrepareDialog.vue'
))
const
ScoreViewPrepareDialog
=
defineAsyncComponent
(()
=>
import
(
'./ScoreViewPrepareDialog.vue'
))
const
ScoreViewResultDialog
=
defineAsyncComponent
(()
=>
import
(
'./ScoreViewResultDialog.vue'
))
const
ScoreViewResultDialog
=
defineAsyncComponent
(()
=>
import
(
'./ScoreViewResultDialog.vue'
))
const
ScoreViewAutoDialog
=
defineAsyncComponent
(()
=>
import
(
'./ScoreViewAutoDialog.vue'
))
interface
Props
{
interface
Props
{
data
:
RecordItem
data
:
RecordItem
...
@@ -23,43 +24,45 @@ const emit = defineEmits<{
...
@@ -23,43 +24,45 @@ const emit = defineEmits<{
let
experiment
=
$ref
<
any
>
()
let
experiment
=
$ref
<
any
>
()
let
detail
=
$ref
<
any
>
()
let
detail
=
$ref
<
any
>
()
async
function
fetchInfo
()
{
async
function
fetchInfo
()
{
await
getExperimentScore
({
experiment_id
:
props
.
data
.
experiment_id
,
student_id
:
props
.
data
.
student_id
}).
then
(
async
res
=>
{
await
getExperimentScore
({
experiment_id
:
props
.
data
.
experiment_id
,
student_id
:
props
.
data
.
student_id
}).
then
(
experiment
=
res
.
data
.
experiment
async
(
res
)
=>
{
detail
=
res
.
data
.
achievement
experiment
=
res
.
data
.
experiment
if
(
detail
.
score_details
)
{
detail
=
res
.
data
.
achievement
try
{
if
(
detail
.
score_details
)
{
form
.
score_details
=
JSON
.
parse
(
detail
.
score_details
).
map
((
item
:
any
)
=>
{
try
{
return
{
form
.
score_details
=
JSON
.
parse
(
detail
.
score_details
).
map
((
item
:
any
)
=>
{
...
item
,
return
{
percent
:
parseFloat
(
item
.
percent
),
...
item
,
score
:
parseFloat
(
item
.
score
),
percent
:
parseFloat
(
item
.
percent
),
commit_score
:
parseFloat
(
item
.
commit_score
)
score
:
parseFloat
(
item
.
score
),
}
commit_score
:
parseFloat
(
item
.
commit_score
),
})
}
}
catch
(
error
)
{
})
}
catch
(
error
)
{
await
fetchTemplate
()
console
.
log
(
error
)
}
}
else
{
await
fetchTemplate
()
await
fetchTemplate
()
console
.
log
(
error
)
}
}
}
else
{
if
(
experiment
.
report_upload_way
===
2
)
{
await
fetchTemplate
()
await
fetchReport
()
}
}
if
(
experiment
.
report_upload_way
===
2
)
{
await
fetchReport
()
}
}
}
)
)
}
}
watchEffect
(()
=>
{
watchEffect
(()
=>
{
fetchInfo
()
fetchInfo
()
})
})
async
function
fetchTemplate
()
{
async
function
fetchTemplate
()
{
await
getExperimentScoreTemplate
({
experiment_id
:
props
.
data
.
experiment_id
}).
then
(
res
=>
{
await
getExperimentScoreTemplate
({
experiment_id
:
props
.
data
.
experiment_id
}).
then
(
(
res
)
=>
{
form
.
score_details
=
res
.
data
.
detail
.
rule_list
.
map
((
item
:
any
)
=>
{
form
.
score_details
=
res
.
data
.
detail
.
rule_list
.
map
((
item
:
any
)
=>
{
return
{
return
{
...
item
,
...
item
,
percent
:
parseFloat
(
item
.
percent
),
percent
:
parseFloat
(
item
.
percent
),
score
:
parseFloat
(
item
.
score
),
score
:
parseFloat
(
item
.
score
),
commit_score
:
parseFloat
(
item
.
commit_score
)
commit_score
:
parseFloat
(
item
.
commit_score
)
,
}
}
})
})
})
})
...
@@ -68,16 +71,18 @@ async function fetchTemplate() {
...
@@ -68,16 +71,18 @@ async function fetchTemplate() {
// 获取实验报告分数
// 获取实验报告分数
let
report
=
$ref
<
any
>
()
let
report
=
$ref
<
any
>
()
async
function
fetchReport
()
{
async
function
fetchReport
()
{
await
getExperimentReport
({
experiment_id
:
props
.
data
.
experiment_id
,
student_id
:
props
.
data
.
student_id
}).
then
(
res
=>
{
await
getExperimentReport
({
experiment_id
:
props
.
data
.
experiment_id
,
student_id
:
props
.
data
.
student_id
}).
then
(
report
=
res
.
data
.
detail
(
res
)
=>
{
const
reportScore
=
parseFloat
(
report
.
score
||
0
)
report
=
res
.
data
.
detail
form
.
score_details
=
form
.
score_details
.
map
((
item
:
any
)
=>
{
const
reportScore
=
parseFloat
(
report
.
score
||
0
)
if
(
item
.
type
===
1
)
{
form
.
score_details
=
form
.
score_details
.
map
((
item
:
any
)
=>
{
item
.
commit_score
=
reportScore
if
(
item
.
type
===
1
)
{
}
item
.
commit_score
=
reportScore
return
item
}
})
return
item
})
})
}
)
}
}
// 实验报告文件
// 实验报告文件
...
@@ -93,7 +98,7 @@ const file = $computed<FileItem>(() => {
...
@@ -93,7 +98,7 @@ const file = $computed<FileItem>(() => {
const
form
=
reactive
<
any
>
({
const
form
=
reactive
<
any
>
({
experiment_id
:
props
.
data
.
experiment_id
,
experiment_id
:
props
.
data
.
experiment_id
,
student_id
:
props
.
data
.
student_id
,
student_id
:
props
.
data
.
student_id
,
score_details
:
[]
score_details
:
[]
,
})
})
const
score
=
$computed
<
number
>
(()
=>
{
const
score
=
$computed
<
number
>
(()
=>
{
...
@@ -105,14 +110,16 @@ const score = $computed<number>(() => {
...
@@ -105,14 +110,16 @@ const score = $computed<number>(() => {
// 提交
// 提交
function
handleSubmit
()
{
function
handleSubmit
()
{
ElMessageBox
.
confirm
(
'更改成绩之后将以最新成绩为准,您可以查看批改成绩历史数据,确定需要修改成绩吗?'
,
'提示'
).
then
(()
=>
{
ElMessageBox
.
confirm
(
'更改成绩之后将以最新成绩为准,您可以查看批改成绩历史数据,确定需要修改成绩吗?'
,
'提示'
).
then
(
const
params
=
{
...
form
,
score_details
:
JSON
.
stringify
(
form
.
score_details
)
}
()
=>
{
updateExperimentScore
(
params
).
then
(()
=>
{
const
params
=
{
...
form
,
score_details
:
JSON
.
stringify
(
form
.
score_details
)
}
ElMessage
({
message
:
'保存成功'
,
type
:
'success'
})
updateExperimentScore
(
params
).
then
(()
=>
{
emit
(
'update'
)
ElMessage
({
message
:
'保存成功'
,
type
:
'success'
})
emit
(
'update:modelValue'
,
false
)
emit
(
'update'
)
})
emit
(
'update:modelValue'
,
false
)
})
})
}
)
}
}
function
scoreValue
(
value
:
any
)
{
function
scoreValue
(
value
:
any
)
{
...
@@ -146,10 +153,22 @@ function getOperationUrl(type: number) {
...
@@ -146,10 +153,22 @@ function getOperationUrl(type: number) {
return
`
${
dmlURL
}
/material?experiment_id=
${
props
.
data
.
experiment_id
}
&student_id=
${
props
.
data
.
student_id
}
`
return
`
${
dmlURL
}
/material?experiment_id=
${
props
.
data
.
experiment_id
}
&student_id=
${
props
.
data
.
student_id
}
`
}
}
}
}
const
autoVisible
=
ref
(
false
)
const
currentRow
=
ref
(
null
)
function
handleViewAuto
(
row
:
any
)
{
autoVisible
.
value
=
true
currentRow
.
value
=
row
}
</
script
>
</
script
>
<
template
>
<
template
>
<el-dialog
title=
"学生实验评分"
:close-on-click-modal=
"false"
width=
"800px"
@
update:modelValue=
"value => $emit('update:modelValue', value)"
>
<el-dialog
title=
"学生实验评分"
:close-on-click-modal=
"false"
width=
"800px"
@
update:modelValue=
"(value) => $emit('update:modelValue', value)"
>
<el-form
label-width=
"120px"
label-suffix=
":"
v-if=
"detail"
>
<el-form
label-width=
"120px"
label-suffix=
":"
v-if=
"detail"
>
<el-row>
<el-row>
<el-col
:span=
"12"
>
<el-col
:span=
"12"
>
...
@@ -189,12 +208,16 @@ function getOperationUrl(type: number) {
...
@@ -189,12 +208,16 @@ function getOperationUrl(type: number) {
<p
class=
"t1"
>
{{
scoreValue
(
score
)
}}
</p>
<p
class=
"t1"
>
{{
scoreValue
(
score
)
}}
</p>
<p
class=
"t2"
>
满分:
{{
experiment
.
score
}}
</p>
<p
class=
"t2"
>
满分:
{{
experiment
.
score
}}
</p>
</div>
</div>
<el-table
:data=
"form.score_details"
stripe
:header-cell-style=
"
{ background: '#ededed' }" style="margin-top: 20px">
<el-table
<el-table-column
label=
"实验成绩组成项"
prop=
"name"
align=
"center"
></el-table-column>
:data=
"form.score_details"
<el-table-column
label=
"权重"
prop=
"percent"
align=
"center"
>
stripe
:header-cell-style=
"
{ background: '#ededed' }"
style="margin-top: 20px">
<el-table-column
label=
"实验成绩组成项"
prop=
"name"
align=
"left"
></el-table-column>
<el-table-column
label=
"权重"
prop=
"percent"
align=
"center"
width=
"80"
>
<template
#
default=
"
{ row }">
{{
row
.
percent
}}
%
</
template
>
<template
#
default=
"
{ row }">
{{
row
.
percent
}}
%
</
template
>
</el-table-column>
</el-table-column>
<el-table-column
label=
"满分"
prop=
"score"
align=
"center"
>
100
</el-table-column>
<el-table-column
label=
"满分"
prop=
"score"
align=
"center"
width=
"100"
>
100
</el-table-column>
<el-table-column
label=
"得分"
prop=
"commit_score"
align=
"center"
>
<el-table-column
label=
"得分"
prop=
"commit_score"
align=
"center"
>
<
template
#
default=
"{ row }"
>
<
template
#
default=
"{ row }"
>
<el-input-number
<el-input-number
...
@@ -210,22 +233,29 @@ function getOperationUrl(type: number) {
...
@@ -210,22 +233,29 @@ function getOperationUrl(type: number) {
<span
v-else
>
{{
row
.
commit_score
}}
</span>
<span
v-else
>
{{
row
.
commit_score
}}
</span>
</
template
>
</
template
>
</el-table-column>
</el-table-column>
<el-table-column
label=
"操作"
prop=
"commit_score"
align=
"center
"
>
<el-table-column
label=
"操作"
align=
"center"
width=
"180
"
>
<
template
#
default=
"{ row }"
>
<
template
#
default=
"{ row }"
>
<template
v-if=
"row.type === 1"
>
<template
v-if=
"row.type === 1"
>
<el-button
text
type=
"primary"
v-if=
"experiment.report_upload_way === 2"
>
<el-button
link
type=
"primary"
v-if=
"experiment.report_upload_way === 2"
>
<a
:href=
"getOperationUrl(row.type)"
target=
"_blank"
>
批改
</a>
<a
:href=
"getOperationUrl(row.type)"
target=
"_blank"
>
批改
</a>
</el-button>
</el-button>
<template
v-if=
"experiment.report_upload_way === 1"
>
<template
v-if=
"experiment.report_upload_way === 1"
>
<el-button
text
type=
"primary"
v-if=
"file?.url"
>
<el-button
link
type=
"primary"
v-if=
"file?.url"
>
<a
:href=
"file.url"
target=
"_blank"
>
查阅报告
</a>
<a
:href=
"file.url"
target=
"_blank"
>
查阅报告
</a>
</el-button>
</el-button>
<p
style=
"color: red"
v-else
>
未上传
</p>
<p
style=
"color: red"
v-else
>
未上传
</p>
</
template
>
</
template
>
</template>
</template>
<
template
v-else-if=
"[6, 7, 8, 9, 10].includes(row.type)"
>
<
template
v-if=
"[6, 7, 9, 11, 12].includes(row.type)"
>
<el-button
text
type=
"primary"
>
<el-button
link
type=
"primary"
@
click=
"handleViewAuto(row)"
>
查看自动评分结果
</el-button>
<a
:href=
"`/admin/lab/score/score?id=$
{props.data.experiment_id}
&
sid=${props.data.student_id}
&
type=${row.type}`" target="_blank">查看结果
</a>
</
template
>
<
template
v-if=
"[6, 7, 8, 9, 10, 11, 12].includes(row.type)"
>
<el-button
link
type=
"primary"
>
<a
:href=
"`/admin/lab/score/score?id=$
{props.data.experiment_id}
&
sid=${props.data.student_id}
&
type=${row.type}`"
target="_blank"
>查看原始结果
</a
>
</el-button>
</el-button>
</
template
>
</
template
>
</template>
</template>
...
@@ -253,7 +283,16 @@ function getOperationUrl(type: number) {
...
@@ -253,7 +283,16 @@ function getOperationUrl(type: number) {
:student_id=
"data.student_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>
<ScoreViewPicturesDialog
v-model=
"pictureVisible"
:data=
"detail"
v-if=
"pictureVisible && detail"
></ScoreViewPicturesDialog>
<!-- 实验截图 -->
<ScoreViewAutoDialog
v-model=
"autoVisible"
:data=
"detail"
:row=
"currentRow"
v-if=
"autoVisible"
></ScoreViewAutoDialog>
</el-dialog>
</el-dialog>
</template>
</template>
...
...
src/modules/admin/lab/score/components/ScoreViewAutoDialog.vue
0 → 100644
浏览文件 @
5dabc6d8
<
script
setup
lang=
"ts"
>
import
type
{
RecordItem
}
from
'../types'
import
AppList
from
'@/components/base/AppList.vue'
import
{
getExperimentScoreDetail
}
from
'../api'
import
{
gradeRule
}
from
'@/utils/dictionary'
import
{
useAppConfig
}
from
'@/composables/useAppConfig'
const
appConfig
=
useAppConfig
()
interface
Props
{
data
:
RecordItem
row
:
any
}
const
props
=
defineProps
<
Props
>
()
let
datalist
=
$ref
<
any
>
([])
function
fetchInfo
()
{
getExperimentScoreDetail
({
experiment_id
:
props
.
data
.
experiment_id
,
student_id
:
props
.
data
.
student_id
,
type
:
props
.
row
.
type
,
}).
then
((
res
)
=>
{
datalist
=
res
.
data
})
}
watchEffect
(()
=>
{
fetchInfo
()
})
const
appList
=
$ref
<
InstanceType
<
typeof
AppList
>
|
null
>
(
null
)
const
title
=
computed
(()
=>
{
return
'查看'
+
gradeRule
[
props
.
row
.
type
]
})
// 列表配置
const
listOptions
=
computed
(()
=>
{
let
columns
:
any
=
[]
switch
(
props
.
row
.
type
)
{
case
6
:
// 用户标签
columns
=
[
{
label
:
'序号'
,
type
:
'index'
,
width
:
60
},
{
label
:
'标签名称'
,
prop
:
'student_name'
},
{
label
:
'正确标签名称'
,
prop
:
'teacher_name'
},
{
label
:
'标签数据量'
,
prop
:
'student_total'
},
{
label
:
'正确标签数据量'
,
prop
:
'teacher_total'
},
{
label
:
'操作'
,
prop
:
'status'
,
slots
:
'table-x'
},
]
break
case
7
:
// 用户群组
columns
=
[
{
label
:
'序号'
,
type
:
'index'
,
width
:
60
},
{
label
:
'群组名称'
,
prop
:
'student_name'
},
{
label
:
'正确群组名称'
,
prop
:
'teacher_name'
},
{
label
:
'群组数据量'
,
prop
:
'student_total'
},
{
label
:
'正确群组数据量'
,
prop
:
'teacher_total'
},
{
label
:
'操作'
,
prop
:
'status'
,
slots
:
'table-x'
},
]
break
case
9
:
// 营销资料
columns
=
[
{
label
:
'序号'
,
type
:
'index'
,
width
:
60
},
{
label
:
'营销资料名称'
,
prop
:
'student_name'
},
{
label
:
'营销资料类型'
,
prop
:
'type_name'
},
{
label
:
'正确营销资料名称'
,
prop
:
'teacher_name'
},
{
label
:
'AI综合评分'
,
prop
:
'score'
},
{
label
:
'AI评价'
,
prop
:
'comment'
},
]
break
case
11
:
// 用户数据
columns
=
[
{
label
:
'序号'
,
type
:
'index'
,
width
:
60
},
{
label
:
'文件名称'
,
prop
:
'file_name'
},
{
label
:
'用户数据量'
,
prop
:
'student_total'
},
{
label
:
'正确答案'
,
prop
:
'teacher_total'
},
{
label
:
'导入时间'
,
prop
:
'created_time'
},
{
label
:
'状态'
,
prop
:
'status'
},
]
break
case
12
:
// 事件数据
columns
=
[
{
label
:
'序号'
,
type
:
'index'
,
width
:
60
},
{
label
:
'文件名称'
,
prop
:
'file_name'
},
{
label
:
'事件名称'
,
prop
:
'event_name'
},
{
label
:
'事件数据量'
,
prop
:
'student_total'
},
{
label
:
'正确答案'
,
prop
:
'teacher_total'
},
{
label
:
'导入时间'
,
prop
:
'created_time'
},
{
label
:
'状态'
,
prop
:
'status'
},
]
break
default
:
break
}
return
{
columns
,
data
:
datalist
,
}
})
function
getOperationUrl
(
row
:
any
)
{
const
type
=
props
.
row
.
type
const
dmlURL
=
appConfig
.
dmlURL
||
import
.
meta
.
env
.
VITE_DML_URL
if
(
type
===
6
)
{
// 用户标签
return
`
${
dmlURL
}
/label?experiment_id=
${
props
.
data
.
experiment_id
}
&student_id=
${
props
.
data
.
student_id
}
&id=
${
row
.
id
}
&name=
${
row
.
student_name
}
`
}
else
if
(
type
===
7
)
{
// 用户群组
return
`
${
dmlURL
}
/group?experiment_id=
${
props
.
data
.
experiment_id
}
&student_id=
${
props
.
data
.
student_id
}
&id=
${
row
.
id
}
&name=
${
row
.
student_name
}
`
}
}
</
script
>
<
template
>
<el-dialog
:title=
"title"
width=
"800px"
>
<AppList
v-bind=
"listOptions"
ref=
"appList"
>
<template
#
table-x=
"
{ row }">
<el-button
type=
"primary"
link
>
<a
:href=
"getOperationUrl(row)"
target=
"_blank"
>
查看
</a>
</el-button>
</
template
>
</AppList>
<
template
#
footer
>
<el-row
justify=
"center"
>
<el-button
round
auto-insert-space
@
click=
"$emit('update:modelValue', false)"
>
关闭
</el-button>
</el-row>
</
template
>
</el-dialog>
</template>
src/modules/admin/lab/score/views/Index.vue
浏览文件 @
5dabc6d8
...
@@ -23,15 +23,15 @@ const appList = $ref<InstanceType<typeof AppList> | null>(null)
...
@@ -23,15 +23,15 @@ const appList = $ref<InstanceType<typeof AppList> | null>(null)
const
params
=
reactive
({
const
params
=
reactive
({
student_name
:
''
,
student_name
:
''
,
course_id
:
''
,
course_id
:
(
route
.
query
.
course_id
as
string
)
||
''
,
experiment_id
:
(
route
.
query
.
experiment_id
as
string
)
||
''
,
experiment_id
:
(
route
.
query
.
experiment_id
as
string
)
||
''
,
specialty_id
:
''
,
specialty_id
:
''
,
class_id
:
''
class_id
:
''
,
})
})
const
classList
=
$computed
(()
=>
{
const
classList
=
$computed
(()
=>
{
const
specialty
=
specialties
.
value
.
find
(
item
=>
item
.
id
===
params
.
specialty_id
)
const
specialty
=
specialties
.
value
.
find
(
(
item
)
=>
item
.
id
===
params
.
specialty_id
)
if
(
specialty
)
{
if
(
specialty
)
{
return
classes
.
value
.
filter
(
item
=>
item
.
specialty_id
===
specialty
.
id
)
return
classes
.
value
.
filter
(
(
item
)
=>
item
.
specialty_id
===
specialty
.
id
)
}
}
return
classes
.
value
return
classes
.
value
})
})
...
@@ -48,7 +48,7 @@ const listOptions = $computed(() => {
...
@@ -48,7 +48,7 @@ const listOptions = $computed(() => {
}
}
params
.
specialty_id
=
requestParams
.
specialty_id
||
''
params
.
specialty_id
=
requestParams
.
specialty_id
||
''
return
requestParams
return
requestParams
}
}
,
},
},
filterForm
:
{
labelWidth
:
100
},
filterForm
:
{
labelWidth
:
100
},
filters
:
[
filters
:
[
...
@@ -59,7 +59,7 @@ const listOptions = $computed(() => {
...
@@ -59,7 +59,7 @@ const listOptions = $computed(() => {
placeholder
:
'请选择实验课程名称'
,
placeholder
:
'请选择实验课程名称'
,
options
:
courses
.
value
,
options
:
courses
.
value
,
labelKey
:
'name'
,
labelKey
:
'name'
,
valueKey
:
'id'
valueKey
:
'id'
,
},
},
{
{
type
:
'select'
,
type
:
'select'
,
...
@@ -68,7 +68,7 @@ const listOptions = $computed(() => {
...
@@ -68,7 +68,7 @@ const listOptions = $computed(() => {
placeholder
:
'请选择实验名称'
,
placeholder
:
'请选择实验名称'
,
options
:
experiments
.
value
,
options
:
experiments
.
value
,
labelKey
:
'name'
,
labelKey
:
'name'
,
valueKey
:
'id'
valueKey
:
'id'
,
},
},
{
{
type
:
'select'
,
type
:
'select'
,
...
@@ -77,7 +77,7 @@ const listOptions = $computed(() => {
...
@@ -77,7 +77,7 @@ const listOptions = $computed(() => {
placeholder
:
'请选择专业'
,
placeholder
:
'请选择专业'
,
options
:
specialties
.
value
,
options
:
specialties
.
value
,
labelKey
:
'name'
,
labelKey
:
'name'
,
valueKey
:
'id'
valueKey
:
'id'
,
},
},
{
{
type
:
'select'
,
type
:
'select'
,
...
@@ -86,9 +86,9 @@ const listOptions = $computed(() => {
...
@@ -86,9 +86,9 @@ const listOptions = $computed(() => {
placeholder
:
'请选择班级'
,
placeholder
:
'请选择班级'
,
options
:
classList
,
options
:
classList
,
labelKey
:
'name'
,
labelKey
:
'name'
,
valueKey
:
'id'
valueKey
:
'id'
,
},
},
{
type
:
'input'
,
prop
:
'student_name'
,
label
:
'学生姓名'
,
placeholder
:
'请输入学生姓名'
}
{
type
:
'input'
,
prop
:
'student_name'
,
label
:
'学生姓名'
,
placeholder
:
'请输入学生姓名'
}
,
],
],
columns
:
[
columns
:
[
{
label
:
'序号'
,
type
:
'index'
,
width
:
60
},
{
label
:
'序号'
,
type
:
'index'
,
width
:
60
},
...
@@ -100,8 +100,8 @@ const listOptions = $computed(() => {
...
@@ -100,8 +100,8 @@ const listOptions = $computed(() => {
{
label
:
'提交状态'
,
prop
:
'status_name'
,
slots
:
'table-status'
},
{
label
:
'提交状态'
,
prop
:
'status_name'
,
slots
:
'table-status'
},
{
label
:
'考试成绩'
,
prop
:
'score'
,
slots
:
'table-score'
},
{
label
:
'考试成绩'
,
prop
:
'score'
,
slots
:
'table-score'
},
{
label
:
'更新时间'
,
prop
:
'commit_time'
},
{
label
:
'更新时间'
,
prop
:
'commit_time'
},
{
label
:
'操作'
,
slots
:
'table-x'
,
width
:
210
}
{
label
:
'操作'
,
slots
:
'table-x'
,
width
:
210
}
,
]
]
,
}
}
})
})
const
importVisible
=
$ref
(
false
)
const
importVisible
=
$ref
(
false
)
...
@@ -138,9 +138,28 @@ async function handleReset(row: RecordItem) {
...
@@ -138,9 +138,28 @@ async function handleReset(row: RecordItem) {
<template
#
header-buttons
>
<template
#
header-buttons
>
<el-row
justify=
"space-between"
>
<el-row
justify=
"space-between"
>
<div>
<div>
<el-button
type=
"primary"
round
:icon=
"Upload"
@
click=
"importVisible = true"
v-permission=
"'v1-teacher-record-upload'"
>
批量导入
</el-button>
<el-button
<el-button
type=
"primary"
round
:icon=
"Download"
@
click=
"exportVisible = true"
v-permission=
"'v1-teacher-record-download'"
>
批量导出
</el-button>
type=
"primary"
<el-button
type=
"primary"
round
:icon=
"Refresh"
@
click=
"syncVisible = true"
v-permission=
"'v1-teacher-record-sync-theory-score'"
round
:icon=
"Upload"
@
click=
"importVisible = true"
v-permission=
"'v1-teacher-record-upload'"
>
批量导入
</el-button
>
<el-button
type=
"primary"
round
:icon=
"Download"
@
click=
"exportVisible = true"
v-permission=
"'v1-teacher-record-download'"
>
批量导出
</el-button
>
<el-button
type=
"primary"
round
:icon=
"Refresh"
@
click=
"syncVisible = true"
v-permission=
"'v1-teacher-record-sync-theory-score'"
>
同步理论成绩
</el-button
>
同步理论成绩
</el-button
>
>
</div>
</div>
...
@@ -158,16 +177,34 @@ async function handleReset(row: RecordItem) {
...
@@ -158,16 +177,34 @@ async function handleReset(row: RecordItem) {
<span
:class=
"
{ 'is-info': row.score !== '--' }">
{{
row
.
score
}}
</span>
<span
:class=
"
{ 'is-info': row.score !== '--' }">
{{
row
.
score
}}
</span>
</
template
>
</
template
>
<
template
#
table-x=
"{ row }"
>
<
template
#
table-x=
"{ row }"
>
<el-button
text
type=
"primary"
v-if=
"row.status === 1 || row.status === 2"
@
click=
"handleScore(row)"
v-permission=
"'v1-teacher-record-check'"
<el-button
link
type=
"primary"
v-if=
"row.status === 1 || row.status === 2"
@
click=
"handleScore(row)"
v-permission=
"'v1-teacher-record-check'"
>
打分
</el-button
>
打分
</el-button
>
>
<el-button
text
type=
"primary"
v-if=
"row.status === 1 || row.status === 2"
@
click=
"handleReset(row)"
>
重置
</el-button>
<el-button
link
type=
"primary"
v-if=
"row.status === 1 || row.status === 2"
@
click=
"handleReset(row)"
<el-button
text
type=
"primary"
v-if=
"row.has_score_log"
@
click=
"handleScoreLog(row)"
v-permission=
"'v1-teacher-record-check'"
>
查看历史成绩
</el-button>
>
重置
</el-button
>
<el-button
link
type=
"primary"
v-if=
"row.has_score_log"
@
click=
"handleScoreLog(row)"
v-permission=
"'v1-teacher-record-check'"
>
查看历史成绩
</el-button
>
</
template
>
</
template
>
</AppList>
</AppList>
</AppCard>
</AppCard>
<!-- 评分 -->
<!-- 评分 -->
<ScoreDialog
v-model=
"dialogVisible"
:data=
"rowData"
@
update=
"onUpdateSuccess"
v-if=
"dialogVisible && rowData"
></ScoreDialog>
<ScoreDialog
v-model=
"dialogVisible"
:data=
"rowData"
@
update=
"onUpdateSuccess"
v-if=
"dialogVisible && rowData"
></ScoreDialog>
<!-- 历史成绩 -->
<!-- 历史成绩 -->
<ScoreLogDialog
v-model=
"scoreLogVisible"
:data=
"rowData"
v-if=
"scoreLogVisible && rowData"
></ScoreLogDialog>
<ScoreLogDialog
v-model=
"scoreLogVisible"
:data=
"rowData"
v-if=
"scoreLogVisible && rowData"
></ScoreLogDialog>
<!-- 批量导入 -->
<!-- 批量导入 -->
...
...
src/modules/student/lab/api.ts
浏览文件 @
5dabc6d8
...
@@ -30,7 +30,12 @@ export function getExperimentVideoPlayInfo(params: { source_id: string }) {
...
@@ -30,7 +30,12 @@ export function getExperimentVideoPlayInfo(params: { source_id: string }) {
}
}
// 获取实验讨论交流
// 获取实验讨论交流
export
function
getExperimentDiscussList
(
params
:
{
experiment_id
:
string
;
tag
:
number
;
page
?:
number
;
'per-page'
?:
number
})
{
export
function
getExperimentDiscussList
(
params
:
{
experiment_id
:
string
tag
:
number
page
?:
number
'per-page'
?:
number
})
{
return
httpRequest
.
get
(
'/api/lab/v1/student/experiment-topic/list'
,
{
params
})
return
httpRequest
.
get
(
'/api/lab/v1/student/experiment-topic/list'
,
{
params
})
}
}
// 发表新话题
// 发表新话题
...
@@ -85,11 +90,21 @@ export function getExperimentReportTemplate(params: { experiment_id: string }) {
...
@@ -85,11 +90,21 @@ export function getExperimentReportTemplate(params: { experiment_id: string }) {
return
httpRequest
.
get
(
'/api/lab/v1/student/experiment/report-template'
,
{
params
})
return
httpRequest
.
get
(
'/api/lab/v1/student/experiment/report-template'
,
{
params
})
}
}
// 更新实验在线报告
// 更新实验在线报告
export
function
updateExperimentReport
(
data
:
{
experiment_id
:
string
;
experiment_address
:
string
;
experiment_date
:
string
;
detail
:
string
})
{
export
function
updateExperimentReport
(
data
:
{
experiment_id
:
string
experiment_address
:
string
experiment_date
:
string
detail
:
string
})
{
return
httpRequest
.
post
(
'/api/lab/v1/student/experiment/upload-online-report'
,
data
)
return
httpRequest
.
post
(
'/api/lab/v1/student/experiment/upload-online-report'
,
data
)
}
}
// 缓存实验在线报告
// 缓存实验在线报告
export
function
cacheExperimentReport
(
data
:
{
experiment_id
:
string
;
experiment_address
:
string
;
experiment_date
:
string
;
detail
:
string
})
{
export
function
cacheExperimentReport
(
data
:
{
experiment_id
:
string
experiment_address
:
string
experiment_date
:
string
detail
:
string
})
{
return
httpRequest
.
post
(
'/api/lab/v1/student/experiment/cache-online-report'
,
data
)
return
httpRequest
.
post
(
'/api/lab/v1/student/experiment/cache-online-report'
,
data
)
}
}
// 获取实验在线报告缓存
// 获取实验在线报告缓存
...
@@ -120,3 +135,8 @@ export function getExperimentQuestion(params: { experiment_id: string; id: strin
...
@@ -120,3 +135,8 @@ export function getExperimentQuestion(params: { experiment_id: string; id: strin
export
function
getExperimentExamList
(
params
:
{
experiment_id
:
string
})
{
export
function
getExperimentExamList
(
params
:
{
experiment_id
:
string
})
{
return
httpRequest
.
get
(
'/api/lab/v1/student/experiment-exam/exams'
,
{
params
})
return
httpRequest
.
get
(
'/api/lab/v1/student/experiment-exam/exams'
,
{
params
})
}
}
// 学生查看分数详情页面
export
function
getExperimentScoreDetail
(
params
:
{
experiment_id
:
string
;
type
:
string
})
{
return
httpRequest
.
get
(
'/api/lab/v1/student/experiment-question/score-detail'
,
{
params
})
}
src/modules/student/lab/components/Book.vue
浏览文件 @
5dabc6d8
...
@@ -12,12 +12,16 @@ interface Props {
...
@@ -12,12 +12,16 @@ interface Props {
course_id
?:
string
course_id
?:
string
}
}
const
props
=
defineProps
<
Props
>
()
const
props
=
defineProps
<
Props
>
()
const
emits
=
defineEmits
([
'empty'
])
let
list
=
$ref
<
ExperimentBookType
[]
>
([])
let
list
=
$ref
<
ExperimentBookType
[]
>
([])
function
fetchInfo
()
{
function
fetchInfo
()
{
if
(
!
props
.
experiment_id
)
return
if
(
!
props
.
experiment_id
)
return
getExperimentBookList
({
experiment_id
:
props
.
experiment_id
}).
then
(
res
=>
{
getExperimentBookList
({
experiment_id
:
props
.
experiment_id
}).
then
(
(
res
)
=>
{
list
=
res
.
data
.
items
list
=
res
.
data
.
items
if
(
list
.
length
===
0
)
{
emits
(
'empty'
)
}
})
})
}
}
watchEffect
(()
=>
{
watchEffect
(()
=>
{
...
@@ -34,7 +38,7 @@ function handleView(row: ExperimentBookType) {
...
@@ -34,7 +38,7 @@ function handleView(row: ExperimentBookType) {
log
.
upload
({
log
.
upload
({
event
:
'file_event'
,
event
:
'file_event'
,
action
:
'experiment_book_stu_watch_action'
,
action
:
'experiment_book_stu_watch_action'
,
data
:
{
experiment_id
:
props
.
experiment_id
,
course_id
:
props
.
course_id
,
book_id
:
row
.
id
}
data
:
{
experiment_id
:
props
.
experiment_id
,
course_id
:
props
.
course_id
,
book_id
:
row
.
id
}
,
})
})
}
}
// 关闭
// 关闭
...
...
src/modules/student/lab/components/Case.vue
浏览文件 @
5dabc6d8
...
@@ -8,12 +8,16 @@ interface Props {
...
@@ -8,12 +8,16 @@ interface Props {
course_id
?:
string
course_id
?:
string
}
}
const
props
=
defineProps
<
Props
>
()
const
props
=
defineProps
<
Props
>
()
const
emits
=
defineEmits
([
'empty'
])
let
detail
=
$ref
<
ExperimentBookType
>
()
let
detail
=
$ref
<
ExperimentBookType
>
()
function
fetchInfo
()
{
function
fetchInfo
()
{
if
(
!
props
.
experiment_id
)
return
if
(
!
props
.
experiment_id
)
return
getExperimentCase
({
experiment_id
:
props
.
experiment_id
}).
then
(
res
=>
{
getExperimentCase
({
experiment_id
:
props
.
experiment_id
}).
then
((
res
)
=>
{
detail
=
res
.
data
.
detail
detail
=
res
.
data
.
detail
||
{}
if
(
detail
&&
Object
.
keys
(
detail
).
length
===
0
)
{
emits
(
'empty'
)
}
})
})
}
}
watchEffect
(()
=>
{
watchEffect
(()
=>
{
...
...
src/modules/student/lab/components/Exam.vue
浏览文件 @
5dabc6d8
...
@@ -7,9 +7,15 @@ const appConfig = useAppConfig()
...
@@ -7,9 +7,15 @@ const appConfig = useAppConfig()
interface
Props
{
interface
Props
{
experiment_id
:
string
experiment_id
:
string
examStatus
?:
number
examStatus
?:
number
showInfo
?:
boolean
showIframe
?:
boolean
}
}
const
props
=
defineProps
<
Props
>
()
const
props
=
withDefaults
(
defineProps
<
Props
>
(),
{
showInfo
:
true
,
showIframe
:
false
,
})
const
model
=
defineModel
()
const
model
=
defineModel
()
const
emits
=
defineEmits
([
'empty'
])
const
cookies
=
useCookies
()
const
cookies
=
useCookies
()
...
@@ -22,39 +28,46 @@ const currentExam = computed(() => {
...
@@ -22,39 +28,46 @@ const currentExam = computed(() => {
// 考试平台 URL
// 考试平台 URL
const
examURL
=
computed
(()
=>
{
const
examURL
=
computed
(()
=>
{
if
(
!
currentExam
.
value
)
return
''
if
(
!
currentExam
.
value
)
return
''
return
appConfig
.
system
!==
'x'
||
props
.
examStatus
!==
0
return
appConfig
.
system
===
'x'
&&
props
.
examStatus
===
0
?
`
${
import
.
meta
.
env
.
VITE_EXAM_SHOW_URL
}
/exam/
${
currentExam
.
value
?.
exam_id
}
`
?
`
${
import
.
meta
.
env
.
VITE_EXAM_SHOW_URL
}
/exam/
${
: `
$
{
import
.
meta
.
env
.
VITE_EXAM_SHOW_URL
}
/exam/
$
{
currentExam
.
value
?.
exam_id
currentExam
.
value
?.
exam_id
}?
has_time
=
0
&
has_submit
=
0
&
has_save
=
1
&
show_answer
=
1
`
}?
has_time
=
0
&
has_submit
=
0
&
has_save
=
1
&
show_answer
=
1
`
: `
$
{
import
.
meta
.
env
.
VITE_EXAM_SHOW_URL
}
/exam/
$
{
currentExam
.
value
?.
exam_id
}
`
// return `
https
:
//dev.ezijing.com:5173/exam/7003551966412406784?has_time=0&has_submit=0&has_save=1&show_answer=1`
// return `
https
:
//dev.ezijing.com:5173/exam/7003551966412406784?has_time=0&has_submit=0&has_save=1&show_answer=1`
})
})
async
function
fetchInfo
()
{
async
function
fetchInfo
()
{
if
(
!
props
.
experiment_id
)
return
const
res
=
await
getExperimentExamList
({
experiment_id
:
props
.
experiment_id
})
const
res
=
await
getExperimentExamList
({
experiment_id
:
props
.
experiment_id
})
const
resCookies
=
res
.
data
.
cookies
const
resCookies
=
res
.
data
.
cookies
cookies
.
set
(
resCookies
.
key
,
resCookies
.
auth_key
,
{
domain
:
'.ezijing.com'
,
path
:
'/'
})
cookies
.
set
(
resCookies
.
key
,
resCookies
.
auth_key
,
{
domain
:
'.ezijing.com'
,
path
:
'/'
})
list
.
value
=
res
.
data
.
items
||
[]
list
.
value
=
res
.
data
.
items
||
[]
model
.
value
=
examURL
.
value
model
.
value
=
examURL
.
value
if
(
list
.
value
.
length
===
0
)
{
emits
(
'empty'
)
}
}
}
onMounted
(()
=>
{
watchEffect
(()
=>
{
fetchInfo
()
fetchInfo
()
})
})
</
script
>
</
script
>
<
template
>
<
template
>
<template
v-if=
"currentExam"
>
<template
v-if=
"currentExam"
>
<el-form
label-suffix=
":"
label-position=
"top"
v-if=
"
appConfig.system !== 'x'
"
>
<el-form
label-suffix=
":"
label-position=
"top"
v-if=
"
showInfo
"
>
<el-form-item
label=
"考试名称"
>
{{
currentExam
.
exam_info
.
name
}}
</el-form-item>
<el-form-item
label=
"考试名称"
>
{{
currentExam
.
exam_info
.
name
}}
</el-form-item>
<el-form-item
label=
"考试时间"
<el-form-item
label=
"考试时间"
>
{{
currentExam
.
exam_info
.
start_time
}}
~
{{
currentExam
.
exam_info
.
end_time
}}
</el-form-item
>
{{
currentExam
.
exam_info
.
start_time
}}
~
{{
currentExam
.
exam_info
.
end_time
}}
</el-form-item
>
>
</el-form>
</el-form>
<div
style=
"width: 100%; height: 100%"
v-if=
"props.examStatus === 0"
>
<iframe
<iframe
style=
"width: 100%; height: 100%"
allowfullscreen
class=
"iframe"
:src=
"examURL"
frameborder=
"0"
></iframe>
style=
"width: 100%; height: 100%"
</div>
allowfullscreen
<!--
<teleport
to=
".lab-box"
>
-->
class=
"iframe"
<!--
</teleport>
-->
:src=
"examURL"
frameborder=
"0"
v-if=
"showIframe"
></iframe>
</
template
>
</
template
>
<el-empty
description=
"暂无数据"
v-else
/>
<el-empty
description=
"暂无数据"
v-else
/>
</template>
</template>
src/modules/student/lab/components/Question.vue
浏览文件 @
5dabc6d8
...
@@ -2,9 +2,10 @@
...
@@ -2,9 +2,10 @@
import
{
getExperimentQuestionList
,
getExperimentQuestion
}
from
'../api'
import
{
getExperimentQuestionList
,
getExperimentQuestion
}
from
'../api'
import
{
Document
}
from
'@element-plus/icons-vue'
import
{
Document
}
from
'@element-plus/icons-vue'
import
{
filesize
}
from
'filesize'
import
{
filesize
}
from
'filesize'
import
{
saveAs
}
from
'file-saver'
interface
Props
{
interface
Props
{
experiment_id
:
string
,
experiment_id
:
string
exam_status
?:
number
exam_status
?:
number
}
}
interface
QuestionListItem
{
interface
QuestionListItem
{
...
@@ -20,6 +21,7 @@ interface QuestionGroupList {
...
@@ -20,6 +21,7 @@ interface QuestionGroupList {
}
}
const
props
=
defineProps
<
Props
>
()
const
props
=
defineProps
<
Props
>
()
const
emits
=
defineEmits
([
'empty'
])
const
questionIndex
=
ref
<
number
>
(
1
)
const
questionIndex
=
ref
<
number
>
(
1
)
const
questionId
=
computed
(()
=>
{
const
questionId
=
computed
(()
=>
{
...
@@ -45,6 +47,9 @@ async function fetchList() {
...
@@ -45,6 +47,9 @@ async function fetchList() {
if
(
!
props
.
experiment_id
)
return
if
(
!
props
.
experiment_id
)
return
const
res
=
await
getExperimentQuestionList
({
experiment_id
:
props
.
experiment_id
})
const
res
=
await
getExperimentQuestionList
({
experiment_id
:
props
.
experiment_id
})
questionList
.
value
=
res
.
data
.
items
questionList
.
value
=
res
.
data
.
items
if
(
questionList
.
value
.
length
===
0
)
{
emits
(
'empty'
)
}
}
}
watchEffect
(()
=>
{
watchEffect
(()
=>
{
if
(
props
.
experiment_id
)
fetchList
()
if
(
props
.
experiment_id
)
fetchList
()
...
@@ -52,19 +57,21 @@ watchEffect(() => {
...
@@ -52,19 +57,21 @@ watchEffect(() => {
// 试题详情
// 试题详情
const
questionDetail
=
ref
()
const
questionDetail
=
ref
()
const
file
=
ref
()
async
function
fetchDetail
()
{
async
function
fetchDetail
()
{
if
(
!
questionId
.
value
)
return
if
(
!
questionId
.
value
)
return
const
res
=
await
getExperimentQuestion
({
experiment_id
:
props
.
experiment_id
,
id
:
questionId
.
value
})
const
res
=
await
getExperimentQuestion
({
experiment_id
:
props
.
experiment_id
,
id
:
questionId
.
value
})
const
detail
=
res
.
data
.
detail
const
detail
=
res
.
data
.
detail
||
{}
let
files
=
[]
let
answer
:
any
=
{}
try
{
try
{
files
=
JSON
.
parse
(
detail
.
files
)
answer
=
JSON
.
parse
(
detail
.
answer
)
file
.
value
=
answer
.
data
?.
file
||
{}
}
catch
(
error
)
{
}
catch
(
error
)
{
console
.
log
(
error
)
console
.
log
(
error
)
}
}
questionDetail
.
value
=
{
...
detail
,
files
,
score
:
parseFloat
(
detail
.
score
)
}
questionDetail
.
value
=
{
...
detail
,
answer
,
score
:
parseFloat
(
detail
.
score
)
}
}
}
watch
(
questionId
,
id
=>
{
watch
(
questionId
,
(
id
)
=>
{
if
(
id
)
fetchDetail
()
if
(
id
)
fetchDetail
()
})
})
...
@@ -79,7 +86,9 @@ function handleNext() {
...
@@ -79,7 +86,9 @@ function handleNext() {
}
}
function
getQuestionTypeName
(
type
:
string
)
{
function
getQuestionTypeName
(
type
:
string
)
{
if
([
'101'
,
'102'
].
includes
(
type
))
return
'用户/事件管理'
if
([
'101'
].
includes
(
type
))
return
'用户管理'
if
([
'102'
].
includes
(
type
))
return
'事件管理'
// if (['101', '102'].includes(type)) return '用户/事件管理'
if
([
'201'
,
'202'
].
includes
(
type
))
return
'标签管理'
if
([
'201'
,
'202'
].
includes
(
type
))
return
'标签管理'
if
([
'301'
,
'302'
].
includes
(
type
))
return
'群组管理'
if
([
'301'
,
'302'
].
includes
(
type
))
return
'群组管理'
if
([
'401'
,
'402'
,
'403'
,
'404'
,
'405'
,
'406'
,
'407'
].
includes
(
type
))
return
'营销资料管理'
if
([
'401'
,
'402'
,
'403'
,
'404'
,
'405'
,
'406'
,
'407'
].
includes
(
type
))
return
'营销资料管理'
...
@@ -111,17 +120,18 @@ function customFloor(num: number) {
...
@@ -111,17 +120,18 @@ function customFloor(num: number) {
<el-card
shadow=
"never"
class=
"question-item"
v-if=
"questionDetail"
>
<el-card
shadow=
"never"
class=
"question-item"
v-if=
"questionDetail"
>
<h3
class=
"question-item__title"
>
{{
getQuestionTypeName
(
questionDetail
.
type
)
}}
</h3>
<h3
class=
"question-item__title"
>
{{
getQuestionTypeName
(
questionDetail
.
type
)
}}
</h3>
<p
class=
"question-item__stem"
>
<p
class=
"question-item__stem"
>
{{
questionIndex
}}
、
{{
questionDetail
.
title
}}
<span
v-if=
"props?.exam_status !== 1"
>
(
{{
questionDetail
.
score
}}
分)
</span>
{{
questionIndex
}}
、
{{
questionDetail
.
title
}}
<span>
(
{{
questionDetail
.
score
}}
分)
</span>
</p>
</p>
<p
class=
"question-item__content"
>
{{
questionDetail
.
content
}}
</p>
<p
class=
"question-item__content"
>
{{
questionDetail
.
content
}}
</p>
<ul
class=
"question-item__files"
>
<ul
class=
"question-item__files"
v-if=
"!!Object.keys(file).length"
>
<li
class=
"question-item__files-item"
v-for=
"(file, index) in questionDetail.files"
:key=
"index"
>
<li
class=
"question-item__files-item"
>
<el-icon><Document
/></el-icon>
<el-icon><Document
/></el-icon>
<div
class=
"question-item__files-item__title"
>
<div
class=
"question-item__files-item__title"
>
<p>
{{
file
.
name
}}
</p>
<p>
{{
file
.
name
}}
</p>
<p>
{{
filesize
(
file
.
size
)
}}
</p>
<p>
{{
filesize
(
file
.
size
)
}}
</p>
</div>
</div>
<a
:href=
"file.url"
target=
"_blank"
download
v-if=
"file.is_download
"
>
下载
</a>
<a
href=
"javascript:void(0)"
:download=
"file.name"
@
click=
"saveAs(file.url, file.name)
"
>
下载
</a>
<a
:href=
"file.url"
target=
"_blank"
>
查看
</a>
<a
:href=
"file.url"
target=
"_blank"
>
查看
</a>
</li>
</li>
</ul>
</ul>
...
...
src/modules/student/lab/components/ResultScoreDialog.vue
浏览文件 @
5dabc6d8
<
script
setup
lang=
"ts"
>
<
script
setup
lang=
"ts"
>
import
{
getExperimentScore
}
from
'../api'
import
{
getExperimentScore
}
from
'../api'
import
{
useAppConfig
}
from
'@/composables/useAppConfig'
const
appConfig
=
useAppConfig
()
const
ResultScoreViewAutoDialog
=
defineAsyncComponent
(()
=>
import
(
'./ResultScoreViewAutoDialog.vue'
))
interface
Props
{
interface
Props
{
experiment_id
:
string
experiment_id
:
string
}
}
import
{
useAppConfig
}
from
'@/composables/useAppConfig'
const
appConfig
=
useAppConfig
()
const
props
=
defineProps
<
Props
>
()
const
props
=
defineProps
<
Props
>
()
let
experiment
=
$ref
<
any
>
()
let
experiment
=
$ref
<
any
>
()
...
@@ -16,7 +19,7 @@ const classText = $computed(() => {
...
@@ -16,7 +19,7 @@ const classText = $computed(() => {
})
})
function
fetchInfo
()
{
function
fetchInfo
()
{
getExperimentScore
({
experiment_id
:
props
.
experiment_id
}).
then
(
res
=>
{
getExperimentScore
({
experiment_id
:
props
.
experiment_id
}).
then
(
(
res
)
=>
{
experiment
=
res
.
data
.
experiment
experiment
=
res
.
data
.
experiment
let
scoreDetails
=
[]
let
scoreDetails
=
[]
try
{
try
{
...
@@ -28,7 +31,7 @@ function fetchInfo() {
...
@@ -28,7 +31,7 @@ function fetchInfo() {
}
}
detail
=
Object
.
assign
(
res
.
data
.
achievement
,
{
detail
=
Object
.
assign
(
res
.
data
.
achievement
,
{
score
:
parseFloat
(
res
.
data
.
achievement
.
score
),
score
:
parseFloat
(
res
.
data
.
achievement
.
score
),
score_details
:
scoreDetails
score_details
:
scoreDetails
,
})
})
})
})
}
}
...
@@ -40,15 +43,54 @@ function getOperationUrl(type: number) {
...
@@ -40,15 +43,54 @@ function getOperationUrl(type: number) {
if
(
type
===
1
)
{
if
(
type
===
1
)
{
// 实验报告
// 实验报告
return
`/student/lab/report/view/
${
experiment
.
id
}
`
return
`/student/lab/report/view/
${
experiment
.
id
}
`
}
else
if
(
type
===
6
)
{
// 用户标签
return
`
${
appConfig
.
dmlURL
||
import
.
meta
.
env
.
VITE_DML_URL
}
/label?experiment_id=
${
experiment
.
id
}
&student_id=
${
experiment
.
student
.
id
}
`
}
else
if
(
type
===
7
)
{
// 用户群组
return
`
${
appConfig
.
dmlURL
||
import
.
meta
.
env
.
VITE_DML_URL
}
/group?experiment_id=
${
experiment
.
id
}
&student_id=
${
experiment
.
student
.
id
}
`
}
else
if
(
type
===
8
)
{
}
else
if
(
type
===
8
)
{
// 用户旅程
// 用户旅程
return
`
${
appConfig
.
dmlURL
||
import
.
meta
.
env
.
VITE_DML_URL
}
/trip/my/score?experiment_id=
${
experiment
.
id
}
&student_id=
${
experiment
.
student
.
id
}
`
return
`
${
appConfig
.
dmlURL
||
import
.
meta
.
env
.
VITE_DML_URL
}
/trip/my/score?experiment_id=
${
experiment
.
id
}
&student_id=
${
experiment
.
student
.
id
}
`
}
else
if
(
type
===
9
)
{
// 营销资料
return
`
${
appConfig
.
dmlURL
||
import
.
meta
.
env
.
VITE_DML_URL
}
/material?experiment_id=
${
experiment
.
id
}
&student_id=
${
experiment
.
student
.
id
}
`
}
else
if
(
type
===
11
)
{
// 用户数据
return
`
${
appConfig
.
dmlURL
||
import
.
meta
.
env
.
VITE_DML_URL
}
/user?experiment_id=
${
experiment
.
id
}
&student_id=
${
experiment
.
student
.
id
}
`
}
else
if
(
type
===
12
)
{
// 事件数据
return
`
${
appConfig
.
dmlURL
||
import
.
meta
.
env
.
VITE_DML_URL
}
/user?experiment_id=
${
experiment
.
id
}
&student_id=
${
experiment
.
student
.
id
}
`
}
else
{
// 去首页
return
`
${
appConfig
.
dmlURL
||
import
.
meta
.
env
.
VITE_DML_URL
}
/?experiment_id=
${
experiment
.
id
}
&student_id=
${
experiment
.
student
.
id
}
`
}
}
}
}
const
autoVisible
=
ref
(
false
)
const
currentRow
=
ref
(
null
)
function
handleViewAuto
(
row
:
any
)
{
autoVisible
.
value
=
true
currentRow
.
value
=
row
}
</
script
>
</
script
>
<
template
>
<
template
>
<el-dialog
title=
"实验成绩详情"
width=
"
6
00px"
>
<el-dialog
title=
"实验成绩详情"
width=
"
8
00px"
>
<el-form
label-width=
"120px"
label-suffix=
":"
v-if=
"detail"
>
<el-form
label-width=
"120px"
label-suffix=
":"
v-if=
"detail"
>
<el-form-item
label=
"实验名称"
>
{{
experiment
.
name
}}
</el-form-item>
<el-form-item
label=
"实验名称"
>
{{
experiment
.
name
}}
</el-form-item>
<el-form-item
label=
"实验课程名称"
>
{{
experiment
.
course
.
name
}}
</el-form-item>
<el-form-item
label=
"实验课程名称"
>
{{
experiment
.
course
.
name
}}
</el-form-item>
...
@@ -71,7 +113,9 @@ function getOperationUrl(type: number) {
...
@@ -71,7 +113,9 @@ function getOperationUrl(type: number) {
<el-row>
<el-row>
<el-col
:span=
"12"
>
<el-col
:span=
"12"
>
<el-form-item
label=
"评分教师"
>
<el-form-item
label=
"评分教师"
>
{{
detail
.
checker_sso_user
.
real_name
||
detail
.
checker_sso_user
.
nickname
||
detail
.
checker_sso_user
.
username
}}
{{
detail
.
checker_sso_user
.
real_name
||
detail
.
checker_sso_user
.
nickname
||
detail
.
checker_sso_user
.
username
}}
</el-form-item>
</el-form-item>
</el-col>
</el-col>
<el-col
:span=
"12"
>
<el-col
:span=
"12"
>
...
@@ -83,7 +127,11 @@ function getOperationUrl(type: number) {
...
@@ -83,7 +127,11 @@ function getOperationUrl(type: number) {
<p>
实验得分
</p>
<p>
实验得分
</p>
<p
class=
"t1"
>
{{
detail
.
score
}}
</p>
<p
class=
"t1"
>
{{
detail
.
score
}}
</p>
</div>
</div>
<el-table
:data=
"detail.score_details"
stripe
:header-cell-style=
"
{ background: '#ededed' }" v-if="detail.is_show === '1'">
<el-table
:data=
"detail.score_details"
stripe
:header-cell-style=
"
{ background: '#ededed' }"
v-if="detail.is_show === '1'">
<el-table-column
label=
"实验成绩组成项"
prop=
"name"
align=
"center"
></el-table-column>
<el-table-column
label=
"实验成绩组成项"
prop=
"name"
align=
"center"
></el-table-column>
<el-table-column
label=
"权重"
prop=
"percent"
align=
"center"
>
<el-table-column
label=
"权重"
prop=
"percent"
align=
"center"
>
<template
#
default=
"
{ row }">
{{
row
.
percent
}}
%
</
template
>
<template
#
default=
"
{ row }">
{{
row
.
percent
}}
%
</
template
>
...
@@ -99,6 +147,25 @@ function getOperationUrl(type: number) {
...
@@ -99,6 +147,25 @@ function getOperationUrl(type: number) {
</
template
>
</
template
>
</template>
</template>
</el-table-column>
</el-table-column>
<el-table-column
label=
"标准答案"
align=
"center"
width=
"80"
>
<
template
#
default=
"{ row }"
>
<el-button
type=
"primary"
link
@
click=
"handleViewAuto(row)"
v-if=
"[6, 7, 9, 11, 12].includes(row.type)"
>
查看
</el-button
>
</
template
>
</el-table-column>
<el-table-column
label=
"我的答案"
align=
"center"
width=
"80"
>
<
template
#
default=
"{ row }"
>
<el-button
link
type=
"primary"
>
<a
:href=
"getOperationUrl(row.type)"
target=
"_blank"
>
查看
</a>
</el-button>
</
template
>
</el-table-column>
<el-table-column
label=
"评语"
align=
"center"
width=
"80"
v-if=
"false"
>
<
template
#
default=
"{ row }"
>
<el-button
type=
"primary"
link
v-if=
"row.type === 9"
>
查看
</el-button>
</
template
>
</el-table-column>
</el-table>
</el-table>
</div>
</div>
</el-form>
</el-form>
...
@@ -107,6 +174,12 @@ function getOperationUrl(type: number) {
...
@@ -107,6 +174,12 @@ function getOperationUrl(type: number) {
<el-button
round
auto-insert-space
@
click=
"$emit('update:modelValue', false)"
>
关闭
</el-button>
<el-button
round
auto-insert-space
@
click=
"$emit('update:modelValue', false)"
>
关闭
</el-button>
</el-row>
</el-row>
</
template
>
</
template
>
<ResultScoreViewAutoDialog
v-model=
"autoVisible"
:data=
"experiment"
:row=
"currentRow"
v-if=
"currentRow"
></ResultScoreViewAutoDialog>
</el-dialog>
</el-dialog>
</template>
</template>
...
...
src/modules/student/lab/components/ResultScoreViewAutoDialog.vue
0 → 100644
浏览文件 @
5dabc6d8
<
script
setup
>
import
AppList
from
'@/components/base/AppList.vue'
import
{
getExperimentScoreDetail
}
from
'../api'
import
{
gradeRule
}
from
'@/utils/dictionary'
import
Preview
from
'@/components/Preview.vue'
import
{
useAppConfig
}
from
'@/composables/useAppConfig'
const
appConfig
=
useAppConfig
()
const
props
=
defineProps
({
data
:
{
type
:
Object
,
default
:
()
=>
({}),
},
row
:
{
type
:
Object
,
default
:
()
=>
({}),
},
})
let
datalist
=
$ref
([])
function
fetchInfo
()
{
getExperimentScoreDetail
({
experiment_id
:
props
.
data
.
id
,
type
:
props
.
row
.
type
,
}).
then
((
res
)
=>
{
datalist
=
res
.
data
})
}
watchEffect
(()
=>
{
fetchInfo
()
})
const
title
=
computed
(()
=>
{
return
'查看'
+
gradeRule
[
props
.
row
.
type
]
})
// 列表配置
const
listOptions
=
computed
(()
=>
{
let
columns
=
[]
switch
(
props
.
row
.
type
)
{
case
6
:
// 用户标签
columns
=
[
{
label
:
'序号'
,
type
:
'index'
,
width
:
60
},
{
label
:
'标签名称'
,
prop
:
'tag_name'
},
{
label
:
'操作'
,
prop
:
'status'
,
slots
:
'table-x'
},
]
break
case
7
:
// 用户群组
columns
=
[
{
label
:
'序号'
,
type
:
'index'
,
width
:
60
},
{
label
:
'群组名称'
,
prop
:
'group_name'
},
{
label
:
'操作'
,
prop
:
'status'
,
slots
:
'table-x'
},
]
break
case
9
:
// 营销资料
columns
=
[
{
label
:
'序号'
,
type
:
'index'
,
width
:
60
},
{
label
:
'资料名称'
,
prop
:
'material_name'
},
{
label
:
'资料类型'
,
prop
:
'type_name'
,
computed
()
{
return
'文本'
},
},
{
label
:
'评语'
,
prop
:
'comment'
},
{
label
:
'操作'
,
prop
:
'status'
,
slots
:
'table-x'
},
]
break
case
12
:
// 事件数据
columns
=
[
{
label
:
'序号'
,
type
:
'index'
,
width
:
60
},
{
label
:
'事件名称'
,
prop
:
'event_name'
},
{
label
:
'操作'
,
prop
:
'status'
,
slots
:
'table-x'
},
]
break
default
:
break
}
return
{
columns
,
data
:
datalist
,
}
})
function
getOperationUrl
(
row
)
{
const
type
=
props
.
row
.
type
const
dmlURL
=
appConfig
.
dmlURL
||
import
.
meta
.
env
.
VITE_DML_URL
if
(
type
===
6
)
{
// 用户标签
return
`
${
dmlURL
}
/label?experiment_id=
${
props
.
data
.
id
}
&student_id=
${
props
.
data
.
student
.
id
}
&id=
${
row
.
tag_id
}
&name=
${
row
.
tag_name
}
`
}
else
if
(
type
===
7
)
{
// 用户群组
return
`
${
dmlURL
}
/group?experiment_id=
${
props
.
data
.
id
}
&student_id=
${
props
.
data
.
student
.
id
}
&id=
${
row
.
group_id
}
&name=
${
row
.
group_name
}
`
}
else
if
(
type
===
9
)
{
// 营销资料
return
`
${
dmlURL
}
/material?experiment_id=
${
props
.
data
.
id
}
&student_id=
${
props
.
data
.
student
.
id
}
&id=
${
row
.
material_id
}
&name=
${
row
.
material_name
}
`
}
else
if
(
type
===
12
)
{
const
url
=
row
.
file
.
url
// 事件数据
return
[
'pptx'
,
'doc'
,
'docx'
,
'xls'
,
'xlsx'
].
includes
(
url
)
?
`https://view.officeapps.live.com/op/view.aspx?src=
${
url
}
`
:
url
}
}
</
script
>
<
template
>
<el-dialog
:title=
"title"
width=
"800px"
>
<template
v-if=
"row.type === 11"
>
<Preview
v-for=
"(item, index) in datalist"
:key=
"index"
:url=
"item.file.url"
></Preview>
</
template
>
<AppList
v-bind=
"listOptions"
ref=
"appList"
v-else
>
<
template
#
table-x=
"{ row }"
>
<el-button
type=
"primary"
link
>
<a
:href=
"getOperationUrl(row)"
target=
"_blank"
>
查看
</a>
</el-button>
</
template
>
</AppList>
<
template
#
footer
>
<el-row
justify=
"center"
>
<el-button
round
auto-insert-space
@
click=
"$emit('update:modelValue', false)"
>
关闭
</el-button>
</el-row>
</
template
>
</el-dialog>
</template>
src/modules/student/lab/components/Video.vue
浏览文件 @
5dabc6d8
...
@@ -8,12 +8,16 @@ interface Props {
...
@@ -8,12 +8,16 @@ interface Props {
course_id
?:
string
course_id
?:
string
}
}
const
props
=
defineProps
<
Props
>
()
const
props
=
defineProps
<
Props
>
()
const
emits
=
defineEmits
([
'empty'
])
let
list
=
$ref
<
ExperimentVideoType
[]
>
([])
let
list
=
$ref
<
ExperimentVideoType
[]
>
([])
function
fetchInfo
()
{
function
fetchInfo
()
{
if
(
!
props
.
experiment_id
)
return
if
(
!
props
.
experiment_id
)
return
getExperimentVideoList
({
experiment_id
:
props
.
experiment_id
}).
then
(
res
=>
{
getExperimentVideoList
({
experiment_id
:
props
.
experiment_id
}).
then
(
(
res
)
=>
{
list
=
res
.
data
.
list
list
=
res
.
data
.
list
if
(
list
.
length
===
0
)
{
emits
(
'empty'
)
}
})
})
}
}
watchEffect
(()
=>
{
watchEffect
(()
=>
{
...
@@ -33,8 +37,7 @@ const isEmpty = $computed(() => {
...
@@ -33,8 +37,7 @@ const isEmpty = $computed(() => {
:key=
"item.id"
:key=
"item.id"
:data=
"item"
:data=
"item"
:course_id=
"course_id"
:course_id=
"course_id"
:experiment_id=
"experiment_id"
:experiment_id=
"experiment_id"
></VideoItem>
></VideoItem>
</
template
>
</
template
>
</template>
</template>
...
...
src/modules/student/lab/types.ts
浏览文件 @
5dabc6d8
...
@@ -141,6 +141,7 @@ export interface ExperimentInfo {
...
@@ -141,6 +141,7 @@ export interface ExperimentInfo {
is_commit_report
:
boolean
is_commit_report
:
boolean
is_commit
:
boolean
is_commit
:
boolean
exam_status
:
number
exam_status
:
number
can_repeat_commit
:
0
|
1
}
}
interface
IdName
{
interface
IdName
{
...
...
src/modules/student/lab/views/Index.vue
浏览文件 @
5dabc6d8
差异被折叠。
点击展开。
src/utils/dictionary.ts
浏览文件 @
5dabc6d8
// json to array
// json to array
export
const
json2Array
=
function
(
data
:
any
,
isValueToNumber
=
true
)
{
export
const
json2Array
=
function
(
data
:
any
,
isValueToNumber
=
true
)
{
return
Object
.
keys
(
data
).
map
(
value
=>
({
label
:
data
[
value
],
value
:
isValueToNumber
?
parseInt
(
value
)
:
value
}))
return
Object
.
keys
(
data
).
map
(
(
value
)
=>
({
label
:
data
[
value
],
value
:
isValueToNumber
?
parseInt
(
value
)
:
value
}))
}
}
// 参赛模式
// 参赛模式
export
const
contestMode
:
Record
<
string
,
any
>
=
{
export
const
contestMode
:
Record
<
string
,
any
>
=
{
'1'
:
'个人赛'
'1'
:
'个人赛'
,
}
}
// 参赛模式列表
// 参赛模式列表
export
const
contestModeList
=
json2Array
(
contestMode
,
false
)
export
const
contestModeList
=
json2Array
(
contestMode
,
false
)
...
@@ -15,7 +15,7 @@ export const scoreRule: Record<number, any> = {
...
@@ -15,7 +15,7 @@ export const scoreRule: Record<number, any> = {
1
:
'平均法'
,
1
:
'平均法'
,
2
:
'加权平均法'
,
2
:
'加权平均法'
,
3
:
'综合得分法'
,
3
:
'综合得分法'
,
4
:
'最高分'
4
:
'最高分'
,
}
}
// 参赛模式列表
// 参赛模式列表
export
const
scoreRuleList
=
json2Array
(
scoreRule
,
false
)
export
const
scoreRuleList
=
json2Array
(
scoreRule
,
false
)
...
@@ -31,7 +31,9 @@ export const gradeRule: Record<number, any> = {
...
@@ -31,7 +31,9 @@ export const gradeRule: Record<number, any> = {
7
:
'用户群组'
,
7
:
'用户群组'
,
8
:
'用户旅程'
,
8
:
'用户旅程'
,
9
:
'营销资料'
,
9
:
'营销资料'
,
10
:
'用户/事件数据'
10
:
'用户/事件数据'
,
11
:
'用户数据'
,
12
:
'事件数据'
,
}
}
// 参赛模式列表
// 参赛模式列表
export
const
gradeRuleList
=
json2Array
(
gradeRule
)
export
const
gradeRuleList
=
json2Array
(
gradeRule
)
...
@@ -39,6 +41,6 @@ export const gradeRuleList = json2Array(gradeRule)
...
@@ -39,6 +41,6 @@ export const gradeRuleList = json2Array(gradeRule)
// 实验报告评分规则
// 实验报告评分规则
export
const
reportScoreRule
:
Record
<
number
,
any
>
=
{
export
const
reportScoreRule
:
Record
<
number
,
any
>
=
{
1
:
'人工评分'
,
1
:
'人工评分'
,
2
:
'自动评分'
2
:
'自动评分'
,
}
}
export
const
reportScoreRuleList
=
json2Array
(
reportScoreRule
)
export
const
reportScoreRuleList
=
json2Array
(
reportScoreRule
)
src/utils/upload.ts
浏览文件 @
5dabc6d8
import
axios
from
'axios'
import
{
getLocalFileChunk
,
uploadLocalFile
}
from
'@/api/base'
import
{
getLocalFileChunk
,
uploadLocalFile
}
from
'@/api/base'
export
async
function
upload
(
file
:
Blob
)
{
export
async
function
upload
(
file
:
Blob
)
{
...
@@ -12,3 +13,8 @@ export async function upload(file: Blob) {
...
@@ -12,3 +13,8 @@ export async function upload(file: Blob) {
return
res
.
data
.
detail
.
uri
return
res
.
data
.
detail
.
uri
}
}
export
async
function
uploadFileByUrl
(
url
:
string
)
{
const
res
=
await
axios
.
get
(
url
,
{
responseType
:
'blob'
})
return
upload
(
res
.
data
)
}
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论