Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
S
saas-lab
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
图表
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
EzijingWeb
saas-lab
Commits
cdcb443e
提交
cdcb443e
authored
8月 18, 2022
作者:
王鹏飞
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
chore: update
上级
7649fdcd
隐藏空白字符变更
内嵌
并排
正在显示
13 个修改的文件
包含
381 行增加
和
53 行删除
+381
-53
types.ts
src/modules/admin/system/experiment/types.ts
+3
-0
Group.vue
src/modules/admin/system/experiment/views/Group.vue
+3
-3
api.ts
src/modules/student/lab/api.ts
+38
-0
Book.vue
src/modules/student/lab/components/Book.vue
+40
-4
Discuss.vue
src/modules/student/lab/components/Discuss.vue
+32
-10
DiscussItem.vue
src/modules/student/lab/components/DiscussItem.vue
+42
-0
Result.vue
src/modules/student/lab/components/Result.vue
+6
-1
Video.vue
src/modules/student/lab/components/Video.vue
+29
-2
VideoItem.vue
src/modules/student/lab/components/VideoItem.vue
+40
-0
useGetCourseList.ts
src/modules/student/lab/composables/useGetCourseList.ts
+12
-0
types.ts
src/modules/student/lab/types.ts
+85
-0
Index.vue
src/modules/student/lab/views/Index.vue
+45
-31
vite.config.ts
vite.config.ts
+6
-2
没有找到文件。
src/modules/admin/system/experiment/types.ts
浏览文件 @
cdcb443e
...
...
@@ -115,4 +115,7 @@ export interface GroupItem {
student_num
:
number
updated_operator
:
string
updated_time
:
string
experiment_name
?:
string
course_name
?:
string
class_name
?:
string
}
src/modules/admin/system/experiment/views/Group.vue
浏览文件 @
cdcb443e
...
...
@@ -64,10 +64,10 @@ function handleRemoveStudent(row: StudentItem) {
<
template
>
<AppCard
title=
"实验管理"
>
<el-descriptions
:column=
"2"
v-if=
"detail"
>
<el-descriptions-item
label=
"实验名称:"
>
{{
detail
.
name
}}
</el-descriptions-item>
<el-descriptions-item
label=
"实验课程:"
>
{{
detail
.
name
}}
</el-descriptions-item>
<el-descriptions-item
label=
"实验名称:"
>
{{
detail
.
experiment_
name
}}
</el-descriptions-item>
<el-descriptions-item
label=
"实验课程:"
>
{{
detail
.
course_
name
}}
</el-descriptions-item>
<el-descriptions-item
label=
"小组名称:"
>
{{
detail
.
name
}}
</el-descriptions-item>
<el-descriptions-item
label=
"班级名称:"
>
{{
detail
.
name
}}
</el-descriptions-item>
<el-descriptions-item
label=
"班级名称:"
>
{{
detail
.
class_
name
}}
</el-descriptions-item>
</el-descriptions>
<AppList
v-bind=
"listOptions"
ref=
"appList"
>
<template
#
header-buttons
>
...
...
src/modules/student/lab/api.ts
0 → 100644
浏览文件 @
cdcb443e
import
httpRequest
from
'@/utils/axios'
// 获取课程列表
export
function
getCourseList
()
{
return
httpRequest
.
get
(
'/api/student/v1/student/course/all'
)
}
// 获取实验指导书
export
function
getExperimentBook
(
params
:
{
experiment_id
:
string
})
{
return
httpRequest
.
get
(
'/api/student/v1/student/experiment-book/detail'
,
{
params
})
}
// 获取实验视频
export
function
getExperimentVideoList
(
params
:
{
experiment_id
:
string
})
{
return
httpRequest
.
get
(
'/api/student/v1/student/experiment-video/all'
,
{
params
})
}
// 获取实验视频播放信息
export
function
getExperimentVideoPlayInfo
(
params
:
{
source_id
:
string
})
{
return
httpRequest
.
get
(
'/api/student/v1/student/experiment-video/replay-list'
,
{
params
})
}
// 获取实验讨论交流
export
function
getExperimentDiscussList
(
params
:
{
experiment_id
:
string
tag
:
string
page
?:
number
'per-page'
?:
number
})
{
return
httpRequest
.
get
(
'/api/student/v1/student/experiment-topic/list'
,
{
params
})
}
// 发表新话题
export
function
addExperimentDiscuss
(
data
:
{
experiment_id
:
string
;
title
:
string
;
content
:
string
})
{
return
httpRequest
.
post
(
'/api/student/v1/student/experiment-topic/issue'
,
data
)
}
// 发表回复
export
function
addExperimentDiscussComment
(
data
:
{
discussion_id
:
string
;
content
:
string
})
{
return
httpRequest
.
post
(
'/api/student/v1/student/experiment-topic/comment'
,
data
)
}
src/modules/student/lab/components/Book.vue
浏览文件 @
cdcb443e
<
script
setup
lang=
"ts"
></
script
>
<
script
setup
lang=
"ts"
>
import
type
{
ExperimentBookType
}
from
'../types'
import
{
getExperimentBook
}
from
'../api'
interface
Props
{
experiment_id
?:
string
}
const
props
=
defineProps
<
Props
>
()
let
detail
=
$ref
<
ExperimentBookType
>
()
function
fetchInfo
()
{
if
(
!
props
.
experiment_id
)
return
getExperimentBook
({
experiment_id
:
props
.
experiment_id
}).
then
(
res
=>
{
detail
=
res
.
data
.
detail
})
}
watchEffect
(()
=>
{
fetchInfo
()
})
const
isEmpty
=
$computed
(()
=>
{
return
!
props
.
experiment_id
||
!
detail
?.
id
})
// 文件扩展名
const
fileExtensionName
=
$computed
(()
=>
{
return
detail
?.
url
?.
split
(
'.'
).
pop
()
||
''
})
// office文件
const
officeUrl
=
$computed
(()
=>
{
return
[
'pptx'
,
'doc'
,
'docx'
,
'xls'
,
'xlsx'
].
includes
(
fileExtensionName
)
?
`https://view.officeapps.live.com/op/view.aspx?src=
${
detail
.
url
}
`
:
''
})
</
script
>
<
template
>
<div>
book
</div>
<el-empty
description=
"暂无数据"
v-if=
"isEmpty"
/>
<template
v-else
>
<iframe
:src=
"officeUrl"
frameborder=
"0"
style=
"width: 100%; height: 100%"
v-if=
"officeUrl"
></iframe>
<object
:data=
"detail.url"
style=
"width: 100%; height: 100%; object-fit: none"
v-else
></object>
</
template
>
</template>
<
style
lang=
"scss"
scoped
></
style
>
src/modules/student/lab/components/Discuss.vue
浏览文件 @
cdcb443e
<
script
setup
lang=
"ts"
>
import
DiscussAddDialog
from
'./DiscussAddDialog.vue'
import
DiscussCommentAddDialog
from
'./DiscussCommentAddDialog.vue'
import
type
{
ExperimentDiscussType
}
from
'../types'
import
{
getExperimentDiscussList
}
from
'../api'
import
DiscussItem
from
'./DiscussItem.vue'
const
DiscussAddDialog
=
defineAsyncComponent
(()
=>
import
(
'./DiscussAddDialog.vue'
))
interface
Props
{
experiment_id
?:
string
}
const
props
=
defineProps
<
Props
>
()
const
discussTag
=
$ref
(
'1'
)
let
list
=
$ref
<
ExperimentDiscussType
[]
>
([])
function
fetchInfo
()
{
if
(
!
props
.
experiment_id
)
return
getExperimentDiscussList
({
experiment_id
:
props
.
experiment_id
,
tag
:
discussTag
}).
then
(
res
=>
{
list
=
res
.
data
.
list
})
}
watchEffect
(()
=>
{
fetchInfo
()
})
const
isEmpty
=
$computed
(()
=>
{
return
!
props
.
experiment_id
||
!
list
.
length
})
const
dialogVisible
=
$ref
(
false
)
const
commentDialogVisible
=
$ref
(
false
)
</
script
>
<
template
>
<el-radio-group>
<el-radio-group
v-model=
"discussTag"
>
<el-radio
:label=
"1"
>
我发起的
</el-radio>
<el-radio
:label=
"2"
>
我回复的
</el-radio>
<el-radio
:label=
"3"
>
我的小组
</el-radio>
...
...
@@ -16,12 +37,13 @@ const commentDialogVisible = $ref(false)
<el-row
justify=
"end"
>
<el-button
round
type=
"primary"
@
click=
"dialogVisible = true"
>
发表新话题
</el-button>
</el-row>
<div>
discuss
</div>
<el-row
justify=
"end"
>
<el-button
round
type=
"primary"
@
click=
"commentDialogVisible = true"
>
我要评论
</el-button>
</el-row>
<DiscussAddDialog
v-model=
"dialogVisible"
></DiscussAddDialog>
<DiscussCommentAddDialog
v-model=
"commentDialogVisible"
></DiscussCommentAddDialog>
<el-empty
description=
"暂无数据"
v-if=
"isEmpty"
/>
<template
v-else
>
<DiscussItem
v-for=
"item in list"
:key=
"item.id"
:data=
"item"
></DiscussItem>
</
template
>
<!-- 发表新话题 -->
<DiscussAddDialog
v-model=
"dialogVisible"
v-if=
"dialogVisible"
></DiscussAddDialog>
</template>
<
style
lang=
"scss"
scoped
></
style
>
src/modules/student/lab/components/DiscussItem.vue
0 → 100644
浏览文件 @
cdcb443e
<
script
setup
lang=
"ts"
>
import
type
{
ExperimentDiscussType
}
from
'../types'
const
DiscussCommentAddDialog
=
defineAsyncComponent
(()
=>
import
(
'./DiscussCommentAddDialog.vue'
))
interface
Props
{
data
:
ExperimentDiscussType
}
defineProps
<
Props
>
()
const
commentDialogVisible
=
$ref
(
false
)
</
script
>
<
template
>
<div
class=
"discuss-item"
>
<div
class=
"discuss-item-user"
>
<img
src=
""
/>
<p></p>
</div>
<div
class=
"discuss-item-main"
></div>
</div>
<el-row
justify=
"end"
>
<el-button
round
type=
"primary"
@
click=
"commentDialogVisible = true"
>
我要评论
</el-button>
</el-row>
<!-- 我要评论 -->
<DiscussCommentAddDialog
v-model=
"commentDialogVisible"
v-if=
"commentDialogVisible"
></DiscussCommentAddDialog>
</
template
>
<
style
lang=
"scss"
scoped
>
.video-item
{
h2
{
font-size
:
16px
;
color
:
#333
;
margin-bottom
:
10px
;
text-align
:
center
;
}
img
{
width
:
100%
;
height
:
200px
;
object-fit
:
cover
;
}
}
</
style
>
src/modules/student/lab/components/Result.vue
浏览文件 @
cdcb443e
<
script
setup
lang=
"ts"
></
script
>
<
script
setup
lang=
"ts"
>
interface
Props
{
experiment_id
?:
string
}
defineProps
<
Props
>
()
</
script
>
<
template
>
<div>
result
</div>
...
...
src/modules/student/lab/components/Video.vue
浏览文件 @
cdcb443e
<
script
setup
lang=
"ts"
></
script
>
<
script
setup
lang=
"ts"
>
import
type
{
ExperimentVideoType
}
from
'../types'
import
VideoItem
from
'./VideoItem.vue'
import
{
getExperimentVideoList
}
from
'../api'
interface
Props
{
experiment_id
?:
string
}
const
props
=
defineProps
<
Props
>
()
let
list
=
$ref
<
ExperimentVideoType
[]
>
([])
function
fetchInfo
()
{
if
(
!
props
.
experiment_id
)
return
getExperimentVideoList
({
experiment_id
:
props
.
experiment_id
}).
then
(
res
=>
{
list
=
res
.
data
.
list
})
}
watchEffect
(()
=>
{
fetchInfo
()
})
const
isEmpty
=
$computed
(()
=>
{
return
!
props
.
experiment_id
||
!
list
.
length
})
</
script
>
<
template
>
<div>
video
</div>
<el-empty
description=
"暂无数据"
v-if=
"isEmpty"
/>
<template
v-else
>
<VideoItem
v-for=
"item in list"
:key=
"item.id"
:data=
"item"
></VideoItem>
</
template
>
</template>
<
style
lang=
"scss"
scoped
></
style
>
src/modules/student/lab/components/VideoItem.vue
0 → 100644
浏览文件 @
cdcb443e
<
script
setup
lang=
"ts"
>
import
type
{
ExperimentVideoType
,
PlayInfo
}
from
'../types'
import
{
getExperimentVideoPlayInfo
}
from
'../api'
interface
Props
{
data
:
ExperimentVideoType
}
const
props
=
defineProps
<
Props
>
()
let
playList
=
$ref
<
PlayInfo
[]
>
([])
function
fetchInfo
()
{
getExperimentVideoPlayInfo
({
source_id
:
props
.
data
.
source_id
}).
then
(
res
=>
{
playList
=
res
.
data
.
play_info_list
})
}
console
.
log
(
playList
)
onMounted
(()
=>
{
fetchInfo
()
})
</
script
>
<
template
>
<div
class=
"video-item"
>
<h2>
{{
data
.
name
}}
</h2>
<img
:src=
"data.cover"
/>
</div>
</
template
>
<
style
lang=
"scss"
scoped
>
.video-item
{
h2
{
font-size
:
16px
;
color
:
#333
;
margin-bottom
:
10px
;
text-align
:
center
;
}
img
{
width
:
100%
;
height
:
200px
;
object-fit
:
cover
;
}
}
</
style
>
src/modules/student/lab/composables/useGetCourseList.ts
0 → 100644
浏览文件 @
cdcb443e
import
type
{
CourseType
}
from
'../types'
import
{
getCourseList
}
from
'../api'
const
courses
=
ref
<
CourseType
[]
>
([])
export
function
useGetCourseList
()
{
!
courses
.
value
.
length
&&
getCourseList
().
then
((
res
:
any
)
=>
{
courses
.
value
=
res
.
data
.
list
})
return
{
courses
}
}
src/modules/student/lab/types.ts
0 → 100644
浏览文件 @
cdcb443e
export
interface
CourseType
{
id
:
string
name
:
string
cover
:
string
experiments
:
ExperimentType
[]
}
export
interface
ExperimentType
{
id
:
string
name
:
string
course_id
:
string
organ_id
:
string
}
export
interface
ExperimentBookType
{
id
:
string
name
:
string
size
:
string
type
:
string
url
:
string
}
export
interface
ExperimentVideoType
{
id
:
string
name
:
string
size
:
string
type
:
string
source_id
:
string
length
:
number
cover
:
string
}
export
interface
PlayInfo
{
BitDepth
:
number
Bitrate
:
string
CreationTime
:
string
Definition
:
string
Duration
:
string
Encrypt
:
number
Format
:
string
Fps
:
string
HDRType
:
string
Height
:
number
JobId
:
string
ModificationTime
:
string
NarrowBandType
:
string
PlayURL
:
string
PreprocessStatus
:
string
Size
:
number
Specification
:
string
Status
:
string
StreamType
:
string
Width
:
number
}
export
interface
ExperimentDiscussType
{
content
:
string
created_operator
:
string
created_time
:
string
id
:
string
is_reply
:
string
replies
:
ExperimentDiscussCommentType
[]
reply_count
:
number
sso_user
:
UserType
student_id
:
string
title
:
string
updated_time
:
string
}
export
interface
ExperimentDiscussCommentType
{
content
:
string
created_time
:
string
discussion_id
:
string
id
:
string
role
:
string
sso_id
:
string
sso_user
:
UserType
}
export
interface
UserType
{
avatar
:
string
id
:
string
nickname
:
string
real_name
:
string
username
:
string
}
src/modules/student/lab/views/Index.vue
浏览文件 @
cdcb443e
<
script
setup
lang=
"ts"
>
import
type
{
CourseType
}
from
'../types'
import
{
HomeFilled
,
Select
,
UploadFilled
,
FullScreen
}
from
'@element-plus/icons-vue'
import
type
{
FormInstance
,
FormRules
}
from
'element-plus'
import
ReportDialog
from
'../components/ReportDialog.vue'
import
{
useGetCourseList
}
from
'../composables/useGetCourseList'
const
Book
=
defineAsyncComponent
(()
=>
import
(
'../components/Book.vue'
))
const
Video
=
defineAsyncComponent
(()
=>
import
(
'../components/Video.vue'
))
const
Discuss
=
defineAsyncComponent
(()
=>
import
(
'../components/Discuss.vue'
))
const
Result
=
defineAsyncComponent
(()
=>
import
(
'../components/Result.vue'
))
const
ReportDialog
=
defineAsyncComponent
(()
=>
import
(
'../components/ReportDialog.vue'
))
// 左侧
const
formRef
=
$ref
<
FormInstance
>
()
const
form
=
reactive
({
course_id
:
''
,
e_id
:
1
})
const
rules
=
ref
<
FormRules
>
({
course_id
:
[{
required
:
true
,
message
:
'请选择课程'
,
trigger
:
'change'
}],
e_id
:
[{
required
:
true
,
message
:
'请选择实验'
,
trigger
:
'change'
}]
const
form
=
reactive
<
{
course
?:
CourseType
;
experiment_id
:
string
}
>
({
course
:
undefined
,
experiment_id
:
'6965149866569760768'
})
// 课程列表
const
{
courses
}
=
useGetCourseList
()
// 实验列表
const
experimentList
=
$computed
(()
=>
{
return
form
.
course
?.
experiments
||
[]
})
// 右侧
const
LAB_URL
=
import
.
meta
.
env
.
VITE_LAB_URL
...
...
@@ -61,33 +66,30 @@ onUnmounted(() => {
<
template
>
<section
class=
"lab"
>
<div
class=
"lab-left"
>
<el-form
:model=
"form"
:rules=
"rules"
label-suffix=
":"
hide-required-asterisk
ref=
"formRef"
style=
"--el-text-color-regular: #fff"
>
<el-form-item
label=
"请选择课程"
prop=
"course_id"
>
<el-select
style=
"width: 100%"
></el-select>
<el-form
:model=
"form"
label-suffix=
":"
hide-required-asterisk
>
<el-form-item
label=
"请选择课程"
>
<el-select
value-key=
"id"
v-model=
"form.course"
style=
"width: 100%"
>
<el-option
v-for=
"item in courses"
:key=
"item.id"
:label=
"item.name"
:value=
"item"
></el-option>
</el-select>
</el-form-item>
<el-form-item
label=
"请选择实验"
prop=
"e_id"
>
<el-select
style=
"width: 100%"
></el-select>
<el-form-item
label=
"请选择实验"
prop=
"experiment_id"
>
<el-select
v-model=
"form.experiment_id"
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"
>
<el-tab-pane
label=
"实训指导"
name=
"first"
>
<Book></Book>
<el-tabs
type=
"border-card"
stretch
>
<el-tab-pane
label=
"实训指导"
lazy
>
<Book
:experiment_id=
"form.experiment_id"
></Book>
</el-tab-pane>
<el-tab-pane
label=
"操作视频"
name=
"second"
>
<Video></Video>
<el-tab-pane
label=
"操作视频"
lazy
>
<Video
:experiment_id=
"form.experiment_id"
></Video>
</el-tab-pane>
<el-tab-pane
label=
"讨论交流"
name=
"third"
>
<Discuss></Discuss>
<el-tab-pane
label=
"讨论交流"
lazy
>
<Discuss
:experiment_id=
"form.experiment_id"
></Discuss>
</el-tab-pane>
<el-tab-pane
label=
"过程与结果"
name=
"fourth"
>
<Result></Result>
<el-tab-pane
label=
"过程与结果"
lazy
>
<Result
:experiment_id=
"form.experiment_id"
></Result>
</el-tab-pane>
</el-tabs>
</div>
...
...
@@ -119,8 +121,8 @@ onUnmounted(() => {
</div>
</div>
</section>
<ReportDialog
v-model=
"reportDialogVisible"
></ReportDialog>
<!-- 上传报告 -->
<ReportDialog
v-model=
"reportDialogVisible"
v-if=
"reportDialogVisible"
></ReportDialog>
</
template
>
<
style
lang=
"scss"
scoped
>
...
...
@@ -129,11 +131,23 @@ onUnmounted(() => {
height
:
100%
;
}
.lab-left
{
display
:
flex
;
flex-direction
:
column
;
width
:
500px
;
padding
:
20px
;
color
:
#fff
;
background-color
:
rgba
(
45
,
48
,
55
,
1
);
border-radius
:
6px
;
.el-tabs
{
flex
:
1
;
}
:deep
(
.el-tabs__content
)
{
height
:
calc
(
100%
-
40px
);
box-sizing
:
border-box
;
}
:deep
(
.el-tab-pane
)
{
height
:
100%
;
overflow-y
:
auto
;
}
}
.lab-right
{
margin-left
:
20px
;
...
...
vite.config.ts
浏览文件 @
cdcb443e
...
...
@@ -26,8 +26,12 @@ export default defineConfig(({ mode }) => ({
cert
:
fs
.
readFileSync
(
path
.
join
(
__dirname
,
'./https/dev.ezijing.com.pem'
))
},
proxy
:
{
'/api'
:
'https://resource-center.ezijing.com'
,
'/lab'
:
'https://dev.ezijing.com'
'/api/student'
:
{
target
:
'http://test-resource-api.ezijing.com:8001'
,
changeOrigin
:
true
,
rewrite
:
path
=>
path
.
replace
(
/^
\/
api
\/
student/
,
''
)
},
'/api'
:
'https://resource-center.ezijing.com'
}
},
resolve
:
{
...
...
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论