419 lines
13 KiB
Vue
419 lines
13 KiB
Vue
<template>
|
||
<GiPageLayout>
|
||
<template #left>
|
||
<DeptTree @node-click="handleSelectDept" />
|
||
</template>
|
||
<GiTable
|
||
row-key="userId"
|
||
:data="dataList"
|
||
:columns="columns"
|
||
:loading="loading"
|
||
:scroll="{ x: '100%', y: '100%', minWidth: 1500 }"
|
||
:pagination="pagination"
|
||
:disabled-tools="['size']"
|
||
:disabled-column-keys="['name']"
|
||
@page-change="handlePageChange"
|
||
@page-size-change="handlePageSizeChange"
|
||
@refresh="search"
|
||
>
|
||
<template #top>
|
||
<GiForm v-model="queryForm" search :columns="queryFormColumns" size="medium" @search="search" @reset="reset"></GiForm>
|
||
</template>
|
||
<template #toolbar-left>
|
||
<a-button v-permission="['system:user:create']" type="primary" @click="onAdd">
|
||
<template #icon><icon-plus /></template>
|
||
<template #default>新增</template>
|
||
</a-button>
|
||
<a-button v-permission="['system:user:import']" @click="onImport">
|
||
<template #icon><icon-upload /></template>
|
||
<template #default>导入</template>
|
||
</a-button>
|
||
</template>
|
||
<template #toolbar-right>
|
||
<a-button v-permission="['system:user:export']" @click="onExport">
|
||
<template #icon><icon-download /></template>
|
||
<template #default>导出</template>
|
||
</a-button>
|
||
</template>
|
||
<template #name="{ record }">
|
||
<GiCellAvatar :avatar="record.avatar" :name="record.name" />
|
||
</template>
|
||
<template #gender="{ record }">
|
||
<GiCellGender :gender="record.gender" />
|
||
</template>
|
||
<template #roleIds="{ record }">
|
||
<GiCellTags :data="record.roleIds" />
|
||
</template>
|
||
<template #status="{ record }">
|
||
<GiCellStatus :status="record.status" />
|
||
</template>
|
||
<template #userStatus="{ record }">
|
||
<a-tag :color="record.userStatus === 'ENABLED' ? 'green' : 'red'" size="small">
|
||
{{ record.userStatusLabel || record.userStatus }}
|
||
</a-tag>
|
||
</template>
|
||
<template #userType="{ record }">
|
||
<a-tag color="blue" size="small">
|
||
{{ record.userTypeLabel || record.userType }}
|
||
</a-tag>
|
||
</template>
|
||
<template #action="{ record }">
|
||
<a-space>
|
||
<a-link v-permission="['system:user:get']" title="详情" @click="onDetail(record)">详情</a-link>
|
||
<a-link v-permission="['system:user:update']" title="修改" @click="onUpdate(record)">修改</a-link>
|
||
<a-link
|
||
v-permission="['system:user:delete']"
|
||
status="danger"
|
||
:title="'删除'"
|
||
@click="onDelete(record)"
|
||
>
|
||
删除
|
||
</a-link>
|
||
<a-dropdown>
|
||
<a-button v-if="has.hasPermOr(['system:user:resetPwd', 'system:user:updateRole'])" type="text" size="mini" title="更多">
|
||
<template #icon>
|
||
<icon-more :size="16" />
|
||
</template>
|
||
</a-button>
|
||
<template #content>
|
||
<a-doption v-permission="['system:user:resetPwd']" title="重置密码" @click="onResetPwd(record)">重置密码</a-doption>
|
||
<a-doption v-permission="['system:user:updateRole']" title="分配角色" @click="onUpdateRole(record)">分配角色</a-doption>
|
||
</template>
|
||
</a-dropdown>
|
||
</a-space>
|
||
</template>
|
||
</GiTable>
|
||
|
||
<UserAddDrawer ref="UserAddDrawerRef" @save-success="search" />
|
||
<UserImportDrawer ref="UserImportDrawerRef" @save-success="search" />
|
||
<UserDetailDrawer ref="UserDetailDrawerRef" />
|
||
<UserResetPwdModal ref="UserResetPwdModalRef" />
|
||
<UserUpdateRoleModal ref="UserUpdateRoleModalRef" @save-success="search" />
|
||
</GiPageLayout>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
import type { TableInstance } from '@arco-design/web-vue'
|
||
import { Modal, Message } from '@arco-design/web-vue'
|
||
import DeptTree from './dept/index.vue'
|
||
import UserAddDrawer from './UserAddDrawer.vue'
|
||
import UserImportDrawer from './UserImportDrawer.vue'
|
||
import UserDetailDrawer from './UserDetailDrawer.vue'
|
||
import UserResetPwdModal from './UserResetPwdModal.vue'
|
||
import UserUpdateRoleModal from './UserUpdateRoleModal.vue'
|
||
import {
|
||
deleteUserNew,
|
||
listUserNew,
|
||
pageUserNew
|
||
} from '@/apis/system/user-new'
|
||
import { exportUser } from '@/apis/system/user'
|
||
import type { UserNewResp, UserNewPageQuery, UserNewQuery } from '@/apis/system/type'
|
||
import { DisEnableStatusList } from '@/constant/common'
|
||
import { useDownload, useResetReactive, useTable } from '@/hooks'
|
||
import { isMobile } from '@/utils'
|
||
import has from '@/utils/has'
|
||
import type { ColumnItem } from '@/components/GiForm'
|
||
import { onMounted } from 'vue'
|
||
|
||
defineOptions({ name: 'SystemUser' })
|
||
|
||
const [queryForm, resetForm] = useResetReactive({
|
||
account: undefined,
|
||
name: undefined,
|
||
userStatus: undefined,
|
||
})
|
||
const queryFormColumns: ColumnItem[] = reactive([
|
||
{
|
||
type: 'input',
|
||
label: '用户名',
|
||
field: 'account',
|
||
span: { xs: 24, sm: 8, xxl: 8 },
|
||
props: {
|
||
placeholder: '账号/姓名/手机号',
|
||
},
|
||
},
|
||
{
|
||
type: 'input',
|
||
label: '姓名',
|
||
field: 'name',
|
||
span: { xs: 24, sm: 8, xxl: 8 },
|
||
props: {
|
||
placeholder: '请输入姓名',
|
||
},
|
||
},
|
||
{
|
||
type: 'select',
|
||
label: '在职状态',
|
||
field: 'userStatus',
|
||
span: { xs: 24, sm: 8, xxl: 8 },
|
||
props: {
|
||
options: [
|
||
{ label: '在职', value: 'ENABLED' },
|
||
{ label: '离职', value: 'DISABLED' }
|
||
],
|
||
placeholder: '请选择在职状态',
|
||
},
|
||
},
|
||
])
|
||
|
||
// 保存所有用户数据和筛选后的用户数据
|
||
const allUsers = ref<UserNewResp[]>([])
|
||
const filteredUsers = ref<UserNewResp[]>([])
|
||
const loading = ref(false)
|
||
// 当前选中的部门名称
|
||
const selectedDeptName = ref<string>('')
|
||
|
||
// 分页配置
|
||
const pagination = reactive({
|
||
current: 1,
|
||
pageSize: 10,
|
||
total: 0,
|
||
showTotal: true,
|
||
showJumper: true,
|
||
showPageSize: true,
|
||
})
|
||
|
||
// 获取所有用户数据
|
||
const fetchAllUsers = async () => {
|
||
try {
|
||
loading.value = true
|
||
// 直接使用 /user/list 接口获取所有用户
|
||
const { data } = await listUserNew({
|
||
account: queryForm.account,
|
||
name: queryForm.name,
|
||
userStatus: queryForm.userStatus,
|
||
sort: undefined
|
||
} as UserNewQuery)
|
||
console.log(data)
|
||
allUsers.value = data || []
|
||
|
||
// 根据当前筛选条件过滤用户
|
||
filterUsersByDept()
|
||
} catch (error) {
|
||
console.error('获取用户列表失败:', error)
|
||
} finally {
|
||
loading.value = false
|
||
}
|
||
}
|
||
|
||
// 根据部门名称筛选用户
|
||
const filterUsersByDept = () => {
|
||
if (!selectedDeptName.value) {
|
||
// 没有选择部门,显示所有用户
|
||
filteredUsers.value = [...allUsers.value]
|
||
} else {
|
||
// 有部门名称,筛选该部门的用户
|
||
filteredUsers.value = allUsers.value.filter(user => user.deptName === selectedDeptName.value)
|
||
}
|
||
|
||
// 更新分页总数
|
||
pagination.total = filteredUsers.value.length
|
||
}
|
||
|
||
// 当前页数据
|
||
const dataList = computed(() => {
|
||
const start = (pagination.current - 1) * pagination.pageSize
|
||
const end = start + pagination.pageSize
|
||
return filteredUsers.value.slice(start, end)
|
||
})
|
||
|
||
// 处理分页变化
|
||
const handlePageChange = (current: number) => {
|
||
pagination.current = current
|
||
}
|
||
|
||
// 处理每页条数变化
|
||
const handlePageSizeChange = (pageSize: number) => {
|
||
pagination.pageSize = pageSize
|
||
pagination.current = 1
|
||
}
|
||
|
||
// 重置
|
||
const reset = () => {
|
||
resetForm()
|
||
fetchAllUsers()
|
||
}
|
||
|
||
// 搜索
|
||
const search = () => {
|
||
pagination.current = 1
|
||
fetchAllUsers()
|
||
}
|
||
|
||
// 删除
|
||
const handleDelete = (callback: () => Promise<any>, options: { content?: string; showModal?: boolean } = {}) => {
|
||
const { content, showModal = false } = options
|
||
const doDelete = async () => {
|
||
loading.value = true
|
||
try {
|
||
await callback()
|
||
// 删除成功后重新获取数据
|
||
fetchAllUsers()
|
||
Message.success('删除成功')
|
||
return true
|
||
} catch (error) {
|
||
console.error('删除失败:', error)
|
||
Message.error('删除失败')
|
||
return false
|
||
} finally {
|
||
loading.value = false
|
||
}
|
||
}
|
||
|
||
if (showModal) {
|
||
Modal.confirm({
|
||
title: '确认删除',
|
||
content: content || '确定要删除此记录吗?',
|
||
okText: '确认',
|
||
cancelText: '取消',
|
||
onOk: () => doDelete()
|
||
})
|
||
return
|
||
}
|
||
|
||
return doDelete()
|
||
}
|
||
|
||
// 删除用户
|
||
const onDelete = (record: UserNewResp) => {
|
||
if (!record || !record.userId) {
|
||
return Message.warning('用户ID不存在,无法删除')
|
||
}
|
||
|
||
return handleDelete(
|
||
() => deleteUserNew(record.userId),
|
||
{
|
||
content: `是否确定删除用户「${record.name || ''}(${record.account || ''})」?`,
|
||
showModal: true
|
||
}
|
||
)
|
||
}
|
||
|
||
// 导出
|
||
const onExport = () => {
|
||
useDownload(() => exportUser({...queryForm, sort: undefined}))
|
||
}
|
||
|
||
const columns: TableInstance['columns'] = [
|
||
{
|
||
title: '序号',
|
||
width: 66,
|
||
align: 'center',
|
||
render: ({ rowIndex }) => h('span', {}, rowIndex + 1 + (pagination.current - 1) * pagination.pageSize),
|
||
fixed: !isMobile() ? 'left' : undefined,
|
||
},
|
||
{
|
||
title: '姓名',
|
||
dataIndex: 'name',
|
||
slotName: 'name',
|
||
minWidth: 140,
|
||
ellipsis: true,
|
||
tooltip: true,
|
||
fixed: !isMobile() ? 'left' : undefined,
|
||
},
|
||
{ title: '账号', dataIndex: 'account', minWidth: 140, ellipsis: true, tooltip: true },
|
||
{ title: '员工编码', dataIndex: 'userCode', minWidth: 120, ellipsis: true, tooltip: true },
|
||
{ title: '性别', dataIndex: 'gender', slotName: 'gender', align: 'center', width: 80 },
|
||
{ title: '手机号', dataIndex: 'mobile', minWidth: 170, ellipsis: true, tooltip: true },
|
||
{ title: '所属部门', dataIndex: 'deptName', minWidth: 180, ellipsis: true, tooltip: true },
|
||
{ title: '学历', dataIndex: 'educationLabel', width: 100, ellipsis: true, tooltip: true, show: false },
|
||
{ title: '专业', dataIndex: 'majorField', width: 120, ellipsis: true, tooltip: true, show: false },
|
||
{ title: '在职状态', dataIndex: 'userStatus', slotName: 'userStatus', align: 'center', width: 100 },
|
||
{ title: '员工性质', dataIndex: 'userType', slotName: 'userType', align: 'center', width: 100 },
|
||
{ title: '角色', dataIndex: 'roleName', slotName: 'roleName', minWidth: 185 },
|
||
{ title: '邮箱', dataIndex: 'email', slotName: 'email', minWidth: 170, ellipsis: true, tooltip: true },
|
||
{ title: '入职日期', dataIndex: 'hiredate', width: 120, ellipsis: true, tooltip: true },
|
||
{ title: '出生日期', dataIndex: 'birthdate', width: 120, ellipsis: true, tooltip: true, show: false },
|
||
{ title: '工作方向', dataIndex: 'workField', width: 120, ellipsis: true, tooltip: true, show: false },
|
||
{ title: '身份证', dataIndex: 'identityCard', width: 180, ellipsis: true, tooltip: true, show: false },
|
||
{
|
||
title: '操作',
|
||
dataIndex: 'action',
|
||
slotName: 'action',
|
||
width: 190,
|
||
align: 'center',
|
||
fixed: !isMobile() ? 'right' : undefined,
|
||
show: has.hasPermOr([
|
||
'system:user:get',
|
||
'system:user:update',
|
||
'system:user:delete',
|
||
'system:user:resetPwd',
|
||
'system:user:updateRole',
|
||
]),
|
||
},
|
||
]
|
||
|
||
// 根据选中部门查询
|
||
const handleSelectDept = (keys: Array<any>, node?: any) => {
|
||
// 如果选择"all",则设置部门名称为空字符串,查询全部
|
||
if (keys.length === 1 && keys[0] === 'all') {
|
||
selectedDeptName.value = ''
|
||
} else if (node && node.title) {
|
||
// 设置选中的部门名称
|
||
selectedDeptName.value = node.title
|
||
} else {
|
||
selectedDeptName.value = ''
|
||
}
|
||
|
||
// 仅在本地过滤数据,不重新请求API
|
||
filterUsersByDept()
|
||
// 重置分页到第一页
|
||
pagination.current = 1
|
||
}
|
||
|
||
const UserImportDrawerRef = ref<InstanceType<typeof UserImportDrawer>>()
|
||
// 导入
|
||
const onImport = () => {
|
||
UserImportDrawerRef.value?.onOpen()
|
||
}
|
||
|
||
const UserAddDrawerRef = ref<InstanceType<typeof UserAddDrawer>>()
|
||
// 新增
|
||
const onAdd = () => {
|
||
UserAddDrawerRef.value?.onAdd()
|
||
}
|
||
|
||
// 修改
|
||
const onUpdate = (record: UserNewResp) => {
|
||
UserAddDrawerRef.value?.onUpdate(record.userId)
|
||
}
|
||
|
||
const UserDetailDrawerRef = ref<InstanceType<typeof UserDetailDrawer>>()
|
||
// 详情
|
||
const onDetail = (record: UserNewResp) => {
|
||
UserDetailDrawerRef.value?.onOpen(record.userId)
|
||
}
|
||
|
||
const UserResetPwdModalRef = ref<InstanceType<typeof UserResetPwdModal>>()
|
||
// 重置密码
|
||
const onResetPwd = (record: UserNewResp) => {
|
||
UserResetPwdModalRef.value?.onOpen(record.userId)
|
||
}
|
||
|
||
const UserUpdateRoleModalRef = ref<InstanceType<typeof UserUpdateRoleModal>>()
|
||
// 分配角色
|
||
const onUpdateRole = (record: UserNewResp) => {
|
||
UserUpdateRoleModalRef.value?.onOpen(record.userId)
|
||
}
|
||
|
||
// 声明是否首次加载,首次加载时展示所有用户
|
||
const isFirstLoad = ref(true)
|
||
|
||
// 初始加载
|
||
onMounted(() => {
|
||
// 初始加载所有用户数据
|
||
fetchAllUsers()
|
||
})
|
||
</script>
|
||
|
||
<style scoped lang="scss">
|
||
.page_header {
|
||
flex: 0 0 auto;
|
||
}
|
||
|
||
.page_content {
|
||
flex: 1;
|
||
overflow: auto;
|
||
}
|
||
</style>
|