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:
wangli 2025-07-02 17:27:33 +08:00
commit 372dec7a2b
41 changed files with 543 additions and 84 deletions

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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() {

View File

@ -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 推送"),
;

View File

@ -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());
}

View File

@ -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;
}

View File

@ -55,4 +55,7 @@ public class CategorySearchDTO extends BpmPageParam {
*/
@ApiModelProperty(value = "业务类型")
private BusinessTypeEnum businessType;
@ApiModelProperty(value = "根据创建时间排序")
private String orderCreateAt;
}

View File

@ -75,5 +75,9 @@ public class MessagePushDTO implements Serializable {
* 节点电子签开关
*/
private Boolean activitySignature;
/**
* 催办专用属性催办时的终端类型管理端工人端
*/
private String terminalType;
}

View File

@ -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)) {

View File

@ -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()));
// 异步任务异常重试时间间隔

View File

@ -89,4 +89,7 @@ public class SupportRefreshProperties {
@Value("${workflow.esSyncBatchSize:10}")
private Integer esSyncBatchSize;
@Value("${workflow.imTemplateCode:}")
private String imTemplateCode;
}

View File

@ -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;

View File

@ -109,7 +109,7 @@ public class CustomApproveTaskCmd extends AbstractCommand<Void> implements Seria
if (Objects.nonNull(operationDesc)) {
this.operationDesc = operationDesc;
} else {
this.operationDesc = "(已通过)";
this.operationDesc = "已同意";
}
}

View File

@ -130,7 +130,7 @@ public class CustomApproveTaskWithFormCmd extends AbstractCommand<Void> implemen
if (Objects.nonNull(operationDesc)) {
this.operationDesc = operationDesc;
} else {
this.operationDesc = "(已通过)";
this.operationDesc = "已同意";
}
}

View File

@ -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);

View File

@ -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();

View File

@ -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();
}
}

View File

@ -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;
}
}

View File

@ -35,4 +35,8 @@ public interface MessagePushEvent extends FlowableEvent {
String getTaskId();
String getImTemplateCode();
String getTerminalType();
}

View File

@ -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);
}
}

View File

@ -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;

View File

@ -43,6 +43,10 @@ public enum MessagePushEventType implements FlowableEventType {
* 推送短信
*/
SMS,
/**
* IM 消息
*/
IM,
;
public static final MessagePushEventType[] EMPTY_ARRAY = new MessagePushEventType[]{};

View File

@ -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));
}
}

View File

@ -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;

View File

@ -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:
}
}

View File

@ -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 对象不一致

View File

@ -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 对象不一致

View File

@ -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) {
}
}

View File

@ -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())) {

View File

@ -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

View File

@ -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);
}

View File

@ -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());

View File

@ -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"));

View File

@ -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);
}

View File

@ -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, "无需审批人,自动同意");
}
}

View File

@ -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));
}

View File

@ -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;

View File

@ -83,4 +83,10 @@ public interface MessageNotificationEventHandler extends Ordered {
default void pushSms(MessagePushDTO dto) {
}
/**
* IM 推送
* @param dto
*/
default void pushIm(MessagePushDTO dto) {}
}

View File

@ -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);
}