mirror of
https://gitee.com/huangge1199_admin/vue-pro.git
synced 2024-11-22 23:31:52 +08:00
【代码评审】BPM:review 快搭的实现
This commit is contained in:
parent
8585e05772
commit
41b9ab2ba5
@ -4,7 +4,6 @@ import cn.hutool.core.util.ArrayUtil;
|
|||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
|
||||||
// TODO @芋艿:审批方式的名字,可能要看下;
|
|
||||||
/**
|
/**
|
||||||
* BPM 多人审批方式的枚举
|
* BPM 多人审批方式的枚举
|
||||||
*
|
*
|
||||||
|
@ -13,6 +13,7 @@ import lombok.Getter;
|
|||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
public enum BpmFieldPermissionEnum {
|
public enum BpmFieldPermissionEnum {
|
||||||
|
|
||||||
|
// TODO @jason:这个顺序要不要改下,和页面保持一致;只读(1)、编辑(2)、隐藏(3)
|
||||||
WRITE(1, "可编辑"),
|
WRITE(1, "可编辑"),
|
||||||
READ(2, "只读"),
|
READ(2, "只读"),
|
||||||
NONE(3, "隐藏");
|
NONE(3, "隐藏");
|
||||||
|
@ -13,8 +13,10 @@ import lombok.Getter;
|
|||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
public enum BpmUserTaskRejectHandlerType {
|
public enum BpmUserTaskRejectHandlerType {
|
||||||
|
|
||||||
|
// TODO @jason:是不是收敛成 2 个:FINISH_PROCESS => 1. 直接结束流程;RETURN_PRE_USER_TASK => 2. 驳回到指定节点(RETURN_USER_TASK【去掉 PRE】)
|
||||||
FINISH_PROCESS(1, "终止流程"),
|
FINISH_PROCESS(1, "终止流程"),
|
||||||
RETURN_PRE_USER_TASK(2, "驳回到指定任务节点"),
|
RETURN_PRE_USER_TASK(2, "驳回到指定任务节点"),
|
||||||
|
|
||||||
FINISH_PROCESS_BY_REJECT_NUMBER(3, "按拒绝人数终止流程"), // 用于会签
|
FINISH_PROCESS_BY_REJECT_NUMBER(3, "按拒绝人数终止流程"), // 用于会签
|
||||||
FINISH_TASK(4, "结束任务"); // 待实现,可能会用于意见分支
|
FINISH_TASK(4, "结束任务"); // 待实现,可能会用于意见分支
|
||||||
|
|
||||||
@ -24,4 +26,5 @@ public enum BpmUserTaskRejectHandlerType {
|
|||||||
public static BpmUserTaskRejectHandlerType typeOf(Integer type) {
|
public static BpmUserTaskRejectHandlerType typeOf(Integer type) {
|
||||||
return ArrayUtil.firstMatch(item -> item.getType().equals(type), values());
|
return ArrayUtil.firstMatch(item -> item.getType().equals(type), values());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -149,6 +149,7 @@ public class BpmModelController {
|
|||||||
|
|
||||||
// ========== 仿钉钉/飞书的精简模型 =========
|
// ========== 仿钉钉/飞书的精简模型 =========
|
||||||
|
|
||||||
|
// TODO @jason:modelId => id 哈。一般属于自己的模块,可以简化命名。
|
||||||
@GetMapping("/simple/get")
|
@GetMapping("/simple/get")
|
||||||
@Operation(summary = "获得仿钉钉流程设计模型")
|
@Operation(summary = "获得仿钉钉流程设计模型")
|
||||||
@Parameter(name = "modelId", description = "流程模型编号", required = true, example = "a2c5eee0-eb6c-11ee-abf4-0c37967c420a")
|
@Parameter(name = "modelId", description = "流程模型编号", required = true, example = "a2c5eee0-eb6c-11ee-abf4-0c37967c420a")
|
||||||
|
@ -43,6 +43,7 @@ public class BpmSimpleModelNodeVO {
|
|||||||
@Schema(description = "节点的属性")
|
@Schema(description = "节点的属性")
|
||||||
private Map<String, Object> attributes; // TODO @jason:建议是字段分拆下;类似说:
|
private Map<String, Object> attributes; // TODO @jason:建议是字段分拆下;类似说:
|
||||||
|
|
||||||
|
// TODO @jason:看看是不是可以简化;
|
||||||
/**
|
/**
|
||||||
* 附加节点 Id, 该节点不从前端传入。 由程序生成. 由于当个节点无法完成功能。 需要附加节点来完成。
|
* 附加节点 Id, 该节点不从前端传入。 由程序生成. 由于当个节点无法完成功能。 需要附加节点来完成。
|
||||||
* 例如: 会签时需要按拒绝人数来终止流程。 需要 userTask + ServiceTask 两个节点配合完成。 serviceTask 由后端生成。
|
* 例如: 会签时需要按拒绝人数来终止流程。 需要 userTask + ServiceTask 两个节点配合完成。 serviceTask 由后端生成。
|
||||||
@ -52,12 +53,13 @@ public class BpmSimpleModelNodeVO {
|
|||||||
|
|
||||||
// Map<String, Integer> formPermissions; 表单权限;仅发起、审批、抄送节点会使用
|
// Map<String, Integer> formPermissions; 表单权限;仅发起、审批、抄送节点会使用
|
||||||
// Integer approveMethod; 审批方式;仅审批节点会使用
|
// Integer approveMethod; 审批方式;仅审批节点会使用
|
||||||
// TODO @jason 后面和前端一起调整一下
|
// TODO @jason 后面和前端一起调整一下;下面的 ①、②、③ 是优先级
|
||||||
// TODO @芋艿:审批人的选择;
|
// TODO @芋艿:① 审批人的选择;
|
||||||
// TODO @芋艿:没有人的策略?
|
// TODO @芋艿:⑥ 没有人的策略?
|
||||||
// TODO @芋艿:审批拒绝的策略?
|
// TODO @芋艿:② 审批拒绝的策略?
|
||||||
// TODO @芋艿:配置的可操作列表?
|
// TODO @芋艿:③ 配置的可操作列表?(操作权限)
|
||||||
// TODO @芋艿:超时配置;要支持指定时间点、指定时间间隔;
|
// TODO @芋艿:④ 表单的权限列表?
|
||||||
|
// TODO @芋艿:⑨ 超时配置;要支持指定时间点、指定时间间隔;
|
||||||
// TODO @芋艿:条件;建议可以固化的一些选项;然后有个表达式兜底;要支持
|
// TODO @芋艿:条件;建议可以固化的一些选项;然后有个表达式兜底;要支持
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,7 @@ import lombok.Data;
|
|||||||
@Data
|
@Data
|
||||||
public class BpmSimpleModelUpdateReqVO {
|
public class BpmSimpleModelUpdateReqVO {
|
||||||
|
|
||||||
|
// TODO @jason:=> id
|
||||||
@Schema(description = "流程模型编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
@Schema(description = "流程模型编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||||
@NotEmpty(message = "流程模型编号不能为空")
|
@NotEmpty(message = "流程模型编号不能为空")
|
||||||
private String modelId; // 对应 Flowable act_re_model 表 ID_ 字段
|
private String modelId; // 对应 Flowable act_re_model 表 ID_ 字段
|
||||||
|
@ -28,9 +28,6 @@ public class BpmTaskCandidateStartUserStrategy implements BpmTaskCandidateStrate
|
|||||||
return BpmTaskCandidateStrategyEnum.START_USER;
|
return BpmTaskCandidateStrategyEnum.START_USER;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 无需校验参数
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public void validateParam(String param) {}
|
public void validateParam(String param) {}
|
||||||
|
|
||||||
@ -40,11 +37,9 @@ public class BpmTaskCandidateStartUserStrategy implements BpmTaskCandidateStrate
|
|||||||
return SetUtils.asSet(Long.valueOf(startUserId));
|
return SetUtils.asSet(Long.valueOf(startUserId));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 不需要参数
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isParamRequired() {
|
public boolean isParamRequired() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package cn.iocoder.yudao.module.bpm.framework.flowable.core.custom.delegate;
|
package cn.iocoder.yudao.module.bpm.framework.flowable.core.custom.delegate;
|
||||||
|
|
||||||
|
import cn.hutool.core.collection.CollUtil;
|
||||||
import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.BpmTaskCandidateInvoker;
|
import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.BpmTaskCandidateInvoker;
|
||||||
import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceCopyService;
|
import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceCopyService;
|
||||||
import jakarta.annotation.Resource;
|
import jakarta.annotation.Resource;
|
||||||
@ -10,23 +11,29 @@ import org.springframework.stereotype.Service;
|
|||||||
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
// TODO @jason:类名可以改成 BpmCopyTaskDelegate
|
||||||
/**
|
/**
|
||||||
* 处理抄送用户的代理
|
* 处理抄送用户的 {@link JavaDelegate} 的实现类
|
||||||
*
|
*
|
||||||
* @author jason
|
* @author jason
|
||||||
*/
|
*/
|
||||||
@Service
|
@Service // TODO @jason:这种注解,建议用 @Component
|
||||||
public class CopyUserDelegate implements JavaDelegate {
|
public class CopyUserDelegate implements JavaDelegate {
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private BpmTaskCandidateInvoker taskCandidateInvoker;
|
private BpmTaskCandidateInvoker taskCandidateInvoker;
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private BpmProcessInstanceCopyService processInstanceCopyService;
|
private BpmProcessInstanceCopyService processInstanceCopyService;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void execute(DelegateExecution execution) {
|
public void execute(DelegateExecution execution) {
|
||||||
// TODO @芋艿:可能要考虑,系统抄送,没有 taskId 的情况。
|
// 1. 获得抄送人
|
||||||
Set<Long> userIds = taskCandidateInvoker.calculateUsers(execution);
|
Set<Long> userIds = taskCandidateInvoker.calculateUsers(execution);
|
||||||
|
if (CollUtil.isEmpty(userIds)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 2. 执行抄送
|
||||||
FlowElement currentFlowElement = execution.getCurrentFlowElement();
|
FlowElement currentFlowElement = execution.getCurrentFlowElement();
|
||||||
processInstanceCopyService.createProcessInstanceCopy(userIds, execution.getProcessInstanceId(),
|
processInstanceCopyService.createProcessInstanceCopy(userIds, execution.getProcessInstanceId(),
|
||||||
currentFlowElement.getId(), currentFlowElement.getName());
|
currentFlowElement.getId(), currentFlowElement.getName());
|
||||||
|
@ -10,6 +10,7 @@ import org.flowable.engine.delegate.DelegateExecution;
|
|||||||
import org.flowable.engine.delegate.JavaDelegate;
|
import org.flowable.engine.delegate.JavaDelegate;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
// TODO @jason:微信已经讨论,简化哈
|
||||||
/**
|
/**
|
||||||
* 处理会签 Service Task 代理
|
* 处理会签 Service Task 代理
|
||||||
*
|
*
|
||||||
@ -25,7 +26,7 @@ public class MultiInstanceServiceTaskDelegate implements JavaDelegate {
|
|||||||
public void execute(DelegateExecution execution) {
|
public void execute(DelegateExecution execution) {
|
||||||
|
|
||||||
String attachUserTaskId = BpmnModelUtils.parseExtensionElement(execution.getCurrentFlowElement(),
|
String attachUserTaskId = BpmnModelUtils.parseExtensionElement(execution.getCurrentFlowElement(),
|
||||||
BpmnModelConstants.SERVICE_TASK_ATTACH_USER_TASK_ID);
|
BpmnModelConstants.SERVICE_TASK_ATTACH_USER_TASK_ID); // TODO @jason:上面不需要加空行哈;
|
||||||
Assert.notNull(attachUserTaskId, "附属的用户任务 Id 不能为空");
|
Assert.notNull(attachUserTaskId, "附属的用户任务 Id 不能为空");
|
||||||
// 获取会签任务是否被拒绝
|
// 获取会签任务是否被拒绝
|
||||||
Boolean userTaskRejected = execution.getVariable(String.format("%s_reject", attachUserTaskId), Boolean.class);
|
Boolean userTaskRejected = execution.getVariable(String.format("%s_reject", attachUserTaskId), Boolean.class);
|
||||||
|
@ -19,6 +19,7 @@ import static cn.iocoder.yudao.module.bpm.enums.definition.BpmApproveMethodEnum.
|
|||||||
import static cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants.USER_TASK_APPROVE_METHOD;
|
import static cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants.USER_TASK_APPROVE_METHOD;
|
||||||
import static cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants.USER_TASK_APPROVE_RATIO;
|
import static cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants.USER_TASK_APPROVE_RATIO;
|
||||||
|
|
||||||
|
// TODO @jason:微信已经讨论,简化哈
|
||||||
/**
|
/**
|
||||||
* 按拒绝人数计算会签的完成条件的流程表达式实现
|
* 按拒绝人数计算会签的完成条件的流程表达式实现
|
||||||
*
|
*
|
||||||
|
@ -4,6 +4,7 @@ import org.flowable.common.engine.api.variable.VariableContainer;
|
|||||||
import org.flowable.common.engine.impl.el.function.AbstractFlowableVariableExpressionFunction;
|
import org.flowable.common.engine.impl.el.function.AbstractFlowableVariableExpressionFunction;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
// TODO @jason:这个自定义转换的原因是啥呀?
|
||||||
/**
|
/**
|
||||||
* 根据流程变量 variable 的类型, 转换参数的值
|
* 根据流程变量 variable 的类型, 转换参数的值
|
||||||
*
|
*
|
||||||
|
@ -40,6 +40,7 @@ public interface BpmnModelConstants {
|
|||||||
*/
|
*/
|
||||||
String USER_TASK_TIMEOUT_HANDLER_ACTION = "timeoutAction";
|
String USER_TASK_TIMEOUT_HANDLER_ACTION = "timeoutAction";
|
||||||
|
|
||||||
|
// TODO @jason:1)是不是上面的 timeoutAction 改成 timeoutHandler;2)rejectHandlerType 改成 rejectHandler 哇?
|
||||||
/**
|
/**
|
||||||
* BPMN ExtensionElement 的扩展属性,用于标记用户任务拒绝处理类型
|
* BPMN ExtensionElement 的扩展属性,用于标记用户任务拒绝处理类型
|
||||||
*/
|
*/
|
||||||
|
@ -73,6 +73,7 @@ public class BpmTaskEventListener extends AbstractFlowableEngineEventListener {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO @jason:这块如果不需要,可以删除掉~~~
|
||||||
// @Override
|
// @Override
|
||||||
// protected void activityMessageReceived(FlowableMessageEvent event) {
|
// protected void activityMessageReceived(FlowableMessageEvent event) {
|
||||||
// BpmnModel bpmnModel = bpmModelService.getBpmnModelByDefinitionId(event.getProcessDefinitionId());
|
// BpmnModel bpmnModel = bpmModelService.getBpmnModelByDefinitionId(event.getProcessDefinitionId());
|
||||||
|
@ -29,6 +29,7 @@ import org.springframework.stereotype.Component;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
// TODO @芋艿:这块需要仔细再瞅瞅
|
||||||
/**
|
/**
|
||||||
* 监听定时器触发事件
|
* 监听定时器触发事件
|
||||||
*
|
*
|
||||||
@ -96,7 +97,6 @@ public class BpmTimerFiredEventListener extends AbstractFlowableEngineEventListe
|
|||||||
BpmTaskApproveReqVO req = new BpmTaskApproveReqVO().setId(task.getId())
|
BpmTaskApproveReqVO req = new BpmTaskApproveReqVO().setId(task.getId())
|
||||||
.setReason("超时系统自动同意");
|
.setReason("超时系统自动同意");
|
||||||
bpmTaskService.approveTask(Long.parseLong(task.getAssignee()), req);
|
bpmTaskService.approveTask(Long.parseLong(task.getAssignee()), req);
|
||||||
|
|
||||||
}
|
}
|
||||||
// 自动拒绝
|
// 自动拒绝
|
||||||
if (userTaskTimeoutAction == BpmUserTaskTimeoutActionEnum.AUTO_REJECT) {
|
if (userTaskTimeoutAction == BpmUserTaskTimeoutActionEnum.AUTO_REJECT) {
|
||||||
|
@ -7,6 +7,7 @@ import org.springframework.context.ApplicationContext;
|
|||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
import org.springframework.validation.annotation.Validated;
|
import org.springframework.validation.annotation.Validated;
|
||||||
|
|
||||||
|
// TODO @jason:建议直接调用 BpmMessageService 哈;更简化一点~
|
||||||
/**
|
/**
|
||||||
* 待办任务提醒 Producer
|
* 待办任务提醒 Producer
|
||||||
*
|
*
|
||||||
@ -22,4 +23,5 @@ public class TodoTaskReminderProducer {
|
|||||||
public void sendReminderMessage(@Valid TodoTaskReminderMessage message) {
|
public void sendReminderMessage(@Valid TodoTaskReminderMessage message) {
|
||||||
applicationContext.publishEvent(message);
|
applicationContext.publishEvent(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
package cn.iocoder.yudao.module.bpm.framework.flowable.core.simple;
|
package cn.iocoder.yudao.module.bpm.framework.flowable.core.simplemodel;
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
@ -1,4 +1,4 @@
|
|||||||
package cn.iocoder.yudao.module.bpm.framework.flowable.core.simple;
|
package cn.iocoder.yudao.module.bpm.framework.flowable.core.simplemodel;
|
||||||
|
|
||||||
import cn.iocoder.yudao.module.bpm.enums.definition.BpmApproveMethodEnum;
|
import cn.iocoder.yudao.module.bpm.enums.definition.BpmApproveMethodEnum;
|
||||||
import cn.iocoder.yudao.module.bpm.enums.definition.BpmUserTaskRejectHandlerType;
|
import cn.iocoder.yudao.module.bpm.enums.definition.BpmUserTaskRejectHandlerType;
|
||||||
@ -19,7 +19,6 @@ public class SimpleModelUserTaskConfig {
|
|||||||
* 候选人策略
|
* 候选人策略
|
||||||
*/
|
*/
|
||||||
private Integer candidateStrategy;
|
private Integer candidateStrategy;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 候选人参数
|
* 候选人参数
|
||||||
*/
|
*/
|
||||||
@ -34,11 +33,11 @@ public class SimpleModelUserTaskConfig {
|
|||||||
* 审批方式 {@link BpmApproveMethodEnum }
|
* 审批方式 {@link BpmApproveMethodEnum }
|
||||||
*/
|
*/
|
||||||
private Integer approveMethod;
|
private Integer approveMethod;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 通过比例 当审批方式为 多人会签(按通过比例) 需设置
|
* 通过比例 当审批方式为 多人会签(按通过比例) 需设置
|
||||||
*/
|
*/
|
||||||
private Integer approveRatio;
|
private Integer approveRatio;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 超时处理
|
* 超时处理
|
||||||
*/
|
*/
|
@ -15,7 +15,7 @@ import java.util.Map;
|
|||||||
|
|
||||||
import static cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants.FORM_FIELD_PERMISSION_ELEMENT_FIELD_ATTRIBUTE;
|
import static cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants.FORM_FIELD_PERMISSION_ELEMENT_FIELD_ATTRIBUTE;
|
||||||
|
|
||||||
|
// TODO @芋艿:这块去研究下!
|
||||||
/**
|
/**
|
||||||
* Bpmn 流程表单相关工具方法
|
* Bpmn 流程表单相关工具方法
|
||||||
*
|
*
|
||||||
|
@ -27,6 +27,7 @@ public class BpmnModelUtils {
|
|||||||
// TODO @芋艿 尝试从 ExtensionElement 取. 后续相关扩展是否都可以 存 extensionElement。 如表单权限。 按钮权限
|
// TODO @芋艿 尝试从 ExtensionElement 取. 后续相关扩展是否都可以 存 extensionElement。 如表单权限。 按钮权限
|
||||||
if (candidateStrategy == null) {
|
if (candidateStrategy == null) {
|
||||||
ExtensionElement element = CollUtil.getFirst(userTask.getExtensionElements().get(BpmnModelConstants.USER_TASK_CANDIDATE_STRATEGY));
|
ExtensionElement element = CollUtil.getFirst(userTask.getExtensionElements().get(BpmnModelConstants.USER_TASK_CANDIDATE_STRATEGY));
|
||||||
|
// TODO @jason:这里可以改成 element != null 看着会简单点 element != null ? NumberUtils.parseInt(element.getElementText()) : null;
|
||||||
candidateStrategy = NumberUtils.parseInt(Optional.ofNullable(element).map(ExtensionElement::getElementText).orElse(null));
|
candidateStrategy = NumberUtils.parseInt(Optional.ofNullable(element).map(ExtensionElement::getElementText).orElse(null));
|
||||||
}
|
}
|
||||||
return candidateStrategy;
|
return candidateStrategy;
|
||||||
@ -37,6 +38,7 @@ public class BpmnModelUtils {
|
|||||||
BpmnModelConstants.NAMESPACE, BpmnModelConstants.USER_TASK_CANDIDATE_PARAM);
|
BpmnModelConstants.NAMESPACE, BpmnModelConstants.USER_TASK_CANDIDATE_PARAM);
|
||||||
if (candidateParam == null) {
|
if (candidateParam == null) {
|
||||||
ExtensionElement element = CollUtil.getFirst(userTask.getExtensionElements().get(BpmnModelConstants.USER_TASK_CANDIDATE_PARAM));
|
ExtensionElement element = CollUtil.getFirst(userTask.getExtensionElements().get(BpmnModelConstants.USER_TASK_CANDIDATE_PARAM));
|
||||||
|
// TODO @jason:这里可以改成 element != null 看着会简单点 element != null ? element.getElementText() : null;
|
||||||
candidateParam = Optional.ofNullable(element).map(ExtensionElement::getElementText).orElse(null);
|
candidateParam = Optional.ofNullable(element).map(ExtensionElement::getElementText).orElse(null);
|
||||||
}
|
}
|
||||||
return candidateParam;
|
return candidateParam;
|
||||||
|
@ -12,9 +12,9 @@ import cn.iocoder.yudao.module.bpm.enums.definition.BpmApproveMethodEnum;
|
|||||||
import cn.iocoder.yudao.module.bpm.enums.definition.BpmSimpleModeConditionType;
|
import cn.iocoder.yudao.module.bpm.enums.definition.BpmSimpleModeConditionType;
|
||||||
import cn.iocoder.yudao.module.bpm.enums.definition.BpmSimpleModelNodeType;
|
import cn.iocoder.yudao.module.bpm.enums.definition.BpmSimpleModelNodeType;
|
||||||
import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants;
|
import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants;
|
||||||
import cn.iocoder.yudao.module.bpm.framework.flowable.core.simple.SimpleModelConditionGroups;
|
import cn.iocoder.yudao.module.bpm.framework.flowable.core.simplemodel.SimpleModelConditionGroups;
|
||||||
import cn.iocoder.yudao.module.bpm.framework.flowable.core.simple.SimpleModelUserTaskConfig;
|
import cn.iocoder.yudao.module.bpm.framework.flowable.core.simplemodel.SimpleModelUserTaskConfig;
|
||||||
import cn.iocoder.yudao.module.bpm.framework.flowable.core.simple.SimpleModelUserTaskConfig.RejectHandler;
|
import cn.iocoder.yudao.module.bpm.framework.flowable.core.simplemodel.SimpleModelUserTaskConfig.RejectHandler;
|
||||||
import org.flowable.bpmn.BpmnAutoLayout;
|
import org.flowable.bpmn.BpmnAutoLayout;
|
||||||
import org.flowable.bpmn.model.Process;
|
import org.flowable.bpmn.model.Process;
|
||||||
import org.flowable.bpmn.model.*;
|
import org.flowable.bpmn.model.*;
|
||||||
@ -253,33 +253,26 @@ public class SimpleModelUtils {
|
|||||||
return sequenceFlow;
|
return sequenceFlow;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO-DONE @jason:要不改成 recursionNode 递归节点,然后把 build 名字让出来,专门用于构建各种 Node
|
// TODO @芋艿 改成了 traverseNodeToBuildFlowNode, 连线的叫 traverseNodeToBuildSequenceFlow
|
||||||
// @芋艿 改成了 traverseNodeToBuildFlowNode, 连线的叫 traverseNodeToBuildSequenceFlow
|
|
||||||
// TODO-DONE @jason:node 改成 node,process 改成 process;更符合递归的感觉哈,处理当前节点
|
|
||||||
private static void traverseNodeToBuildFlowNode(BpmSimpleModelNodeVO node, Process process) {
|
private static void traverseNodeToBuildFlowNode(BpmSimpleModelNodeVO node, Process process) {
|
||||||
// 判断是否有效节点
|
// 判断是否有效节点
|
||||||
// TODO-DONE @jason:是不是写个 isValidNode 方法:判断是否为有效节点;
|
|
||||||
if (!isValidNode(node)) {
|
if (!isValidNode(node)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
BpmSimpleModelNodeType nodeType = BpmSimpleModelNodeType.valueOf(node.getType());
|
BpmSimpleModelNodeType nodeType = BpmSimpleModelNodeType.valueOf(node.getType());
|
||||||
Assert.notNull(nodeType, "模型节点类型不支持");
|
Assert.notNull(nodeType, "模型节点类型不支持");
|
||||||
|
|
||||||
// TODO-DONE @jason:要不抽个 buildNode 方法,然后返回一个 List<FlowElement>,之后这个方法 addFlowElement;原因是,让当前这个方法,有主干逻辑;不然现在太长了;
|
|
||||||
List<FlowElement> flowElements = buildFlowNode(node, nodeType);
|
List<FlowElement> flowElements = buildFlowNode(node, nodeType);
|
||||||
flowElements.forEach(process::addFlowElement);
|
flowElements.forEach(process::addFlowElement);
|
||||||
|
|
||||||
// 如果不是网关类型的接口, 并且chileNode为空退出
|
// 如果不是网关类型的接口, 并且chileNode为空退出
|
||||||
// TODO-DONE @jason:建议这个判断去掉,可以更简洁一点;因为往下走;如果不成功,本身也就会结束哈;主要是,这里多了一个这样的判断,增加了理解成本;
|
|
||||||
// 如果是“分支”节点,则递归处理条件
|
// 如果是“分支”节点,则递归处理条件
|
||||||
if (BpmSimpleModelNodeType.isBranchNode(node.getType())
|
if (BpmSimpleModelNodeType.isBranchNode(node.getType())
|
||||||
&& ArrayUtil.isNotEmpty(node.getConditionNodes())) {
|
&& ArrayUtil.isNotEmpty(node.getConditionNodes())) {
|
||||||
// TODO-DONE @jason:可以搞成 stream 写成一行哈
|
|
||||||
node.getConditionNodes().forEach(item -> traverseNodeToBuildFlowNode(item.getChildNode(), process));
|
node.getConditionNodes().forEach(item -> traverseNodeToBuildFlowNode(item.getChildNode(), process));
|
||||||
}
|
}
|
||||||
|
|
||||||
// 如果有“子”节点,则递归处理子节点
|
// 如果有“子”节点,则递归处理子节点
|
||||||
// TODO-DONE @jason:这个,是不是不写判断,直接继续调用;因为本身 buildAndAddBpmnFlowNode 就会最开始判断了哈,就不重复判断了;
|
|
||||||
traverseNodeToBuildFlowNode(node.getChildNode(), process);
|
traverseNodeToBuildFlowNode(node.getChildNode(), process);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -291,16 +284,13 @@ public class SimpleModelUtils {
|
|||||||
List<FlowElement> list = new ArrayList<>();
|
List<FlowElement> list = new ArrayList<>();
|
||||||
switch (nodeType) {
|
switch (nodeType) {
|
||||||
case START_NODE: {
|
case START_NODE: {
|
||||||
// TODO-DONE @jason:每个 nodeType,buildXXX 方法要不更明确,并且去掉 Bpmn;
|
|
||||||
// @芋艿 改成 convert 是不是好理解一点
|
// @芋艿 改成 convert 是不是好理解一点
|
||||||
StartEvent startEvent = convertStartNode(node);
|
StartEvent startEvent = convertStartNode(node);
|
||||||
list.add(startEvent);
|
list.add(startEvent);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case APPROVE_NODE: {
|
case APPROVE_NODE: {
|
||||||
// TODO-DONE @jason:这个,搞成一个 buildUserTask,然后把下面这 2 种节点,搞在一起实现类;这样 buildNode 里面可以更简洁;
|
// TODO @芋艿 改成 convertXXXNode, , 方面里面使用 buildBpmnXXXNode. 是否更好理解
|
||||||
// TODO-DONE @jason:这里还有个想法,是不是可以所有的都叫 buildXXXNode,然后里面有一些是 bpmn 相关的构建,叫做 buildBpmnUserTask,用于区分;
|
|
||||||
// @芋艿 改成 convertXXXNode, , 方面里面使用 buildBpmnXXXNode. 是否更好理解
|
|
||||||
// 转换审批节点
|
// 转换审批节点
|
||||||
List<FlowElement> flowElements = convertApproveNode(node);
|
List<FlowElement> flowElements = convertApproveNode(node);
|
||||||
list.addAll(flowElements);
|
list.addAll(flowElements);
|
||||||
|
@ -50,31 +50,6 @@ public interface BpmModelService {
|
|||||||
*/
|
*/
|
||||||
byte[] getModelBpmnXML(String id);
|
byte[] getModelBpmnXML(String id);
|
||||||
|
|
||||||
/**
|
|
||||||
* 保存流程模型的 BPMN XML
|
|
||||||
*
|
|
||||||
* @param id 编号
|
|
||||||
* @param xmlBytes BPMN XML bytes
|
|
||||||
*/
|
|
||||||
// TODO @芋艿:感觉可以不修改这个方法,而是额外加一个方法;传入 id,bpmn,json;
|
|
||||||
void saveModelBpmnXml(String id, byte[] xmlBytes);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获得仿钉钉快搭模型的 JSON 数据
|
|
||||||
*
|
|
||||||
* @param id 编号
|
|
||||||
* @return JSON bytes
|
|
||||||
*/
|
|
||||||
byte[] getModelSimpleJson(String id);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 保存仿钉钉快搭模型的 JSON 数据
|
|
||||||
*
|
|
||||||
* @param id 编号
|
|
||||||
* @param jsonBytes JSON bytes
|
|
||||||
*/
|
|
||||||
void saveModelSimpleJson(String id, byte[] jsonBytes);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 修改流程模型
|
* 修改流程模型
|
||||||
*
|
*
|
||||||
@ -129,6 +104,6 @@ public interface BpmModelService {
|
|||||||
*/
|
*/
|
||||||
void updateSimpleModel(@Valid BpmSimpleModelUpdateReqVO reqVO);
|
void updateSimpleModel(@Valid BpmSimpleModelUpdateReqVO reqVO);
|
||||||
|
|
||||||
// TODO @jason:另外个问题,因为是存储到 modelExtra 里,那需要 deploy 存储出快照。和 bpmn xml 一样。目前我想到的,就是存储到 BpmProcessDefinitionInfoDO 加一个 simple_model 字段,text 类型。可以看看还有啥方案?
|
// TODO @jason:另外个问题,因为是存储到 modelExtra 里,那需要 deploy 存储出快照。和 bpmn xml 一样。目前我想到的,就是存储到 BpmProcessDefinitionInfoDO 加一个 simple_model 字段,text 类型。可以看看还有啥方案?【重要】
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -107,7 +107,7 @@ public class BpmModelServiceImpl implements BpmModelService {
|
|||||||
// 保存流程定义
|
// 保存流程定义
|
||||||
repositoryService.saveModel(model);
|
repositoryService.saveModel(model);
|
||||||
// 保存 BPMN XML
|
// 保存 BPMN XML
|
||||||
saveModelBpmnXml(model.getId(), StrUtil.utf8Bytes(bpmnXml));
|
saveModelBpmnXml(model.getId(), bpmnXml);
|
||||||
return model.getId();
|
return model.getId();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -125,7 +125,7 @@ public class BpmModelServiceImpl implements BpmModelService {
|
|||||||
// 更新模型
|
// 更新模型
|
||||||
repositoryService.saveModel(model);
|
repositoryService.saveModel(model);
|
||||||
// 更新 BPMN XML
|
// 更新 BPMN XML
|
||||||
saveModelBpmnXml(model.getId(), StrUtil.utf8Bytes(updateReqVO.getBpmnXml()));
|
saveModelBpmnXml(model.getId(), updateReqVO.getBpmnXml());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -218,23 +218,24 @@ public class BpmModelServiceImpl implements BpmModelService {
|
|||||||
if (model == null) {
|
if (model == null) {
|
||||||
throw exception(MODEL_NOT_EXISTS);
|
throw exception(MODEL_NOT_EXISTS);
|
||||||
}
|
}
|
||||||
// 通过 ACT_RE_MODEL 表 EDITOR_SOURCE_EXTRA_VALUE_ID_ 获取 仿钉钉快搭模型的JSON 数据
|
// 通过 ACT_RE_MODEL 表 EDITOR_SOURCE_EXTRA_VALUE_ID_ ,获取仿钉钉快搭模型的 JSON 数据
|
||||||
byte[] jsonBytes = getModelSimpleJson(model.getId());
|
byte[] jsonBytes = getModelSimpleJson(model.getId());
|
||||||
return JsonUtils.parseObject(jsonBytes, BpmSimpleModelNodeVO.class);
|
return JsonUtils.parseObject(jsonBytes, BpmSimpleModelNodeVO.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateSimpleModel(BpmSimpleModelUpdateReqVO reqVO) {
|
public void updateSimpleModel(BpmSimpleModelUpdateReqVO reqVO) {
|
||||||
// 1.1 校验流程模型存在
|
// 1. 校验流程模型存在
|
||||||
Model model = getModel(reqVO.getModelId());
|
Model model = getModel(reqVO.getModelId());
|
||||||
if (model == null) {
|
if (model == null) {
|
||||||
throw exception(MODEL_NOT_EXISTS);
|
throw exception(MODEL_NOT_EXISTS);
|
||||||
}
|
}
|
||||||
// 1.2 JSON 转换成 bpmnModel
|
|
||||||
|
// 2.1 JSON 转换成 bpmnModel
|
||||||
BpmnModel bpmnModel = SimpleModelUtils.buildBpmnModel(model.getKey(), model.getName(), reqVO.getSimpleModel());
|
BpmnModel bpmnModel = SimpleModelUtils.buildBpmnModel(model.getKey(), model.getName(), reqVO.getSimpleModel());
|
||||||
// 2.1 保存 Bpmn XML
|
// 2.2 保存 Bpmn XML
|
||||||
saveModelBpmnXml(model.getId(), StrUtil.utf8Bytes(BpmnModelUtils.getBpmnXml(bpmnModel)));
|
saveModelBpmnXml(model.getId(), BpmnModelUtils.getBpmnXml(bpmnModel));
|
||||||
// 2.2 保存 JSON 数据
|
// 2.3 保存 JSON 数据
|
||||||
saveModelSimpleJson(model.getId(), JsonUtils.toJsonByte(reqVO.getSimpleModel()));
|
saveModelSimpleJson(model.getId(), JsonUtils.toJsonByte(reqVO.getSimpleModel()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -266,21 +267,18 @@ public class BpmModelServiceImpl implements BpmModelService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private void saveModelBpmnXml(String id, String bpmnXml) {
|
||||||
public void saveModelBpmnXml(String id, byte[] xmlBytes) {
|
if (StrUtil.isEmpty(bpmnXml)) {
|
||||||
if (ArrayUtil.isEmpty(xmlBytes)) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
repositoryService.addModelEditorSource(id, xmlBytes);
|
repositoryService.addModelEditorSource(id, StrUtil.utf8Bytes(bpmnXml));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private byte[] getModelSimpleJson(String id) {
|
||||||
public byte[] getModelSimpleJson(String id) {
|
|
||||||
return repositoryService.getModelEditorSourceExtra(id);
|
return repositoryService.getModelEditorSourceExtra(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private void saveModelSimpleJson(String id, byte[] jsonBytes) {
|
||||||
public void saveModelSimpleJson(String id, byte[] jsonBytes) {
|
|
||||||
if (ArrayUtil.isEmpty(jsonBytes)) {
|
if (ArrayUtil.isEmpty(jsonBytes)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,8 @@ import java.util.Collection;
|
|||||||
*/
|
*/
|
||||||
public interface BpmProcessInstanceCopyService {
|
public interface BpmProcessInstanceCopyService {
|
||||||
|
|
||||||
|
// TODO @jason:要不把 createProcessInstanceCopy 搞 2 个方法,一个方法参数是之前的 userIds、taskId;一个方法是现在 userIds、processInstanceId、taskId、taskName;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 流程实例的抄送
|
* 流程实例的抄送
|
||||||
*
|
*
|
||||||
|
@ -127,23 +127,23 @@ public interface BpmProcessInstanceService {
|
|||||||
void updateProcessInstanceWhenCancel(FlowableCancelledEvent event);
|
void updateProcessInstanceWhenCancel(FlowableCancelledEvent event);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 更新 ProcessInstance 拓展记录为完成
|
* 更新 ProcessInstance 为完成
|
||||||
*
|
*
|
||||||
* @param instance 流程任务
|
* @param instance 流程任务
|
||||||
*/
|
*/
|
||||||
void updateProcessInstanceWhenApprove(ProcessInstance instance);
|
void updateProcessInstanceWhenApprove(ProcessInstance instance);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 更新 ProcessInstance 拓展记录为不通过
|
* 更新 ProcessInstance 为不通过
|
||||||
*
|
*
|
||||||
* @param id 流程编号
|
* @param id 流程编号
|
||||||
* @param currentActivityId 当前的活动Id
|
* @param currentActivityId 当前的活动编号
|
||||||
* @param reason 理由。例如说,审批不通过时,需要传递该值
|
* @param reason 理由。例如说,审批不通过时,需要传递该值
|
||||||
*/
|
*/
|
||||||
void updateProcessInstanceReject(String id, String currentActivityId, String reason);
|
void updateProcessInstanceReject(String id, String currentActivityId, String reason);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 当流程结束时候。 更新 ProcessInstance
|
* 当流程结束时候,更新 ProcessInstance 为通过
|
||||||
*
|
*
|
||||||
* @param instance 流程任务
|
* @param instance 流程任务
|
||||||
*/
|
*/
|
||||||
|
File diff suppressed because one or more lines are too long
@ -129,6 +129,7 @@ public interface BpmTaskService {
|
|||||||
*/
|
*/
|
||||||
Task getTask(String id);
|
Task getTask(String id);
|
||||||
|
|
||||||
|
// TODO @jason:jason:这个貌似可以去掉了。
|
||||||
/**
|
/**
|
||||||
* 根据条件查询已经分配的用户任务列表
|
* 根据条件查询已经分配的用户任务列表
|
||||||
* @param processInstanceId 流程实例编号,不允许为空
|
* @param processInstanceId 流程实例编号,不允许为空
|
||||||
|
@ -335,14 +335,18 @@ public class BpmTaskServiceImpl implements BpmTaskService {
|
|||||||
// 2.2 添加评论
|
// 2.2 添加评论
|
||||||
taskService.addComment(task.getId(), task.getProcessInstanceId(), BpmCommentTypeEnum.REJECT.getType(),
|
taskService.addComment(task.getId(), task.getProcessInstanceId(), BpmCommentTypeEnum.REJECT.getType(),
|
||||||
BpmCommentTypeEnum.REJECT.formatComment(reqVO.getReason()));
|
BpmCommentTypeEnum.REJECT.formatComment(reqVO.getReason()));
|
||||||
|
|
||||||
// 3.1 解析用户任务的拒绝处理类型
|
// 3.1 解析用户任务的拒绝处理类型
|
||||||
BpmnModel bpmnModel = bpmModelService.getBpmnModelByDefinitionId(task.getProcessDefinitionId());
|
BpmnModel bpmnModel = bpmModelService.getBpmnModelByDefinitionId(task.getProcessDefinitionId());
|
||||||
|
// TODO @jason:342 到 344 最好抽象一个方法出来哈。放在 BpmnModelUtils,参照类似 parseCandidateStrategy
|
||||||
UserTask flowElement = (UserTask) BpmnModelUtils.getFlowElementById(bpmnModel, task.getTaskDefinitionKey());
|
UserTask flowElement = (UserTask) BpmnModelUtils.getFlowElementById(bpmnModel, task.getTaskDefinitionKey());
|
||||||
Integer rejectHandlerType = NumberUtils.parseInt(BpmnModelUtils.parseExtensionElement(flowElement, USER_TASK_REJECT_HANDLER_TYPE));
|
Integer rejectHandlerType = NumberUtils.parseInt(BpmnModelUtils.parseExtensionElement(flowElement, USER_TASK_REJECT_HANDLER_TYPE));
|
||||||
BpmUserTaskRejectHandlerType userTaskRejectHandlerType = BpmUserTaskRejectHandlerType.typeOf(rejectHandlerType);
|
BpmUserTaskRejectHandlerType userTaskRejectHandlerType = BpmUserTaskRejectHandlerType.typeOf(rejectHandlerType);
|
||||||
// 3.2 类型为驳回到指定的任务节点
|
// 3.2 类型为驳回到指定的任务节点 TODO @jason:下面这种判断,最好是 JSON
|
||||||
if (userTaskRejectHandlerType == BpmUserTaskRejectHandlerType.RETURN_PRE_USER_TASK) {
|
if (userTaskRejectHandlerType == BpmUserTaskRejectHandlerType.RETURN_PRE_USER_TASK) {
|
||||||
|
// TODO @jason:348 最好抽象一个方法出来哈。放在 BpmnModelUtils,参照类似 parseCandidateStrategy
|
||||||
String returnTaskId = BpmnModelUtils.parseExtensionElement(flowElement, USER_TASK_REJECT_RETURN_TASK_ID);
|
String returnTaskId = BpmnModelUtils.parseExtensionElement(flowElement, USER_TASK_REJECT_RETURN_TASK_ID);
|
||||||
|
// TODO @jason:这里如果找不到,直接抛出系统异常;因为说白了,已经不是业务异常啦。
|
||||||
if (returnTaskId == null) {
|
if (returnTaskId == null) {
|
||||||
throw exception(TASK_RETURN_NOT_ASSIGN_TARGET_TASK_ID);
|
throw exception(TASK_RETURN_NOT_ASSIGN_TARGET_TASK_ID);
|
||||||
}
|
}
|
||||||
@ -351,6 +355,7 @@ public class BpmTaskServiceImpl implements BpmTaskService {
|
|||||||
returnTask(userId, returnReq);
|
returnTask(userId, returnReq);
|
||||||
return;
|
return;
|
||||||
} else if (userTaskRejectHandlerType == BpmUserTaskRejectHandlerType.FINISH_PROCESS_BY_REJECT_NUMBER) {
|
} else if (userTaskRejectHandlerType == BpmUserTaskRejectHandlerType.FINISH_PROCESS_BY_REJECT_NUMBER) {
|
||||||
|
// TODO @jason:微信沟通,去掉类似的逻辑;
|
||||||
// 3.3 按拒绝人数终止流程
|
// 3.3 按拒绝人数终止流程
|
||||||
if (!flowElement.hasMultiInstanceLoopCharacteristics()) {
|
if (!flowElement.hasMultiInstanceLoopCharacteristics()) {
|
||||||
log.error("[rejectTask] 按拒绝人数终止流程类型,只能用于会签任务. 当前任务【{}】不是会签任务", task.getId());
|
log.error("[rejectTask] 按拒绝人数终止流程类型,只能用于会签任务. 当前任务【{}】不是会签任务", task.getId());
|
||||||
@ -362,7 +367,8 @@ public class BpmTaskServiceImpl implements BpmTaskService {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// 3.4 其他情况 终止流程。
|
// 3.4 其他情况 终止流程。
|
||||||
processInstanceService.updateProcessInstanceReject(instance.getProcessInstanceId(), task.getTaskDefinitionKey(), reqVO.getReason());
|
processInstanceService.updateProcessInstanceReject(instance.getProcessInstanceId(),
|
||||||
|
task.getTaskDefinitionKey(), reqVO.getReason());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Loading…
Reference in New Issue
Block a user