Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
S
saas-lab
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
图表
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
EzijingWeb
saas-lab
Commits
468e4f08
提交
468e4f08
authored
2月 24, 2025
作者:
王鹏飞
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
chore: update
上级
d669985a
隐藏空白字符变更
内嵌
并排
正在显示
11 个修改的文件
包含
321 行增加
和
181 行删除
+321
-181
DragPanel.vue
src/components/DragPanel.vue
+3
-3
ScoreViewAutoDialog.vue
...odules/admin/lab/score/components/ScoreViewAutoDialog.vue
+1
-1
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
+11
-7
Question.vue
src/modules/student/lab/components/Question.vue
+20
-11
ResultScoreDialog.vue
src/modules/student/lab/components/ResultScoreDialog.vue
+49
-8
ResultScoreViewAutoDialog.vue
...ules/student/lab/components/ResultScoreViewAutoDialog.vue
+131
-0
Video.vue
src/modules/student/lab/components/Video.vue
+6
-3
Index.vue
src/modules/student/lab/views/Index.vue
+65
-141
没有找到文件。
src/components/DragPanel.vue
浏览文件 @
468e4f08
...
...
@@ -5,7 +5,7 @@ const emit = defineEmits<{
(
e
:
'resize'
):
void
}
>
()
defineProps
<
{
isLeftShow
?:
number
}
>
()
defineProps
<
{
isLeftShow
?:
boolean
}
>
()
const
leftPanelVisible
=
$ref
<
boolean
>
(
true
)
const
leftPanelWidth
=
useStorage
(
'leftPanelWidth'
,
400
)
...
...
@@ -42,7 +42,7 @@ onMounted(() => {
<
template
>
<section
class=
"drag-panel"
>
<div
v-show=
"
isLeftShow !== 1
"
class=
"drag-panel-left"
:class=
"
{ 'is-hidden': !leftPanelVisible }">
<div
v-show=
"
!isLeftShow
"
class=
"drag-panel-left"
:class=
"
{ 'is-hidden': !leftPanelVisible }">
<div
class=
"drag-cover"
v-if=
"dragFlag"
></div>
<slot
name=
"left"
></slot>
<div
class=
"panel-resize"
id=
"panel-resize"
></div>
...
...
@@ -73,6 +73,7 @@ onMounted(() => {
.drag-panel
{
display
:
flex
;
height
:
calc
(
100vh
-
110px
);
gap
:
20px
;
}
.drag-panel-left
{
position
:
relative
;
...
...
@@ -123,7 +124,6 @@ onMounted(() => {
display
:
flex
;
flex-direction
:
column
;
height
:
100%
;
margin-left
:
20px
;
}
.drag-cover
{
width
:
100%
;
...
...
src/modules/admin/lab/score/components/ScoreViewAutoDialog.vue
浏览文件 @
468e4f08
...
...
@@ -35,7 +35,7 @@ const title = computed(() => {
// 列表配置
const
listOptions
=
computed
(()
=>
{
let
columns
=
[]
let
columns
:
any
=
[]
switch
(
props
.
row
.
type
)
{
case
6
:
// 用户标签
...
...
src/modules/student/lab/api.ts
浏览文件 @
468e4f08
...
...
@@ -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
})
}
// 发表新话题
...
...
@@ -85,11 +90,21 @@ export function getExperimentReportTemplate(params: { experiment_id: string }) {
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
)
}
// 缓存实验在线报告
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
)
}
// 获取实验在线报告缓存
...
...
@@ -120,3 +135,8 @@ export function getExperimentQuestion(params: { experiment_id: string; id: strin
export
function
getExperimentExamList
(
params
:
{
experiment_id
:
string
})
{
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
浏览文件 @
468e4f08
...
...
@@ -12,12 +12,16 @@ interface Props {
course_id
?:
string
}
const
props
=
defineProps
<
Props
>
()
const
emits
=
defineEmits
([
'empty'
])
let
list
=
$ref
<
ExperimentBookType
[]
>
([])
function
fetchInfo
()
{
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
if
(
list
.
length
===
0
)
{
emits
(
'empty'
)
}
})
}
watchEffect
(()
=>
{
...
...
@@ -34,7 +38,7 @@ function handleView(row: ExperimentBookType) {
log
.
upload
({
event
:
'file_event'
,
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
浏览文件 @
468e4f08
...
...
@@ -8,12 +8,16 @@ interface Props {
course_id
?:
string
}
const
props
=
defineProps
<
Props
>
()
const
emits
=
defineEmits
([
'empty'
])
let
detail
=
$ref
<
ExperimentBookType
>
()
function
fetchInfo
()
{
if
(
!
props
.
experiment_id
)
return
getExperimentCase
({
experiment_id
:
props
.
experiment_id
}).
then
(
res
=>
{
detail
=
res
.
data
.
detail
getExperimentCase
({
experiment_id
:
props
.
experiment_id
}).
then
((
res
)
=>
{
detail
=
res
.
data
.
detail
||
{}
if
(
detail
&&
Object
.
keys
(
detail
).
length
===
0
)
{
emits
(
'empty'
)
}
})
}
watchEffect
(()
=>
{
...
...
src/modules/student/lab/components/Exam.vue
浏览文件 @
468e4f08
...
...
@@ -10,6 +10,7 @@ interface Props {
}
const
props
=
defineProps
<
Props
>
()
const
model
=
defineModel
()
const
emits
=
defineEmits
([
'empty'
])
const
cookies
=
useCookies
()
...
...
@@ -22,22 +23,27 @@ const currentExam = computed(() => {
// 考试平台 URL
const
examURL
=
computed
(()
=>
{
if
(
!
currentExam
.
value
)
return
''
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/
$
{
return
appConfig
.
system
===
'x'
&&
props
.
examStatus
===
0
?
`
${
import
.
meta
.
env
.
VITE_EXAM_SHOW_URL
}
/exam/
${
currentExam
.
value
?.
exam_id
}?
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`
})
async
function
fetchInfo
()
{
if
(
!
props
.
experiment_id
)
return
const
res
=
await
getExperimentExamList
({
experiment_id
:
props
.
experiment_id
})
const
resCookies
=
res
.
data
.
cookies
cookies
.
set
(
resCookies
.
key
,
resCookies
.
auth_key
,
{
domain
:
'.ezijing.com'
,
path
:
'/'
})
list
.
value
=
res
.
data
.
items
||
[]
model
.
value
=
examURL
.
value
if
(
list
.
value
.
length
===
0
)
{
emits
(
'empty'
)
}
}
onMounted
(()
=>
{
watchEffect
(()
=>
{
fetchInfo
()
})
</
script
>
...
...
@@ -50,11 +56,9 @@ onMounted(() => {
>
{{
currentExam
.
exam_info
.
start_time
}}
~
{{
currentExam
.
exam_info
.
end_time
}}
</el-form-item
>
</el-form>
<div
style=
"width: 100%; height: 100%"
v-if=
"props.examStatus === 0"
>
<div
style=
"width: 100%; height: 100%"
>
<iframe
style=
"width: 100%; height: 100%"
allowfullscreen
class=
"iframe"
:src=
"examURL"
frameborder=
"0"
></iframe>
</div>
<!--
<teleport
to=
".lab-box"
>
-->
<!--
</teleport>
-->
</
template
>
<el-empty
description=
"暂无数据"
v-else
/>
</template>
src/modules/student/lab/components/Question.vue
浏览文件 @
468e4f08
...
...
@@ -4,7 +4,7 @@ import { Document } from '@element-plus/icons-vue'
import
{
filesize
}
from
'filesize'
interface
Props
{
experiment_id
:
string
,
experiment_id
:
string
exam_status
?:
number
}
interface
QuestionListItem
{
...
...
@@ -20,6 +20,7 @@ interface QuestionGroupList {
}
const
props
=
defineProps
<
Props
>
()
const
emits
=
defineEmits
([
'empty'
])
const
questionIndex
=
ref
<
number
>
(
1
)
const
questionId
=
computed
(()
=>
{
...
...
@@ -45,6 +46,9 @@ async function fetchList() {
if
(
!
props
.
experiment_id
)
return
const
res
=
await
getExperimentQuestionList
({
experiment_id
:
props
.
experiment_id
})
questionList
.
value
=
res
.
data
.
items
if
(
questionList
.
value
.
length
===
0
)
{
emits
(
'empty'
)
}
}
watchEffect
(()
=>
{
if
(
props
.
experiment_id
)
fetchList
()
...
...
@@ -52,19 +56,21 @@ watchEffect(() => {
// 试题详情
const
questionDetail
=
ref
()
const
file
=
ref
()
async
function
fetchDetail
()
{
if
(
!
questionId
.
value
)
return
const
res
=
await
getExperimentQuestion
({
experiment_id
:
props
.
experiment_id
,
id
:
questionId
.
value
})
const
detail
=
res
.
data
.
detail
let
files
=
[]
const
detail
=
res
.
data
.
detail
||
{}
let
answer
:
any
=
{}
try
{
files
=
JSON
.
parse
(
detail
.
files
)
answer
=
JSON
.
parse
(
detail
.
answer
)
file
.
value
=
answer
.
data
?.
file
||
{}
}
catch
(
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
()
})
...
...
@@ -79,7 +85,9 @@ function handleNext() {
}
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
([
'301'
,
'302'
].
includes
(
type
))
return
'群组管理'
if
([
'401'
,
'402'
,
'403'
,
'404'
,
'405'
,
'406'
,
'407'
].
includes
(
type
))
return
'营销资料管理'
...
...
@@ -111,17 +119,18 @@ function customFloor(num: number) {
<el-card
shadow=
"never"
class=
"question-item"
v-if=
"questionDetail"
>
<h3
class=
"question-item__title"
>
{{
getQuestionTypeName
(
questionDetail
.
type
)
}}
</h3>
<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
class=
"question-item__content"
>
{{
questionDetail
.
content
}}
</p>
<ul
class=
"question-item__files"
>
<li
class=
"question-item__files-item"
v-for=
"(file, index) in questionDetail.files"
:key=
"index"
>
<ul
class=
"question-item__files"
v-if=
"!!Object.keys(file).length"
>
<li
class=
"question-item__files-item"
>
<el-icon><Document
/></el-icon>
<div
class=
"question-item__files-item__title"
>
<p>
{{
file
.
name
}}
</p>
<p>
{{
filesize
(
file
.
size
)
}}
</p>
</div>
<a
:href=
"file.url"
target=
"_blank"
download
v-if=
"file.is_download"
>
下载
</a>
<a
:href=
"file.url"
target=
"_blank"
download
>
下载
</a>
<a
:href=
"file.url"
target=
"_blank"
>
查看
</a>
</li>
</ul>
...
...
src/modules/student/lab/components/ResultScoreDialog.vue
浏览文件 @
468e4f08
<
script
setup
lang=
"ts"
>
import
{
getExperimentScore
}
from
'../api'
import
{
useAppConfig
}
from
'@/composables/useAppConfig'
const
appConfig
=
useAppConfig
()
const
ResultScoreViewAutoDialog
=
defineAsyncComponent
(()
=>
import
(
'./ResultScoreViewAutoDialog.vue'
))
interface
Props
{
experiment_id
:
string
}
import
{
useAppConfig
}
from
'@/composables/useAppConfig'
const
appConfig
=
useAppConfig
()
const
props
=
defineProps
<
Props
>
()
let
experiment
=
$ref
<
any
>
()
...
...
@@ -16,7 +19,7 @@ const classText = $computed(() => {
})
function
fetchInfo
()
{
getExperimentScore
({
experiment_id
:
props
.
experiment_id
}).
then
(
res
=>
{
getExperimentScore
({
experiment_id
:
props
.
experiment_id
}).
then
(
(
res
)
=>
{
experiment
=
res
.
data
.
experiment
let
scoreDetails
=
[]
try
{
...
...
@@ -28,7 +31,7 @@ function fetchInfo() {
}
detail
=
Object
.
assign
(
res
.
data
.
achievement
,
{
score
:
parseFloat
(
res
.
data
.
achievement
.
score
),
score_details
:
scoreDetails
score_details
:
scoreDetails
,
})
})
}
...
...
@@ -42,13 +45,22 @@ function getOperationUrl(type: number) {
return
`/student/lab/report/view/
${
experiment
.
id
}
`
}
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
}
`
}
}
const
autoVisible
=
ref
(
false
)
const
currentRow
=
ref
(
null
)
function
handleViewAuto
(
row
:
any
)
{
autoVisible
.
value
=
true
currentRow
.
value
=
row
}
</
script
>
<
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-item
label=
"实验名称"
>
{{
experiment
.
name
}}
</el-form-item>
<el-form-item
label=
"实验课程名称"
>
{{
experiment
.
course
.
name
}}
</el-form-item>
...
...
@@ -71,7 +83,9 @@ function getOperationUrl(type: number) {
<el-row>
<el-col
:span=
"12"
>
<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-col>
<el-col
:span=
"12"
>
...
...
@@ -83,7 +97,11 @@ function getOperationUrl(type: number) {
<p>
实验得分
</p>
<p
class=
"t1"
>
{{
detail
.
score
}}
</p>
</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=
"percent"
align=
"center"
>
<template
#
default=
"
{ row }">
{{
row
.
percent
}}
%
</
template
>
...
...
@@ -99,6 +117,23 @@ function getOperationUrl(type: number) {
</
template
>
</template>
</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
type=
"primary"
@
click=
"handleViewAuto(row)"
link
>
查看
</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>
</div>
</el-form>
...
...
@@ -107,6 +142,12 @@ function getOperationUrl(type: number) {
<el-button
round
auto-insert-space
@
click=
"$emit('update:modelValue', false)"
>
关闭
</el-button>
</el-row>
</
template
>
<ResultScoreViewAutoDialog
v-model=
"autoVisible"
:data=
"experiment"
:row=
"currentRow"
v-if=
"currentRow"
></ResultScoreViewAutoDialog>
</el-dialog>
</template>
...
...
src/modules/student/lab/components/ResultScoreViewAutoDialog.vue
0 → 100644
浏览文件 @
468e4f08
<
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
浏览文件 @
468e4f08
...
...
@@ -8,12 +8,16 @@ interface Props {
course_id
?:
string
}
const
props
=
defineProps
<
Props
>
()
const
emits
=
defineEmits
([
'empty'
])
let
list
=
$ref
<
ExperimentVideoType
[]
>
([])
function
fetchInfo
()
{
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
if
(
list
.
length
===
0
)
{
emits
(
'empty'
)
}
})
}
watchEffect
(()
=>
{
...
...
@@ -33,8 +37,7 @@ const isEmpty = $computed(() => {
:key=
"item.id"
:data=
"item"
:course_id=
"course_id"
:experiment_id=
"experiment_id"
></VideoItem>
:experiment_id=
"experiment_id"
></VideoItem>
</
template
>
</template>
...
...
src/modules/student/lab/views/Index.vue
浏览文件 @
468e4f08
...
...
@@ -57,12 +57,16 @@ function handleCourseChange(value: string) {
ElMessageBox
.
confirm
(
'切换实验,将会导致当前操作内容变化,请确认当前操作无误并确认切换实验。'
,
'提示'
).
then
(()
=>
{
form
.
course_id
=
value
form
.
experiment_id
=
''
tabActive
.
value
=
'info'
empty
.
value
=
[]
})
}
// 实验改变
function
handleExperimentChange
(
value
:
string
)
{
ElMessageBox
.
confirm
(
'切换实验,将会导致当前操作内容变化,请确认当前操作无误并确认切换实验。'
,
'提示'
).
then
(()
=>
{
form
.
experiment_id
=
value
tabActive
.
value
=
'info'
empty
.
value
=
[]
})
}
...
...
@@ -100,9 +104,9 @@ const examURL = ref('')
// 右侧
const
cookies
=
useCookies
([
'TGC'
])
const
LAB_URL
:
any
=
computed
(()
=>
{
if
(
tabActive
.
value
===
'exam'
&&
examURL
.
value
)
return
examURL
.
value
if
(
tabActive
.
value
===
'exam'
&&
examURL
.
value
&&
experimentInfo
?.
exam_status
===
1
)
return
examURL
.
value
return
experimentInfo
?.
type
===
4
?
`
${
appConfig
.
dmlURL
||
import
.
meta
.
env
.
VITE_DML_URL
}
/trip/my
?experiment_id=
${
form
.
experiment_id
}
`
?
`
${
appConfig
.
dmlURL
||
import
.
meta
.
env
.
VITE_DML_URL
}
?experiment_id=
${
form
.
experiment_id
}
`
:
`
${
appConfig
.
dmlURL
||
import
.
meta
.
env
.
VITE_LAB_URL
}
&token=
${
cookies
.
get
(
'TGC'
)}
`
})
...
...
@@ -225,10 +229,16 @@ function handleReportPreviewReady() {
isExport = false
}, 100)
}
const empty = ref<string[]>([])
function handleEmpty(name: string) {
empty.value.push(name)
}
</
script
>
<
template
>
<DragPanel
@
resize=
"handleResize"
v-if=
"appConfig.system !== 'x'
"
>
<DragPanel
@
resize=
"handleResize"
:isLeftShow=
"appConfig.system === 'x' && experimentInfo?.exam_status === 1
"
>
<template
#
left
>
<div
class=
"lab-left"
>
<el-form
:model=
"form"
label-suffix=
":"
hide-required-asterisk
>
...
...
@@ -243,29 +253,44 @@ function handleReportPreviewReady() {
</el-select>
</el-form-item>
</el-form>
<el-tabs
type=
"border-card"
v-model=
"tabActive"
>
<el-tab-pane
label=
"实验信息"
name=
"info"
lazy
>
<el-tabs
type=
"border-card"
v-model=
"tabActive"
v-if=
"experimentInfo"
>
<el-tab-pane
label=
"实验信息"
name=
"info"
>
<Info
:data=
"experimentInfo"
></Info>
</el-tab-pane>
<el-tab-pane
label=
"案例原文"
lazy
>
<Case
:course_id=
"form.course_id"
:experiment_id=
"form.experiment_id"
:key=
"resizeKey"
></Case>
<el-tab-pane
label=
"案例原文"
name=
"case"
v-if=
"!empty.includes('case')"
>
<Case
:course_id=
"form.course_id"
:experiment_id=
"form.experiment_id"
:key=
"resizeKey"
@
empty=
"handleEmpty('case')"
></Case>
</el-tab-pane>
<el-tab-pane
label=
"实训指导"
lazy
>
<Book
:course_id=
"form.course_id"
:experiment_id=
"form.experiment_id"
:key=
"resizeKey"
></Book>
<el-tab-pane
label=
"实训指导"
name=
"book"
v-if=
"!empty.includes('book')"
>
<Book
:course_id=
"form.course_id"
:experiment_id=
"form.experiment_id"
:key=
"resizeKey"
@
empty=
"handleEmpty('book')"
></Book>
</el-tab-pane>
<el-tab-pane
label=
"操作视频"
lazy
>
<Video
:course_id=
"form.course_id"
:experiment_id=
"form.experiment_id"
></Video>
<el-tab-pane
label=
"操作视频"
name=
"video"
v-if=
"!empty.includes('video')"
>
<Video
:course_id=
"form.course_id"
:experiment_id=
"form.experiment_id"
@
empty=
"handleEmpty('video')"
></Video>
</el-tab-pane>
<el-tab-pane
label=
"理论考试"
name=
"exam"
lazy
>
<Exam
:experiment_id=
"form.experiment_id"
v-model=
"examURL"
></Exam>
<el-tab-pane
label=
"理论试题"
name=
"exam"
v-if=
"!empty.includes('exam')"
>
<Exam
:experiment_id=
"form.experiment_id"
v-model=
"examURL"
:examStatus=
"experimentInfo?.exam_status"
@
empty=
"handleEmpty('exam')"
></Exam>
</el-tab-pane>
<el-tab-pane
label=
"实
验试题"
name=
"qa"
lazy
>
<Question
:experiment_id=
"form.experiment_id"
></Question>
<el-tab-pane
label=
"实
操试题"
name=
"qa"
v-if=
"!empty.includes('qa')"
>
<Question
:experiment_id=
"form.experiment_id"
@
empty=
"handleEmpty('qa')"
></Question>
</el-tab-pane>
<el-tab-pane
label=
"过程与结果"
lazy
>
<el-tab-pane
label=
"过程与结果"
name=
"result"
lazy
>
<Result
:data=
"experimentInfo"
@
update=
"fetchExperimentRecord"
></Result>
</el-tab-pane>
<el-tab-pane
label=
"讨论交流"
lazy
>
<el-tab-pane
label=
"讨论交流"
name=
"discuss"
lazy
>
<Discuss
:experiment_id=
"form.experiment_id"
></Discuss>
</el-tab-pane>
</el-tabs>
...
...
@@ -273,7 +298,11 @@ function handleReportPreviewReady() {
</
template
>
<
template
#
right
>
<AppCard>
<el-row
justify=
"space-between"
>
<div
class=
"exam-status"
v-if=
"appConfig.system === 'x' && experimentInfo?.exam_status === 1"
>
<el-button
type=
"primary"
@
click=
"tabActive = 'qa'"
>
实操系统
</el-button>
<el-button
type=
"primary"
@
click=
"tabActive = 'exam'"
>
理论试题
</el-button>
</div>
<el-row
justify=
"space-between"
v-else
>
<div>
<el-button
type=
"primary"
:icon=
"HomeFilled"
:disabled=
"submitted"
@
click=
"handleBackHome"
>
返回首页
</el-button
...
...
@@ -315,130 +344,25 @@ function handleReportPreviewReady() {
</el-row>
</AppCard>
<div
class=
"lab-box"
>
<el-empty
description=
"您已经提交该实验,不能再进行操作,切换其他实验再做操作吧。"
v-if=
"submitted"
/>
<iframe
allow=
"camera; microphone"
allowfullscreen
:src=
"LAB_URL"
:key=
"iframeKey"
frameborder=
"0"
class=
"iframe"
ref=
"iframeRef"
v-else
></iframe>
</div>
</
template
>
</DragPanel>
<DragPanel
v-else
@
resize=
"handleResize"
:isLeftShow=
"experimentInfo?.exam_status"
>
<
template
#
left
>
<div
class=
"lab-left"
>
<el-form
:model=
"form"
label-suffix=
":"
hide-required-asterisk
>
<el-form-item
label=
"请选择课程"
>
<el-select
:model-value=
"form.course_id"
@
change=
"handleCourseChange"
style=
"width: 100%"
>
<el-option
v-for=
"item in courses"
:key=
"item.id"
:label=
"item.name"
:value=
"item.id"
></el-option>
</el-select>
</el-form-item>
<el-form-item
label=
"请选择实验"
prop=
"experiment_id"
>
<el-select
:model-value=
"form.experiment_id"
@
change=
"handleExperimentChange"
style=
"width: 100%"
>
<el-option
v-for=
"item in experimentList"
:key=
"item.id"
:label=
"item.name"
:value=
"item.id"
></el-option>
</el-select>
</el-form-item>
</el-form>
<el-tabs
type=
"border-card"
v-model=
"tabActive"
>
<el-tab-pane
:label=
"experimentInfo?.exam_status === 0 ? '实验训练' : '实验试题'"
name=
"qa"
lazy
>
<Exam
:experiment_id=
"form.experiment_id"
v-model=
"examURL"
:examStatus=
"experimentInfo?.exam_status"
v-if=
"experimentInfo?.exam_status === 0"
></Exam>
<Question
:experiment_id=
"form.experiment_id"
v-else
></Question>
</el-tab-pane>
<el-tab-pane
label=
"理论考试"
name=
"exam"
lazy
v-show=
"experimentInfo?.exam_status === 1 && tabActive === 'exam'"
>
<Exam
:experiment_id=
"form.experiment_id"
v-model=
"examURL"
></Exam>
</el-tab-pane>
<el-tab-pane
label=
"实验信息"
lazy
>
<Info
:data=
"experimentInfo"
></Info>
</el-tab-pane>
<el-tab-pane
label=
"案例原文"
lazy
>
<Case
:course_id=
"form.course_id"
:experiment_id=
"form.experiment_id"
:key=
"resizeKey"
></Case>
</el-tab-pane>
<el-tab-pane
label=
"实训指导"
lazy
>
<Book
:course_id=
"form.course_id"
:experiment_id=
"form.experiment_id"
:key=
"resizeKey"
></Book>
</el-tab-pane>
<el-tab-pane
label=
"操作视频"
lazy
>
<Video
:course_id=
"form.course_id"
:experiment_id=
"form.experiment_id"
></Video>
</el-tab-pane>
<el-tab-pane
label=
"讨论交流"
lazy
>
<Discuss
:experiment_id=
"form.experiment_id"
></Discuss>
</el-tab-pane>
<el-tab-pane
label=
"过程与结果"
lazy
>
<Result
:data=
"experimentInfo"
@
update=
"fetchExperimentRecord"
></Result>
</el-tab-pane>
</el-tabs>
</div>
</
template
>
<
template
#
right
>
<div
class=
"exam-status"
v-if=
"appConfig.system === 'x' && experimentInfo?.exam_status === 1"
>
<el-button
type=
"primary"
@
click=
"tabActive = 'qa'"
>
实操系统
</el-button>
<el-button
type=
"primary"
@
click=
"tabActive = 'exam'"
>
理论试题
</el-button>
</div>
<AppCard
v-else
>
<el-row
justify=
"space-between"
>
<div>
<el-button
type=
"primary"
:icon=
"HomeFilled"
:disabled=
"submitted"
@
click=
"handleBackHome"
>
返回首页
</el-button
>
<el-button
type=
"primary"
:disabled=
"disabled"
@
click=
"handleSubmit"
>
提交实验
</el-button>
<el-empty
description=
"您已经提交该实验,不能再进行操作,切换其他实验再做操作吧。"
style=
"flex: 1"
v-if=
"submitted"
/>
<template
v-else
>
<iframe
allow=
"camera; microphone"
allowfullscreen
:src=
"LAB_URL"
:key=
"iframeKey"
frameborder=
"0"
class=
"iframe"
ref=
"iframeRef"
></iframe>
<div
style=
"padding: 10px; background-color: #fff; max-width: 300px; min-width: 300px"
v-if=
"experimentInfo?.exam_status === 1 && tabActive === 'qa'"
>
<Question
:experiment_id=
"form.experiment_id"
:exam_status=
"experimentInfo?.exam_status"
></Question>
</div>
<div>
<el-button
type=
"primary"
:disabled=
"disabled"
:loading=
"screenshotLoading"
@
click=
"handleCapture"
>
截图
</el-button
>
<el-button
type=
"primary"
:disabled=
"disabled"
@
click=
"prepareDialogVisible = true"
>
实验准备
</el-button>
<el-button
type=
"primary"
:disabled=
"disabled"
@
click=
"resultDialogVisible = true"
>
实验结果
</el-button>
<el-button
type=
"primary"
:disabled=
"disabled"
v-if=
"experimentInfo?.report_upload_way === 2 && !experimentInfo?.is_commit_report"
>
<router-link
:to=
"`/student/lab/report/$
{form.experiment_id}`" target="_blank">在线实验报告
</router-link>
</el-button>
<el-button
type=
"primary"
:disabled=
"disabled"
@
click=
"reportDialogVisible = true"
v-if=
"experimentInfo?.report_upload_way === 1 && !submitted"
>
上传实验报告
</el-button
>
<el-button
type=
"primary"
@
click=
"handleReportView"
v-if=
"experimentInfo?.is_commit_report"
>
查看实验报告
</el-button
>
<el-button
type=
"primary"
@
click=
"handleReportExport"
v-if=
"detail?.status === 2 && experimentInfo?.is_commit_report"
>
导出实验报告
</el-button
>
</div>
</el-row>
</AppCard>
<div
class=
"lab-box"
>
<el-empty
description=
"您已经提交该实验,不能再进行操作,切换其他实验再做操作吧。"
v-if=
"submitted"
/>
<iframe
allowfullscreen
:src=
"LAB_URL"
:key=
"iframeKey"
frameborder=
"0"
class=
"iframe"
ref=
"iframeRef"
v-else
></iframe>
<div
style=
"padding: 10px; background-color: #fff; max-width: 300px; min-width: 300px"
v-if=
"experimentInfo?.exam_status === 1 && tabActive === 'qa'"
>
<Question
:experiment_id=
"form.experiment_id"
:exam_status=
"experimentInfo?.exam_status"
></Question>
</div>
</
template
>
</div>
</template>
</DragPanel>
...
...
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论