yxk-20260731

改善提案-删除流程功能
为已发起且仍在处理中的改善提案增加“删除流程”操作。删除后终止当前 Flowable 实例、清理本轮流程数据,并将提案回退为草稿,允许重新编辑和发起。
Implementation Changes
后端新增 POST /improvementproposal/improvementProposal/withdrawProcess?id=...,复用现有 improvementproposal:improvement_proposal:delete 权限。
在 ImprovementProposalService 新增事务方法:锁定主表后,仅允许 bpm_status='2' 且存在运行中流程实例的提案撤回;流程已完成、已作废、草稿或实例不存在时拒绝操作。
参考党委会的流程清理方式,终止 Flowable 运行实例并删除该实例的历史、审批意见、抄送、流程中间数据和流程日志;不改动全局流程引擎代码。
删除本轮 improvement_dept_score、improvement_institute_vote 数据,避免重新发起后复用旧评分、投票结果。
将流程衍生字段清空:流程实例、初审/评分/负责人奖项、评分汇总、所级投票人数与结果、最终奖项、人工确认、归档人及归档时间;保留提案基本信息、编号和业务附件。
将主表 bpm_status 重置为 1,使现有编辑、删除和发起流程逻辑自动恢复可用。
前端台账操作菜单在处理中记录显示“删除流程”,增加明确提示“删除后将回退为草稿,当前评分、投票和审批数据将被清空”;成功后刷新列表。
不增加批量删除流程功能,现有批量删除仍只处理草稿。
This commit is contained in:
ye1023
2026-07-31 15:07:48 +08:00
parent a30ef73be2
commit 5e14c952cb
3 changed files with 129 additions and 0 deletions
@@ -171,6 +171,22 @@ public class ImprovementProposalController {
} }
} }
/**
* 删除运行中的流程并回退草稿。提案基本信息和业务附件会保留,流程产生的评分、投票数据会清空。
*/
@AutoLog(value = "改善提案-删除流程并回退草稿")
@Operation(summary = "改善提案-删除流程并回退草稿")
@RequiresPermissions("improvementproposal:improvement_proposal:delete")
@PostMapping(value = "/withdrawProcess")
public Result<String> withdrawProcess(@RequestParam(name = "id") String id) {
try {
improvementProposalService.withdrawProcess(id);
return Result.OK("流程已删除,提案已回退为草稿");
} catch (IllegalStateException e) {
return Result.error(e.getMessage());
}
}
@PostMapping(value = "/bpm/initialReview") @PostMapping(value = "/bpm/initialReview")
@Operation(summary = "保存部门精益专员初审结果") @Operation(summary = "保存部门精益专员初审结果")
public Result<String> saveInitialReview(@RequestBody ImprovementProposalBpmActionDTO action) { public Result<String> saveInitialReview(@RequestBody ImprovementProposalBpmActionDTO action) {
@@ -31,6 +31,13 @@ public interface IImprovementProposalService extends IService<ImprovementProposa
*/ */
String startProcess(String id, String username); String startProcess(String id, String username);
/**
* 删除当前运行中的改善提案流程,并将提案恢复为可编辑、可重新发起的草稿。
*
* @param id 提案主表 ID
*/
void withdrawProcess(String id);
/** /**
* 添加一对多 * 添加一对多
* *
@@ -15,7 +15,16 @@ import org.jeecg.common.api.vo.Result;
import org.jeecg.common.util.oConvertUtils; import org.jeecg.common.util.oConvertUtils;
import org.jeecg.common.system.vo.LoginUser; import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.modules.extbpm.process.service.impl.BpmBaseExtApiImpl; import org.jeecg.modules.extbpm.process.service.impl.BpmBaseExtApiImpl;
import org.jeecg.modules.extbpm.process.entity.ExtActBpmFile;
import org.jeecg.modules.extbpm.process.entity.ExtActBpmLog;
import org.jeecg.modules.extbpm.process.entity.ExtActFlowData;
import org.jeecg.modules.extbpm.process.entity.ExtActTaskCc;
import org.jeecg.modules.extbpm.process.service.IExtActBpmFileService;
import org.jeecg.modules.extbpm.process.service.IExtActBpmLogService;
import org.jeecg.modules.extbpm.process.service.IExtActFlowDataService;
import org.jeecg.modules.extbpm.process.service.IExtActTaskCcService; import org.jeecg.modules.extbpm.process.service.IExtActTaskCcService;
import org.jeecg.modules.taskapprovalopinion.entity.TaskApprovalOpinion;
import org.jeecg.modules.taskapprovalopinion.service.ITaskApprovalOpinionService;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@@ -39,6 +48,7 @@ import org.jeecg.modules.system.entity.SysDepart;
import org.jeecg.modules.system.service.ISysRoleService; import org.jeecg.modules.system.service.ISysRoleService;
import org.jeecg.modules.system.service.ISysUserDepartService; import org.jeecg.modules.system.service.ISysUserDepartService;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
@@ -93,6 +103,14 @@ public class ImprovementProposalServiceImpl extends ServiceImpl<ImprovementPropo
private ISysUserDepartService sysUserDepartService; private ISysUserDepartService sysUserDepartService;
@Autowired @Autowired
private IExtActTaskCcService extActTaskCcService; private IExtActTaskCcService extActTaskCcService;
@Autowired
private ITaskApprovalOpinionService taskApprovalOpinionService;
@Autowired
private IExtActFlowDataService extActFlowDataService;
@Autowired
private IExtActBpmLogService extActBpmLogService;
@Autowired
private IExtActBpmFileService extActBpmFileService;
@Override @Override
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
@@ -147,6 +165,77 @@ public class ImprovementProposalServiceImpl extends ServiceImpl<ImprovementPropo
saveMain(improvementProposal, null, null); saveMain(improvementProposal, null, null);
} }
@Override
@Transactional(rollbackFor = Exception.class)
public void withdrawProcess(String id) {
ImprovementProposal proposal = getProcessingProposalForUpdate(id);
String processInstanceId = proposal.getProcessInstanceId();
long runtimeCount = runtimeService.createProcessInstanceQuery()
.processInstanceId(processInstanceId)
.count();
if (runtimeCount == 0) {
throw new IllegalStateException("当前流程已结束或不存在,不能删除流程");
}
// 改善提案未使用 task_task 中间表,按实例 ID 清理本轮流程数据,避免重新发起时读取到旧记录。
runtimeService.deleteProcessInstance(processInstanceId, "改善提案删除流程并回退草稿");
historyService.deleteHistoricProcessInstance(processInstanceId);
clearProcessRelatedData(processInstanceId);
improvementDeptScoreMapper.deleteByMainId(proposal.getId());
improvementInstituteVoteMapper.deleteByMainId(proposal.getId());
// MyBatis-Plus 默认会忽略实体中的 null;使用 UpdateWrapper 才能把上一轮流程结果真正清空。
LambdaUpdateWrapper<ImprovementProposal> resetWrapper = new LambdaUpdateWrapper<ImprovementProposal>()
.eq(ImprovementProposal::getId, proposal.getId())
.set(ImprovementProposal::getProcessInstanceId, null)
.set(ImprovementProposal::getBpmStatus, BPM_STATUS_DRAFT)
.set(ImprovementProposal::getInitialAward, null)
.set(ImprovementProposal::getNeedDeptScore, null)
.set(ImprovementProposal::getDeptAvgScore, null)
.set(ImprovementProposal::getSuggestedAward, null)
.set(ImprovementProposal::getLeaderFinalAward, null)
.set(ImprovementProposal::getIsneedvote, null)
.set(ImprovementProposal::getInstituteVoters, null)
.set(ImprovementProposal::getInstituteTotalVoters, null)
.set(ImprovementProposal::getInstituteAgreeCount, null)
.set(ImprovementProposal::getInstituteDisagreeCount, null)
.set(ImprovementProposal::getInstituteVoteResult, null)
.set(ImprovementProposal::getFinalAward, null)
.set(ImprovementProposal::getManualConfirmResult, null)
.set(ImprovementProposal::getArchiveBy, null)
.set(ImprovementProposal::getArchiveTime, null);
if (improvementProposalMapper.update(null, resetWrapper) != 1) {
throw new IllegalStateException("流程已删除,但提案回退草稿失败");
}
}
/** 清理仅属于本次流程实例的审批、抄送和日志数据,不影响提案申请附件。 */
private void clearProcessRelatedData(String processInstanceId) {
taskApprovalOpinionService.remove(new LambdaQueryWrapper<TaskApprovalOpinion>()
.eq(TaskApprovalOpinion::getProcessInstId, processInstanceId));
extActTaskCcService.remove(new LambdaQueryWrapper<ExtActTaskCc>()
.eq(ExtActTaskCc::getProcInstId, processInstanceId));
extActFlowDataService.remove(new LambdaQueryWrapper<ExtActFlowData>()
.eq(ExtActFlowData::getProcessInstId, processInstanceId));
List<ExtActBpmLog> bpmLogs = extActBpmLogService.list(new LambdaQueryWrapper<ExtActBpmLog>()
.eq(ExtActBpmLog::getProcInstId, processInstanceId));
if (!bpmLogs.isEmpty()) {
List<String> bpmLogIds = new ArrayList<>();
for (ExtActBpmLog bpmLog : bpmLogs) {
if (oConvertUtils.isNotEmpty(bpmLog.getId())) {
bpmLogIds.add(bpmLog.getId());
}
}
if (!bpmLogIds.isEmpty()) {
extActBpmFileService.remove(new LambdaQueryWrapper<ExtActBpmFile>()
.in(ExtActBpmFile::getBpmLogId, bpmLogIds));
}
extActBpmLogService.remove(new LambdaQueryWrapper<ExtActBpmLog>()
.eq(ExtActBpmLog::getProcInstId, processInstanceId));
}
}
@Override @Override
public List<ImprovementProposalDepartmentDTO> getMyProposalDepartments(LoginUser loginUser) { public List<ImprovementProposalDepartmentDTO> getMyProposalDepartments(LoginUser loginUser) {
if (loginUser == null || oConvertUtils.isEmpty(loginUser.getId())) { if (loginUser == null || oConvertUtils.isEmpty(loginUser.getId())) {
@@ -814,6 +903,23 @@ public class ImprovementProposalServiceImpl extends ServiceImpl<ImprovementPropo
} }
return proposal; return proposal;
} }
/**
* 撤回只能作用于正在运行的实例;通过主表行锁防止与流程办理、流程结束回写并发交叉。
*/
private ImprovementProposal getProcessingProposalForUpdate(String id) {
if (oConvertUtils.isEmpty(id)) {
throw new IllegalStateException("提案ID不能为空");
}
ImprovementProposal proposal = improvementProposalMapper.selectByIdForUpdate(id);
if (proposal == null) {
throw new IllegalStateException("未找到对应提案");
}
if (!"2".equals(proposal.getBpmStatus()) || oConvertUtils.isEmpty(proposal.getProcessInstanceId())) {
throw new IllegalStateException("仅处理中的提案允许删除流程");
}
return proposal;
}
@Override @Override
public Integer getLatestProposalSequence(Integer year) { public Integer getLatestProposalSequence(Integer year) {