From 5d565a3068f6cb576075e8db023c3af5ef7e3c30 Mon Sep 17 00:00:00 2001 From: ye1023 <12588209+ye1023@user.noreply.gitee.com> Date: Tue, 28 Jul 2026 10:42:48 +0800 Subject: [PATCH 01/12] =?UTF-8?q?yxk-20260728=20=E6=94=B9=E5=96=84?= =?UTF-8?q?=E6=8F=90=E6=A1=88=20=E5=A2=9E=E5=8A=A0=E6=89=80=E7=BA=A7?= =?UTF-8?q?=E8=AF=84=E8=AE=AE=E9=A2=86=E5=AF=BC=E5=90=8D=E5=8D=95=E5=AD=97?= =?UTF-8?q?=E6=AE=B5=EF=BC=8C=E6=B5=81=E7=A8=8B=E4=B8=AD=E4=BC=9A=E7=94=A8?= =?UTF-8?q?=E5=88=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../improvementproposal/entity/ImprovementProposal.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/jeecg-module-supervision/src/main/java/org/jeecg/modules/improvementproposal/entity/ImprovementProposal.java b/jeecg-module-supervision/src/main/java/org/jeecg/modules/improvementproposal/entity/ImprovementProposal.java index cf536df..bce03ee 100644 --- a/jeecg-module-supervision/src/main/java/org/jeecg/modules/improvementproposal/entity/ImprovementProposal.java +++ b/jeecg-module-supervision/src/main/java/org/jeecg/modules/improvementproposal/entity/ImprovementProposal.java @@ -124,6 +124,10 @@ public class ImprovementProposal implements Serializable { @Excel(name = "最终奖项", width = 15) @Schema(description = "最终奖项") private String finalAward; + /**所级评议领导名单*/ + @Excel(name = "所级评议领导名单", width = 15) + @Schema(description = "所级评议领导名单") + private Integer instituteVoters; /**所级评议应投票人数*/ @Excel(name = "所级评议应投票人数", width = 15) @Schema(description = "所级评议应投票人数") From bbebf12399fb40d3cfb590a9eb7339efd2ce9dc0 Mon Sep 17 00:00:00 2001 From: ye1023 <12588209+ye1023@user.noreply.gitee.com> Date: Tue, 28 Jul 2026 14:57:22 +0800 Subject: [PATCH 02/12] =?UTF-8?q?yxk-20260728=20=E6=94=B9=E5=96=84?= =?UTF-8?q?=E6=8F=90=E6=A1=88=20=E5=AE=9E=E7=8E=B0=E9=83=A8=E9=97=A8?= =?UTF-8?q?=E8=AF=84=E8=AE=AE=E5=B0=8F=E7=BB=84=E6=89=93=E5=88=86=E5=8A=9F?= =?UTF-8?q?=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../task/TaskCreatedAutoSubmitListener.java | 2 +- .../ImprovementProposalController.java | 28 +++ .../dto/ImprovementDeptScoreBpmDTO.java | 37 ++++ .../service/IImprovementProposalService.java | 10 + .../impl/ImprovementProposalServiceImpl.java | 194 ++++++++++++++++++ 5 files changed, 270 insertions(+), 1 deletion(-) create mode 100644 jeecg-module-supervision/src/main/java/org/jeecg/modules/improvementproposal/dto/ImprovementDeptScoreBpmDTO.java diff --git a/jeecg-boot-platform/jeecg-boot-module-bpm-flowable/src/main/java/org/jeecg/modules/extbpm/listener/task/TaskCreatedAutoSubmitListener.java b/jeecg-boot-platform/jeecg-boot-module-bpm-flowable/src/main/java/org/jeecg/modules/extbpm/listener/task/TaskCreatedAutoSubmitListener.java index 8f010ac..72277d3 100644 --- a/jeecg-boot-platform/jeecg-boot-module-bpm-flowable/src/main/java/org/jeecg/modules/extbpm/listener/task/TaskCreatedAutoSubmitListener.java +++ b/jeecg-boot-platform/jeecg-boot-module-bpm-flowable/src/main/java/org/jeecg/modules/extbpm/listener/task/TaskCreatedAutoSubmitListener.java @@ -33,7 +33,7 @@ import java.util.Map; public class TaskCreatedAutoSubmitListener implements TaskListener { private static final long serialVersionUID = 1L; - private static final String DEFAULT_START_APPROVAL_OPINION = "发起督办流程。"; + private static final String DEFAULT_START_APPROVAL_OPINION = "发起流程。"; private static ISysBaseAPI sysBaseAPI; private static IExtActBpmLogService extActBpmLogService; protected static RuntimeService runtimeService; diff --git a/jeecg-module-supervision/src/main/java/org/jeecg/modules/improvementproposal/controller/ImprovementProposalController.java b/jeecg-module-supervision/src/main/java/org/jeecg/modules/improvementproposal/controller/ImprovementProposalController.java index f70d08d..23770dd 100644 --- a/jeecg-module-supervision/src/main/java/org/jeecg/modules/improvementproposal/controller/ImprovementProposalController.java +++ b/jeecg-module-supervision/src/main/java/org/jeecg/modules/improvementproposal/controller/ImprovementProposalController.java @@ -27,6 +27,7 @@ import org.jeecg.common.util.oConvertUtils; import org.jeecg.modules.improvementproposal.entity.ImprovementDeptScore; import org.jeecg.modules.improvementproposal.entity.ImprovementInstituteVote; import org.jeecg.modules.improvementproposal.entity.ImprovementProposal; +import org.jeecg.modules.improvementproposal.dto.ImprovementDeptScoreBpmDTO; import org.jeecg.modules.improvementproposal.dto.ImprovementProposalBpmActionDTO; import org.jeecg.modules.improvementproposal.vo.ImprovementProposalPage; import org.jeecg.modules.improvementproposal.service.IImprovementProposalService; @@ -157,6 +158,33 @@ public class ImprovementProposalController { return handleBpmAction(() -> improvementProposalService.saveInitialReview(action, currentUser())); } + @GetMapping(value = "/bpm/myDeptScore") + @Operation(summary = "查询当前部门评委个人评分") + public Result getMyDeptScore(@RequestParam String mainId, @RequestParam String processInstanceId, + @RequestParam String taskId) { + ImprovementProposalBpmActionDTO action = new ImprovementProposalBpmActionDTO(); + action.setMainId(mainId); + action.setProcessInstanceId(processInstanceId); + action.setTaskId(taskId); + try { + return Result.OK(improvementProposalService.getMyDeptScore(action, currentUser())); + } catch (IllegalStateException e) { + return Result.error(e.getMessage()); + } + } + + @PostMapping(value = "/bpm/deptScore") + @Operation(summary = "保存当前部门评委个人评分草稿") + public Result saveDeptScore(@RequestBody ImprovementDeptScoreBpmDTO score) { + return handleBpmAction(() -> improvementProposalService.saveDeptScore(score, currentUser())); + } + + @PostMapping(value = "/bpm/submitDeptScore") + @Operation(summary = "锁定当前部门评委个人评分") + public Result submitDeptScore(@RequestBody ImprovementProposalBpmActionDTO action) { + return handleBpmAction(() -> improvementProposalService.submitDeptScore(action, currentUser())); + } + @PostMapping(value = "/bpm/leaderAward") @Operation(summary = "保存部门负责人确认奖项") public Result saveLeaderAward(@RequestBody ImprovementProposalBpmActionDTO action) { diff --git a/jeecg-module-supervision/src/main/java/org/jeecg/modules/improvementproposal/dto/ImprovementDeptScoreBpmDTO.java b/jeecg-module-supervision/src/main/java/org/jeecg/modules/improvementproposal/dto/ImprovementDeptScoreBpmDTO.java new file mode 100644 index 0000000..2575342 --- /dev/null +++ b/jeecg-module-supervision/src/main/java/org/jeecg/modules/improvementproposal/dto/ImprovementDeptScoreBpmDTO.java @@ -0,0 +1,37 @@ +package org.jeecg.modules.improvementproposal.dto; + +import java.math.BigDecimal; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * 部门评议评委提交个人评分时使用的流程节点参数。 + */ +@Data +public class ImprovementDeptScoreBpmDTO { + + @Schema(description = "改善提案主表ID") + private String mainId; + + @Schema(description = "流程实例ID") + private String processInstanceId; + + @Schema(description = "当前流程任务ID") + private String taskId; + + @Schema(description = "改善效果得分,0-100") + private BigDecimal effectScore; + + @Schema(description = "可推广度得分,0-100") + private BigDecimal promotionScore; + + @Schema(description = "独创性得分,0-100") + private BigDecimal originalityScore; + + @Schema(description = "努力度得分,0-100") + private BigDecimal effortScore; + + @Schema(description = "评分意见") + private String scoreOpinion; +} diff --git a/jeecg-module-supervision/src/main/java/org/jeecg/modules/improvementproposal/service/IImprovementProposalService.java b/jeecg-module-supervision/src/main/java/org/jeecg/modules/improvementproposal/service/IImprovementProposalService.java index 33b1031..23630cd 100644 --- a/jeecg-module-supervision/src/main/java/org/jeecg/modules/improvementproposal/service/IImprovementProposalService.java +++ b/jeecg-module-supervision/src/main/java/org/jeecg/modules/improvementproposal/service/IImprovementProposalService.java @@ -3,6 +3,7 @@ package org.jeecg.modules.improvementproposal.service; import org.jeecg.modules.improvementproposal.entity.ImprovementDeptScore; import org.jeecg.modules.improvementproposal.entity.ImprovementInstituteVote; import org.jeecg.modules.improvementproposal.entity.ImprovementProposal; +import org.jeecg.modules.improvementproposal.dto.ImprovementDeptScoreBpmDTO; import org.jeecg.modules.improvementproposal.dto.ImprovementProposalBpmActionDTO; import org.jeecg.common.system.vo.LoginUser; import com.baomidou.mybatisplus.extension.service.IService; @@ -62,6 +63,15 @@ public interface IImprovementProposalService extends IService() + .eq(ImprovementDeptScore::getId, existingScore.getId()) + .eq(ImprovementDeptScore::getScoreStatus, "pending") + .set(ImprovementDeptScore::getProcessTaskId, scoreAction.getTaskId()) + .set(ImprovementDeptScore::getEffectScore, scoreAction.getEffectScore()) + .set(ImprovementDeptScore::getPromotionScore, scoreAction.getPromotionScore()) + .set(ImprovementDeptScore::getOriginalityScore, scoreAction.getOriginalityScore()) + .set(ImprovementDeptScore::getEffortScore, scoreAction.getEffortScore()) + .set(ImprovementDeptScore::getTotalScore, totalScore) + .set(ImprovementDeptScore::getScoreOpinion, scoreAction.getScoreOpinion()) + .set(ImprovementDeptScore::getScoreStatus, "pending") + .set(ImprovementDeptScore::getScoreTime, null)); + if (updated != 1) { + throw new IllegalStateException("评分状态已变化,请刷新后重试"); + } + } + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void submitDeptScore(ImprovementProposalBpmActionDTO action, LoginUser loginUser) { + ImprovementProposal proposal = validateDeptScoreTask(action, loginUser); + ImprovementProposal lockedProposal = improvementProposalMapper.selectByIdForUpdate(proposal.getId()); + if (lockedProposal == null || !action.getProcessInstanceId().equals(lockedProposal.getProcessInstanceId())) { + throw new IllegalStateException("提案流程状态已变化,请刷新后重试"); + } + ImprovementDeptScore score = findDeptScore(lockedProposal.getId(), loginUser.getId()); + if (score == null) { + throw new IllegalStateException("请先保存个人评分"); + } + validateSavedScore(score); + + // 通用流程办理可能因网络重试再次调用 beforeHandle;已锁定时保持幂等,让任务能够再次提交完成。 + if (!"completed".equals(score.getScoreStatus())) { + int updated = improvementDeptScoreMapper.update(null, new LambdaUpdateWrapper() + .eq(ImprovementDeptScore::getId, score.getId()) + .eq(ImprovementDeptScore::getScoreStatus, "pending") + .set(ImprovementDeptScore::getScoreStatus, "completed") + .set(ImprovementDeptScore::getScoreTime, new Date()) + .set(ImprovementDeptScore::getProcessTaskId, action.getTaskId())); + if (updated != 1) { + throw new IllegalStateException("评分状态已变化,请刷新后重试"); + } + } + updateDeptScoreSummaryIfComplete(lockedProposal, action.getProcessInstanceId()); + } + @Override @Transactional(rollbackFor = Exception.class) public void saveLeaderAward(ImprovementProposalBpmActionDTO action, LoginUser loginUser) { @@ -257,6 +345,112 @@ public class ImprovementProposalServiceImpl extends ServiceImpl scorerId.equals(item.getScorerId())) + .findFirst() + .orElse(null); + } + + private void validateScoreValues(ImprovementDeptScoreBpmDTO scoreAction) { + if (scoreAction == null) { + throw new IllegalStateException("评分参数不能为空"); + } + validateScoreValue(scoreAction.getEffectScore(), "改善效果"); + validateScoreValue(scoreAction.getPromotionScore(), "可推广度"); + validateScoreValue(scoreAction.getOriginalityScore(), "独创性"); + validateScoreValue(scoreAction.getEffortScore(), "努力度"); + } + + private void validateScoreValue(BigDecimal score, String dimensionName) { + if (score == null || score.scale() > 2 || score.compareTo(BigDecimal.ZERO) < 0 || score.compareTo(BigDecimal.valueOf(100)) > 0) { + throw new IllegalStateException(dimensionName + "得分必须是 0 到 100 之间且最多两位小数的数值"); + } + } + + private BigDecimal calculateTotalScore(ImprovementDeptScoreBpmDTO scoreAction) { + return scoreAction.getEffectScore().multiply(new BigDecimal("0.50")) + .add(scoreAction.getPromotionScore().multiply(new BigDecimal("0.20"))) + .add(scoreAction.getOriginalityScore().multiply(new BigDecimal("0.20"))) + .add(scoreAction.getEffortScore().multiply(new BigDecimal("0.10"))) + .setScale(2, RoundingMode.HALF_UP); + } + + private void fillDeptScoreDraft(ImprovementDeptScore target, ImprovementDeptScoreBpmDTO source, BigDecimal totalScore) { + target.setEffectScore(source.getEffectScore()); + target.setPromotionScore(source.getPromotionScore()); + target.setOriginalityScore(source.getOriginalityScore()); + target.setEffortScore(source.getEffortScore()); + target.setTotalScore(totalScore); + target.setScoreOpinion(source.getScoreOpinion()); + target.setScoreStatus("pending"); + target.setScoreTime(null); + } + + private void validateSavedScore(ImprovementDeptScore score) { + validateScoreValue(score.getEffectScore(), "改善效果"); + validateScoreValue(score.getPromotionScore(), "可推广度"); + validateScoreValue(score.getOriginalityScore(), "独创性"); + validateScoreValue(score.getEffortScore(), "努力度"); + if (score.getTotalScore() == null) { + throw new IllegalStateException("请先保存完整个人评分"); + } + } + + private void updateDeptScoreSummaryIfComplete(ImprovementProposal proposal, String processInstanceId) { + long expectedScorerCount = historyService.createHistoricTaskInstanceQuery() + .processInstanceId(processInstanceId) + .taskDefinitionKey(TASK_DEPT_SCORE) + .count(); + List scoreList = improvementDeptScoreMapper.selectByMainId(proposal.getId()); + boolean allCompleted = expectedScorerCount > 0 && scoreList.size() == expectedScorerCount + && scoreList.stream().allMatch(item -> "completed".equals(item.getScoreStatus()) && item.getTotalScore() != null); + if (!allCompleted) { + return; + } + + BigDecimal totalScore = scoreList.stream() + .map(ImprovementDeptScore::getTotalScore) + .reduce(BigDecimal.ZERO, BigDecimal::add); + BigDecimal averageScore = totalScore.divide(BigDecimal.valueOf(expectedScorerCount), 2, RoundingMode.HALF_UP); + ImprovementProposal summary = new ImprovementProposal(); + summary.setId(proposal.getId()); + summary.setDeptAvgScore(averageScore); + summary.setSuggestedAward(resolveSuggestedAward(averageScore)); + improvementProposalMapper.updateById(summary); + } + + private String resolveSuggestedAward(BigDecimal averageScore) { + if (averageScore.compareTo(BigDecimal.valueOf(80)) >= 0) { + return AWARD_GOLD; + } + if (averageScore.compareTo(BigDecimal.valueOf(60)) >= 0) { + return AWARD_SILVER; + } + if (averageScore.compareTo(BigDecimal.valueOf(40)) >= 0) { + return AWARD_BRONZE; + } + return AWARD_PARTICIPATION; + } + private ImprovementProposal validateRunningTask(ImprovementProposalBpmActionDTO action, LoginUser loginUser, String expectedTaskDefKey) { if (action == null || oConvertUtils.isEmpty(action.getMainId()) || oConvertUtils.isEmpty(action.getProcessInstanceId()) || oConvertUtils.isEmpty(action.getTaskId())) { From 9a6416f2fda86079062ce4ef13b50d7e59a9a43d Mon Sep 17 00:00:00 2001 From: ye1023 <12588209+ye1023@user.noreply.gitee.com> Date: Tue, 28 Jul 2026 15:05:15 +0800 Subject: [PATCH 03/12] =?UTF-8?q?yxk-20260728=20=E6=94=B9=E5=96=84?= =?UTF-8?q?=E6=8F=90=E6=A1=88=20=E6=94=B9=E5=96=84=E6=95=88=E6=9E=9C?= =?UTF-8?q?=E5=BE=97=E5=88=86=E6=8B=86=E5=88=86=E4=B8=BA=E5=AE=89=E5=85=A8?= =?UTF-8?q?=E3=80=81=E8=B4=A8=E9=87=8F=E3=80=81=E6=95=88=E7=8E=87=E3=80=81?= =?UTF-8?q?=E6=88=90=E6=9C=AC=E5=9B=9B=E4=B8=AA=EF=BC=8C=E6=9D=83=E9=87=8D?= =?UTF-8?q?=E5=B9=B3=E5=9D=87=E5=88=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dto/ImprovementDeptScoreBpmDTO.java | 13 +++++- .../entity/ImprovementDeptScore.java | 16 +++++++ .../impl/ImprovementProposalServiceImpl.java | 45 ++++++++++++++----- 3 files changed, 62 insertions(+), 12 deletions(-) diff --git a/jeecg-module-supervision/src/main/java/org/jeecg/modules/improvementproposal/dto/ImprovementDeptScoreBpmDTO.java b/jeecg-module-supervision/src/main/java/org/jeecg/modules/improvementproposal/dto/ImprovementDeptScoreBpmDTO.java index 2575342..a65feb2 100644 --- a/jeecg-module-supervision/src/main/java/org/jeecg/modules/improvementproposal/dto/ImprovementDeptScoreBpmDTO.java +++ b/jeecg-module-supervision/src/main/java/org/jeecg/modules/improvementproposal/dto/ImprovementDeptScoreBpmDTO.java @@ -20,8 +20,17 @@ public class ImprovementDeptScoreBpmDTO { @Schema(description = "当前流程任务ID") private String taskId; - @Schema(description = "改善效果得分,0-100") - private BigDecimal effectScore; + @Schema(description = "安全得分,0-100") + private BigDecimal safetyScore; + + @Schema(description = "质量得分,0-100") + private BigDecimal qualityScore; + + @Schema(description = "效率得分,0-100") + private BigDecimal efficiencyScore; + + @Schema(description = "成本得分,0-100") + private BigDecimal costScore; @Schema(description = "可推广度得分,0-100") private BigDecimal promotionScore; diff --git a/jeecg-module-supervision/src/main/java/org/jeecg/modules/improvementproposal/entity/ImprovementDeptScore.java b/jeecg-module-supervision/src/main/java/org/jeecg/modules/improvementproposal/entity/ImprovementDeptScore.java index 2b18d21..2edf323 100644 --- a/jeecg-module-supervision/src/main/java/org/jeecg/modules/improvementproposal/entity/ImprovementDeptScore.java +++ b/jeecg-module-supervision/src/main/java/org/jeecg/modules/improvementproposal/entity/ImprovementDeptScore.java @@ -50,6 +50,22 @@ public class ImprovementDeptScore implements Serializable { @Excel(name = "评分状态:pending/completed", width = 15) @Schema(description = "评分状态:pending/completed") private String scoreStatus; + /**安全得分*/ + @Excel(name = "安全得分", width = 15) + @Schema(description = "安全得分") + private java.math.BigDecimal safetyScore; + /**质量得分*/ + @Excel(name = "质量得分", width = 15) + @Schema(description = "质量得分") + private java.math.BigDecimal qualityScore; + /**效率得分*/ + @Excel(name = "效率得分", width = 15) + @Schema(description = "效率得分") + private java.math.BigDecimal efficiencyScore; + /**成本得分*/ + @Excel(name = "成本得分", width = 15) + @Schema(description = "成本得分") + private java.math.BigDecimal costScore; /**改善效果得分*/ @Excel(name = "改善效果得分", width = 15) @Schema(description = "改善效果得分") diff --git a/jeecg-module-supervision/src/main/java/org/jeecg/modules/improvementproposal/service/impl/ImprovementProposalServiceImpl.java b/jeecg-module-supervision/src/main/java/org/jeecg/modules/improvementproposal/service/impl/ImprovementProposalServiceImpl.java index 4018ef0..1ffa739 100644 --- a/jeecg-module-supervision/src/main/java/org/jeecg/modules/improvementproposal/service/impl/ImprovementProposalServiceImpl.java +++ b/jeecg-module-supervision/src/main/java/org/jeecg/modules/improvementproposal/service/impl/ImprovementProposalServiceImpl.java @@ -231,14 +231,16 @@ public class ImprovementProposalServiceImpl extends ServiceImpl Date: Tue, 28 Jul 2026 18:34:20 +0800 Subject: [PATCH 04/12] =?UTF-8?q?yxk-20260728=20=E6=94=B9=E5=96=84?= =?UTF-8?q?=E6=8F=90=E6=A1=88=20=E5=9C=A8=20Task=5Fimprove003=20=E9=83=A8?= =?UTF-8?q?=E9=97=A8=E8=B4=9F=E8=B4=A3=E4=BA=BA=E5=AE=A1=E6=A0=B8=E8=8A=82?= =?UTF-8?q?=E7=82=B9=EF=BC=8C=E8=B4=9F=E8=B4=A3=E4=BA=BA=E5=8F=AA=E8=83=BD?= =?UTF-8?q?=E9=80=89=E6=8B=A9=E5=9F=BA=E5=87=86=E5=A5=96=E9=A1=B9=E6=9C=AC?= =?UTF-8?q?=E6=A1=A3=E6=88=96=E6=9B=B4=E4=BD=8E=E6=A1=A3=E5=A5=96=E9=A1=B9?= =?UTF-8?q?=EF=BC=8C=E4=B8=8D=E5=85=81=E8=AE=B8=E5=8D=87=E6=A1=A3=E3=80=82?= =?UTF-8?q?=E5=9F=BA=E5=87=86=E5=A5=96=E9=A1=B9=E6=8C=89=E6=98=AF=E5=90=A6?= =?UTF-8?q?=E7=BB=8F=E8=BF=87=E9=83=A8=E9=97=A8=E8=AF=84=E8=AE=AE=E7=A1=AE?= =?UTF-8?q?=E5=AE=9A=EF=BC=9A=20need=5Fdept=5Fscore=3D'1'=EF=BC=9A?= =?UTF-8?q?=E4=BB=A5=20suggested=5Faward=20=E4=B8=BA=E5=9F=BA=E5=87=86?= =?UTF-8?q?=E3=80=82=20=E6=9C=AA=E7=BB=8F=E8=BF=87=E9=83=A8=E9=97=A8?= =?UTF-8?q?=E8=AF=84=E8=AE=AE=EF=BC=9A=E4=BB=A5=20initial=5Faward=20?= =?UTF-8?q?=E4=B8=BA=E5=9F=BA=E5=87=86=E3=80=82=20=E5=A5=96=E9=A1=B9?= =?UTF-8?q?=E7=BC=96=E7=A0=81=E4=BF=9D=E6=8C=81=E7=8E=B0=E6=9C=89=E9=A1=BA?= =?UTF-8?q?=E5=BA=8F=EF=BC=9A0=3D=E9=87=91=E5=A5=96=E3=80=811=3D=E9=93=B6?= =?UTF-8?q?=E5=A5=96=E3=80=812=3D=E9=93=9C=E5=A5=96=E3=80=813=3D=E5=8F=82?= =?UTF-8?q?=E4=B8=8E=E5=A5=96=EF=BC=9B=E7=BC=96=E7=A0=81=E6=95=B0=E5=80=BC?= =?UTF-8?q?=E5=A4=A7=E4=BA=8E=E7=AD=89=E4=BA=8E=E5=9F=BA=E5=87=86=E7=BC=96?= =?UTF-8?q?=E7=A0=81=E5=8D=B3=E4=B8=BA=E6=9C=AC=E6=A1=A3=E6=88=96=E9=99=8D?= =?UTF-8?q?=E6=A1=A3=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../impl/ImprovementProposalServiceImpl.java | 25 ++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/jeecg-module-supervision/src/main/java/org/jeecg/modules/improvementproposal/service/impl/ImprovementProposalServiceImpl.java b/jeecg-module-supervision/src/main/java/org/jeecg/modules/improvementproposal/service/impl/ImprovementProposalServiceImpl.java index 1ffa739..7884082 100644 --- a/jeecg-module-supervision/src/main/java/org/jeecg/modules/improvementproposal/service/impl/ImprovementProposalServiceImpl.java +++ b/jeecg-module-supervision/src/main/java/org/jeecg/modules/improvementproposal/service/impl/ImprovementProposalServiceImpl.java @@ -300,6 +300,10 @@ public class ImprovementProposalServiceImpl extends ServiceImpl Date: Wed, 29 Jul 2026 09:38:52 +0800 Subject: [PATCH 05/12] =?UTF-8?q?yxk-20260729=20=E6=94=B9=E5=96=84?= =?UTF-8?q?=E6=8F=90=E6=A1=88=20=E6=96=B0=E5=A2=9E=E6=B5=81=E7=A8=8B?= =?UTF-8?q?=E8=A1=A8=E8=BE=BE=E5=BC=8FgetRequiredUsersListByRole=20?= =?UTF-8?q?=E6=A0=B9=E6=8D=AE=E8=A7=92=E8=89=B2=E6=89=BE=E4=BA=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/expression/FlowNodeExpression.java | 23 +++++++++++++++++++ .../api/fallback/SysBaseAPIFallback.java | 7 ++++++ .../jeecg/common/system/api/ISysBaseAPI.java | 11 ++++++++- .../modules/system/mapper/SysUserMapper.java | 9 ++++++++ .../system/mapper/xml/SysUserMapper.xml | 11 +++++++++ .../system/service/ISysUserService.java | 9 ++++++++ .../system/service/impl/SysBaseApiImpl.java | 13 ++++++++++- .../service/impl/SysUserServiceImpl.java | 8 +++++++ 8 files changed, 89 insertions(+), 2 deletions(-) diff --git a/jeecg-boot-platform/jeecg-boot-module-bpm-flowable/src/main/java/org/jeecg/modules/extbpm/process/common/expression/FlowNodeExpression.java b/jeecg-boot-platform/jeecg-boot-module-bpm-flowable/src/main/java/org/jeecg/modules/extbpm/process/common/expression/FlowNodeExpression.java index fce908a..26f11b9 100644 --- a/jeecg-boot-platform/jeecg-boot-module-bpm-flowable/src/main/java/org/jeecg/modules/extbpm/process/common/expression/FlowNodeExpression.java +++ b/jeecg-boot-platform/jeecg-boot-module-bpm-flowable/src/main/java/org/jeecg/modules/extbpm/process/common/expression/FlowNodeExpression.java @@ -6,6 +6,7 @@ import com.alibaba.fastjson.JSONObject; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang.StringUtils; +import org.jeecg.common.exception.JeecgBootException; import org.flowable.engine.RuntimeService; import org.flowable.engine.delegate.DelegateExecution; import org.flowable.engine.runtime.Execution; @@ -276,6 +277,28 @@ public class FlowNodeExpression { return sysbase.getUserByRoleIdLocalApi(roleId); } + /** + * Get required usernames for a Flowable multi-instance task. + * An empty collection would otherwise make Flowable skip the task, so fail fast instead. + * Example: ${flowNodeExpression.getRequiredUsersListByRole('roleIdValue')} + * + * @param roleId system role id + * @return non-empty username list + */ + public List getRequiredUsersListByRole(String roleId) { + if (StringUtils.isBlank(roleId)) { + throw new JeecgBootException("流程角色ID不能为空"); + } + + List usernames = ISysBaseAPI.getUsernamesByRoleIdLocalApi(roleId); + log.info("流程多实例按角色取人,roleId={}, usernames={}, count={}", roleId, usernames, + usernames == null ? 0 : usernames.size()); + if (CollectionUtils.isEmpty(usernames)) { + throw new JeecgBootException("角色[" + roleId + "]未配置有效用户,流程无法继续"); + } + return usernames; + } + /** * Get subprocess variable. * Example: ${flowNodeExpression.getSonProcessVariable(execution, 'subApproveUser')} diff --git a/jeecg-module-system/jeecg-system-api/jeecg-system-cloud-api/src/main/java/org/jeecg/common/system/api/fallback/SysBaseAPIFallback.java b/jeecg-module-system/jeecg-system-api/jeecg-system-cloud-api/src/main/java/org/jeecg/common/system/api/fallback/SysBaseAPIFallback.java index 7b8a3d3..9336d11 100644 --- a/jeecg-module-system/jeecg-system-api/jeecg-system-cloud-api/src/main/java/org/jeecg/common/system/api/fallback/SysBaseAPIFallback.java +++ b/jeecg-module-system/jeecg-system-api/jeecg-system-cloud-api/src/main/java/org/jeecg/common/system/api/fallback/SysBaseAPIFallback.java @@ -10,6 +10,7 @@ import org.jeecg.common.constant.enums.EmailTemplateEnum; import org.jeecg.common.system.api.ISysBaseAPI; import org.jeecg.common.system.vo.*; +import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Set; @@ -24,6 +25,12 @@ public class SysBaseAPIFallback implements ISysBaseAPI { @Setter private Throwable cause; + @Override + public List getUsernamesByRoleIdLocalApi(String roleId) { + log.error("Query usernames by role failed, roleId={}", roleId, cause); + return Collections.emptyList(); + } + @Override public void sendSysAnnouncement(MessageDTO message) { log.error("发送消息失败 {}", cause); diff --git a/jeecg-module-system/jeecg-system-api/jeecg-system-local-api/src/main/java/org/jeecg/common/system/api/ISysBaseAPI.java b/jeecg-module-system/jeecg-system-api/jeecg-system-local-api/src/main/java/org/jeecg/common/system/api/ISysBaseAPI.java index 632c7c4..8a994ba 100644 --- a/jeecg-module-system/jeecg-system-api/jeecg-system-local-api/src/main/java/org/jeecg/common/system/api/ISysBaseAPI.java +++ b/jeecg-module-system/jeecg-system-api/jeecg-system-local-api/src/main/java/org/jeecg/common/system/api/ISysBaseAPI.java @@ -575,4 +575,13 @@ public interface ISysBaseAPI extends CommonAPI { List getUsersListByDeptIdAndRoleIdLocalApi(String deptId, String roleId); List getUserByRoleIdLocalApi(String roleId); - } + + /** + * Query active usernames by role for Flowable multi-instance tasks. + * This method intentionally uses an independent query path so existing role queries remain unchanged. + * + * @param roleId system role id + * @return active username list + */ + List getUsernamesByRoleIdLocalApi(String roleId); +} diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/SysUserMapper.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/SysUserMapper.java index 4a359dc..dfe3411 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/SysUserMapper.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/SysUserMapper.java @@ -251,4 +251,13 @@ public interface SysUserMapper extends BaseMapper { * @return */ List getUserByRoleId(String roleId); + + /** + * Query active usernames by role through a dedicated statement. + * It must not reuse the overloaded getUserByRoleId statement used by the user management page. + * + * @param roleId role id + * @return username list + */ + List getUsernamesByRoleId(@Param("roleId") String roleId); } diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/xml/SysUserMapper.xml b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/xml/SysUserMapper.xml index 4efa813..248441f 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/xml/SysUserMapper.xml +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/xml/SysUserMapper.xml @@ -59,6 +59,17 @@ + + + + main_id = #{mainId} + AND del_flag = '0' + + + + + UPDATE improvement_institute_vote + SET del_flag = '1' + WHERE main_id = #{mainId} + AND del_flag = '0' + AND vote_status = 'pending' + diff --git a/jeecg-module-supervision/src/main/java/org/jeecg/modules/improvementproposal/mapper/xml/ImprovementProposalMapper.xml b/jeecg-module-supervision/src/main/java/org/jeecg/modules/improvementproposal/mapper/xml/ImprovementProposalMapper.xml index f21cac3..1b7e498 100644 --- a/jeecg-module-supervision/src/main/java/org/jeecg/modules/improvementproposal/mapper/xml/ImprovementProposalMapper.xml +++ b/jeecg-module-supervision/src/main/java/org/jeecg/modules/improvementproposal/mapper/xml/ImprovementProposalMapper.xml @@ -10,4 +10,17 @@ LIMIT 1 + + + diff --git a/jeecg-module-supervision/src/main/java/org/jeecg/modules/improvementproposal/service/IImprovementProposalService.java b/jeecg-module-supervision/src/main/java/org/jeecg/modules/improvementproposal/service/IImprovementProposalService.java index 23630cd..cf41ad1 100644 --- a/jeecg-module-supervision/src/main/java/org/jeecg/modules/improvementproposal/service/IImprovementProposalService.java +++ b/jeecg-module-supervision/src/main/java/org/jeecg/modules/improvementproposal/service/IImprovementProposalService.java @@ -4,6 +4,7 @@ import org.jeecg.modules.improvementproposal.entity.ImprovementDeptScore; import org.jeecg.modules.improvementproposal.entity.ImprovementInstituteVote; import org.jeecg.modules.improvementproposal.entity.ImprovementProposal; import org.jeecg.modules.improvementproposal.dto.ImprovementDeptScoreBpmDTO; +import org.jeecg.modules.improvementproposal.dto.ImprovementInstituteVoteCandidateDTO; import org.jeecg.modules.improvementproposal.dto.ImprovementProposalBpmActionDTO; import org.jeecg.common.system.vo.LoginUser; import com.baomidou.mybatisplus.extension.service.IService; @@ -75,6 +76,12 @@ public interface IImprovementProposalService extends IService getInstituteVoteCandidates(ImprovementProposalBpmActionDTO action, LoginUser loginUser); + + /** 保存所级评议名单、待投票记录及多实例流程变量。 */ + void saveInstituteVoteMembers(ImprovementProposalBpmActionDTO action, LoginUser loginUser); + /** 保存经办人归档确认的最终奖项。 */ void saveArchiveAward(ImprovementProposalBpmActionDTO action, LoginUser loginUser); diff --git a/jeecg-module-supervision/src/main/java/org/jeecg/modules/improvementproposal/service/impl/ImprovementProposalServiceImpl.java b/jeecg-module-supervision/src/main/java/org/jeecg/modules/improvementproposal/service/impl/ImprovementProposalServiceImpl.java index 7884082..afead7b 100644 --- a/jeecg-module-supervision/src/main/java/org/jeecg/modules/improvementproposal/service/impl/ImprovementProposalServiceImpl.java +++ b/jeecg-module-supervision/src/main/java/org/jeecg/modules/improvementproposal/service/impl/ImprovementProposalServiceImpl.java @@ -4,6 +4,7 @@ import org.jeecg.modules.improvementproposal.entity.ImprovementProposal; import org.jeecg.modules.improvementproposal.entity.ImprovementDeptScore; import org.jeecg.modules.improvementproposal.entity.ImprovementInstituteVote; import org.jeecg.modules.improvementproposal.dto.ImprovementDeptScoreBpmDTO; +import org.jeecg.modules.improvementproposal.dto.ImprovementInstituteVoteCandidateDTO; import org.jeecg.modules.improvementproposal.dto.ImprovementProposalBpmActionDTO; import org.jeecg.modules.improvementproposal.mapper.ImprovementDeptScoreMapper; import org.jeecg.modules.improvementproposal.mapper.ImprovementInstituteVoteMapper; @@ -29,9 +30,13 @@ import org.flowable.engine.RuntimeService; import org.flowable.engine.HistoryService; import org.flowable.engine.TaskService; import org.flowable.task.api.Task; +import org.jeecg.modules.system.entity.SysRole; +import org.jeecg.modules.system.service.ISysRoleService; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import java.util.regex.Matcher; import java.util.regex.Pattern; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; /** * @Description: improvement_proposal @@ -49,8 +54,10 @@ public class ImprovementProposalServiceImpl extends ServiceImpl getInstituteVoteCandidates(ImprovementProposalBpmActionDTO action, LoginUser loginUser) { + validateRunningTask(action, loginUser, TASK_INSTITUTE_REVIEW); + return loadInstituteVoteCandidates(); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void saveInstituteVoteMembers(ImprovementProposalBpmActionDTO action, LoginUser loginUser) { + ImprovementProposal proposal = validateRunningTask(action, loginUser, TASK_INSTITUTE_REVIEW); + ImprovementProposal lockedProposal = improvementProposalMapper.selectByIdForUpdate(proposal.getId()); + if (lockedProposal == null || !action.getProcessInstanceId().equals(lockedProposal.getProcessInstanceId())) { + throw new IllegalStateException("提案流程状态已变化,请刷新后重试"); + } + + List candidates = loadInstituteVoteCandidates(); + Map candidateById = new LinkedHashMap<>(); + for (ImprovementInstituteVoteCandidateDTO candidate : candidates) { + candidateById.put(candidate.getId(), candidate); + } + if (action.getVoterIds() == null || action.getVoterIds().isEmpty()) { + throw new IllegalStateException("请至少选择一名所级评议人员"); + } + + LinkedHashSet selectedUserIds = new LinkedHashSet<>(); + for (String voterId : action.getVoterIds()) { + if (oConvertUtils.isEmpty(voterId) || !selectedUserIds.add(voterId)) { + throw new IllegalStateException("所级评议人员选择数据不合法"); + } + } + LinkedHashSet usernames = new LinkedHashSet<>(); + for (String voterId : selectedUserIds) { + ImprovementInstituteVoteCandidateDTO candidate = candidateById.get(voterId); + if (candidate == null) { + throw new IllegalStateException("所选人员不属于所级评议小组"); + } + if (!usernames.add(candidate.getUsername())) { + throw new IllegalStateException("所级评议人员用户名重复"); + } + } + + List activeVotes = improvementInstituteVoteMapper.selectByMainId(lockedProposal.getId()); + if (activeVotes.stream().anyMatch(item -> !"pending".equals(item.getVoteStatus()))) { + throw new IllegalStateException("所级评议已开始投票,不能重新选择人员"); + } + // beforeHandle 可能因网络重试重复调用;先失效未投票记录再重建,确保有效名单始终和流程变量一致。 + improvementInstituteVoteMapper.logicalDeletePendingByMainId(lockedProposal.getId()); + for (String voterId : selectedUserIds) { + ImprovementInstituteVoteCandidateDTO candidate = candidateById.get(voterId); + ImprovementInstituteVote vote = new ImprovementInstituteVote(); + vote.setMainId(lockedProposal.getId()); + vote.setVoterId(candidate.getId()); + vote.setVoterName(oConvertUtils.isEmpty(candidate.getRealname()) ? candidate.getUsername() : candidate.getRealname()); + vote.setVoteStatus("pending"); + vote.setSysOrgCode(lockedProposal.getSysOrgCode()); + vote.setDelFlag(NORMAL_DEL_FLAG); + improvementInstituteVoteMapper.insert(vote); + } + + ImprovementProposal update = new ImprovementProposal(); + update.setId(lockedProposal.getId()); + update.setInstituteTotalVoters(selectedUserIds.size()); + update.setInstituteAgreeCount(null); + update.setInstituteDisagreeCount(null); + update.setInstituteVoteResult(null); + improvementProposalMapper.updateById(update); + runtimeService.setVariable(action.getProcessInstanceId(), "suoleadervotelist", String.join(",", usernames)); + } + @Override @Transactional(rollbackFor = Exception.class) public void saveArchiveAward(ImprovementProposalBpmActionDTO action, LoginUser loginUser) { @@ -355,6 +433,21 @@ public class ImprovementProposalServiceImpl extends ServiceImpl loadInstituteVoteCandidates() { + SysRole role = sysRoleService.getRoleNoTenant(INSTITUTE_VOTE_ROLE_CODE); + if (role == null) { + throw new IllegalStateException("未配置所级评议小组角色:" + INSTITUTE_VOTE_ROLE_CODE); + } + List candidates = improvementProposalMapper.selectInstituteVoteCandidates(INSTITUTE_VOTE_ROLE_CODE); + if (candidates == null || candidates.isEmpty()) { + throw new IllegalStateException("所级评议小组角色未配置有效用户"); + } + return candidates; + } + private ImprovementProposalBpmActionDTO toBpmAction(ImprovementDeptScoreBpmDTO scoreAction) { ImprovementProposalBpmActionDTO action = new ImprovementProposalBpmActionDTO(); action.setMainId(scoreAction.getMainId()); From 0a04d98c7291d2802c89c94ab5a3b6cd5a3e2dec Mon Sep 17 00:00:00 2001 From: ye1023 <12588209+ye1023@user.noreply.gitee.com> Date: Wed, 29 Jul 2026 10:18:38 +0800 Subject: [PATCH 08/12] =?UTF-8?q?yxk-20260729=20=E6=94=B9=E5=96=84?= =?UTF-8?q?=E6=8F=90=E6=A1=88=20=E4=BA=91=E7=AB=AF=20ISysBaseAPI=20?= =?UTF-8?q?=E6=9C=AA=E5=A3=B0=E6=98=8E=E6=96=B0=E6=96=B9=E6=B3=95=EF=BC=8C?= =?UTF-8?q?=E5=AF=BC=E8=87=B4=20SysBaseAPIFallback=20=E7=9A=84=20@Override?= =?UTF-8?q?=20=E6=97=A0=E6=B3=95=E5=8C=B9=E9=85=8D=E3=80=82=20=E6=88=91?= =?UTF-8?q?=E5=B7=B2=EF=BC=9A=20=E5=9C=A8=E4=BA=91=E7=AB=AF=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3=E8=A1=A5=E5=85=85=20getUsernamesByRoleIdLocalApi=20?= =?UTF-8?q?=E5=A3=B0=E6=98=8E=E4=B8=8E=20Feign=20=E8=B7=AF=E5=BE=84?= =?UTF-8?q?=E3=80=82=20=E5=9C=A8=20SystemApiController=20=E8=A1=A5?= =?UTF-8?q?=E5=85=85=20/sys/api/getUsernamesByRoleId=20=E6=98=A0=E5=B0=84?= =?UTF-8?q?=EF=BC=8C=E4=BF=9D=E8=AF=81=E5=88=86=E5=B8=83=E5=BC=8F=E8=B0=83?= =?UTF-8?q?=E7=94=A8=E4=B9=9F=E8=83=BD=E5=AE=9E=E9=99=85=E8=BF=94=E5=9B=9E?= =?UTF-8?q?=E7=94=A8=E6=88=B7=E5=90=8D=E5=88=97=E8=A1=A8=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/org/jeecg/common/system/api/ISysBaseAPI.java | 9 +++++++++ .../modules/api/controller/SystemApiController.java | 8 ++++++++ 2 files changed, 17 insertions(+) diff --git a/jeecg-module-system/jeecg-system-api/jeecg-system-cloud-api/src/main/java/org/jeecg/common/system/api/ISysBaseAPI.java b/jeecg-module-system/jeecg-system-api/jeecg-system-cloud-api/src/main/java/org/jeecg/common/system/api/ISysBaseAPI.java index d23a691..2eb36c5 100644 --- a/jeecg-module-system/jeecg-system-api/jeecg-system-cloud-api/src/main/java/org/jeecg/common/system/api/ISysBaseAPI.java +++ b/jeecg-module-system/jeecg-system-api/jeecg-system-cloud-api/src/main/java/org/jeecg/common/system/api/ISysBaseAPI.java @@ -78,6 +78,15 @@ public interface ISysBaseAPI extends CommonAPI { @GetMapping("/sys/api/getUserById") LoginUser getUserById(@RequestParam("id") String id); + /** + * 查询角色下未逻辑删除用户的登录用户名,供流程多实例任务分配使用。 + * + * @param roleId 系统角色 ID + * @return 用户名列表 + */ + @GetMapping("/sys/api/getUsernamesByRoleId") + List getUsernamesByRoleIdLocalApi(@RequestParam("roleId") String roleId); + /** * 7通过用户账号查询角色集合 * @param username diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/api/controller/SystemApiController.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/api/controller/SystemApiController.java index 4fffe7c..354bcd4 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/api/controller/SystemApiController.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/api/controller/SystemApiController.java @@ -131,6 +131,14 @@ public class SystemApiController { return loginUser; } + /** + * 流程多实例节点只接受 username 作为办理人标识,统一由系统服务按角色查询。 + */ + @GetMapping("/getUsernamesByRoleId") + List getUsernamesByRoleId(@RequestParam("roleId") String roleId) { + return sysBaseApi.getUsernamesByRoleIdLocalApi(roleId); + } + /** * 通过用户账号查询角色集合 * @param username From 8751c8e86b1af29a68818f71a745085f8e397c7c Mon Sep 17 00:00:00 2001 From: ye1023 <12588209+ye1023@user.noreply.gitee.com> Date: Wed, 29 Jul 2026 10:39:00 +0800 Subject: [PATCH 09/12] =?UTF-8?q?yxk-20260729=20=E6=94=B9=E5=96=84?= =?UTF-8?q?=E6=8F=90=E6=A1=88=20=E6=8A=95=E7=A5=A8/=E6=89=93=E5=88=86?= =?UTF-8?q?=E9=A1=B5=E9=9D=A2=E9=80=BB=E8=BE=91=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ImprovementProposalController.java | 6 ++ .../service/IImprovementProposalService.java | 3 + .../impl/ImprovementProposalServiceImpl.java | 77 +++++++++++++++++-- 3 files changed, 78 insertions(+), 8 deletions(-) diff --git a/jeecg-module-supervision/src/main/java/org/jeecg/modules/improvementproposal/controller/ImprovementProposalController.java b/jeecg-module-supervision/src/main/java/org/jeecg/modules/improvementproposal/controller/ImprovementProposalController.java index 7ce05cf..16af363 100644 --- a/jeecg-module-supervision/src/main/java/org/jeecg/modules/improvementproposal/controller/ImprovementProposalController.java +++ b/jeecg-module-supervision/src/main/java/org/jeecg/modules/improvementproposal/controller/ImprovementProposalController.java @@ -225,6 +225,12 @@ public class ImprovementProposalController { return handleBpmAction(() -> improvementProposalService.castInstituteVote(action, currentUser())); } + @PostMapping(value = "/bpm/submitInstituteVote") + @Operation(summary = "锁定所级评委投票并汇总结果") + public Result submitInstituteVote(@RequestBody ImprovementProposalBpmActionDTO action) { + return handleBpmAction(() -> improvementProposalService.submitInstituteVote(action, currentUser())); + } + private LoginUser currentUser() { return (LoginUser) SecurityUtils.getSubject().getPrincipal(); } diff --git a/jeecg-module-supervision/src/main/java/org/jeecg/modules/improvementproposal/service/IImprovementProposalService.java b/jeecg-module-supervision/src/main/java/org/jeecg/modules/improvementproposal/service/IImprovementProposalService.java index cf41ad1..fa800f1 100644 --- a/jeecg-module-supervision/src/main/java/org/jeecg/modules/improvementproposal/service/IImprovementProposalService.java +++ b/jeecg-module-supervision/src/main/java/org/jeecg/modules/improvementproposal/service/IImprovementProposalService.java @@ -88,6 +88,9 @@ public interface IImprovementProposalService extends IService loginUser.getId().equals(item.getVoterId())) - .findFirst() - .orElseThrow(() -> new IllegalStateException("当前用户不在所级评议投票名单中")); + ImprovementInstituteVote vote = findInstituteVote(proposal.getId(), loginUser.getId()); if ("voted".equals(vote.getVoteStatus())) { - throw new IllegalStateException("您已完成投票,不能重复修改"); + throw new IllegalStateException("投票已锁定,请重新提交流程办理"); } int updated = improvementInstituteVoteMapper.update(null, new LambdaUpdateWrapper() .eq(ImprovementInstituteVote::getId, vote.getId()) .eq(ImprovementInstituteVote::getVoteStatus, "pending") .set(ImprovementInstituteVote::getVoteResult, action.getVoteResult()) - .set(ImprovementInstituteVote::getVoteStatus, "voted") - .set(ImprovementInstituteVote::getVoteTime, new Date()) + .set(ImprovementInstituteVote::getVoteTime, null) .set(ImprovementInstituteVote::getProcessTaskId, action.getTaskId())); if (updated != 1) { throw new IllegalStateException("投票状态已变化,请刷新后重试"); } } + @Override + @Transactional(rollbackFor = Exception.class) + public void submitInstituteVote(ImprovementProposalBpmActionDTO action, LoginUser loginUser) { + ImprovementProposal proposal = validateRunningTask(action, loginUser, TASK_INSTITUTE_VOTE); + ImprovementProposal lockedProposal = improvementProposalMapper.selectByIdForUpdate(proposal.getId()); + if (lockedProposal == null || !action.getProcessInstanceId().equals(lockedProposal.getProcessInstanceId())) { + throw new IllegalStateException("提案流程状态已变化,请刷新后重试"); + } + ImprovementInstituteVote vote = findInstituteVote(lockedProposal.getId(), loginUser.getId()); + if (!"voted".equals(vote.getVoteStatus())) { + if (!"agree".equals(vote.getVoteResult()) && !"disagree".equals(vote.getVoteResult())) { + throw new IllegalStateException("请先选择投票通过或投票反对"); + } + int updated = improvementInstituteVoteMapper.update(null, new LambdaUpdateWrapper() + .eq(ImprovementInstituteVote::getId, vote.getId()) + .eq(ImprovementInstituteVote::getVoteStatus, "pending") + .set(ImprovementInstituteVote::getVoteStatus, "voted") + .set(ImprovementInstituteVote::getVoteTime, new Date()) + .set(ImprovementInstituteVote::getProcessTaskId, action.getTaskId())); + if (updated != 1) { + throw new IllegalStateException("投票状态已变化,请刷新后重试"); + } + } + updateInstituteVoteSummaryIfComplete(lockedProposal, action.getProcessInstanceId()); + } + + private ImprovementInstituteVote findInstituteVote(String mainId, String voterId) { + return improvementInstituteVoteMapper.selectByMainId(mainId).stream() + .filter(item -> voterId.equals(item.getVoterId())) + .findFirst() + .orElseThrow(() -> new IllegalStateException("当前用户不在所级评议投票名单中")); + } + + /** + * 所级评议以名单确定时写入的应投票人数为分母。赞成票满足 agree * 3 >= total * 2 即通过,避免小数取整歧义。 + */ + private void updateInstituteVoteSummaryIfComplete(ImprovementProposal proposal, String processInstanceId) { + Integer totalVoters = proposal.getInstituteTotalVoters(); + if (totalVoters == null || totalVoters <= 0) { + throw new IllegalStateException("所级评议应投票人数未初始化"); + } + List votes = improvementInstituteVoteMapper.selectByMainId(proposal.getId()); + if (votes.size() != totalVoters) { + throw new IllegalStateException("所级评议投票名单与应投票人数不一致"); + } + if (votes.stream().anyMatch(item -> !"voted".equals(item.getVoteStatus()))) { + return; + } + long agreeCount = votes.stream().filter(item -> "agree".equals(item.getVoteResult())).count(); + long disagreeCount = votes.stream().filter(item -> "disagree".equals(item.getVoteResult())).count(); + if (agreeCount + disagreeCount != totalVoters) { + throw new IllegalStateException("所级评议投票结果不完整"); + } + String voteResult = agreeCount * 3 >= (long) totalVoters * 2 ? "passed" : "failed"; + ImprovementProposal update = new ImprovementProposal(); + update.setId(proposal.getId()); + update.setInstituteAgreeCount((int) agreeCount); + update.setInstituteDisagreeCount((int) disagreeCount); + update.setInstituteVoteResult(voteResult); + improvementProposalMapper.updateById(update); + runtimeService.setVariable(processInstanceId, "institute_vote_result", voteResult); + } + /** * 固定按角色编码读取名单,保存时再次查询以防前端伪造用户 ID 或角色配置已变更。 */ From 47bef7b81f6dcc57cb54820df7471da8750f81be Mon Sep 17 00:00:00 2001 From: ye1023 <12588209+ye1023@user.noreply.gitee.com> Date: Wed, 29 Jul 2026 10:59:14 +0800 Subject: [PATCH 10/12] =?UTF-8?q?yxk-20260729=20=E6=94=B9=E5=96=84?= =?UTF-8?q?=E6=8F=90=E6=A1=88=20Task=5Fimprove005=20=E4=B8=8D=E6=98=BE?= =?UTF-8?q?=E7=A4=BA=20TaskHandleInnerContent=E3=80=82=E8=AF=84=E5=A7=94?= =?UTF-8?q?=E9=80=89=E6=8B=A9=E2=80=9C=E6=8A=95=E7=A5=A8=E9=80=9A=E8=BF=87?= =?UTF-8?q?=E2=80=9D=E6=88=96=E2=80=9C=E6=8A=95=E7=A5=A8=E5=8F=8D=E5=AF=B9?= =?UTF-8?q?=E2=80=9D=E5=90=8E=E5=BC=B9=E5=87=BA=E7=A1=AE=E8=AE=A4=E6=A1=86?= =?UTF-8?q?=EF=BC=9B=E7=A1=AE=E8=AE=A4=E5=8D=B3=E9=94=81=E5=AE=9A=E4=B8=AA?= =?UTF-8?q?=E4=BA=BA=E6=8A=95=E7=A5=A8=E5=B9=B6=E7=9B=B4=E6=8E=A5=E5=AE=8C?= =?UTF-8?q?=E6=88=90=E5=BD=93=E5=89=8D=E6=B5=81=E7=A8=8B=E4=BB=BB=E5=8A=A1?= =?UTF-8?q?=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ImprovementProposalController.java | 6 ++-- .../service/IImprovementProposalService.java | 4 +++ .../impl/ImprovementProposalServiceImpl.java | 36 +++++++++++++++++-- 3 files changed, 40 insertions(+), 6 deletions(-) diff --git a/jeecg-module-supervision/src/main/java/org/jeecg/modules/improvementproposal/controller/ImprovementProposalController.java b/jeecg-module-supervision/src/main/java/org/jeecg/modules/improvementproposal/controller/ImprovementProposalController.java index 16af363..8bfe805 100644 --- a/jeecg-module-supervision/src/main/java/org/jeecg/modules/improvementproposal/controller/ImprovementProposalController.java +++ b/jeecg-module-supervision/src/main/java/org/jeecg/modules/improvementproposal/controller/ImprovementProposalController.java @@ -226,9 +226,9 @@ public class ImprovementProposalController { } @PostMapping(value = "/bpm/submitInstituteVote") - @Operation(summary = "锁定所级评委投票并汇总结果") - public Result submitInstituteVote(@RequestBody ImprovementProposalBpmActionDTO action) { - return handleBpmAction(() -> improvementProposalService.submitInstituteVote(action, currentUser())); + @Operation(summary = "确认所级评委投票并直接完成流程任务") + public Result submitInstituteVote(@RequestBody ImprovementProposalBpmActionDTO action, HttpServletRequest request) { + return handleBpmAction(() -> improvementProposalService.submitInstituteVoteAndComplete(action, currentUser(), request)); } private LoginUser currentUser() { diff --git a/jeecg-module-supervision/src/main/java/org/jeecg/modules/improvementproposal/service/IImprovementProposalService.java b/jeecg-module-supervision/src/main/java/org/jeecg/modules/improvementproposal/service/IImprovementProposalService.java index fa800f1..b02b44c 100644 --- a/jeecg-module-supervision/src/main/java/org/jeecg/modules/improvementproposal/service/IImprovementProposalService.java +++ b/jeecg-module-supervision/src/main/java/org/jeecg/modules/improvementproposal/service/IImprovementProposalService.java @@ -8,6 +8,7 @@ import org.jeecg.modules.improvementproposal.dto.ImprovementInstituteVoteCandida import org.jeecg.modules.improvementproposal.dto.ImprovementProposalBpmActionDTO; import org.jeecg.common.system.vo.LoginUser; import com.baomidou.mybatisplus.extension.service.IService; +import javax.servlet.http.HttpServletRequest; import java.io.Serializable; import java.util.Collection; import java.util.List; @@ -91,6 +92,9 @@ public interface IImprovementProposalService extends IService() .eq(ImprovementInstituteVote::getId, vote.getId()) .eq(ImprovementInstituteVote::getVoteStatus, "pending") + .set(ImprovementInstituteVote::getVoteResult, action.getVoteResult()) .set(ImprovementInstituteVote::getVoteStatus, "voted") .set(ImprovementInstituteVote::getVoteTime, new Date()) .set(ImprovementInstituteVote::getProcessTaskId, action.getTaskId())); @@ -457,6 +467,26 @@ public class ImprovementProposalServiceImpl extends ServiceImpl processParams = new HashMap<>(4); + processParams.put("taskId", action.getTaskId()); + processParams.put("processModel", "1"); + processParams.put("nextCodeCount", "1"); + // Task5 只有正常流转分支;通用办理服务以 end + 单分支执行 taskService.complete。 + processParams.put("nextnode", "end"); + Result result = extActTaskCcService.processComplete(processParams, request); + if (result == null || !result.isSuccess()) { + throw new IllegalStateException(result == null || oConvertUtils.isEmpty(result.getMessage()) + ? "投票已确认,但流程办理失败" + : result.getMessage()); + } + } + private ImprovementInstituteVote findInstituteVote(String mainId, String voterId) { return improvementInstituteVoteMapper.selectByMainId(mainId).stream() .filter(item -> voterId.equals(item.getVoterId())) From a0547c5db73a70693a45ae4c0411cdccc1e18bfd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E5=BF=97=E6=B5=A9?= <8583167+chen-zh@user.noreply.gitee.com> Date: Wed, 29 Jul 2026 03:08:07 +0000 Subject: [PATCH 11/12] =?UTF-8?q?!97=20czh-20260729-requestId=E7=A9=BA?= =?UTF-8?q?=E5=80=BC=E4=BF=9D=E6=8A=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * czh-20260729-requestId空值保护 * czh-20260729-sendBatch响应改用requestId --- .../jeecg/modules/ksim/controller/KsimTestController.java | 4 +--- .../modules/ksim/service/impl/KsimMessageServiceImpl.java | 7 +++---- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/jeecg-boot-module/jeecg-module-im/src/main/java/org/jeecg/modules/ksim/controller/KsimTestController.java b/jeecg-boot-module/jeecg-module-im/src/main/java/org/jeecg/modules/ksim/controller/KsimTestController.java index d73a871..e1cc756 100644 --- a/jeecg-boot-module/jeecg-module-im/src/main/java/org/jeecg/modules/ksim/controller/KsimTestController.java +++ b/jeecg-boot-module/jeecg-module-im/src/main/java/org/jeecg/modules/ksim/controller/KsimTestController.java @@ -105,9 +105,7 @@ public class KsimTestController { if (msgRespBody != null) { int code = msgRespBody.getIntValue("code"); result.put("success", code == 0 || code == 200); - if (msgRespBody.getJSONObject("dataBody") != null) { - result.put("messageId", msgRespBody.getJSONObject("dataBody").getString("messageId")); - } + result.put("requestId", msgRespBody.getString("requestId")); result.put("responseCode", code); } else { result.put("success", false); diff --git a/jeecg-boot-module/jeecg-module-im/src/main/java/org/jeecg/modules/ksim/service/impl/KsimMessageServiceImpl.java b/jeecg-boot-module/jeecg-module-im/src/main/java/org/jeecg/modules/ksim/service/impl/KsimMessageServiceImpl.java index bf620bd..aaa0d2b 100644 --- a/jeecg-boot-module/jeecg-module-im/src/main/java/org/jeecg/modules/ksim/service/impl/KsimMessageServiceImpl.java +++ b/jeecg-boot-module/jeecg-module-im/src/main/java/org/jeecg/modules/ksim/service/impl/KsimMessageServiceImpl.java @@ -66,10 +66,9 @@ public class KsimMessageServiceImpl implements IKsimMessageService { return Result.error(apiResult.getCode(), "即时通发送失败: " + apiResult.getMessage()); } - String messageId = apiResult.getDataBody() != null - ? apiResult.getDataBody().getString("messageId") : ""; - log.info("【即时通推送-sendBatch】成功, messageId: {}, toUserCount: {}, title: {}", messageId, + String requestId = apiResult.getRequestId() != null ? apiResult.getRequestId() : ""; + log.info("【即时通推送-sendBatch】成功, requestId: {}, toUserCount: {}, title: {}", requestId, toUserValueList != null ? toUserValueList.size() : 0, title); - return Result.OK(messageId); + return Result.OK(requestId); } } From 526a4df4ff4e39135058de32505488cadca73897 Mon Sep 17 00:00:00 2001 From: ye1023 <12588209+ye1023@user.noreply.gitee.com> Date: Wed, 29 Jul 2026 14:12:49 +0800 Subject: [PATCH 12/12] =?UTF-8?q?yxk-20260729=20=E6=94=B9=E5=96=84?= =?UTF-8?q?=E6=8F=90=E6=A1=88=20=E6=89=80=E7=BA=A7=E8=AF=84=E8=AE=AE?= =?UTF-8?q?=E7=BB=93=E6=9E=9C=EF=BC=9A=E9=80=9A=E8=BF=87/=E4=B8=8D?= =?UTF-8?q?=E9=80=9A=E8=BF=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../improvementproposal/entity/ImprovementProposal.java | 6 +++--- .../service/impl/ImprovementProposalServiceImpl.java | 8 ++++++-- .../improvementproposal/vo/ImprovementProposalPage.java | 6 +++--- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/jeecg-module-supervision/src/main/java/org/jeecg/modules/improvementproposal/entity/ImprovementProposal.java b/jeecg-module-supervision/src/main/java/org/jeecg/modules/improvementproposal/entity/ImprovementProposal.java index bce03ee..515fdae 100644 --- a/jeecg-module-supervision/src/main/java/org/jeecg/modules/improvementproposal/entity/ImprovementProposal.java +++ b/jeecg-module-supervision/src/main/java/org/jeecg/modules/improvementproposal/entity/ImprovementProposal.java @@ -140,9 +140,9 @@ public class ImprovementProposal implements Serializable { @Excel(name = "所级评议不同意票数", width = 15) @Schema(description = "所级评议不同意票数") private Integer instituteDisagreeCount; - /**所级评议结果:passed/failed*/ - @Excel(name = "所级评议结果:passed/failed", width = 15) - @Schema(description = "所级评议结果:passed/failed") + /**所级评议结果:通过/不通过*/ + @Excel(name = "所级评议结果:通过/不通过", width = 15) + @Schema(description = "所级评议结果:通过/不通过") private String instituteVoteResult; /**金奖未通过后的经办人手动确认结果*/ @Excel(name = "金奖未通过后的经办人手动确认结果", width = 15) diff --git a/jeecg-module-supervision/src/main/java/org/jeecg/modules/improvementproposal/service/impl/ImprovementProposalServiceImpl.java b/jeecg-module-supervision/src/main/java/org/jeecg/modules/improvementproposal/service/impl/ImprovementProposalServiceImpl.java index 352889b..dadc51b 100644 --- a/jeecg-module-supervision/src/main/java/org/jeecg/modules/improvementproposal/service/impl/ImprovementProposalServiceImpl.java +++ b/jeecg-module-supervision/src/main/java/org/jeecg/modules/improvementproposal/service/impl/ImprovementProposalServiceImpl.java @@ -64,6 +64,8 @@ public class ImprovementProposalServiceImpl extends ServiceImpl= (long) totalVoters * 2 ? "passed" : "failed"; + String voteResult = agreeCount * 3 >= (long) totalVoters * 2 + ? INSTITUTE_VOTE_RESULT_PASSED + : INSTITUTE_VOTE_RESULT_FAILED; ImprovementProposal update = new ImprovementProposal(); update.setId(proposal.getId()); update.setInstituteAgreeCount((int) agreeCount); diff --git a/jeecg-module-supervision/src/main/java/org/jeecg/modules/improvementproposal/vo/ImprovementProposalPage.java b/jeecg-module-supervision/src/main/java/org/jeecg/modules/improvementproposal/vo/ImprovementProposalPage.java index 064a54a..47c01a5 100644 --- a/jeecg-module-supervision/src/main/java/org/jeecg/modules/improvementproposal/vo/ImprovementProposalPage.java +++ b/jeecg-module-supervision/src/main/java/org/jeecg/modules/improvementproposal/vo/ImprovementProposalPage.java @@ -128,9 +128,9 @@ public class ImprovementProposalPage { @Excel(name = "所级评议不同意票数", width = 15) @Schema(description = "所级评议不同意票数") private Integer instituteDisagreeCount; - /**所级评议结果:passed/failed*/ - @Excel(name = "所级评议结果:passed/failed", width = 15) - @Schema(description = "所级评议结果:passed/failed") + /**所级评议结果:通过/不通过*/ + @Excel(name = "所级评议结果:通过/不通过", width = 15) + @Schema(description = "所级评议结果:通过/不通过") private String instituteVoteResult; /**金奖未通过后的经办人手动确认结果*/ @Excel(name = "金奖未通过后的经办人手动确认结果", width = 15)