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] =?UTF-8?q?yxk-20260728=20=E6=94=B9=E5=96=84=E6=8F=90?= =?UTF-8?q?=E6=A1=88=20=E5=AE=9E=E7=8E=B0=E9=83=A8=E9=97=A8=E8=AF=84?= =?UTF-8?q?=E8=AE=AE=E5=B0=8F=E7=BB=84=E6=89=93=E5=88=86=E5=8A=9F=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())) {