feat: 任务子类型大分类支持设置接单部门,子分类自动继承;部门选择显示层级结构
This commit is contained in:
parent
1e1aa5872d
commit
d130e310ea
@ -63,12 +63,24 @@ public class TaskSubType implements Serializable {
|
||||
*/
|
||||
private Integer checkInventory;
|
||||
|
||||
/**
|
||||
* 可接单部门ID列表(逗号分隔),只在父级分类上设置
|
||||
* 子分类自动继承父分类的设置
|
||||
*/
|
||||
private String allowedDeptIds;
|
||||
|
||||
/**
|
||||
* 子分类列表(非数据库字段)
|
||||
*/
|
||||
@TableField(exist = false)
|
||||
private List<TaskSubType> children;
|
||||
|
||||
/**
|
||||
* 前端使用的部门ID数组(非数据库字段)
|
||||
*/
|
||||
@TableField(exist = false)
|
||||
private List<Long> departmentIds;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
|
||||
@ -71,6 +71,8 @@ export interface TaskSubType {
|
||||
sortOrder?: number
|
||||
isEnabled?: number
|
||||
checkInventory?: number // 是否检查库存
|
||||
allowedDeptIds?: string // 可接单部门ID(逗号分隔),只在父级分类设置
|
||||
departmentIds?: number[] // 前端使用的部门ID数组
|
||||
createTime?: string
|
||||
updateTime?: string
|
||||
children?: TaskSubType[] // 子分类列表
|
||||
|
||||
@ -172,6 +172,16 @@
|
||||
<a-tag v-if="!record.parentId" color="blue">{{ record.name }}</a-tag>
|
||||
<span v-else>{{ getParentName(record.parentId) }}</span>
|
||||
</template>
|
||||
<template v-else-if="column.key === 'allowedDepts'">
|
||||
<template v-if="!record.parentId">
|
||||
<!-- 大分类显示接单部门 -->
|
||||
<span v-if="record.allowedDeptIds" style="font-size: 12px;">
|
||||
{{ getAllowedDeptNames(record.allowedDeptIds) }}
|
||||
</span>
|
||||
<span v-else style="color: #999; font-size: 12px;">全部部门</span>
|
||||
</template>
|
||||
<span v-else style="color: #999; font-size: 12px;">继承大分类</span>
|
||||
</template>
|
||||
<template v-else-if="column.key === 'checkInventory'">
|
||||
<a-tag v-if="record.checkInventory === 1" color="orange">是</a-tag>
|
||||
<span v-else style="color: #999;">否</span>
|
||||
@ -1207,7 +1217,7 @@
|
||||
:title="taskSubTypeModalTitle"
|
||||
@ok="saveTaskSubType"
|
||||
@cancel="closeModal('taskSubType')"
|
||||
width="560px"
|
||||
width="640px"
|
||||
>
|
||||
<a-form :model="formData.taskSubType" layout="vertical">
|
||||
<a-form-item v-if="!isAddingParentType" label="所属需求类型(大分类)">
|
||||
@ -1222,7 +1232,7 @@
|
||||
</a-select>
|
||||
<div class="form-tip" style="margin-top: 4px;">
|
||||
<Icon name="info" size="sm" color="#6B6B6B" style="margin-right: 4px;" />
|
||||
选择大分类后,此子类型将归属于该分类下
|
||||
选择大分类后,此子类型将归属于该分类下,并继承大分类的接单部门设置
|
||||
</div>
|
||||
</a-form-item>
|
||||
<a-form-item :label="isAddingParentType ? '需求类型名称' : '需求类型细分名称'" required>
|
||||
@ -1237,6 +1247,24 @@
|
||||
</template>
|
||||
</a-input>
|
||||
</a-form-item>
|
||||
<!-- 只有大分类才需要设置接单部门 -->
|
||||
<a-form-item v-if="isAddingParentType || (!formData.taskSubType.parentId && editingItem)" label="可接单部门">
|
||||
<a-tree-select
|
||||
v-model:value="formData.taskSubType.departmentIds"
|
||||
:tree-data="receivingDeptTreeData"
|
||||
:field-names="{ children: 'children', label: 'title', value: 'value' }"
|
||||
tree-checkable
|
||||
:show-checked-strategy="SHOW_PARENT"
|
||||
placeholder="选择可接单的部门(选择父部门会自动包含所有子部门)"
|
||||
style="width: 100%"
|
||||
:tree-default-expand-all="true"
|
||||
:max-tag-count="3"
|
||||
/>
|
||||
<div class="form-tip" style="margin-top: 4px;">
|
||||
<Icon name="info" size="sm" color="#6B6B6B" style="margin-right: 4px;" />
|
||||
选择父部门后,其下所有子部门都可接单。子分类会自动继承此设置。
|
||||
</div>
|
||||
</a-form-item>
|
||||
<a-form-item v-if="!isAddingParentType" label="单价分值">
|
||||
<a-input-number
|
||||
v-model:value="formData.taskSubType.unitPrice"
|
||||
@ -1709,7 +1737,8 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive, onMounted, computed, watch } from 'vue'
|
||||
import DefaultLayout from '@/layouts/DefaultLayout.vue'
|
||||
import { message } from 'ant-design-vue'
|
||||
import { message, TreeSelect } from 'ant-design-vue'
|
||||
const { SHOW_PARENT } = TreeSelect
|
||||
import Icon from '@/components/Icon.vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { useSiteSettingsStore } from '@/stores/siteSettings'
|
||||
@ -1879,6 +1908,80 @@ const filterTaskSubTypes = () => {
|
||||
// 筛选器变化时触发重新渲染
|
||||
}
|
||||
|
||||
// 构建接单部门树形数据(只显示接单部门,带层级标识)
|
||||
interface DeptTreeNode {
|
||||
title: string
|
||||
value: number
|
||||
key: number
|
||||
children?: DeptTreeNode[]
|
||||
}
|
||||
|
||||
const receivingDeptTreeData = computed((): DeptTreeNode[] => {
|
||||
// 只获取接单部门
|
||||
const receivingDepts = departments.value.filter(d => d.deptType === 'receiving')
|
||||
|
||||
// 构建层级映射
|
||||
const deptMap = new Map<number, DepartmentOverview>()
|
||||
receivingDepts.forEach(d => deptMap.set(d.id!, d))
|
||||
|
||||
// 找出所有顶级部门(parentId为0或null)
|
||||
const rootDepts = receivingDepts.filter(d => !d.parentId || d.parentId === 0)
|
||||
|
||||
// 递归构建树
|
||||
const buildTree = (dept: DepartmentOverview, level: number): DeptTreeNode => {
|
||||
const levelPrefix = level === 1 ? '【一级】' : level === 2 ? '【二级】' : level === 3 ? '【三级】' : ''
|
||||
const children = receivingDepts
|
||||
.filter(d => d.parentId === dept.id)
|
||||
.map(child => buildTree(child, level + 1))
|
||||
|
||||
return {
|
||||
title: `${levelPrefix}${dept.deptName}`,
|
||||
value: dept.id!,
|
||||
key: dept.id!,
|
||||
children: children.length > 0 ? children : undefined
|
||||
}
|
||||
}
|
||||
|
||||
return rootDepts.map(d => buildTree(d, 1))
|
||||
})
|
||||
|
||||
// 获取部门及其所有子部门ID
|
||||
const getAllChildDeptIds = (deptId: number): number[] => {
|
||||
const result: number[] = [deptId]
|
||||
const children = departments.value.filter(d => d.parentId === deptId)
|
||||
children.forEach(child => {
|
||||
result.push(...getAllChildDeptIds(child.id!))
|
||||
})
|
||||
return result
|
||||
}
|
||||
|
||||
// 展开选中的部门ID,包含所有子部门
|
||||
const expandDeptIdsWithChildren = (deptIds: number[]): number[] => {
|
||||
const allIds = new Set<number>()
|
||||
deptIds.forEach(id => {
|
||||
getAllChildDeptIds(id).forEach(childId => allIds.add(childId))
|
||||
})
|
||||
return Array.from(allIds)
|
||||
}
|
||||
|
||||
// 获取接单部门名称(用于表格显示)
|
||||
const getAllowedDeptNames = (allowedDeptIds: string): string => {
|
||||
if (!allowedDeptIds) return '全部部门'
|
||||
const ids = allowedDeptIds.split(',').map(id => parseInt(id.trim())).filter(id => !isNaN(id))
|
||||
// 只显示顶级选中的部门(非子部门)
|
||||
const topLevelIds = ids.filter(id => {
|
||||
const dept = departments.value.find(d => d.id === id)
|
||||
if (!dept) return false
|
||||
// 如果父部门也在列表中,则不显示此部门
|
||||
return !ids.includes(dept.parentId || 0)
|
||||
})
|
||||
const names = topLevelIds.map(id => {
|
||||
const dept = departments.value.find(d => d.id === id)
|
||||
return dept ? dept.deptName : ''
|
||||
}).filter(n => n)
|
||||
return names.length > 0 ? names.slice(0, 3).join('、') + (names.length > 3 ? '...' : '') : '全部部门'
|
||||
}
|
||||
|
||||
const userLoading = ref(false)
|
||||
const usersLoaded = ref(false)
|
||||
const usersByDept = ref<Record<number, User[]>>({})
|
||||
@ -2118,15 +2221,15 @@ const demandTypeColumns = [
|
||||
]
|
||||
|
||||
const taskSubTypeColumns = [
|
||||
{ title: 'ID', dataIndex: 'id', key: 'id', width: 60 },
|
||||
{ title: '需求类型', key: 'parentName', width: 100 },
|
||||
{ title: '需求类型细分', dataIndex: 'name', key: 'name' },
|
||||
{ title: '单价分值', dataIndex: 'unitPrice', key: 'unitPrice', width: 100 },
|
||||
{ title: '编码', dataIndex: 'code', key: 'code', width: 120 },
|
||||
{ title: '检查库存', key: 'checkInventory', width: 90 },
|
||||
{ title: '排序', dataIndex: 'sortOrder', key: 'sortOrder', width: 70 },
|
||||
{ title: '状态', key: 'status', width: 80 },
|
||||
{ title: '操作', key: 'actions', width: 130 }
|
||||
{ title: 'ID', dataIndex: 'id', key: 'id', width: 50 },
|
||||
{ title: '需求类型', key: 'parentName', width: 90 },
|
||||
{ title: '需求类型细分', dataIndex: 'name', key: 'name', width: 150 },
|
||||
{ title: '单价分值', dataIndex: 'unitPrice', key: 'unitPrice', width: 80 },
|
||||
{ title: '可接单部门', key: 'allowedDepts', ellipsis: true },
|
||||
{ title: '检查库存', key: 'checkInventory', width: 80 },
|
||||
{ title: '排序', dataIndex: 'sortOrder', key: 'sortOrder', width: 60 },
|
||||
{ title: '状态', key: 'status', width: 70 },
|
||||
{ title: '操作', key: 'actions', width: 120 }
|
||||
]
|
||||
|
||||
const brandColumns = [
|
||||
@ -2487,11 +2590,15 @@ const showTaskSubTypeModal = (item?: TaskSubType | null, addParent: boolean = fa
|
||||
isAddingParentType.value = addParent
|
||||
|
||||
if (item) {
|
||||
// 编辑模式
|
||||
// 编辑模式:将allowedDeptIds(逗号分隔字符串)转换为数组
|
||||
const departmentIds = item.allowedDeptIds
|
||||
? item.allowedDeptIds.split(',').map(id => parseInt(id.trim())).filter(id => !isNaN(id))
|
||||
: []
|
||||
formData.taskSubType = {
|
||||
...item,
|
||||
checkInventory: item.checkInventory === 1,
|
||||
unitPrice: item.unitPrice || 0
|
||||
unitPrice: item.unitPrice || 0,
|
||||
departmentIds
|
||||
}
|
||||
} else {
|
||||
// 新建模式
|
||||
@ -2500,7 +2607,8 @@ const showTaskSubTypeModal = (item?: TaskSubType | null, addParent: boolean = fa
|
||||
sortOrder: 0,
|
||||
isEnabled: 1,
|
||||
checkInventory: false,
|
||||
unitPrice: 0
|
||||
unitPrice: 0,
|
||||
departmentIds: []
|
||||
}
|
||||
}
|
||||
modals.taskSubType = true
|
||||
@ -2605,7 +2713,17 @@ const saveDemandType = async () => {
|
||||
|
||||
const saveTaskSubType = async () => {
|
||||
try {
|
||||
const saveData: Partial<TaskSubType> & { checkInventory?: number } = {
|
||||
// 处理接单部门:只有大分类需要设置,选中的部门会自动展开包含所有子部门
|
||||
const isParentType = isAddingParentType.value || (!formData.taskSubType.parentId && editingItem.value)
|
||||
let allowedDeptIds: string | null = null
|
||||
|
||||
if (isParentType && formData.taskSubType.departmentIds && formData.taskSubType.departmentIds.length > 0) {
|
||||
// 展开所有选中的部门,包含其子部门
|
||||
const expandedIds = expandDeptIdsWithChildren(formData.taskSubType.departmentIds as number[])
|
||||
allowedDeptIds = expandedIds.join(',')
|
||||
}
|
||||
|
||||
const saveData: Partial<TaskSubType> & { checkInventory?: number; allowedDeptIds?: string | null } = {
|
||||
parentId: isAddingParentType.value ? null : (formData.taskSubType.parentId || null),
|
||||
name: formData.taskSubType.name,
|
||||
code: formData.taskSubType.code,
|
||||
@ -2613,7 +2731,8 @@ const saveTaskSubType = async () => {
|
||||
unitPrice: formData.taskSubType.unitPrice ?? 0,
|
||||
sortOrder: formData.taskSubType.sortOrder ?? 0,
|
||||
isEnabled: formData.taskSubType.isEnabled ?? 1,
|
||||
checkInventory: isAddingParentType.value ? 0 : ((formData.taskSubType as any).checkInventory ? 1 : 0)
|
||||
checkInventory: isAddingParentType.value ? 0 : ((formData.taskSubType as any).checkInventory ? 1 : 0),
|
||||
allowedDeptIds: isParentType ? allowedDeptIds : undefined // 只有大分类保存接单部门设置
|
||||
}
|
||||
|
||||
if (editingItem.value) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user