🐛 修复审核通过后再提交未新建MK流程实例的问题

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-09-29 02:44:48 +08:00
parent fc1e9a95de
commit 32cff235e0
9 changed files with 108 additions and 13 deletions
@@ -42,6 +42,7 @@ public interface IBusinessProcessClient {
String GET_CURRENT_NODES = API_PREFIX + "/getCurrentNodes"; String GET_CURRENT_NODES = API_PREFIX + "/getCurrentNodes";
String GET_PROCESS_INFO = API_PREFIX + "/getProcessInfo"; String GET_PROCESS_INFO = API_PREFIX + "/getProcessInfo";
String RESOLVE_BY_FORM_INSTANCE_ID = API_PREFIX + "/resolveByFormInstanceId"; String RESOLVE_BY_FORM_INSTANCE_ID = API_PREFIX + "/resolveByFormInstanceId";
String MARK_PROCESS_FINISHED = API_PREFIX + "/markProcessFinished";
/** /**
* 提交业务流程 * 提交业务流程
@@ -137,4 +138,15 @@ public interface IBusinessProcessClient {
*/ */
@GetMapping(RESOLVE_BY_FORM_INSTANCE_ID) @GetMapping(RESOLVE_BY_FORM_INSTANCE_ID)
FR<MkFormBindVO> resolveByFormInstanceId(@RequestParam("formInstanceId") Long formInstanceId); FR<MkFormBindVO> resolveByFormInstanceId(@RequestParam("formInstanceId") Long formInstanceId);
/**
* 公开页流程结束时标记业务流程通过/驳回并完结
*
* @param processInstanceId 流程实例id
* @param approved true=通过 false=驳回
* @return 是否更新成功
*/
@PostMapping(MARK_PROCESS_FINISHED)
FR<Boolean> markProcessFinished(@RequestParam("processInstanceId") String processInstanceId,
@RequestParam("approved") boolean approved);
} }
@@ -102,4 +102,12 @@ public class BusinessProcessClient implements IBusinessProcessClient {
public FR<MkFormBindVO> resolveByFormInstanceId(@RequestParam("formInstanceId") Long formInstanceId) { public FR<MkFormBindVO> resolveByFormInstanceId(@RequestParam("formInstanceId") Long formInstanceId) {
return FR.data(businessProcessService.resolveByFormInstanceId(formInstanceId)); return FR.data(businessProcessService.resolveByFormInstanceId(formInstanceId));
} }
@PreAuth(AuthConstant.PERMIT_ALL)
@PostMapping(MARK_PROCESS_FINISHED)
@Override
public FR<Boolean> markProcessFinished(@RequestParam("processInstanceId") String processInstanceId,
@RequestParam("approved") boolean approved) {
return FR.data(businessProcessService.markProcessFinished(processInstanceId, approved));
}
} }
@@ -58,6 +58,15 @@ public interface IBusinessProcessService extends IService<BusinessProcess> {
*/ */
MkFormBindVO resolveByFormInstanceId(Long formInstanceId); MkFormBindVO resolveByFormInstanceId(Long formInstanceId);
/**
* 公开页流程结束时标记业务流程通过/驳回并完结
*
* @param processInstanceId 流程实例id
* @param approved true=通过 false=驳回
* @return 是否更新成功
*/
boolean markProcessFinished(String processInstanceId, boolean approved);
/** /**
* 获取流程当前节点详情 * 获取流程当前节点详情
* *
@@ -62,13 +62,14 @@ public interface IMkFormBindService extends IService<MkFormBind> {
MkFormBindVO resolveByFormInstanceId(Long formInstanceId); MkFormBindVO resolveByFormInstanceId(Long formInstanceId);
/** /**
* 解析或生成表单实例id:无当前绑定则新建;当前流程已审批通过则新建;否则复用 * 解析或生成表单实例id:无当前绑定则新建;强制新建/当前流程已通过或已完结则新建;否则复用
* *
* @param bizType 业务类型 * @param bizType 业务类型
* @param bizId 业务主键 * @param bizId 业务主键
* @param forceNew 是否强制生成新表单实例(审核通过后再次提交)
* @return 本次应使用的表单实例id * @return 本次应使用的表单实例id
*/ */
Long resolveOrCreateFormInstanceId(String bizType, Long bizId); Long resolveOrCreateFormInstanceId(String bizType, Long bizId, boolean forceNew);
/** /**
* 回写流程实例id到当前绑定 * 回写流程实例id到当前绑定
@@ -140,7 +140,8 @@ public class BusinessProcessServiceImpl extends ServiceImpl<BusinessProcessMappe
String bizType = param.getBizType(); String bizType = param.getBizType();
Long bizId = resolveBizIdFromSubmitParam(param); Long bizId = resolveBizIdFromSubmitParam(param);
Long formInstanceId = mkFormBindService.resolveOrCreateFormInstanceId(bizType, bizId); boolean forceNew = Boolean.TRUE.equals(param.getForceNewFormInstance());
Long formInstanceId = mkFormBindService.resolveOrCreateFormInstanceId(bizType, bizId, forceNew);
String formInstanceIdText = String.valueOf(formInstanceId); String formInstanceIdText = String.valueOf(formInstanceId);
param.setFormInstanceId(formInstanceIdText); param.setFormInstanceId(formInstanceIdText);
@@ -149,8 +150,8 @@ public class BusinessProcessServiceImpl extends ServiceImpl<BusinessProcessMappe
.orderByDesc(BusinessProcess::getUpdateTime) .orderByDesc(BusinessProcess::getUpdateTime)
.last("limit 1") .last("limit 1")
); );
// 已有流程实例且 MK 仍能查到详情时,不再删除、不再重新创建提交 // 已有流程实例且 MK 仍能查到详情时,不再删除、不再重新创建提交(强制新建时跳过短路)
if (businessProcess != null && StringUtil.isNotBlank(businessProcess.getProcessInstanceId()) if (!forceNew && businessProcess != null && StringUtil.isNotBlank(businessProcess.getProcessInstanceId())
&& Objects.equals(formInstanceId, businessProcess.getFormInstanceId())) { && Objects.equals(formInstanceId, businessProcess.getFormInstanceId())) {
String existingProcessInstanceId = businessProcess.getProcessInstanceId(); String existingProcessInstanceId = businessProcess.getProcessInstanceId();
Object existingProcessInfo = this.getProcessInfo(existingProcessInstanceId, loginName); Object existingProcessInfo = this.getProcessInfo(existingProcessInstanceId, loginName);
@@ -247,8 +248,9 @@ public class BusinessProcessServiceImpl extends ServiceImpl<BusinessProcessMappe
if (businessProcess == null || StringUtil.isBlank(businessProcess.getProcessInstanceId())) { if (businessProcess == null || StringUtil.isBlank(businessProcess.getProcessInstanceId())) {
return false; return false;
} }
// 审批通过后允许再次提交新表单实例,视为当前无有效待办流程 // 审批通过 / 已完结:允许再次提交新表单实例
if (Objects.equals(ApproveStatusEnum.APPROVED.getValue(), businessProcess.getApproveStatus())) { if (Objects.equals(ApproveStatusEnum.APPROVED.getValue(), businessProcess.getApproveStatus())
|| (businessProcess.getIsCompleted() != null && businessProcess.getIsCompleted() == 1)) {
return false; return false;
} }
String loginName = businessProcess.getPromoterLoginName(); String loginName = businessProcess.getPromoterLoginName();
@@ -261,9 +263,24 @@ public class BusinessProcessServiceImpl extends ServiceImpl<BusinessProcessMappe
return false; return false;
} }
Object processInfo = this.getProcessInfo(businessProcess.getProcessInstanceId(), loginName); Object processInfo = this.getProcessInfo(businessProcess.getProcessInstanceId(), loginName);
// MK 流程已结束(fdProcessStatus=30)时视为无有效待办,需重新提交新实例
if (isMkProcessFinished(processInfo)) {
return false;
}
return hasProcessInfoData(processInfo); return hasProcessInfoData(processInfo);
} }
/**
* MK getProcessInfo 是否为已结束流程
*/
private boolean isMkProcessFinished(Object processInfo) {
if (!(processInfo instanceof Map<?, ?> map)) {
return false;
}
Object status = map.get("fdProcessStatus");
return status != null && "30".equals(String.valueOf(status));
}
/** /**
* MK getProcessInfo 是否返回有效数据 * MK getProcessInfo 是否返回有效数据
*/ */
@@ -345,6 +362,30 @@ public class BusinessProcessServiceImpl extends ServiceImpl<BusinessProcessMappe
return fallback; return fallback;
} }
@Transactional(rollbackFor = Exception.class)
@Override
public boolean markProcessFinished(String processInstanceId, boolean approved) {
AssertUtils.notBlank(processInstanceId, "流程实例id不能为空");
BusinessProcess businessProcess = this.getBusinessProcessByProcessInstanceId(processInstanceId);
if (businessProcess == null) {
log.warn("标记流程完结跳过,未找到业务流程 processInstanceId={}", processInstanceId);
return false;
}
String approveStatus = approved
? ApproveStatusEnum.APPROVED.getValue()
: ApproveStatusEnum.REJECTED.getValue();
businessProcess.setApproveStatus(approveStatus);
businessProcess.setIsCompleted(1);
businessProcess.setCompleteTime(new Date());
businessProcess.setCurrentNodeIds(null);
businessProcess.setCurrentNodeNames(null);
businessProcess.setCurrentHandlers(null);
boolean updated = this.updateById(businessProcess);
log.info("标记流程完结 processInstanceId={} approved={} approveStatus={} result={}",
processInstanceId, approved, approveStatus, updated);
return updated;
}
@Override @Override
public List<?> getCurrentNodes(String processInstanceId, String loginName) { public List<?> getCurrentNodes(String processInstanceId, String loginName) {
if (StringUtils.isBlank(processInstanceId)) { if (StringUtils.isBlank(processInstanceId)) {
@@ -619,6 +660,7 @@ public class BusinessProcessServiceImpl extends ServiceImpl<BusinessProcessMappe
if (processInstanceIdBlank) { if (processInstanceIdBlank) {
BusinessProcess businessProcess = this.getOne(Wrappers.<BusinessProcess>lambdaQuery() BusinessProcess businessProcess = this.getOne(Wrappers.<BusinessProcess>lambdaQuery()
.eq(BusinessProcess::getBizId, bizId) .eq(BusinessProcess::getBizId, bizId)
.orderByDesc(BusinessProcess::getUpdateTime)
.last("limit 1") .last("limit 1")
); );
AssertUtils.notNull(businessProcess, "业务流程不存在"); AssertUtils.notNull(businessProcess, "业务流程不存在");
@@ -109,7 +109,7 @@ public class MkFormBindServiceImpl extends ServiceImpl<MkFormBindMapper, MkFormB
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
@Override @Override
public Long resolveOrCreateFormInstanceId(String bizType, Long bizId) { public Long resolveOrCreateFormInstanceId(String bizType, Long bizId, boolean forceNew) {
AssertUtils.notNull(bizId, "业务id不能为空"); AssertUtils.notNull(bizId, "业务id不能为空");
MkFormBind current = this.getCurrentBind(bizType, bizId); MkFormBind current = this.getCurrentBind(bizType, bizId);
if (current == null) { if (current == null) {
@@ -122,9 +122,12 @@ public class MkFormBindServiceImpl extends ServiceImpl<MkFormBindMapper, MkFormB
); );
boolean approvedPass = businessProcess != null boolean approvedPass = businessProcess != null
&& Objects.equals(ApproveStatusEnum.APPROVED.getValue(), businessProcess.getApproveStatus()); && Objects.equals(ApproveStatusEnum.APPROVED.getValue(), businessProcess.getApproveStatus());
if (approvedPass) { boolean completed = businessProcess != null
log.info("审核通过后再次提交,生成新表单实例 bizType={} bizId={} oldFormInstanceId={}", && businessProcess.getIsCompleted() != null
bizType, bizId, current.getFormInstanceId()); && businessProcess.getIsCompleted() == 1;
if (forceNew || approvedPass || completed) {
log.info("生成新表单实例 forceNew={} approvedPass={} completed={} bizType={} bizId={} oldFormInstanceId={}",
forceNew, approvedPass, completed, bizType, bizId, current.getFormInstanceId());
this.lambdaUpdate() this.lambdaUpdate()
.eq(MkFormBind::getBizId, bizId) .eq(MkFormBind::getBizId, bizId)
.eq(MkFormBind::getIsCurrent, 1) .eq(MkFormBind::getIsCurrent, 1)
@@ -151,6 +151,14 @@ public class MkProcessMessageService {
} else { } else {
handler.rejectFromProcess(bizId, processorName); handler.rejectFromProcess(bizId, processorName);
} }
try {
FR<Boolean> markResult = businessProcessClient.markProcessFinished(processId, approved);
log.info("公开页标记业务流程完结 bizType={} processId={} approved={} result={}",
bizType, processId, approved, JSON.toJSONString(markResult));
} catch (Exception markException) {
log.error("公开页标记业务流程完结失败 bizType={} processId={} approved={}",
bizType, processId, approved, markException);
}
} catch (NumberFormatException e) { } catch (NumberFormatException e) {
log.warn("流程{}但业务id格式不正确 bizType={} id={}", action, bizType, bizIdText); log.warn("流程{}但业务id格式不正确 bizType={} id={}", action, bizType, bizIdText);
} catch (Exception e) { } catch (Exception e) {
@@ -143,6 +143,13 @@ public class CustomerArchivePublicProcessService {
} else { } else {
customerArchiveService.rejectFromProcess(customerId, processorName); customerArchiveService.rejectFromProcess(customerId, processorName);
} }
try {
FR<Boolean> markResult = businessProcessClient.markProcessFinished(processId, approved);
log.info("客商公开页标记业务流程完结 processId={} approved={} result={}",
processId, approved, JSON.toJSONString(markResult));
} catch (Exception markException) {
log.error("客商公开页标记业务流程完结失败 processId={} approved={}", processId, approved, markException);
}
} catch (NumberFormatException e) { } catch (NumberFormatException e) {
log.warn("流程{}但客商id格式不正确:{}", action, customerIdText); log.warn("流程{}但客商id格式不正确:{}", action, customerIdText);
} catch (Exception e) { } catch (Exception e) {
@@ -55,4 +55,9 @@ public class MKProcessCreateDTO implements Serializable {
*/ */
@JsonProperty(access = JsonProperty.Access.WRITE_ONLY) @JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
private String bizType; private String bizType;
/**
* 强制生成新表单实例(审核通过后再次提交),仅 ERP 内部使用,不传给 MK
*/
@JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
private Boolean forceNewFormInstance;
} }