Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
phsl
/
admin
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Members
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit
6d8ed5ee
authored
Mar 21, 2023
by
fengjingtao
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: 用户管理重写尝试
parent
812300cc
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
761 additions
and
496 deletions
+761
-496
src/views/system/user/index.vue
+761
-496
No files found.
src/views/system/user/index.vue
View file @
6d8ed5ee
<
template
>
<
template
>
<div
class=
"flex"
>
<div
class=
"app-container"
>
<el-card
class=
"w-1/5 user"
:gutter=
"12"
shadow=
"always"
>
<!-- 搜索工作栏 -->
<template
#
header
>
<el-row
:gutter=
"20"
>
<div
class=
"card-header"
>
<!--部门数据-->
<span>
部门列表
</span>
<el-col
:span=
"4"
:xs=
"24"
>
<XTextButton
title=
"修改部门"
@
click=
"handleDeptEdit()"
/>
<div
class=
"head-container"
>
<el-input
v-model=
"deptName"
placeholder=
"请输入部门名称"
clearable
size=
"small"
prefix-icon=
"el-icon-search"
style=
"margin-bottom: 20px"
/>
</div>
</div>
</
template
>
<div
class=
"head-container"
>
<el-input
v-model=
"filterText"
placeholder=
"搜索部门"
/>
<el-scrollbar
height=
"650"
>
<el-tree
<el-tree
ref=
"treeRef"
node-key=
"id"
default-expand-all
:data=
"deptOptions"
:data=
"deptOptions"
:props=
"defaultProps"
:props=
"defaultProps"
:highlight-current=
"true"
:filter-node-method=
"filterNode"
:expand-on-click-node=
"false"
:expand-on-click-node=
"false"
@
node-click=
"handleDeptNodeClick"
:filter-node-method=
"filterNode"
ref=
"tree"
default-expand-all
highlight-current
@
node-click=
"handleNodeClick"
/>
/>
</el-scrollbar>
</el-card>
<el-card
class=
"w-4/5 user"
style=
"margin-left: 10px"
:gutter=
"12"
shadow=
"hover"
>
<
template
#
header
>
<div
class=
"card-header"
>
<span>
{{
tableTitle
}}
</span>
</div>
</div>
</
template
>
</el-col>
<!-- 列表 -->
<!--用户数据-->
<XTable
@
register=
"registerTable"
>
<el-col
:span=
"20"
:xs=
"24"
>
<
template
#
toolbar_buttons
>
<el-form
<!-- 操作:新增 -->
:model=
"queryParams"
<XButton
ref=
"queryForm"
size=
"small"
:inline=
"true"
v-show=
"showSearch"
label-width=
"68px"
>
<el-form-item
label=
"用户名称"
prop=
"username"
>
<el-input
v-model=
"queryParams.username"
placeholder=
"请输入用户名称"
clearable
style=
"width: 240px"
@
keyup
.
enter
.
native=
"handleQuery"
/>
</el-form-item>
<el-form-item
label=
"手机号码"
prop=
"mobile"
>
<el-input
v-model=
"queryParams.mobile"
placeholder=
"请输入手机号码"
clearable
style=
"width: 240px"
@
keyup
.
enter
.
native=
"handleQuery"
/>
</el-form-item>
<el-form-item
label=
"状态"
prop=
"status"
>
<el-select
v-model=
"queryParams.status"
placeholder=
"用户状态"
clearable
style=
"width: 240px"
>
<el-option
v-for=
"dict in statusDictDatas"
:key=
"parseInt(dict.value)"
:label=
"dict.label"
:value=
"parseInt(dict.value)"
/>
</el-select>
</el-form-item>
<el-form-item
label=
"创建时间"
prop=
"createTime"
>
<el-date-picker
v-model=
"queryParams.createTime"
style=
"width: 240px"
value-format=
"yyyy-MM-dd HH:mm:ss"
type=
"daterange"
range-separator=
"-"
start-placeholder=
"开始日期"
end-placeholder=
"结束日期"
:default-time=
"['00:00:00', '23:59:59']"
/>
</el-form-item>
<el-form-item>
<el-button
type=
"primary"
icon=
"el-icon-search"
@
click=
"handleQuery"
>
搜索
</el-button>
<el-button
icon=
"el-icon-refresh"
@
click=
"resetQuery"
>
重置
</el-button>
</el-form-item>
</el-form>
<el-row
:gutter=
"10"
class=
"mb8"
>
<el-col
:span=
"1.5"
>
<el-button
type=
"primary"
type=
"primary"
preIcon=
"ep:zoom-in"
plain
:title=
"t('action.add')"
icon=
"el-icon-plus"
size=
"mini"
@
click=
"handleAdd"
v-hasPermi=
"['system:user:create']"
v-hasPermi=
"['system:user:create']"
@
click=
"handleCreate()"
>
新增
</el-button
/>
>
<!-- 操作:导入用户 -->
</el-col>
<XButton
<el-col
:span=
"1.5"
>
type=
"warning"
<el-button
preIcon=
"ep:upload"
type=
"info"
:title=
"t('action.import')"
icon=
"el-icon-upload2"
size=
"mini"
@
click=
"handleImport"
v-hasPermi=
"['system:user:import']"
v-hasPermi=
"['system:user:import']"
@
click=
"importDialogVisible = true"
>
导入
</el-button
/>
>
<!-- 操作:导出用户 -->
</el-col>
<XButton
<el-col
:span=
"1.5"
>
<el-button
type=
"warning"
type=
"warning"
preIcon=
"ep:download"
icon=
"el-icon-download"
:title=
"t('action.export')"
size=
"mini"
@
click=
"handleExport"
:loading=
"exportLoading"
v-hasPermi=
"['system:user:export']"
v-hasPermi=
"['system:user:export']"
@
click=
"exportList('用户数据.xls')"
>
导出
</el-button
>
</el-col>
<right-toolbar
:showSearch
.
sync=
"showSearch"
@
queryTable=
"getList"
:columns=
"columns"
></right-toolbar>
</el-row>
<el-table
v-loading=
"loading"
:data=
"userList"
>
<el-table-column
label=
"用户编号"
align=
"center"
key=
"id"
prop=
"id"
v-if=
"columns[0].visible"
/>
/>
</
template
>
<el-table-column
<
template
#
status_default=
"{ row }"
>
label=
"用户名称"
align=
"center"
key=
"username"
prop=
"username"
v-if=
"columns[1].visible"
:show-overflow-tooltip=
"true"
/>
<el-table-column
label=
"用户昵称"
align=
"center"
key=
"nickname"
prop=
"nickname"
v-if=
"columns[2].visible"
:show-overflow-tooltip=
"true"
/>
<el-table-column
label=
"部门"
align=
"center"
key=
"deptName"
prop=
"dept.name"
v-if=
"columns[3].visible"
:show-overflow-tooltip=
"true"
/>
<el-table-column
label=
"手机号码"
align=
"center"
key=
"mobile"
prop=
"mobile"
v-if=
"columns[4].visible"
width=
"120"
/>
<el-table-column
label=
"状态"
key=
"status"
v-if=
"columns[5].visible"
align=
"center"
>
<template
v-slot=
"scope"
>
<el-switch
<el-switch
v-model=
"
row.status"
v-model=
"scope.
row.status"
:active-value=
"0"
:active-value=
"0"
:inactive-value=
"1"
:inactive-value=
"1"
@
change=
"handleStatusChange(
row)"
@
change=
"handleStatusChange(scope.
row)"
/>
/>
</
template
>
</
template
>
<
template
#
actionbtns_default=
"{ row }"
>
</el-table-column>
<!-- 操作:编辑 -->
<el-table-column
<XTextButton
label=
"创建时间"
preIcon=
"ep:edit"
align=
"center"
:title=
"t('action.edit')"
prop=
"createTime"
v-hasPermi=
"['system:user:update']"
v-if=
"columns[6].visible"
@
click=
"handleUpdate(row.id)"
width=
"160"
/>
>
<!-- 操作:详情 -->
<
template
v-slot=
"scope"
>
<XTextButton
<span>
{{
parseTime
(
scope
.
row
.
createTime
)
}}
</span>
preIcon=
"ep:view"
</
template
>
:title=
"t('action.detail')"
</el-table-column>
<el-table-column
label=
"操作"
align=
"center"
width=
"160"
class-name=
"small-padding fixed-width"
>
<
template
v-slot=
"scope"
>
<el-button
size=
"mini"
type=
"text"
icon=
"el-icon-edit"
@
click=
"handleUpdate(scope.row)"
v-hasPermi=
"['system:user:update']"
v-hasPermi=
"['system:user:update']"
@
click=
"handleDetail(row.id)"
>
修改
</el-button
/
>
>
<el-dropdown
<el-dropdown
class=
"p-0.5
"
@
command=
"(command) => handleCommand(command, scope.$index, scope.row)
"
v-hasPermi=
"[
v-hasPermi=
"[
'system:user:delete',
'system:user:update-password',
'system:user:update-password',
'system:permission:assign-user-role',
'system:permission:assign-user-role'
'system:user:delete'
]"
]"
>
>
<XTextButton
:title=
"t('action.more')"
postIcon=
"ep:arrow-down"
/>
<el-button
size=
"mini"
type=
"text"
icon=
"el-icon-d-arrow-right"
>
更多
</el-button>
<template
#
dropdown
>
<el-dropdown-menu
slot=
"dropdown"
>
<el-dropdown-menu>
<el-dropdown-item
<el-dropdown-item>
command=
"handleDelete"
<!-- 操作:重置密码 -->
v-if=
"scope.row.id !== 1"
<XTextButton
size=
"mini"
preIcon=
"ep:key"
type=
"text"
title=
"重置密码"
icon=
"el-icon-delete"
v-hasPermi=
"['system:user:delete']"
>
删除
</el-dropdown-item
>
<el-dropdown-item
command=
"handleResetPwd"
size=
"mini"
type=
"text"
icon=
"el-icon-key"
v-hasPermi=
"['system:user:update-password']"
v-hasPermi=
"['system:user:update-password']"
@
click=
"handleResetPwd(row)"
>
重置密码
</el-dropdown-item
/>
>
</el-dropdown-item>
<el-dropdown-item
<el-dropdown-item>
command=
"handleRole"
<!-- 操作:分配角色 -->
size=
"mini"
<XTextButton
type=
"text"
preIcon=
"ep:key"
icon=
"el-icon-circle-check"
title=
"分配角色"
v-hasPermi=
"['system:permission:assign-user-role']"
v-hasPermi=
"['system:permission:assign-user-role']"
@
click=
"handleRole(row)"
>
分配角色
</el-dropdown-item
/>
>
</el-dropdown-item>
<el-dropdown-item>
<!-- 操作:删除 -->
<XTextButton
preIcon=
"ep:delete"
:title=
"t('action.del')"
v-hasPermi=
"['system:user:delete']"
@
click=
"deleteData(row.id)"
/>
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown-menu>
</
template
>
</el-dropdown>
</el-dropdown>
</
template
>
</
template
>
</XTable>
</el-table-column>
</el-card>
</el-table>
</div>
<XModal
v-model=
"dialogVisible"
:title=
"dialogTitle"
>
<pagination
<!-- 对话框(添加 / 修改) -->
v-show=
"total > 0"
<Form
:total=
"total"
v-if=
"['create', 'update'].includes(actionType)"
:page
.
sync=
"queryParams.pageNo"
:rules=
"rules"
:limit
.
sync=
"queryParams.pageSize"
:schema=
"allSchemas.formSchema"
@
pagination=
"getList"
ref=
"formRef"
>
<
template
#
deptId=
"form"
>
<el-tree-select
node-key=
"id"
v-model=
"form['deptId']"
:props=
"defaultProps"
:data=
"deptOptions"
check-strictly
/>
/>
</
template
>
</el-col>
<
template
#
postIds=
"form"
>
</el-row>
<el-select
v-model=
"form['postIds']"
multiple
:placeholder=
"t('common.selectText')"
>
<!-- 添加或修改参数配置对话框 -->
<el-dialog
:title=
"title"
:visible
.
sync=
"open"
width=
"600px"
append-to-body
>
<el-form
ref=
"form"
:model=
"form"
:rules=
"rules"
label-width=
"80px"
>
<el-row>
<el-col
:span=
"12"
>
<el-form-item
label=
"用户昵称"
prop=
"nickname"
>
<el-input
v-model=
"form.nickname"
placeholder=
"请输入用户昵称"
/>
</el-form-item>
</el-col>
<el-col
:span=
"12"
>
<el-form-item
label=
"归属部门"
prop=
"deptId"
>
<treeselect
v-model=
"form.deptId"
:options=
"deptOptions"
:show-count=
"true"
:clearable=
"false"
placeholder=
"请选择归属部门"
:normalizer=
"normalizer"
/>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col
:span=
"12"
>
<el-form-item
label=
"手机号码"
prop=
"mobile"
>
<el-input
v-model=
"form.mobile"
placeholder=
"请输入手机号码"
maxlength=
"11"
/>
</el-form-item>
</el-col>
<el-col
:span=
"12"
>
<el-form-item
label=
"邮箱"
prop=
"email"
>
<el-input
v-model=
"form.email"
placeholder=
"请输入邮箱"
maxlength=
"50"
/>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col
:span=
"12"
>
<el-form-item
v-if=
"form.id === undefined"
label=
"用户名称"
prop=
"username"
>
<el-input
v-model=
"form.username"
placeholder=
"请输入用户名称"
/>
</el-form-item>
</el-col>
<el-col
:span=
"12"
>
<el-form-item
v-if=
"form.id === undefined"
label=
"用户密码"
prop=
"password"
>
<el-input
v-model=
"form.password"
placeholder=
"请输入用户密码"
type=
"password"
show-password
/>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col
:span=
"12"
>
<el-form-item
label=
"用户性别"
>
<el-select
v-model=
"form.sex"
placeholder=
"请选择"
>
<el-option
v-for=
"dict in sexDictDatas"
:key=
"parseInt(dict.value)"
:label=
"dict.label"
:value=
"parseInt(dict.value)"
/>
</el-select>
</el-form-item>
</el-col>
<el-col
:span=
"12"
>
<el-form-item
label=
"岗位"
>
<el-select
v-model=
"form.postIds"
multiple
placeholder=
"请选择"
>
<el-option
<el-option
v-for=
"item in postOptions"
v-for=
"item in postOptions"
:key=
"item.id"
:key=
"item.id"
:label=
"item.name"
:label=
"item.name"
:value=
"(item.id as unknown as number)
"
:value=
"item.id
"
/
>
></el-option
>
</el-select>
</el-select>
</
template
>
</Form>
<!-- 对话框(详情) -->
<Descriptions
v-if=
"actionType === 'detail'"
:schema=
"allSchemas.detailSchema"
:data=
"detailData"
>
<
template
#
deptId=
"{ row }"
>
<el-tag>
{{
dataFormater
(
row
.
deptId
)
}}
</el-tag>
</
template
>
<
template
#
postIds=
"{ row }"
>
<template
v-if=
"row.postIds !== ''"
>
<el-tag
v-for=
"(post, index) in row.postIds"
:key=
"index"
index=
""
>
<template
v-for=
"postObj in postOptions"
>
{{
post
===
postObj
.
id
?
postObj
.
name
:
''
}}
</
template
>
</el-tag>
</template>
<
template
v-else
>
</
template
>
</template>
</Descriptions>
<!-- 操作按钮 -->
<
template
#
footer
>
<!-- 按钮:保存 -->
<XButton
v-if=
"['create', 'update'].includes(actionType)"
type=
"primary"
:title=
"t('action.save')"
:loading=
"loading"
@
click=
"submitForm()"
/>
<!-- 按钮:关闭 -->
<XButton
:loading=
"loading"
:title=
"t('dialog.close')"
@
click=
"dialogVisible = false"
/>
</
template
>
</XModal>
<!-- 分配用户角色 -->
<XModal
v-model=
"roleDialogVisible"
title=
"分配角色"
>
<el-form
:model=
"userRole"
label-width=
"140px"
:inline=
"true"
>
<el-form-item
label=
"用户名称"
>
<el-tag>
{{ userRole.username }}
</el-tag>
</el-form-item>
<el-form-item
label=
"用户昵称"
>
<el-tag>
{{ userRole.nickname }}
</el-tag>
</el-form-item>
</el-form-item>
<el-form-item
label=
"角色"
>
</el-col>
<el-transfer
</el-row>
v-model=
"userRole.roleIds"
<el-row>
:titles=
"['角色列表', '已选择']"
<el-col
:span=
"24"
>
:props=
"{
<el-form-item
label=
"备注"
>
key: 'id',
<el-input
v-model=
"form.remark"
type=
"textarea"
placeholder=
"请输入内容"
></el-input>
label: 'name'
}"
:data=
"roleOptions"
/>
</el-form-item>
</el-form-item>
</el-col>
</el-row>
</el-form>
</el-form>
<!-- 操作按钮 -->
<div
slot=
"footer"
class=
"dialog-footer"
>
<
template
#
footer
>
<el-button
type=
"primary"
@
click=
"submitForm"
>
确 定
</el-button>
<!-- 按钮:保存 -->
<el-button
@
click=
"cancel"
>
取 消
</el-button>
<XButton
type=
"primary"
:title=
"t('action.save')"
:loading=
"loading"
@
click=
"submitRole()"
/>
</div>
<!-- 按钮:关闭 -->
</el-dialog>
<XButton
:title=
"t('dialog.close')"
@
click=
"roleDialogVisible = false"
/>
</
template
>
<!-- 用户导入对话框 -->
</XModal>
<el-dialog
:title=
"upload.title"
:visible
.
sync=
"upload.open"
width=
"400px"
append-to-body
>
<!-- 导入 -->
<XModal
v-model=
"importDialogVisible"
:title=
"importDialogTitle"
>
<el-form
class=
"drawer-multiColumn-form"
label-width=
"150px"
>
<el-form-item
label=
"模板下载 :"
>
<XButton
type=
"primary"
prefix=
"ep:download"
title=
"点击下载"
@
click=
"handleImportTemp()"
/>
</el-form-item>
<el-form-item
label=
"文件上传 :"
>
<el-upload
<el-upload
ref=
"uploadRef"
ref=
"upload"
:action=
"updateUrl + '?updateSupport=' + updateSupport"
:headers=
"uploadHeaders"
:drag=
"true"
:limit=
"1"
:limit=
"1"
:multiple=
"true
"
accept=
".xlsx, .xls
"
:show-file-list=
"true
"
:headers=
"upload.headers
"
:disabled=
"uploadDisabled
"
:action=
"upload.url + '?updateSupport=' + upload.updateSupport
"
:before-upload=
"beforeExcelUpload
"
:disabled=
"upload.isUploading
"
:on-exceed=
"handleExceed
"
:on-progress=
"handleFileUploadProgress
"
:on-success=
"handleFileSuccess"
:on-success=
"handleFileSuccess"
:on-error=
"excelUploadError"
:auto-upload=
"false"
:auto-upload=
"false"
accept=
"application/vnd.ms-excel,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
drag
>
>
<Icon
icon=
"ep:upload-filled"
/
>
<i
class=
"el-icon-upload"
></i
>
<div
class=
"el-upload__text"
>
将文件拖到此处,或
<em>
点击上传
</em></div>
<div
class=
"el-upload__text"
>
将文件拖到此处,或
<em>
点击上传
</em></div>
<
template
#
tip
>
<div
class=
"el-upload__tip text-center"
slot=
"tip"
>
<div
class=
"el-upload__tip"
>
请上传 .xls , .xlsx 标准格式文件
</div>
<div
class=
"el-upload__tip"
slot=
"tip"
>
</
template
>
<el-checkbox
v-model=
"upload.updateSupport"
/>
是否更新已经存在的用户数据
</div>
<span>
仅允许导入xls、xlsx格式文件。
</span>
<el-link
type=
"primary"
:underline=
"false"
style=
"font-size: 12px; vertical-align: baseline"
@
click=
"importTemplate"
>
下载模板
</el-link
>
</div>
</el-upload>
</el-upload>
<div
slot=
"footer"
class=
"dialog-footer"
>
<el-button
type=
"primary"
@
click=
"submitFileForm"
>
确 定
</el-button>
<el-button
@
click=
"upload.open = false"
>
取 消
</el-button>
</div>
</el-dialog>
<!-- 分配角色 -->
<el-dialog
title=
"分配角色"
:visible
.
sync=
"openRole"
width=
"500px"
append-to-body
>
<el-form
:model=
"form"
label-width=
"80px"
>
<el-form-item
label=
"用户名称"
>
<el-input
v-model=
"form.username"
:disabled=
"true"
/>
</el-form-item>
</el-form-item>
<el-form-item
label=
"是否更新已经存在的用户数据:"
>
<el-form-item
label=
"用户昵称"
>
<el-checkbox
v-model=
"updateSupport"
/>
<el-input
v-model=
"form.nickname"
:disabled=
"true"
/>
</el-form-item>
<el-form-item
label=
"角色"
>
<el-select
v-model=
"form.roleIds"
multiple
placeholder=
"请选择"
>
<el-option
v-for=
"item in roleOptions"
:key=
"parseInt(item.id)"
:label=
"item.name"
:value=
"parseInt(item.id)"
></el-option>
</el-select>
</el-form-item>
</el-form-item>
</el-form>
</el-form>
<
template
#
footer
>
<div
slot=
"footer"
class=
"dialog-footer"
>
<!-- 按钮:保存 -->
<el-button
type=
"primary"
@
click=
"submitRole"
>
确 定
</el-button>
<XButton
<el-button
@
click=
"cancelRole"
>
取 消
</el-button>
type=
"warning"
</div>
preIcon=
"ep:upload-filled"
</el-dialog>
:title=
"t('action.save')"
</div>
@
click=
"submitFileForm()"
/>
<!-- 按钮:关闭 -->
<XButton
:title=
"t('dialog.close')"
@
click=
"importDialogVisible = false"
/>
</
template
>
</XModal>
</template>
</template>
<
script
setup
lang=
"ts"
name=
"User"
>
import
type
{
ElTree
,
UploadRawFile
,
UploadInstance
}
from
'element-plus'
<
script
>
import
{
handleTree
,
defaultProps
}
from
'@/utils/tree'
import
download
from
'@/utils/download'
import
{
CommonStatusEnum
}
from
'@/utils/constants'
import
{
getAccessToken
,
getTenantId
}
from
'@/utils/auth'
import
type
{
FormExpose
}
from
'@/components/Form'
import
{
rules
,
allSchemas
}
from
'./user.data'
import
*
as
UserApi
from
'@/api/system/user'
import
{
listSimpleDeptApi
}
from
'@/api/system/dept'
import
{
listSimpleRolesApi
}
from
'@/api/system/role'
import
{
listSimplePostsApi
,
PostVO
}
from
'@/api/system/post'
import
{
import
{
aassignUserRoleApi
,
createUserApi
as
addUser
,
listUserRolesApi
,
updateUserStatusApi
as
changeUserStatus
,
PermissionAssignUserRoleReqVO
deleteUserApi
as
delUser
,
}
from
'@/api/system/permission'
exportUserApi
as
exportUser
,
// TODO: praseStrEmpty(id)
getUserApi
as
getUser
,
importUserTemplateApi
as
importTemplate
,
getUserPageApi
as
listUser
,
resetUserPwdApi
as
resetUserPwd
,
updateUserApi
as
updateUser
}
from
'@/api/system/user'
// TODO: change
import
Treeselect
from
'@riophae/vue-treeselect'
// TODO: change???
import
'@riophae/vue-treeselect/dist/vue-treeselect.css'
const
{
t
}
=
useI18n
()
// 国际化
import
{
listSimpleDeptApi
}
from
'@/api/system/dept'
const
message
=
useMessage
()
// 消息弹窗
import
{
listSimplePostsApi
}
from
'@/api/system/post'
const
queryParams
=
reactive
({
import
{
CommonStatusEnum
}
from
'@/utils/constants'
deptId
:
null
import
{
DICT_TYPE
,
getDictDatas
}
from
'@/utils/dict'
})
import
{
assignUserRole
,
listUserRoles
}
from
'@/api/system/permission'
// ========== 列表相关 ==========
import
{
listSimpleRoles
}
from
'@/api/system/role'
const
tableTitle
=
ref
(
'用户列表'
)
import
{
getBaseHeader
}
from
'@/utils/request'
// 列表相关的变量
const
[
registerTable
,
{
reload
,
deleteData
,
exportList
}]
=
useXTable
({
allSchemas
:
allSchemas
,
params
:
queryParams
,
getListApi
:
UserApi
.
getUserPageApi
,
deleteApi
:
UserApi
.
deleteUserApi
,
exportListApi
:
UserApi
.
exportUserApi
})
// ========== 创建部门树结构 ==========
const
filterText
=
ref
(
''
)
const
deptOptions
=
ref
<
Tree
[]
>
([])
// 树形结构
const
treeRef
=
ref
<
InstanceType
<
typeof
ElTree
>>
()
const
getTree
=
async
()
=>
{
const
res
=
await
listSimpleDeptApi
()
deptOptions
.
value
.
push
(...
handleTree
(
res
))
}
const
filterNode
=
(
value
:
string
,
data
:
Tree
)
=>
{
if
(
!
value
)
return
true
return
data
.
name
.
includes
(
value
)
}
const
handleDeptNodeClick
=
async
(
row
:
{
[
key
:
string
]:
any
})
=>
{
queryParams
.
deptId
=
row
.
id
await
reload
()
}
const
{
push
}
=
useRouter
()
const
handleDeptEdit
=
()
=>
{
push
(
'/system/dept'
)
}
watch
(
filterText
,
(
val
)
=>
{
treeRef
.
value
!
.
filter
(
val
)
})
// ========== CRUD 相关 ==========
const
loading
=
ref
(
false
)
// 遮罩层
const
actionType
=
ref
(
''
)
// 操作按钮的类型
const
dialogVisible
=
ref
(
false
)
// 是否显示弹出层
const
dialogTitle
=
ref
(
'edit'
)
// 弹出层标题
const
formRef
=
ref
<
FormExpose
>
()
// 表单 Ref
const
postOptions
=
ref
<
PostVO
[]
>
([])
//岗位列表
// 获取岗位列表
export
default
{
const
getPostOptions
=
async
()
=>
{
name
:
'User'
,
const
res
=
await
listSimplePostsApi
()
components
:
{
Treeselect
},
postOptions
.
value
.
push
(...
res
)
data
()
{
}
return
{
const
dataFormater
=
(
val
)
=>
{
// 遮罩层
return
deptFormater
(
deptOptions
.
value
,
val
)
loading
:
true
,
}
// 导出遮罩层
//部门回显
exportLoading
:
false
,
const
deptFormater
=
(
ary
,
val
:
any
)
=>
{
// 显示搜索条件
var
o
=
''
showSearch
:
true
,
if
(
ary
&&
val
)
{
// 总条数
for
(
const
v
of
ary
)
{
total
:
0
,
if
(
v
.
id
==
val
)
{
// 用户表格数据
o
=
v
.
name
userList
:
null
,
if
(
o
)
return
o
// 弹出层标题
}
else
if
(
v
.
children
?.
length
)
{
title
:
''
,
o
=
deptFormater
(
v
.
children
,
val
)
// 部门树选项
if
(
o
)
return
o
deptOptions
:
undefined
,
}
// 是否显示弹出层
open
:
false
,
// 部门名称
deptName
:
undefined
,
// 默认密码
initPassword
:
undefined
,
// 性别状态字典
sexOptions
:
[],
// 岗位选项
postOptions
:
[],
// 角色选项
roleOptions
:
[],
// 表单参数
form
:
{},
defaultProps
:
{
children
:
'children'
,
label
:
'name'
},
// 用户导入参数
upload
:
{
// 是否显示弹出层(用户导入)
open
:
false
,
// 弹出层标题(用户导入)
title
:
''
,
// 是否禁用上传
isUploading
:
false
,
// 是否更新已经存在的用户数据
updateSupport
:
0
,
// 设置上传的请求头部
headers
:
getBaseHeader
(),
// 上传的地址
url
:
process
.
env
.
VUE_APP_BASE_API
+
'/admin-api/system/user/import'
},
// 查询参数
queryParams
:
{
pageNo
:
1
,
pageSize
:
10
,
username
:
undefined
,
mobile
:
undefined
,
status
:
undefined
,
deptId
:
undefined
,
createTime
:
[]
},
// 列信息
columns
:
[
{
key
:
0
,
label
:
`用户编号`
,
visible
:
true
},
{
key
:
1
,
label
:
`用户名称`
,
visible
:
true
},
{
key
:
2
,
label
:
`用户昵称`
,
visible
:
true
},
{
key
:
3
,
label
:
`部门`
,
visible
:
true
},
{
key
:
4
,
label
:
`手机号码`
,
visible
:
true
},
{
key
:
5
,
label
:
`状态`
,
visible
:
true
},
{
key
:
6
,
label
:
`创建时间`
,
visible
:
true
}
],
// 表单校验
rules
:
{
username
:
[{
required
:
true
,
message
:
'用户名称不能为空'
,
trigger
:
'blur'
}],
nickname
:
[{
required
:
true
,
message
:
'用户昵称不能为空'
,
trigger
:
'blur'
}],
password
:
[{
required
:
true
,
message
:
'用户密码不能为空'
,
trigger
:
'blur'
}],
email
:
[
{
type
:
'email'
,
message
:
"'请输入正确的邮箱地址"
,
trigger
:
[
'blur'
,
'change'
]
}
}
return
o
],
}
else
{
mobile
:
[
return
val
{
pattern
:
/^
(?:(?:\+
|00
)
86
)?
1
(?:
3
[\d]
|4
[
5-79
]
|5
[
0-35-9
]
|6
[
5-7
]
|7
[
0-8
]
|8
[\d]
|9
[
189
])\d{8}
$/
,
message
:
'请输入正确的手机号码'
,
trigger
:
'blur'
}
}
}
]
},
// 设置标题
// 是否显示弹出层(角色权限)
const
setDialogTile
=
async
(
type
:
string
)
=>
{
openRole
:
false
,
dialogTitle
.
value
=
t
(
'action.'
+
type
)
actionType
.
value
=
type
dialogVisible
.
value
=
true
}
// 新增操作
// 枚举
const
handleCreate
=
async
()
=>
{
SysCommonStatusEnum
:
CommonStatusEnum
,
setDialogTile
(
'create'
)
// 数据字典
// 重置表单
statusDictDatas
:
getDictDatas
(
DICT_TYPE
.
COMMON_STATUS
),
await
nextTick
()
sexDictDatas
:
getDictDatas
(
DICT_TYPE
.
SYSTEM_USER_SEX
)
if
(
allSchemas
.
formSchema
[
0
].
field
!==
'username'
)
{
}
unref
(
formRef
)?.
addSchema
(
{
field
:
'username'
,
label
:
'用户账号'
,
component
:
'Input'
},
},
0
watch
:
{
)
// 根据名称筛选部门树
unref
(
formRef
)?.
addSchema
(
deptName
(
val
)
{
{
this
.
$refs
.
tree
.
filter
(
val
)
field
:
'password'
,
}
label
:
'用户密码'
,
},
component
:
'InputPassword'
created
()
{
this
.
getList
()
this
.
getTreeselect
()
// this.getConfigKey("sys.user.init-password").then(response => {
// this.initPassword = response.msg;
// });
},
},
1
methods
:
{
)
// 更多操作
handleCommand
(
command
,
index
,
row
)
{
switch
(
command
)
{
case
'handleUpdate'
:
this
.
handleUpdate
(
row
)
//修改客户信息
break
case
'handleDelete'
:
this
.
handleDelete
(
row
)
//红号变更
break
case
'handleResetPwd'
:
this
.
handleResetPwd
(
row
)
break
case
'handleRole'
:
this
.
handleRole
(
row
)
break
default
:
break
}
}
}
},
/** 查询用户列表 */
// 修改操作
getList
()
{
const
handleUpdate
=
async
(
rowId
:
number
)
=>
{
this
.
loading
=
true
setDialogTile
(
'update'
)
listUser
(
this
.
queryParams
).
then
((
response
)
=>
{
await
nextTick
()
this
.
userList
=
response
.
data
.
list
unref
(
formRef
)?.
delSchema
(
'username'
)
this
.
total
=
response
.
data
.
total
unref
(
formRef
)?.
delSchema
(
'password'
)
this
.
loading
=
false
// 设置数据
})
const
res
=
await
UserApi
.
getUserApi
(
rowId
)
},
unref
(
formRef
)?.
setValues
(
res
)
/** 查询部门下拉树结构 + 岗位下拉 */
}
getTreeselect
()
{
const
detailData
=
ref
()
listSimpleDeptApi
().
then
((
response
)
=>
{
// 处理 deptOptions 参数
// 详情操作
this
.
deptOptions
=
[]
const
handleDetail
=
async
(
rowId
:
number
)
=>
{
this
.
deptOptions
.
push
(...
this
.
handleTree
(
response
.
data
,
'id'
))
// 设置数据
})
const
res
=
await
UserApi
.
getUserApi
(
rowId
)
listSimplePostsApi
().
then
((
response
)
=>
{
detailData
.
value
=
res
// 处理 postOptions 参数
await
setDialogTile
(
'detail'
)
this
.
postOptions
=
[]
}
this
.
postOptions
.
push
(...
response
.
data
)
})
// 提交按钮
},
const
submitForm
=
async
()
=>
{
// 筛选节点
const
elForm
=
unref
(
formRef
)?.
getElFormRef
()
filterNode
(
value
,
data
)
{
if
(
!
elForm
)
return
if
(
!
value
)
return
true
elForm
.
validate
(
async
(
valid
)
=>
{
return
data
.
name
.
indexOf
(
value
)
!==
-
1
},
// 节点单击事件
handleNodeClick
(
data
)
{
this
.
queryParams
.
deptId
=
data
.
id
this
.
getList
()
},
// 用户状态修改
handleStatusChange
(
row
)
{
let
text
=
row
.
status
===
CommonStatusEnum
.
ENABLE
?
'启用'
:
'停用'
this
.
$modal
.
confirm
(
'确认要"'
+
text
+
'""'
+
row
.
username
+
'"用户吗?'
)
.
then
(
function
()
{
return
changeUserStatus
(
row
.
id
,
row
.
status
)
})
.
then
(()
=>
{
this
.
$modal
.
msgSuccess
(
text
+
'成功'
)
})
.
catch
(
function
()
{
row
.
status
=
row
.
status
===
CommonStatusEnum
.
ENABLE
?
CommonStatusEnum
.
DISABLE
:
CommonStatusEnum
.
ENABLE
})
},
// 取消按钮
cancel
()
{
this
.
open
=
false
this
.
reset
()
},
// 取消按钮(角色权限)
cancelRole
()
{
this
.
openRole
=
false
this
.
reset
()
},
// 表单重置
reset
()
{
this
.
form
=
{
id
:
undefined
,
deptId
:
undefined
,
username
:
undefined
,
nickname
:
undefined
,
password
:
undefined
,
mobile
:
undefined
,
email
:
undefined
,
sex
:
undefined
,
status
:
'0'
,
remark
:
undefined
,
postIds
:
[],
roleIds
:
[]
}
this
.
resetForm
(
'form'
)
},
/** 搜索按钮操作 */
handleQuery
()
{
this
.
queryParams
.
pageNo
=
1
this
.
getList
()
},
/** 重置按钮操作 */
resetQuery
()
{
this
.
resetForm
(
'queryForm'
)
this
.
handleQuery
()
},
/** 新增按钮操作 */
handleAdd
()
{
this
.
reset
()
// 获得下拉数据
this
.
getTreeselect
()
// 打开表单,并设置初始化
this
.
open
=
true
this
.
title
=
'添加用户'
this
.
form
.
password
=
this
.
initPassword
},
/** 修改按钮操作 */
handleUpdate
(
row
)
{
this
.
reset
()
this
.
getTreeselect
()
const
id
=
row
.
id
getUser
(
id
).
then
((
response
)
=>
{
this
.
form
=
response
.
data
this
.
open
=
true
this
.
title
=
'修改用户'
this
.
form
.
password
=
''
})
},
/** 重置密码按钮操作 */
handleResetPwd
(
row
)
{
this
.
$prompt
(
'请输入"'
+
row
.
username
+
'"的新密码'
,
'提示'
,
{
confirmButtonText
:
'确定'
,
cancelButtonText
:
'取消'
})
.
then
(({
value
})
=>
{
resetUserPwd
(
row
.
id
,
value
).
then
((
response
)
=>
{
this
.
$modal
.
msgSuccess
(
'修改成功,新密码是:'
+
value
)
})
})
.
catch
(()
=>
{})
},
/** 分配用户角色操作 */
handleRole
(
row
)
{
this
.
reset
()
const
id
=
row
.
id
// 处理了 form 的用户 username 和 nickname 的展示
this
.
form
.
id
=
id
this
.
form
.
username
=
row
.
username
this
.
form
.
nickname
=
row
.
nickname
// 打开弹窗
this
.
openRole
=
true
// 获得角色列表
listSimpleRoles
().
then
((
response
)
=>
{
// 处理 roleOptions 参数
this
.
roleOptions
=
[]
this
.
roleOptions
.
push
(...
response
.
data
)
})
// 获得角色拥有的菜单集合
listUserRoles
(
id
).
then
((
response
)
=>
{
// 设置选中
this
.
form
.
roleIds
=
response
.
data
})
},
/** 提交按钮 */
submitForm
:
function
()
{
this
.
$refs
[
'form'
].
validate
((
valid
)
=>
{
if
(
valid
)
{
if
(
valid
)
{
// 提交请求
if
(
this
.
form
.
id
!==
undefined
)
{
try
{
updateUser
(
this
.
form
).
then
((
response
)
=>
{
const
data
=
unref
(
formRef
)?.
formModel
as
UserApi
.
UserVO
this
.
$modal
.
msgSuccess
(
'修改成功'
)
if
(
actionType
.
value
===
'create'
)
{
this
.
open
=
false
loading
.
value
=
true
this
.
getList
()
await
UserApi
.
createUserApi
(
data
)
})
message
.
success
(
t
(
'common.createSuccess'
))
}
else
{
}
else
{
loading
.
value
=
true
addUser
(
this
.
form
).
then
((
response
)
=>
{
await
UserApi
.
updateUserApi
(
data
)
this
.
$modal
.
msgSuccess
(
'新增成功'
)
message
.
success
(
t
(
'common.updateSuccess'
))
this
.
open
=
false
}
this
.
getList
()
dialogVisible
.
value
=
false
})
}
finally
{
// unref(formRef)?.setSchema(allSchemas.formSchema)
// 刷新列表
await
reload
()
loading
.
value
=
false
}
}
}
}
})
})
}
},
// 改变用户状态操作
/** 提交按钮(角色权限) */
const
handleStatusChange
=
async
(
row
:
UserApi
.
UserVO
)
=>
{
submitRole
:
function
()
{
const
text
=
row
.
status
===
CommonStatusEnum
.
ENABLE
?
'启用'
:
'停用'
if
(
this
.
form
.
id
!==
undefined
)
{
message
assignUserRole
({
.
confirm
(
'确认要"'
+
text
+
'""'
+
row
.
username
+
'"用户吗?'
,
t
(
'common.reminder'
))
userId
:
this
.
form
.
id
,
.
then
(
async
()
=>
{
roleIds
:
this
.
form
.
roleIds
row
.
status
=
}).
then
((
response
)
=>
{
row
.
status
===
CommonStatusEnum
.
ENABLE
?
CommonStatusEnum
.
ENABLE
:
CommonStatusEnum
.
DISABLE
this
.
$modal
.
msgSuccess
(
'分配角色成功'
)
await
UserApi
.
updateUserStatusApi
(
row
.
id
,
row
.
status
)
this
.
openRole
=
false
message
.
success
(
text
+
'成功'
)
this
.
getList
()
// 刷新列表
await
reload
()
})
})
.
catch
(()
=>
{
}
row
.
status
=
},
row
.
status
===
CommonStatusEnum
.
ENABLE
?
CommonStatusEnum
.
DISABLE
:
CommonStatusEnum
.
ENABLE
/** 删除按钮操作 */
handleDelete
(
row
)
{
const
ids
=
row
.
id
||
this
.
ids
this
.
$modal
.
confirm
(
'是否确认删除用户编号为"'
+
ids
+
'"的数据项?'
)
.
then
(
function
()
{
return
delUser
(
ids
)
})
})
}
.
then
(()
=>
{
// 重置密码
this
.
getList
()
const
handleResetPwd
=
(
row
:
UserApi
.
UserVO
)
=>
{
this
.
$modal
.
msgSuccess
(
'删除成功'
)
message
.
prompt
(
'请输入"'
+
row
.
username
+
'"的新密码'
,
t
(
'common.reminder'
)).
then
(({
value
})
=>
{
UserApi
.
resetUserPwdApi
(
row
.
id
,
value
).
then
(()
=>
{
message
.
success
(
'修改成功,新密码是:'
+
value
)
})
})
.
catch
(()
=>
{})
},
/** 导出按钮操作 */
handleExport
()
{
this
.
$modal
.
confirm
(
'是否确认导出所有用户数据项?'
)
.
then
(()
=>
{
// 处理查询参数
let
params
=
{
...
this
.
queryParams
}
params
.
pageNo
=
undefined
params
.
pageSize
=
undefined
this
.
exportLoading
=
true
return
exportUser
(
params
)
})
})
}
.
then
((
response
)
=>
{
// 分配角色
this
.
$download
.
excel
(
response
,
'用户数据.xls'
)
const
roleDialogVisible
=
ref
(
false
)
this
.
exportLoading
=
false
const
roleOptions
=
ref
()
const
userRole
=
reactive
({
id
:
0
,
username
:
''
,
nickname
:
''
,
roleIds
:
[]
})
const
handleRole
=
async
(
row
:
UserApi
.
UserVO
)
=>
{
userRole
.
id
=
row
.
id
userRole
.
username
=
row
.
username
userRole
.
nickname
=
row
.
nickname
// 获得角色拥有的权限集合
const
roles
=
await
listUserRolesApi
(
row
.
id
)
userRole
.
roleIds
=
roles
// 获取角色列表
const
roleOpt
=
await
listSimpleRolesApi
()
roleOptions
.
value
=
roleOpt
roleDialogVisible
.
value
=
true
}
// 提交
const
submitRole
=
async
()
=>
{
const
data
=
ref
<
PermissionAssignUserRoleReqVO
>
({
userId
:
userRole
.
id
,
roleIds
:
userRole
.
roleIds
})
})
await
aassignUserRoleApi
(
data
.
value
)
.
catch
(()
=>
{})
message
.
success
(
t
(
'common.updateSuccess'
))
},
roleDialogVisible
.
value
=
false
/** 导入按钮操作 */
}
handleImport
()
{
// ========== 导入相关 ==========
this
.
upload
.
title
=
'用户导入'
// TODO @星语:这个要不要把导入用户,封装成一个小组件?可选哈
this
.
upload
.
open
=
true
const
importDialogVisible
=
ref
(
false
)
},
const
uploadDisabled
=
ref
(
false
)
/** 下载模板操作 */
const
importDialogTitle
=
ref
(
'用户导入'
)
importTemplate
()
{
const
updateSupport
=
ref
(
0
)
importTemplate
().
then
((
response
)
=>
{
let
updateUrl
=
import
.
meta
.
env
.
VITE_BASE_URL
+
import
.
meta
.
env
.
VITE_API_URL
+
'/system/user/import'
this
.
$download
.
excel
(
response
,
'用户导入模板.xls'
)
const
uploadHeaders
=
ref
()
})
// 下载导入模版
},
const
handleImportTemp
=
async
()
=>
{
// 文件上传中处理
const
res
=
await
UserApi
.
importUserTemplateApi
()
handleFileUploadProgress
(
event
,
file
,
fileList
)
{
download
.
excel
(
res
,
'用户导入模版.xls'
)
this
.
upload
.
isUploading
=
true
}
},
// 文件上传之前判断
// 文件上传成功处理
const
beforeExcelUpload
=
(
file
:
UploadRawFile
)
=>
{
handleFileSuccess
(
response
,
file
,
fileList
)
{
const
isExcel
=
file
.
type
===
'application/vnd.ms-excel'
||
file
.
type
===
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
const
isLt5M
=
file
.
size
/
1024
/
1024
<
5
if
(
!
isExcel
)
message
.
error
(
'上传文件只能是 xls / xlsx 格式!'
)
if
(
!
isLt5M
)
message
.
error
(
'上传文件大小不能超过 5MB!'
)
return
isExcel
&&
isLt5M
}
// 文件上传
const
uploadRef
=
ref
<
UploadInstance
>
()
const
submitFileForm
=
()
=>
{
uploadHeaders
.
value
=
{
Authorization
:
'Bearer '
+
getAccessToken
(),
'tenant-id'
:
getTenantId
()
}
uploadDisabled
.
value
=
true
uploadRef
.
value
!
.
submit
()
}
// 文件上传成功
const
handleFileSuccess
=
async
(
response
:
any
):
Promise
<
void
>
=>
{
if
(
response
.
code
!==
0
)
{
if
(
response
.
code
!==
0
)
{
message
.
e
rror
(
response
.
msg
)
this
.
$modal
.
msgE
rror
(
response
.
msg
)
return
return
}
}
importDialogVisible
.
value
=
false
this
.
upload
.
open
=
false
uploadDisabled
.
value
=
false
this
.
upload
.
isUploading
=
false
const
data
=
response
.
data
this
.
$refs
.
upload
.
clearFiles
()
let
text
=
'上传成功数量:'
+
data
.
createUsernames
.
length
+
';'
// 拼接提示语
for
(
let
username
of
data
.
createUsernames
)
{
let
data
=
response
.
data
text
+=
'
<
' + username + '
>
'
let
text
=
'创建成功数量:'
+
data
.
createUsernames
.
length
for
(
const
username
of
data
.
createUsernames
)
{
text
+=
'
<
br
/>&
nbsp
;
&
nbsp
;
&
nbsp
;
&
nbsp
;
' + username
}
}
text += '
更新成功数量:
' + data.updateUsernames.length + '
;
'
text += '
<
br
/>
更新成功数量:
' + data.updateUsernames.length
for (const username of data.updateUsernames) {
for (const username of data.updateUsernames) {
text += '
<
' + username + '
>
'
text += '
<
br
/>&
nbsp
;
&
nbsp
;
&
nbsp
;
&
nbsp
;
' + username
}
}
text += '
更新失败数量:
' + Object.keys(data.failureUsernames).length + '
;
'
text += '
<
br
/>
更新失败数量:
' + Object.keys(data.failureUsernames).length
for (const username in data.failureUsernames) {
for (const username in data.failureUsernames) {
text += '
<
' + username + '
:
' + data.failureUsernames[username] + '
>
'
text += '
<
br
/>&
nbsp
;
&
nbsp
;
&
nbsp
;
&
nbsp
;
' + username + '
:
' + data.failureUsernames[username]
}
this.$alert(text, '
导入结果'
,
{
dangerouslyUseHTMLString
:
true
})
this
.
getList
()
},
// 提交上传文件
submitFileForm
()
{
this
.
$refs
.
upload
.
submit
()
},
// 格式化部门的下拉框
normalizer
(
node
)
{
return
{
id
:
node
.
id
,
label
:
node
.
name
,
children
:
node
.
children
}
}
}
}
message.alert(text)
await reload()
}
// 文件数超出提示
const handleExceed = (): void => {
message.error('
最多只能上传一个文件!
')
}
// 上传错误提示
const excelUploadError = (): void => {
message.error('
导入数据失败,请您重新上传!'
)
}
}
// ========== 初始化 ==========
onMounted
(
async
()
=>
{
await
getPostOptions
()
await
getTree
()
})
</
script
>
</
script
>
<
style
scoped
>
.user
{
height
:
780px
;
max-height
:
800px
;
}
.card-header
{
display
:
flex
;
justify-content
:
space-between
;
align-items
:
center
;
}
</
style
>
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment