fix: fallback receiving approvals to parent leaders

This commit is contained in:
Your Name 2026-03-31 11:09:37 +08:00
parent 9fa05ac39a
commit b90dbb5594
3 changed files with 161 additions and 53 deletions

View File

@ -273,19 +273,16 @@ public class TaskApprovalService {
// 3. 所有任务都需要接单部门负责人审核(无论是否预先指定了设计师)
String releaseType = task.getReleaseType();
// 确定接单部门和负责人,并把部门落库,避免后续部门调整时出现待审核任务无法追溯归属
Long receivingDeptId = determineReceivingDeptId(task);
Long receivingLeaderId = null;
if (receivingDeptId != null) {
Department receivingDept = departmentMapper.selectById(receivingDeptId);
if (receivingDept != null) {
receivingLeaderId = receivingDept.getLeaderId();
}
}
if (receivingLeaderId == null) {
throw new BusinessException(ResultCode.PARAM_ERROR, "无法确定接单部门负责人,请在系统设置中为接单部门配置负责人");
}
// 确定接单审核部门和负责人。
// 若具体接单小组未配置负责人,则自动回退到最近的有负责人的父级接单部门。
Department receivingApprovalDept = resolveReceivingApprovalDepartment(task);
if (receivingApprovalDept == null || receivingApprovalDept.getLeaderId() == null) {
throw new BusinessException(ResultCode.PARAM_ERROR, "无法确定接单部门负责人,请在系统设置中为接单部门配置负责人");
}
Long receivingDeptId = receivingApprovalDept.getId();
Long receivingLeaderId = receivingApprovalDept.getLeaderId();
// 更新任务状态为待接单部门审核
task.setApprovalStatus("pending_receiving_approval");
@ -1041,12 +1038,7 @@ public class TaskApprovalService {
* 确定接单部门负责人(支持三级分类继承二级分类的配置)
*/
public Long determineReceivingLeader(Task task) {
Long receivingDeptId = determineReceivingDeptId(task);
if (receivingDeptId == null) {
return null;
}
Department dept = departmentMapper.selectById(receivingDeptId);
Department dept = resolveReceivingApprovalDepartment(task);
if (dept == null || dept.getLeaderId() == null) {
return null;
}
@ -1055,6 +1047,62 @@ public class TaskApprovalService {
return dept.getLeaderId();
}
/**
* 确定任务当前应该流转到哪个接单审核部门。
* - 优先保留子任务/任务类型计算出的实际接单部门
* - 如果该部门没有负责人,则自动回退到最近的有负责人的父级接单部门
*/
public Department resolveReceivingApprovalDepartment(Task task) {
Long receivingDeptId = determineReceivingDeptId(task);
if (receivingDeptId == null) {
return null;
}
return resolveNearestReceivingDeptWithLeader(receivingDeptId);
}
private Department resolveNearestReceivingDeptWithLeader(Long deptId) {
if (deptId == null) {
return null;
}
Long currentDeptId = deptId;
Department fallbackDept = null;
while (currentDeptId != null && currentDeptId != 0) {
Department currentDept = departmentMapper.selectById(currentDeptId);
if (currentDept == null) {
break;
}
if (!"receiving".equals(currentDept.getDeptType())
|| !Integer.valueOf(1).equals(currentDept.getStatus())
|| Integer.valueOf(1).equals(currentDept.getDeleted())) {
currentDeptId = currentDept.getParentId();
continue;
}
if (fallbackDept == null) {
fallbackDept = currentDept;
}
if (currentDept.getLeaderId() != null) {
if (!currentDept.getId().equals(deptId)) {
log.info("接单部门 {} 未配置负责人,自动回退到父级部门 {}(负责人ID={})",
deptId, currentDept.getId(), currentDept.getLeaderId());
}
return currentDept;
}
currentDeptId = currentDept.getParentId();
}
if (fallbackDept != null) {
log.warn("接单部门 {} 及其父级接单部门均未配置负责人", deptId);
}
return null;
}
/**
* 应用任务更新
*/

View File

@ -1106,15 +1106,13 @@ public class TaskItemService {
if (!unassignedItems.isEmpty()) {
Set<Long> notifiedLeaderIds = new HashSet<>();
for (TaskItem nextItem : unassignedItems) {
Long targetDeptId = getTargetDeptIdFromTaskType(nextItem.getTaskTypeId());
if (targetDeptId != null) {
com.designhub.entity.Department receiverDept = departmentMapper.selectById(targetDeptId);
if (receiverDept != null && receiverDept.getLeaderId() != null
&& !notifiedLeaderIds.contains(receiverDept.getLeaderId())) {
notifiedLeaderIds.add(receiverDept.getLeaderId());
com.designhub.entity.Department approvalDept = resolveReceivingApprovalDeptForItem(nextItem);
if (approvalDept != null && approvalDept.getLeaderId() != null) {
if (!notifiedLeaderIds.contains(approvalDept.getLeaderId())) {
notifiedLeaderIds.add(approvalDept.getLeaderId());
Notification notification = new Notification();
notification.setReceiverId(receiverDept.getLeaderId());
notification.setReceiverId(approvalDept.getLeaderId());
notification.setNotificationType("task_approval");
notification.setTitle("新子任务组待审核");
notification.setContent("任务《" + mainTask.getTitle() + "》第 " + nextDeptIndex + " 个部门共 " +
@ -1126,10 +1124,10 @@ public class TaskItemService {
notificationService.sendNotification(notification);
log.info("已通知接单部门负责人(部门: {}, 负责人ID: {})审核第 {} 个部门子任务",
receiverDept.getDeptName(), receiverDept.getLeaderId(), nextDeptIndex);
approvalDept.getDeptName(), approvalDept.getLeaderId(), nextDeptIndex);
}
} else {
log.warn("子任务 {} 的任务类型未配置接单部门", nextItem.getItemNo());
log.warn("子任务 {} 无法确定可审核的接单部门负责人", nextItem.getItemNo());
}
}
@ -1355,21 +1353,17 @@ public class TaskItemService {
// 从子任务的任务类型配置获取接单部门
TaskItem firstItem = checkItems.get(0);
Long targetDeptId = getTargetDeptIdFromTaskType(firstItem.getTaskTypeId());
boolean hasPermission = false;
// 检查任务类型配置的接单部门
if (targetDeptId != null) {
com.designhub.entity.Department receiverDept = departmentMapper.selectById(targetDeptId);
if (receiverDept != null && approverId.equals(receiverDept.getLeaderId())) {
hasPermission = true;
}
// 优先检查子任务实际归属的审核部门(支持子部门自动回退到有负责人的父级接单部门)
com.designhub.entity.Department approvalDept = resolveReceivingApprovalDeptForItem(firstItem);
if (approvalDept != null && approverId.equals(approvalDept.getLeaderId())) {
hasPermission = true;
}
// 兼容:也检查主任务的 receiver_dept_id
if (!hasPermission && mainTask.getReceiverDeptId() != null) {
com.designhub.entity.Department receiverDept = departmentMapper.selectById(mainTask.getReceiverDeptId());
com.designhub.entity.Department receiverDept = resolveNearestReceivingDeptWithLeader(mainTask.getReceiverDeptId());
if (receiverDept != null && approverId.equals(receiverDept.getLeaderId())) {
hasPermission = true;
}
@ -1679,7 +1673,7 @@ public class TaskItemService {
// 2. 如果任务已指定接单部门,检查用户是否是该部门的负责人
if (!hasPermission && mainTask.getReceiverDeptId() != null) {
com.designhub.entity.Department receiverDept = departmentMapper.selectById(mainTask.getReceiverDeptId());
com.designhub.entity.Department receiverDept = resolveNearestReceivingDeptWithLeader(mainTask.getReceiverDeptId());
if (receiverDept != null && rejectorId.equals(receiverDept.getLeaderId())) {
hasPermission = true;
log.info("用户 {} 是任务接单部门 {} 的负责人", rejectorId, mainTask.getReceiverDeptId());
@ -1707,7 +1701,7 @@ public class TaskItemService {
);
java.util.Set<Long> groupDeptIds = groupItems.stream()
.map(TaskItem::getReceiverDeptId)
.map(this::resolveReceivingApprovalDeptIdForItem)
.filter(java.util.Objects::nonNull)
.collect(java.util.stream.Collectors.toSet());
@ -1860,6 +1854,13 @@ public class TaskItemService {
hasPermission = true;
log.info("匹配成功(通过任务类型配置)");
}
if (!hasPermission) {
com.designhub.entity.Department approvalDept = resolveReceivingApprovalDeptForItem(item);
if (approvalDept != null && approvalDept.getId().equals(receiverDeptId)) {
hasPermission = true;
log.info("匹配成功(通过子任务接单部门负责人兜底)");
}
}
// 兼容:也检查主任务的 receiver_dept_id
if (!hasPermission && mainTask.getReceiverDeptId() != null
&& mainTask.getReceiverDeptId().equals(receiverDeptId)) {
@ -1975,17 +1976,14 @@ public class TaskItemService {
groupInfo.put("subTaskTypeId", item.getTaskTypeId());
// 添加审核人信息(目标部门负责人)
Long targetDeptId = getTargetDeptIdFromTaskType(item.getTaskTypeId());
if (targetDeptId != null) {
com.designhub.entity.Department targetDept = departmentMapper.selectById(targetDeptId);
if (targetDept != null && targetDept.getLeaderId() != null) {
com.designhub.entity.User leader = userMapper.selectById(targetDept.getLeaderId());
com.designhub.entity.Department approvalDept = resolveReceivingApprovalDeptForItem(item);
if (approvalDept != null && approvalDept.getLeaderId() != null) {
com.designhub.entity.User leader = userMapper.selectById(approvalDept.getLeaderId());
if (leader != null) {
groupInfo.put("currentApproverName", leader.getRealName());
groupInfo.put("currentApproverRole", "receiving_leader");
groupInfo.put("approvalStatus", "pending_receiving_approval");
}
}
}
// 计算子任务组总积分(BigDecimal类型)
@ -2162,6 +2160,73 @@ public class TaskItemService {
com.designhub.entity.Department department = departmentMapper.selectById(deptId);
return department != null ? department.getDeptName() : null;
}
private Long resolveReceivingApprovalDeptIdForItem(TaskItem item) {
com.designhub.entity.Department approvalDept = resolveReceivingApprovalDeptForItem(item);
return approvalDept != null ? approvalDept.getId() : null;
}
private com.designhub.entity.Department resolveReceivingApprovalDeptForItem(TaskItem item) {
if (item == null) {
return null;
}
if (item.getReceiverDeptId() != null) {
com.designhub.entity.Department dept = resolveNearestReceivingDeptWithLeader(item.getReceiverDeptId());
if (dept != null) {
return dept;
}
}
Long targetDeptId = getTargetDeptIdFromTaskType(item.getTaskTypeId());
if (targetDeptId == null) {
return null;
}
return resolveNearestReceivingDeptWithLeader(targetDeptId);
}
private com.designhub.entity.Department resolveNearestReceivingDeptWithLeader(Long deptId) {
if (deptId == null) {
return null;
}
Long currentDeptId = deptId;
com.designhub.entity.Department fallbackDept = null;
while (currentDeptId != null && currentDeptId != 0) {
com.designhub.entity.Department currentDept = departmentMapper.selectById(currentDeptId);
if (currentDept == null) {
break;
}
if (!"receiving".equals(currentDept.getDeptType())
|| currentDept.getStatus() == null || currentDept.getStatus() != 1
|| (currentDept.getDeleted() != null && currentDept.getDeleted() == 1)) {
currentDeptId = currentDept.getParentId();
continue;
}
if (fallbackDept == null) {
fallbackDept = currentDept;
}
if (currentDept.getLeaderId() != null) {
if (!currentDept.getId().equals(deptId)) {
log.info("接单部门 {} 未配置负责人,子任务审核自动回退到父级部门 {}(负责人ID={})",
deptId, currentDept.getId(), currentDept.getLeaderId());
}
return currentDept;
}
currentDeptId = currentDept.getParentId();
}
if (fallbackDept != null) {
log.warn("接单部门 {} 及其父级接单部门均未配置负责人", deptId);
}
return null;
}
/**
* 从子任务编号解析部门序号

View File

@ -4000,14 +4000,9 @@ public class TaskService {
taskApprovalService.logApproval(task.getId(), completerId, 0, "complete_detail", "已完善任务明细");
// 确定接单部门负责人,并把部门归属同步写入任务,避免后续组织架构调整时待审核任务失联
Long receivingDeptId = taskApprovalService.determineReceivingDeptId(task);
Long receivingLeaderId = null;
if (receivingDeptId != null) {
Department receivingDept = departmentService.getDepartmentById(receivingDeptId);
if (receivingDept != null) {
receivingLeaderId = receivingDept.getLeaderId();
}
}
Department receivingApprovalDept = taskApprovalService.resolveReceivingApprovalDepartment(task);
Long receivingDeptId = receivingApprovalDept != null ? receivingApprovalDept.getId() : null;
Long receivingLeaderId = receivingApprovalDept != null ? receivingApprovalDept.getLeaderId() : null;
if (receivingLeaderId != null) {
// 更新任务状态为待接单部门审核
task.setApprovalStatus("pending_receiving_approval");