This commit is contained in:
2026-07-03 08:46:44 +08:00
parent a79280d16d
commit 8c3c6f45c3
2 changed files with 115 additions and 32 deletions
@@ -13,7 +13,6 @@ import com.budwk.app.base.page.Pagination;
import com.budwk.app.base.param.PageForm; import com.budwk.app.base.param.PageForm;
import com.budwk.app.base.result.Result; import com.budwk.app.base.result.Result;
import com.budwk.app.base.service.BaseService; import com.budwk.app.base.service.BaseService;
import com.budwk.app.flow.entity.ProcessTask;
import com.budwk.app.flow.enums.ProcessTaskStateEnum; import com.budwk.app.flow.enums.ProcessTaskStateEnum;
import com.budwk.app.flow.service.ProcessTaskService; import com.budwk.app.flow.service.ProcessTaskService;
import com.budwk.app.sys.models.Sys_role; import com.budwk.app.sys.models.Sys_role;
@@ -173,19 +172,23 @@ public class ProposalConfigUnitController {
int syncActorCount = 0; int syncActorCount = 0;
int skipUnitCount = 0; int skipUnitCount = 0;
for (ProposalUndertake undertake : undertakes) { Map<String, List<String>> unitLeaderMap = undertakes.stream().collect(Collectors.toMap(ProposalUndertake::getId, undertake -> {
List<Sys_user_role> sysUserRoles = dao.query(Sys_user_role.class, Cnd.where(Sys_user_role::getRoleId, "=", sysRole.getId()) List<Sys_user_role> sysUserRoles = dao.query(Sys_user_role.class, Cnd.where(Sys_user_role::getRoleId, "=", sysRole.getId())
.and(Sys_user_role::getUnderTakeId, "=", undertake.getId())); .and(Sys_user_role::getUnderTakeId, "=", undertake.getId()));
List<String> userIds = sysUserRoles.stream().map(Sys_user_role::getUserId).distinct().toList(); return sysUserRoles.stream().map(Sys_user_role::getUserId).filter(StrUtil::isNotBlank).distinct().toList();
if (CollectionUtil.isEmpty(userIds)) { }));
for (ProposalUndertake undertake : undertakes) {
if (CollectionUtil.isEmpty(unitLeaderMap.get(undertake.getId()))) {
skipUnitCount++; skipUnitCount++;
continue;
} }
}
List<ProcessTask> tasks = queryDoingUnitReplyTasks(undertake.getId()); List<NutMap> taskTargets = queryDoingUnitReplyTaskTargets();
scanTaskCount += tasks.size(); scanTaskCount = taskTargets.size();
for (ProcessTask task : tasks) { for (NutMap taskTarget : taskTargets) {
int syncCount = processTaskService.syncTaskActors(task.getId(), userIds); List<String> userIds = unitLeaderMap.get(taskTarget.getString("unitId"));
if (CollectionUtil.isNotEmpty(userIds)) {
int syncCount = processTaskService.syncTaskActors(taskTarget.getLong("taskId"), userIds);
if (syncCount > 0) { if (syncCount > 0) {
syncTaskCount++; syncTaskCount++;
syncActorCount += syncCount; syncActorCount += syncCount;
@@ -197,35 +200,114 @@ public class ProposalConfigUnitController {
} }
/** /**
* 根据承办单位和提案承办单位记录查询正在办理中的答复任务。 * 根据提案承办单位记录计算正在办理中的答复任务与承办单位对应关系
* *
* 说明: * 说明:
* 1. 参数 underTakeId 为 proposal_undertake.id,即当前承办单位配置ID * 1. 无入参,自动扫描当前进行中的主办答复、协办答复、意见主办答复任务
* 2. 不依赖 wf_process_task.variable 中的 underTakeId,避免历史任务变量和承办单位配置不一致导致漏同步 * 2. 返回值为 List<NutMap>,每行包含 taskId 和 unitId,表示该任务应按哪个承办单位负责人同步办理人
* 3. 主办单位只匹配 master_reply、opinion_master_reply,协办单位只匹配 slave_reply * 3. 优先使用 task.variable.underTakeId,其次使用现有 actorUnitId 与 proposal_reply_unit.unitId 的匹配关系
* 4. 返回值为当前仍在办理中的流程任务列表 * 4. 对历史缺少 underTakeId 且 actorUnitId 不匹配承办单位的数据,只在“剩余任务数”和“剩余承办单位数”能一一对应时按顺序补位,避免多个协办单位互相覆盖
*/ */
private List<ProcessTask> queryDoingUnitReplyTasks(String underTakeId) { private List<NutMap> queryDoingUnitReplyTaskTargets() {
Sql sql = Sqls.queryEntity(""" Sql sql = Sqls.create("""
SELECT DISTINCT WITH direct_targets AS (
t.* SELECT DISTINCT
ins.businessNo AS proposalId,
t.id AS taskId,
IF(t.taskName IN ('master_reply', 'opinion_master_reply'), 1, 0) AS isMaster,
pru.unitId AS unitId
FROM
wf_process_task t
INNER JOIN wf_process_instance ins ON ins.id = t.processInstanceId
INNER JOIN proposal_reply_unit pru ON pru.proposalId = ins.businessNo
AND (
(t.taskName IN ('master_reply', 'opinion_master_reply') AND pru.isMaster = 1)
OR (t.taskName = 'slave_reply' AND pru.isMaster = 0)
)
LEFT JOIN wf_process_task_actor ta ON ta.processTaskId = t.id
WHERE
t.taskState = @taskState
AND t.taskName IN ('master_reply', 'slave_reply', 'opinion_master_reply')
AND (
JSON_UNQUOTE(JSON_EXTRACT(t.variable, '$.underTakeId')) = pru.unitId
OR (
IFNULL(JSON_UNQUOTE(JSON_EXTRACT(t.variable, '$.underTakeId')), '') = ''
AND ta.actorUnitId = pru.unitId
)
)
),
remain_units AS (
SELECT
pru.proposalId,
pru.unitId,
pru.unitName,
pru.isMaster,
ROW_NUMBER() OVER(PARTITION BY pru.proposalId, pru.isMaster ORDER BY pru.unitName, pru.unitId) AS rn,
COUNT(*) OVER(PARTITION BY pru.proposalId, pru.isMaster) AS unitCount
FROM
proposal_reply_unit pru
WHERE
EXISTS (
SELECT 1
FROM wf_process_instance ins
INNER JOIN wf_process_task t ON t.processInstanceId = ins.id
WHERE ins.businessNo = pru.proposalId
AND t.taskState = @taskState
AND (
(t.taskName IN ('master_reply', 'opinion_master_reply') AND pru.isMaster = 1)
OR (t.taskName = 'slave_reply' AND pru.isMaster = 0)
)
)
AND NOT EXISTS (
SELECT 1
FROM direct_targets dt
WHERE dt.proposalId = pru.proposalId
AND dt.unitId = pru.unitId
)
),
remain_tasks AS (
SELECT
ins.businessNo AS proposalId,
t.id AS taskId,
IF(t.taskName IN ('master_reply', 'opinion_master_reply'), 1, 0) AS isMaster,
ROW_NUMBER() OVER(
PARTITION BY ins.businessNo, IF(t.taskName IN ('master_reply', 'opinion_master_reply'), 1, 0)
ORDER BY t.id
) AS rn,
COUNT(*) OVER(
PARTITION BY ins.businessNo, IF(t.taskName IN ('master_reply', 'opinion_master_reply'), 1, 0)
) AS taskCount
FROM
wf_process_task t
INNER JOIN wf_process_instance ins ON ins.id = t.processInstanceId
WHERE
t.taskState = @taskState
AND t.taskName IN ('master_reply', 'slave_reply', 'opinion_master_reply')
AND IFNULL(JSON_UNQUOTE(JSON_EXTRACT(t.variable, '$.underTakeId')), '') = ''
AND NOT EXISTS (
SELECT 1
FROM direct_targets dt
WHERE dt.taskId = t.id
)
)
SELECT
taskId,
unitId
FROM FROM
wf_process_task t direct_targets
INNER JOIN wf_process_instance ins ON ins.id = t.processInstanceId UNION
INNER JOIN proposal_reply_unit pru ON pru.proposalId = ins.businessNo SELECT
AND pru.unitId = @underTakeId rt.taskId,
WHERE ru.unitId
t.taskState = @taskState FROM
AND ( remain_tasks rt
(t.taskName IN ('master_reply', 'opinion_master_reply') AND pru.isMaster = 1) INNER JOIN remain_units ru ON ru.proposalId = rt.proposalId
OR (t.taskName = 'slave_reply' AND pru.isMaster = 0) AND ru.isMaster = rt.isMaster
) AND ru.rn = rt.rn
AND ru.unitCount = rt.taskCount
"""); """);
sql.setParam("underTakeId", underTakeId);
sql.setParam("taskState", ProcessTaskStateEnum.DOING.getCode()); sql.setParam("taskState", ProcessTaskStateEnum.DOING.getCode());
sql.setEntity(dao.getEntity(ProcessTask.class)); return baseService.listMap(sql);
dao.execute(sql);
return sql.getList(ProcessTask.class);
} }
/** /**
@@ -132,6 +132,7 @@ public class ProposalUnderTakeReplyController {
LEFT JOIN proposal_type type on type.id = info.typeId LEFT JOIN proposal_type type on type.id = info.typeId
LEFT JOIN proposal_merge mer ON mer.proposalId = info.id LEFT JOIN proposal_merge mer ON mer.proposalId = info.id
LEFT JOIN proposal_reply_unit pru ON pru.proposalId = ins.businessNo LEFT JOIN proposal_reply_unit pru ON pru.proposalId = ins.businessNo
AND pru.unitId = IFNULL(t.variable->>'$.underTakeId', ta.actorUnitId)
AND ( AND (
(t.taskName IN ('master_reply', 'opinion_master_reply') AND pru.isMaster = 1) (t.taskName IN ('master_reply', 'opinion_master_reply') AND pru.isMaster = 1)
OR (t.taskName = 'slave_reply' AND pru.isMaster = 0) OR (t.taskName = 'slave_reply' AND pru.isMaster = 0)