Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
C
center-resource
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
图表
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
EzijingWeb
center-resource
Commits
48826ec2
提交
48826ec2
authored
3月 20, 2026
作者:
王鹏飞
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
feat: 新增案例授权
上级
151ff894
全部展开
隐藏空白字符变更
内嵌
并排
正在显示
9 个修改的文件
包含
528 行增加
和
1 行删除
+528
-1
Aside.vue
src/components/layout/Aside.vue
+1
-1
api.ts
src/modules/case-auth/api.ts
+76
-0
useCaseAuthorization.ts
src/modules/case-auth/composables/useCaseAuthorization.ts
+0
-0
useCaseLibrary.ts
src/modules/case-auth/composables/useCaseLibrary.ts
+20
-0
useGetCourseList.ts
src/modules/case-auth/composables/useGetCourseList.ts
+17
-0
useGetExperimentList.ts
src/modules/case-auth/composables/useGetExperimentList.ts
+23
-0
index.ts
src/modules/case-auth/index.ts
+10
-0
types.ts
src/modules/case-auth/types.ts
+77
-0
Index.vue
src/modules/case-auth/views/Index.vue
+304
-0
没有找到文件。
src/components/layout/Aside.vue
浏览文件 @
48826ec2
...
...
@@ -43,7 +43,7 @@ function handleClick(path: string) {
</
script
>
<
template
>
<aside
class=
"app-aside"
>
<aside
class=
"app-aside"
v-if=
"menuList.length > 0"
>
<nav
class=
"nav"
>
<el-menu
:default-active=
"defaultActive"
class=
"app-menu"
>
<template
v-for=
"item in menuList"
:key=
"item.path"
>
...
...
src/modules/case-auth/api.ts
0 → 100644
浏览文件 @
48826ec2
import
{
getCreateAuth
,
updateAuth
}
from
'@/api/base'
import
httpRequest
from
'@/utils/axios'
import
type
{
BookAuthorizeCreateItem
,
CaseAuthorizeCreateItem
,
ResourceDocumentCreateItem
,
ResourceVideoCreateItem
,
VideoAuthorizeCreateItem
,
VideoUploadAuthParams
,
VideoUploadRefreshParams
,
}
from
'./types'
// 获取课程列表
export
function
getCourseList
()
{
return
httpRequest
.
get
(
'/api/lab/v1/teacher/course/list'
)
}
// 获取实验列表
export
function
getExperimentList
(
params
:
{
course_id
:
string
})
{
return
httpRequest
.
get
(
'/api/resource/v1/backend/experiment/experiments'
,
{
params
})
}
// 创建案例原文
export
function
createCase
(
data
:
CaseAuthorizeCreateItem
)
{
return
httpRequest
.
post
(
'/api/lab/v1/teacher/experiment-cases/create'
,
data
)
}
// 创建指导书
export
function
createBook
(
data
:
BookAuthorizeCreateItem
)
{
return
httpRequest
.
post
(
'/api/lab/v1/teacher/book/create'
,
data
)
}
// 创建操作视频
export
function
createVideo
(
data
:
VideoAuthorizeCreateItem
)
{
return
httpRequest
.
post
(
'/api/lab/v1/teacher/video/create'
,
data
)
}
// 获取上传视频凭证
export
function
getUploadVideoAuth
(
data
:
VideoUploadAuthParams
)
{
return
httpRequest
.
post
(
'/api/lab/v1/teacher/video/auth-create'
,
data
)
}
// 刷新上传视频地址凭证
export
function
updateUploadVideoAuth
(
data
:
VideoUploadRefreshParams
)
{
return
httpRequest
.
post
(
'/api/lab/v1/teacher/video/create-auth'
,
data
)
}
// 统一资源平台视频上传凭证
export
function
getResourceUploadVideoAuth
(
data
:
VideoUploadAuthParams
)
{
return
getCreateAuth
(
data
)
}
// 统一资源平台刷新上传视频地址凭证
export
function
updateResourceUploadVideoAuth
(
data
:
VideoUploadRefreshParams
)
{
return
updateAuth
(
data
)
}
// 创建统一资源平台视频
export
function
createResourceVideo
(
data
:
ResourceVideoCreateItem
)
{
return
httpRequest
.
post
(
'/api/resource/v1/resource/video/create'
,
data
)
}
// 创建统一资源平台课件
export
function
createResourceCourseware
(
data
:
ResourceDocumentCreateItem
)
{
return
httpRequest
.
post
(
'/api/resource/v1/resource/courseware/create'
,
data
)
}
// 创建统一资源平台教案
export
function
createResourceLessonPlan
(
data
:
ResourceDocumentCreateItem
)
{
return
httpRequest
.
post
(
'/api/resource/v1/resource/lesson-plan/create'
,
data
)
}
// 创建统一资源平台其他资料
export
function
createResourceOther
(
data
:
ResourceDocumentCreateItem
)
{
return
httpRequest
.
post
(
'/api/resource/v1/resource/other-information/create'
,
data
)
}
src/modules/case-auth/composables/useCaseAuthorization.ts
0 → 100644
浏览文件 @
48826ec2
差异被折叠。
点击展开。
src/modules/case-auth/composables/useCaseLibrary.ts
0 → 100644
浏览文件 @
48826ec2
import
axios
from
'axios'
import
type
{
CaseLibraryItem
}
from
'../types'
export
function
useCaseLibrary
()
{
const
list
=
ref
<
CaseLibraryItem
[]
>
([])
const
loading
=
ref
(
false
)
function
fetchList
()
{
loading
.
value
=
true
return
axios
.
get
(
`https://webapp-pub.ezijing.com/case_library/case.json?_t=
${
Date
.
now
()}
`
)
.
then
((
res
)
=>
{
list
.
value
=
res
.
data
})
.
finally
(()
=>
{
loading
.
value
=
false
})
}
return
{
list
,
loading
,
fetchList
}
}
src/modules/case-auth/composables/useGetCourseList.ts
0 → 100644
浏览文件 @
48826ec2
import
{
getCourseList
}
from
'../api'
export
interface
CourseType
{
id
:
string
name
:
string
}
const
courses
=
ref
<
CourseType
[]
>
([])
export
function
useGetCourseList
()
{
function
updateCourses
()
{
getCourseList
().
then
((
res
:
any
)
=>
{
courses
.
value
=
res
.
data
})
}
return
{
courses
,
updateCourses
}
}
src/modules/case-auth/composables/useGetExperimentList.ts
0 → 100644
浏览文件 @
48826ec2
import
{
getExperimentList
}
from
'../api'
export
interface
ExperimentType
{
id
:
string
name
:
string
}
export
function
useGetExperimentList
()
{
const
experiments
=
ref
<
ExperimentType
[]
>
([])
function
updateExperiments
(
courseId
?:
string
)
{
if
(
!
courseId
)
{
experiments
.
value
=
[]
return
}
getExperimentList
({
course_id
:
courseId
}).
then
((
res
:
any
)
=>
{
experiments
.
value
=
res
.
data
}).
catch
((
err
)
=>
{
console
.
error
(
'获取实验列表失败'
,
err
)
experiments
.
value
=
[]
})
}
return
{
experiments
,
updateExperiments
}
}
src/modules/case-auth/index.ts
0 → 100644
浏览文件 @
48826ec2
import
type
{
RouteRecordRaw
}
from
'vue-router'
import
AppLayout
from
'@/components/layout/Index.vue'
export
const
routes
:
Array
<
RouteRecordRaw
>
=
[
{
path
:
'/case-auth'
,
component
:
AppLayout
,
children
:
[{
path
:
''
,
component
:
()
=>
import
(
'./views/Index.vue'
)
}],
},
]
src/modules/case-auth/types.ts
0 → 100644
浏览文件 @
48826ec2
export
interface
CaseLibraryFile
{
type
:
string
type_name
:
string
name
:
string
url
:
string
size
?:
string
source_id
?:
string
created_at
:
string
updated_at
:
string
}
export
interface
CaseLibraryItem
{
id
:
string
name
:
string
description
:
string
files
:
CaseLibraryFile
[]
operator
:
{
id
:
string
;
name
:
string
}
created_at
:
string
updated_at
:
string
}
export
type
CaseFileSelectionType
=
'case'
|
'ppt'
|
'book'
|
'video'
|
'dataset'
export
type
AuthorizePlatform
=
'resource'
|
'experiment'
export
interface
CaseAuthorizeCreateItem
{
experiment_id
:
string
status
:
string
name
:
string
type
:
string
url
:
string
size
:
string
}
export
interface
BookAuthorizeCreateItem
{
experiment_id
:
string
status
:
string
name
:
string
type
:
string
url
:
string
size
:
string
}
export
interface
VideoAuthorizeCreateItem
{
experiment_id
:
string
status
:
string
name
:
string
source_id
:
string
}
export
interface
VideoUploadAuthParams
{
title
:
string
file_name
:
string
}
export
interface
VideoUploadRefreshParams
{
source_id
:
string
}
export
interface
ResourceDocumentCreateItem
{
name
:
string
source
:
string
classification
:
string
knowledge_points
?:
string
url
:
string
type
:
string
size
:
string
}
export
interface
ResourceVideoCreateItem
{
name
:
string
source
:
string
classification
:
string
knowledge_points
:
string
cover
:
string
source_id
:
string
}
src/modules/case-auth/views/Index.vue
0 → 100644
浏览文件 @
48826ec2
<
script
setup
lang=
"ts"
>
import
{
useCaseAuthorization
}
from
'../composables/useCaseAuthorization'
const
defaultProps
=
{
children
:
'children'
,
label
:
'category_name'
,
value
:
'id'
,
}
const
{
caseFileSectionConfig
,
caseFileTypeMap
,
categoryList
,
courses
,
experiments
,
fileSelections
,
groupedFiles
,
list
,
loading
,
platformSelections
,
progress
,
progressText
,
resourceClassification
,
selectedCase
,
selectedCaseId
,
selectedCount
,
selectedCourse
,
selectedExperiment
,
submitting
,
getAllChecked
,
getFileKey
,
getFilesByType
,
handleCaseChange
,
handleToggleAll
,
isTypeSelectable
,
submitAuthorize
,
}
=
useCaseAuthorization
()
</
script
>
<
template
>
<AppCard
title=
"案例授权"
>
<div
class=
"case-auth-toolbar"
>
<el-checkbox-group
v-model=
"platformSelections"
>
<el-checkbox
label=
"resource"
>
统一资源平台
</el-checkbox>
<el-checkbox
label=
"experiment"
>
实操平台
</el-checkbox>
</el-checkbox-group>
<el-tree-select
v-if=
"platformSelections.includes('resource')"
v-model=
"resourceClassification"
:data=
"categoryList"
:props=
"defaultProps"
node-key=
"id"
clearable
check-strictly
filterable
style=
"width: 240px"
placeholder=
"请选择统一资源分类"
/>
<el-select
v-if=
"platformSelections.includes('experiment')"
v-model=
"selectedCourse"
placeholder=
"请选择课程"
filterable
clearable
style=
"width: 200px"
>
<el-option
v-for=
"item in courses"
:key=
"item.id"
:label=
"item.name"
:value=
"item.id"
/>
</el-select>
<el-select
v-if=
"platformSelections.includes('experiment')"
v-model=
"selectedExperiment"
placeholder=
"请选择实验"
filterable
clearable
style=
"width: 200px"
>
<el-option
v-for=
"item in experiments"
:key=
"item.id"
:label=
"item.name"
:value=
"item.id"
/>
</el-select>
<el-button
type=
"primary"
:loading=
"submitting"
@
click=
"submitAuthorize"
:disabled=
"!selectedCount"
>
批量授权
</el-button>
</div>
<el-alert
type=
"warning"
:closable=
"false"
class=
"case-auth-alert"
>
<div
class=
"case-auth-alert__content"
>
<div
class=
"case-auth-alert__title"
>
重要提示:
</div>
<div>
1、授权到实操平台前请先创建课程和实验
</div>
<div>
2、授权到统一资源平台时必须选择分类
</div>
<div
class=
"case-auth-alert__title"
>
授权资源映射说明:
</div>
<div>
1、案例原文 -> 实操平台:实验案例原文
</div>
<div>
2、案例指导书 -> 实操平台:实验案例指导书;统一资源平台:教案
</div>
<div>
3、案例PPT -> 统一资源平台:课件
</div>
<div>
4、案例操作视频 -> 统一资源平台:视频;实操平台:实验操作视频
</div>
<div>
5、案例数据集 -> 统一资源平台:其他资料
</div>
</div>
</el-alert>
<div
v-if=
"selectedCount || submitting || progress"
class=
"case-auth-progress"
>
<div
class=
"case-auth-progress__header"
>
<span>
{{
progressText
||
`准备处理 0/${selectedCount
}
`
}}
<
/span
>
<
span
>
{{
progress
}}
%<
/span
>
<
/div
>
<
el
-
progress
:
percentage
=
"progress"
:
show
-
text
=
"false"
/>
<
/div
>
<
div
v
-
loading
=
"loading"
class
=
"case-list"
>
<
div
v
-
for
=
"item in list"
:
key
=
"item.id"
class
=
"case-card"
:
class
=
"{ 'case-card--active': selectedCaseId === item.id
}
"
@
click
=
"handleCaseChange(item.id)"
>
<
div
class
=
"case-card__top"
>
<
div
>
<
div
class
=
"case-card__name"
>
{{
item
.
name
}}
<
/div
>
<
div
class
=
"case-card__id"
>
{{
item
.
id
}}
<
/div
>
<
/div
>
<
el
-
radio
:
model
-
value
=
"selectedCaseId === item.id"
:
label
=
"true"
>
选择
<
/el-radio
>
<
/div
>
<
div
class
=
"case-card__desc"
>
{{
item
.
description
||
'暂无案例简介'
}}
<
/div
>
<
div
class
=
"case-card__meta"
>
<
el
-
tag
v
-
for
=
"section in caseFileSectionConfig"
:
key
=
"section.key"
size
=
"small"
:
type
=
"getFilesByType(item.files, caseFileTypeMap[section.key]).length ? 'success' : 'info'"
>
{{
section
.
title
}}
{{
getFilesByType
(
item
.
files
,
caseFileTypeMap
[
section
.
key
]).
length
}}
<
/el-tag
>
<
/div
>
<
/div
>
<
/div
>
<
div
v
-
if
=
"selectedCase"
class
=
"case-auth-sections"
>
<
div
v
-
for
=
"section in caseFileSectionConfig"
:
key
=
"section.key"
class
=
"case-auth-section"
:
class
=
"{ 'case-auth-section--disabled': !isTypeSelectable(section.key)
}
"
>
<
div
class
=
"case-auth-section__header"
>
<
div
class
=
"case-auth-section__title"
>
{{
section
.
title
}}
<
/div
>
<
el
-
checkbox
:
model
-
value
=
"getAllChecked(section.key)"
:
disabled
=
"!groupedFiles[section.key].length || !isTypeSelectable(section.key)"
@
update
:
model
-
value
=
"(value) => handleToggleAll(section.key, !!value)"
>
全选
<
/el-checkbox
>
<
/div
>
<
el
-
checkbox
-
group
v
-
model
=
"fileSelections[section.key]"
class
=
"case-auth-options"
>
<
el
-
checkbox
v
-
for
=
"file in groupedFiles[section.key]"
:
key
=
"getFileKey(file)"
:
label
=
"getFileKey(file)"
:
disabled
=
"!isTypeSelectable(section.key)"
>
{{
file
.
name
}}
<
/el-checkbox
>
<
/el-checkbox-group
>
<
el
-
empty
v
-
if
=
"!groupedFiles[section.key].length"
:
description
=
"section.emptyText"
:
image
-
size
=
"72"
/>
<
/div
>
<
/div
>
<
/AppCard
>
<
/template
>
<
style
lang
=
"scss"
scoped
>
.
case
-
auth
-
toolbar
{
display
:
flex
;
align
-
items
:
center
;
flex
-
wrap
:
wrap
;
gap
:
10
px
;
margin
-
bottom
:
16
px
;
}
.
case
-
auth
-
alert
{
margin
-
bottom
:
16
px
;
}
.
case
-
auth
-
alert__title
{
font
-
weight
:
600
;
}
.
case
-
auth
-
alert__content
{
display
:
flex
;
flex
-
direction
:
column
;
gap
:
6
px
;
line
-
height
:
1.6
;
}
.
case
-
auth
-
progress
{
margin
-
bottom
:
16
px
;
padding
:
12
px
16
px
;
background
:
var
(
--
el
-
fill
-
color
-
light
);
border
-
radius
:
8
px
;
}
.
case
-
auth
-
progress__header
{
display
:
flex
;
justify
-
content
:
space
-
between
;
gap
:
12
px
;
margin
-
bottom
:
8
px
;
font
-
size
:
14
px
;
color
:
var
(
--
el
-
text
-
color
-
regular
);
}
.
case
-
list
{
display
:
grid
;
grid
-
template
-
columns
:
repeat
(
3
,
minmax
(
0
,
1
fr
));
gap
:
16
px
;
}
.
case
-
card
{
padding
:
16
px
;
border
:
1
px
solid
var
(
--
el
-
border
-
color
);
border
-
radius
:
10
px
;
background
:
#
fff
;
cursor
:
pointer
;
transition
:
border
-
color
0.2
s
ease
,
box
-
shadow
0.2
s
ease
;
}
.
case
-
card
:
hover
,
.
case
-
card
--
active
{
border
-
color
:
var
(
--
el
-
color
-
primary
);
box
-
shadow
:
0
0
0
2
px
rgb
(
64
158
255
/
12
%
);
}
.
case
-
card__top
{
display
:
flex
;
align
-
items
:
flex
-
start
;
justify
-
content
:
space
-
between
;
gap
:
12
px
;
margin
-
bottom
:
10
px
;
}
.
case
-
card__name
{
font
-
size
:
16
px
;
font
-
weight
:
600
;
color
:
var
(
--
el
-
text
-
color
-
primary
);
}
.
case
-
card__id
{
margin
-
top
:
4
px
;
font
-
size
:
12
px
;
color
:
var
(
--
el
-
text
-
color
-
secondary
);
}
.
case
-
card__desc
{
min
-
height
:
44
px
;
font
-
size
:
14
px
;
line
-
height
:
1.6
;
color
:
var
(
--
el
-
text
-
color
-
regular
);
}
.
case
-
card__meta
{
display
:
flex
;
flex
-
wrap
:
wrap
;
gap
:
8
px
;
margin
-
top
:
12
px
;
}
.
case
-
auth
-
sections
{
display
:
grid
;
grid
-
template
-
columns
:
repeat
(
3
,
minmax
(
0
,
1
fr
));
gap
:
16
px
;
margin
-
top
:
16
px
;
}
.
case
-
auth
-
section
{
padding
:
16
px
;
background
:
var
(
--
el
-
fill
-
color
-
light
);
border
-
radius
:
8
px
;
min
-
height
:
180
px
;
}
.
case
-
auth
-
section
--
disabled
{
opacity
:
0.65
;
}
.
case
-
auth
-
section__header
{
display
:
flex
;
align
-
items
:
center
;
justify
-
content
:
space
-
between
;
gap
:
12
px
;
margin
-
bottom
:
12
px
;
}
.
case
-
auth
-
section__title
{
font
-
size
:
15
px
;
font
-
weight
:
600
;
color
:
var
(
--
el
-
text
-
color
-
primary
);
}
.
case
-
auth
-
options
{
display
:
flex
;
flex
-
direction
:
column
;
gap
:
10
px
;
}
@
media
(
max
-
width
:
1200
px
)
{
.
case
-
list
,
.
case
-
auth
-
sections
{
grid
-
template
-
columns
:
1
fr
;
}
}
<
/style
>
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论