From d130e310ea868208b3918183f8d8db5e85dbef69 Mon Sep 17 00:00:00 2001 From: Your Name Date: Mon, 5 Jan 2026 17:54:53 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E4=BB=BB=E5=8A=A1=E5=AD=90=E7=B1=BB?= =?UTF-8?q?=E5=9E=8B=E5=A4=A7=E5=88=86=E7=B1=BB=E6=94=AF=E6=8C=81=E8=AE=BE?= =?UTF-8?q?=E7=BD=AE=E6=8E=A5=E5=8D=95=E9=83=A8=E9=97=A8=EF=BC=8C=E5=AD=90?= =?UTF-8?q?=E5=88=86=E7=B1=BB=E8=87=AA=E5=8A=A8=E7=BB=A7=E6=89=BF=EF=BC=9B?= =?UTF-8?q?=E9=83=A8=E9=97=A8=E9=80=89=E6=8B=A9=E6=98=BE=E7=A4=BA=E5=B1=82?= =?UTF-8?q?=E7=BA=A7=E7=BB=93=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/designhub/entity/TaskSubType.java | 12 ++ frontend/src/api/config.ts | 2 + frontend/src/views/Settings.vue | 153 ++++++++++++++++-- 3 files changed, 150 insertions(+), 17 deletions(-) diff --git a/backend/src/main/java/com/designhub/entity/TaskSubType.java b/backend/src/main/java/com/designhub/entity/TaskSubType.java index 9ca8dc4..40fe049 100644 --- a/backend/src/main/java/com/designhub/entity/TaskSubType.java +++ b/backend/src/main/java/com/designhub/entity/TaskSubType.java @@ -63,12 +63,24 @@ public class TaskSubType implements Serializable { */ private Integer checkInventory; + /** + * 可接单部门ID列表(逗号分隔),只在父级分类上设置 + * 子分类自动继承父分类的设置 + */ + private String allowedDeptIds; + /** * 子分类列表(非数据库字段) */ @TableField(exist = false) private List children; + /** + * 前端使用的部门ID数组(非数据库字段) + */ + @TableField(exist = false) + private List departmentIds; + /** * 创建时间 */ diff --git a/frontend/src/api/config.ts b/frontend/src/api/config.ts index 66f9a4d..3c6344f 100644 --- a/frontend/src/api/config.ts +++ b/frontend/src/api/config.ts @@ -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[] // 子分类列表 diff --git a/frontend/src/views/Settings.vue b/frontend/src/views/Settings.vue index f12eaf7..18a01e7 100644 --- a/frontend/src/views/Settings.vue +++ b/frontend/src/views/Settings.vue @@ -172,6 +172,16 @@ {{ record.name }} {{ getParentName(record.parentId) }} + + + + +
+ + 选择父部门后,其下所有子部门都可接单。子分类会自动继承此设置。 +
+
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() + 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() + 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>({}) @@ -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 & { 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 & { 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) {