Merge remote-tracking branch 'origin/master' into feature/REQ-4468
# Conflicts: # workflow-engine-common/src/main/java/cn/axzo/workflow/common/enums/BpmnButtonEnum.java # workflow-engine-core/src/main/java/cn/axzo/workflow/core/conf/FlowableConfiguration.java # workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessInstanceServiceImpl.java # workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessTaskServiceImpl.java # workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/ExtAxProcessLogServiceImpl.java
This commit is contained in:
commit
372dec7a2b
@ -31,6 +31,7 @@ public enum BpmnInstanceRespCode implements IModuleRespCode {
|
||||
PROCESS_DOC_READ_PARAM_ERROR("016", "查询审批人阅读状态参数丢失自然人 ID 数据"),
|
||||
PROCESS_DOC_ID_NOT_IN_MODEL("017", "当前流程中,不存在指定文档"),
|
||||
PROCESS_SIGN_DATA_NOT_EXISTS("018", "签署业务审批未获取到初始模板复制数据"),
|
||||
PROCESS_INSTANCE_CANT_REMIND("019", "流程实例【{}】不存在, 不能评论"),
|
||||
;
|
||||
private final String code;
|
||||
private final String message;
|
||||
|
||||
@ -41,6 +41,7 @@ public enum BpmnTaskRespCode implements IModuleRespCode {
|
||||
BACK_NODE_CANNOT_REACHABLE("024", "退回节点【{}】不可达,不允许退回"),
|
||||
REACHED_BACKED_MAXIMUM_NUM("025", "达到回退操作次数上限【{}】次"),
|
||||
TRANSFER_TO_SELF("026", "任务不能转交给自己"),
|
||||
REMIND_TASK_TOO_MANY("027", "催办任务数据异常")
|
||||
;
|
||||
|
||||
private final String code;
|
||||
|
||||
@ -21,6 +21,7 @@ public enum OtherRespCode implements IModuleRespCode {
|
||||
MESSAGE_PUSH_EVENT_BUILD_ERROR("006", "不能使用 createEvent 函数创建`发送待办`的事件, 请调用 createPendingPushEvent 函数"),
|
||||
ASYNC_JOB_EXECUTION_ERROR("007", "获取指定实例 ID【{}】的锁失败"),
|
||||
ILLEGAL_PARAM_ERROR("008", "非法的参数:【{}】"),
|
||||
MESSAGE_IM_EVENT_BUILD_ERROR("009", "不能使用 createEvent 函数创建`IM 消息`的事件, 请调用 createIMEvent 函数"),
|
||||
;
|
||||
|
||||
private final String code;
|
||||
|
||||
@ -13,9 +13,12 @@ public enum ApprovalMethodEnum {
|
||||
|
||||
human("human", "人工审批", ""),
|
||||
autoPassed("autoPassed", "自动通过", "[仅审批节点可能选该值]"),
|
||||
autoPassed_empty("autoPassed", "自动通过", "该枚举仅日志处理使用"),
|
||||
autoRejection("autoRejection", "自动驳回", "[仅审批节点可能选该值]"),
|
||||
autoRejection_empty("autoRejection", "自动驳回", "该枚举仅日志处理使用"),
|
||||
nobody("nobody", "不设置审批人", "[仅业务节点可能有该值]"),
|
||||
bizSpecify("bizSpecify", "业务指定审批人", "[仅业务节点可能有该值]"),
|
||||
transferToAdmin("transferToAdmin", "转办给管理员", "该枚举仅日志处理使用"),
|
||||
;
|
||||
|
||||
private String type;
|
||||
|
||||
@ -59,10 +59,14 @@ public enum BpmnButtonEnum {
|
||||
* 提级审批按钮
|
||||
*/
|
||||
BPMN_UPGRADE(12, "BPMN_UPGRADE", "提级审批", Lists.newArrayList(APPROVAL, SIGN)),
|
||||
/**
|
||||
* 催办按钮
|
||||
*/
|
||||
BPMN_REMIND(11, "BPMN_REMIND", "催办", Lists.newArrayList(APPROVAL, SIGN)),
|
||||
/**
|
||||
* 管理员转交按钮
|
||||
*/
|
||||
BPMN_ADMIN_TRANSFER(99, "BPMN_ADMIN_TRANSFER", "管理员转交", Lists.newArrayList());
|
||||
BPMN_ADMIN_TRANSFER(90, "BPMN_ADMIN_TRANSFER", "管理员转交", Lists.newArrayList());
|
||||
|
||||
|
||||
public int getOrder() {
|
||||
|
||||
@ -17,6 +17,7 @@ public enum ProcessMessagePushEventEnum {
|
||||
PROCESS_CARBON_COPY("process-push", "process-carbon-copy", "抄送流程"),
|
||||
PROCESS_CARBON_COPY_COMPLETE("process-push", "process-carbon-copy-complete", "完成抄送"),
|
||||
PROCESS_PUSH_SMS("process-push", "process-push-sms", "短信推送"),
|
||||
PROCESS_PUSH_IM("process-push", "process-push-im", "IM 推送"),
|
||||
;
|
||||
|
||||
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
package cn.axzo.workflow.common.model.request.bpmn.task;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.google.common.collect.Lists;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
@ -112,6 +113,13 @@ public class BpmnTaskDelegateAssigner extends BaseBpmnTaskDelegateAssigner imple
|
||||
*/
|
||||
private String nodeId;
|
||||
|
||||
/**
|
||||
* 扩展字段, 业务无需关系
|
||||
* <p>
|
||||
* 仅用于日志展示人的一些状态信息
|
||||
*/
|
||||
private JSONObject ext;
|
||||
|
||||
public final String buildAssigneeId_1_2_1() {
|
||||
if (StringUtils.hasLength(assigneeType)) {
|
||||
return tenantId + "|" + assignee + "|" + assigneeType;
|
||||
@ -140,6 +148,12 @@ public class BpmnTaskDelegateAssigner extends BaseBpmnTaskDelegateAssigner imple
|
||||
this.tenantId = tenantId;
|
||||
}
|
||||
|
||||
public BpmnTaskDelegateAssigner(String assignee, String assigneeType, String assignerName, String personId, String tenantId, String ouId, String avatar, String nodeId) {
|
||||
this.assignerName = assignerName;
|
||||
this.personId = personId;
|
||||
this.tenantId = tenantId;
|
||||
}
|
||||
|
||||
public final boolean comparePersonIdToOther(BpmnTaskDelegateAssigner other) {
|
||||
return Objects.equals(personId, other.getPersonId());
|
||||
}
|
||||
|
||||
@ -2,10 +2,13 @@ package cn.axzo.workflow.common.model.request.bpmn.task;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@ -16,8 +19,16 @@ import java.util.List;
|
||||
*/
|
||||
@ApiModel("催办功能入参模型")
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Builder
|
||||
public class BpmnTaskRemindDTO {
|
||||
|
||||
/**
|
||||
* 操作催办时的终端类型,管理端cmp、工人端cm
|
||||
*/
|
||||
@NotBlank(message = "终端类型不能为空")
|
||||
private String terminalType;
|
||||
/**
|
||||
* 审批节点唯一标识
|
||||
*/
|
||||
@ -27,9 +38,9 @@ public class BpmnTaskRemindDTO {
|
||||
/**
|
||||
* 催办方式
|
||||
* <p>
|
||||
* 站内信:notice 短信:sms
|
||||
* IM, 如果为空,默认是 IM
|
||||
*/
|
||||
@NotEmpty(message = "催办方式不能为空")
|
||||
@ApiModelProperty(value = "催办方式", example = "im")
|
||||
private List<String> remindTypes;
|
||||
|
||||
/**
|
||||
@ -40,8 +51,9 @@ public class BpmnTaskRemindDTO {
|
||||
private String processInstanceId;
|
||||
|
||||
/**
|
||||
* 租户 ID
|
||||
* 是否异步执行
|
||||
*/
|
||||
@ApiModelProperty("租户 ID")
|
||||
private String tenantId;
|
||||
@ApiModelProperty(value = "是否异步", notes = "异步时,只接收请求便返回数据")
|
||||
@Builder.Default
|
||||
private Boolean async = true;
|
||||
}
|
||||
|
||||
@ -55,4 +55,7 @@ public class CategorySearchDTO extends BpmPageParam {
|
||||
*/
|
||||
@ApiModelProperty(value = "业务类型")
|
||||
private BusinessTypeEnum businessType;
|
||||
|
||||
@ApiModelProperty(value = "根据创建时间排序")
|
||||
private String orderCreateAt;
|
||||
}
|
||||
|
||||
@ -75,5 +75,9 @@ public class MessagePushDTO implements Serializable {
|
||||
* 节点电子签开关
|
||||
*/
|
||||
private Boolean activitySignature;
|
||||
/**
|
||||
* 催办专用属性,催办时的终端类型(管理端、工人端)
|
||||
*/
|
||||
private String terminalType;
|
||||
|
||||
}
|
||||
|
||||
@ -241,7 +241,10 @@ public final class BpmnJsonConverterUtil {
|
||||
mainProcess.addFlowElement(convertJsonToElement(EndEvent.class, mainProcess, formKey));
|
||||
|
||||
// 解析前端传入的模型设计 json
|
||||
List<String> lastNodeIds = create(formKey, bpmnJsonNode, mainProcess, bpmnModel, null, START_EVENT_ID);
|
||||
List<String> lastNodeIds = Lists.newArrayList(START_EVENT_ID);
|
||||
if (StringUtils.hasText(bpmnJsonNode.getId())) {
|
||||
lastNodeIds = create(formKey, bpmnJsonNode, mainProcess, bpmnModel, null, START_EVENT_ID);
|
||||
}
|
||||
|
||||
if (CollectionUtils.isEmpty(lastNodeIds)) {
|
||||
throw new WorkflowEngineException(CONVERTOR_COMMON_ERROR, "未找到链接结束节点的节点数据");
|
||||
@ -765,7 +768,7 @@ public final class BpmnJsonConverterUtil {
|
||||
}
|
||||
|
||||
private static FlowElement convertJsonToElement(Class<? extends BaseElement> clz, BpmnJsonNode bpmnJsonNode,
|
||||
Process process, String formKey) {
|
||||
Process process, String formKey) {
|
||||
AbstractBpmnJsonConverter converter = CONVERTERS.getOrDefault(clz, new NotSupportConverter());
|
||||
FlowElement flowElement = converter.convertJsonToElement(bpmnJsonNode, process, formKey);
|
||||
if (Objects.nonNull(bpmnJsonNode)) {
|
||||
|
||||
@ -18,6 +18,7 @@ import cn.axzo.workflow.core.engine.job.AsyncCancelProcessInstanceJobHandler;
|
||||
import cn.axzo.workflow.core.engine.job.AsyncCountersignUserTaskJobHandler;
|
||||
import cn.axzo.workflow.core.engine.job.AsyncExtTaskInstJobHandler;
|
||||
import cn.axzo.workflow.core.engine.job.AsyncRejectTaskJobHandler;
|
||||
import cn.axzo.workflow.core.engine.job.AsyncRemindTaskJobHandler;
|
||||
import cn.axzo.workflow.core.engine.job.AsyncResetApproversUserTaskJobHandler;
|
||||
import cn.axzo.workflow.core.engine.job.AsyncTermNodeAlterJobHandler;
|
||||
import cn.axzo.workflow.core.engine.job.AsyncTransferUserTaskJobHandler;
|
||||
@ -117,6 +118,7 @@ public class FlowableConfiguration {
|
||||
configuration.addCustomJobHandler(new AsyncActivityLeaveJobHandler(bpmnProcessActivityService));
|
||||
configuration.addCustomJobHandler(new AsyncActivityCallbackJobHandler());
|
||||
configuration.addCustomJobHandler(new AsyncApproveTaskWithFormJobHandler());
|
||||
configuration.addCustomJobHandler(new AsyncRemindTaskJobHandler(refreshProperties));
|
||||
configuration.addCustomJobHandler(new AsyncResetApproversUserTaskJobHandler(extAxHiTaskInstService));
|
||||
configurers.forEach(i -> configuration.addCustomJobHandler(i.getJobHandler()));
|
||||
// 异步任务异常重试时间间隔
|
||||
|
||||
@ -89,4 +89,7 @@ public class SupportRefreshProperties {
|
||||
|
||||
@Value("${workflow.esSyncBatchSize:10}")
|
||||
private Integer esSyncBatchSize;
|
||||
|
||||
@Value("${workflow.imTemplateCode:}")
|
||||
private String imTemplateCode;
|
||||
}
|
||||
|
||||
@ -52,7 +52,7 @@ public class CustomActivityTriggerCmd extends AbstractCommand<Void> implements S
|
||||
if (Objects.isNull(task)) {
|
||||
throw new WorkflowEngineException(ACTIVITY_TRIGGER_NOT_EXISTS, dto.getTriggerId());
|
||||
}
|
||||
addComment(commandContext, task, COMMENT_TYPE_OPERATION_DESC, "已处理");
|
||||
addComment(commandContext, task, COMMENT_TYPE_OPERATION_DESC, "已同意");
|
||||
RuntimeService runtimeService = processEngineConfiguration.getRuntimeService();
|
||||
runtimeService.trigger(dto.getTriggerId());
|
||||
return null;
|
||||
|
||||
@ -109,7 +109,7 @@ public class CustomApproveTaskCmd extends AbstractCommand<Void> implements Seria
|
||||
if (Objects.nonNull(operationDesc)) {
|
||||
this.operationDesc = operationDesc;
|
||||
} else {
|
||||
this.operationDesc = "(已通过)";
|
||||
this.operationDesc = "已同意";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -130,7 +130,7 @@ public class CustomApproveTaskWithFormCmd extends AbstractCommand<Void> implemen
|
||||
if (Objects.nonNull(operationDesc)) {
|
||||
this.operationDesc = operationDesc;
|
||||
} else {
|
||||
this.operationDesc = "(已通过)";
|
||||
this.operationDesc = "已同意";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -170,7 +170,10 @@ public class CustomCountersignUserTaskCmd extends AbstractCommand<Void> implemen
|
||||
message.append("、");
|
||||
}
|
||||
}
|
||||
message.append("等").append(targetTaskAssigneeList.size()).append("人进行审批");
|
||||
if (targetTaskAssigneeList.size() > end) {
|
||||
message.append("等");
|
||||
}
|
||||
message.append(targetTaskAssigneeList.size()).append("人进行审批");
|
||||
Task virtualTask = createVirtualTask(commandContext, extAxHiTaskInstService, task.getProcessInstanceId(), task.getName(),
|
||||
task.getTaskDefinitionKey(), advice, originTaskAssignee, COUNTERSIGN.getStatus(), new AddComment(message.toString()));
|
||||
batchAddAttachment(commandContext, task.getProcessInstanceId(), task, attachmentList, originTaskAssignee);
|
||||
|
||||
@ -69,7 +69,7 @@ public class CustomRejectionTaskCmd extends AbstractCommand<Void> implements Ser
|
||||
if (Objects.nonNull(operationDesc)) {
|
||||
this.operationDesc = operationDesc;
|
||||
} else {
|
||||
this.operationDesc = "(已驳回)";
|
||||
this.operationDesc = "已驳回";
|
||||
}
|
||||
this.attachmentList = dto.getAttachmentList();
|
||||
this.approver = dto.getApprover();
|
||||
|
||||
@ -0,0 +1,106 @@
|
||||
package cn.axzo.workflow.core.engine.cmd;
|
||||
|
||||
import cn.axzo.workflow.common.exception.WorkflowEngineException;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskRemindDTO;
|
||||
import cn.axzo.workflow.core.engine.job.AsyncApproveTaskJobHandler;
|
||||
import cn.axzo.workflow.core.engine.job.AsyncRemindTaskJobHandler;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.flowable.common.engine.impl.interceptor.CommandContext;
|
||||
import org.flowable.engine.RuntimeService;
|
||||
import org.flowable.engine.TaskService;
|
||||
import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl;
|
||||
import org.flowable.engine.impl.util.CommandContextUtil;
|
||||
import org.flowable.engine.runtime.ProcessInstance;
|
||||
import org.flowable.job.service.JobService;
|
||||
import org.flowable.job.service.impl.persistence.entity.JobEntity;
|
||||
import org.flowable.task.api.Task;
|
||||
import org.flowable.task.api.TaskQuery;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static cn.axzo.workflow.common.code.BpmnInstanceRespCode.PROCESS_INSTANCE_CANT_REMIND;
|
||||
import static cn.axzo.workflow.common.code.BpmnTaskRespCode.REMIND_TASK_TOO_MANY;
|
||||
import static cn.axzo.workflow.common.code.BpmnTaskRespCode.TASK_REMIND_ERROR_NOT_EXISTS;
|
||||
|
||||
/**
|
||||
* TODO
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2025-06-13 14:01
|
||||
*/
|
||||
public class CustomRemindTaskAsyncCmd extends AbstractCommand<String> implements Serializable {
|
||||
private static final Logger logger = LoggerFactory.getLogger(CustomRemindTaskAsyncCmd.class);
|
||||
private final BpmnTaskRemindDTO dto;
|
||||
|
||||
public CustomRemindTaskAsyncCmd(BpmnTaskRemindDTO dto) {
|
||||
this.dto = dto;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String paramToJsonString() {
|
||||
return JSON.toJSONString(dto);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String executeInternal(CommandContext commandContext) {
|
||||
ProcessEngineConfigurationImpl processEngineConfiguration =
|
||||
CommandContextUtil.getProcessEngineConfiguration(commandContext);
|
||||
RuntimeService runtimeService = processEngineConfiguration.getRuntimeService();
|
||||
ProcessInstance processInstance =
|
||||
runtimeService.createProcessInstanceQuery().processInstanceId(dto.getProcessInstanceId()).singleResult();
|
||||
if (Objects.isNull(processInstance)) {
|
||||
throw new WorkflowEngineException(PROCESS_INSTANCE_CANT_REMIND, dto.getProcessInstanceId());
|
||||
}
|
||||
|
||||
TaskService taskService = processEngineConfiguration.getTaskService();
|
||||
TaskQuery taskQuery = taskService.createTaskQuery().processInstanceId(dto.getProcessInstanceId());
|
||||
if (StringUtils.hasLength(dto.getTaskDefinitionKey())) {
|
||||
taskQuery.taskDefinitionKey(dto.getTaskDefinitionKey());
|
||||
}
|
||||
List<Task> list = taskQuery.active().list();
|
||||
if (CollectionUtils.isEmpty(list)) {
|
||||
throw new WorkflowEngineException(TASK_REMIND_ERROR_NOT_EXISTS);
|
||||
}
|
||||
if (!StringUtils.hasText(dto.getTaskDefinitionKey())) {
|
||||
List<String> taskDefinitionKeys = list.stream().map(Task::getTaskDefinitionKey).distinct().collect(Collectors.toList());
|
||||
if (taskDefinitionKeys.isEmpty()) {
|
||||
throw new WorkflowEngineException(TASK_REMIND_ERROR_NOT_EXISTS);
|
||||
} else if (taskDefinitionKeys.size() > 1) {
|
||||
throw new WorkflowEngineException(REMIND_TASK_TOO_MANY);
|
||||
} else {
|
||||
dto.setTaskDefinitionKey(taskDefinitionKeys.get(0));
|
||||
}
|
||||
}
|
||||
return startAsync(processEngineConfiguration, list.get(0));
|
||||
}
|
||||
|
||||
private String startAsync(ProcessEngineConfigurationImpl processEngineConfiguration, Task task) {
|
||||
JobService jobService = processEngineConfiguration.getJobServiceConfiguration().getJobService();
|
||||
|
||||
JobEntity job = jobService.createJob();
|
||||
// 这里的 executionId 可为 null
|
||||
job.setExecutionId(task.getExecutionId());
|
||||
job.setProcessInstanceId(task.getProcessInstanceId());
|
||||
job.setProcessDefinitionId(task.getProcessDefinitionId());
|
||||
job.setElementId(task.getTaskDefinitionKey());
|
||||
job.setElementName(task.getName());
|
||||
job.setJobHandlerType(AsyncRemindTaskJobHandler.TYPE);
|
||||
job.setTenantId(task.getTenantId());
|
||||
|
||||
// 携带自定义的数据
|
||||
job.setCustomValues(JSONUtil.toJsonStr(dto));
|
||||
|
||||
// 创建异步任务并调度
|
||||
jobService.createAsyncJob(job, false);
|
||||
jobService.scheduleAsyncJob(job);
|
||||
return job.getId();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,141 @@
|
||||
package cn.axzo.workflow.core.engine.cmd;
|
||||
|
||||
import cn.axzo.workflow.common.exception.WorkflowEngineException;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.BpmnNoticeConf;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner;
|
||||
import cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper;
|
||||
import cn.axzo.workflow.core.conf.SupportRefreshProperties;
|
||||
import cn.axzo.workflow.core.engine.event.MessagePushEventBuilder;
|
||||
import cn.axzo.workflow.core.engine.event.MessagePushEventImpl;
|
||||
import cn.axzo.workflow.core.engine.event.MessagePushEventType;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.google.common.collect.Lists;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.flowable.bpmn.model.Process;
|
||||
import org.flowable.common.engine.api.delegate.event.FlowableEventDispatcher;
|
||||
import org.flowable.common.engine.impl.interceptor.CommandContext;
|
||||
import org.flowable.engine.RuntimeService;
|
||||
import org.flowable.engine.TaskService;
|
||||
import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl;
|
||||
import org.flowable.engine.impl.util.CommandContextUtil;
|
||||
import org.flowable.engine.impl.util.ProcessDefinitionUtil;
|
||||
import org.flowable.engine.runtime.ProcessInstance;
|
||||
import org.flowable.task.api.Task;
|
||||
import org.flowable.task.api.TaskQuery;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static cn.axzo.workflow.common.code.BpmnInstanceRespCode.PROCESS_INSTANCE_CANT_REMIND;
|
||||
import static cn.axzo.workflow.common.code.BpmnTaskRespCode.REMIND_TASK_TOO_MANY;
|
||||
import static cn.axzo.workflow.common.code.BpmnTaskRespCode.TASK_REMIND_ERROR_NOT_EXISTS;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_TASK_RELATION_ASSIGNEE_INFO;
|
||||
import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getActivitySignature;
|
||||
|
||||
/**
|
||||
* 自定义(同步)催办任务的命令器实现
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2025-06-13 13:39
|
||||
*/
|
||||
public class CustomRemindTaskCmd extends AbstractCommand<Void> implements Serializable {
|
||||
private static final Logger log = LoggerFactory.getLogger(CustomRemindTaskCmd.class);
|
||||
private final SupportRefreshProperties refreshProperties;
|
||||
/**
|
||||
* 操作催办时的终端类型,管理端cm、工人端cmp
|
||||
*/
|
||||
private final String terminalType;
|
||||
private final String processInstanceId;
|
||||
private String taskDefinitionKey;
|
||||
/**
|
||||
* 催办方式
|
||||
* <p>
|
||||
* IM, 如果为空,默认是 IM
|
||||
*/
|
||||
private final List<String> remindTypes;
|
||||
|
||||
public CustomRemindTaskCmd(String terminalType, String processInstanceId, String taskDefinitionKey, List<String> remindTypes, SupportRefreshProperties refreshProperties) {
|
||||
this.terminalType = terminalType;
|
||||
this.processInstanceId = processInstanceId;
|
||||
this.taskDefinitionKey = taskDefinitionKey;
|
||||
this.remindTypes = CollectionUtils.isEmpty(remindTypes) ? Lists.newArrayList("IM") : remindTypes;
|
||||
this.refreshProperties = refreshProperties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String paramToJsonString() {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("terminalType", terminalType);
|
||||
params.put("processInstanceId", processInstanceId);
|
||||
params.put("taskDefinitionKey", taskDefinitionKey);
|
||||
params.put("remindTypes", remindTypes);
|
||||
return JSON.toJSONString(params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void executeInternal(CommandContext commandContext) {
|
||||
ProcessEngineConfigurationImpl processEngineConfiguration =
|
||||
CommandContextUtil.getProcessEngineConfiguration(commandContext);
|
||||
RuntimeService runtimeService = processEngineConfiguration.getRuntimeService();
|
||||
ProcessInstance processInstance =
|
||||
runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
|
||||
if (Objects.isNull(processInstance)) {
|
||||
throw new WorkflowEngineException(PROCESS_INSTANCE_CANT_REMIND, processInstanceId);
|
||||
}
|
||||
|
||||
TaskService taskService = processEngineConfiguration.getTaskService();
|
||||
TaskQuery taskQuery = taskService.createTaskQuery().processInstanceId(processInstanceId);
|
||||
if (StringUtils.hasLength(taskDefinitionKey)) {
|
||||
taskQuery.taskDefinitionKey(taskDefinitionKey);
|
||||
}
|
||||
List<Task> list = taskQuery.active().list();
|
||||
if (CollectionUtils.isEmpty(list)) {
|
||||
throw new WorkflowEngineException(TASK_REMIND_ERROR_NOT_EXISTS);
|
||||
}
|
||||
if (!StringUtils.hasText(taskDefinitionKey)) {
|
||||
List<String> taskDefinitionKeys = list.stream().map(Task::getTaskDefinitionKey).distinct().collect(Collectors.toList());
|
||||
if (taskDefinitionKeys.isEmpty()) {
|
||||
throw new WorkflowEngineException(TASK_REMIND_ERROR_NOT_EXISTS);
|
||||
} else if (taskDefinitionKeys.size() > 1) {
|
||||
throw new WorkflowEngineException(REMIND_TASK_TOO_MANY);
|
||||
} else {
|
||||
taskDefinitionKey = taskDefinitionKeys.get(0);
|
||||
}
|
||||
}
|
||||
FlowableEventDispatcher eventDispatcher = processEngineConfiguration.getEventDispatcher();
|
||||
Process process = ProcessDefinitionUtil.getProcess(processInstance.getProcessDefinitionId());
|
||||
Optional<BpmnNoticeConf> noticeConfig =
|
||||
BpmnMetaParserHelper.getNoticeConfig(process);
|
||||
|
||||
Map<String, Object> variables = runtimeService.getVariables(processInstanceId, list.stream()
|
||||
.map(i -> INTERNAL_TASK_RELATION_ASSIGNEE_INFO + i.getId()).collect(Collectors.toList()));
|
||||
List<BpmnTaskDelegateAssigner> assigners = variables.values().stream()
|
||||
.map(BpmnTaskDelegateAssigner::toObjectCompatible)
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
|
||||
// 过滤出未审批的任何,用选择的方式去发送消息
|
||||
remindTypes.forEach(type -> {
|
||||
list.forEach(task -> {
|
||||
assigners.stream().filter(i -> Objects.equals(task.getAssignee(), i.buildAssigneeId())).findAny().ifPresent(assigner -> {
|
||||
MessagePushEventImpl event = MessagePushEventBuilder.createEvent(MessagePushEventType.valueOf(type),
|
||||
Lists.newArrayList(assigner), noticeConfig.orElse(null), processInstance.getProcessInstanceId(),
|
||||
processInstance.getProcessDefinitionKey(), processInstance.getTenantId(), task.getId(),
|
||||
getActivitySignature(process.getFlowElement(taskDefinitionKey)),
|
||||
refreshProperties.getImTemplateCode(), terminalType);
|
||||
eventDispatcher.dispatchEvent(event, processEngineConfiguration.getEngineCfgKey());
|
||||
});
|
||||
});
|
||||
});
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@ -35,4 +35,8 @@ public interface MessagePushEvent extends FlowableEvent {
|
||||
|
||||
String getTaskId();
|
||||
|
||||
String getImTemplateCode();
|
||||
|
||||
String getTerminalType();
|
||||
|
||||
}
|
||||
|
||||
@ -9,7 +9,14 @@ import java.util.List;
|
||||
|
||||
import static cn.axzo.workflow.common.code.OtherRespCode.MESSAGE_PUSH_EVENT_BUILD_ERROR;
|
||||
import static cn.axzo.workflow.common.code.OtherRespCode.MES_PUSH_OBJECT_BUILD_ERROR;
|
||||
import static cn.axzo.workflow.core.engine.event.MessagePushEventType.*;
|
||||
import static cn.axzo.workflow.core.engine.event.MessagePushEventType.CARBON_COPY;
|
||||
import static cn.axzo.workflow.core.engine.event.MessagePushEventType.CARBON_COPY_COMPLETE;
|
||||
import static cn.axzo.workflow.core.engine.event.MessagePushEventType.IM;
|
||||
import static cn.axzo.workflow.core.engine.event.MessagePushEventType.NOTICE;
|
||||
import static cn.axzo.workflow.core.engine.event.MessagePushEventType.PENDING_COMPLETE;
|
||||
import static cn.axzo.workflow.core.engine.event.MessagePushEventType.PENDING_PUSH;
|
||||
import static cn.axzo.workflow.core.engine.event.MessagePushEventType.PENDING_ROLLBACK;
|
||||
import static cn.axzo.workflow.core.engine.event.MessagePushEventType.SMS;
|
||||
|
||||
/**
|
||||
* 推送事件对象构造器
|
||||
@ -22,6 +29,11 @@ public class MessagePushEventBuilder {
|
||||
public static MessagePushEventImpl createEvent(MessagePushEventType type, List<BpmnTaskDelegateAssigner> assigners,
|
||||
BpmnNoticeConf noticeConf, String processInstanceId, String processDefinitionKey,
|
||||
String tenantId, String taskId, Boolean activitySignature) {
|
||||
return createEvent(type, assigners, noticeConf, processInstanceId, processDefinitionKey, tenantId, taskId, activitySignature, null, null);
|
||||
}
|
||||
public static MessagePushEventImpl createEvent(MessagePushEventType type, List<BpmnTaskDelegateAssigner> assigners,
|
||||
BpmnNoticeConf noticeConf, String processInstanceId, String processDefinitionKey,
|
||||
String tenantId, String taskId, Boolean activitySignature, String imTemplateCode, String terminalType) {
|
||||
switch (type) {
|
||||
case NOTICE:
|
||||
return createNoticeEvent(assigners, noticeConf, processInstanceId, processDefinitionKey, tenantId, taskId, activitySignature);
|
||||
@ -35,6 +47,8 @@ public class MessagePushEventBuilder {
|
||||
return createCarbonCopyCompleteEvent(assigners, noticeConf, processInstanceId, processDefinitionKey, tenantId, activitySignature);
|
||||
case SMS:
|
||||
return createSmsEvent(assigners, noticeConf, processInstanceId, processDefinitionKey, tenantId, taskId, activitySignature);
|
||||
case IM:
|
||||
return createImEvent(assigners, imTemplateCode, processInstanceId, terminalType);
|
||||
default:
|
||||
throw new WorkflowEngineException(MES_PUSH_OBJECT_BUILD_ERROR);
|
||||
}
|
||||
@ -111,4 +125,11 @@ public class MessagePushEventBuilder {
|
||||
newEvent.setActivitySignature(activitySignature);
|
||||
return newEvent;
|
||||
}
|
||||
|
||||
public static MessagePushEventImpl createImEvent(List<BpmnTaskDelegateAssigner> assigners,
|
||||
String imTemplateCode,
|
||||
String processInstanceId,
|
||||
String terminalType) {
|
||||
return new MessagePushEventImpl(IM, assigners, imTemplateCode, processInstanceId, terminalType);
|
||||
}
|
||||
}
|
||||
|
||||
@ -30,6 +30,8 @@ public class MessagePushEventImpl implements MessagePushEvent {
|
||||
private String currentTaskDefinitionKey;
|
||||
private String tenantId;
|
||||
private String taskId;
|
||||
private String imTemplateCode;
|
||||
private String terminalType;
|
||||
|
||||
public MessagePushEventImpl(FlowableEventType type) {
|
||||
if (type == null) {
|
||||
@ -61,6 +63,13 @@ public class MessagePushEventImpl implements MessagePushEvent {
|
||||
this.taskId = taskId;
|
||||
}
|
||||
|
||||
public MessagePushEventImpl(FlowableEventType type, List<BpmnTaskDelegateAssigner> assigners, String imTemplateCode,
|
||||
String processInstanceId, String terminalType) {
|
||||
this(type, assigners, null, processInstanceId, null, null, null);
|
||||
this.imTemplateCode = imTemplateCode;
|
||||
this.terminalType = terminalType;
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用该对象时需遵守,如果是 task 级的,一定要传 taskId, 其他参数则都是必传
|
||||
* <p>
|
||||
@ -190,6 +199,24 @@ public class MessagePushEventImpl implements MessagePushEvent {
|
||||
return activitySignature;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getImTemplateCode() {
|
||||
return imTemplateCode;
|
||||
}
|
||||
|
||||
public void setImTemplateCode(String imTemplateCode) {
|
||||
this.imTemplateCode = imTemplateCode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTerminalType() {
|
||||
return terminalType;
|
||||
}
|
||||
|
||||
public void setTerminalType(String terminalType) {
|
||||
this.terminalType = terminalType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getClass() + " - " + type;
|
||||
|
||||
@ -43,6 +43,10 @@ public enum MessagePushEventType implements FlowableEventType {
|
||||
* 推送短信
|
||||
*/
|
||||
SMS,
|
||||
/**
|
||||
* IM 消息
|
||||
*/
|
||||
IM,
|
||||
;
|
||||
|
||||
public static final MessagePushEventType[] EMPTY_ARRAY = new MessagePushEventType[]{};
|
||||
|
||||
@ -0,0 +1,45 @@
|
||||
package cn.axzo.workflow.core.engine.job;
|
||||
|
||||
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskRemindDTO;
|
||||
import cn.axzo.workflow.core.conf.SupportRefreshProperties;
|
||||
import cn.axzo.workflow.core.engine.cmd.CustomRemindTaskCmd;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.flowable.common.engine.impl.interceptor.CommandContext;
|
||||
import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl;
|
||||
import org.flowable.engine.impl.util.CommandContextUtil;
|
||||
import org.flowable.job.service.JobHandler;
|
||||
import org.flowable.job.service.impl.persistence.entity.JobEntity;
|
||||
import org.flowable.variable.api.delegate.VariableScope;
|
||||
|
||||
/**
|
||||
* 异步的催办任务的处理器
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2025-06-13 14:13
|
||||
*/
|
||||
@Slf4j
|
||||
public class AsyncRemindTaskJobHandler extends AbstractExecuteWithLockJobHandler implements JobHandler {
|
||||
public static final String TYPE = "async-remind-task";
|
||||
private final SupportRefreshProperties refreshProperties;
|
||||
|
||||
public AsyncRemindTaskJobHandler(SupportRefreshProperties refreshProperties) {
|
||||
this.refreshProperties = refreshProperties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getType() {
|
||||
return TYPE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void executeInternal(JobEntity job, String configuration, VariableScope variableScope, CommandContext commandContext) {
|
||||
log.info("AsyncRejectTaskJobHandler executing...");
|
||||
log(job);
|
||||
ProcessEngineConfigurationImpl processEngineConfiguration =
|
||||
CommandContextUtil.getProcessEngineConfiguration(commandContext);
|
||||
BpmnTaskRemindDTO dto = JSONUtil.toBean(job.getCustomValues(), BpmnTaskRemindDTO.class);
|
||||
processEngineConfiguration.getCommandExecutor().execute(new CustomRemindTaskCmd(dto.getTerminalType(),
|
||||
dto.getProcessInstanceId(), dto.getTaskDefinitionKey(), dto.getRemindTypes(), refreshProperties));
|
||||
}
|
||||
}
|
||||
@ -196,12 +196,12 @@ public class EngineExecutionStartListener implements ExecutionListener {
|
||||
assigners.addAll(approverSelect(ApproverEmptyHandleTypeEnum.transferToAdmin.getType(), userTask,
|
||||
execution, true));
|
||||
|
||||
finalEmptyAssigneeHandle(assigners, userTask, execution, "转交管理员失败,系统中止", "karma: " + (refreshProperties.getUseNewToAdminApi() ? "api/flow/listTaskAssignerAdmin/v2" : "api/flow/listTaskAssignerAdmin"));
|
||||
finalEmptyAssigneeHandle(assigners, userTask, execution, "未找到审批人且转交管理员失败,自动中止", "karma: " + (refreshProperties.getUseNewToAdminApi() ? "api/flow/listTaskAssignerAdmin/v2" : "api/flow/listTaskAssignerAdmin"));
|
||||
break;
|
||||
case specifyAssignee:
|
||||
assigners.addAll(approverSelect(ApproverEmptyHandleTypeEnum.specifyAssignee.getType(), userTask,
|
||||
execution, true));
|
||||
finalEmptyAssigneeHandle(assigners, userTask, execution, "转交指定人员失败,系统自动中止", "org-gateway: api/node-user/list");
|
||||
finalEmptyAssigneeHandle(assigners, userTask, execution, "转交指定人员失败,自动中止", "org-gateway: api/node-user/list");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
||||
@ -19,6 +19,7 @@ import java.util.Set;
|
||||
|
||||
import static cn.axzo.workflow.core.engine.event.MessagePushEventType.CARBON_COPY;
|
||||
import static cn.axzo.workflow.core.engine.event.MessagePushEventType.CARBON_COPY_COMPLETE;
|
||||
import static cn.axzo.workflow.core.engine.event.MessagePushEventType.IM;
|
||||
import static cn.axzo.workflow.core.engine.event.MessagePushEventType.NOTICE;
|
||||
import static cn.axzo.workflow.core.engine.event.MessagePushEventType.PENDING_COMPLETE;
|
||||
import static cn.axzo.workflow.core.engine.event.MessagePushEventType.PENDING_PUSH;
|
||||
@ -47,6 +48,7 @@ public class EngineNoticeEventListener extends AbstractFlowableEventListener {
|
||||
.add(CARBON_COPY)
|
||||
.add(CARBON_COPY_COMPLETE)
|
||||
.add(SMS)
|
||||
.add(IM)
|
||||
.build();
|
||||
|
||||
@Override
|
||||
@ -101,6 +103,12 @@ public class EngineNoticeEventListener extends AbstractFlowableEventListener {
|
||||
stopWatch.stop();
|
||||
log.info("SMS StopWatch : running time = {} 's", stopWatch.getTotalTimeSeconds());
|
||||
break;
|
||||
case IM:
|
||||
stopWatch.start("IM Event Execution Time");
|
||||
getOrderedListeners().forEach(i -> i.onIm(event));
|
||||
stopWatch.stop();
|
||||
log.info("IM StopWatch : running time = {} 's", stopWatch.getTotalTimeSeconds());
|
||||
break;
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
@ -41,6 +41,7 @@ import static org.flowable.common.engine.impl.interceptor.EngineConfigurationCon
|
||||
public class AutoPassTransactionListener implements TransactionListener {
|
||||
private final DelegateTask delegateTask;
|
||||
private final String advice;
|
||||
private final String operationDesc;
|
||||
|
||||
@Override
|
||||
public void execute(CommandContext commandContext) {
|
||||
@ -59,7 +60,7 @@ public class AutoPassTransactionListener implements TransactionListener {
|
||||
pass.setTaskId(delegateTask.getId());
|
||||
pass.setAdvice(advice);
|
||||
pass.setApprover(assigner);
|
||||
pass.setOperationDesc("(自动通过)");
|
||||
pass.setOperationDesc(operationDesc);
|
||||
String jobId = commandExecutor.execute(commandConfig, new CustomApproveTaskAsyncCmd(pass));
|
||||
|
||||
// 重置任务,因为上面的 cmd 和这个 cmd 的 lock 对象不一致
|
||||
|
||||
@ -33,6 +33,7 @@ import static org.flowable.common.engine.impl.interceptor.EngineConfigurationCon
|
||||
@AllArgsConstructor
|
||||
public class AutoRejectTransactionListener implements TransactionListener {
|
||||
private final DelegateTask delegateTask;
|
||||
private final String operationDesc;
|
||||
|
||||
@Override
|
||||
public void execute(CommandContext commandContext) {
|
||||
@ -46,8 +47,8 @@ public class AutoRejectTransactionListener implements TransactionListener {
|
||||
CommandExecutor commandExecutor = springProcessEngineConfiguration.getCommandExecutor();
|
||||
BpmnTaskAuditDTO reject = new BpmnTaskAuditDTO();
|
||||
reject.setTaskId(delegateTask.getId());
|
||||
reject.setApprover(new BpmnTaskDelegateAssigner("系统", "system", delegateTask.getTenantId()));
|
||||
reject.setOperationDesc("自动驳回");
|
||||
reject.setApprover(new BpmnTaskDelegateAssigner("", "system", delegateTask.getTenantId()));
|
||||
reject.setOperationDesc(operationDesc);
|
||||
String jobId = commandExecutor.execute(commandConfig, new CustomRejectionTaskAsyncCmd(reject));
|
||||
|
||||
// 重置任务,因为上面的 cmd 和这个 cmd 的 lock 对象不一致
|
||||
|
||||
@ -38,6 +38,7 @@ public interface BpmnMessagePushEventListener extends OperationContext, Ordered
|
||||
|
||||
/**
|
||||
* 恢复待办
|
||||
*
|
||||
* @param event
|
||||
*/
|
||||
default void onPendingRollback(MessagePushEvent event) {
|
||||
@ -67,4 +68,12 @@ public interface BpmnMessagePushEventListener extends OperationContext, Ordered
|
||||
*/
|
||||
default void onSms(MessagePushEvent event) {
|
||||
}
|
||||
|
||||
/**
|
||||
* 推送即时消息
|
||||
*
|
||||
* @param event
|
||||
*/
|
||||
default void onIm(MessagePushEvent event) {
|
||||
}
|
||||
}
|
||||
|
||||
@ -188,8 +188,11 @@ import static cn.axzo.workflow.common.constant.BpmnConstants.SIGN_VARIABLE;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.WORKFLOW_ENGINE_VERSION;
|
||||
import static cn.axzo.workflow.common.constant.MetaInfoConstants.MODEL_TYPE_PROCESS;
|
||||
import static cn.axzo.workflow.common.enums.ApprovalMethodEnum.autoPassed;
|
||||
import static cn.axzo.workflow.common.enums.ApprovalMethodEnum.autoPassed_empty;
|
||||
import static cn.axzo.workflow.common.enums.ApprovalMethodEnum.autoRejection;
|
||||
import static cn.axzo.workflow.common.enums.ApprovalMethodEnum.autoRejection_empty;
|
||||
import static cn.axzo.workflow.common.enums.ApprovalMethodEnum.human;
|
||||
import static cn.axzo.workflow.common.enums.ApprovalMethodEnum.transferToAdmin;
|
||||
import static cn.axzo.workflow.common.enums.BpmnButtonEnum.BPMN_UPGRADE;
|
||||
import static cn.axzo.workflow.common.enums.BpmnFlowNodeMode.AND;
|
||||
import static cn.axzo.workflow.common.enums.BpmnFlowNodeMode.EXCEPTIONAL;
|
||||
@ -1102,10 +1105,13 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic
|
||||
getApproverEmptyHandleType(i).ifPresent(emptyHandleType -> {
|
||||
switch (emptyHandleType) {
|
||||
case autoPassed:
|
||||
node.setApprovalMethod(autoPassed);
|
||||
node.setApprovalMethod(autoPassed_empty);
|
||||
break;
|
||||
case autoRejection:
|
||||
node.setApprovalMethod(autoRejection);
|
||||
node.setApprovalMethod(autoRejection_empty);
|
||||
break;
|
||||
case transferToAdmin:
|
||||
node.setApprovalMethod(transferToAdmin);
|
||||
break;
|
||||
default:
|
||||
node.setNodeMode(EXCEPTIONAL);
|
||||
@ -1591,16 +1597,29 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic
|
||||
if (Objects.nonNull(e.getApprovalMethod())) {
|
||||
switch (e.getApprovalMethod()) {
|
||||
case bizSpecify:
|
||||
build.setOperationDesc("动态审批人");
|
||||
break;
|
||||
case nobody:
|
||||
build.setOperationDesc("待处理");
|
||||
build.setOperationDesc("系统处理");
|
||||
break;
|
||||
case autoPassed:
|
||||
build.setOperationDesc("无需审批人,自动同意");
|
||||
break;
|
||||
case autoRejection:
|
||||
build.setOperationDesc("无需审批人,自动驳回");
|
||||
break;
|
||||
case autoPassed_empty:
|
||||
build.setOperationDesc("未找到审批人,自动同意");
|
||||
break;
|
||||
case autoRejection_empty:
|
||||
build.setOperationDesc("未找到审批人,自动驳回");
|
||||
break;
|
||||
case transferToAdmin:
|
||||
build.setOperationDesc("找不到审批人且转交管理员失败,自动中止");
|
||||
break;
|
||||
case human:
|
||||
if (Objects.equals(e.getNodeMode(), EXCEPTIONAL)) {
|
||||
build.setOperationDesc("节点异常");
|
||||
build.setOperationDesc("");
|
||||
} else {
|
||||
int countPerson = e.getForecastAssigners().size();
|
||||
if (Objects.equals(BpmnFlowNodeMode.AND, e.getNodeMode())) {
|
||||
|
||||
@ -31,6 +31,7 @@ import cn.axzo.workflow.common.model.response.bpmn.task.BpmnTaskDonePageItemVO;
|
||||
import cn.axzo.workflow.common.model.response.bpmn.task.BpmnTaskInstanceVO;
|
||||
import cn.axzo.workflow.common.model.response.bpmn.task.BpmnTaskTodoPageItemVO;
|
||||
import cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper;
|
||||
import cn.axzo.workflow.core.conf.SupportRefreshProperties;
|
||||
import cn.axzo.workflow.core.engine.cmd.CustomApproveTaskAsyncCmd;
|
||||
import cn.axzo.workflow.core.engine.cmd.CustomApproveTaskCmd;
|
||||
import cn.axzo.workflow.core.engine.cmd.CustomApproveTaskWithFormAsyncCmd;
|
||||
@ -44,6 +45,8 @@ import cn.axzo.workflow.core.engine.cmd.CustomCountersignUserTaskCmd;
|
||||
import cn.axzo.workflow.core.engine.cmd.CustomCreateDummyTaskCmd;
|
||||
import cn.axzo.workflow.core.engine.cmd.CustomRejectionTaskAsyncCmd;
|
||||
import cn.axzo.workflow.core.engine.cmd.CustomRejectionTaskCmd;
|
||||
import cn.axzo.workflow.core.engine.cmd.CustomRemindTaskAsyncCmd;
|
||||
import cn.axzo.workflow.core.engine.cmd.CustomRemindTaskCmd;
|
||||
import cn.axzo.workflow.core.engine.cmd.CustomResetTaskApproversAsyncCmd;
|
||||
import cn.axzo.workflow.core.engine.cmd.CustomResetTaskApproversCmd;
|
||||
import cn.axzo.workflow.core.engine.cmd.CustomTransferUserTaskAsyncCmd;
|
||||
@ -194,6 +197,8 @@ public class BpmnProcessTaskServiceImpl implements BpmnProcessTaskService {
|
||||
private ExtAxProcessLogService extAxProcessLogService;
|
||||
@Resource
|
||||
private ExtAxProcessLogService processLogService;
|
||||
@Resource
|
||||
private SupportRefreshProperties refreshProperties;
|
||||
|
||||
@Override
|
||||
public BpmPageResult<BpmnTaskTodoPageItemVO> getTodoTaskPage(BpmnTaskPageSearchDTO dto) {
|
||||
@ -887,47 +892,12 @@ public class BpmnProcessTaskServiceImpl implements BpmnProcessTaskService {
|
||||
|
||||
@Override
|
||||
public void remindTask(BpmnTaskRemindDTO dto) {
|
||||
TaskQuery taskQuery = taskService.createTaskQuery().processInstanceId(dto.getProcessInstanceId());
|
||||
if (StringUtils.hasLength(dto.getTaskDefinitionKey())) {
|
||||
taskQuery.taskDefinitionKey(dto.getTaskDefinitionKey());
|
||||
CommandExecutor commandExecutor = processEngineConfiguration.getCommandExecutor();
|
||||
if (Boolean.TRUE.equals(dto.getAsync())) {
|
||||
commandExecutor.execute(new CustomRemindTaskAsyncCmd(dto));
|
||||
} else {
|
||||
commandExecutor.execute(new CustomRemindTaskCmd(dto.getTerminalType(), dto.getProcessInstanceId(), dto.getTaskDefinitionKey(), dto.getRemindTypes(), refreshProperties));
|
||||
}
|
||||
List<Task> list = taskQuery.active().list();
|
||||
if (CollectionUtils.isEmpty(list)) {
|
||||
throw new WorkflowEngineException(TASK_REMIND_ERROR_NOT_EXISTS);
|
||||
}
|
||||
|
||||
if (CollectionUtils.isEmpty(dto.getRemindTypes())) {
|
||||
return;
|
||||
}
|
||||
ProcessEngineConfigurationImpl processEngineConfiguration = CommandContextUtil.getProcessEngineConfiguration();
|
||||
FlowableEventDispatcher eventDispatcher = processEngineConfiguration.getEventDispatcher();
|
||||
ProcessInstance processInstance =
|
||||
runtimeService.createProcessInstanceQuery().processInstanceId(dto.getProcessInstanceId()).singleResult();
|
||||
Process process = ProcessDefinitionUtil.getProcess(processInstance.getProcessDefinitionId());
|
||||
Optional<BpmnNoticeConf> noticeConfig =
|
||||
BpmnMetaParserHelper.getNoticeConfig(process);
|
||||
@SuppressWarnings("unchecked")
|
||||
List<BpmnTaskDelegateAssigner> assigners =
|
||||
(List<BpmnTaskDelegateAssigner>) runtimeService.getVariable(dto.getProcessInstanceId(),
|
||||
INTERNAL_ACTIVITY_RELATION_ASSIGNEE_LIST_INFO_SNAPSHOT + dto.getTaskDefinitionKey());
|
||||
|
||||
// 过滤出未审批的任何,用选择的方式去发送消息
|
||||
dto.getRemindTypes().forEach(type -> {
|
||||
list.forEach(task -> {
|
||||
assigners.stream().filter(i -> Objects.equals(task.getAssignee(), i.buildAssigneeId())).findAny().ifPresent(assigner -> {
|
||||
MessagePushEventImpl event = MessagePushEventBuilder.createEvent(MessagePushEventType.valueOf(type),
|
||||
Lists.newArrayList(assigner), noticeConfig.orElse(null),
|
||||
processInstance.getProcessInstanceId(),
|
||||
processInstance.getProcessDefinitionKey(),
|
||||
processInstance.getTenantId(), task.getId(),
|
||||
getActivitySignature(process.getFlowElement(dto.getTaskDefinitionKey())));
|
||||
event.setProcessInstanceId(processInstance.getProcessInstanceId());
|
||||
event.setTenantId(processInstance.getTenantId());
|
||||
event.setTaskId(task.getId());
|
||||
eventDispatcher.dispatchEvent(event, processEngineConfiguration.getEngineCfgKey());
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -226,7 +226,9 @@ public class CategoryServiceImpl extends ServiceImpl<ExtAxDictMapper, ExtAxDict>
|
||||
dto.getWorkspaceTypeCode())
|
||||
.eq(ExtAxDict::getTenantId, dto.getTenantId())
|
||||
.eq(dto.getBusinessType() != null, ExtAxDict::getBusinessType, dto.getBusinessType())
|
||||
.eq(ExtAxDict::getIsDelete, 0);
|
||||
.eq(ExtAxDict::getIsDelete, 0)
|
||||
.orderByDesc(Objects.equals(dto.getOrderCreateAt(), "desc"), ExtAxDict::getCreateAt);
|
||||
;
|
||||
List<ExtAxDict> extAxDicts = dictMapper.selectList(queryWrapper);
|
||||
return categoryConverter.toVos(extAxDicts);
|
||||
}
|
||||
|
||||
@ -18,7 +18,11 @@ import javax.annotation.Resource;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.*;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.DUMMY_ASSIGNEE_ID;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.HIDDEN_ASSIGNEE_ID;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.NO_ASSIGNEE;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.ROBOT_ASSIGNEE_ID;
|
||||
import static cn.axzo.workflow.core.common.enums.BpmnProcessTaskResultEnum.HANDLING;
|
||||
|
||||
/**
|
||||
* Api Log 表操服务实现
|
||||
@ -53,7 +57,8 @@ public class ExtAxProcessLogServiceImpl implements ExtAxProcessLogService {
|
||||
|
||||
@Override
|
||||
public void updateAssigneeAndSnapshot(ExtAxProcessLog queryLog, BpmnTaskDelegateAssigner assignee, OrgStructureSnapshotInfo snapshotInfo) {
|
||||
updateAssigneeAndSnapshot(queryLog, assignee, snapshotInfo, assignee.getAssignerName());
|
||||
updateAssigneeAndSnapshot(queryLog, assignee, snapshotInfo, assignee.getAssignerName() + HANDLING.getDesc());
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -64,7 +69,7 @@ public class ExtAxProcessLogServiceImpl implements ExtAxProcessLogService {
|
||||
return;
|
||||
}
|
||||
ExtAxProcessLog update = new ExtAxProcessLog();
|
||||
update.setOperationDesc(StringUtils.hasText(operationDesc) ? operationDesc : assignee.getAssignerName());
|
||||
update.setOperationDesc(StringUtils.hasText(operationDesc) ? operationDesc : assignee.getAssignerName() + HANDLING.getDesc());
|
||||
update.setAssigneeFull(Lists.newArrayList(assignee));
|
||||
update.setAssigneeId(Long.valueOf(assignee.getPersonId()));
|
||||
update.setAssigneeTenantId(assignee.getTenantId());
|
||||
|
||||
@ -234,7 +234,7 @@ public abstract class AbstractBpmnTaskAssigneeSelector implements BpmnTaskAssign
|
||||
}
|
||||
List<Long> personIds = assigners.stream()
|
||||
.map(BpmnTaskDelegateAssigner::getPersonId)
|
||||
.filter(e -> Objects.nonNull(e) && StringUtils.hasText(e) && !Objects.equals("null", e))
|
||||
.filter(e -> Objects.nonNull(e) && StringUtils.hasText(e) && !Objects.equals("null", e) && !Objects.equals("system", e))
|
||||
.map(Long::parseLong)
|
||||
.distinct().collect(Collectors.toList());
|
||||
if (CollectionUtils.isEmpty(personIds)) {
|
||||
@ -244,7 +244,7 @@ public abstract class AbstractBpmnTaskAssigneeSelector implements BpmnTaskAssign
|
||||
"根据 PersonId 查询自然人档案", "cn.axzo.karma.client.feign.FlowSupportApi.listPersons", refreshProperties, context, personIds)
|
||||
.stream().collect(Collectors.toMap(PersonProfileResp::getId, Function.identity(), (s, t) -> s));
|
||||
assigners.forEach(assigner -> {
|
||||
if (!StringUtils.hasText(assigner.getPersonId()) || Objects.equals("null", assigner.getPersonId())) {
|
||||
if (!StringUtils.hasText(assigner.getPersonId()) || Objects.equals("null", assigner.getPersonId()) || Objects.equals("system", assigner.getPersonId())) {
|
||||
return;
|
||||
}
|
||||
long personId = Long.parseLong(Optional.ofNullable(assigner.getPersonId()).orElse("-1"));
|
||||
|
||||
@ -85,6 +85,7 @@ import static cn.axzo.workflow.common.constant.VariableConstants.VAR_TASK_USER_N
|
||||
import static cn.axzo.workflow.common.enums.BpmnButtonEnum.BPMN_UPGRADE;
|
||||
import static cn.axzo.workflow.common.enums.ProcessMessagePushEventEnum.PROCESS_CARBON_COPY;
|
||||
import static cn.axzo.workflow.common.enums.ProcessMessagePushEventEnum.PROCESS_CARBON_COPY_COMPLETE;
|
||||
import static cn.axzo.workflow.common.enums.ProcessMessagePushEventEnum.PROCESS_PUSH_IM;
|
||||
import static cn.axzo.workflow.common.enums.ProcessMessagePushEventEnum.PROCESS_PUSH_NOTICE;
|
||||
import static cn.axzo.workflow.common.enums.ProcessMessagePushEventEnum.PROCESS_PUSH_PENDING;
|
||||
import static cn.axzo.workflow.common.enums.ProcessMessagePushEventEnum.PROCESS_PUSH_PENDING_COMPLETE;
|
||||
@ -346,6 +347,21 @@ public class RocketMqMessagePushEventListener extends AbstractBpmnEventListener<
|
||||
event.getNoticeConfig().getSms().getSmsId(), JSONUtil.toJsonStr(event.getAssigners()), event.getProcessInstanceId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onIm(MessagePushEvent event) {
|
||||
if (!StringUtils.hasText(event.getImTemplateCode()) && !StringUtils.hasText(event.getTerminalType())) {
|
||||
log.warn("RocketMqMessagePushEventListener#onIm...ignore, imTemplateCode or terminalType is empty, event: {}", JSONUtil.toJsonStr(event));
|
||||
return;
|
||||
}
|
||||
log.info("RocketMqMessagePushEventListener#onIm...msgTemplateId: {}, receivePerson: {}, processInstanceId: {}",
|
||||
event.getImTemplateCode(), JSONUtil.toJsonStr(event.getAssigners()), event.getProcessInstanceId());
|
||||
MessagePushDTO dto = build(event.getImTemplateCode(),
|
||||
PROCESS_PUSH_IM, event, collectionVariable(event), event.getActivitySignature(), event.getTerminalType());
|
||||
sendMessageQueue(dto, PROCESS_PUSH_IM);
|
||||
log.info("RocketMqMessagePushEventListener#onIm...end, msgTemplateId: {}, receivePerson: {}, processInstanceId: {}",
|
||||
event.getImTemplateCode(), JSONUtil.toJsonStr(event.getAssigners()), event.getProcessInstanceId());
|
||||
}
|
||||
|
||||
private Map<String, Object> collectionVariable(MessagePushEvent event) {
|
||||
Map<String, Object> variables = new HashMap<>();
|
||||
|
||||
@ -422,6 +438,11 @@ public class RocketMqMessagePushEventListener extends AbstractBpmnEventListener<
|
||||
|
||||
public MessagePushDTO build(String templateId, ProcessMessagePushEventEnum type, MessagePushEvent event, Map<String,
|
||||
Object> variables, Boolean activitySignature) {
|
||||
return build(templateId, type, event, variables, activitySignature, null);
|
||||
}
|
||||
|
||||
public MessagePushDTO build(String templateId, ProcessMessagePushEventEnum type, MessagePushEvent event, Map<String,
|
||||
Object> variables, Boolean activitySignature, String terminalType) {
|
||||
return new MessagePushDTO()
|
||||
.setProcessInstanceId(event.getProcessInstanceId())
|
||||
.setAdscriptionTenantId(event.getTenantId())
|
||||
@ -432,7 +453,8 @@ public class RocketMqMessagePushEventListener extends AbstractBpmnEventListener<
|
||||
.setReceivePersons(event.getAssigners())
|
||||
.setVariables(variables)
|
||||
.setProcessApproveConf(event.getProcessApproveConfig())
|
||||
.setActivitySignature(activitySignature);
|
||||
.setActivitySignature(activitySignature)
|
||||
.setTerminalType(terminalType);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -83,7 +83,7 @@ public class AutoOperatorEvent_101_Listener extends AbstractBpmnEventListener<Ta
|
||||
boolean exists = checkApproverService.checkApproverExists(delegateTask, userTask, mainProcess, getContext());
|
||||
log.info("是否需要自动过程判断 exists:{},processInstId:{},taskDefinitionKey:{}", exists, delegateTask.getProcessInstanceId(), delegateTask.getTaskDefinitionKey());
|
||||
if (exists) {
|
||||
autoPass(delegateTask, "同一审批人,自动过审");
|
||||
autoPass(delegateTask, null,"已同意(同一审批人,自动过审)");
|
||||
}
|
||||
}
|
||||
// 检测节点自身配置是否有自动操作
|
||||
@ -136,10 +136,10 @@ public class AutoOperatorEvent_101_Listener extends AbstractBpmnEventListener<Ta
|
||||
.ifPresent(approverEmptyHandleTypeEnum -> {
|
||||
switch (approverEmptyHandleTypeEnum) {
|
||||
case autoPassed:
|
||||
autoPass(delegateTask);
|
||||
autoPass(delegateTask, "", "未找到审批人,自动同意");
|
||||
break;
|
||||
case autoRejection:
|
||||
autoReject(delegateTask);
|
||||
autoReject(delegateTask, "未找到审批人,自动驳回");
|
||||
break;
|
||||
case autoSkipped:
|
||||
// autoReject(delegateTask);
|
||||
@ -184,9 +184,13 @@ public class AutoOperatorEvent_101_Listener extends AbstractBpmnEventListener<Ta
|
||||
*
|
||||
* @param delegateTask 自动操作的任务
|
||||
*/
|
||||
private void autoReject(DelegateTask delegateTask) {
|
||||
private void autoReject(DelegateTask delegateTask, @Nullable String operationDesc) {
|
||||
Context.getTransactionContext().addTransactionListener(TransactionState.COMMITTED,
|
||||
new AutoRejectTransactionListener(delegateTask));
|
||||
new AutoRejectTransactionListener(delegateTask, operationDesc));
|
||||
}
|
||||
|
||||
private void autoReject(DelegateTask delegateTask) {
|
||||
autoReject(delegateTask,"无需审批人,自动驳回" );
|
||||
}
|
||||
|
||||
/**
|
||||
@ -197,9 +201,9 @@ public class AutoOperatorEvent_101_Listener extends AbstractBpmnEventListener<Ta
|
||||
* @param delegateTask 自动操作的任务
|
||||
* @param advice 添加自动操作任务时的额外意见
|
||||
*/
|
||||
private void autoPass(DelegateTask delegateTask, @Nullable String advice) {
|
||||
private void autoPass(DelegateTask delegateTask, @Nullable String advice, @Nullable String operationDesc) {
|
||||
Context.getTransactionContext().addTransactionListener(TransactionState.COMMITTED,
|
||||
new AutoPassTransactionListener(delegateTask, advice));
|
||||
new AutoPassTransactionListener(delegateTask, advice, operationDesc));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -208,7 +212,7 @@ public class AutoOperatorEvent_101_Listener extends AbstractBpmnEventListener<Ta
|
||||
* @param delegateTask 自动操作的任务
|
||||
*/
|
||||
private void autoPass(DelegateTask delegateTask) {
|
||||
autoPass(delegateTask, null);
|
||||
autoPass(delegateTask, null, "无需审批人,自动同意");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -166,8 +166,14 @@ public class BpmnProcessInstanceController extends BasicPopulateAvatarController
|
||||
@RepeatSubmit
|
||||
public CommonResponse<String> createProcessInstance(@Validated @RequestBody BpmnProcessInstanceCreateDTO dto) {
|
||||
log.info("发起审核createProcessInstance===>>>参数:{}", JSONUtil.toJsonStr(dto));
|
||||
// 填充头像
|
||||
// 填充名称头像
|
||||
populateUsersAvatar(dto.getInitiator());
|
||||
// 填充指定审批人名称头像
|
||||
if (!CollectionUtils.isEmpty(dto.getSpecifyAssignerMap())) {
|
||||
populateUsersAvatar(dto.getSpecifyAssignerMap().entrySet().stream().flatMap(e -> e.getValue().stream().filter(Objects::nonNull)).collect(Collectors.toList()));
|
||||
}
|
||||
// 填充签署人名称头像
|
||||
populateUsersAvatar(dto.getSignatories());
|
||||
dto.setAsync(false);
|
||||
return success(bpmnProcessInstanceService.createProcessInstance(dto));
|
||||
}
|
||||
|
||||
@ -63,7 +63,7 @@ import static cn.axzo.workflow.common.enums.BpmnFlowNodeType.NODE_STARTER;
|
||||
import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.APPROVED;
|
||||
import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.DELETED;
|
||||
import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.PROCESSING;
|
||||
import static cn.axzo.workflow.core.common.enums.BpmnProcessTaskResultEnum.PENDING;
|
||||
import static cn.axzo.workflow.core.common.enums.BpmnProcessTaskResultEnum.HANDLING;
|
||||
import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getActivitySignature;
|
||||
import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getApprovalMethod;
|
||||
import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getNodeType;
|
||||
@ -112,7 +112,7 @@ public class TaskEntityEventHandle implements EntityEventHandle<TaskEntity> {
|
||||
log.setNodeMode((isNodeStarter ? BpmnFlowNodeMode.GENERAL : getNodeMode(flowElement)).getType());
|
||||
log.setTaskId(taskEntity.getId());
|
||||
String operationDesc = taskEntity.getVariable(COMMENT_TYPE_OPERATION_DESC, String.class);
|
||||
log.setOperationDesc(StringUtils.hasText(operationDesc) ? operationDesc : PENDING.getDesc());
|
||||
log.setOperationDesc(StringUtils.hasText(operationDesc) ? operationDesc : HANDLING.getDesc());
|
||||
log.setStartTime(taskEntity.getCreateTime());
|
||||
log.setStatus(PROCESSING.getStatus());
|
||||
log.setSignature(getActivitySignature(flowElement));
|
||||
@ -217,7 +217,7 @@ public class TaskEntityEventHandle implements EntityEventHandle<TaskEntity> {
|
||||
ExtAxProcessLog queryLog = new ExtAxProcessLog();
|
||||
queryLog.setProcessInstanceId(taskEntity.getProcessInstanceId());
|
||||
queryLog.setTaskId(taskEntity.getId());
|
||||
queryLog.setOperationDesc(PENDING.getDesc());
|
||||
queryLog.setOperationDesc(HANDLING.getDesc());
|
||||
ExtAxProcessLog update = new ExtAxProcessLog();
|
||||
|
||||
ProcessEngineConfigurationImpl processEngineConfiguration = CommandContextUtil.getProcessEngineConfiguration();
|
||||
@ -229,6 +229,7 @@ public class TaskEntityEventHandle implements EntityEventHandle<TaskEntity> {
|
||||
update.setAssigneeTenantId(assignee.getTenantId());
|
||||
update.setAssigneeName(assignee.getAssignerName());
|
||||
update.setAssigneeOuId(assignee.getOuId());
|
||||
update.setOperationDesc(assignee.getAssignerName());
|
||||
}
|
||||
|
||||
boolean needDelete = false;
|
||||
|
||||
@ -83,4 +83,10 @@ public interface MessageNotificationEventHandler extends Ordered {
|
||||
default void pushSms(MessagePushDTO dto) {
|
||||
}
|
||||
|
||||
/**
|
||||
* IM 推送
|
||||
* @param dto
|
||||
*/
|
||||
default void pushIm(MessagePushDTO dto) {}
|
||||
|
||||
}
|
||||
|
||||
@ -66,6 +66,8 @@ public class InnerNotificationEventListener extends AbstractInnerWorkflowListene
|
||||
case PROCESS_PUSH_SMS:
|
||||
consumer = noticeListener::pushSms;
|
||||
break;
|
||||
case PROCESS_PUSH_IM:
|
||||
consumer = noticeListener::pushIm;
|
||||
default:
|
||||
log.warn("unknown message event type: {}", type);
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user