feat: 部门管理使用树形结构展示层级关系
This commit is contained in:
parent
4c9384dbed
commit
11c9fcc7e6
@ -502,12 +502,23 @@
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<a-alert type="info" show-icon style="margin-bottom: 16px;">
|
||||
<template #message>
|
||||
<span>部门类型说明</span>
|
||||
</template>
|
||||
<template #description>
|
||||
<span>需求部门:只能发起需求;接单部门:只能接收任务。请根据实际情况设置部门类型。</span>
|
||||
</template>
|
||||
</a-alert>
|
||||
|
||||
<a-table
|
||||
:columns="departmentColumns"
|
||||
:data-source="filteredDepartments"
|
||||
:data-source="filteredDepartmentsTree"
|
||||
:loading="loading.departments"
|
||||
row-key="id"
|
||||
:pagination="{ pageSize: 10 }"
|
||||
:pagination="false"
|
||||
:default-expand-all-rows="true"
|
||||
:indent-size="24"
|
||||
>
|
||||
<template #bodyCell="{ column, record }">
|
||||
<template v-if="column.key === 'deptInfo'">
|
||||
@ -515,9 +526,27 @@
|
||||
<div class="dept-info-main">
|
||||
<span class="dept-name-text">{{ record.deptName }}</span>
|
||||
<a-tag
|
||||
v-if="getDepartmentLevel(record) === 1"
|
||||
size="small"
|
||||
:color="record.deptType === 'demand' ? 'blue' : 'green'"
|
||||
color="blue"
|
||||
style="margin-left: 8px;"
|
||||
>一级</a-tag>
|
||||
<a-tag
|
||||
v-else-if="getDepartmentLevel(record) === 2"
|
||||
size="small"
|
||||
color="cyan"
|
||||
style="margin-left: 8px;"
|
||||
>二级</a-tag>
|
||||
<a-tag
|
||||
v-else
|
||||
size="small"
|
||||
color="purple"
|
||||
style="margin-left: 8px;"
|
||||
>三级</a-tag>
|
||||
<a-tag
|
||||
size="small"
|
||||
:color="record.deptType === 'demand' ? 'orange' : 'green'"
|
||||
style="margin-left: 4px;"
|
||||
>
|
||||
{{ record.deptType === 'demand' ? '需求部门' : '接单部门' }}
|
||||
</a-tag>
|
||||
@ -1725,15 +1754,29 @@
|
||||
</a-form-item>
|
||||
<a-form-item label="上级部门">
|
||||
<a-select v-model:value="departmentParentId" placeholder="请选择上级部门" allow-clear>
|
||||
<a-select-option :value="0">顶级部门</a-select-option>
|
||||
<a-select-option
|
||||
v-for="dept in departments.filter(d => !editingItem || d.id !== editingItem.id)"
|
||||
:key="dept.id"
|
||||
:value="dept.id"
|
||||
>
|
||||
{{ dept.deptName }}
|
||||
</a-select-option>
|
||||
<a-select-option :value="0">顶级部门(一级)</a-select-option>
|
||||
<a-select-opt-group label="一级部门(选择后成为二级)">
|
||||
<a-select-option
|
||||
v-for="dept in parentDepartmentOptions.level1"
|
||||
:key="dept.id"
|
||||
:value="dept.id"
|
||||
>
|
||||
{{ dept.deptName }}
|
||||
</a-select-option>
|
||||
</a-select-opt-group>
|
||||
<a-select-opt-group label="二级部门(选择后成为三级)">
|
||||
<a-select-option
|
||||
v-for="dept in parentDepartmentOptions.level2"
|
||||
:key="dept.id"
|
||||
:value="dept.id"
|
||||
>
|
||||
{{ dept.parentName }} / {{ dept.deptName }}
|
||||
</a-select-option>
|
||||
</a-select-opt-group>
|
||||
</a-select>
|
||||
<div class="form-tip" style="margin-top: 4px; color: #888; font-size: 12px;">
|
||||
选择顶级表示创建一级部门,选择一级部门则创建二级部门,选择二级部门则创建三级部门
|
||||
</div>
|
||||
</a-form-item>
|
||||
<a-form-item label="描述">
|
||||
<a-textarea v-model:value="formData.department.description" :rows="3" placeholder="请输入描述" />
|
||||
@ -2382,6 +2425,116 @@ const getDemandTypeLevel = (record: DemandType): number => {
|
||||
return 3
|
||||
}
|
||||
|
||||
// 构建部门树形结构数据
|
||||
const departmentsTree = computed(() => {
|
||||
// 获取所有一级部门(没有parentId的)
|
||||
const level1 = departments.value.filter(d => !d.parentId)
|
||||
|
||||
// 为每个一级部门添加子节点
|
||||
return level1.map(l1 => {
|
||||
// 获取该一级部门下的二级部门
|
||||
const level2Children = departments.value.filter(d => d.parentId === l1.id)
|
||||
|
||||
// 为每个二级部门添加三级子节点
|
||||
const l1WithChildren = {
|
||||
...l1,
|
||||
children: level2Children.map(l2 => {
|
||||
// 获取该二级部门下的三级部门
|
||||
const level3Children = departments.value.filter(d => d.parentId === l2.id)
|
||||
return {
|
||||
...l2,
|
||||
children: level3Children.length > 0 ? level3Children : undefined
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 如果没有子节点,不设置children属性
|
||||
if (l1WithChildren.children.length === 0) {
|
||||
delete l1WithChildren.children
|
||||
}
|
||||
|
||||
return l1WithChildren
|
||||
})
|
||||
})
|
||||
|
||||
// 过滤后的部门树(支持搜索)
|
||||
const filteredDepartmentsTree = computed(() => {
|
||||
if (!departmentSearchText.value) {
|
||||
return departmentsTree.value
|
||||
}
|
||||
|
||||
const searchText = departmentSearchText.value.toLowerCase()
|
||||
|
||||
// 递归过滤函数
|
||||
const filterTree = (nodes: any[]): any[] => {
|
||||
return nodes.reduce((acc, node) => {
|
||||
const nameMatch = node.deptName?.toLowerCase().includes(searchText)
|
||||
const codeMatch = node.deptCode?.toLowerCase().includes(searchText)
|
||||
const leaderMatch = node.leaderName?.toLowerCase().includes(searchText)
|
||||
|
||||
// 递归过滤子节点
|
||||
const filteredChildren = node.children ? filterTree(node.children) : []
|
||||
|
||||
// 如果当前节点匹配,或者有匹配的子节点,则保留
|
||||
if (nameMatch || codeMatch || leaderMatch || filteredChildren.length > 0) {
|
||||
acc.push({
|
||||
...node,
|
||||
children: filteredChildren.length > 0 ? filteredChildren : node.children
|
||||
})
|
||||
}
|
||||
|
||||
return acc
|
||||
}, [] as any[])
|
||||
}
|
||||
|
||||
return filterTree(departmentsTree.value)
|
||||
})
|
||||
|
||||
// 获取部门的层级
|
||||
const getDepartmentLevel = (record: DepartmentOverview): number => {
|
||||
if (!record.parentId) return 1
|
||||
const parent = departments.value.find(d => d.id === record.parentId)
|
||||
if (!parent) return 1
|
||||
if (!parent.parentId) return 2
|
||||
return 3
|
||||
}
|
||||
|
||||
// 上级部门选项(分层级)- 用于部门编辑弹窗
|
||||
const parentDepartmentOptions = computed(() => {
|
||||
// 排除当前正在编辑的部门及其子部门
|
||||
const excludeIds = new Set<number>()
|
||||
if (editingItem.value?.id) {
|
||||
excludeIds.add(editingItem.value.id)
|
||||
// 递归获取所有子部门ID
|
||||
const getChildIds = (parentId: number) => {
|
||||
departments.value.filter(d => d.parentId === parentId).forEach(d => {
|
||||
if (d.id) {
|
||||
excludeIds.add(d.id)
|
||||
getChildIds(d.id)
|
||||
}
|
||||
})
|
||||
}
|
||||
getChildIds(editingItem.value.id)
|
||||
}
|
||||
|
||||
const filteredDepts = departments.value.filter(d => d.id && !excludeIds.has(d.id))
|
||||
|
||||
// 一级部门(没有parentId)
|
||||
const level1 = filteredDepts.filter(d => !d.parentId)
|
||||
|
||||
// 二级部门(parentId指向一级部门)
|
||||
const level1Ids = new Set(level1.map(d => d.id))
|
||||
const level2 = filteredDepts.filter(d => d.parentId && level1Ids.has(d.parentId)).map(d => {
|
||||
const parent = level1.find(l1 => l1.id === d.parentId)
|
||||
return {
|
||||
...d,
|
||||
parentName: parent?.deptName || ''
|
||||
}
|
||||
})
|
||||
|
||||
return { level1, level2 }
|
||||
})
|
||||
|
||||
// 扁平化的部门选项(带层级显示)
|
||||
const flatDepartmentOptions = computed(() => {
|
||||
const receiving = departments.value.filter(dept => dept.deptType === 'receiving')
|
||||
@ -2558,14 +2711,14 @@ const categoryColumns = [
|
||||
]
|
||||
|
||||
const departmentColumns = [
|
||||
{ title: '部门信息', key: 'deptInfo' },
|
||||
{ title: '负责人', key: 'leader', width: 160 },
|
||||
{ title: '成员数', key: 'memberCount', width: 120 },
|
||||
{ title: '积分余额', key: 'score', width: 160 },
|
||||
{ title: '本周期消耗', key: 'limit', width: 200 },
|
||||
{ title: '预警', key: 'alert', width: 120 },
|
||||
{ title: '状态', key: 'status', width: 120 },
|
||||
{ title: '操作', key: 'actions', width: 240 }
|
||||
{ title: '部门信息', key: 'deptInfo', width: 320 },
|
||||
{ title: '负责人', key: 'leader', width: 120 },
|
||||
{ title: '成员数', key: 'memberCount', width: 80 },
|
||||
{ title: '积分余额', key: 'score', width: 140 },
|
||||
{ title: '本周期消耗', key: 'limit', width: 140 },
|
||||
{ title: '预警', key: 'alert', width: 80 },
|
||||
{ title: '状态', key: 'status', width: 100 },
|
||||
{ title: '操作', key: 'actions', width: 200 }
|
||||
]
|
||||
|
||||
// 加载数据
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user