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 065ef57..d51949c 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 @@ -118,14 +118,36 @@ public class ImprovementProposalController { @RequiresPermissions("improvementproposal:improvement_proposal:edit") @RequestMapping(value = "/edit", method = {RequestMethod.PUT,RequestMethod.POST}) public Result edit(@RequestBody ImprovementProposalPage improvementProposalPage) { - ImprovementProposal improvementProposal = new ImprovementProposal(); - BeanUtils.copyProperties(improvementProposalPage, improvementProposal); - ImprovementProposal improvementProposalEntity = improvementProposalService.getById(improvementProposal.getId()); - if(improvementProposalEntity==null) { - return Result.error("未找到对应数据"); + try { + ImprovementProposal improvementProposal = new ImprovementProposal(); + BeanUtils.copyProperties(improvementProposalPage, improvementProposal); + improvementProposalService.updateMain(improvementProposal, improvementProposalPage.getImprovementDeptScoreList(),improvementProposalPage.getImprovementInstituteVoteList()); + return Result.OK("编辑成功!"); + } catch (IllegalStateException e) { + return Result.error(e.getMessage()); + } + } + + /** + * 使用改善提案主表作为流程业务数据发起审批,不复用督办任务表。 + */ + @PostMapping(value = "/startProcess") + public Result startProcess(@RequestBody(required = false) Map requestBody, + @RequestParam(name = "id", required = false) String id) { + // defHttp 的 POST 参数默认在请求体中;同时兼容外部调用将 id 放在 URL 查询串的场景。 + if (oConvertUtils.isEmpty(id) && requestBody != null) { + id = requestBody.get("id"); + } + if (oConvertUtils.isEmpty(id)) { + return Result.error("提案ID不能为空"); + } + LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal(); + try { + String processInstanceId = improvementProposalService.startProcess(id, sysUser.getUsername()); + return Result.OK("流程发起成功!", processInstanceId); + } catch (IllegalStateException e) { + return Result.error(e.getMessage()); } - improvementProposalService.updateMain(improvementProposal, improvementProposalPage.getImprovementDeptScoreList(),improvementProposalPage.getImprovementInstituteVoteList()); - return Result.OK("编辑成功!"); } /** @@ -139,8 +161,12 @@ public class ImprovementProposalController { @RequiresPermissions("improvementproposal:improvement_proposal:delete") @DeleteMapping(value = "/delete") public Result delete(@RequestParam(name="id",required=true) String id) { - improvementProposalService.delMain(id); - return Result.OK("删除成功!"); + try { + improvementProposalService.delMain(id); + return Result.OK("删除成功!"); + } catch (IllegalStateException e) { + return Result.error(e.getMessage()); + } } /** @@ -154,8 +180,12 @@ public class ImprovementProposalController { @RequiresPermissions("improvementproposal:improvement_proposal:deleteBatch") @DeleteMapping(value = "/deleteBatch") public Result deleteBatch(@RequestParam(name="ids",required=true) String ids) { - this.improvementProposalService.delBatchMain(Arrays.asList(ids.split(","))); - return Result.OK("批量删除成功!"); + try { + this.improvementProposalService.delBatchMain(Arrays.asList(ids.split(","))); + return Result.OK("批量删除成功!"); + } catch (IllegalStateException e) { + return Result.error(e.getMessage()); + } } /** 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 167f101..9f100d7 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 @@ -1,8 +1,7 @@ package org.jeecg.modules.improvementproposal.mapper; -import java.util.List; - import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; import org.jeecg.modules.improvementproposal.entity.ImprovementProposal; import com.baomidou.mybatisplus.core.mapper.BaseMapper; @@ -14,4 +13,10 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper; */ public interface ImprovementProposalMapper extends BaseMapper { + /** + * 锁定提案主表,串行化流程发起、编辑和删除操作,避免同一提案生成多个流程实例。 + */ + @Select("SELECT * FROM improvement_proposal WHERE id = #{id} AND del_flag = '0' FOR UPDATE") + ImprovementProposal selectByIdForUpdate(@Param("id") String id); + } 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 6ef7e75..6ac33e2 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 @@ -16,6 +16,15 @@ import java.util.List; */ public interface IImprovementProposalService extends IService { + /** + * 发起改善提案审批流程。 + * + * @param id 提案主表 ID + * @param username 当前发起人账号 + * @return 流程实例 ID + */ + String startProcess(String id, String username); + /** * 添加一对多 * 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 7e41be7..381e8c2 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 @@ -7,6 +7,9 @@ import org.jeecg.modules.improvementproposal.mapper.ImprovementDeptScoreMapper; import org.jeecg.modules.improvementproposal.mapper.ImprovementInstituteVoteMapper; import org.jeecg.modules.improvementproposal.mapper.ImprovementProposalMapper; import org.jeecg.modules.improvementproposal.service.IImprovementProposalService; +import org.jeecg.common.api.vo.Result; +import org.jeecg.common.util.oConvertUtils; +import org.jeecg.modules.extbpm.process.service.impl.BpmBaseExtApiImpl; import org.springframework.stereotype.Service; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import org.springframework.beans.factory.annotation.Autowired; @@ -24,6 +27,9 @@ import java.util.Collection; @Service public class ImprovementProposalServiceImpl extends ServiceImpl implements IImprovementProposalService { private static final String NORMAL_DEL_FLAG = "0"; + private static final String BPM_STATUS_DRAFT = "1"; + private static final String FLOW_CODE = "dev_improvement_proposal_001"; + private static final String BPM_FORM_URL = "gh/improvementProposal/components/ImprovementProposalBPMForm"; @Autowired private ImprovementProposalMapper improvementProposalMapper; @@ -31,6 +37,34 @@ public class ImprovementProposalServiceImpl extends ServiceImpl result = bpmBaseExtApi.startMutilProcess(FLOW_CODE, proposal.getId(), BPM_FORM_URL, BPM_FORM_URL, username, null); + if (result == null || !result.isSuccess() || oConvertUtils.isEmpty(result.getResult())) { + throw new IllegalStateException(result == null || oConvertUtils.isEmpty(result.getMessage()) ? "发起流程失败" : result.getMessage()); + } + + // 流程引擎会按 BPM 配置将 bpm_status 回写为处理中;此处使用局部对象更新,避免旧实体的草稿状态将其覆盖。 + ImprovementProposal processUpdate = new ImprovementProposal(); + processUpdate.setId(proposal.getId()); + processUpdate.setProcessInstanceId(result.getResult()); + if (improvementProposalMapper.updateById(processUpdate) != 1) { + throw new IllegalStateException("流程已启动,但流程实例关联保存失败"); + } + return result.getResult(); + } catch (IllegalStateException e) { + throw e; + } catch (Exception e) { + throw new IllegalStateException("发起流程失败:" + e.getMessage(), e); + } + } @Override @Transactional(rollbackFor = Exception.class) @@ -65,6 +99,10 @@ public class ImprovementProposalServiceImpl extends ServiceImpl improvementDeptScoreList,List improvementInstituteVoteList) { + ImprovementProposal existingProposal = getDraftProposalForUpdate(improvementProposal.getId()); + // 草稿编辑不能伪造流程状态或覆盖已关联的流程实例。 + improvementProposal.setBpmStatus(existingProposal.getBpmStatus()); + improvementProposal.setProcessInstanceId(existingProposal.getProcessInstanceId()); improvementProposalMapper.updateById(improvementProposal); //1.先删除子表数据 @@ -97,6 +135,7 @@ public class ImprovementProposalServiceImpl extends ServiceImpl idList) { for(Serializable id:idList) { + getDraftProposalForUpdate(id.toString()); improvementDeptScoreMapper.deleteByMainId(id.toString()); improvementInstituteVoteMapper.deleteByMainId(id.toString()); improvementProposalMapper.deleteById(id); } } + + /** + * 任何会改变主表生命周期的操作都必须先锁定并确认仍是未发起草稿, + * 这样并发的“发起流程”和“编辑/删除”不会让流程与业务数据脱节。 + */ + private ImprovementProposal getDraftProposalForUpdate(String id) { + if (oConvertUtils.isEmpty(id)) { + throw new IllegalStateException("提案ID不能为空"); + } + ImprovementProposal proposal = improvementProposalMapper.selectByIdForUpdate(id); + if (proposal == null) { + throw new IllegalStateException("未找到对应提案"); + } + if (!BPM_STATUS_DRAFT.equals(proposal.getBpmStatus()) || oConvertUtils.isNotEmpty(proposal.getProcessInstanceId())) { + throw new IllegalStateException("提案已进入流程,不能编辑、删除或重复发起"); + } + return proposal; + } }