wangna0328 2025-07-29 20:16:19 +08:00
commit 1feb4832c5
12 changed files with 337 additions and 77 deletions

View File

@ -4,6 +4,7 @@ import http from '@/utils/http'
export type * from './type' export type * from './type'
const BASE_URL = '/system/role' const BASE_URL = '/system/role'
const BASE_URL_NEW = '/role'
/** @desc 查询角色列表(已废弃) */ /** @desc 查询角色列表(已废弃) */
export function listRole(query: T.RoleQuery) { export function listRole(query: T.RoleQuery) {
@ -72,7 +73,7 @@ export function updateRolePermission(id: string, data: any) {
/** @desc 查询角色关联用户 */ /** @desc 查询角色关联用户 */
export function listRoleUser(id: string, query: T.RoleUserPageQuery) { export function listRoleUser(id: string, query: T.RoleUserPageQuery) {
return http.get<PageRes<T.RoleUserResp[]>>(`${BASE_URL}/${id}/user`, query) return http.get<PageRes<T.RoleUserResp[]>>(`${BASE_URL_NEW}/${id}/user`, query)
} }
/** @desc 分配角色给用户 */ /** @desc 分配角色给用户 */
@ -87,5 +88,5 @@ export function unassignFromUsers(userRoleIds: Array<string | number>) {
/** @desc 查询角色关联用户 ID */ /** @desc 查询角色关联用户 ID */
export function listRoleUserId(id: string) { export function listRoleUserId(id: string) {
return http.get(`${BASE_URL}/${id}/user/id`) return http.get(`${BASE_URL_NEW}/${id}/user`)
} }

View File

@ -138,6 +138,7 @@ export const systemRoutes: RouteRecordRaw[] = [
}, },
], ],
}, },
//
// { // {
// path: '/organization/hr/salary/insurance', // path: '/organization/hr/salary/insurance',
// name: 'HRInsurance', // name: 'HRInsurance',
@ -174,9 +175,10 @@ export const systemRoutes: RouteRecordRaw[] = [
// name: 'HRPersonalInfo', // name: 'HRPersonalInfo',
// component: () => import('@/views/hr/salary/insurance/personal-info/index.vue'), // component: () => import('@/views/hr/salary/insurance/personal-info/index.vue'),
// meta: { title: '个人信息', icon: 'user', hidden: false }, // meta: { title: '个人信息', icon: 'user', hidden: false },
// } // },
// ] // ],
// }, // },
//
{ {
path: '/organization/hr/salary/system-insurance/health-management', path: '/organization/hr/salary/system-insurance/health-management',
name: 'HRSystemHealthManagement', name: 'HRSystemHealthManagement',
@ -953,6 +955,18 @@ export const systemRoutes: RouteRecordRaw[] = [
// } // }
], ],
}, },
{
path: '/user/profile',
name: 'UserProfile',
component: () => import('@/views/user/profile/index.vue'),
meta: {
title: '个人中心',
icon: 'user',
hidden: false,
sort: 100,
},
children: [],
},
{ {
path: '/enterprise-settings', path: '/enterprise-settings',
name: 'EnterpriseSettings', name: 'EnterpriseSettings',
@ -1156,7 +1170,6 @@ export const systemRoutes: RouteRecordRaw[] = [
}, },
], ],
}, },
{ {
path: '/', path: '/',
redirect: '/project-management/project-template/project-aproval', redirect: '/project-management/project-template/project-aproval',
@ -1182,6 +1195,11 @@ export const constantRoutes: RouteRecordRaw[] = [
}, },
], ],
}, },
// {
// path: '/user/profile',
// component: () => import('@/views/user/profile/index.vue'),
// meta: { hidden: true },
// },
{ {
path: '/:pathMatch(.*)*', path: '/:pathMatch(.*)*',
component: () => import('@/views/default/error/404.vue'), component: () => import('@/views/default/error/404.vue'),

View File

@ -1,4 +1,5 @@
<template> <template>
<GiPageLayout> <GiPageLayout>
<div> <div>
<a-radio-group v-model="viewType" type="button" size="small" style="margin-bottom: 16px;"> <a-radio-group v-model="viewType" type="button" size="small" style="margin-bottom: 16px;">
@ -51,6 +52,7 @@
<a-link v-permission="['system:dept:update']" title="修改" @click="onUpdate(record)">修改</a-link> <a-link v-permission="['system:dept:update']" title="修改" @click="onUpdate(record)">修改</a-link>
<a-link <a-link
v-permission="['system:dept:delete']" v-permission="['system:dept:delete']"
:disabled="record.children && record.children.length > 0"
status="danger" status="danger"
title="删除" title="删除"
@click="onDelete(record)" @click="onDelete(record)"
@ -71,14 +73,14 @@
:collapsable="true" :collapsable="true"
:horizontal="false" :horizontal="false"
:define-menus="menus" :define-menus="menus"
:expand-all="true"
:default-expand-level="999" :default-expand-level="999"
:props="{ id: 'deptId', parentId: 'parentId', label: 'deptName', children: 'children' }" :props="{ id: 'deptId', parentId: 'parentId', label: 'deptName', children: 'children' }"
center center
:node-add="handleAdd" :node-add="handleAdd"
:node-delete="onDelete" :node-delete="onDelete"
:node-edit="onUpdate" :node-edit="onUpdate"
@on-expand-all="bool => nodeExpandAll = bool" :expanded-keys="nodeExpandedKeys"
@node-click="(node) => toggleExpand(node.deptId)"
> >
</Vue3TreeOrg> </Vue3TreeOrg>
</a-dropdown> </a-dropdown>
@ -92,6 +94,7 @@
import 'vue3-tree-org/lib/vue3-tree-org.css' import 'vue3-tree-org/lib/vue3-tree-org.css'
import { Vue3TreeOrg } from 'vue3-tree-org' import { Vue3TreeOrg } from 'vue3-tree-org'
import type { TableInstance } from '@arco-design/web-vue' import type { TableInstance } from '@arco-design/web-vue'
import { Message } from '@arco-design/web-vue'
import DeptAddModal from './DeptAddModal.vue' import DeptAddModal from './DeptAddModal.vue'
import { type DeptQuery, type DeptResp, deleteDept, getDeptTree } from '@/apis/system/dept' import { type DeptQuery, type DeptResp, deleteDept, getDeptTree } from '@/apis/system/dept'
import type GiTable from '@/components/GiTable/index.vue' import type GiTable from '@/components/GiTable/index.vue'
@ -99,6 +102,8 @@ import { useDownload, useTable } from '@/hooks'
import { isMobile } from '@/utils' import { isMobile } from '@/utils'
import has from '@/utils/has' import has from '@/utils/has'
const $message = Message
defineOptions({ name: 'SystemDept' }) defineOptions({ name: 'SystemDept' })
const queryForm = reactive<DeptQuery>({}) const queryForm = reactive<DeptQuery>({})
@ -111,10 +116,21 @@ const {
} = useTable<DeptResp>(() => getDeptTree(queryForm), { } = useTable<DeptResp>(() => getDeptTree(queryForm), {
immediate: true, immediate: true,
onSuccess: () => { onSuccess: () => {
// nextTick(() => { if (isFirstLoad.value) {
// tableRef.value?.tableRef?.expandAll(true) // id
// }) const collectKeys = (nodes: DeptResp[]): string[] => {
// let keys: string[] = []
nodes.forEach(node => {
keys.push(node.deptId)
if (node.children && node.children.length) {
keys = keys.concat(collectKeys(node.children))
}
})
return keys
}
expandedKeys.value = collectKeys(tableData.value)
isFirstLoad.value = false
}
}, },
}) })
// //
@ -126,9 +142,9 @@ const menus = [
{ name: '删除部门', command: 'delete' }, { name: '删除部门', command: 'delete' },
] ]
// //
const nodeExpandAll = ref<boolean>(true)
// //
const expandedKeys = ref<string[]>([]) const expandedKeys = ref<string[]>([])
const isFirstLoad = ref(true)
// //
const searchData = (name: string) => { const searchData = (name: string) => {
const loop = (data: DeptResp[]) => { const loop = (data: DeptResp[]) => {
@ -185,6 +201,13 @@ const reset = () => {
// //
const onDelete = (record: DeptResp) => { const onDelete = (record: DeptResp) => {
//
if (record.children && record.children.length > 0) {
//
$message.warning('该部门存在子部门,无法直接删除')
return Promise.reject()
}
return handleDelete(() => deleteDept(record.deptId), { return handleDelete(() => deleteDept(record.deptId), {
content: `是否确定删除部门「${record.deptName}」?`, content: `是否确定删除部门「${record.deptName}」?`,
showModal: true, showModal: true,
@ -220,6 +243,20 @@ const onExpand = (expanded: boolean, record: DeptResp) => {
expandedKeys.value = expandedKeys.value.filter(k => k !== key) expandedKeys.value = expandedKeys.value.filter(k => k !== key)
} }
} }
// /
const toggleExpandAll = () => {
nodeExpandAll.value = !nodeExpandAll.value
}
// :
const nodeExpandedKeys = ref<string[]>([])
const toggleExpand = (deptId: string) => {
const index = nodeExpandedKeys.value.indexOf(deptId)
index > -1
? nodeExpandedKeys.value.splice(index, 1)
: nodeExpandedKeys.value.push(deptId)
}
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">

View File

@ -27,8 +27,8 @@
<a-radio :value="0">停用</a-radio> <a-radio :value="0">停用</a-radio>
</a-radio-group> </a-radio-group>
</a-form-item> </a-form-item>
<a-form-item field="remark" label="备注"> <a-form-item field="remark" label="说明">
<a-textarea v-model="formData.remark" placeholder="请输入备注" allow-clear /> <a-textarea v-model="formData.remark" placeholder="请输入岗位说明" allow-clear />
</a-form-item> </a-form-item>
</a-form> </a-form>
</a-modal> </a-modal>

View File

@ -2,65 +2,276 @@
<a-drawer <a-drawer
v-model:visible="visible" v-model:visible="visible"
title="岗位详情" title="岗位详情"
width="500px" width="620px"
:footer="false"
unmount-on-close unmount-on-close
class="post-detail-drawer"
@close="() => visible = false"
> >
<a-descriptions <a-spin :loading="loading" class="detail-container">
:data="detailData" <div class="detail-card">
:column="1" <div class="detail-header">
:align="{ label: 'right' }" <div class="post-name">{{ primaryInfo?.name || '-' }}</div>
label-style="width: 120px" <a-tag class="status-tag" :color="getStatusColor(primaryInfo?.status)">
size="medium" {{ getStatusText(primaryInfo?.status) }}
:loading="loading" </a-tag>
border </div>
>
<template #label="{ label }">{{ label }}</template> <div class="detail-group">
<template #value="{ value }"> <div class="group-title">基本信息</div>
<span v-if="value !== undefined && value !== null">{{ value }}</span> <div class="info-grid">
<span v-else>-</span> <div class="info-item">
</template> <div class="info-label">岗位ID</div>
</a-descriptions> <div class="info-value">{{ primaryInfo?.id || '-' }}</div>
</div>
<div class="info-item">
<div class="info-label">岗位排序</div>
<div class="info-value">{{ primaryInfo?.sort || '-' }}</div>
</div>
</div>
</div>
<div v-if="primaryInfo?.remark" class="detail-group">
<div class="group-title">岗位说明</div>
<div class="remark-container">
<div class="remark-content">{{ primaryInfo.remark }}</div>
</div>
</div>
<div class="detail-group">
<div class="group-title">时间信息</div>
<div class="info-grid">
<div class="info-item">
<div class="info-label">创建时间</div>
<div class="info-value">{{ primaryInfo?.createTime || '-' }}</div>
</div>
<div class="info-item">
<div class="info-label">更新时间</div>
<div class="info-value">{{primaryInfo?.updateTime || '-' }}</div>
</div>
</div>
</div>
</div>
</a-spin>
<template #footer>
<div class="footer-actions">
<a-button type="primary" @click="handleClose">关闭详情</a-button>
</div>
</template>
</a-drawer> </a-drawer>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { nextTick, ref } from 'vue'
import { getPostDetail } from '@/apis/system/post' import { getPostDetail } from '@/apis/system/post'
import { useLoading } from '@/hooks' import { useLoading } from '@/hooks'
//import { formatDate } from '@/utils/date'
defineOptions({ name: 'PostDetailDrawer' }) defineOptions({ name: 'PostDetailDrawer' })
const visible = ref(false) const visible = ref(false)
const { loading, setLoading } = useLoading() const { loading, setLoading } = useLoading()
const detailData = ref<Array<{ label: string; value: any }>>([]) const primaryInfo = ref<any>(null)
// //
const getDetail = async (id: string) => { const getDetail = async (id: string) => {
try { try {
setLoading(true) setLoading(true)
const { data } = await getPostDetail(id) primaryInfo.value = null
if (data) {
detailData.value = [ const response = await getPostDetail(id)
{ label: '岗位名称', value: data.postName }, const data = response?.data || response
{ label: '岗位排序', value: data.postSort },
{ label: '状态', value: Number(data.status) === 1 ? '正常' : '停用' }, if (data && typeof data === 'object') {
{ label: '备注', value: data.remark }, primaryInfo.value = {
{ label: '创建时间', value: data.createTime }, id: data.postId ?? data.id,
{ label: '更新时间', value: data.updateTime }, name: data.postName ?? data.name,
] sort: data.postSort,
status: data.status,
remark: data.remark,
createTime: data.createTime,
updateTime: data.updateTime,
}
} }
} catch (error: any) {
console.error('获取岗位详情失败:', error)
} finally { } finally {
setLoading(false) setLoading(false)
} }
} }
//
const getStatusText = (status: number | string) => {
if (status === 1 || status === '1') return '正常'
if (status === 0 || status === '0') return '停用'
return '未知状态'
}
//
const getStatusColor = (status: number | string) => {
if (status === 1 || status === '1') return 'rgb(82, 196, 26)'
if (status === 0 || status === '0') return 'rgb(245, 34, 45)'
return 'rgb(150, 150, 150)'
}
//
const handleClose = () => {
visible.value = false
}
// //
const onDetail = async (id: string) => { const onDetail = async (id: string) => {
if (!id) return
visible.value = true visible.value = true
await nextTick()
await getDetail(id) await getDetail(id)
} }
defineExpose({ defineExpose({
onDetail, onDetail,
}) })
</script> </script>
<style scoped>
.post-detail-drawer {
--primary-color: #3498db;
--light-bg: #f9fafc;
--border-color: #eaeaea;
--label-color: #666;
--value-color: #333;
--group-title-color: #555;
--group-bg: #f5f7fa;
}
.detail-container {
padding: 16px 24px;
}
.detail-card {
background-color: #fff;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.05);
padding: 20px;
transition: all 0.3s ease;
}
.detail-header {
display: flex;
align-items: center;
margin-bottom: 28px;
padding-bottom: 20px;
border-bottom: 1px solid var(--border-color);
}
.post-name {
font-size: 22px;
font-weight: 600;
color: var(--value-color);
margin-right: 15px;
letter-spacing: 0.5px;
}
.status-tag {
padding: 4px 12px;
border-radius: 4px;
font-size: 14px;
font-weight: 500;
border: none;
color: white !important;
}
.detail-group {
margin-bottom: 25px;
position: relative;
background-color: var(--group-bg);
border-radius: 8px;
padding: 12px 16px;
}
.detail-group:last-child {
margin-bottom: 0;
}
.group-title {
font-size: 16px;
font-weight: 600;
color: var(--group-title-color);
padding-bottom: 12px;
border-bottom: 1px solid var(--border-color);
margin-bottom: 15px;
display: flex;
align-items: center;
}
.group-title::before {
content: '';
display: inline-block;
width: 4px;
height: 16px;
background-color: var(--primary-color);
margin-right: 8px;
border-radius: 2px;
}
.info-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 18px;
}
.info-item {
display: flex;
flex-direction: column;
background: white;
padding: 12px 15px;
border-radius: 6px;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.03);
border: 1px solid var(--border-color);
transition: transform 0.2s, box-shadow 0.2s;
}
.info-item:hover {
transform: translateY(-2px);
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.05);
}
.info-label {
font-size: 14px;
color: var(--label-color);
margin-bottom: 6px;
font-weight: 500;
display: flex;
align-items: center;
}
.info-label::after {
content: ':';
margin-right: 4px;
}
.info-value {
font-size: 16px;
color: var(--value-color);
font-weight: 500;
word-break: break-word;
}
.remark-container {
padding: 16px;
background: white;
border-radius: 6px;
border: 1px solid var(--border-color);
}
.remark-content {
color: var(--value-color);
line-height: 1.7;
font-size: 15px;
}
.footer-actions {
display: flex;
justify-content: flex-end;
padding: 16px 24px;
}
</style>

View File

@ -26,6 +26,7 @@
</template> </template>
<template #action="{ record }"> <template #action="{ record }">
<a-space> <a-space>
<a-link v-permission="['system:post:query']" title="详情" @click="onDetail(record)">详情</a-link>
<a-link v-permission="['system:post:update']" title="修改" @click="onUpdate(record)">修改</a-link> <a-link v-permission="['system:post:update']" title="修改" @click="onUpdate(record)">修改</a-link>
<a-link <a-link
v-permission="['system:post:delete']" v-permission="['system:post:delete']"
@ -128,7 +129,7 @@ const tableColumns = ref<TableColumnData[]>([
width: 100 width: 100
}, },
{ {
title: '备注', title: '说明',
dataIndex: 'remark', dataIndex: 'remark',
minWidth: 180, minWidth: 180,
ellipsis: true, ellipsis: true,
@ -148,7 +149,7 @@ const tableColumns = ref<TableColumnData[]>([
title: '操作', title: '操作',
dataIndex: 'action', dataIndex: 'action',
slotName: 'action', slotName: 'action',
width: 160, width: 200,
fixed: !isMobile() ? 'right' : undefined, fixed: !isMobile() ? 'right' : undefined,
show: has.hasPermOr(['system:post:update', 'system:post:delete']), show: has.hasPermOr(['system:post:update', 'system:post:delete']),
}, },
@ -187,4 +188,4 @@ const onDetail = (record: PostVO) => {
} }
</script> </script>
<style scoped lang="scss"></style> <style scoped lang="scss"></style>

View File

@ -1,13 +1,13 @@
<template> <template>
<a-modal <a-modal
v-model:visible="visible" v-model:visible="visible"
title="分配角色" title="分配角色"
:mask-closable="false" :mask-closable="false"
:esc-to-close="false" :esc-to-close="false"
:width="width >= 1100 ? 1100 : '100%'" :width="width >= 1100 ? 1100 : '100%'"
draggable draggable
@before-ok="save" @before-ok="save"
@close="reset" @close="reset"
> >
<UserSelect v-if="visible" ref="UserSelectRef" v-model:value="selectedUsers" :role-id="dataId" @select-user="onSelectUser" /> <UserSelect v-if="visible" ref="UserSelectRef" v-model:value="selectedUsers" :role-id="dataId" @select-user="onSelectUser" />
</a-modal> </a-modal>
@ -17,6 +17,7 @@
import { Message } from '@arco-design/web-vue' import { Message } from '@arco-design/web-vue'
import { useWindowSize } from '@vueuse/core' import { useWindowSize } from '@vueuse/core'
import { assignToUsers } from '@/apis/system/role' import { assignToUsers } from '@/apis/system/role'
//
const emit = defineEmits<{ const emit = defineEmits<{
(e: 'save-success'): void (e: 'save-success'): void

View File

@ -98,21 +98,11 @@ const columns: TableInstance['columns'] = [
render: ({ rowIndex }) => h('span', {}, rowIndex + 1 + (pagination.current - 1) * pagination.pageSize), render: ({ rowIndex }) => h('span', {}, rowIndex + 1 + (pagination.current - 1) * pagination.pageSize),
fixed: !isMobile() ? 'left' : undefined, fixed: !isMobile() ? 'left' : undefined,
}, },
{ { title: '用户名', dataIndex: 'name', slotName: 'name', minWidth: 120, ellipsis: true, tooltip: true },
title: '昵称',
dataIndex: 'nickname',
slotName: 'nickname',
minWidth: 130,
ellipsis: true,
tooltip: true,
fixed: !isMobile() ? 'left' : undefined,
},
{ title: '用户名', dataIndex: 'username', slotName: 'username', minWidth: 120, ellipsis: true, tooltip: true },
{ title: '状态', dataIndex: 'status', slotName: 'status', align: 'center' },
{ title: '性别', dataIndex: 'gender', slotName: 'gender', align: 'center' }, { title: '性别', dataIndex: 'gender', slotName: 'gender', align: 'center' },
{ title: '状态', dataIndex: 'status', slotName: 'status', align: 'center' },
{ title: '所属部门', dataIndex: 'deptName', minWidth: 140, ellipsis: true, tooltip: true }, { title: '所属部门', dataIndex: 'deptName', minWidth: 140, ellipsis: true, tooltip: true },
{ title: '角色', dataIndex: 'roleNames', slotName: 'roleNames', minWidth: 165 }, { title: '角色', dataIndex: 'roleNames', slotName: 'roleNames', minWidth: 165 },
{ title: '描述', dataIndex: 'description', minWidth: 130, ellipsis: true, tooltip: true },
{ {
title: '操作', title: '操作',
dataIndex: 'action', dataIndex: 'action',
@ -142,7 +132,7 @@ const onMulDelete = () => {
content: `是否确定取消分配角色给所选的${selectedKeys.value.length}个用户?`, content: `是否确定取消分配角色给所选的${selectedKeys.value.length}个用户?`,
hideCancel: false, hideCancel: false,
onOk: async () => { onOk: async () => {
await unassignFromUsers(selectedKeys.value) await unassignFromUsers(selectedKeys.value.map(id => String(id)))
Message.success('取消成功') Message.success('取消成功')
search() search()
}, },
@ -151,7 +141,7 @@ const onMulDelete = () => {
// //
const onDelete = (record: RoleUserResp) => { const onDelete = (record: RoleUserResp) => {
return handleDelete(() => unassignFromUsers([record.id]), { return handleDelete(() => unassignFromUsers([String(record.id)]), {
content: `是否确定取消分配角色给用户「${record.nickname}(${record.username})」?`, content: `是否确定取消分配角色给用户「${record.nickname}(${record.username})」?`,
successTip: '取消成功', successTip: '取消成功',
showModal: true, showModal: true,

View File

@ -19,6 +19,7 @@
import RoleTree from './tree/index.vue' import RoleTree from './tree/index.vue'
import Permission from './components/Permission.vue' import Permission from './components/Permission.vue'
import RoleUser from './components/RoleUser.vue' import RoleUser from './components/RoleUser.vue'
import {listRoleUserId} from "@/apis";
defineOptions({ name: 'SystemRole' }) defineOptions({ name: 'SystemRole' })

View File

@ -60,7 +60,7 @@ const save = async () => {
try { try {
const isInvalid = await formRef.value?.formRef?.validate() const isInvalid = await formRef.value?.formRef?.validate()
if (isInvalid) return false if (isInvalid) return false
await updateUserRole({ roleIds: form.roleIds }, dataId.value) await updateUserRole({ roleIds: form.roleIds.map(id => String(id)) }, dataId.value)
Message.success('分配成功') Message.success('分配成功')
emit('save-success') emit('save-success')
return true return true

View File

@ -93,7 +93,7 @@ const handleSubmit = async () => {
await bindUserRole({ await bindUserRole({
userId: props.userData.userId, userId: props.userData.userId,
roleIds: selectedRoles.value roleIds: selectedRoles.value.map(id => String(id))
}) })
Message.success('角色分配成功') Message.success('角色分配成功')

View File

@ -313,17 +313,17 @@ const columns: TableInstance['columns'] = [
}, },
{ title: '账号', dataIndex: 'account', minWidth: 140, ellipsis: true, tooltip: true }, { title: '账号', dataIndex: 'account', minWidth: 140, ellipsis: true, tooltip: true },
{ title: '员工编码', dataIndex: 'userCode', minWidth: 120, ellipsis: true, tooltip: true }, { title: '员工编码', dataIndex: 'userCode', minWidth: 120, ellipsis: true, tooltip: true },
{ title: '在职状态', dataIndex: 'userStatus', slotName: 'userStatus', align: 'center', width: 100 },
{ title: '员工性质', dataIndex: 'userType', slotName: 'userType', align: 'center', width: 100 },
{ title: '性别', dataIndex: 'gender', slotName: 'gender', align: 'center', width: 80 }, { title: '性别', dataIndex: 'gender', slotName: 'gender', align: 'center', width: 80 },
{ title: '所属部门', dataIndex: 'deptName', minWidth: 180, ellipsis: true, tooltip: true },
{ title: '角色', dataIndex: 'roleIds', slotName: 'roleIds', minWidth: 165 },
{ title: '手机号', dataIndex: 'mobile', minWidth: 170, ellipsis: true, tooltip: true }, { title: '手机号', dataIndex: 'mobile', minWidth: 170, ellipsis: true, tooltip: true },
{ title: '邮箱', dataIndex: 'email', minWidth: 170, ellipsis: true, tooltip: true }, { title: '所属部门', dataIndex: 'deptName', minWidth: 180, 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: 'educationLabel', width: 100, ellipsis: true, tooltip: true, show: false }, { title: '学历', dataIndex: 'educationLabel', width: 100, ellipsis: true, tooltip: true, show: false },
{ title: '专业', dataIndex: 'majorField', width: 120, 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: 'workField', width: 120, ellipsis: true, tooltip: true, show: false },
{ title: '身份证', dataIndex: 'identityCard', width: 180, ellipsis: true, tooltip: true, show: false }, { title: '身份证', dataIndex: 'identityCard', width: 180, ellipsis: true, tooltip: true, show: false },
{ {