Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
S
saas-lab
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
图表
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
EzijingWeb
saas-lab
Commits
325b2cc5
提交
325b2cc5
authored
2月 24, 2025
作者:
王鹏飞
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
chore: 修改实验成绩规则的自动评分
上级
d1490681
全部展开
显示空白字符变更
内嵌
并排
正在显示
20 个修改的文件
包含
825 行增加
和
445 行删除
+825
-445
api.ts
src/modules/admin/lab/experiment/api.ts
+39
-7
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
+42
-27
JourneyQuestion.vue
...n/lab/experiment/components/Questions/JourneyQuestion.vue
+18
-16
MaterialQuestion.vue
.../lab/experiment/components/Questions/MaterialQuestion.vue
+71
-91
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
+46
-36
UserQuestion.vue
...dmin/lab/experiment/components/Questions/UserQuestion.vue
+106
-79
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
+86
-82
View.vue
src/modules/admin/lab/experiment/views/View.vue
+18
-19
Index.vue
src/modules/admin/lab/score/views/Index.vue
+56
-19
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
+21
-3
没有找到文件。
src/modules/admin/lab/experiment/api.ts
浏览文件 @
325b2cc5
...
@@ -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
})
}
}
// 更新实验的理论考试
// 更新实验的理论考试
...
...
src/modules/admin/lab/experiment/components/FormDialog.vue
浏览文件 @
325b2cc5
...
@@ -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
浏览文件 @
325b2cc5
...
@@ -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
浏览文件 @
325b2cc5
<
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
浏览文件 @
325b2cc5
<
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
/>
</el-icon>
<div
class=
"head-box"
>
<div
class=
"head-box"
>
<el-tabs
v-model=
"item.type"
type=
"card"
class=
"demo-tabs
"
>
<el-tabs
v-model=
"item.type"
type=
"card
"
>
<el-tab-pane
label=
"静态群组"
:name=
"301"
></el-tab-pane>
<el-tab-pane
label=
"静态群组"
:name=
"301"
></el-tab-pane>
<el-tab-pane
label=
"动态群组"
:name=
"302"
></el-tab-pane>
<el-tab-pane
label=
"动态群组"
:name=
"302"
></el-tab-pane>
</el-tabs>
</el-tabs>
<el-form-item
label=
"本题分值"
class=
"head-r"
>
<el-form-item
<el-input-number
v-model=
"item.score"
:min=
"1"
:max=
"100"
controls-position=
"right"
/>
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>
</div>
<el-form
ref=
"ruleFormRef"
label-width=
"120px"
class=
"demo-ruleForm"
status-icon
>
<el-form-item
label=
"题目标题"
:prop=
"`questions.$
{index}.title`" :rules="{ required: true, message: '请输入' }">
<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 === 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
浏览文件 @
325b2cc5
...
@@ -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-form
ref=
"formRef"
label-width=
"120px"
:model=
"form"
scroll-to-error
>
<el-card
:id=
"`site-card$
{index}`" class="box-card" v-for="(item, index) in modelValue" :key="item">
<el-card
:id=
"`site-card$
{index}`" class="box-card" v-for="(item, index) in modelValue" :key="item">
<el-icon
@
click=
"removeQuestion(index)"
v-if=
"modelValue.length > 1"
class=
"close"
size=
"28"
color=
"#c01c40"
<el-icon
@
click=
"$emit('remove', index)"
v-if=
"modelValue.length > 1"
class=
"close"
size=
"28"
color=
"#c01c40"
>
><CircleCloseFilled
<CircleCloseFilled
/>
/>
</el-icon>
</el-icon>
<div
class=
"head-box"
>
<div
class=
"head-box"
>
<el-form-item
label=
"本题分值"
class=
"head-r"
>
<el-form-item
label=
"本题分值"
class=
"head-r"
:prop=
"`questions.$
{index}.score`"
:rules="{ required: true, message: '请输入' }">
<el-input-number
v-model=
"item.score"
:min=
"1"
:max=
"100"
controls-position=
"right"
/>
<el-input-number
v-model=
"item.score"
:min=
"1"
:max=
"100"
controls-position=
"right"
/>
</el-form-item>
</el-form-item>
</div>
</div>
<el-form
ref=
"ruleFormRef"
label-width=
"120px"
class=
"demo-ruleForm"
status-icon
>
<el-form-item
label=
"题目标题"
:prop=
"`questions.$
{index}.title`" :rules="{ required: true, message: '请输入' }">
<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>
</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
浏览文件 @
325b2cc5
<
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-form
ref=
"formRef"
label-width=
"120px"
:model=
"form"
scroll-to-error
>
<el-card
:id=
"`site-card$
{index}`" class="box-card" v-for="(item, index) in modelValue" :key="item">
<el-card
:id=
"`site-card$
{index}`" class="box-card" v-for="(item, index) in modelValue" :key="item">
<el-icon
@
click=
"removeQuestion(index)"
v-if=
"modelValue.length > 1"
class=
"close"
size=
"28"
color=
"#c01c40"
<el-icon
@
click=
"$emit('remove', index)"
v-if=
"modelValue.length > 1"
class=
"close"
size=
"28"
color=
"#c01c40"
>
><CircleCloseFilled
<CircleCloseFilled
/>
/>
</el-icon>
</el-icon>
<div
class=
"head-box"
>
<div
class=
"head-box"
>
<el-select
v-model=
"item.type"
class=
"m-2"
placeholder=
"请选择"
size=
"large"
>
<el-form-item
<el-option
v-for=
"item in options"
:key=
"item.id"
:label=
"item.name"
:value=
"item.id"
/>
label=
"本题分值"
</el-select>
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-input-number
v-model=
"item.score"
:min=
"0"
:max=
"100"
controls-position=
"right"
/>
</el-form-item>
</el-form-item>
</div>
</div>
<el-form
ref=
"ruleFormRef"
label-width=
"120px"
class=
"demo-ruleForm"
status-icon
>
<el-form-item
label=
"题目标题"
:prop=
"`questions.$
{index}.title`" :rules="{ required: true, message: '请输入' }">
<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
<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>
<el-form-item
label=
"试题文件"
v-if=
"item.type !== 401"
>
<el-form-item
<AppUpload
v-model=
"item.files"
>
label=
"评分AI"
<template
#
tip
>
{{
getTips
(
item
.
type
)
}}
</
template
>
:prop=
"`questions.$
{index}.answer.ai`"
<
template
#
file=
"{ file }"
>
:rules="{ required: true, message: '请选择' }">
<div
class=
"upload-box"
>
<el-select
v-model=
"item.answer.ai"
placeholder=
"请选择"
>
<div
class=
"upload-loading"
>
<el-option
v-for=
"item in aiOptions"
:key=
"item.value"
:label=
"item.label"
:value=
"item.value"
/>
<el-icon
style=
"margin-right: 5px"
><Document
/></el-icon>
</el-select>
<p
style=
"margin-right: 5px"
>
{{
file
.
name
}}
</p>
</el-form-item>
<p
v-if=
"file.status === 'uploading'"
>
{{
file
.
percentage
}}
%
</p>
<el-form-item
label=
"答案解析"
v-if=
"false"
>
<template
v-if=
"file.status === 'success'"
>
<el-input
v-model=
"item.answer_analysis"
:rows=
"5"
type=
"textarea"
placeholder=
"请输入"
/>
<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
浏览文件 @
325b2cc5
<
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
浏览文件 @
325b2cc5
...
@@ -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
浏览文件 @
325b2cc5
<
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
浏览文件 @
325b2cc5
<
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
href
=
computed
(()
=>
{
const
dmlURL
=
appConfig
.
dmlURL
||
import
.
meta
.
env
.
VITE_DML_URL
return
`
${
dmlURL
}
/connect?experiment_id=
${
route
.
query
.
id
}
`
})
const
removeQuestion
=
(
index
:
number
)
=>
{
async
function
handleDataTypeChange
(
item
:
any
)
{
modelValue
.
value
.
splice
(
index
,
1
)
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">
<el-icon
@
click=
"$emit('remove', index)"
v-if=
"modelValue.length > 1"
class=
"close"
size=
"28"
color=
"#c01c40"
><CircleCloseFilled
><CircleCloseFilled
/></el-icon>
/></el-icon>
<div
class=
"head-box"
>
<div
class=
"head-box"
>
<el-tabs
v-model=
"item.type"
type=
"card"
class=
"demo-tabs"
>
<el-form-item
<el-tab-pane
label=
"用户数据"
:name=
"101"
></el-tab-pane>
label=
"本题分值"
<el-tab-pane
label=
"事件数据"
:name=
"102"
></el-tab-pane>
class=
"head-r"
</el-tabs>
:prop=
"`questions.$
{index}.score`"
<el-form-item
label=
"本题分值"
class=
"head-r
"
>
:rules="{ required: true, message: '请输入' }
">
<el-input-number
v-model=
"item.score"
:min=
"1
"
:max=
"100"
controls-position=
"right"
/>
<el-input-number
v-model=
"item.score"
:min=
"0
"
:max=
"100"
controls-position=
"right"
/>
</el-form-item>
</el-form-item>
</div>
</div>
<el-form
ref=
"ruleFormRef"
label-width=
"120px"
class=
"demo-ruleForm"
status-icon
>
<el-form-item
label=
"题目标题"
:prop=
"`questions.$
{index}.title`" :rules="{ required: true, message: '请输入' }">
<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>
<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-form-item>
<el-radio
label=
"1"
>
指定文件
</el-radio>
<el-form-item
label=
"试题文件"
>
<el-radio
label=
"2"
>
自动生成
</el-radio>
<AppUpload
v-model=
"item.files"
>
</el-radio-group>
<template
#
tip
>
试题文件支持格式包含:png jpg doc docx xls xlsx pdf ppt pptx,大小不超过50M
</
template
>
<div
class=
"form-item-box"
>
<
template
#
file=
"{ file }"
>
<template
v-if=
"item.answer.data.type == 1"
>
<div
class=
"upload-box"
>
<el-button
:icon=
"Plus"
size=
"large"
@
click=
"handleUpload(item)"
></el-button>
<div
class=
"upload-loading"
>
<template
v-if=
"item.answer.data.file.url"
>
<el-icon
style=
"margin-right: 5px"
><Document
/></el-icon>
<div
class=
"file-info"
>
<p
style=
"margin-right: 5px"
>
{{
file
.
name
}}
</p>
<p>
{{
item
.
answer
.
data
.
file
.
name
}}
</p>
<p
v-if=
"file.status === 'uploading'"
>
{{
file
.
percentage
}}
%
</p>
<p>
总数据量:
{{
item
.
answer
.
data
.
file
.
total
}}
条
</p>
<template
v-if=
"file.status === 'success'"
>
</div>
<el-icon
class=
"succ-icon1"
color=
"#67c23a"
size=
"18"
style=
"margin-left: 30px"
<el-button
type=
"primary"
plain
@
click=
"item.answer.data.file =
{}">删除数据集
</el-button>
><CircleCheck
</
template
>
/></el-icon>
</template>
<el-icon
class=
"succ-icon2"
size=
"18"
style=
"margin-left: 30px"
@
click=
"handleRemove(file)"
<
template
v-else
>
><CircleClose
<a
:href=
"href"
target=
"_blank"
>
/></el-icon>
<el-button
type=
"primary"
>
查看自动生成规则
</el-button>
</a>
<el-alert
title=
"该实验尚未维护自动生成数据规则,请维护!"
type=
"info"
style=
"margin-left: 40px"
v-if=
"!item.answer.data.exists"
/>
</
template
>
</
template
>
</div>
</div>
<el-switch
@
change=
"handleDownload(file)"
v-model=
"file.is_download"
size=
"large"
active-text=
"能否下载"
/>
</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
>
</
template
>
</AppUpload>
<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-form-item>
</el-form>
</el-card>
</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
{
display
:
flex
;
.form-item-box
{
.upload-loading
{
width
:
300px
;
display
:
flex
;
display
:
flex
;
align-items
:
center
;
align-items
:
center
;
&
:hover
{
p
{
.succ-icon2
{
font-size
:
13px
;
display
:
block
;
margin
:
0
20px
0
10px
;
}
line-height
:
1
.4
;
.succ-icon1
{
display
:
none
;
}
}
.succ-icon2
{
display
:
none
;
cursor
:
pointer
;
}
}
}
}
}
</
style
>
</
style
>
src/modules/admin/lab/experiment/composables/useQuestion.ts
0 → 100644
浏览文件 @
325b2cc5
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
浏览文件 @
325b2cc5
...
@@ -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
浏览文件 @
325b2cc5
...
@@ -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
浏览文件 @
325b2cc5
<
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
)
{
questions
.
value
=
resp
.
data
.
items
.
map
((
item
)
=>
{
ElMessage
.
error
(
`第
${
findItem
(
'title'
)
+
1
}
题,题目不能为空`
)
return
{
...
item
,
answer
:
JSON
.
parse
(
item
.
answer
),
score
:
parseInt
(
item
.
score
)
||
0
,
type
:
parseInt
(
item
.
type
)
}
return
false
}
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 +107,36 @@ const getCurrentQuestions = function () {
...
@@ -108,31 +107,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
浏览文件 @
325b2cc5
<
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/views/Index.vue
浏览文件 @
325b2cc5
...
@@ -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>
...
@@ -156,16 +175,34 @@ async function handleReset(row: RecordItem) {
...
@@ -156,16 +175,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
text
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
text
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
text
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/views/Index.vue
浏览文件 @
325b2cc5
差异被折叠。
点击展开。
src/utils/dictionary.ts
浏览文件 @
325b2cc5
// 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
浏览文件 @
325b2cc5
import
axios
from
'axios'
import
md5
from
'blueimp-md5'
import
md5
from
'blueimp-md5'
import
{
getSignature
,
uploadFile
}
from
'@/api/base'
import
{
getSignature
,
uploadFile
}
from
'@/api/base'
export
async
function
upload
(
blob
:
Blob
)
{
export
async
function
upload
(
blob
:
Blob
|
File
)
{
const
key
=
'upload/saas-lab/'
+
md5
(
new
Date
().
getTime
()
+
Math
.
random
().
toString
(
36
).
slice
(
-
8
))
+
'.png'
let
fileType
=
'png'
if
(
blob
instanceof
File
&&
blob
.
name
)
{
const
matches
=
blob
.
name
.
match
(
/
\.(\w
+
)
$/
)
if
(
matches
)
{
fileType
=
matches
[
1
]
}
}
else
if
(
blob
.
type
)
{
const
mimeType
=
blob
.
type
.
split
(
'/'
).
pop
()
if
(
mimeType
)
{
fileType
=
mimeType
}
}
const
key
=
'upload/saas-lab/'
+
md5
(
new
Date
().
getTime
()
+
Math
.
random
().
toString
(
36
).
slice
(
-
8
))
+
'.'
+
fileType
const
response
:
any
=
await
getSignature
()
const
response
:
any
=
await
getSignature
()
const
params
=
{
const
params
=
{
key
,
key
,
...
@@ -12,8 +25,13 @@ export async function upload(blob: Blob) {
...
@@ -12,8 +25,13 @@ export async function upload(blob: Blob) {
signature
:
response
.
signature
,
signature
:
response
.
signature
,
success_action_status
:
'200'
,
success_action_status
:
'200'
,
file
:
blob
,
file
:
blob
,
url
:
`
${
response
.
host
}
/
${
key
}
`
url
:
`
${
response
.
host
}
/
${
key
}
`
,
}
}
await
uploadFile
(
params
)
await
uploadFile
(
params
)
return
params
.
url
return
params
.
url
}
}
export
async
function
uploadFileByUrl
(
url
:
string
)
{
const
res
=
await
axios
.
get
(
url
,
{
responseType
:
'blob'
})
return
upload
(
res
.
data
)
}
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论