diff --git a/pom.xml b/pom.xml index d94b5b69..4ee8f7b7 100644 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ 4.0.0 jar com.budwk - zhgh_hdc + mini 5.6.0-plus 2.6.0-SNAPSHOT diff --git a/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/transact/ProposalSecondedController.java b/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/transact/ProposalSecondedController.java index 349fded1..a2d1d7dd 100644 --- a/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/transact/ProposalSecondedController.java +++ b/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/transact/ProposalSecondedController.java @@ -108,9 +108,10 @@ public class ProposalSecondedController { Cnd cnd = Cnd.NEW(); cnd.and("t.taskName", "=", "second"); - if (!AuthUtil.hasRole(RoleConstant.SYSADMIN.name())) { + /* if (!AuthUtil.hasRole(RoleConstant.SYSADMIN.name())) { cnd.and("ta.actorId", "in", List.of(SecurityUtil.getUserId())); - } + }*/ + cnd.and("ta.actorId", "in", List.of(SecurityUtil.getUserId())); if (approval) { cnd.and("t.taskState", "in", List.of(ProcessTaskStateEnum.FINISHED.getCode(), ProcessTaskStateEnum.INTERRUPT.getCode())); @@ -151,9 +152,10 @@ public class ProposalSecondedController { cnd.and("t.taskState", "=", ProcessTaskStateEnum.DOING.getCode()); cnd.andEX("info.sessionId", "=", sessionId); - if (!AuthUtil.hasRole(RoleConstant.SYSADMIN.name())) { + /* if (!AuthUtil.hasRole(RoleConstant.SYSADMIN.name())) { cnd.and("ta.actorId", "in", List.of(SecurityUtil.getUserId())); - } + }*/ + cnd.and("ta.actorId", "in", List.of(SecurityUtil.getUserId())); sql.setCondition(cnd); return Result.success(baseService.count(sql)); diff --git a/src/main/java/com/budwk/app/zhgh/democratic/proposal/service/ProposalSecondedService.java b/src/main/java/com/budwk/app/zhgh/democratic/proposal/service/ProposalSecondedService.java index d7c86a0c..6a05049b 100644 --- a/src/main/java/com/budwk/app/zhgh/democratic/proposal/service/ProposalSecondedService.java +++ b/src/main/java/com/budwk/app/zhgh/democratic/proposal/service/ProposalSecondedService.java @@ -7,7 +7,7 @@ import com.budwk.app.zhgh.democratic.proposal.models.ProposalSecond; public interface ProposalSecondedService extends BaseService { /** - * 保存受邀附议办理结果,并在“受邀附议 + 主动附议”总同意人数达到 2 人时自动推进到团长审核。 + * 保存受邀附议办理结果,并在受邀附议同意人数达到配置数量时自动推进到团长审核。 * * @param proposalId 提案ID * @param taskActorUserId 受邀附议办理人ID @@ -18,7 +18,8 @@ public interface ProposalSecondedService extends BaseService { Result updateInviteSecondInfo(String proposalId, String taskActorUserId, String opinion, Integer submitType); /** - * 保存主动附议结果,并在“受邀附议 + 主动附议”总同意人数达到 2 人时自动推进到团长审核。 + * 保存主动附议结果。 + * 主动附议只记录业务附议人信息,不参与工作流会签统计,也不触发流程自动推进。 * * @param proposalId 提案ID * @param opinion 附议意见 diff --git a/src/main/java/com/budwk/app/zhgh/democratic/proposal/service/common/ProposalCommonServiceImpl.java b/src/main/java/com/budwk/app/zhgh/democratic/proposal/service/common/ProposalCommonServiceImpl.java index 960daa0a..79a816d8 100644 --- a/src/main/java/com/budwk/app/zhgh/democratic/proposal/service/common/ProposalCommonServiceImpl.java +++ b/src/main/java/com/budwk/app/zhgh/democratic/proposal/service/common/ProposalCommonServiceImpl.java @@ -1,6 +1,7 @@ package com.budwk.app.zhgh.democratic.proposal.service.common; import cn.hutool.core.date.DateUtil; +import cn.hutool.core.lang.Dict; import cn.hutool.core.util.NumberUtil; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; @@ -15,6 +16,7 @@ import com.budwk.app.flow.engine.FlowEngine; import com.budwk.app.flow.engine.util.FlowUtil; import com.budwk.app.flow.entity.ProcessInstance; import com.budwk.app.flow.entity.ProcessTask; +import com.budwk.app.flow.enums.ProcessSubmitTypeEnum; import com.budwk.app.flow.enums.ProcessTaskStateEnum; import com.budwk.app.flow.vo.ProcessTaskVO; import com.budwk.app.sys.models.Sys_dict; @@ -143,7 +145,9 @@ public class ProposalCommonServiceImpl extends BaseServiceImpl imp List positiveSecondList = dao().query( ProposalSecond.class, - Cnd.where(ProposalSecond::getProposalId, "=", id).and(ProposalSecond::getMode, "=", false) + Cnd.where(ProposalSecond::getProposalId, "=", id) + .and(ProposalSecond::getMode, "=", false) + .asc(ProposalSecond::getSecondedTime) ); info.put("positiveSecondList", positiveSecondList); return info; @@ -217,6 +221,20 @@ public class ProposalCommonServiceImpl extends BaseServiceImpl imp // 按任务节点分组 Map> taskGroups = doneTaskVos.stream().collect(Collectors.groupingBy(ProcessTaskVO::getDisplayName)); + // 主动附议不进入工作流,但 Word 模板的附议人明细仍使用“提案附议”分组渲染。 + // 这里把 proposal_second 中的主动附议业务记录转换成模板可识别的任务数据,和受邀附议一起导出。 + List positiveSecondList = dao().query( + ProposalSecond.class, + Cnd.where(ProposalSecond::getProposalId, "=", id) + .and(ProposalSecond::getMode, "=", false) + .asc(ProposalSecond::getSecondedTime) + ); + if (Lang.isNotEmpty(positiveSecondList)) { + List proposalSecondTasks = taskGroups.computeIfAbsent("提案附议", key -> new ArrayList<>()); + for (ProposalSecond positiveSecond : positiveSecondList) { + proposalSecondTasks.add(buildPositiveSecondTaskVO(processInstance.getId(), positiveSecond)); + } + } docData.putAll(taskGroups); LoopRowTableRenderPolicy policy = new LoopRowTableRenderPolicy(); @@ -238,6 +256,37 @@ public class ProposalCommonServiceImpl extends BaseServiceImpl imp } } + /** + * 将主动附议业务记录转换成 Word 模板已支持的流程任务结构。 + * + * @param processInstanceId 流程实例 ID,用于保持导出数据与当前提案流程关联 + * @param positiveSecond 主动附议记录,包含附议人、附议时间、附议意见和附议结果 + * @return ProcessTaskVO,放入“提案附议”模板分组后可复用现有 Word 表格渲染 + */ + private ProcessTaskVO buildPositiveSecondTaskVO(Long processInstanceId, ProposalSecond positiveSecond) { + ProcessTaskVO taskVO = new ProcessTaskVO(); + taskVO.setProcessInstanceId(processInstanceId); + taskVO.setTaskName("second"); + taskVO.setDisplayName("提案附议"); + taskVO.setTaskState(ProcessTaskStateEnum.FINISHED.getCode()); + taskVO.setOperator(positiveSecond.getSeconderId()); + taskVO.setFinishTime(positiveSecond.getSecondedTime()); + + Dict variable = Dict.create(); + variable.put(FlowConst.SUBMIT_TYPE, Boolean.TRUE.equals(positiveSecond.getIsAgree()) + ? ProcessSubmitTypeEnum.AGREE.getCode() + : ProcessSubmitTypeEnum.COUNTERSIGN_DISAGREE.getCode()); + variable.put(FlowConst.TASK_FORM_DATA_PREFIX + "userName", positiveSecond.getUserName()); + variable.put(FlowConst.TASK_FORM_DATA_PREFIX + "loginName", positiveSecond.getLoginName()); + variable.put(FlowConst.TASK_FORM_DATA_PREFIX + "unitName", positiveSecond.getUnitName()); + variable.put(FlowConst.TASK_FORM_DATA_PREFIX + "unionName", positiveSecond.getUnionName()); + variable.put(FlowConst.TASK_FORM_DATA_PREFIX + "delegationName", positiveSecond.getDelegationName()); + variable.put(FlowConst.TASK_FORM_DATA_PREFIX + "opinion", positiveSecond.getOpinion()); + variable.put(FlowConst.TASK_FORM_DATA_PREFIX + "secondedMode", "主动附议"); + taskVO.setVariable(Json.toJson(variable)); + return taskVO; + } + @Override public void exportProposalFeedBackAsDocx(String id, ByteArrayOutputStream byteArrayOutputStream) { if (id == null || id.isEmpty()) { diff --git a/src/main/java/com/budwk/app/zhgh/democratic/proposal/service/impl/ProposalExportServiceImpl.java b/src/main/java/com/budwk/app/zhgh/democratic/proposal/service/impl/ProposalExportServiceImpl.java index 8264bc23..1d970bac 100644 --- a/src/main/java/com/budwk/app/zhgh/democratic/proposal/service/impl/ProposalExportServiceImpl.java +++ b/src/main/java/com/budwk/app/zhgh/democratic/proposal/service/impl/ProposalExportServiceImpl.java @@ -19,6 +19,7 @@ import com.budwk.app.sys.models.Sys_dict; import com.budwk.app.sys.services.SysDictService; import com.budwk.app.web.commons.base.Globals; import com.budwk.app.zhgh.democratic.proposal.models.ProposalInfo; +import com.budwk.app.zhgh.democratic.proposal.models.ProposalSecond; import com.budwk.app.zhgh.democratic.proposal.param.ProposalQueryComprehensiveParam; import com.budwk.app.zhgh.democratic.proposal.service.ProposalExportService; import com.budwk.app.zhgh.democratic.proposal.service.common.ProposalCommonService; @@ -196,24 +197,7 @@ public class ProposalExportServiceImpl extends BaseServiceImpl imp list.get(i).put("brief", HtmlUtil.cleanHtmlTag(list.get(i).getString("brief"))); list.get(i).put("measures", HtmlUtil.cleanHtmlTag(list.get(i).getString("measures"))); - // 流程实例 - ProcessInstance instance = dao().fetch(ProcessInstance.class, Cnd.where(ProcessInstance::getBusinessNo, "=", list.get(i).getString("id"))); - - // 查询附议人信息 - ProcessTask inviteTask = dao().fetch(ProcessTask.class, - Cnd.where(ProcessTask::getProcessInstanceId, "=", instance.getId()) - .and(ProcessTask::getTaskName, "=", "invite") - .and(ProcessTask::getTaskState, "in", - List.of(ProcessTaskStateEnum.DOING.getCode(), ProcessTaskStateEnum.FINISHED.getCode())) - .desc(ProcessTask::getCreatedAt)); - - if (inviteTask != null) { - NutMap variable = Json.fromJson(NutMap.class, inviteTask.getVariable()); - List seconders = variable.getAsList(FlowConst.TASK_FORM_DATA_PREFIX + "seconder", NutMap.class); - if (Lang.isNotEmpty(seconders)) { - list.get(i).put("secondedUserNames", seconders.stream().map(v -> v.getString("userName")).collect(Collectors.joining(","))); - } - } + list.get(i).put("secondedUserNames", buildSecondedUserNames(list.get(i).getString("id"))); } List exportEntities = new ArrayList<>(); @@ -225,7 +209,7 @@ public class ProposalExportServiceImpl extends BaseServiceImpl imp exportEntities.add(new ExcelExportEntity("代表建议措施", "measures", 40)); exportEntities.add(new ExcelExportEntity("提案人", "createUserName", 20)); exportEntities.add(new ExcelExportEntity("提案人电话", "mobile", 20)); - exportEntities.add(new ExcelExportEntity("附议人(两名)", "secondedUserNames", 20)); + exportEntities.add(new ExcelExportEntity("附议人", "secondedUserNames", 20)); exportEntities.add(new ExcelExportEntity("提案单位", "unitName", 20)); // exportEntities.add(new ExcelExportEntity("拟交办单位", "", 20)); @@ -239,6 +223,30 @@ public class ProposalExportServiceImpl extends BaseServiceImpl imp CommonDownloadUtil.download(title + ".xlsx", workbook, response); } + /** + * 汇总表附议人统一从 proposal_second 获取。 + * 邀请附议和主动附议都会写入该表,这里只负责导出附议人姓名,不再依赖流程任务变量。 + * + * @param proposalId 提案 ID + * @return 附议人姓名字符串,多个附议人用逗号分隔;无附议人时返回空字符串 + */ + private String buildSecondedUserNames(String proposalId) { + List seconds = dao().query( + ProposalSecond.class, + Cnd.where(ProposalSecond::getProposalId, "=", proposalId) + .asc(ProposalSecond::getInviteTime) + .asc(ProposalSecond::getSecondedTime) + ); + if (Lang.isEmpty(seconds)) { + return ""; + } + return seconds.stream() + .map(ProposalSecond::getUserName) + .filter(StrUtil::isNotBlank) + .distinct() + .collect(Collectors.joining(",")); + } + @Override public void exportProposalRegisterSummaryAsExcel(ProposalQueryComprehensiveParam pageForm, HttpServletResponse response) { Sql sql = exportComprehensiveSql(pageForm); diff --git a/src/main/java/com/budwk/app/zhgh/democratic/proposal/service/impl/ProposalSecondedServiceImpl.java b/src/main/java/com/budwk/app/zhgh/democratic/proposal/service/impl/ProposalSecondedServiceImpl.java index c16d8561..f8c17722 100644 --- a/src/main/java/com/budwk/app/zhgh/democratic/proposal/service/impl/ProposalSecondedServiceImpl.java +++ b/src/main/java/com/budwk/app/zhgh/democratic/proposal/service/impl/ProposalSecondedServiceImpl.java @@ -12,6 +12,7 @@ import com.budwk.app.flow.entity.ProcessTask; import com.budwk.app.flow.enums.ProcessSubmitTypeEnum; import com.budwk.app.web.commons.auth.utils.SecurityUtil; import com.budwk.app.sys.views.View_user; +import com.budwk.app.zhgh.democratic.proposal.models.ProposalConfig; import com.budwk.app.zhgh.democratic.proposal.models.ProposalInfo; import com.budwk.app.zhgh.democratic.proposal.models.ProposalSecond; import com.budwk.app.zhgh.democratic.proposal.service.ProposalSecondedService; @@ -44,6 +45,7 @@ public class ProposalSecondedServiceImpl extends BaseServiceImpl ProposalSecond.class, Cnd.where(ProposalSecond::getProposalId, "=", proposalId) .and(ProposalSecond::getSeconderId, "=", taskActorUserId) + .and(ProposalSecond::getMode, "=", true) ); if (proposalSecond == null) { return Result.error("未查询到附议记录"); @@ -113,15 +115,13 @@ public class ProposalSecondedServiceImpl extends BaseServiceImpl seconded.setIsAgree(ObjectUtil.equals(submitType, ProcessSubmitTypeEnum.AGREE.getCode())); dao().insert(seconded); - if (ObjectUtil.equals(submitType, ProcessSubmitTypeEnum.AGREE.getCode())) { - autoAdvanceToDelegationWhenEnoughSeconders(proposalId); - } + // 主动附议只做业务留痕,不参与 second 会签统计,也不触发流程自动流转。 return Result.success(); } /** - * 统一按 proposal_second 里的“同意附议”人数判断是否已满足 2 人附议。 - * 一旦满足 2 人,就用系统自动执行一个仍处于办理中的 second 任务来触发流程引擎会签合并, + * 只按受邀附议记录判断是否达到配置的附议人数。 + * 一旦满足配置数量,就用系统自动执行一个仍处于办理中的 second 任务来触发流程引擎会签合并, * 这样 second 节点会自动废弃其余未办任务,并按流程定义流转到 delegation 节点。 */ private void autoAdvanceToDelegationWhenEnoughSeconders(String proposalId) { @@ -130,12 +130,18 @@ public class ProposalSecondedServiceImpl extends BaseServiceImpl return; } + ProposalConfig proposalConfig = dao().fetch(ProposalConfig.class, Cnd.NEW()); + if (proposalConfig == null || proposalConfig.getSeconderNum() == null) { + return; + } + long agreeCount = dao().count( ProposalSecond.class, Cnd.where(ProposalSecond::getProposalId, "=", proposalId) + .and(ProposalSecond::getMode, "=", true) .and(ProposalSecond::getIsAgree, "=", true) ); - if (agreeCount < 2) { + if (agreeCount < proposalConfig.getSeconderNum()) { return; } int mergedCompletedCount = (int) Math.max(agreeCount - 1, 0); @@ -145,8 +151,8 @@ public class ProposalSecondedServiceImpl extends BaseServiceImpl return; } - // 当前流程仍停留在 second 会签节点时,把“已同意附议人数”桥接到会签变量里。 - // 这样系统自动完成一个 second 任务后,会签节点会按“累计 2 个同意”直接合并到团长审核。 + // 当前流程仍停留在 second 会签节点时,把“受邀同意附议人数”桥接到会签变量里。 + // 这样系统自动完成一个 second 任务后,会签节点会按配置的受邀附议人数合并到团长审核。 String prefix = FlowConst.COUNTERSIGN_VARIABLE_PREFIX + "second_"; Dict instanceVariable = Dict.create(); instanceVariable.put(prefix + FlowConst.NR_OF_COMPLETED_INSTANCES, mergedCompletedCount); diff --git a/src/main/resources/views/platform/zhgh/democratic/proposal/common/info.js b/src/main/resources/views/platform/zhgh/democratic/proposal/common/info.js index 167b1509..ebc917a5 100644 --- a/src/main/resources/views/platform/zhgh/democratic/proposal/common/info.js +++ b/src/main/resources/views/platform/zhgh/democratic/proposal/common/info.js @@ -146,7 +146,8 @@ const PROPOSAL_INFO = { - +