feat: 支持用户选择接单部门 - 当任务类型配置多个部门时

This commit is contained in:
Your Name 2026-01-07 11:19:47 +08:00
parent 599f9ef4a8
commit d5364ed814
3 changed files with 89 additions and 21 deletions

View File

@ -81,5 +81,10 @@ public class PipelineTaskDTO {
* 指定接收人ID
*/
private Long receiverId;
/**
* 用户选择的接单部门ID(当任务类型配置多个部门时使用)
*/
private Long selectedDeptId;
}
}

View File

@ -350,34 +350,42 @@ public class TaskService {
// **步骤1:按接单部门自动分组**
// 遍历任务类型列表,根据接单部门分组
int currentGroupNo = 1;
String lastAllowedDeptIds = null;
String lastDeptKey = null;
for (int i = 0; i < dto.getItems().size(); i++) {
com.designhub.dto.PipelineTaskDTO.TaskItemDTO itemDto = dto.getItems().get(i);
var demandType = configService.getDemandTypeById(itemDto.getTaskTypeId());
// 获取当前任务类型的接单部门配置(支持三级分类继承二级分类的配置)
String currentAllowedDeptIds = demandType.getAllowedDeptIds();
if (currentAllowedDeptIds == null && demandType.getParentId() != null) {
// 如果当前类型没有配置,尝试获取父级的配置
var parentType = configService.getDemandTypeById(demandType.getParentId());
if (parentType != null) {
currentAllowedDeptIds = parentType.getAllowedDeptIds();
log.info("三级分类 {} 继承父级 {} 的接单部门配置: {}",
demandType.getName(), parentType.getName(), currentAllowedDeptIds);
// 获取当前任务类型的接单部门配置
String currentDeptKey;
// 🔥 优先使用用户选择的接单部门
if (itemDto.getSelectedDeptId() != null) {
currentDeptKey = String.valueOf(itemDto.getSelectedDeptId());
log.info("任务类型 {} 使用用户选择的接单部门: {}", demandType.getName(), currentDeptKey);
} else {
// 否则使用任务类型配置的 allowedDeptIds(支持三级分类继承二级分类的配置)
currentDeptKey = demandType.getAllowedDeptIds();
if (currentDeptKey == null && demandType.getParentId() != null) {
// 如果当前类型没有配置,尝试获取父级的配置
var parentType = configService.getDemandTypeById(demandType.getParentId());
if (parentType != null) {
currentDeptKey = parentType.getAllowedDeptIds();
log.info("三级分类 {} 继承父级 {} 的接单部门配置: {}",
demandType.getName(), parentType.getName(), currentDeptKey);
}
}
}
// 判断是否需要创建新分组
boolean needNewGroup = false;
if (i > 0) {
// 如果当前或上一个的 allowed_dept_ids 为 null,则必须分组
// 因为 null 表示所有部门可接单,无法确定具体接单部门
if (currentAllowedDeptIds == null || lastAllowedDeptIds == null) {
// 如果当前或上一个的部门配置为 null,则必须分组
if (currentDeptKey == null || lastDeptKey == null) {
needNewGroup = true;
}
// 如果两者都不为 null,则比较是否相同
else if (!currentAllowedDeptIds.equals(lastAllowedDeptIds)) {
else if (!currentDeptKey.equals(lastDeptKey)) {
needNewGroup = true;
}
}
@ -385,12 +393,12 @@ public class TaskService {
if (needNewGroup) {
currentGroupNo++;
log.info("检测到接单部门变化,创建新分组: groupNo={}, 前一部门={}, 当前部门={}",
currentGroupNo, lastAllowedDeptIds, currentAllowedDeptIds);
currentGroupNo, lastDeptKey, currentDeptKey);
}
// 记录当前分组号(临时存储在sortOrder字段,稍后会恢复)
itemDto.setSortOrder(currentGroupNo * 1000 + i); // 高位存group_no,低位存原始顺序
lastAllowedDeptIds = currentAllowedDeptIds;
lastDeptKey = currentDeptKey;
}
log.info("分组完成,共 {} 个子任务组", currentGroupNo);

View File

@ -106,6 +106,25 @@
/>
</div>
<!-- 部门选择器:当任务类型有多个接单部门时显示 -->
<div v-if="getTaskTypeDeptOptions(item).length > 1" class="task-type-dept">
<a-select
v-model:value="item.selectedDeptId"
placeholder="选择接单部门"
style="width: 160px"
size="large"
@change="calculateScore"
>
<a-select-option
v-for="dept in getTaskTypeDeptOptions(item)"
:key="dept.id"
:value="dept.id"
>
{{ dept.deptName }}
</a-select-option>
</a-select>
</div>
<div v-if="formData.releaseType === 'assigned'" class="task-type-receiver">
<a-select
v-model:value="item.receiverId"
@ -590,6 +609,7 @@ interface TaskTypeItem {
taskTypePath?: (string | number)[] // 级联选择路径 [level1Id, level2Id, level3Id]
quantity: number
receiverId?: number // 指定接收人ID
selectedDeptId?: number // 当任务类型有多个接单部门时,用户选择的部门ID
}
// 级联选择器选项接口
@ -609,7 +629,7 @@ const formData = reactive({
title: '',
isPipeline: true, // 固定为流水线任务
pipelineMode: 'sequential' as 'sequential' | 'parallel', // 固定为顺序流水线
taskTypes: [{ taskTypeId: undefined, taskTypePath: undefined, quantity: 1, receiverId: undefined }] as TaskTypeItem[], // 任务类型数组
taskTypes: [{ taskTypeId: undefined, taskTypePath: undefined, quantity: 1, receiverId: undefined, selectedDeptId: undefined }] as TaskTypeItem[], // 任务类型数组
taskSubType: '', // 动态加载,初始为空
brandId: undefined,
platformId: undefined,
@ -878,7 +898,8 @@ const addTaskType = () => {
taskTypeId: undefined,
taskTypePath: undefined,
quantity: 1,
receiverId: undefined
receiverId: undefined,
selectedDeptId: undefined
})
}
@ -1073,8 +1094,17 @@ const pipelineGroups = computed(() => {
if (!typeInfo) continue
// 获取接单部门配置(三级分类从二级父类继承)
const deptIds = getTypeAllowedDeptIds(typeInfo)
const deptName = getDeptNameFromIds(deptIds)
let deptIds = getTypeAllowedDeptIds(typeInfo)
let deptName = ''
// 如果用户选择了具体部门,使用用户选择的部门
if (taskType.selectedDeptId) {
deptIds = String(taskType.selectedDeptId)
const selectedDept = departmentList.value.find(d => d.id === taskType.selectedDeptId)
deptName = selectedDept?.deptName || '未知部门'
} else {
deptName = getDeptNameFromIds(deptIds)
}
// 判断是否需要创建新分组
if (!currentGroup || currentGroup.deptIds !== deptIds) {
@ -1117,6 +1147,26 @@ const pipelineGroups = computed(() => {
return groups
})
// 获取任务类型可选的部门列表
const getTaskTypeDeptOptions = (item: TaskTypeItem): Array<{ id: number, deptName: string }> => {
if (!item.taskTypeId) return []
const typeInfo = getTaskTypeInfo(item.taskTypeId)
if (!typeInfo) return []
const deptIds = getTypeAllowedDeptIds(typeInfo)
if (!deptIds) return []
const ids = deptIds.split(',').map(id => parseInt(id.trim())).filter(id => !isNaN(id))
if (ids.length <= 1) return [] // 只有一个部门时不需要选择
// 返回部门列表
return ids.map(id => {
const dept = departmentList.value.find(d => d.id === id)
return dept ? { id: dept.id!, deptName: dept.deptName } : null
}).filter(d => d !== null) as Array<{ id: number, deptName: string }>
}
// 根据部门ID获取部门名称
const getDeptNameFromIds = (deptIds: string): string => {
if (!deptIds) return '所有部门'
@ -1304,7 +1354,8 @@ const handleSubmit = async () => {
taskTypeId: item.taskTypeId!,
quantity: item.quantity,
sortOrder: index + 1,
receiverId: formData.releaseType === 'assigned' ? item.receiverId : undefined
receiverId: formData.releaseType === 'assigned' ? item.receiverId : undefined,
selectedDeptId: item.selectedDeptId // 用户选择的接单部门
})),
brandId: formData.brandId,
platformId: formData.platformId,
@ -2057,6 +2108,10 @@ onUnmounted(() => {
min-width: 150px;
max-width: 200px;
}
.task-type-dept {
flex-shrink: 0;
}
.task-type-actions {
min-width: 90px;