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 23770dd..7ce05cf 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 @@ -28,6 +28,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.modules.improvementproposal.vo.ImprovementProposalPage; import org.jeecg.modules.improvementproposal.service.IImprovementProposalService; @@ -191,6 +192,27 @@ public class ImprovementProposalController { return handleBpmAction(() -> improvementProposalService.saveLeaderAward(action, currentUser())); } + @GetMapping(value = "/bpm/instituteVoteCandidates") + @Operation(summary = "查询所级评议投票候选人") + public Result> getInstituteVoteCandidates(@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.getInstituteVoteCandidates(action, currentUser())); + } catch (IllegalStateException e) { + return Result.error(e.getMessage()); + } + } + + @PostMapping(value = "/bpm/instituteVoteMembers") + @Operation(summary = "保存所级评议投票人员") + public Result saveInstituteVoteMembers(@RequestBody ImprovementProposalBpmActionDTO action) { + return handleBpmAction(() -> improvementProposalService.saveInstituteVoteMembers(action, currentUser())); + } + @PostMapping(value = "/bpm/archiveAward") @Operation(summary = "保存归档最终奖项") public Result saveArchiveAward(@RequestBody ImprovementProposalBpmActionDTO action) { diff --git a/jeecg-module-supervision/src/main/java/org/jeecg/modules/improvementproposal/dto/ImprovementInstituteVoteCandidateDTO.java b/jeecg-module-supervision/src/main/java/org/jeecg/modules/improvementproposal/dto/ImprovementInstituteVoteCandidateDTO.java new file mode 100644 index 0000000..3b777c5 --- /dev/null +++ b/jeecg-module-supervision/src/main/java/org/jeecg/modules/improvementproposal/dto/ImprovementInstituteVoteCandidateDTO.java @@ -0,0 +1,25 @@ +package org.jeecg.modules.improvementproposal.dto; + +import java.io.Serializable; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * 所级评议投票候选人。 + * 仅暴露名单选择和 Flowable 多实例所需的最小用户信息。 + */ +@Data +@Schema(description = "所级评议投票候选人") +public class ImprovementInstituteVoteCandidateDTO implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "用户ID") + private String id; + + @Schema(description = "登录用户名") + private String username; + + @Schema(description = "真实姓名") + private String realname; +} diff --git a/jeecg-module-supervision/src/main/java/org/jeecg/modules/improvementproposal/dto/ImprovementProposalBpmActionDTO.java b/jeecg-module-supervision/src/main/java/org/jeecg/modules/improvementproposal/dto/ImprovementProposalBpmActionDTO.java index be088d3..15373a5 100644 --- a/jeecg-module-supervision/src/main/java/org/jeecg/modules/improvementproposal/dto/ImprovementProposalBpmActionDTO.java +++ b/jeecg-module-supervision/src/main/java/org/jeecg/modules/improvementproposal/dto/ImprovementProposalBpmActionDTO.java @@ -1,6 +1,7 @@ package org.jeecg.modules.improvementproposal.dto; import java.io.Serializable; +import java.util.List; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; @@ -35,4 +36,11 @@ public class ImprovementProposalBpmActionDTO implements Serializable { @Schema(description = "投票结果:agree/disagree") private String voteResult; + + /** + * 精益管理部门经办人在所级评议节点选择的投票人 ID 列表。 + * 服务端会按固定角色重新校验该列表,不能将其作为投票人身份的信任来源。 + */ + @Schema(description = "所级评议投票人ID列表") + private List voterIds; } diff --git a/jeecg-module-supervision/src/main/java/org/jeecg/modules/improvementproposal/mapper/ImprovementInstituteVoteMapper.java b/jeecg-module-supervision/src/main/java/org/jeecg/modules/improvementproposal/mapper/ImprovementInstituteVoteMapper.java index fcf2b9c..93fc97d 100644 --- a/jeecg-module-supervision/src/main/java/org/jeecg/modules/improvementproposal/mapper/ImprovementInstituteVoteMapper.java +++ b/jeecg-module-supervision/src/main/java/org/jeecg/modules/improvementproposal/mapper/ImprovementInstituteVoteMapper.java @@ -28,4 +28,7 @@ public interface ImprovementInstituteVoteMapper extends BaseMapper */ public List selectByMainId(@Param("mainId") String mainId); + + /** 任务尚未进入投票节点时,仅失效本轮待投票记录,保留已投票历史。 */ + int logicalDeletePendingByMainId(@Param("mainId") String mainId); } diff --git a/jeecg-module-supervision/src/main/java/org/jeecg/modules/improvementproposal/mapper/ImprovementProposalMapper.java b/jeecg-module-supervision/src/main/java/org/jeecg/modules/improvementproposal/mapper/ImprovementProposalMapper.java index 335b2d5..6a633c9 100644 --- a/jeecg-module-supervision/src/main/java/org/jeecg/modules/improvementproposal/mapper/ImprovementProposalMapper.java +++ b/jeecg-module-supervision/src/main/java/org/jeecg/modules/improvementproposal/mapper/ImprovementProposalMapper.java @@ -2,8 +2,10 @@ package org.jeecg.modules.improvementproposal.mapper; import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Select; +import org.jeecg.modules.improvementproposal.dto.ImprovementInstituteVoteCandidateDTO; import org.jeecg.modules.improvementproposal.entity.ImprovementProposal; import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import java.util.List; /** * @Description: improvement_proposal @@ -20,4 +22,7 @@ public interface ImprovementProposalMapper extends BaseMapper selectInstituteVoteCandidates(@Param("roleCode") String roleCode); + } diff --git a/jeecg-module-supervision/src/main/java/org/jeecg/modules/improvementproposal/mapper/xml/ImprovementInstituteVoteMapper.xml b/jeecg-module-supervision/src/main/java/org/jeecg/modules/improvementproposal/mapper/xml/ImprovementInstituteVoteMapper.xml index c70bb9b..4335c78 100644 --- a/jeecg-module-supervision/src/main/java/org/jeecg/modules/improvementproposal/mapper/xml/ImprovementInstituteVoteMapper.xml +++ b/jeecg-module-supervision/src/main/java/org/jeecg/modules/improvementproposal/mapper/xml/ImprovementInstituteVoteMapper.xml @@ -12,5 +12,16 @@ SELECT * FROM improvement_institute_vote WHERE - main_id = #{mainId} + 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());