Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
C
center-resource
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
图表
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
EzijingWeb
center-resource
Commits
8c25052d
提交
8c25052d
authored
12月 30, 2024
作者:
王鹏飞
浏览文件
操作
浏览文件
下载
差异文件
Merge branch 'master' into 202412
上级
f0ac0bf7
6b4e5045
隐藏空白字符变更
内嵌
并排
正在显示
25 个修改的文件
包含
1719 行增加
和
131 行删除
+1719
-131
AppList.vue
src/components/base/AppList.vue
+8
-13
api.ts
src/modules/admin/student/api.ts
+26
-7
AddStudent.vue
src/modules/admin/student/components/AddStudent.vue
+2
-2
ImportStudent.vue
src/modules/admin/student/components/ImportStudent.vue
+87
-22
UpdateStudent.vue
src/modules/admin/student/components/UpdateStudent.vue
+138
-0
useData.ts
src/modules/admin/student/composables/useData.ts
+29
-0
List.vue
src/modules/admin/student/views/List.vue
+117
-48
api.ts
src/modules/course/create/api.ts
+27
-0
AddCourseData.vue
...rse/create/components/stepOneComponents/AddCourseData.vue
+2
-1
AddTextbook.vue
...ourse/create/components/stepOneComponents/AddTextbook.vue
+107
-0
AddGraphbookDialog.vue
...reate/components/stepTwoComponents/AddGraphbookDialog.vue
+147
-0
AddTextbookDialog.vue
...create/components/stepTwoComponents/AddTextbookDialog.vue
+153
-0
AddTextbookListDialog.vue
...te/components/stepTwoComponents/AddTextbookListDialog.vue
+119
-0
AddVideoDialog.vue
...se/create/components/stepTwoComponents/AddVideoDialog.vue
+19
-7
StepOne.vue
src/modules/course/create/views/StepOne.vue
+43
-9
StepTwo.vue
src/modules/course/create/views/StepTwo.vue
+92
-19
api.ts
src/modules/course/my/api.ts
+39
-0
Operation.vue
src/modules/course/my/components/Operation.vue
+6
-0
ViewCourseInfo.vue
src/modules/course/my/components/ViewCourseInfo.vue
+2
-1
ViewGraphBook.vue
src/modules/course/my/components/ViewGraphBook.vue
+112
-0
ViewGraphCourse.vue
src/modules/course/my/components/ViewGraphCourse.vue
+112
-0
index.ts
src/modules/course/my/index.ts
+2
-1
Graph.vue
src/modules/course/my/views/Graph.vue
+292
-0
upload.ts
src/utils/upload.ts
+38
-0
vite.config.ts
vite.config.ts
+0
-1
没有找到文件。
src/components/base/AppList.vue
浏览文件 @
8c25052d
...
@@ -25,7 +25,7 @@ const props = withDefaults(
...
@@ -25,7 +25,7 @@ const props = withDefaults(
limit
:
10
,
limit
:
10
,
data
()
{
data
()
{
return
[]
return
[]
}
}
,
}
}
)
)
...
@@ -38,7 +38,7 @@ const page = reactive({ total: 0, size: props.limit, currentPage: 1 })
...
@@ -38,7 +38,7 @@ const page = reactive({ total: 0, size: props.limit, currentPage: 1 })
const
params
=
reactive
({
...
props
.
remote
?.
params
})
const
params
=
reactive
({
...
props
.
remote
?.
params
})
watch
(
watch
(
()
=>
props
.
data
,
()
=>
props
.
data
,
list
=>
{
(
list
)
=>
{
dataList
.
value
=
list
||
[]
dataList
.
value
=
list
||
[]
},
},
{
immediate
:
true
}
{
immediate
:
true
}
...
@@ -147,8 +147,7 @@ defineExpose({ refetch, tableRef, params, loading })
...
@@ -147,8 +147,7 @@ defineExpose({ refetch, tableRef, params, loading })
clearable
clearable
@
change=
"search"
@
change=
"search"
style=
"width: 200px"
style=
"width: 200px"
v-if=
"item.type === 'input'"
v-if=
"item.type === 'input'"
/>
/>
<!-- select -->
<!-- select -->
<el-select
<el-select
v-model=
"params[item.prop]"
v-model=
"params[item.prop]"
...
@@ -156,14 +155,12 @@ defineExpose({ refetch, tableRef, params, loading })
...
@@ -156,14 +155,12 @@ defineExpose({ refetch, tableRef, params, loading })
clearable
clearable
@
change=
"search"
@
change=
"search"
v-if=
"item.type === 'select'"
v-if=
"item.type === 'select'"
style=
"width: 200px"
style=
"width: 200px"
>
>
<el-option
<el-option
:label=
"option[item.labelKey] || option.label"
:label=
"option[item.labelKey] || option.label"
:value=
"option[item.valueKey] || option.value"
:value=
"option[item.valueKey] || option.value"
v-for=
"(option, index) in item.options"
v-for=
"(option, index) in item.options"
:key=
"index"
:key=
"index"
/>
/>
</el-select>
</el-select>
</
template
>
</
template
>
</el-form-item>
</el-form-item>
...
@@ -186,8 +183,7 @@ defineExpose({ refetch, tableRef, params, loading })
...
@@ -186,8 +183,7 @@ defineExpose({ refetch, tableRef, params, loading })
v-bind=
"$attrs"
v-bind=
"$attrs"
style=
"height: 100%"
style=
"height: 100%"
ref=
"tableRef"
ref=
"tableRef"
:header-cell-style=
"{ background: '#EFEFEF' }"
:header-cell-style=
"{ background: '#EFEFEF' }"
>
>
<el-table-column
v-bind=
"item || {}"
v-for=
"item in columns"
:key=
"item.prop"
>
<el-table-column
v-bind=
"item || {}"
v-for=
"item in columns"
:key=
"item.prop"
>
<
template
#
default=
"scope"
v-if=
"item.slots || item.computed"
>
<
template
#
default=
"scope"
v-if=
"item.slots || item.computed"
>
<slot
:name=
"item.slots"
v-bind=
"scope"
v-if=
"item.slots"
></slot>
<slot
:name=
"item.slots"
v-bind=
"scope"
v-if=
"item.slots"
></slot>
...
@@ -206,15 +202,14 @@ defineExpose({ refetch, tableRef, params, loading })
...
@@ -206,15 +202,14 @@ defineExpose({ refetch, tableRef, params, loading })
class=
"table-list-pagination"
class=
"table-list-pagination"
background
background
layout=
"total, sizes, prev, pager, next, jumper"
layout=
"total, sizes, prev, pager, next, jumper"
:page-sizes=
"[10, 20, 30, 50
, 100
]"
:page-sizes=
"[10, 20, 30, 50]"
:page-size=
"page.size"
:page-size=
"page.size"
:total=
"page.total"
:total=
"page.total"
v-model:currentPage=
"page.currentPage"
v-model:currentPage=
"page.currentPage"
@
size-change=
"pageSizeChange"
@
size-change=
"pageSizeChange"
@
current-change=
"fetchList()"
@
current-change=
"fetchList()"
:hide-on-single-page=
"true"
:hide-on-single-page=
"true"
v-if=
"hasPagination"
v-if=
"hasPagination"
>
>
</el-pagination>
</el-pagination>
</div>
</div>
</div>
</div>
...
...
src/modules/admin/student/api.ts
浏览文件 @
8c25052d
...
@@ -4,12 +4,16 @@ import httpRequest from '@/utils/axios'
...
@@ -4,12 +4,16 @@ import httpRequest from '@/utils/axios'
export
function
getStudentList
(
params
?:
{
name
?:
string
;
organ_id
?:
string
;
page
?:
string
;
'per-page'
?:
string
})
{
export
function
getStudentList
(
params
?:
{
name
?:
string
;
organ_id
?:
string
;
page
?:
string
;
'per-page'
?:
string
})
{
return
httpRequest
.
get
(
'/api/resource/v1/learning/student/list'
,
{
params
})
return
httpRequest
.
get
(
'/api/resource/v1/learning/student/list'
,
{
params
})
}
}
// // 导入学生
// 导入学生
export
function
importStudent
(
data
:
{
file
:
any
})
{
export
function
importStudent
(
data
:
{
url
:
string
;
name
:
string
;
size
:
number
})
{
return
httpRequest
.
post
(
'/api/resource/v1/learning/student/import'
,
data
,
{
return
httpRequest
.
post
(
'/api/resource/v1/learning/student/import'
,
data
)
headers
:
{
'Content-Type'
:
'multipart/form-data'
}
})
}
}
// 批量修改学生
export
function
batchUpdateStudent
(
data
:
{
url
:
string
;
name
:
string
;
size
:
number
})
{
return
httpRequest
.
post
(
'/api/resource/v1/learning/student/batch-update'
,
data
)
}
// 导出学生
// 导出学生
export
function
exportStudent
(
params
:
{
name
:
string
;
organ_id
:
string
})
{
export
function
exportStudent
(
params
:
{
name
:
string
;
organ_id
:
string
})
{
return
httpRequest
.
get
(
'/api/resource/v1/learning/student/download'
,
{
params
,
responseType
:
'blob'
})
return
httpRequest
.
get
(
'/api/resource/v1/learning/student/download'
,
{
params
,
responseType
:
'blob'
})
...
@@ -50,10 +54,25 @@ export function getStuDetail(params?: { id: string }) {
...
@@ -50,10 +54,25 @@ export function getStuDetail(params?: { id: string }) {
return
httpRequest
.
get
(
'/api/resource/v1/learning/student/view'
,
{
params
})
return
httpRequest
.
get
(
'/api/resource/v1/learning/student/view'
,
{
params
})
}
}
// 班级搜索
// 班级搜索
export
function
getClassList
(
params
?:
{
specialty_id
:
string
;
organ_id
:
string
;
page
?:
string
;
'per-page'
?:
string
})
{
export
function
searchClass
(
params
?:
{
specialty_id
:
string
;
organ_id
:
string
;
page
?:
string
;
'per-page'
?:
string
})
{
return
httpRequest
.
get
(
'/api/resource/v1/learning/student/search-class'
,
{
params
})
return
httpRequest
.
get
(
'/api/resource/v1/learning/student/search-class'
,
{
params
})
}
}
// 获取专业列表
// 获取专业列表
export
function
getProList
(
params
?:
{
name
?:
string
;
page
?:
string
;
'per-page'
?:
string
})
{
export
function
getProList
(
params
?:
{
name
?:
string
;
page
?:
string
;
'per-page'
?:
string
;
sort
?:
string
})
{
return
httpRequest
.
get
(
'/api/resource/v1/backend/specialty/list'
,
{
params
})
return
httpRequest
.
get
(
'/api/resource/v1/backend/specialty/list'
,
{
params
})
}
}
// 获取班级列表
export
function
getClassList
(
params
?:
{
specialty_id
:
string
organ_id
:
string
page
?:
string
'per-page'
?:
string
sort
?:
string
})
{
return
httpRequest
.
get
(
'/api/resource/v1/learning/class/list'
,
{
params
})
}
// 学生导入进度查询
export
function
getStudentProgress
(
params
:
{
id
:
string
})
{
return
httpRequest
.
get
(
'/api/resource/v1/learning/student/progress'
,
{
params
})
}
src/modules/admin/student/components/AddStudent.vue
浏览文件 @
8c25052d
...
@@ -4,7 +4,7 @@ import { ElMessage } from 'element-plus'
...
@@ -4,7 +4,7 @@ import { ElMessage } from 'element-plus'
import
{
useProjectList
}
from
'@/composables/useGetProjectList'
import
{
useProjectList
}
from
'@/composables/useGetProjectList'
import
{
useMapStore
}
from
'@/stores/map'
import
{
useMapStore
}
from
'@/stores/map'
import
{
useUserStore
}
from
'@/stores/user'
import
{
useUserStore
}
from
'@/stores/user'
import
{
addStudent
,
updateStudent
,
getStuDetail
,
getClassList
,
getProList
}
from
'../api'
import
{
addStudent
,
updateStudent
,
getStuDetail
,
searchClass
,
getProList
}
from
'../api'
const
store
=
useMapStore
()
const
store
=
useMapStore
()
const
userStore
=
useUserStore
()
const
userStore
=
useUserStore
()
...
@@ -112,7 +112,7 @@ if (userStore.roles[0].name !== '超级管理员') {
...
@@ -112,7 +112,7 @@ if (userStore.roles[0].name !== '超级管理员') {
}
}
// 获取班级列表
// 获取班级列表
const
handleClassList
=
()
=>
{
const
handleClassList
=
()
=>
{
getClassList
({
searchClass
({
specialty_id
:
form
.
specialty_id
,
specialty_id
:
form
.
specialty_id
,
organ_id
:
form
.
organ_id
||
userStore
.
organization
?.
id
,
organ_id
:
form
.
organ_id
||
userStore
.
organization
?.
id
,
'per-page'
:
'100'
'per-page'
:
'100'
...
...
src/modules/admin/student/components/ImportStudent.vue
浏览文件 @
8c25052d
<
script
lang=
"ts"
setup
>
<
script
lang=
"ts"
setup
>
import
{
ElMessage
}
from
'element-plus'
import
{
ElMessage
}
from
'element-plus'
import
{
UploadFilled
}
from
'@element-plus/icons-vue'
import
{
UploadFilled
,
Loading
}
from
'@element-plus/icons-vue'
import
{
splitStrLast
}
from
'@/utils/util'
import
{
splitStrLast
}
from
'@/utils/util'
import
{
importStudent
}
from
'../api'
import
{
importStudent
,
getStudentProgress
}
from
'../api'
import
{
upload
}
from
'@/utils/upload'
const
emit
=
defineEmits
<
Emits
>
()
const
emit
=
defineEmits
<
Emits
>
()
const
upload
=
ref
()
const
upload
Ref
=
ref
()
const
fileList
=
ref
([])
// 文件列表
const
fileList
=
ref
([])
// 文件列表
defineProps
({
defineProps
({
isShowImportDialog
:
{
isShowImportDialog
:
{
type
:
Boolean
type
:
Boolean
,
}
}
,
})
})
interface
Emits
{
interface
Emits
{
(
e
:
'update:isShowImportDialog'
,
isShowImportDialog
:
boolean
):
void
(
e
:
'update:isShowImportDialog'
,
isShowImportDialog
:
boolean
):
void
...
@@ -31,26 +33,64 @@ const beforeUpload = (file: any) => {
...
@@ -31,26 +33,64 @@ const beforeUpload = (file: any) => {
return
true
return
true
}
}
}
}
const
fetchFileUpload
=
(
option
:
any
)
=>
{
const
loading
=
ref
(
false
)
return
new
Promise
(()
=>
{
importStudent
({
file
:
option
.
file
}).
then
(()
=>
{
const
progress
=
reactive
({
ElMessage
.
success
(
'导入数据成功'
)
progress
:
'-'
,
emit
(
'update:isShowImportDialog'
,
false
)
total
:
'-'
,
emit
(
'create'
)
message
:
'导入中'
,
})
status
:
2
,
})
})
let
timer
:
any
=
null
const
fetchFileUpload
=
async
(
option
:
any
)
=>
{
const
file
=
option
.
file
const
url
=
await
upload
(
file
)
const
res
=
await
importStudent
({
url
,
name
:
file
.
name
,
size
:
file
.
size
})
const
id
=
res
.
data
.
id
loading
.
value
=
true
timer
&&
clearInterval
(
timer
)
timer
=
setInterval
(()
=>
{
getStudentProgress
({
id
})
.
then
((
res
)
=>
{
const
data
=
res
.
data
Object
.
assign
(
progress
,
data
)
if
(
data
.
status
===
3
||
data
.
status
===
4
)
{
clearInterval
(
timer
)
loading
.
value
=
false
ElMessage
({
type
:
data
.
status
===
3
?
'success'
:
'error'
,
message
:
data
.
message
,
})
emit
(
'create'
)
}
})
.
catch
(()
=>
{
clearInterval
(
timer
)
loading
.
value
=
false
})
},
1000
)
}
}
onUnmounted
(()
=>
{
timer
&&
clearInterval
(
timer
)
})
const
handleSubmitUpload
=
()
=>
{
const
handleSubmitUpload
=
()
=>
{
upload
.
value
.
submit
()
upload
Ref
.
value
.
submit
()
}
}
</
script
>
</
script
>
<
template
>
<
template
>
<el-dialog
:model-value=
"isShowImportDialog"
draggable
:before-close=
"handleCancel"
title=
"批量导入学生"
width=
"30%"
>
<el-dialog
draggable
:model-value=
"isShowImportDialog"
:close-on-click-modal=
"false"
:before-close=
"handleCancel"
title=
"批量导入学生"
width=
"500px"
custom-class=
"my-dialog"
>
<el-upload
<el-upload
style=
"text-align: center"
style=
"text-align: center"
class=
"file-import"
class=
"file-import"
ref=
"upload"
ref=
"upload
Ref
"
action=
"#"
action=
"#"
accept=
".xls,.xlsx"
accept=
".xls,.xlsx"
drag
drag
...
@@ -62,14 +102,18 @@ const handleSubmitUpload = () => {
...
@@ -62,14 +102,18 @@ const handleSubmitUpload = () => {
<el-icon
class=
"el-icon--upload"
><upload-filled
/></el-icon>
<el-icon
class=
"el-icon--upload"
><upload-filled
/></el-icon>
<div
class=
"el-upload__text"
>
将文件拖至此处,点击上传
</div>
<div
class=
"el-upload__text"
>
将文件拖至此处,点击上传
</div>
</el-upload>
</el-upload>
<div
style=
"margin-bottom: 10px; text-align:
center
"
>
<div
style=
"margin-bottom: 10px; text-align:
right
"
>
导入模板下载:
<a
<a
href=
"/center_resource/%E5%AD%A6%E7%94%9F%E5%AF%BC%E5%85%A5%E6%A8%A1%E6%9D%BF.xlsx"
href=
"/center_resource/%E5%AD%A6%E7%94%9F%E5%AF%BC%E5%85%A5%E6%A8%A1%E6%9D%BF.xlsx"
download=
"学生模板"
download=
"批量导入学生模板"
>
><el-link
type=
"primary"
>
学生模板.xlsx
</el-link></a
<el-link
type=
"primary"
>
下载模板
</el-link>
>
</a>
</div>
<div
class=
"dialog-loading"
v-if=
"loading"
>
<el-icon
class=
"is-loading"
><Loading
/></el-icon>
<p>
批量导入中
</p>
<p>
{{
progress
.
progress
}}
/
{{
progress
.
total
}}
</p>
</div>
</div>
<template
#
footer
>
<template
#
footer
>
<span>
<span>
<el-button
@
click=
"handleCancel"
>
取消
</el-button>
<el-button
@
click=
"handleCancel"
>
取消
</el-button>
...
@@ -78,3 +122,24 @@ const handleSubmitUpload = () => {
...
@@ -78,3 +122,24 @@ const handleSubmitUpload = () => {
</
template
>
</
template
>
</el-dialog>
</el-dialog>
</template>
</template>
<
style
lang=
"scss"
>
.my-dialog
{
position
:
relative
;
}
.dialog-loading
{
position
:
absolute
;
left
:
0
;
top
:
0
;
right
:
0
;
bottom
:
0
;
background-color
:
rgba
(
0
,
0
,
0
,
0
.6
);
display
:
flex
;
flex-direction
:
column
;
justify-content
:
center
;
align-items
:
center
;
font-size
:
16px
;
line-height
:
30px
;
color
:
#fff
;
}
</
style
>
src/modules/admin/student/components/UpdateStudent.vue
0 → 100644
浏览文件 @
8c25052d
<
script
lang=
"ts"
setup
>
import
{
ElMessage
}
from
'element-plus'
import
{
UploadFilled
,
Loading
}
from
'@element-plus/icons-vue'
import
{
splitStrLast
}
from
'@/utils/util'
import
{
batchUpdateStudent
,
getStudentProgress
}
from
'../api'
import
{
upload
}
from
'@/utils/upload'
const
emit
=
defineEmits
<
Emits
>
()
const
uploadRef
=
ref
()
const
fileList
=
ref
([])
// 文件列表
defineProps
({
modelValue
:
{
type
:
Boolean
},
})
interface
Emits
{
(
e
:
'update:modelValue'
,
modelValue
:
boolean
):
void
(
e
:
'create'
):
void
}
// 取消
const
handleCancel
=
()
=>
{
emit
(
'update:modelValue'
,
false
)
}
const
beforeUpload
=
(
file
:
any
)
=>
{
const
suffix
=
splitStrLast
(
file
.
name
,
'.'
)
if
(
!
[
'xlsx'
,
'xls'
].
includes
(
suffix
))
{
ElMessage
.
warning
(
'只能上传excel文件'
)
return
false
}
else
{
return
true
}
}
const
loading
=
ref
(
false
)
const
progress
=
reactive
({
progress
:
'-'
,
total
:
'-'
,
message
:
'导入中'
,
status
:
2
,
})
let
timer
:
any
=
null
const
fetchFileUpload
=
async
(
option
:
any
)
=>
{
const
file
=
option
.
file
const
url
=
await
upload
(
file
)
const
res
=
await
batchUpdateStudent
({
url
,
name
:
file
.
name
,
size
:
file
.
size
})
const
id
=
res
.
data
.
id
loading
.
value
=
true
timer
&&
clearInterval
(
timer
)
timer
=
setInterval
(()
=>
{
getStudentProgress
({
id
})
.
then
((
res
)
=>
{
const
data
=
res
.
data
Object
.
assign
(
progress
,
data
)
if
(
data
.
status
===
3
||
data
.
status
===
4
)
{
clearInterval
(
timer
)
loading
.
value
=
false
ElMessage
({
type
:
data
.
status
===
3
?
'success'
:
'error'
,
message
:
data
.
message
,
})
emit
(
'create'
)
}
})
.
catch
(()
=>
{
clearInterval
(
timer
)
loading
.
value
=
false
})
},
1000
)
}
const
handleSubmitUpload
=
()
=>
{
uploadRef
.
value
.
submit
()
}
</
script
>
<
template
>
<el-dialog
draggable
:model-value=
"modelValue"
:close-on-click-modal=
"false"
:before-close=
"handleCancel"
title=
"批量修改学生"
width=
"500px"
>
<el-upload
style=
"text-align: center"
class=
"file-import"
ref=
"uploadRef"
action=
"#"
accept=
".xls,.xlsx"
drag
:auto-upload=
"false"
:file-list=
"fileList"
:limit=
"1"
:before-upload=
"beforeUpload"
:http-request=
"fetchFileUpload"
>
<el-icon
class=
"el-icon--upload"
><upload-filled
/></el-icon>
<div
class=
"el-upload__text"
>
将文件拖至此处,点击上传
</div>
</el-upload>
<div
style=
"margin-bottom: 10px; text-align: right"
>
<a
href=
"/center_resource/%E5%AD%A6%E7%94%9F%E5%AF%BC%E5%85%A5%E6%A8%A1%E6%9D%BF.xlsx"
download=
"批量修改学生模板"
><el-link
type=
"primary"
>
下载模板
</el-link></a
>
</div>
<div
class=
"dialog-loading"
v-if=
"loading"
>
<el-icon
class=
"is-loading"
><Loading
/></el-icon>
<p>
批量修改中
</p>
<p>
{{
progress
.
progress
}}
/
{{
progress
.
total
}}
</p>
</div>
<template
#
footer
>
<span>
<el-button
@
click=
"handleCancel"
>
取消
</el-button>
<el-button
type=
"primary"
@
click=
"handleSubmitUpload"
>
确认
</el-button>
</span>
</
template
>
</el-dialog>
</template>
<
style
lang=
"scss"
>
.my-dialog
{
position
:
relative
;
}
.dialog-loading
{
position
:
absolute
;
left
:
0
;
top
:
0
;
right
:
0
;
bottom
:
0
;
background-color
:
rgba
(
0
,
0
,
0
,
0
.6
);
display
:
flex
;
flex-direction
:
column
;
justify-content
:
center
;
align-items
:
center
;
font-size
:
16px
;
line-height
:
30px
;
color
:
#fff
;
}
</
style
>
src/modules/admin/student/composables/useData.ts
0 → 100644
浏览文件 @
8c25052d
import
{
getClassList
,
getProList
}
from
'../api'
// 专业列表
export
function
useSpecialtyList
()
{
const
items
=
ref
([])
const
params
=
reactive
({
name
:
''
})
const
fetchList
=
async
()
=>
{
const
{
data
}
=
await
getProList
({
...
params
,
'per-page'
:
'100'
,
sort
:
'name'
})
items
.
value
=
data
.
list
}
onMounted
(
fetchList
)
return
{
items
,
params
,
fetchList
}
}
// 班级列表
export
function
useClassList
()
{
const
items
=
ref
([])
const
params
=
reactive
({
organ_id
:
''
,
specialty_id
:
''
})
const
fetchList
=
async
()
=>
{
const
{
data
}
=
await
getClassList
({
...
params
,
'per-page'
:
'100'
,
sort
:
'name'
})
items
.
value
=
data
.
list
}
watch
(
params
,
fetchList
)
onMounted
(
fetchList
)
return
{
items
,
params
,
fetchList
}
}
src/modules/admin/student/views/List.vue
浏览文件 @
8c25052d
...
@@ -3,48 +3,91 @@ import { ElMessage } from 'element-plus'
...
@@ -3,48 +3,91 @@ import { ElMessage } from 'element-plus'
import
{
useProjectList
}
from
'@/composables/useGetProjectList'
import
{
useProjectList
}
from
'@/composables/useGetProjectList'
import
AddStudent
from
'../components/AddStudent.vue'
import
AddStudent
from
'../components/AddStudent.vue'
import
ImportStudent
from
'../components/ImportStudent.vue'
import
ImportStudent
from
'../components/ImportStudent.vue'
import
UpdateStudent
from
'../components/UpdateStudent.vue'
// import SourceAnalysis from '../components/SourceAnalysis.vue'
// import SourceAnalysis from '../components/SourceAnalysis.vue'
import
{
getStudentList
,
exportStudent
,
updateStudent
}
from
'../api'
import
{
getStudentList
,
exportStudent
,
updateStudent
}
from
'../api'
import
{
useUserStore
}
from
'@/stores/user'
import
{
useUserStore
}
from
'@/stores/user'
import
{
useClassList
,
useSpecialtyList
}
from
'../composables/useData'
// 判断当前用户是不是超级管理员
// 判断当前用户是不是超级管理员
const
user
=
useUserStore
().
roles
const
user
=
useUserStore
().
roles
const
isAdmin
=
!!
user
.
find
((
item
:
any
)
=>
item
.
name
===
'超级管理员'
)
const
isAdmin
=
!!
user
.
find
((
item
:
any
)
=>
item
.
name
===
'超级管理员'
)
const
departmentList
:
any
=
useProjectList
(
''
,
'79806610719731712'
).
departmentList
const
{
departmentList
}
=
useProjectList
(
''
,
'79806610719731712'
)
const
appList
=
ref
()
const
appList
=
ref
()
const
id
=
ref
(
''
)
const
id
=
ref
(
''
)
const
title
=
ref
(
''
)
const
title
=
ref
(
''
)
const
isEdit
=
ref
(
''
)
const
isEdit
=
ref
(
''
)
const
isShowAddDialog
=
ref
(
false
)
const
isShowAddDialog
=
ref
(
false
)
const
isShowImportDialog
=
ref
(
false
)
const
isShowImportDialog
=
ref
(
false
)
// 专业
const
{
items
:
specialtyList
}
=
useSpecialtyList
()
// 班级
let
{
items
:
classList
,
params
}
=
useClassList
()
// const isShowAnalysisDialog = ref(false)
// const isShowAnalysisDialog = ref(false)
const
listOptions
=
{
const
listOptions
=
computed
(()
=>
{
remote
:
{
httpRequest
:
getStudentList
,
params
:
{
name
:
''
,
organ_id
:
''
}
},
return
{
filters
:
[
remote
:
{
{
type
:
'input'
,
prop
:
'name'
,
label
:
'学生姓名:'
,
placeholder
:
'学生姓名'
},
httpRequest
:
getStudentList
,
{
type
:
'select'
,
prop
:
'organ_id'
,
slots
:
'filter-department'
}
params
:
{
name
:
''
,
organ_id
:
''
,
mobile
:
''
,
specialty_id
:
''
,
class_id
:
''
},
],
beforeRequest
:
(
requestPrams
:
any
)
=>
{
columns
:
[
params
.
organ_id
=
requestPrams
.
organ_id
{
type
:
'selection'
},
params
.
specialty_id
=
requestPrams
.
specialty_id
{
label
:
'序号'
,
type
:
'index'
,
align
:
'center'
},
return
requestPrams
{
label
:
'学号'
,
prop
:
'sno_number'
,
align
:
'center'
,
minWidth
:
'200'
},
},
{
label
:
'姓名'
,
prop
:
'name'
,
align
:
'center'
,
minWidth
:
'100'
},
},
{
label
:
'性别'
,
prop
:
'gender_name'
,
align
:
'center'
},
filters
:
[
{
label
:
'出生年月'
,
prop
:
'birthday'
,
align
:
'center'
,
minWidth
:
'200'
},
{
{
label
:
'省'
,
prop
:
'province_name'
,
align
:
'center'
},
type
:
'select'
,
{
label
:
'市'
,
prop
:
'city_name'
,
align
:
'center'
},
prop
:
'organ_id'
,
{
label
:
'县'
,
prop
:
'county_name'
,
align
:
'center'
},
label
:
'所属部门/学校:'
,
{
label
:
'联系电话'
,
prop
:
'mobile'
,
align
:
'center'
,
minWidth
:
'200'
},
options
:
departmentList
.
value
,
{
label
:
'部门/学校'
,
prop
:
'organ_id_name'
,
align
:
'center'
,
minWidth
:
'200'
},
labelKey
:
'name'
,
{
label
:
'专业'
,
prop
:
'specialty_id_name'
,
align
:
'center'
,
minWidth
:
'200'
},
valueKey
:
'id'
,
{
label
:
'班级'
,
prop
:
'class_id_name'
,
align
:
'center'
,
minWidth
:
'200'
},
},
{
label
:
'身份证号'
,
prop
:
'id_number'
,
align
:
'center'
,
minWidth
:
'200'
},
{
{
label
:
'生效状态'
,
slots
:
'status'
,
align
:
'center'
},
type
:
'select'
,
{
label
:
'更新时间'
,
prop
:
'updated_time'
,
align
:
'center'
,
minWidth
:
'200'
},
prop
:
'specialty_id'
,
{
label
:
'操作'
,
slots
:
'table-operate'
,
align
:
'center'
,
minWidth
:
'200'
,
fixed
:
'right'
}
label
:
'所属专业:'
,
]
options
:
specialtyList
.
value
,
}
labelKey
:
'name'
,
valueKey
:
'id'
,
},
{
type
:
'select'
,
prop
:
'class_id'
,
label
:
'所属班级:'
,
options
:
classList
.
value
,
labelKey
:
'name'
,
valueKey
:
'id'
,
},
{
type
:
'input'
,
prop
:
'name'
,
label
:
'学生姓名:'
,
placeholder
:
'学生姓名'
},
{
type
:
'input'
,
prop
:
'mobile'
,
label
:
'学生电话:'
,
placeholder
:
'学生电话'
},
],
columns
:
[
// { type: 'selection' },
{
label
:
'序号'
,
type
:
'index'
,
align
:
'center'
},
{
label
:
'学号'
,
prop
:
'sno_number'
,
align
:
'center'
,
minWidth
:
'200'
},
{
label
:
'姓名'
,
prop
:
'name'
,
align
:
'center'
,
minWidth
:
'100'
},
{
label
:
'性别'
,
prop
:
'gender_name'
,
align
:
'center'
},
{
label
:
'联系电话'
,
prop
:
'mobile'
,
align
:
'center'
,
minWidth
:
'200'
},
{
label
:
'部门/学校'
,
prop
:
'organ_id_name'
,
align
:
'center'
,
minWidth
:
'200'
},
{
label
:
'专业'
,
prop
:
'specialty_id_name'
,
align
:
'center'
,
minWidth
:
'200'
},
{
label
:
'班级'
,
prop
:
'class_id_name'
,
align
:
'center'
,
minWidth
:
'200'
},
{
label
:
'身份证号'
,
prop
:
'id_number'
,
align
:
'center'
,
minWidth
:
'200'
},
{
label
:
'出生年月'
,
prop
:
'birthday'
,
align
:
'center'
,
minWidth
:
'200'
},
{
label
:
'省'
,
prop
:
'province_name'
,
align
:
'center'
},
{
label
:
'市'
,
prop
:
'city_name'
,
align
:
'center'
},
{
label
:
'县'
,
prop
:
'county_name'
,
align
:
'center'
},
{
label
:
'生效状态'
,
slots
:
'status'
,
align
:
'center'
},
{
label
:
'更新时间'
,
prop
:
'updated_time'
,
align
:
'center'
,
minWidth
:
'200'
},
{
label
:
'操作'
,
slots
:
'table-operate'
,
align
:
'center'
,
minWidth
:
'200'
,
fixed
:
'right'
},
],
}
})
// 刷新页面
// 刷新页面
const
handleRefresh
=
()
=>
{
const
handleRefresh
=
()
=>
{
...
@@ -83,20 +126,25 @@ const handleChangeStatus = (row: any) => {
...
@@ -83,20 +126,25 @@ const handleChangeStatus = (row: any) => {
const
handleImport
=
()
=>
{
const
handleImport
=
()
=>
{
isShowImportDialog
.
value
=
true
isShowImportDialog
.
value
=
true
}
}
// 批量修改
const
updateDialogVisible
=
ref
(
false
)
const
handleUpdate
=
()
=>
{
updateDialogVisible
.
value
=
true
}
// 导出
// 导出
const
handleExport
=
()
=>
{
const
handleExport
=
()
=>
{
const
params
=
Object
.
assign
({},
appList
.
value
?.
params
)
const
params
=
Object
.
assign
({},
appList
.
value
?.
params
)
exportStudent
(
params
).
then
((
r
:
any
)
=>
{
exportStudent
(
params
).
then
((
r
:
any
)
=>
{
const
blob
=
new
Blob
([
r
],
{
type
:
'application/vnd.ms-excel'
})
const
blob
=
new
Blob
([
r
],
{
type
:
'application/vnd.ms-excel'
})
if
(
'download'
in
document
.
createElement
(
'a'
))
{
if
(
'download'
in
document
.
createElement
(
'a'
))
{
const
e
link
=
document
.
createElement
(
'a'
)
const
link
=
document
.
createElement
(
'a'
)
e
link
.
download
=
'学员数据.xlsx'
link
.
download
=
'学员数据.xlsx'
e
link
.
style
.
display
=
'none'
link
.
style
.
display
=
'none'
e
link
.
href
=
URL
.
createObjectURL
(
blob
)
link
.
href
=
URL
.
createObjectURL
(
blob
)
document
.
body
.
appendChild
(
e
link
)
document
.
body
.
appendChild
(
link
)
e
link
.
click
()
link
.
click
()
URL
.
revokeObjectURL
(
e
link
.
href
)
URL
.
revokeObjectURL
(
link
.
href
)
document
.
body
.
removeChild
(
e
link
)
document
.
body
.
removeChild
(
link
)
}
}
})
})
}
}
...
@@ -115,17 +163,26 @@ const handleAnalysis = () => {
...
@@ -115,17 +163,26 @@ const handleAnalysis = () => {
<
template
>
<
template
>
<AppCard
title=
"学生管理"
>
<AppCard
title=
"学生管理"
>
<AppList
v-bind=
"listOptions"
ref=
"appList"
@
selection-change=
"handleSelectionChange"
border
stripe
style=
"margin-top: 30px"
>
<AppList
<el-button
type=
"primary"
round
@
click=
"handleAddStudent"
v-permission=
"'v1-learning-student-create'"
>
新增学生
</el-button>
v-bind=
"listOptions"
<el-button
type=
"primary"
round
@
click=
"handleImport"
v-permission=
"'v1-learning-student-import'"
>
批量导入
</el-button>
ref=
"appList"
<el-button
type=
"primary"
round
@
click=
"handleExport"
v-permission=
"'v1-learning-student-download'"
>
导出
</el-button>
@
selection-change=
"handleSelectionChange"
border
stripe
style=
"margin-top: 30px"
>
<el-button
type=
"primary"
round
@
click=
"handleAddStudent"
v-permission=
"'v1-learning-student-create'"
>
新增学生
</el-button
>
<el-button
type=
"primary"
round
@
click=
"handleImport"
v-permission=
"'v1-learning-student-import'"
>
批量导入
</el-button
>
<el-button
type=
"primary"
round
@
click=
"handleExport"
v-permission=
"'v1-learning-student-download'"
>
批量导出
</el-button
>
<el-button
type=
"primary"
round
@
click=
"handleUpdate"
v-permission=
"'v1-learning-student-import'"
>
批量修改
</el-button
>
<el-button
type=
"primary"
round
@
click=
"handleAnalysis"
>
生源地分析
</el-button>
<el-button
type=
"primary"
round
@
click=
"handleAnalysis"
>
生源地分析
</el-button>
<template
v-if=
"isAdmin"
#
filter-department=
"
{ params }">
<div
class=
"name"
style=
"font-size: 14px; color: #606266; padding-right: 12px"
>
所属部门/学校:
</div>
<el-select
@
change=
"handleRefresh"
clearable
v-model=
"params.organ_id"
placeholder=
"请选择所属部门/学校"
>
<el-option
v-for=
"item in departmentList"
:key=
"item.id"
:label=
"item.name"
:value=
"item.id"
/>
</el-select>
</
template
>
<template
#
status=
"
{ row }">
<template
#
status=
"
{ row }">
<el-switch
<el-switch
size=
"large"
size=
"large"
...
@@ -139,16 +196,28 @@ const handleAnalysis = () => {
...
@@ -139,16 +196,28 @@ const handleAnalysis = () => {
</
template
>
</
template
>
<
template
#
table-operate=
"{ row }"
>
<
template
#
table-operate=
"{ row }"
>
<el-space>
<el-space>
<el-link
type=
"primary"
plain
@
click=
"handleDetail(row)"
v-permission=
"'v1-learning-student-view'"
>
查看
</el-link>
<el-link
type=
"primary"
plain
@
click=
"handleDetail(row)"
v-permission=
"'v1-learning-student-view'"
<el-link
type=
"primary"
plain
@
click=
"handleEdit(row)"
v-permission=
"'v1-learning-student-update'"
>
编辑
</el-link>
>
查看
</el-link
>
<el-link
type=
"primary"
plain
@
click=
"handleEdit(row)"
v-permission=
"'v1-learning-student-update'"
>
编辑
</el-link
>
</el-space>
</el-space>
</
template
>
</
template
>
</AppList>
</AppList>
</AppCard>
</AppCard>
<!-- 新增学生 -->
<!-- 新增学生 -->
<AddStudent
v-if=
"isShowAddDialog === true"
v-model:isShowAddDialog=
"isShowAddDialog"
:id=
"id"
:title=
"title"
:isEdit=
"isEdit"
@
create=
"handleRefresh"
/>
<AddStudent
v-if=
"isShowAddDialog === true"
v-model:isShowAddDialog=
"isShowAddDialog"
:id=
"id"
:title=
"title"
:isEdit=
"isEdit"
@
create=
"handleRefresh"
/>
<!-- 导入学生 -->
<!-- 导入学生 -->
<ImportStudent
v-if=
"isShowImportDialog"
v-model:isShowImportDialog=
"isShowImportDialog"
@
create=
"handleRefresh"
/>
<ImportStudent
v-if=
"isShowImportDialog"
v-model:isShowImportDialog=
"isShowImportDialog"
@
create=
"handleRefresh"
/>
<!-- 导入学生 -->
<UpdateStudent
v-if=
"updateDialogVisible"
v-model=
"updateDialogVisible"
@
create=
"handleRefresh"
/>
<!-- 生源地分析 -->
<!-- 生源地分析 -->
<!-- <SourceAnalysis v-if="isShowAnalysisDialog" v-model:isShowAnalysisDialog="isShowAnalysisDialog" /> -->
<!-- <SourceAnalysis v-if="isShowAnalysisDialog" v-model:isShowAnalysisDialog="isShowAnalysisDialog" /> -->
</template>
</template>
src/modules/course/create/api.ts
浏览文件 @
8c25052d
...
@@ -238,3 +238,30 @@ export function setDownload(data: { course_id: string; information_id: string; c
...
@@ -238,3 +238,30 @@ export function setDownload(data: { course_id: string; information_id: string; c
export
function
searchAssistant
(
params
:
{
name
:
string
;
page
?:
string
;
'per-page'
?:
string
})
{
export
function
searchAssistant
(
params
:
{
name
:
string
;
page
?:
string
;
'per-page'
?:
string
})
{
return
httpRequest
.
get
(
'/api/resource/v1/course/course/search-teacher'
,
{
params
})
return
httpRequest
.
get
(
'/api/resource/v1/course/course/search-teacher'
,
{
params
})
}
}
// 获取教师书籍列表
export
function
getBookList
(
data
:
{
tel
:
string
;
name
?:
string
;
})
{
return
httpRequest
.
post
(
'/api/ebook/open/teacher/book/getList'
,
data
)
}
// 获取教师书籍详情
export
function
getBookDetail
(
data
:
{
id
:
string
;
})
{
return
httpRequest
.
post
(
'/api/ebook/open/teacher/book/getInfoById'
,
data
)
}
// 获取教师书籍详情
export
function
getChapter
(
data
:
{
book_id
:
string
;
})
{
return
httpRequest
.
post
(
'/api/ebook/open/teacher/chapter/getAllList'
,
data
)
}
// 获取知识图谱
export
function
getTagList
(
params
:
{
type
:
string
;
parent_id
:
string
;
chapter_id
?:
string
})
{
return
httpRequest
.
get
(
'/api/resource/v1/course/course/tag-list'
,
{
params
})
}
// 关联知识图谱
export
function
addTagCourse
(
data
:
{
tag_id
:
string
;
course_id
:
string
;
chapter_id
:
string
;
})
{
return
httpRequest
.
post
(
'/api/resource/v1/course/course/tag-add-course'
,
data
)
}
// /v1/course/course/tag-add-course
src/modules/course/create/components/stepOneComponents/AddCourseData.vue
浏览文件 @
8c25052d
...
@@ -105,7 +105,8 @@ const imgUrl = (val: any) => {
...
@@ -105,7 +105,8 @@ const imgUrl = (val: any) => {
:chapterID=
"''"
:chapterID=
"''"
:course_id=
"'0'"
:course_id=
"'0'"
:btnInfo=
"{ btn_name: '课程资料', resource_type: '4' }"
:btnInfo=
"{ btn_name: '课程资料', resource_type: '4' }"
@
create=
"handleAdd"
/>
@
create=
"handleAdd"
/>
</div>
</div>
</template>
</template>
<
style
>
<
style
>
...
...
src/modules/course/create/components/stepOneComponents/AddTextbook.vue
0 → 100644
浏览文件 @
8c25052d
<
script
setup
lang=
"ts"
>
import
AddTextbookListDialog
from
'../stepTwoComponents/AddTextbookListDialog.vue'
const
emit
=
defineEmits
<
Emits
>
()
const
dataList
:
any
=
ref
([])
const
isShowAddDialog
=
ref
(
false
)
interface
Emits
{
(
e
:
'information'
,
dataList
:
any
):
void
}
const
props
=
defineProps
({
data
:
{
type
:
Array
,
required
:
true
},
id
:
{
type
:
String
}
})
watch
(
()
=>
props
.
data
,
value
=>
{
if
(
value
?.
length
>
0
)
{
dataList
.
value
=
[...
props
.
data
]
}
else
{
dataList
.
value
=
[]
}
},
{
immediate
:
true
}
)
watch
(
()
=>
dataList
.
value
,
value
=>
{
if
(
value
?.
length
>
0
)
{
emit
(
'information'
,
dataList
.
value
)
}
}
)
const
handleAddData
=
()
=>
{
isShowAddDialog
.
value
=
true
}
const
handleAdd
=
(
val
:
any
)
=>
{
dataList
.
value
=
[
val
]
emit
(
'information'
,
dataList
.
value
)
}
const
listOptions
=
$computed
(()
=>
{
return
{
columns
:
[
{
label
:
'数字教材名称'
,
prop
:
'name'
},
{
label
:
'封面'
,
prop
:
'img'
,
computed
(
row
:
any
)
{
return
`<img src="
${
row
.
row
.
img
}
" style="height:100px;display:block">`
}
},
{
label
:
'作者'
,
prop
:
'authors'
},
// { label: '发布者', prop: 'user.real_name' },
// { label: '版号', prop: 'name' },
{
label
:
'操作'
,
slots
:
'table-operate'
,
align
:
'center'
,
width
:
200
,
fixed
:
'right'
}
],
data
:
dataList
.
value
.
length
>
0
?
dataList
.
value
:
[]
}
})
const
handleDel
=
(
row
:
any
)
=>
{
const
index
=
dataList
.
value
.
findIndex
((
item
:
any
)
=>
item
.
id
===
row
.
id
)
dataList
.
value
.
splice
(
index
,
1
)
emit
(
'information'
,
dataList
.
value
)
}
const
handleView
=
function
(
row
:
any
)
{
window
.
open
(
`https://zijingebook.ezijing.com/student/book?book_id=
${
row
.
id
}
`
)
}
</
script
>
<
template
>
<div>
<el-button
type=
"primary"
@
click=
"handleAddData"
>
添加数字教材
</el-button>
<AppList
v-bind=
"listOptions"
ref=
"appList"
>
<template
#
table-operate=
"
{ row }">
<el-button
plain
@
click=
"handleView(row)"
>
查阅
</el-button>
<el-button
type=
"primary"
plain
@
click=
"handleDel(row)"
>
删除
</el-button>
</
template
>
</AppList>
<!-- 添加资源 -->
<AddTextbookListDialog
v-if=
"isShowAddDialog === true"
v-model:isShowAddDialog=
"isShowAddDialog"
@
create=
"handleAdd"
/>
</div>
</template>
<
style
>
.node_type
{
background
:
#bf9d6b
;
border-radius
:
20px
;
line-height
:
1
;
font-size
:
12px
;
font-weight
:
400
;
color
:
#ffffff
;
text-align
:
center
;
padding
:
4px
8px
;
margin-right
:
14px
;
}
</
style
>
src/modules/course/create/components/stepTwoComponents/AddGraphbookDialog.vue
0 → 100644
浏览文件 @
8c25052d
<
script
setup
lang=
"ts"
>
import
{
getTagList
,
addTagCourse
}
from
'../../api'
import
{
Plus
}
from
'@element-plus/icons-vue'
import
{
ElMessage
}
from
'element-plus'
const
route
=
useRoute
()
const
emit
=
defineEmits
<
Emits
>
()
const
props
=
defineProps
({
isShowTextbookDialog2
:
{
type
:
Boolean
,
required
:
true
},
course_id
:
{
type
:
String
,
required
:
false
},
chapterName
:
{
type
:
String
,
required
:
false
},
chapterID
:
{
type
:
String
,
required
:
false
}
})
interface
Emits
{
(
e
:
'update:isShowTextbookDialog2'
,
isShowVideoDialog2
:
boolean
):
void
(
e
:
'create'
,
val
:
any
):
void
}
// 取消
const
handleCancel
=
()
=>
{
emit
(
'update:isShowTextbookDialog2'
,
false
)
}
const
chapterList
=
ref
([])
onMounted
(()
=>
{
getTagList
({
type
:
'1'
,
parent_id
:
route
.
query
.
id
as
string
}).
then
(
res
=>
{
chapterList
.
value
=
res
.
data
.
reduce
((
a
:
any
,
b
:
any
)
=>
{
b
.
index
=
'0'
if
(
b
.
children
)
{
b
.
children
.
map
((
m
:
any
)
=>
{
m
.
index
=
'1'
})
}
a
.
push
(
b
)
return
a
},
[])
console
.
log
(
chapterList
.
value
,
'chapterList.value'
)
})
})
// emit('update:isShowTextbookDialog', false)
const
handleView
=
function
(
id
:
any
)
{
window
.
open
(
`https://zijingebook.ezijing.com/student/book?book_id=
${
route
.
query
.
bid
}
&chapter_id=
${
id
}
`
)
}
const
handleGl
=
function
(
val
:
any
)
{
const
params
:
any
=
{
tag_id
:
val
.
id
,
course_id
:
props
.
course_id
,
chapter_id
:
props
.
chapterID
}
addTagCourse
(
params
).
then
(()
=>
{
emit
(
'update:isShowTextbookDialog2'
,
false
)
emit
(
'create'
,
val
)
ElMessage
.
success
(
'添加成功'
)
})
}
</
script
>
<
template
>
<el-drawer
:model-value=
"isShowTextbookDialog2"
draggable
:before-close=
"handleCancel"
size=
"60%"
title=
"关联知识图谱"
>
<el-tree
:data=
"chapterList"
node-key=
"id"
:accordion=
"true"
:expand-on-click-node=
"false"
style=
"min-width: 100%"
>
<template
#
default=
"
{ data }">
<span
class=
"custom-tree-node"
>
<span
class=
"node_title"
>
{{
data
.
name
}}
</span>
<div
v-if=
"course_id"
>
<!--
<el-button
class=
"btn_operate"
v-if=
"data.index === '1'"
@
click=
"handleView(data.id)"
>
查阅
</el-button>
-->
<el-button
class=
"btn_operate"
v-if=
"data.index === '1'"
@
click=
"handleGl(data)"
>
<el-icon><Plus
/></el-icon>
关联
</el-button>
</div>
</span>
</
template
>
</el-tree>
</el-drawer>
</template>
<
style
lang=
"scss"
scoped
>
.custom-tree-node
{
flex
:
1
;
display
:
flex
;
align-items
:
center
;
justify-content
:
space-between
;
font-size
:
14px
;
padding-right
:
8px
;
}
.btn_operate
{
background-color
:
rgba
(
248
,
241
,
229
,
0
.39
);
font-weight
:
400
;
color
:
#b2833d
;
border
:
none
;
border-radius
:
16px
;
margin
:
3px
;
}
.card-list
{
display
:
flex
;
flex-direction
:
column
;
}
.card-list-con
{
background
:
#fafafa
;
padding
:
20px
;
display
:
flex
;
flex-wrap
:
wrap
;
}
.video-head
{
position
:
relative
;
.video-head-icon
{
position
:
absolute
;
top
:
0
;
right
:
0
;
font-size
:
30px
;
color
:
#666
;
cursor
:
pointer
;
}
}
.video-tool-btn
{
padding
:
10px
0
30px
0
;
}
.video-head-icon
{
position
:
absolute
;
top
:
0
;
right
:
0
;
font-size
:
30px
;
color
:
#666
;
cursor
:
pointer
;
}
</
style
>
src/modules/course/create/components/stepTwoComponents/AddTextbookDialog.vue
0 → 100644
浏览文件 @
8c25052d
<
script
setup
lang=
"ts"
>
import
{
getChapter
,
createCharacter
}
from
'../../api'
import
{
Plus
}
from
'@element-plus/icons-vue'
import
{
ElMessage
}
from
'element-plus'
const
route
=
useRoute
()
const
emit
=
defineEmits
<
Emits
>
()
const
props
=
defineProps
({
isShowTextbookDialog
:
{
type
:
Boolean
,
required
:
true
},
course_id
:
{
type
:
String
,
required
:
false
},
chapterName
:
{
type
:
String
,
required
:
false
},
chapterID
:
{
type
:
String
,
required
:
false
},
drawerName
:
{
type
:
String
,
required
:
false
}
})
interface
Emits
{
(
e
:
'update:isShowTextbookDialog'
,
isShowVideoDialog
:
boolean
):
void
(
e
:
'create'
,
val
:
any
):
void
}
// 取消
const
handleCancel
=
()
=>
{
emit
(
'update:isShowTextbookDialog'
,
false
)
}
const
chapterList
=
ref
([])
onMounted
(()
=>
{
getChapter
({
book_id
:
route
.
query
?.
bid
as
string
}).
then
(
res
=>
{
chapterList
.
value
=
res
.
data
.
reduce
((
a
:
any
,
b
:
any
)
=>
{
b
.
index
=
'0'
if
(
b
.
children
)
{
b
.
children
.
map
((
m
:
any
)
=>
{
m
.
index
=
'1'
})
}
a
.
push
(
b
)
return
a
},
[])
console
.
log
(
chapterList
.
value
,
'chapterList.value'
)
})
})
// emit('update:isShowTextbookDialog', false)
const
handleView
=
function
(
id
:
any
)
{
window
.
open
(
`https://zijingebook.ezijing.com/student/book?book_id=
${
route
.
query
.
bid
}
&chapter_id=
${
id
}
`
)
}
const
handleGl
=
function
(
val
:
any
)
{
const
params
:
any
=
{
name
:
val
.
name
,
course_id
:
props
.
course_id
,
resource_type
:
'13'
,
parent_id
:
props
.
chapterID
,
resource_id
:
val
.
id
}
createCharacter
(
params
).
then
(()
=>
{
emit
(
'update:isShowTextbookDialog'
,
false
)
emit
(
'create'
,
val
)
ElMessage
.
success
(
'添加成功'
)
})
}
</
script
>
<
template
>
<el-drawer
:model-value=
"isShowTextbookDialog"
draggable
:before-close=
"handleCancel"
size=
"60%"
:title=
"drawerName || '添加数字教材'"
>
<el-tree
:data=
"chapterList"
node-key=
"id"
:accordion=
"true"
:expand-on-click-node=
"false"
style=
"min-width: 100%"
>
<template
#
default=
"
{ data }">
<span
class=
"custom-tree-node"
>
<span
class=
"node_title"
>
{{
data
.
name
}}
</span>
<div
v-if=
"course_id"
>
<el-button
class=
"btn_operate"
v-if=
"data.index === '1'"
@
click=
"handleView(data.id)"
>
查阅
</el-button>
<el-button
class=
"btn_operate"
v-if=
"data.index === '1'"
@
click=
"handleGl(data)"
>
<el-icon><Plus
/></el-icon>
关联
</el-button>
</div>
</span>
</
template
>
</el-tree>
</el-drawer>
</template>
<
style
lang=
"scss"
scoped
>
.custom-tree-node
{
flex
:
1
;
display
:
flex
;
align-items
:
center
;
justify-content
:
space-between
;
font-size
:
14px
;
padding-right
:
8px
;
}
.btn_operate
{
background-color
:
rgba
(
248
,
241
,
229
,
0
.39
);
font-weight
:
400
;
color
:
#b2833d
;
border
:
none
;
border-radius
:
16px
;
margin
:
3px
;
}
.card-list
{
display
:
flex
;
flex-direction
:
column
;
}
.card-list-con
{
background
:
#fafafa
;
padding
:
20px
;
display
:
flex
;
flex-wrap
:
wrap
;
}
.video-head
{
position
:
relative
;
.video-head-icon
{
position
:
absolute
;
top
:
0
;
right
:
0
;
font-size
:
30px
;
color
:
#666
;
cursor
:
pointer
;
}
}
.video-tool-btn
{
padding
:
10px
0
30px
0
;
}
.video-head-icon
{
position
:
absolute
;
top
:
0
;
right
:
0
;
font-size
:
30px
;
color
:
#666
;
cursor
:
pointer
;
}
</
style
>
src/modules/course/create/components/stepTwoComponents/AddTextbookListDialog.vue
0 → 100644
浏览文件 @
8c25052d
<
script
setup
lang=
"ts"
>
import
{
getBookList
}
from
'../../api'
import
{
useUserStore
}
from
'@/stores/user'
const
appList
=
ref
()
const
userStore
=
useUserStore
()
const
userInfo
:
any
=
userStore
.
user
const
emit
=
defineEmits
<
Emits
>
()
const
props
=
defineProps
({
isShowAddDialog
:
{
type
:
Boolean
,
required
:
true
}
})
interface
Emits
{
(
e
:
'update:isShowAddDialog'
,
isShowVideoDialog
:
boolean
):
void
(
e
:
'create'
,
val
:
any
):
void
}
const
listOptions
=
computed
(()
=>
{
return
{
remote
:
{
httpRequest
:
getBookList
,
params
:
{
tel
:
userInfo
.
mobile
,
name
:
''
}
},
filters
:
[{
type
:
'input'
,
prop
:
'name'
,
placeholder
:
'书籍名称'
}],
columns
:
[
// { type: 'selection' },
{
label
:
'数字教材名称'
,
prop
:
'name'
},
{
label
:
'封面'
,
prop
:
'img'
,
computed
(
row
:
any
)
{
return
`<img src="
${
row
.
row
.
img
}
" style="height:100px;display:block">`
}
},
{
label
:
'作者'
,
prop
:
'authors'
},
{
label
:
'发布者'
,
prop
:
'user.real_name'
},
{
label
:
'审核状态'
,
prop
:
'audit_status'
,
computed
(
row
:
any
)
{
const
j
:
any
=
{
'1'
:
'待发布'
,
'2'
:
'审核中'
,
'3'
:
'审核未通过'
,
'4'
:
'审核通过'
}
return
j
[
row
?.
row
?.
audit_status
]
}
},
// { label: '版号', prop: 'name' },
{
label
:
'操作'
,
slots
:
'table-operate'
,
align
:
'center'
,
width
:
200
,
fixed
:
'right'
}
]
}
})
// 取消
const
handleCancel
=
()
=>
{
emit
(
'update:isShowAddDialog'
,
false
)
}
const
handleDetail
=
function
(
row
:
any
)
{
emit
(
'update:isShowAddDialog'
,
false
)
emit
(
'create'
,
row
)
}
const
handleView
=
function
(
row
:
any
)
{
window
.
open
(
`https://zijingebook.ezijing.com/student/book?book_id=
${
row
.
id
}
`
)
}
</
script
>
<
template
>
<el-drawer
:model-value=
"isShowAddDialog"
draggable
:before-close=
"handleCancel"
size=
"60%"
title=
"添加数字教材"
>
<AppList
v-bind=
"listOptions"
ref=
"appList"
>
<!--
<el-button
style=
"margin-bottom: 15px"
type=
"primary"
@
click=
"addTextbook"
>
添加
</el-button>
-->
<template
#
table-operate=
"
{ row }">
<el-button
plain
@
click=
"handleView(row)"
>
查阅
</el-button>
<el-button
plain
@
click=
"handleDetail(row)"
>
添加
</el-button>
</
template
>
</AppList>
</el-drawer>
</template>
<
style
lang=
"scss"
scoped
>
.card-list
{
display
:
flex
;
flex-direction
:
column
;
}
.card-list-con
{
background
:
#fafafa
;
padding
:
20px
;
display
:
flex
;
flex-wrap
:
wrap
;
}
.video-head
{
position
:
relative
;
.video-head-icon
{
position
:
absolute
;
top
:
0
;
right
:
0
;
font-size
:
30px
;
color
:
#666
;
cursor
:
pointer
;
}
}
.video-tool-btn
{
padding
:
10px
0
30px
0
;
}
.video-head-icon
{
position
:
absolute
;
top
:
0
;
right
:
0
;
font-size
:
30px
;
color
:
#666
;
cursor
:
pointer
;
}
</
style
>
src/modules/course/create/components/stepTwoComponents/AddVideoDialog.vue
浏览文件 @
8c25052d
...
@@ -75,7 +75,6 @@ const listOptions = computed(() => {
...
@@ -75,7 +75,6 @@ const listOptions = computed(() => {
callback
(
data
:
any
)
{
callback
(
data
:
any
)
{
data
.
list
.
forEach
((
item
:
any
)
=>
(
item
.
check_status
=
false
))
data
.
list
.
forEach
((
item
:
any
)
=>
(
item
.
check_status
=
false
))
tableData
=
data
tableData
=
data
console
.
log
(
tableData
.
list
,
'123'
)
return
{
list
:
data
.
list
,
total
:
data
.
total
}
return
{
list
:
data
.
list
,
total
:
data
.
total
}
},
},
params
:
{
tab
:
tabValue
,
status
:
'1'
,
authorized
:
''
,
name
:
''
,
course_id
:
props
.
course_id
||
''
}
params
:
{
tab
:
tabValue
,
status
:
'1'
,
authorized
:
''
,
name
:
''
,
course_id
:
props
.
course_id
||
''
}
...
@@ -211,11 +210,9 @@ const changeCard = () => {
...
@@ -211,11 +210,9 @@ const changeCard = () => {
let
checkBox
=
$ref
([])
let
checkBox
=
$ref
([])
const
select
=
function
(
row
:
any
)
{
const
select
=
function
(
row
:
any
)
{
checkBox
=
row
checkBox
=
row
console
.
log
(
row
)
}
}
const
addVideoList
=
function
()
{
const
addVideoList
=
function
()
{
console
.
log
(
checkBox
,
'checkBox'
)
checkBox
.
forEach
((
item
:
any
,
index
:
number
)
=>
{
checkBox
.
forEach
((
item
:
any
,
index
:
number
)
=>
{
addRequest
(
item
,
index
,
checkBox
)
addRequest
(
item
,
index
,
checkBox
)
})
})
...
@@ -223,7 +220,13 @@ const addVideoList = function () {
...
@@ -223,7 +220,13 @@ const addVideoList = function () {
</
script
>
</
script
>
<
template
>
<
template
>
<el-drawer
:model-value=
"isShowAddDialog"
draggable
:before-close=
"handleCancel"
size=
"60%"
:title=
"`添加$
{props.btnInfo.btn_name}`">
<el-drawer
:model-value=
"isShowAddDialog"
draggable
:before-close=
"handleCancel"
size=
"60%"
:title=
"`添加$
{props.btnInfo.btn_name}`"
>
<div
class=
"video-head"
>
<div
class=
"video-head"
>
<el-tabs
@
tab-change=
"tabChange"
v-model=
"tabValue"
>
<el-tabs
@
tab-change=
"tabChange"
v-model=
"tabValue"
>
<el-tab-pane
label=
"我的资源"
name=
"1"
></el-tab-pane>
<el-tab-pane
label=
"我的资源"
name=
"1"
></el-tab-pane>
...
@@ -248,7 +251,8 @@ const addVideoList = function () {
...
@@ -248,7 +251,8 @@ const addVideoList = function () {
display: block;
display: block;
height: 83px;
height: 83px;
background-size: cover;
background-size: cover;
background-image: url($
{row.cover});`">
</div>
background-image: url($
{row.cover});`"
>
</div>
</div>
</div>
</
template
>
</
template
>
<
template
#
filter-type=
"{ params }"
>
<
template
#
filter-type=
"{ params }"
>
...
@@ -259,7 +263,8 @@ const addVideoList = function () {
...
@@ -259,7 +263,8 @@ const addVideoList = function () {
:props=
"defaultProps"
:props=
"defaultProps"
v-model=
"params.classification"
v-model=
"params.classification"
:data=
"selectTree"
:data=
"selectTree"
:default-expanded-keys=
"selectTree.length ? [selectTree[0]?.id] : []"
/>
:default-expanded-keys=
"selectTree.length ? [selectTree[0]?.id] : []"
/>
</
template
>
</
template
>
<
template
#
body=
"{ data }"
v-if=
"isCard"
>
<
template
#
body=
"{ data }"
v-if=
"isCard"
>
<div
class=
"card-list"
v-if=
"data.length"
>
<div
class=
"card-list"
v-if=
"data.length"
>
...
@@ -268,7 +273,14 @@ const addVideoList = function () {
...
@@ -268,7 +273,14 @@ const addVideoList = function () {
<el-button
type=
"primary"
@
click=
"addVideo"
>
添加
</el-button>
<el-button
type=
"primary"
@
click=
"addVideo"
>
添加
</el-button>
</div>
</div>
<div
class=
"card-list-con"
>
<div
class=
"card-list-con"
>
<CardListItem
v-for=
"(item, index) in data"
:key=
"index"
:tabIndex=
"tabValue"
:data=
"item"
:path=
"path"
@
add=
"handleAdd"
>
<CardListItem
v-for=
"(item, index) in data"
:key=
"index"
:tabIndex=
"tabValue"
:data=
"item"
:path=
"path"
@
add=
"handleAdd"
>
<el-checkbox
@
change=
"checkboxSelect"
v-model=
"item.check_status"
></el-checkbox>
<el-checkbox
@
change=
"checkboxSelect"
v-model=
"item.check_status"
></el-checkbox>
</CardListItem>
</CardListItem>
</div>
</div>
...
...
src/modules/course/create/views/StepOne.vue
浏览文件 @
8c25052d
<
script
setup
lang=
"ts"
>
<
script
setup
lang=
"ts"
>
import
{
createCourse
,
getCourseDetails
,
updateCourse
,
getMajorList
}
from
'../api'
import
{
createCourse
,
getCourseDetails
,
updateCourse
,
getMajorList
,
getBookDetail
}
from
'../api'
// setStatus
// setStatus
import
{
useGetCategoryList
}
from
'@/composables/useGetCategoryList'
import
{
useGetCategoryList
}
from
'@/composables/useGetCategoryList'
import
{
useMapStore
}
from
'@/stores/map'
import
{
useMapStore
}
from
'@/stores/map'
...
@@ -19,6 +19,9 @@ import AddLive from '../components/stepOneComponents/AddLive.vue'
...
@@ -19,6 +19,9 @@ import AddLive from '../components/stepOneComponents/AddLive.vue'
import
AddCourseData
from
'../components/stepOneComponents/AddCourseData.vue'
import
AddCourseData
from
'../components/stepOneComponents/AddCourseData.vue'
// 添加数字教材
import
AddTextbook
from
'../components/stepOneComponents/AddTextbook.vue'
import
{
ElMessage
}
from
'element-plus'
import
{
ElMessage
}
from
'element-plus'
import
type
{
FormInstance
,
FormRules
}
from
'element-plus'
import
type
{
FormInstance
,
FormRules
}
from
'element-plus'
const
store
=
useMapStore
()
const
store
=
useMapStore
()
...
@@ -74,7 +77,8 @@ const form = reactive<Record<string, any>>({
...
@@ -74,7 +77,8 @@ const form = reactive<Record<string, any>>({
exam_id
:
''
,
exam_id
:
''
,
live_id
:
''
,
live_id
:
''
,
specialty_id
:
[],
specialty_id
:
[],
information_id
:
''
information_id
:
''
,
book_id
:
''
})
})
// 表单验证
// 表单验证
...
@@ -111,6 +115,7 @@ const changeExam = (data: any) => {
...
@@ -111,6 +115,7 @@ const changeExam = (data: any) => {
// 考试数据回显
// 考试数据回显
const
examList
:
any
=
ref
([])
const
examList
:
any
=
ref
([])
const
information
:
any
=
ref
([])
const
information
:
any
=
ref
([])
const
textbookInfo
:
any
=
ref
([])
// 获取详情
// 获取详情
let
loading
=
$ref
<
boolean
>
(
false
)
let
loading
=
$ref
<
boolean
>
(
false
)
...
@@ -123,6 +128,15 @@ function fetchDetail() {
...
@@ -123,6 +128,15 @@ function fetchDetail() {
form
.
exam_id
=
res
.
data
.
examinations
.
map
((
item
:
any
)
=>
item
.
id
).
toString
()
form
.
exam_id
=
res
.
data
.
examinations
.
map
((
item
:
any
)
=>
item
.
id
).
toString
()
form
.
specialty_id
=
res
.
data
.
specialty
.
map
((
item
:
any
)
=>
item
.
id
)
form
.
specialty_id
=
res
.
data
.
specialty
.
map
((
item
:
any
)
=>
item
.
id
)
form
.
teacher_id
=
res
.
data
.
teachers
.
map
((
item
:
any
)
=>
item
.
id
)
form
.
teacher_id
=
res
.
data
.
teachers
.
map
((
item
:
any
)
=>
item
.
id
)
// textbookList.value = res.data.books?.book_id
if
(
res
.
data
.
books
.
length
)
{
getBookDetail
({
id
:
res
.
data
.
books
[
0
]?.
book_id
}).
then
(
res
=>
{
if
(
res
.
data
)
{
textbookInfo
.
value
=
[
res
.
data
]
}
})
// res.data.books[0]?.book_id
}
loading
=
false
loading
=
false
})
})
}
}
...
@@ -165,7 +179,7 @@ function handleCreate() {
...
@@ -165,7 +179,7 @@ function handleCreate() {
// 操作第二部
// 操作第二部
router
.
push
({
router
.
push
({
path
:
'/course/update-course/stepTwo'
,
path
:
'/course/update-course/stepTwo'
,
query
:
{
id
:
res
.
data
.
id
,
isEditCourse
:
'0'
}
query
:
{
id
:
res
.
data
.
id
,
isEditCourse
:
'0'
,
bid
:
form
.
book_id
}
})
})
}
}
})
})
...
@@ -178,7 +192,7 @@ function handleUpdate() {
...
@@ -178,7 +192,7 @@ function handleUpdate() {
// 操作第二部
// 操作第二部
router
.
push
({
router
.
push
({
path
:
'/course/update-course/stepTwo'
,
path
:
'/course/update-course/stepTwo'
,
query
:
{
id
:
res
.
data
.
id
,
isEditCourse
:
'1'
}
query
:
{
id
:
res
.
data
.
id
,
isEditCourse
:
'1'
,
bid
:
form
.
book_id
}
})
})
}
}
})
})
...
@@ -196,6 +210,10 @@ getMajorList({ name: '', 'per-page': '100' }).then((res: any) => {
...
@@ -196,6 +210,10 @@ getMajorList({ name: '', 'per-page': '100' }).then((res: any) => {
const
handleInformation
=
(
val
:
any
)
=>
{
const
handleInformation
=
(
val
:
any
)
=>
{
form
.
information_id
=
val
.
map
((
item
:
any
)
=>
item
.
id
).
toString
()
form
.
information_id
=
val
.
map
((
item
:
any
)
=>
item
.
id
).
toString
()
}
}
const
handleTextbook
=
(
val
:
any
)
=>
{
form
.
book_id
=
val
[
0
].
id
}
</
script
>
</
script
>
<
template
>
<
template
>
...
@@ -229,7 +247,8 @@ const handleInformation = (val: any) => {
...
@@ -229,7 +247,8 @@ const handleInformation = (val: any) => {
:data=
"selectTree"
:data=
"selectTree"
node-key=
"id"
node-key=
"id"
:default-expanded-keys=
"selectTree.length ? [selectTree[0]?.id] : []"
:default-expanded-keys=
"selectTree.length ? [selectTree[0]?.id] : []"
placeholder=
"请选择课程分类"
/>
placeholder=
"请选择课程分类"
/>
</el-form-item>
</el-form-item>
<el-form-item
label=
"课程学分"
prop=
"credit"
>
<el-form-item
label=
"课程学分"
prop=
"credit"
>
<el-input
v-model=
"form.credit"
maxlength=
"3"
/>
<el-input
v-model=
"form.credit"
maxlength=
"3"
/>
...
@@ -241,14 +260,16 @@ const handleInformation = (val: any) => {
...
@@ -241,14 +260,16 @@ const handleInformation = (val: any) => {
style=
"width: 100%"
style=
"width: 100%"
clearable
clearable
multiple
multiple
v-permission=
"'v1-course-search-specialty'"
>
v-permission=
"'v1-course-search-specialty'"
>
<!-- :remote-method="handleMajorList" -->
<!-- :remote-method="handleMajorList" -->
<el-option
<el-option
v-for=
"(item, index) in majorList"
v-for=
"(item, index) in majorList"
:key=
"index"
:key=
"index"
:label=
"item.name"
:label=
"item.name"
:value=
"item.id"
></el-option>
:value=
"item.id"
></el-option>
</el-select>
</el-select>
</el-form-item>
</el-form-item>
</el-form>
</el-form>
...
@@ -259,7 +280,8 @@ const handleInformation = (val: any) => {
...
@@ -259,7 +280,8 @@ const handleInformation = (val: any) => {
:model=
"form"
:model=
"form"
:rules=
"rules"
:rules=
"rules"
label-suffix=
":"
label-suffix=
":"
style=
"width: 100%; margin-top: 30px"
>
style=
"width: 100%; margin-top: 30px"
>
<el-form-item
label=
"课程助教"
prop=
"teacher_id"
>
<el-form-item
label=
"课程助教"
prop=
"teacher_id"
>
<!-- 添加助教 -->
<!-- 添加助教 -->
<AddAssistant
v-model=
"form.teachers"
style=
"width: 100%"
></AddAssistant>
<AddAssistant
v-model=
"form.teachers"
style=
"width: 100%"
></AddAssistant>
...
@@ -295,7 +317,19 @@ const handleInformation = (val: any) => {
...
@@ -295,7 +317,19 @@ const handleInformation = (val: any) => {
:data=
"information"
:data=
"information"
style=
"width: 100%"
style=
"width: 100%"
:id=
"id"
:id=
"id"
@
information=
"handleInformation"
></AddCourseData>
@
information=
"handleInformation"
></AddCourseData>
</el-form-item>
<!-- AddDigitalTextbook -->
<el-form-item
label=
"数字教材"
prop=
"information_id"
>
<!-- 添加数字教材 -->
<AddTextbook
v-model=
"form.book_id"
:data=
"textbookInfo"
style=
"width: 100%"
:id=
"id"
@
information=
"handleTextbook"
></AddTextbook>
</el-form-item>
</el-form-item>
</el-form>
</el-form>
</div>
</div>
...
...
src/modules/course/create/views/StepTwo.vue
浏览文件 @
8c25052d
...
@@ -12,6 +12,9 @@ import AddVideoDialog from '../components/stepTwoComponents/AddVideoDialog.vue'
...
@@ -12,6 +12,9 @@ import AddVideoDialog from '../components/stepTwoComponents/AddVideoDialog.vue'
import
AddExamDialog
from
'../components/stepTwoComponents/AddExamDialog.vue'
import
AddExamDialog
from
'../components/stepTwoComponents/AddExamDialog.vue'
import
VideoPlayDialog
from
'../components/stepTwoComponents/VideoPlayDialog.vue'
import
VideoPlayDialog
from
'../components/stepTwoComponents/VideoPlayDialog.vue'
import
AddChapterDialog
from
'../components/stepTwoComponents/AddChapterDialog.vue'
import
AddChapterDialog
from
'../components/stepTwoComponents/AddChapterDialog.vue'
import
AddTextbookDialog
from
'../components/stepTwoComponents/AddTextbookDialog.vue'
import
AddGraphbookDialog
from
'../components/stepTwoComponents/AddGraphbookDialog.vue'
import
OpenRules
from
'../components/stepTwoComponents/OpenRules.vue'
import
OpenRules
from
'../components/stepTwoComponents/OpenRules.vue'
const
route
=
useRoute
()
const
route
=
useRoute
()
const
router
=
useRouter
()
const
router
=
useRouter
()
...
@@ -24,6 +27,8 @@ const isShowSectionDialog = ref(false)
...
@@ -24,6 +27,8 @@ const isShowSectionDialog = ref(false)
// 修改资源名称弹窗
// 修改资源名称弹窗
const
isEditResourcesNameDialog
=
ref
(
false
)
const
isEditResourcesNameDialog
=
ref
(
false
)
// 资源id
// 资源id
const
isShowTextbookDialog
=
ref
(
false
)
const
isShowTextbookDialog2
=
ref
(
false
)
const
resourceId
=
ref
(
''
)
const
resourceId
=
ref
(
''
)
const
isShowLiveDialog
=
ref
(
false
)
const
isShowLiveDialog
=
ref
(
false
)
const
isShowAddDialog
=
ref
(
false
)
const
isShowAddDialog
=
ref
(
false
)
...
@@ -67,6 +72,14 @@ const btnList = [
...
@@ -67,6 +72,14 @@ const btnList = [
{
{
btn_name
:
'直播'
,
btn_name
:
'直播'
,
resource_type
:
'6'
resource_type
:
'6'
},
{
btn_name
:
'关联数字教材'
,
resource_type
:
'13'
},
{
btn_name
:
'关联知识图谱'
,
resource_type
:
'14'
}
}
]
]
const
defaultProps
=
{
const
defaultProps
=
{
...
@@ -143,7 +156,8 @@ const handleDel = (node: any) => {
...
@@ -143,7 +156,8 @@ const handleDel = (node: any) => {
}
}
// 添加
// 添加
const
handleAddDialog
=
(
node
:
any
,
item
:
any
)
=>
{
const
handleAddDialog
=
(
node
:
any
,
item
:
any
,
data
:
any
)
=>
{
console
.
log
(
data
,
'data'
,
dataSource
)
chapterID
.
value
=
node
.
key
chapterID
.
value
=
node
.
key
chapterName
.
value
=
node
.
label
chapterName
.
value
=
node
.
label
btnInfo
.
value
=
item
btnInfo
.
value
=
item
...
@@ -164,10 +178,16 @@ const handleAddDialog = (node: any, item: any) => {
...
@@ -164,10 +178,16 @@ const handleAddDialog = (node: any, item: any) => {
}
else
if
(
item
.
resource_type
===
'3'
)
{
}
else
if
(
item
.
resource_type
===
'3'
)
{
isShowExamDialog
.
value
=
true
isShowExamDialog
.
value
=
true
paper_use_list
.
value
=
[
2
]
paper_use_list
.
value
=
[
2
]
}
else
if
(
item
.
resource_type
===
'13'
)
{
isShowTextbookDialog
.
value
=
true
}
else
if
(
item
.
resource_type
===
'14'
)
{
isShowTextbookDialog2
.
value
=
true
}
}
}
}
//查阅
//查阅
const
handleConsult
=
(
node
:
any
)
=>
{
const
handleConsult
=
(
node
:
any
)
=>
{
console
.
log
(
node
,
'node'
)
// 视频
// 视频
if
(
node
.
data
.
resource_type
===
'2'
)
{
if
(
node
.
data
.
resource_type
===
'2'
)
{
getVideoDetails
({
id
:
node
.
data
.
resource_id
}).
then
(
res
=>
{
getVideoDetails
({
id
:
node
.
data
.
resource_id
}).
then
(
res
=>
{
...
@@ -175,6 +195,11 @@ const handleConsult = (node: any) => {
...
@@ -175,6 +195,11 @@ const handleConsult = (node: any) => {
isShowVideoPlayDialog
.
value
=
true
isShowVideoPlayDialog
.
value
=
true
})
})
}
}
if
(
node
.
data
.
resource_type
===
'13'
)
{
window
.
open
(
`https://zijingebook.ezijing.com/student/book?book_id=
${
route
.
query
.
bid
}
&chapter_id=
${
node
.
data
.
resource_id
}
`
)
}
}
}
// 下载
// 下载
const
handleDownload
=
(
node
:
any
)
=>
{
const
handleDownload
=
(
node
:
any
)
=>
{
...
@@ -252,6 +277,9 @@ const imgUrl = (node: any) => {
...
@@ -252,6 +277,9 @@ const imgUrl = (node: any) => {
}
else
if
(
node
.
data
.
resource_type
===
'9'
)
{
}
else
if
(
node
.
data
.
resource_type
===
'9'
)
{
// 考试
// 考试
return
'/center_resource/test_img.png'
return
'/center_resource/test_img.png'
}
else
if
(
node
.
data
.
resource_type
===
'13'
)
{
// 考试
return
'/center_resource/docx_img.png'
}
}
}
}
const
nodeType
=
(
node
:
any
)
=>
{
const
nodeType
=
(
node
:
any
)
=>
{
...
@@ -275,6 +303,10 @@ const nodeType = (node: any) => {
...
@@ -275,6 +303,10 @@ const nodeType = (node: any) => {
}
else
if
(
node
.
data
.
resource_type
===
'11'
)
{
}
else
if
(
node
.
data
.
resource_type
===
'11'
)
{
// 考试
// 考试
return
'教案'
return
'教案'
}
else
if
(
node
.
data
.
resource_type
===
'13'
)
{
return
'数字教材'
}
else
if
(
node
.
data
.
resource_type
===
'14'
)
{
return
'知识图谱'
}
}
}
}
const
handleNodeExpand
=
(
data
:
any
)
=>
{
const
handleNodeExpand
=
(
data
:
any
)
=>
{
...
@@ -355,7 +387,8 @@ const handleChangeStatus = (node: any, data: any) => {
...
@@ -355,7 +387,8 @@ const handleChangeStatus = (node: any, data: any) => {
@
node-drop=
"handleDrop"
@
node-drop=
"handleDrop"
style=
"min-width: 100%"
style=
"min-width: 100%"
@
node-expand=
"handleNodeExpand"
@
node-expand=
"handleNodeExpand"
@
node-collapse=
"handleNodeCollapse"
>
@
node-collapse=
"handleNodeCollapse"
>
<!-- -->
<!-- -->
<template
#
default=
"
{ node, data }">
<template
#
default=
"
{ node, data }">
<span
class=
"custom-tree-node"
>
<span
class=
"custom-tree-node"
>
...
@@ -365,9 +398,16 @@ const handleChangeStatus = (node: any, data: any) => {
...
@@ -365,9 +398,16 @@ const handleChangeStatus = (node: any, data: any) => {
<span
class=
"node_title"
>
{{
node
.
label
.
length
>
20
?
node
.
label
.
slice
(
0
,
20
)
+
'...'
:
node
.
label
}}
</span>
<span
class=
"node_title"
>
{{
node
.
label
.
length
>
20
?
node
.
label
.
slice
(
0
,
20
)
+
'...'
:
node
.
label
}}
</span>
<el-link
<el-link
class=
"btn_edit"
class=
"btn_edit"
v-if=
"data.depth === '3' && node.data.resource_type === '2'"
v-if=
"
(data.depth === '3' && node.data.resource_type === '2') ||
node.data.resource_type === '13' ||
node.data.resource_type === '14'
"
@
click=
"handleConsult(node)"
@
click=
"handleConsult(node)"
:disabled=
"node.data.resource.can_view !== true"
:disabled=
"
(node.data.resource?.can_view !== true && node.data.resource_type !== '13') ||
node.data.resource_type === '14'
"
style=
"margin-left: 35px"
style=
"margin-left: 35px"
>
查阅
</el-link
>
查阅
</el-link
>
>
...
@@ -378,15 +418,18 @@ const handleChangeStatus = (node: any, data: any) => {
...
@@ -378,15 +418,18 @@ const handleChangeStatus = (node: any, data: any) => {
node.data.resource_type !== '2' &&
node.data.resource_type !== '2' &&
node.data.resource_type !== '6' &&
node.data.resource_type !== '6' &&
node.data.resource_type !== '3' &&
node.data.resource_type !== '3' &&
node.data.resource_type !== '9'
node.data.resource_type !== '9' &&
node.data.resource_type !== '13' &&
node.data.resource_type !== '14'
"
"
@
click=
"handleDownload(node)"
@
click=
"handleDownload(node)"
:disabled=
"node.data.resource.can_view !== true"
:disabled=
"node.data.resource
?
.can_view !== true"
style=
"margin-left: 35px"
style=
"margin-left: 35px"
>
下载
</el-link
>
下载
</el-link
>
>
<!-- data.depth !== '3' 资源-->
<!-- data.depth !== '3' 资源-->
<el-link
<el-link
v-if=
"node.data.resource_type !== '13' || node.data.resource_type !== '14'"
class=
"btn_edit"
class=
"btn_edit"
@
click=
"handleEdit(node, data.depth)"
@
click=
"handleEdit(node, data.depth)"
style=
"margin-left: 35px"
style=
"margin-left: 35px"
...
@@ -407,7 +450,8 @@ const handleChangeStatus = (node: any, data: any) => {
...
@@ -407,7 +450,8 @@ const handleChangeStatus = (node: any, data: any) => {
class=
"btn_operate"
class=
"btn_operate"
v-if=
"data.depth === '1' || data.depth === '2'"
v-if=
"data.depth === '1' || data.depth === '2'"
@
click=
"handleOpenRules(node, data)"
@
click=
"handleOpenRules(node, data)"
v-permission=
"'v1-course-set-chapter-rules'"
>
v-permission=
"'v1-course-set-chapter-rules'"
>
<el-icon><Plus
/></el-icon>
<el-icon><Plus
/></el-icon>
开放规则
开放规则
</el-button>
</el-button>
...
@@ -420,7 +464,8 @@ const handleChangeStatus = (node: any, data: any) => {
...
@@ -420,7 +464,8 @@ const handleChangeStatus = (node: any, data: any) => {
class=
"btn_operate"
class=
"btn_operate"
v-for=
"(item, index) in btnList"
v-for=
"(item, index) in btnList"
:key=
"index"
:key=
"index"
@
click=
"handleAddDialog(node, item)"
>
@
click=
"handleAddDialog(node, item, data)"
>
<el-icon><Plus
/></el-icon>
<el-icon><Plus
/></el-icon>
{{
item
.
btn_name
}}
{{
item
.
btn_name
}}
</el-button>
</el-button>
...
@@ -431,8 +476,11 @@ const handleChangeStatus = (node: any, data: any) => {
...
@@ -431,8 +476,11 @@ const handleChangeStatus = (node: any, data: any) => {
node.data.resource_type !== '2' &&
node.data.resource_type !== '2' &&
node.data.resource_type !== '6' &&
node.data.resource_type !== '6' &&
node.data.resource_type !== '3' &&
node.data.resource_type !== '3' &&
node.data.resource_type !== '9'
node.data.resource_type !== '9' &&
"
>
node.data.resource_type !== '13' &&
node.data.resource_type !== '14'
"
>
<span
class=
"btn_operate"
>
学生下载控制:
</span>
<span
class=
"btn_operate"
>
学生下载控制:
</span>
<el-switch
<el-switch
class=
"btn_edit"
class=
"btn_edit"
...
@@ -449,7 +497,8 @@ const handleChangeStatus = (node: any, data: any) => {
...
@@ -449,7 +497,8 @@ const handleChangeStatus = (node: any, data: any) => {
inactive-value=
"0"
inactive-value=
"0"
inline-prompt
inline-prompt
style=
"--el-switch-on-color: #aa1941"
style=
"--el-switch-on-color: #aa1941"
@
change=
"handleChangeStatus(node, data)"
></el-switch>
@
change=
"handleChangeStatus(node, data)"
></el-switch>
</
template
>
</
template
>
</span>
</span>
</span>
</span>
...
@@ -471,7 +520,8 @@ const handleChangeStatus = (node: any, data: any) => {
...
@@ -471,7 +520,8 @@ const handleChangeStatus = (node: any, data: any) => {
:chapterID=
"chapterID"
:chapterID=
"chapterID"
:course_id=
"id"
:course_id=
"id"
:sectionName=
"sectionName"
:sectionName=
"sectionName"
:resourceId=
"resourceId"
/>
:resourceId=
"resourceId"
/>
<!-- 添加章 -->
<!-- 添加章 -->
<AddChapterDialog
<AddChapterDialog
v-if=
"isShowDialog === true"
v-if=
"isShowDialog === true"
...
@@ -480,7 +530,8 @@ const handleChangeStatus = (node: any, data: any) => {
...
@@ -480,7 +530,8 @@ const handleChangeStatus = (node: any, data: any) => {
:course_id=
"id"
:course_id=
"id"
:isEdit=
"isEdit"
:isEdit=
"isEdit"
:chapterID=
"chapterID"
:chapterID=
"chapterID"
:chapterName=
"chapterName"
/>
:chapterName=
"chapterName"
/>
<!-- 添加小节 -->
<!-- 添加小节 -->
<AddSectionDialog
<AddSectionDialog
v-if=
"isShowSectionDialog === true"
v-if=
"isShowSectionDialog === true"
...
@@ -490,7 +541,8 @@ const handleChangeStatus = (node: any, data: any) => {
...
@@ -490,7 +541,8 @@ const handleChangeStatus = (node: any, data: any) => {
:chapterID=
"chapterID"
:chapterID=
"chapterID"
:course_id=
"id"
:course_id=
"id"
:isEdit=
"isEdit"
:isEdit=
"isEdit"
:sectionName=
"sectionName"
/>
:sectionName=
"sectionName"
/>
<!-- 添加直播 -->
<!-- 添加直播 -->
<AddLiveDialog
<AddLiveDialog
v-if=
"isShowLiveDialog === true"
v-if=
"isShowLiveDialog === true"
...
@@ -499,7 +551,8 @@ const handleChangeStatus = (node: any, data: any) => {
...
@@ -499,7 +551,8 @@ const handleChangeStatus = (node: any, data: any) => {
:chapterName=
"chapterName"
:chapterName=
"chapterName"
:chapterID=
"chapterID"
:chapterID=
"chapterID"
:course_id=
"id"
:course_id=
"id"
:btnInfo=
"btnInfo"
/>
:btnInfo=
"btnInfo"
/>
<!-- 添加资源 -->
<!-- 添加资源 -->
<AddVideoDialog
<AddVideoDialog
v-if=
"isShowAddDialog === true"
v-if=
"isShowAddDialog === true"
...
@@ -508,7 +561,8 @@ const handleChangeStatus = (node: any, data: any) => {
...
@@ -508,7 +561,8 @@ const handleChangeStatus = (node: any, data: any) => {
:chapterName=
"chapterName"
:chapterName=
"chapterName"
:chapterID=
"chapterID"
:chapterID=
"chapterID"
:course_id=
"id"
:course_id=
"id"
:btnInfo=
"btnInfo"
/>
:btnInfo=
"btnInfo"
/>
<!-- 添加考试 -->
<!-- 添加考试 -->
<AddExamDialog
<AddExamDialog
...
@@ -520,12 +574,14 @@ const handleChangeStatus = (node: any, data: any) => {
...
@@ -520,12 +574,14 @@ const handleChangeStatus = (node: any, data: any) => {
:course_id=
"id"
:course_id=
"id"
:btnInfo=
"btnInfo"
:btnInfo=
"btnInfo"
:paper_use_list=
"paper_use_list"
:paper_use_list=
"paper_use_list"
:isMultiple=
"false"
/>
:isMultiple=
"false"
/>
<!-- 视频查阅弹框 -->
<!-- 视频查阅弹框 -->
<VideoPlayDialog
<VideoPlayDialog
v-if=
"isShowVideoPlayDialog === true"
v-if=
"isShowVideoPlayDialog === true"
v-model:isShowVideoPlayDialog=
"isShowVideoPlayDialog"
v-model:isShowVideoPlayDialog=
"isShowVideoPlayDialog"
:videoOptions=
"videoUrl"
/>
:videoOptions=
"videoUrl"
/>
<OpenRules
<OpenRules
v-model:isShowOpenRules=
"isShowOpenRules"
v-model:isShowOpenRules=
"isShowOpenRules"
v-if=
"isShowOpenRules === true"
v-if=
"isShowOpenRules === true"
...
@@ -534,7 +590,24 @@ const handleChangeStatus = (node: any, data: any) => {
...
@@ -534,7 +590,24 @@ const handleChangeStatus = (node: any, data: any) => {
:chapterID=
"chapterID"
:chapterID=
"chapterID"
:course_id=
"id"
:course_id=
"id"
:controlInfo=
"controlInfo"
:controlInfo=
"controlInfo"
@
create=
"handleFresh"
/>
@
create=
"handleFresh"
/>
<AddTextbookDialog
v-if=
"isShowTextbookDialog === true"
v-model:isShowTextbookDialog=
"isShowTextbookDialog"
@
create=
"handleFresh"
:chapterName=
"chapterName"
:chapterID=
"chapterID"
:course_id=
"id"
/>
<AddGraphbookDialog
v-if=
"isShowTextbookDialog2 === true"
v-model:isShowTextbookDialog2=
"isShowTextbookDialog2"
@
create=
"handleFresh"
:chapterName=
"chapterName"
:chapterID=
"chapterID"
:course_id=
"id"
/>
</template>
</template>
<
style
>
<
style
>
...
...
src/modules/course/my/api.ts
浏览文件 @
8c25052d
...
@@ -92,3 +92,41 @@ export function courseCopy(data: { id: string }) {
...
@@ -92,3 +92,41 @@ export function courseCopy(data: { id: string }) {
export
function
setDownload
(
data
:
{
course_id
:
string
;
information_id
:
string
;
can_download
:
string
})
{
export
function
setDownload
(
data
:
{
course_id
:
string
;
information_id
:
string
;
can_download
:
string
})
{
return
httpRequest
.
post
(
'/api/resource/v1/course/course/set-course-information-can-download '
,
data
)
return
httpRequest
.
post
(
'/api/resource/v1/course/course/set-course-information-can-download '
,
data
)
}
}
// 获取知识图谱
export
function
getTagList
(
params
:
{
type
:
string
;
parent_id
:
string
;
chapter_id
?:
string
})
{
return
httpRequest
.
get
(
'/api/resource/v1/course/course/tag-list'
,
{
params
})
}
// 新增知识图谱
export
function
addTag
(
data
:
{
name
:
string
;
course_id
:
string
;
status
:
string
;
parent_id
?:
string
})
{
return
httpRequest
.
post
(
'/api/resource/v1/course/course/tag-add'
,
data
)
}
// 更新知识图谱
export
function
updateTag
(
data
:
{
id
:
string
;
name
:
string
;
course_id
:
string
;
status
:
string
;
})
{
return
httpRequest
.
post
(
'/api/resource/v1/course/course/tag-update'
,
data
)
}
// 删除知识图谱
export
function
deleteTag
(
data
:
{
id
:
string
;
course_id
:
string
})
{
return
httpRequest
.
post
(
'/api/resource/v1/course/course/tag-delete'
,
data
)
}
// 查看关联的课程章节
export
function
viewTagCourse
(
params
:
{
tag_id
:
string
;
course_id
:
string
})
{
return
httpRequest
.
get
(
'/api/resource/v1/course/course/tag-course'
,
{
params
})
}
// 查看关联的书籍章节
export
function
viewTagBook
(
params
:
{
tag_id
:
string
;
course_id
:
string
})
{
return
httpRequest
.
get
(
'/api/resource/v1/course/course/tag-book'
,
{
params
})
}
// 导入
export
function
importTag
(
data
:
{
course_id
:
string
;
file
:
any
})
{
return
httpRequest
.
post
(
'/api/resource/v1/course/course/tag-import'
,
data
,
{
headers
:
{
'Content-Type'
:
'multipart/form-data'
}
})
}
\ No newline at end of file
src/modules/course/my/components/Operation.vue
浏览文件 @
8c25052d
...
@@ -124,6 +124,11 @@ const handleMembers = () => {
...
@@ -124,6 +124,11 @@ const handleMembers = () => {
members
.
value
=
useProjectList
(
props
.
data
.
organ_id
).
members
members
.
value
=
useProjectList
(
props
.
data
.
organ_id
).
members
}
}
// 点击知识图谱
const
handleChart
=
()
=>
{
router
.
push
({
path
:
'/course/my/graph'
,
query
:
{
n
:
props
.
data
?.
name
,
bid
:
19
,
cid
:
route
.
query
.
id
}
})
}
// 更改负责人确定
// 更改负责人确定
const
handleSetBelong
=
()
=>
{
const
handleSetBelong
=
()
=>
{
setBelong
({
id
:
id
,
belong_operator
:
form
.
members
}).
then
((
res
:
any
)
=>
{
setBelong
({
id
:
id
,
belong_operator
:
form
.
members
}).
then
((
res
:
any
)
=>
{
...
@@ -223,6 +228,7 @@ watch(
...
@@ -223,6 +228,7 @@ watch(
{{
props
.
data
.
status
==
0
?
'课程上线'
:
'课程下线'
}}
{{
props
.
data
.
status
==
0
?
'课程上线'
:
'课程下线'
}}
</div>
</div>
<div
v-if=
"props.data.auth_belong"
class=
"btn-item"
@
click=
"handleMembers"
>
更改负责人
</div>
<div
v-if=
"props.data.auth_belong"
class=
"btn-item"
@
click=
"handleMembers"
>
更改负责人
</div>
<div
class=
"btn-item"
@
click=
"handleChart"
>
知识图谱
</div>
</div>
</div>
<el-dialog
v-if=
"props.data.auth_belong"
v-model=
"dialogFormVisible"
title=
"更改负责人"
center
>
<el-dialog
v-if=
"props.data.auth_belong"
v-model=
"dialogFormVisible"
title=
"更改负责人"
center
>
<el-form
:model=
"form"
>
<el-form
:model=
"form"
>
...
...
src/modules/course/my/components/ViewCourseInfo.vue
浏览文件 @
8c25052d
...
@@ -234,7 +234,8 @@ const handleDetail = (row: any) => {
...
@@ -234,7 +234,8 @@ const handleDetail = (row: any) => {
inline-prompt
inline-prompt
style=
"--el-switch-on-color: #aa1941"
style=
"--el-switch-on-color: #aa1941"
@
click=
"handleChangeStatus(row)"
@
click=
"handleChangeStatus(row)"
:disabled=
"!checkPermission('v1-course-set-course-information-can-download')"
>
:disabled=
"!checkPermission('v1-course-set-course-information-can-download')"
>
</el-switch>
</el-switch>
</
template
>
</
template
>
<
template
#
table-operate=
"{ row }"
>
<
template
#
table-operate=
"{ row }"
>
...
...
src/modules/course/my/components/ViewGraphBook.vue
0 → 100644
浏览文件 @
8c25052d
<
script
setup
lang=
"ts"
>
import
{
viewTagBook
}
from
'../api'
const
route
=
useRoute
()
const
emit
=
defineEmits
<
Emits
>
()
const
props
=
defineProps
({
isShowGraphBookDialog
:
{
type
:
Boolean
,
required
:
true
},
id
:
{
type
:
String
,
required
:
false
}
})
interface
Emits
{
(
e
:
'update:isShowGraphBookDialog'
,
isShowVideoDialog
:
boolean
):
void
(
e
:
'create'
,
val
:
any
):
void
}
// 取消
const
handleCancel
=
()
=>
{
emit
(
'update:isShowGraphBookDialog'
,
false
)
}
const
chapterList
=
ref
([])
onMounted
(()
=>
{
viewTagBook
({
tag_id
:
props
.
id
as
string
,
course_id
:
route
.
query
.
cid
as
string
}).
then
(
res
=>
{
chapterList
.
value
=
res
.
data
.
reduce
((
a
:
any
,
b
:
any
)
=>
{
b
.
index
=
'0'
if
(
b
.
children
)
{
b
.
children
.
map
((
m
:
any
)
=>
{
m
.
index
=
'1'
})
}
a
.
push
(
b
)
return
a
},
[])
console
.
log
(
chapterList
.
value
,
'chapterList.value'
)
})
})
</
script
>
<
template
>
<el-drawer
:model-value=
"isShowGraphBookDialog"
draggable
:before-close=
"handleCancel"
size=
"60%"
title=
"关联数字教材章节"
>
<el-tree
:data=
"chapterList"
node-key=
"id"
:accordion=
"true"
:expand-on-click-node=
"false"
style=
"min-width: 100%"
>
<template
#
default=
"
{ data }">
<span
class=
"custom-tree-node"
>
<span
class=
"node_title"
>
{{
data
.
name
}}
</span>
</span>
</
template
>
</el-tree>
</el-drawer>
</template>
<
style
lang=
"scss"
scoped
>
.custom-tree-node
{
flex
:
1
;
display
:
flex
;
align-items
:
center
;
justify-content
:
space-between
;
font-size
:
14px
;
padding-right
:
8px
;
}
.btn_operate
{
background-color
:
rgba
(
248
,
241
,
229
,
0
.39
);
font-weight
:
400
;
color
:
#b2833d
;
border
:
none
;
border-radius
:
16px
;
margin
:
3px
;
}
.card-list
{
display
:
flex
;
flex-direction
:
column
;
}
.card-list-con
{
background
:
#fafafa
;
padding
:
20px
;
display
:
flex
;
flex-wrap
:
wrap
;
}
.video-head
{
position
:
relative
;
.video-head-icon
{
position
:
absolute
;
top
:
0
;
right
:
0
;
font-size
:
30px
;
color
:
#666
;
cursor
:
pointer
;
}
}
.video-tool-btn
{
padding
:
10px
0
30px
0
;
}
.video-head-icon
{
position
:
absolute
;
top
:
0
;
right
:
0
;
font-size
:
30px
;
color
:
#666
;
cursor
:
pointer
;
}
</
style
>
src/modules/course/my/components/ViewGraphCourse.vue
0 → 100644
浏览文件 @
8c25052d
<
script
setup
lang=
"ts"
>
import
{
viewTagCourse
}
from
'../api'
const
route
=
useRoute
()
const
emit
=
defineEmits
<
Emits
>
()
const
props
=
defineProps
({
isShowGraphCourseDialog
:
{
type
:
Boolean
,
required
:
true
},
id
:
{
type
:
String
,
required
:
false
}
})
interface
Emits
{
(
e
:
'update:isShowGraphCourseDialog'
,
isShowVideoDialog
:
boolean
):
void
(
e
:
'create'
,
val
:
any
):
void
}
// 取消
const
handleCancel
=
()
=>
{
emit
(
'update:isShowGraphCourseDialog'
,
false
)
}
const
chapterList
=
ref
([])
onMounted
(()
=>
{
viewTagCourse
({
tag_id
:
props
.
id
as
string
,
course_id
:
route
.
query
.
cid
as
string
}).
then
(
res
=>
{
chapterList
.
value
=
res
.
data
.
reduce
((
a
:
any
,
b
:
any
)
=>
{
b
.
index
=
'0'
if
(
b
.
children
)
{
b
.
children
.
map
((
m
:
any
)
=>
{
m
.
index
=
'1'
})
}
a
.
push
(
b
)
return
a
},
[])
console
.
log
(
chapterList
.
value
,
'chapterList.value'
)
})
})
</
script
>
<
template
>
<el-drawer
:model-value=
"isShowGraphCourseDialog"
draggable
:before-close=
"handleCancel"
size=
"60%"
title=
"关联课程章节"
>
<el-tree
:data=
"chapterList"
node-key=
"id"
:accordion=
"true"
:expand-on-click-node=
"false"
style=
"min-width: 100%"
>
<template
#
default=
"
{ data }">
<span
class=
"custom-tree-node"
>
<span
class=
"node_title"
>
{{
data
.
name
}}
</span>
</span>
</
template
>
</el-tree>
</el-drawer>
</template>
<
style
lang=
"scss"
scoped
>
.custom-tree-node
{
flex
:
1
;
display
:
flex
;
align-items
:
center
;
justify-content
:
space-between
;
font-size
:
14px
;
padding-right
:
8px
;
}
.btn_operate
{
background-color
:
rgba
(
248
,
241
,
229
,
0
.39
);
font-weight
:
400
;
color
:
#b2833d
;
border
:
none
;
border-radius
:
16px
;
margin
:
3px
;
}
.card-list
{
display
:
flex
;
flex-direction
:
column
;
}
.card-list-con
{
background
:
#fafafa
;
padding
:
20px
;
display
:
flex
;
flex-wrap
:
wrap
;
}
.video-head
{
position
:
relative
;
.video-head-icon
{
position
:
absolute
;
top
:
0
;
right
:
0
;
font-size
:
30px
;
color
:
#666
;
cursor
:
pointer
;
}
}
.video-tool-btn
{
padding
:
10px
0
30px
0
;
}
.video-head-icon
{
position
:
absolute
;
top
:
0
;
right
:
0
;
font-size
:
30px
;
color
:
#666
;
cursor
:
pointer
;
}
</
style
>
src/modules/course/my/index.ts
浏览文件 @
8c25052d
...
@@ -9,7 +9,8 @@ export const routes: Array<RouteRecordRaw> = [
...
@@ -9,7 +9,8 @@ export const routes: Array<RouteRecordRaw> = [
{
path
:
''
,
component
:
()
=>
import
(
'./views/List.vue'
)
},
{
path
:
''
,
component
:
()
=>
import
(
'./views/List.vue'
)
},
{
path
:
'/course/my/view'
,
component
:
()
=>
import
(
'./views/View.vue'
)
},
{
path
:
'/course/my/view'
,
component
:
()
=>
import
(
'./views/View.vue'
)
},
// id: 章节id courseId课程id
// id: 章节id courseId课程id
{
path
:
'/course/my/view/:id/:courseId'
,
component
:
()
=>
import
(
'./views/ViewDetails.vue'
)
}
{
path
:
'/course/my/view/:id/:courseId'
,
component
:
()
=>
import
(
'./views/ViewDetails.vue'
)
},
{
path
:
'/course/my/graph'
,
component
:
()
=>
import
(
'./views/Graph.vue'
)
}
]
]
}
}
]
]
src/modules/course/my/views/Graph.vue
0 → 100644
浏览文件 @
8c25052d
<
script
setup
lang=
"ts"
>
import
{
getTagList
,
addTag
,
updateTag
,
deleteTag
,
importTag
}
from
'../api'
import
ViewGraphCourse
from
'../components/ViewGraphCourse.vue'
import
ViewGraphBook
from
'../components/ViewGraphBook.vue'
import
{
ElMessage
}
from
'element-plus'
const
route
=
useRoute
()
// 获取列表
const
tableData
=
ref
([])
const
updateTagList
=
()
=>
{
getTagList
({
type
:
'1'
,
parent_id
:
route
.
query
.
cid
as
string
}).
then
(
res
=>
{
tableData
.
value
=
res
.
data
})
}
updateTagList
()
// 新增
const
addTagRequest
=
()
=>
{
addTag
({
name
:
pName
.
value
,
course_id
:
route
.
query
?.
cid
as
string
,
status
:
'1'
,
parent_id
:
addTagId
.
value
}).
then
(
res
=>
{
updateTagList
()
ElMessage
({
message
:
'添加成功'
,
type
:
'success'
})
}
)
}
// 更新
const
updateTagRequest
=
()
=>
{
updateTag
({
id
:
addTagId
.
value
,
name
:
pName
.
value
,
course_id
:
route
.
query
?.
cid
as
string
,
status
:
'1'
}).
then
(
res
=>
{
updateTagList
()
ElMessage
({
message
:
'修改成功'
,
type
:
'success'
})
})
}
const
findParentIdById
=
(
items
:
any
,
targetId
:
any
)
=>
{
// 使用栈来模拟递归过程,存储当前遍历元素和父级id
const
stack
=
[...
items
]
// 初始化栈为顶层元素
// 使用栈遍历
while
(
stack
.
length
>
0
)
{
const
currentItem
=
stack
.
pop
()
// 取出栈顶元素
// 检查当前元素是否是目标元素
if
(
currentItem
.
id
===
targetId
)
{
return
currentItem
.
parentId
// 找到目标元素,返回父级id
}
// 如果当前元素有children,继续遍历子元素
if
(
currentItem
.
children
)
{
for
(
const
child
of
currentItem
.
children
)
{
child
.
parentId
=
currentItem
.
id
// 为子元素添加父级id
stack
.
push
(
child
)
// 将子元素压入栈中
}
}
}
return
undefined
// 如果没有找到目标id,返回undefined
}
// 弹窗输入框
const
pName
:
any
=
ref
(
''
)
const
dialogVisible
=
ref
(
false
)
const
isUpdate
=
ref
(
false
)
// 点击添加同级 子级的id
const
addTagId
=
ref
<
any
>
(
''
)
const
handleAddTagSame
=
(
scope
:
any
)
=>
{
const
id
=
findParentIdById
(
tableData
.
value
,
scope
?.
row
?.
id
)
addTagId
.
value
=
id
||
''
isUpdate
.
value
=
false
dialogVisible
.
value
=
true
}
const
handleAddTagChild
=
(
scope
:
any
)
=>
{
addTagId
.
value
=
scope
?.
row
.
id
isUpdate
.
value
=
false
dialogVisible
.
value
=
true
}
const
handleUpdateTag
=
(
scope
:
any
)
=>
{
addTagId
.
value
=
scope
?.
row
?.
id
pName
.
value
=
scope
?.
row
?.
name
isUpdate
.
value
=
true
dialogVisible
.
value
=
true
}
// 输入完名称点击输入框
const
handleConfirm
=
()
=>
{
if
(
isUpdate
)
{
updateTagRequest
()
}
else
{
addTagRequest
()
}
dialogVisible
.
value
=
false
}
const
handleDelete
=
(
scope
:
any
)
=>
{
deleteTag
({
id
:
scope
.
row
?.
id
,
course_id
:
route
.
query
.
cid
as
string
}).
then
(
res
=>
{
updateTagList
()
ElMessage
({
message
:
'删除成功'
,
type
:
'success'
})
})
}
const
isShowGraphCourseDialog
=
ref
(
false
)
const
isShowGraphBookDialog
=
ref
(
false
)
const
handleCourseView
=
function
(
scope
:
any
)
{
addTagId
.
value
=
scope
.
row
?.
id
isShowGraphCourseDialog
.
value
=
true
}
const
handleBookView
=
function
(
scope
:
any
)
{
addTagId
.
value
=
scope
.
row
?.
id
isShowGraphBookDialog
.
value
=
true
}
const
formInline
=
reactive
({
user
:
''
})
// 导出
const
handleTagDownload
=
()
=>
{
// tagDownload({ course_id: route.query.cid as string }).then()
window
.
open
(
`/api/resource/v1/course/course/tag-download?course_id=
${
route
.
query
.
cid
}
`
)
}
const
fetchFileUpload
=
(
option
:
any
)
=>
{
return
new
Promise
(()
=>
{
importTag
({
course_id
:
route
.
query
.
cid
as
string
,
file
:
option
.
file
}).
then
(()
=>
{
updateTagList
()
ElMessage
.
success
(
'导入数据成功'
)
})
})
}
</
script
>
<
template
>
<AppCard
title=
"知识图库"
>
<div
style=
"margin-bottom: 15px"
>
课程名称:
{{
route
.
query
?.
n
}}
</div>
<!--
<div>
<el-form
:inline=
"true"
:model=
"formInline"
class=
"demo-form-inline"
>
<el-form-item
label=
"知识点"
>
<el-input
v-model=
"formInline.user"
placeholder=
"请输入"
clearable
/>
</el-form-item>
<el-form-item>
<el-button
type=
"primary"
>
搜索
</el-button>
<el-button
type=
"primary"
>
重置
</el-button>
</el-form-item>
</el-form>
</div>
-->
<div
style=
"display: flex"
>
<el-button
type=
"primary"
@
click=
"handleAddTagSame"
>
添加知识点
</el-button>
<el-upload
:show-file-list=
"false"
ref=
"upload"
action=
"#"
:limit=
"1"
:http-request=
"fetchFileUpload"
>
<el-button
type=
"primary"
style=
"margin: 0 15px"
>
批量导入
</el-button>
<!--
<el-icon
class=
"el-icon--upload"
><upload-filled
/></el-icon>
<div
class=
"el-upload__text"
>
将文件拖至此处,点击上传
</div>
-->
</el-upload>
<el-button
type=
"primary"
@
click=
"handleTagDownload"
>
导出
</el-button>
</div>
<el-table
:data=
"tableData"
style=
"width: 100%; margin: 20px 0"
row-key=
"id"
highlight-current-row
:tree-props=
"
{ children: 'children', hasChildren: 'hasChildren' }"
align="center"
>
<!--
<el-table-column
type=
"index"
></el-table-column>
-->
<el-table-column
prop=
"name"
label=
"知识点"
>
</el-table-column>
<!--
<el-table-column
prop=
"update"
label=
"更新人"
width=
"180"
>
</el-table-column>
<el-table-column
prop=
"time"
label=
"更新时间"
width=
"180"
>
</el-table-column>
-->
<el-table-column
fixed=
"right"
label=
"操作"
>
<template
#
default=
"scope"
>
<el-button
link
type=
"primary"
size=
"small"
@
click=
"handleAddTagSame(scope)"
>
添加同级
</el-button>
<el-button
link
type=
"primary"
size=
"small"
@
click=
"handleAddTagChild(scope)"
>
添加子级
</el-button>
<el-button
link
type=
"primary"
size=
"small"
@
click=
"handleUpdateTag(scope)"
>
编辑知识点
</el-button>
<el-button
link
type=
"primary"
size=
"small"
@
click=
"handleDelete(scope)"
>
删除
</el-button>
<el-button
link
type=
"primary"
size=
"small"
@
click=
"handleCourseView(scope)"
>
查看关联章节
</el-button>
<el-button
link
type=
"primary"
size=
"small"
@
click=
"handleBookView(scope)"
>
查看关联数字教材
</el-button>
</
template
>
</el-table-column>
</el-table>
<el-dialog
v-model=
"dialogVisible"
title=
"提示"
width=
"500px"
>
<!-- <span>This is a message</span> -->
<el-input
v-model=
"pName"
placeholder=
"请输入知识点名称"
/>
<
template
#
footer
>
<div
class=
"dialog-footer"
>
<el-button
@
click=
"dialogVisible = false"
>
取消
</el-button>
<el-button
type=
"primary"
@
click=
"handleConfirm"
>
确认
</el-button>
</div>
</
template
>
</el-dialog>
<!-- <Operation :data="courseDetails" @update="handleFresh"></Operation>
<div class="course-view">
<ViewCourseInfoTop :data="courseDetails"></ViewCourseInfoTop>
<div class="course-left_info">
<ViewCourseInfo :data="courseDetails" class="info_bottom" :id="id"></ViewCourseInfo>
<ViewCourseChapter
v-if="Object.keys(courseDetails).length"
:data="chapters"
class="info_chapter"
></ViewCourseChapter>
</div>
</div> -->
</AppCard>
<ViewGraphCourse
:id=
"addTagId"
v-if=
"isShowGraphCourseDialog === true"
v-model:isShowGraphCourseDialog=
"isShowGraphCourseDialog"
/>
<ViewGraphBook
:id=
"addTagId"
v-if=
"isShowGraphBookDialog === true"
v-model:isShowGraphBookDialog=
"isShowGraphBookDialog"
/>
</template>
<
style
lang=
"scss"
>
.course-view
{
border
:
1px
solid
#bfbfbf
;
border-radius
:
10px
;
display
:
flex
;
flex-direction
:
column
;
.course-left_info
{
display
:
flex
;
.info_bottom
{
width
:
67%
;
}
.info_chapter
{
width
:
25%
;
}
}
}
.custom-tree-node
{
flex
:
1
;
display
:
flex
;
align-items
:
center
;
justify-content
:
space-between
;
font-size
:
14px
;
padding-right
:
8px
;
}
.course_tip
{
font-size
:
12px
;
font-weight
:
400
;
color
:
#999999
;
margin-left
:
16px
;
line-height
:
36px
;
height
:
36px
;
}
.el-tree-node__content
{
height
:
42px
;
margin-bottom
:
15px
;
background
:
#f4f4f4
;
}
.btn_operate
{
background-color
:
rgba
(
248
,
241
,
229
,
0
.39
);
font-weight
:
400
;
color
:
#b2833d
;
border
:
none
;
border-radius
:
16px
;
margin
:
3px
;
}
.btn_control
{
font-weight
:
400
;
color
:
#b2833d
;
}
.btn_edit
{
color
:
#b2833d
;
margin-right
:
10px
;
}
.node_type
{
background
:
#bf9d6b
;
border-radius
:
20px
;
line-height
:
1
;
font-size
:
12px
;
font-weight
:
400
;
color
:
#ffffff
;
text-align
:
center
;
padding
:
4px
8px
;
margin-right
:
14px
;
}
.node_title
{
font-size
:
14px
;
font-weight
:
400
;
color
:
#666666
;
line-height
:
1
;
text-align
:
center
;
}
</
style
>
src/utils/upload.ts
0 → 100644
浏览文件 @
8c25052d
import
axios
from
'axios'
import
md5
from
'blueimp-md5'
import
{
getSignature
,
uploadFile
}
from
'@/api/base'
export
async
function
upload
(
blob
:
Blob
|
File
)
{
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/resource-center/'
+
md5
(
new
Date
().
getTime
()
+
Math
.
random
().
toString
(
36
).
slice
(
-
8
))
+
'.'
+
fileType
const
response
:
any
=
await
getSignature
()
const
params
=
{
key
,
host
:
response
.
host
,
OSSAccessKeyId
:
response
.
accessid
,
policy
:
response
.
policy
,
signature
:
response
.
signature
,
success_action_status
:
'200'
,
file
:
blob
,
url
:
`
${
response
.
host
}
/
${
key
}
`
,
}
await
uploadFile
(
params
)
return
params
.
url
}
export
async
function
uploadFileByUrl
(
url
:
string
)
{
const
res
=
await
axios
.
get
(
url
,
{
responseType
:
'blob'
})
return
upload
(
res
.
data
)
}
vite.config.ts
浏览文件 @
8c25052d
...
@@ -33,7 +33,6 @@ export default defineConfig(() => ({
...
@@ -33,7 +33,6 @@ export default defineConfig(() => ({
changeOrigin
:
true
,
changeOrigin
:
true
,
rewrite
:
path
=>
path
.
replace
(
/^
\/
api
\/
qbs/
,
''
)
rewrite
:
path
=>
path
.
replace
(
/^
\/
api
\/
qbs/
,
''
)
},
},
'/api'
:
'https://resource-center.ezijing.com'
'/api'
:
'https://resource-center.ezijing.com'
}
}
},
},
...
...
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论