Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
C
center-resource
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
图表
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
EzijingWeb
center-resource
Commits
c7a36aff
提交
c7a36aff
authored
11月 29, 2024
作者:
王鹏飞
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
chore: 学生管理新增批量修改
上级
72c8ad47
显示空白字符变更
内嵌
并排
正在显示
5 个修改的文件
包含
276 行增加
和
34 行删除
+276
-34
api.ts
src/modules/admin/student/api.ts
+14
-5
ImportStudent.vue
src/modules/admin/student/components/ImportStudent.vue
+84
-19
UpdateStudent.vue
src/modules/admin/student/components/UpdateStudent.vue
+138
-0
List.vue
src/modules/admin/student/views/List.vue
+21
-10
upload.ts
src/utils/upload.ts
+19
-0
没有找到文件。
src/modules/admin/student/api.ts
浏览文件 @
c7a36aff
...
...
@@ -4,12 +4,16 @@ import httpRequest from '@/utils/axios'
export
function
getStudentList
(
params
?:
{
name
?:
string
;
organ_id
?:
string
;
page
?:
string
;
'per-page'
?:
string
})
{
return
httpRequest
.
get
(
'/api/resource/v1/learning/student/list'
,
{
params
})
}
// // 导入学生
export
function
importStudent
(
data
:
{
file
:
any
})
{
return
httpRequest
.
post
(
'/api/resource/v1/learning/student/import'
,
data
,
{
headers
:
{
'Content-Type'
:
'multipart/form-data'
},
})
// 导入学生
export
function
importStudent
(
data
:
{
url
:
string
;
name
:
string
;
size
:
number
})
{
return
httpRequest
.
post
(
'/api/resource/v1/learning/student/import'
,
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
})
{
return
httpRequest
.
get
(
'/api/resource/v1/learning/student/download'
,
{
params
,
responseType
:
'blob'
})
...
...
@@ -67,3 +71,8 @@ export function getClassList(params?: {
})
{
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/ImportStudent.vue
浏览文件 @
c7a36aff
<
script
lang=
"ts"
setup
>
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
{
importStudent
}
from
'../api'
import
{
importStudent
,
getStudentProgress
}
from
'../api'
import
{
upload
}
from
'@/utils/upload'
const
emit
=
defineEmits
<
Emits
>
()
const
upload
=
ref
()
const
upload
Ref
=
ref
()
const
fileList
=
ref
([])
// 文件列表
defineProps
({
isShowImportDialog
:
{
type
:
Boolean
}
type
:
Boolean
,
}
,
})
interface
Emits
{
(
e
:
'update:isShowImportDialog'
,
isShowImportDialog
:
boolean
):
void
...
...
@@ -31,26 +33,64 @@ const beforeUpload = (file: any) => {
return
true
}
}
const
fetchFileUpload
=
(
option
:
any
)
=>
{
return
new
Promise
(()
=>
{
importStudent
({
file
:
option
.
file
}).
then
(()
=>
{
ElMessage
.
success
(
'导入数据成功'
)
emit
(
'update:isShowImportDialog'
,
false
)
const
loading
=
ref
(
false
)
const
progress
=
reactive
({
progress
:
'-'
,
total
:
'-'
,
message
:
'导入中'
,
status
:
2
,
})
let
timer
=
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
=
()
=>
{
upload
.
value
.
submit
()
upload
Ref
.
value
.
submit
()
}
</
script
>
<
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
style=
"text-align: center"
class=
"file-import"
ref=
"upload"
ref=
"upload
Ref
"
action=
"#"
accept=
".xls,.xlsx"
drag
...
...
@@ -62,14 +102,18 @@ const handleSubmitUpload = () => {
<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:
center
"
>
导入模板下载:
<a
<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"
>
学生模板.xlsx
</el-link></a
>
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>
...
...
@@ -78,3 +122,24 @@ const handleSubmitUpload = () => {
</
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/components/UpdateStudent.vue
0 → 100644
浏览文件 @
c7a36aff
<
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
=
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/views/List.vue
浏览文件 @
c7a36aff
...
...
@@ -3,6 +3,7 @@ import { ElMessage } from 'element-plus'
import
{
useProjectList
}
from
'@/composables/useGetProjectList'
import
AddStudent
from
'../components/AddStudent.vue'
import
ImportStudent
from
'../components/ImportStudent.vue'
import
UpdateStudent
from
'../components/UpdateStudent.vue'
// import SourceAnalysis from '../components/SourceAnalysis.vue'
import
{
getStudentList
,
exportStudent
,
updateStudent
}
from
'../api'
...
...
@@ -67,7 +68,7 @@ const listOptions = computed(() => {
{
type
:
'input'
,
prop
:
'mobile'
,
label
:
'学生电话:'
,
placeholder
:
'学生电话'
},
],
columns
:
[
{
type
:
'selection'
},
//
{ type: 'selection' },
{
label
:
'序号'
,
type
:
'index'
,
align
:
'center'
},
{
label
:
'学号'
,
prop
:
'sno_number'
,
align
:
'center'
,
minWidth
:
'200'
},
{
label
:
'姓名'
,
prop
:
'name'
,
align
:
'center'
,
minWidth
:
'100'
},
...
...
@@ -125,20 +126,25 @@ const handleChangeStatus = (row: any) => {
const
handleImport
=
()
=>
{
isShowImportDialog
.
value
=
true
}
// 批量修改
const
updateDialogVisible
=
ref
(
false
)
const
handleUpdate
=
()
=>
{
updateDialogVisible
.
value
=
true
}
// 导出
const
handleExport
=
()
=>
{
const
params
=
Object
.
assign
({},
appList
.
value
?.
params
)
exportStudent
(
params
).
then
((
r
:
any
)
=>
{
const
blob
=
new
Blob
([
r
],
{
type
:
'application/vnd.ms-excel'
})
if
(
'download'
in
document
.
createElement
(
'a'
))
{
const
e
link
=
document
.
createElement
(
'a'
)
e
link
.
download
=
'学员数据.xlsx'
e
link
.
style
.
display
=
'none'
e
link
.
href
=
URL
.
createObjectURL
(
blob
)
document
.
body
.
appendChild
(
e
link
)
e
link
.
click
()
URL
.
revokeObjectURL
(
e
link
.
href
)
document
.
body
.
removeChild
(
e
link
)
const
link
=
document
.
createElement
(
'a'
)
link
.
download
=
'学员数据.xlsx'
link
.
style
.
display
=
'none'
link
.
href
=
URL
.
createObjectURL
(
blob
)
document
.
body
.
appendChild
(
link
)
link
.
click
()
URL
.
revokeObjectURL
(
link
.
href
)
document
.
body
.
removeChild
(
link
)
}
})
}
...
...
@@ -171,7 +177,10 @@ const handleAnalysis = () => {
>
批量导入
</el-button
>
<el-button
type=
"primary"
round
@
click=
"handleExport"
v-permission=
"'v1-learning-student-download'"
>
导出
</el-button
>
批量导出
</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>
<template
#
status=
"
{ row }">
...
...
@@ -207,6 +216,8 @@ const handleAnalysis = () => {
@
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" /> -->
</template>
src/utils/upload.ts
0 → 100644
浏览文件 @
c7a36aff
import
md5
from
'blueimp-md5'
import
{
getSignature
,
uploadFile
}
from
'@/api/base'
export
async
function
upload
(
blob
:
Blob
)
{
const
key
=
'upload/resource-center/'
+
md5
(
new
Date
().
getTime
()
+
Math
.
random
().
toString
(
36
).
slice
(
-
8
))
+
'.png'
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
}
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论