fix: expand receiving department children for task type routing

This commit is contained in:
Your Name 2026-03-28 15:05:45 +08:00
parent c76551bef2
commit 462e1a4e88
6 changed files with 149 additions and 95 deletions

View File

@ -646,6 +646,63 @@ public class DepartmentService {
log.info("获取部门{}的所有子部门ID: {}", deptId, result);
return result;
}
/**
* 获取部门自身及所有子部门ID
*/
public List<Long> getDeptAndChildIds(Long deptId) {
if (deptId == null) {
return Collections.emptyList();
}
List<Long> result = new ArrayList<>();
result.add(deptId);
result.addAll(getAllChildDeptIds(deptId));
return result.stream().distinct().collect(Collectors.toList());
}
/**
* 展开逗号分隔的部门ID,自动包含所有子部门
*/
public List<Long> expandDeptIdsWithChildren(String deptIdsText) {
if (!StringUtils.hasText(deptIdsText)) {
return Collections.emptyList();
}
List<Long> deptIds = Arrays.stream(deptIdsText.split(","))
.map(String::trim)
.filter(StringUtils::hasText)
.map(idText -> {
try {
return Long.parseLong(idText);
} catch (NumberFormatException e) {
log.warn("解析部门ID失败: {}", idText);
return null;
}
})
.filter(Objects::nonNull)
.collect(Collectors.toList());
return expandDeptIdsWithChildren(deptIds);
}
/**
* 展开部门ID列表,自动包含所有子部门
*/
public List<Long> expandDeptIdsWithChildren(List<Long> deptIds) {
if (CollectionUtils.isEmpty(deptIds)) {
return Collections.emptyList();
}
java.util.LinkedHashSet<Long> result = new java.util.LinkedHashSet<>();
for (Long deptId : deptIds) {
if (deptId == null) {
continue;
}
result.addAll(getDeptAndChildIds(deptId));
}
return new ArrayList<>(result);
}
/**
* 检查用户是否为任何部门的负责人
@ -665,4 +722,3 @@ public class DepartmentService {
return count != null && count > 0;
}
}

View File

@ -39,6 +39,7 @@ public class TaskApprovalService {
private final CategoryMapper categoryMapper;
private final PlatformMapper platformMapper;
private final NotificationService notificationService;
private final DepartmentService departmentService;
private final TeamScorePoolService teamScorePoolService;
@org.springframework.beans.factory.annotation.Autowired
@ -1013,9 +1014,8 @@ public class TaskApprovalService {
}
if (allowedDeptIds != null && !allowedDeptIds.isEmpty()) {
String[] deptIds = allowedDeptIds.split(",");
if (deptIds.length > 0) {
Long deptId = Long.parseLong(deptIds[0].trim());
List<Long> expandedDeptIds = departmentService.expandDeptIdsWithChildren(allowedDeptIds);
for (Long deptId : expandedDeptIds) {
Department dept = departmentMapper.selectById(deptId);
if (dept != null && dept.getLeaderId() != null) {
log.info("从任务类型配置获取接单部门负责人(降级方案): 部门={}, 负责人ID={}",

View File

@ -132,19 +132,7 @@ public class TaskItemService {
if (allowedDepts == null || allowedDepts.isEmpty()) {
return false;
}
String[] deptIds = allowedDepts.split(",");
for (String deptIdStr : deptIds) {
try {
Long deptId = Long.parseLong(deptIdStr.trim());
// 🔥 检查是否匹配筛选部门或其子部门
if (filterDeptAndChildIds.contains(deptId)) {
return true;
}
} catch (NumberFormatException e) {
// 忽略无效的部门ID
}
}
return false;
return expandAllowedDeptIds(allowedDepts).stream().anyMatch(filterDeptAndChildIds::contains);
})
.map(com.designhub.entity.DemandType::getId)
.collect(java.util.stream.Collectors.toList());
@ -369,23 +357,7 @@ public class TaskItemService {
if (allowedDeptIds == null || allowedDeptIds.isBlank()) {
return java.util.Collections.emptyList();
}
List<Long> result = new java.util.ArrayList<>();
Set<Long> seen = new java.util.HashSet<>();
for (String deptIdText : allowedDeptIds.split(",")) {
if (deptIdText == null || deptIdText.isBlank()) {
continue;
}
try {
Long deptId = Long.parseLong(deptIdText.trim());
if (seen.add(deptId)) {
result.add(deptId);
}
} catch (NumberFormatException e) {
log.warn("解析排队部门ID失败: taskItemId={}, deptIdText={}", item.getId(), deptIdText);
}
}
return result;
return new java.util.ArrayList<>(expandAllowedDeptIds(allowedDeptIds));
}
private int getDeptDistance(Long userDeptId, Long targetDeptId) {
@ -1883,11 +1855,11 @@ public class TaskItemService {
log.info("管理员模式,有权限");
} else {
// 部门负责人:检查子任务的任务类型配置的 allowed_dept_ids 是否包含该部门
Long targetDeptId = getTargetDeptIdFromTaskType(item.getTaskTypeId());
log.info("子任务 {} 的目标部门ID: {}, 查询的部门ID: {}",
item.getId(), targetDeptId, receiverDeptId);
List<Long> targetDeptIds = getTargetDeptIdsFromTaskType(item.getTaskTypeId());
log.info("子任务 {} 的目标部门ID列表: {}, 查询的部门ID: {}",
item.getId(), targetDeptIds, receiverDeptId);
if (targetDeptId != null && targetDeptId.equals(receiverDeptId)) {
if (targetDeptIds.contains(receiverDeptId)) {
hasPermission = true;
log.info("匹配成功(通过任务类型配置)");
}
@ -2108,17 +2080,22 @@ public class TaskItemService {
* 如果当前类型未配置,则递归向上查找父级类型的配置
*/
private Long getTargetDeptIdFromTaskType(Long taskTypeId) {
List<Long> targetDeptIds = getTargetDeptIdsFromTaskType(taskTypeId);
return targetDeptIds.isEmpty() ? null : targetDeptIds.get(0);
}
private List<Long> getTargetDeptIdsFromTaskType(Long taskTypeId) {
log.debug("getTargetDeptIdFromTaskType 调用, taskTypeId: {}", taskTypeId);
if (taskTypeId == null) {
log.debug("taskTypeId 为空,返回 null");
return null;
return java.util.Collections.emptyList();
}
com.designhub.entity.DemandType taskType = demandTypeMapper.selectById(taskTypeId);
if (taskType == null) {
log.warn("任务类型 {} 不存在", taskTypeId);
return null;
return java.util.Collections.emptyList();
}
log.debug("任务类型: id={}, name={}, parentId={}, allowedDeptIds={}",
@ -2127,26 +2104,42 @@ public class TaskItemService {
// 如果当前类型配置了allowed_dept_ids,返回第一个部门ID
String allowedDeptIds = taskType.getAllowedDeptIds();
if (allowedDeptIds != null && !allowedDeptIds.isEmpty()) {
try {
String[] deptIds = allowedDeptIds.split(",");
if (deptIds.length > 0) {
Long result = Long.parseLong(deptIds[0].trim());
log.debug("找到 allowed_dept_ids: {}, 返回第一个: {}", allowedDeptIds, result);
return result;
}
} catch (NumberFormatException e) {
log.warn("解析allowed_dept_ids失败: {}", allowedDeptIds, e);
List<Long> expandedDeptIds = new java.util.ArrayList<>(expandAllowedDeptIds(allowedDeptIds));
if (!expandedDeptIds.isEmpty()) {
log.debug("找到 allowed_dept_ids: {}, 展开后返回: {}", allowedDeptIds, expandedDeptIds);
return expandedDeptIds;
}
}
// 如果当前类型未配置,递归查找父级
if (taskType.getParentId() != null) {
log.debug("当前类型未配置 allowed_dept_ids, 递归查找父级: {}", taskType.getParentId());
return getTargetDeptIdFromTaskType(taskType.getParentId());
return getTargetDeptIdsFromTaskType(taskType.getParentId());
}
log.debug("未找到配置的部门,返回 null");
return null;
return java.util.Collections.emptyList();
}
private Set<Long> expandAllowedDeptIds(String allowedDeptIds) {
Set<Long> result = new java.util.LinkedHashSet<>();
if (allowedDeptIds == null || allowedDeptIds.trim().isEmpty()) {
return result;
}
for (String deptIdText : allowedDeptIds.split(",")) {
if (deptIdText == null || deptIdText.isBlank()) {
continue;
}
try {
Long deptId = Long.parseLong(deptIdText.trim());
result.addAll(getDeptAndChildIds(deptId));
} catch (NumberFormatException e) {
log.warn("解析接单部门ID失败: {}", deptIdText);
}
}
return result;
}
private void markPipelineItemUnlocked(TaskItem item) {

View File

@ -1260,14 +1260,8 @@ public class TaskService {
if (allowedDepts == null || allowedDepts.isEmpty()) {
return true;
}
// 检查用户部门是否在允许列表中
String[] deptIds = allowedDepts.split(",");
for (String deptId : deptIds) {
if (deptId.trim().equals(String.valueOf(userDeptId))) {
return true;
}
}
return false;
// 选择父级接单部门时,运行时需要自动覆盖所有子部门。
return expandAllowedDeptIds(allowedDepts).contains(userDeptId);
})
.map(DemandType::getId)
.collect(Collectors.toList());
@ -1294,19 +1288,7 @@ public class TaskService {
if (allowedDepts == null || allowedDepts.isEmpty()) {
return false; // 所有部门都可接单的不纳入筛选结果
}
String[] deptIds = allowedDepts.split(",");
for (String deptIdStr : deptIds) {
try {
Long deptId = Long.parseLong(deptIdStr.trim());
// 🔥 检查是否匹配筛选部门或其子部门
if (filterDeptAndChildSet.contains(deptId)) {
return true;
}
} catch (NumberFormatException e) {
// 忽略无效的部门ID
}
}
return false;
return expandAllowedDeptIds(allowedDepts).stream().anyMatch(filterDeptAndChildSet::contains);
})
.map(DemandType::getId)
.collect(Collectors.toList());
@ -4263,6 +4245,28 @@ public class TaskService {
collectChildDeptIds(deptId, result);
return result;
}
private Set<Long> expandAllowedDeptIds(String allowedDeptIds) {
Set<Long> result = new HashSet<>();
if (!StringUtils.hasText(allowedDeptIds)) {
return result;
}
for (String deptIdText : allowedDeptIds.split(",")) {
String trimmed = deptIdText == null ? "" : deptIdText.trim();
if (trimmed.isEmpty()) {
continue;
}
try {
Long deptId = Long.parseLong(trimmed);
result.addAll(getDeptAndChildIds(deptId));
} catch (NumberFormatException e) {
log.warn("解析接单部门ID失败: {}", deptIdText);
}
}
return result;
}
/**
* 递归收集所有子部门ID

View File

@ -40,6 +40,9 @@ public class TaskUnlockService {
@Autowired
private DemandTypeMapper demandTypeMapper;
@Autowired
private DepartmentService departmentService;
@Autowired
private TaskStatusNotificationService taskStatusNotificationService;
@ -744,27 +747,7 @@ public class TaskUnlockService {
if (allowedDeptIds == null || allowedDeptIds.trim().isEmpty()) {
return Collections.emptyList();
}
String[] parts = allowedDeptIds.split(",");
List<Long> result = new ArrayList<>();
Set<Long> seen = new HashSet<>();
for (String part : parts) {
if (part == null) {
continue;
}
String s = part.trim();
if (s.isEmpty()) {
continue;
}
try {
Long id = Long.parseLong(s);
if (seen.add(id)) {
result.add(id);
}
} catch (NumberFormatException e) {
// 忽略
}
}
return result;
return departmentService.expandDeptIdsWithChildren(allowedDeptIds);
}
/**

View File

@ -4351,6 +4351,24 @@ const flatDepartmentOptions = computed(() => {
return groups
})
const expandReceivingDepartmentIds = (selectedDeptIds: number[] = []) => {
const expanded = new Set<number>()
const appendDeptAndChildren = (deptId?: number) => {
if (!deptId || expanded.has(deptId)) {
return
}
expanded.add(deptId)
departments.value
.filter(d => d.parentId === deptId && d.deptType === 'receiving' && d.status === 1)
.forEach(child => appendDeptAndChildren(child.id))
}
selectedDeptIds.forEach(id => appendDeptAndChildren(id))
return Array.from(expanded)
}
// 根据部门ID字符串获取部门名称
const getDeptNamesFromIds = (idsStr: string) => {
if (!idsStr) return ''
@ -5175,9 +5193,9 @@ const saveDemandType = async () => {
isEnabled: formData.demandType.isEnabled ?? 1,
// 父级ID(二级、三级分类需要设置)
parentId: (addLevel === 'level2' || addLevel === 'level3') ? formData.demandType.parentId : null,
// 将部门ID数组转换为逗号分隔的字符串(仅二级分类需要设置)
// 选择父级接单部门时,同时持久化所有子级接单部门,保证运行时精确匹配也能命中。
allowedDeptIds: addLevel === 'level2' && formData.demandType.departmentIds?.length > 0
? formData.demandType.departmentIds.join(',')
? expandReceivingDepartmentIds(formData.demandType.departmentIds).join(',')
: null
}