diff --git a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/manage/FormAdminApi.java b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/manage/FormAdminApi.java index 7556be801..2590dd4a4 100644 --- a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/manage/FormAdminApi.java +++ b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/manage/FormAdminApi.java @@ -6,10 +6,13 @@ import cn.axzo.workflow.common.annotation.Manageable; import cn.axzo.workflow.common.model.request.form.definition.StartFormSearchDTO; import cn.axzo.workflow.common.model.request.form.instance.FormDetailDTO; import cn.axzo.workflow.common.model.request.form.instance.FormSearchDTO; +import cn.axzo.workflow.common.model.request.form.instance.FromDataSearchDTO; import cn.axzo.workflow.common.model.response.form.FormVO; import cn.axzo.workflow.common.model.response.form.definition.FormDefinitionVO; +import cn.axzo.workflow.common.model.response.form.instance.FormDataVO; import cn.axzo.workflow.common.model.response.form.instance.FormInstanceVO; import cn.azxo.framework.common.model.CommonResponse; +import io.swagger.v3.oas.annotations.Operation; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; @@ -36,6 +39,7 @@ public interface FormAdminApi { /** * 获取指定审批业务的流程表单设置, + * * @param dto * @return */ @@ -55,4 +59,14 @@ public interface FormAdminApi { @PostMapping("/api/form/admin/instance/render") @InvokeMode(SYNC) CommonResponse getFormInstance(@Validated @RequestBody FormDetailDTO dto); + + /** + * 获取指定表单审批的实例数据 + * + * @param dto + * @return + */ + @PostMapping("/api/form/admin/instance/form/data") + @InvokeMode(SYNC) + CommonResponse> getFormData(@Validated @RequestBody FromDataSearchDTO dto); } diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/enums/FormFieldTypeEnum.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/enums/FormFieldTypeEnum.java new file mode 100644 index 000000000..76c13501a --- /dev/null +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/enums/FormFieldTypeEnum.java @@ -0,0 +1,143 @@ +package cn.axzo.workflow.common.enums; + +import cn.axzo.workflow.common.model.dto.AmountFieldDTO; +import cn.axzo.workflow.common.model.dto.ContactsPersonDTO; +import cn.axzo.workflow.common.model.dto.UploadFieldDTO; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; + +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +/** + * 流程引擎表单字段类型枚举 + *

+ * 参考文档:{@see https://alidocs.dingtalk.com/i/nodes/ZgpG2NdyVXKy17o6fQ5nKGvMWMwvDqPk} + * + * @author wangli + * @since 2025-08-04 11:44 + */ +public enum FormFieldTypeEnum { + input("input", "文本", new TypeReference() { + }), + textarea("textarea", "多行文本", new TypeReference() { + }), + upload("upload", "上传文件", new TypeReference>() { + }), + image("image", "图片", new TypeReference>() { + }), + date("date", "日期", new TypeReference() { + }), + customComponent("customComponent", "自定义组件", new TypeReference>>() { + }), + taskOrder("taskOrder", "任务顺序", new TypeReference>() { + }), + rectifyOrder("rectifyOrder", "整改顺序", new TypeReference>() { + }), + changeSignatureOrder("changeSignatureOrder", "变更签署顺序", new TypeReference>() { + }), + contacts("contacts", "联系人", new TypeReference>() { + }), + amount("amount", "金额", new TypeReference() { + }), + decimal("decimal", "小数", new TypeReference>() { + }), + ; + + private final String type; + private final String desc; + private final TypeReference typeReference; + + FormFieldTypeEnum(String type, String desc, TypeReference typeReference) { + this.type = type; + this.desc = desc; + this.typeReference = typeReference; + } + + public String getType() { + return type; + } + + public String getDesc() { + return desc; + } + + public TypeReference getTypeReference() { + return typeReference; + } + + public static FormFieldTypeEnum valueOfType(String type) { + return Arrays.stream(FormFieldTypeEnum.values()) + .filter(i -> Objects.equals(i.getType(), type)) + .findAny() + .orElse(null); + } + + public static Object parseValue(String type, Object fieldValue, Map fieldParams) { + FormFieldTypeEnum fieldType = valueOfType(type); + if (fieldType == null) { + return null; + } + TypeReference typeReference = fieldType.getTypeReference(); + if (typeReference == null || typeReference.getType() == null) { + return fieldValue; + } + if (fieldValue == null) { + return null; + } + ObjectMapper objectMapper = new ObjectMapper(); + try { + // 如果已经是目标类型,直接返回 + if (objectMapper.constructType(typeReference.getType()).getRawClass().isInstance(fieldValue)) { + return fieldValue; + } + // 先转为字符串再反序列化 + String json = fieldValue.toString(); + if (!(fieldValue instanceof String)) { + json = objectMapper.writeValueAsString(fieldValue); + } + Object defaultValue = handleDefault(fieldParams, json, fieldType); + if (Objects.nonNull(defaultValue)) { + return fieldValue; + } + if (Objects.equals(type, "decimal")) { + // 特殊处理 decimal 类型,确保返回的 Map 包含 unit 字段 + Map decimalMap = new HashMap<>(); + decimalMap.put("value", fieldValue); + decimalMap.put("unit", fieldParams.getOrDefault("unit", "")); + return decimalMap; + } + return objectMapper.readValue(json, typeReference); + } catch (Exception e) { + throw new RuntimeException("字段值解析失败: " + fieldValue, e); + } + } + + private static Object handleDefault(Map fieldParams, String json, FormFieldTypeEnum fieldType) { + if (Objects.equals("[]", json)) { + switch (fieldType) { + case upload: + case image: + case customComponent: + case taskOrder: + case rectifyOrder: + case changeSignatureOrder: + case contacts: + // 对于这些类型,返回空列表而不是空字符串 + return Collections.emptyList(); + case decimal: + HashMap map = new HashMap<>(); + map.put("value", 0); + map.put("unit", fieldParams.getOrDefault("unit", "")); + return map; + default: + return ""; + } + } + return null; + } +} diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/NextNodePreCheckAlterDTO.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/NextNodePreCheckAlterDTO.java index d921ac342..e0a2de5de 100644 --- a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/NextNodePreCheckAlterDTO.java +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/NextNodePreCheckAlterDTO.java @@ -11,6 +11,10 @@ import lombok.Data; @Data public class NextNodePreCheckAlterDTO { + private String processDefinitionKey; + + private String processDefinitionName; + private String processInstanceId; private String activityId; diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/dto/AlterDTO.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/dto/AlterDTO.java index e0408a44e..cc610a66d 100644 --- a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/dto/AlterDTO.java +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/dto/AlterDTO.java @@ -12,6 +12,11 @@ import java.util.Date; */ @Data public class AlterDTO { + + private String processDefinitionKey; + + private String processDefinitionName; + private String processInstanceId; private String activityId; diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/dto/ContactsPersonDTO.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/dto/ContactsPersonDTO.java index 2ff8b1e85..9aa8d5c92 100644 --- a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/dto/ContactsPersonDTO.java +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/dto/ContactsPersonDTO.java @@ -1,5 +1,6 @@ package cn.axzo.workflow.common.model.dto; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -15,6 +16,7 @@ import lombok.NoArgsConstructor; @AllArgsConstructor @NoArgsConstructor @Builder +@JsonIgnoreProperties(ignoreUnknown = true) public class ContactsPersonDTO { /** * xx:xx:xx diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/dto/TermNodeAddTimerJobDTO.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/dto/TermNodeAddTimerJobDTO.java index d075b7194..c5e955d78 100644 --- a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/dto/TermNodeAddTimerJobDTO.java +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/dto/TermNodeAddTimerJobDTO.java @@ -22,5 +22,6 @@ import java.io.Serializable; public class TermNodeAddTimerJobDTO implements Serializable { private String processInstanceId; private String activityId; - private String timeCycle; + private Integer delayTime; + private String timeUnit; } diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/model/doc/DocQueryDTO.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/model/doc/DocQueryDTO.java index a709c868a..ce9527569 100644 --- a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/model/doc/DocQueryDTO.java +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/model/doc/DocQueryDTO.java @@ -7,6 +7,8 @@ import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import java.util.List; + /** * 流程关联文档搜索入参模型 * @@ -22,6 +24,7 @@ public class DocQueryDTO { /** * 流程实例 ID + * 该参数与 processDefinitionKey 二选一, 如果有值,则优先使用实例 ID,仅查询实例下使用的文档 */ @ApiModelProperty(value = "流程实例 ID") private String processInstanceId; @@ -32,6 +35,13 @@ public class DocQueryDTO { @ApiModelProperty(value = "流程定义 KEY(业务 ID)") private String processDefinitionKey; + /** + * 流程定义 KEY 列表(业务 ID 列表) + * 当选择使用 processDefinitionKey/s 时,则查询模板对应默认的文档列表 + */ + @ApiModelProperty(value = "流程定义 KEY 列表(业务 ID 列表)") + private List processDefinitionKeys; + /** * 租户 ID,对应工作台 ID */ diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/category/CategorySearchDTO.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/category/CategorySearchDTO.java index 2e2738eae..a194ff747 100644 --- a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/category/CategorySearchDTO.java +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/category/CategorySearchDTO.java @@ -7,6 +7,8 @@ import io.swagger.annotations.ApiModelProperty; import lombok.Data; import lombok.EqualsAndHashCode; +import java.util.List; + /** * 自定义分类的查询入参模型 */ @@ -31,6 +33,11 @@ public class CategorySearchDTO extends BpmPageParam { */ @ApiModelProperty(value = "字典值", example = "new_business") private String value; + /** + * 字典类型列表, bpm_model_category + */ + @ApiModelProperty(value = "字典值列表", example = "[\"new_business\", \"another_business\"]") + private List values; /** * 字典状态, 0 停用, 1 启用 @@ -44,6 +51,12 @@ public class CategorySearchDTO extends BpmPageParam { @ApiModelProperty(value = "工作台类型值, 1企业工作台 2项目部工作台 3政务监管工作台 6OMS工作台") private String workspaceTypeCode; + /** + * 工作台类型值列表, 1企业工作台 2项目部工作台 3政务监管工作台 6OMS工作台 + */ + @ApiModelProperty(value = "工作台类型值列表, 1企业工作台 2项目部工作台 3政务监管工作台 6OMS工作台") + private List workspaceTypeCodes; + /** * 租户 ID */ @@ -55,6 +68,11 @@ public class CategorySearchDTO extends BpmPageParam { */ @ApiModelProperty(value = "业务类型") private BusinessTypeEnum businessType; + /** + * 业务类型列表 + */ + @ApiModelProperty(value = "业务类型列表") + private List businessTypes; @ApiModelProperty(value = "根据创建时间排序") private String orderCreateAt; diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/form/instance/FromDataSearchDTO.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/form/instance/FromDataSearchDTO.java new file mode 100644 index 000000000..6b56ebdaf --- /dev/null +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/form/instance/FromDataSearchDTO.java @@ -0,0 +1,32 @@ +package cn.axzo.workflow.common.model.request.form.instance; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotBlank; +import java.io.Serializable; + +/** + * 表单数据搜索入参模型 + * + * @author wangli + * @since 2025-07-29 14:33 + */ +@ApiModel("表单数据搜索入参模型") +@Data +public class FromDataSearchDTO implements Serializable { + + /** + * 流程实例 ID + */ + @ApiModelProperty(value = "流程实例ID") + @NotBlank(message = "流程实例 ID 不能为空") + private String processInstanceId; + + /** + * 任务 ID, 获取指定任务绑定的表单数据时使用,一般不传值,获取最新的表单数据即可 + */ + @ApiModelProperty(value = "任务 ID") + private String taskId; +} diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/response/form/instance/FormDataVO.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/response/form/instance/FormDataVO.java new file mode 100644 index 000000000..3c2f61e2d --- /dev/null +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/response/form/instance/FormDataVO.java @@ -0,0 +1,44 @@ +package cn.axzo.workflow.common.model.response.form.instance; + +import cn.axzo.workflow.common.enums.FormFieldTypeEnum; +import io.swagger.annotations.ApiModel; +import lombok.Data; + +import java.util.Map; +import java.util.Objects; + +/** + * 表单实例数据的响应模型 + * + * @author wangli + * @since 2025-08-04 10:54 + */ +@ApiModel("表单实例数据的响应模型") +@Data +public class FormDataVO { + private String fieldId; + + private Object fieldValue; + + private FormFieldTypeEnum fieldType; + + /** + * 数字表单组件的格式化值:数字+单位 + * + * @return + */ + public Object getFormatDecimalValue() { + switch (fieldType) { + case decimal: + Map decimalMap = (Map) fieldValue; + Object value = decimalMap.getOrDefault("value", ""); + if (Objects.isNull(value)) { + return ""; + } else { + return value + "" + decimalMap.getOrDefault("unit", ""); + } + default: + return fieldValue; + } + } +} diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/conf/SupportRefreshProperties.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/conf/SupportRefreshProperties.java index 3cd9f1903..cfac43c61 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/conf/SupportRefreshProperties.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/conf/SupportRefreshProperties.java @@ -19,7 +19,6 @@ import java.util.concurrent.TimeUnit; @Data @RefreshScope public class SupportRefreshProperties { - @Value("${workflow.apiLog.enable: false}") private Boolean apiLogEnable; @@ -92,4 +91,5 @@ public class SupportRefreshProperties { @Value("${workflow.imTemplateCode:}") private String imTemplateCode; + } diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomActivityTriggerCmd.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomActivityTriggerCmd.java index df374ad18..6447abfe7 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomActivityTriggerCmd.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomActivityTriggerCmd.java @@ -8,6 +8,7 @@ import org.flowable.common.engine.impl.interceptor.CommandContext; import org.flowable.engine.RuntimeService; import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl; import org.flowable.engine.impl.util.CommandContextUtil; +import org.flowable.job.service.TimerJobService; import org.flowable.task.service.impl.persistence.entity.TaskEntity; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -54,6 +55,9 @@ public class CustomActivityTriggerCmd extends AbstractCommand implements S } addComment(commandContext, task, COMMENT_TYPE_OPERATION_DESC, "已同意"); RuntimeService runtimeService = processEngineConfiguration.getRuntimeService(); + // 告警节点生产的定时任务需要删除,否则会因为外键约束导致触发功能会重试,并抛出触发节点不存在的问题 + TimerJobService timerJobService = CommandContextUtil.getTimerJobService(); + timerJobService.findTimerJobsByProcessInstanceId(task.getProcessInstanceId()).forEach(timerJobService::deleteTimerJob); runtimeService.trigger(dto.getTriggerId()); return null; } diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomAddTimerJobCmd.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomAddTimerJobCmd.java index 31cae5f7b..8e44f1ba2 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomAddTimerJobCmd.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomAddTimerJobCmd.java @@ -1,24 +1,19 @@ package cn.axzo.workflow.core.engine.cmd; import cn.axzo.workflow.common.model.dto.TermNodeAddTimerJobDTO; -import cn.axzo.workflow.core.converter.json.NotSupportConverter; import cn.axzo.workflow.core.engine.job.AsyncTermNodeAlterJobHandler; +import cn.hutool.core.date.DateUtil; import com.alibaba.fastjson.JSON; import lombok.extern.slf4j.Slf4j; -import org.flowable.bpmn.model.TimerEventDefinition; import org.flowable.common.engine.impl.interceptor.CommandContext; import org.flowable.engine.ManagementService; import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl; -import org.flowable.engine.impl.jobexecutor.TimerEventHandler; -import org.flowable.engine.impl.persistence.entity.ExecutionEntity; import org.flowable.engine.impl.util.CommandContextUtil; -import org.flowable.engine.impl.util.TimerUtil; -import org.flowable.engine.runtime.Execution; +import org.flowable.job.service.TimerJobService; import org.flowable.job.service.impl.persistence.entity.TimerJobEntity; -import org.springframework.util.CollectionUtils; import java.io.Serializable; -import java.util.List; +import java.util.Date; /** * 自定义添加定时任务的逻辑 @@ -41,37 +36,39 @@ public class CustomAddTimerJobCmd extends AbstractCommand implements Seria @Override public Void executeInternal(CommandContext commandContext) { - log.info("CustomAddTimerJobCmd start. instanceId: {}, activityId: {}, timeCycle: {}", dto.getProcessInstanceId(), dto.getActivityId(), dto.getTimeCycle()); + log.info("CustomAddTimerJobCmd start. instanceId: {}, activityId: {}, delayTime: {}, timeUnit: {}", dto.getProcessInstanceId(), dto.getActivityId(), dto.getDelayTime(), dto.getTimeUnit()); ProcessEngineConfigurationImpl processEngineConfiguration = CommandContextUtil.getProcessEngineConfiguration(commandContext); ManagementService managementService = processEngineConfiguration.getManagementService(); - String tableName = managementService.getTableName(Execution.class); - List list = processEngineConfiguration.getRuntimeService() - .createNativeExecutionQuery() - .sql("SELECT * FROM " + tableName + " WHERE PROC_INST_ID_ = #{instanceId} AND ACT_ID_ = #{activityId} AND IS_ACTIVE_ = 1 AND TASK_COUNT_ = 1") - .parameter("instanceId", dto.getProcessInstanceId()) - .parameter("activityId", dto.getActivityId()) - .list(); - if (CollectionUtils.isEmpty(list)) { - return null; + Date alterTime; + switch (dto.getTimeUnit()) { + case "M": + alterTime = DateUtil.offsetDay(new Date(), dto.getDelayTime()); + break; + case "H": + alterTime = DateUtil.offsetHour(new Date(), dto.getDelayTime()); + break; + default: + alterTime = DateUtil.offsetSecond(new Date(), dto.getDelayTime()); + break; } - if (list.get(list.size() - 1) instanceof ExecutionEntity) { - ExecutionEntity executionEntity = (ExecutionEntity) list.get(list.size() - 1); - TimerEventDefinition timerEventDefinition = new TimerEventDefinition(); - timerEventDefinition.setTimeCycle(dto.getTimeCycle()); - TimerJobEntity timerJob = TimerUtil.createTimerEntityForTimerEventDefinition(timerEventDefinition, - new NotSupportConverter.NotSupportFlowElement(), - false, executionEntity, AsyncTermNodeAlterJobHandler.TYPE, - TimerEventHandler.createConfiguration(executionEntity.getCurrentActivityId(), null, - timerEventDefinition.getCalendarName())); - if (timerJob != null) { - CommandContextUtil.getTimerJobService().scheduleTimerJob(timerJob); - } - } else { - log.warn("未找到 execution entity"); - } + managementService.executeCommand(context -> { + TimerJobService timerJobService = CommandContextUtil.getTimerJobService(); + TimerJobEntity timerJobEntity = timerJobService.createTimerJob(); + timerJobEntity.setJobType("timer"); + timerJobEntity.setJobHandlerType(AsyncTermNodeAlterJobHandler.TYPE); // 这里填写你自定义的 JobHandler 类型 + timerJobEntity.setProcessInstanceId(dto.getProcessInstanceId()); + timerJobEntity.setExecutionId(null); + timerJobEntity.setDuedate(alterTime); // 立即执行 + timerJobEntity.setRepeat(null); // 不重复 + timerJobEntity.setRetries(1); + timerJobEntity.setJobHandlerConfiguration(dto.getActivityId()); // 可选,传递参数 + timerJobService.scheduleTimerJob(timerJobEntity); + return null; + }); + return null; } } diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomGetFormDataValuesCmd.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomGetFormDataValuesCmd.java new file mode 100644 index 000000000..90ebe7595 --- /dev/null +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomGetFormDataValuesCmd.java @@ -0,0 +1,44 @@ +package cn.axzo.workflow.core.engine.cmd; + +import org.flowable.common.engine.impl.interceptor.Command; +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.form.api.FormEngineConfigurationApi; +import org.flowable.form.api.FormInstance; +import org.flowable.form.api.FormService; +import org.springframework.util.StringUtils; + +import java.util.Comparator; +import java.util.List; +import java.util.Objects; + +/** + * 算 cn.axzo.workflow.core.engine.cmd.CustomGetFormInstanceLatestValuesCmd 的另一种实现吧 + * + * @author wangli + * @since 2025-07-29 15:19 + */ +public class CustomGetFormDataValuesCmd implements Command { + private final String processInstanceId; + private final String taskId; + + public CustomGetFormDataValuesCmd(String processInstanceId, String taskId) { + this.processInstanceId = processInstanceId; + this.taskId = taskId; + } + + @Override + public byte[] execute(CommandContext commandContext) { + FormEngineConfigurationApi formEngineConfiguration = CommandContextUtil.getFormEngineConfiguration(commandContext); + + FormService formService = formEngineConfiguration.getFormService(); + List list = formService.createFormInstanceQuery().processInstanceId(processInstanceId).list(); + FormInstance formInstance = list.stream().max(Comparator.comparing(FormInstance::getSubmittedDate)).orElse(null); + if (StringUtils.hasText(taskId)) { + formInstance = list.stream().filter(i -> Objects.equals(i.getTaskId(), taskId)).findFirst() + .orElse(formInstance); + } + return formInstance.getFormValueBytes(); + } +} diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomGetFormInstanceLatestValuesCmd.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomGetFormInstanceLatestValuesCmd.java index 169dfb5e0..edeee1b90 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomGetFormInstanceLatestValuesCmd.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomGetFormInstanceLatestValuesCmd.java @@ -35,6 +35,7 @@ import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.PROCES * @since 2025-01-21 10:24 */ public class CustomGetFormInstanceLatestValuesCmd extends GetFormInstanceValuesCmd { + private static final long serialVersionUID = -1017881786777839488L; private String processInstanceId; private Boolean throwException; diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomGetModelDocsCmd.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomGetModelDocsCmd.java index 222f77e2d..7bcb71f65 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomGetModelDocsCmd.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomGetModelDocsCmd.java @@ -27,6 +27,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; +import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.stream.Collectors; @@ -52,6 +53,7 @@ public class CustomGetModelDocsCmd implements Command> { * eg. we1:1:202504021034000000001 or we1 */ private String processDefinitionId; + private List getProcessDefinitionIds; private String tenantId; private Boolean filterEnable = true; /** @@ -84,9 +86,10 @@ public class CustomGetModelDocsCmd implements Command> { this.extAxReModelService = extAxReModelService; } - public CustomGetModelDocsCmd(String processInstanceId, String processDefinitionId, String tenantId, ExtAxModelDocMapper extAxModelDocMapper, ExtAxReModelService extAxReModelService) { + public CustomGetModelDocsCmd(String processInstanceId, String processDefinitionId, List processDefinitionIds, String tenantId, ExtAxModelDocMapper extAxModelDocMapper, ExtAxReModelService extAxReModelService) { this.processInstanceId = processInstanceId; this.processDefinitionId = processDefinitionId; + this.getProcessDefinitionIds = processDefinitionIds; this.tenantId = tenantId; this.extAxModelDocMapper = extAxModelDocMapper; this.extAxReModelService = extAxReModelService; @@ -107,7 +110,8 @@ public class CustomGetModelDocsCmd implements Command> { check(); ProcessEngineConfigurationImpl processEngineConfiguration = CommandContextUtil.getProcessEngineConfiguration(commandContext); RepositoryService repositoryService = processEngineConfiguration.getRepositoryService(); - ProcessDefinition processDefinition; + + List processDefinitions = new ArrayList<>(); List enableDocIds = new ArrayList<>(); if (StringUtils.hasText(processInstanceId)) { HistoryService historyService = processEngineConfiguration.getHistoryService(); @@ -129,37 +133,71 @@ public class CustomGetModelDocsCmd implements Command> { } } } - processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionId(instance.getProcessDefinitionId()).singleResult(); + processDefinitions.add(repositoryService.createProcessDefinitionQuery().processDefinitionId(instance.getProcessDefinitionId()).singleResult()); } else { - List definitions = repositoryService.createProcessDefinitionQuery() - .processDefinitionKey(parseProcessDefinitionKey()) - .list(); + List definitions = new ArrayList<>(); + if (StringUtils.hasText(processDefinitionId)) { + definitions.addAll(repositoryService.createProcessDefinitionQuery() + .processDefinitionKey(parseProcessDefinitionKey(processDefinitionId)) + .list()); + } else { + List definitionIds = getProcessDefinitionIds.stream().filter(StringUtils::hasText).map(this::parseProcessDefinitionKey).collect(Collectors.toList()); + definitions.addAll(repositoryService.createNativeProcessDefinitionQuery() + .sql("SELECT * FROM ACT_RE_PROCDEF WHERE KEY_ IN " + definitionIds.stream().map(i -> "'" + i + "'").collect(Collectors.joining(",", "(", ")"))) + .list()); + } + + if (CollectionUtils.isEmpty(definitions)) { return Collections.emptyList(); } - Optional first = definitions.stream().filter(i -> i.getTenantId().equals(tenantId)) - .max(Comparator.comparing(ProcessDefinition::getVersion)); - if (first.isPresent()) { - processDefinition = first.get(); - CommandExecutor commandExecutor = processEngineConfiguration.getCommandExecutor(); - Model model = commandExecutor.execute(new CustomGetModelByDefinitionIdCmd(processDefinition.getId())); - BpmnModelExtVO modelStatus = extAxReModelService.getStatusByModelId(model.getId()); - if (Objects.equals(0, modelStatus.getStatus())) { - processDefinition = definitions.stream().filter(i -> i.getTenantId().equals(NO_TENANT_ID)).max(Comparator.comparing(ProcessDefinition::getVersion)).get(); + // 按 key 分组,每组取 version 最大的 ProcessDefinition + Map> maxVersionMap = definitions.stream() +// .filter(i -> i.getTenantId().equals(tenantId)) + .collect(Collectors.groupingBy( + ProcessDefinition::getKey, + Collectors.toList())); + + maxVersionMap.forEach((k, definitionList) -> { + Optional first = definitionList.stream() + .filter(i -> Objects.equals(i.getKey(), k)) + .filter(i -> i.getTenantId().equals(tenantId)) + .max(Comparator.comparing(ProcessDefinition::getVersion)); + if (first.isPresent()) { + ProcessDefinition processDefinition = first.get(); + CommandExecutor commandExecutor = processEngineConfiguration.getCommandExecutor(); + Model model = commandExecutor.execute(new CustomGetModelByDefinitionIdCmd(processDefinition.getId())); + BpmnModelExtVO modelStatus = extAxReModelService.getStatusByModelId(model.getId()); + if (Objects.equals(0, modelStatus.getStatus())) { + processDefinitions.add(definitions.stream() + .filter(i -> Objects.equals(i.getKey(), k)) + .filter(i -> i.getTenantId().equals(NO_TENANT_ID)) + .max(Comparator.comparing(ProcessDefinition::getVersion)).get()); + } else { + processDefinitions.add(processDefinition); + } + } else { + processDefinitions.add(first.orElseGet(() -> definitions.stream() + .filter(i -> Objects.equals(i.getKey(), k)) + .filter(i -> i.getTenantId().equals(NO_TENANT_ID)) + .max(Comparator.comparing(ProcessDefinition::getVersion)).get())); } - } else { - processDefinition = first.orElseGet(() -> definitions.stream().filter(i -> i.getTenantId().equals(NO_TENANT_ID)).max(Comparator.comparing(ProcessDefinition::getVersion)).get()); - } + }); } - ExtAxModelDoc query = new ExtAxModelDoc(); - query.setModelKey(processDefinition.getKey()); - if (Objects.equals(Boolean.TRUE, filterEnable)) { - query.setStatus(filterEnable); + List docs = new ArrayList<>(); + if (!CollectionUtils.isEmpty(processDefinitions)) { + for (ProcessDefinition processDefinition : processDefinitions) { + ExtAxModelDoc query = new ExtAxModelDoc(); + query.setModelKey(processDefinition.getKey()); + if (Objects.equals(Boolean.TRUE, filterEnable)) { + query.setStatus(filterEnable); + } + query.setTenantId(processDefinition.getTenantId()); + query.setTempFile(false); + docs.addAll(extAxModelDocMapper.selectList(buildQueryWrapper(query))); + } } - query.setTenantId(processDefinition.getTenantId()); - query.setTempFile(false); - List docs = extAxModelDocMapper.selectList(buildQueryWrapper(query)); if (filterSelect) { docs = docs.stream().filter(i -> enableDocIds.contains(i.getId())).collect(Collectors.toList()); @@ -167,7 +205,7 @@ public class CustomGetModelDocsCmd implements Command> { return BeanMapper.copyList(docs, DocBaseVO.class, (s, t) -> t.setFileType(FileTypeEnum.valueOfType(s.getFileType()))); } - private String parseProcessDefinitionKey() { + private String parseProcessDefinitionKey(String processDefinitionId) { if (StringUtils.hasText(processDefinitionId)) { return processDefinitionId.split(":")[0]; } @@ -175,7 +213,7 @@ public class CustomGetModelDocsCmd implements Command> { } private void check() { - if (!StringUtils.hasText(processInstanceId) && !StringUtils.hasText(processDefinitionId)) { + if (!StringUtils.hasText(processInstanceId) && (!StringUtils.hasText(processDefinitionId)) && CollectionUtils.isEmpty(getProcessDefinitionIds)) { throw new WorkflowEngineException(MODEL_FILE_QUERY_ERROR); } } diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomGetProcessInstanceVariablesToObjectCmd.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomGetProcessInstanceVariablesToObjectCmd.java index 6c119416e..15ee7e83c 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomGetProcessInstanceVariablesToObjectCmd.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomGetProcessInstanceVariablesToObjectCmd.java @@ -75,7 +75,7 @@ public class CustomGetProcessInstanceVariablesToObjectCmd extends AbstractComman private final String processInstanceId; private final SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss"); - private static final List SUPPORTED_FORM_TYPES = Lists.newArrayList("input", "date", "textarea", "image", "contacts", "amount"); + private static final List SUPPORTED_FORM_TYPES = Lists.newArrayList("input", "date", "textarea", "image", "contacts", "amount", "decimal"); public CustomGetProcessInstanceVariablesToObjectCmd(String processInstanceId) { this.processInstanceId = processInstanceId; @@ -210,6 +210,15 @@ public class CustomGetProcessInstanceVariablesToObjectCmd extends AbstractComman .type(convert(field.getType())) .build()); } + } else if (Objects.equals(field.getType(), "decimal")) { + if (StringUtils.hasText(fieldValue.toString())) { + variables.add(VariableObjectDTO.builder() + .key(field.getId()) + .desc(field.getName()) + .value(fieldValue + String.valueOf(field.getParam("unit"))) + .type(convert(field.getType())) + .build()); + } } else { variables.add(VariableObjectDTO.builder() .key(field.getId()) @@ -300,6 +309,7 @@ public class CustomGetProcessInstanceVariablesToObjectCmd extends AbstractComman case "textarea": case "amount": case "contacts": + case "decimal": return VariableObjectDTO.Type.text; case "image": return VariableObjectDTO.Type.img; diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/job/AsyncActivityTriggerJobHandler.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/job/AsyncActivityTriggerJobHandler.java index c59fe7897..7da1fd889 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/job/AsyncActivityTriggerJobHandler.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/job/AsyncActivityTriggerJobHandler.java @@ -18,7 +18,7 @@ import org.flowable.variable.api.delegate.VariableScope; * @since 2024-09-09 14:36 */ @Slf4j -public class AsyncActivityTriggerJobHandler extends AbstractJobHandler implements JobHandler { +public class AsyncActivityTriggerJobHandler extends AbstractExecuteWithLockJobHandler implements JobHandler { public static final String TYPE = "async-activity-trigger"; @Override @@ -27,7 +27,7 @@ public class AsyncActivityTriggerJobHandler extends AbstractJobHandler implement } @Override - public void execute(JobEntity job, String configuration, VariableScope variableScope, CommandContext commandContext) { + public void executeInternal(JobEntity job, String configuration, VariableScope variableScope, CommandContext commandContext) { log.info("AsyncActivityTriggerJobHandler executing..."); ProcessEngineConfigurationImpl processEngineConfiguration = CommandContextUtil.getProcessEngineConfiguration(commandContext); diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/job/AsyncCancelProcessInstanceJobHandler.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/job/AsyncCancelProcessInstanceJobHandler.java index fa171c9fa..06bf6288d 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/job/AsyncCancelProcessInstanceJobHandler.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/job/AsyncCancelProcessInstanceJobHandler.java @@ -14,7 +14,7 @@ import org.flowable.job.service.impl.persistence.entity.JobEntity; import org.flowable.variable.api.delegate.VariableScope; @Slf4j -public class AsyncCancelProcessInstanceJobHandler extends AbstractJobHandler implements JobHandler { +public class AsyncCancelProcessInstanceJobHandler extends AbstractExecuteWithLockJobHandler implements JobHandler { public static final String TYPE = "async-cancel-process"; @@ -30,11 +30,12 @@ public class AsyncCancelProcessInstanceJobHandler extends AbstractJobHandler imp } @Override - public void execute(JobEntity job, String configuration, VariableScope variableScope, CommandContext commandContext) { + public void executeInternal(JobEntity job, String configuration, VariableScope variableScope, CommandContext commandContext) { log.info("AsyncCancelProcessInstanceHandler executing...,jobInfo:{}", JSONUtil.toJsonStr(job)); log(job); ProcessEngineConfigurationImpl processEngineConfiguration = CommandContextUtil.getProcessEngineConfiguration(commandContext); BpmnProcessInstanceCancelDTO dto = JSONUtil.toBean(job.getCustomValues(), BpmnProcessInstanceCancelDTO.class); processEngineConfiguration.getCommandExecutor().execute(new CustomCancelProcessInstanceCmd((SuperBpmnProcessInstanceCancelDTO) dto, extAxHiTaskInstService)); } + } diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/job/AsyncTermNodeAlterJobHandler.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/job/AsyncTermNodeAlterJobHandler.java index 192da572c..5abef2fe2 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/job/AsyncTermNodeAlterJobHandler.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/job/AsyncTermNodeAlterJobHandler.java @@ -3,29 +3,35 @@ package cn.axzo.workflow.core.engine.job; import cn.axzo.basics.common.util.NumberUtil; import cn.axzo.workflow.common.model.dto.AlterDTO; import cn.axzo.workflow.common.model.dto.TermNodePausingDTO; +import cn.axzo.workflow.common.model.response.category.CategoryItemVO; import cn.axzo.workflow.core.common.utils.SpringContextUtils; import cn.axzo.workflow.core.conf.SupportRefreshProperties; -import cn.axzo.workflow.core.engine.tx.listener.DeleteTimerJobTransactionListener; import cn.axzo.workflow.core.listener.Alter; +import cn.axzo.workflow.core.service.CategoryService; +import cn.hutool.core.date.DateTime; import cn.hutool.core.date.DateUtil; import com.alibaba.fastjson.JSON; -import com.alibaba.fastjson.JSONObject; import lombok.extern.slf4j.Slf4j; -import org.flowable.common.engine.impl.cfg.TransactionState; -import org.flowable.common.engine.impl.context.Context; import org.flowable.common.engine.impl.interceptor.CommandContext; +import org.flowable.engine.ManagementService; 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.JobHandler; +import org.flowable.job.service.TimerJobService; import org.flowable.job.service.impl.persistence.entity.JobEntity; +import org.flowable.job.service.impl.persistence.entity.TimerJobEntity; import org.flowable.task.api.Task; import org.flowable.variable.api.delegate.VariableScope; import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; +import java.util.Date; import java.util.List; +import java.util.Objects; +import java.util.Optional; import static cn.axzo.workflow.common.constant.BpmnConstants.BIZ_NODE_ALTER; @@ -53,12 +59,16 @@ public class AsyncTermNodeAlterJobHandler extends AbstractJobHandler implements public void execute(JobEntity job, String configuration, VariableScope variableScope, CommandContext commandContext) { log.warn("AsyncTermNodeAlterJobHandler exec start..."); ProcessEngineConfigurationImpl processEngineConfiguration = CommandContextUtil.getProcessEngineConfiguration(commandContext); - JSONObject jsonObject = JSON.parseObject(job.getJobHandlerConfiguration()); - if (!jsonObject.containsKey("activityId")) { +// JSONObject jsonObject = JSON.parseObject(job.getJobHandlerConfiguration()); +// if (!jsonObject.containsKey("activityId")) { +// return; +// } + String activityId = job.getJobHandlerConfiguration(); + RuntimeService runtimeService = processEngineConfiguration.getRuntimeService(); + ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(job.getProcessInstanceId()).singleResult(); + if(Objects.isNull(processInstance)) { return; } - String activityId = jsonObject.getString("activityId"); - RuntimeService runtimeService = processEngineConfiguration.getRuntimeService(); TermNodePausingDTO dto = runtimeService.getVariable(job.getProcessInstanceId(), BIZ_NODE_ALTER + activityId, TermNodePausingDTO.class); TaskService taskService = processEngineConfiguration.getTaskService(); List tasks = taskService.createTaskQuery() @@ -71,53 +81,85 @@ public class AsyncTermNodeAlterJobHandler extends AbstractJobHandler implements tasks.forEach(e -> { sb.append("id:").append(e.getId()).append(", assignee: ").append(e.getAssignee()); }); - log.info("tasks size:{}", JSON.toJSONString(sb)); + log.info("tasks size:{}, info: {}", tasks.size(), JSON.toJSONString(sb)); if (CollectionUtils.isEmpty(tasks) || tasks.size() > 1 || hasAssignee(tasks.get(0).getAssignee())) { - deleteTimerJob(dto); return; } - if (DateUtil.compare(DateUtil.date(), DateUtil.offsetMinute(tasks.get(0).getCreateTime(), refreshProperties.getPauseDelay())) <= 0) { + + if (DateUtil.compare(DateUtil.date(), getDateTime(tasks.get(0).getCreateTime())) <= 0) { + ManagementService managementService = processEngineConfiguration.getManagementService(); + managementService.executeCommand(context -> { + TimerJobService timerJobService = CommandContextUtil.getTimerJobService(); + TimerJobEntity timerJobEntity = timerJobService.createTimerJob(); + timerJobEntity.setJobType("timer"); + timerJobEntity.setJobHandlerType(AsyncTermNodeAlterJobHandler.TYPE); // 这里填写你自定义的 JobHandler 类型 + timerJobEntity.setProcessInstanceId(dto.getProcessInstanceId()); + timerJobEntity.setExecutionId(null); + timerJobEntity.setDuedate(getDateTime(new Date())); // 立即执行 + timerJobEntity.setRepeat(null); // 不重复 + timerJobEntity.setRetries(1); + timerJobEntity.setJobHandlerConfiguration(dto.getActivityId()); // 可选,传递参数 + timerJobService.scheduleTimerJob(timerJobEntity); + return null; + }); return; } // 不允许重复告警 if (!refreshProperties.getRepeatAlter() && dto.getRetries() > 0) { - deleteTimerJob(dto); + return; + } + // 超过告警次数 + if (refreshProperties.getAlterRetries() != 0 && dto.getRetries() >= refreshProperties.getAlterRetries()) { return; } + CategoryService bean = SpringContextUtils.getBean(CategoryService.class); + Optional bpmModelCategory = bean.get("bpm_model_category", processInstance.getProcessDefinitionKey()); + // 发送告警对象 + Alter alter = SpringContextUtils.getBean(Alter.class); + AlterDTO alterDTO = new AlterDTO(); + alterDTO.setProcessDefinitionKey(processInstance.getProcessDefinitionKey()); + alterDTO.setProcessDefinitionName(bpmModelCategory.orElse(new CategoryItemVO()).getLabel()); + alterDTO.setProcessInstanceId(dto.getProcessInstanceId()); + alterDTO.setActivityId(dto.getActivityId()); + alterDTO.setTaskId(tasks.get(0).getId()); + alterDTO.setStartTime(tasks.get(0).getCreateTime()); + alterDTO.setPrettyStartTime(DateUtil.formatDateTime(tasks.get(0).getCreateTime())); + if (Boolean.TRUE.equals(refreshProperties.getAlterSendDingTalk())) { + alter.invoke(alterDTO); - if (refreshProperties.getAlterRetries() == 0 || dto.getRetries() < refreshProperties.getAlterRetries()) { - // 发送告警对象 - Alter alter = SpringContextUtils.getBean(Alter.class); - AlterDTO alterDTO = new AlterDTO(); - alterDTO.setProcessInstanceId(dto.getProcessInstanceId()); - alterDTO.setActivityId(dto.getActivityId()); - alterDTO.setTaskId(tasks.get(0).getId()); - alterDTO.setStartTime(tasks.get(0).getCreateTime()); - alterDTO.setPrettyStartTime(DateUtil.formatDateTime(tasks.get(0).getCreateTime())); - if (Boolean.TRUE.equals(refreshProperties.getAlterSendDingTalk())) { - alter.invoke(alterDTO); + // 记录告警次数 + incRetries(job, dto, runtimeService, activityId); - // 记录告警次数 - incRetries(job, dto, runtimeService, activityId); - - if (refreshProperties.getAlterRetries() != 0 && dto.getRetries() >= refreshProperties.getAlterRetries()) { - deleteTimerJob(dto); - } - } } } + private DateTime getDateTime(Date date) { + DateTime dateTime; + switch (refreshProperties.getAlterIntervalUnit()) { + case MINUTES: + dateTime = DateUtil.offsetMinute(date, refreshProperties.getPauseDelay()); + break; + case HOURS: + dateTime = DateUtil.offsetHour(date, refreshProperties.getPauseDelay()); + break; + default: + dateTime = DateUtil.offsetSecond(date, refreshProperties.getPauseDelay()); + break; + } + return dateTime; + } + private void incRetries(JobEntity job, TermNodePausingDTO dto, RuntimeService runtimeService, String activityId) { dto.setRetries(dto.getRetries() + 1); runtimeService.setVariable(job.getProcessInstanceId(), BIZ_NODE_ALTER + activityId, dto); } - private void deleteTimerJob(TermNodePausingDTO dto) { - Context.getTransactionContext().addTransactionListener(TransactionState.COMMITTED, - new DeleteTimerJobTransactionListener(dto)); - } +// private void deleteTimerJob(TermNodePausingDTO dto) { +// Context.getTransactionContext().addTransactionListener(TransactionState.COMMITTED, +// new DeleteTimerJobTransactionListener(dto)); +// } private Boolean hasAssignee(String assignee) { if (!StringUtils.hasText(assignee)) { diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/job/NextActivityConfigCheckJobHandler.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/job/NextActivityConfigCheckJobHandler.java index 8c7fc199c..9ad5586c7 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/job/NextActivityConfigCheckJobHandler.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/job/NextActivityConfigCheckJobHandler.java @@ -3,9 +3,11 @@ package cn.axzo.workflow.core.engine.job; import cn.axzo.workflow.common.enums.ApproverEmptyHandleTypeEnum; import cn.axzo.workflow.common.model.NextNodePreCheckAlterDTO; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner; +import cn.axzo.workflow.common.model.response.category.CategoryItemVO; import cn.axzo.workflow.core.common.utils.SpringContextUtils; import cn.axzo.workflow.core.deletage.BpmnTaskAssigneeSelector; import cn.axzo.workflow.core.listener.Alter; +import cn.axzo.workflow.core.service.CategoryService; import cn.axzo.workflow.core.service.support.FlowNodeForecastService; import cn.hutool.json.JSONUtil; import lombok.extern.slf4j.Slf4j; @@ -16,10 +18,12 @@ import org.flowable.bpmn.model.ServiceTask; import org.flowable.bpmn.model.UserTask; import org.flowable.common.engine.api.query.QueryProperty; import org.flowable.common.engine.impl.interceptor.CommandContext; +import org.flowable.engine.RuntimeService; import org.flowable.engine.delegate.DelegateExecution; import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl; import org.flowable.engine.impl.util.CommandContextUtil; import org.flowable.engine.runtime.Execution; +import org.flowable.engine.runtime.ProcessInstance; import org.flowable.job.service.JobHandler; import org.flowable.job.service.impl.persistence.entity.JobEntity; import org.flowable.variable.api.delegate.VariableScope; @@ -28,6 +32,7 @@ import org.springframework.util.CollectionUtils; import java.util.ArrayList; import java.util.List; import java.util.Objects; +import java.util.Optional; import java.util.concurrent.atomic.AtomicReference; import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getApprovalMethod; @@ -56,6 +61,11 @@ public class NextActivityConfigCheckJobHandler extends AbstractJobHandler implem CommandContextUtil.getProcessEngineConfiguration(commandContext); FlowNodeForecastService forecastService = SpringContextUtils.getBean(FlowNodeForecastService.class); String currentActivityId = job.getJobHandlerConfiguration(); + RuntimeService runtimeService = processEngineConfiguration.getRuntimeService(); + ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(job.getProcessInstanceId()).singleResult(); + if (Objects.isNull(processInstance)) { + return; + } List flowElements = forecastService.performProcessForecasting(job.getProcessInstanceId(), null, currentActivityId, false); if (CollectionUtils.isEmpty(flowElements)) { return; @@ -65,9 +75,13 @@ public class NextActivityConfigCheckJobHandler extends AbstractJobHandler implem } catch (Exception e) { // 有任何异常,则通过钉钉告警 log.warn("NextActivityConfigCheckJobHandler msg: {}", e.getMessage(), e); + CategoryService bean = SpringContextUtils.getBean(CategoryService.class); + Optional bpmModelCategory = bean.get("bpm_model_category", processInstance.getProcessDefinitionKey()); Alter alter = SpringContextUtils.getBean(Alter.class); FlowElement flowElement = ListUtils.emptyIfNull(flowElements).stream().filter(i -> i instanceof UserTask || i instanceof ReceiveTask || i instanceof ServiceTask).findFirst().orElse(null); NextNodePreCheckAlterDTO alterDTO = new NextNodePreCheckAlterDTO(); + alterDTO.setProcessDefinitionKey(processInstance.getProcessDefinitionKey()); + alterDTO.setProcessDefinitionName(bpmModelCategory.orElse(new CategoryItemVO()).getLabel()); alterDTO.setProcessInstanceId(job.getProcessInstanceId()); alterDTO.setActivityId(Objects.nonNull(flowElement) ? flowElement.getId() : null); alterDTO.setErrorMsg(e.getMessage()); @@ -130,9 +144,9 @@ public class NextActivityConfigCheckJobHandler extends AbstractJobHandler implem /** * 计算节点的待审批人为空时, 执行模型配置中的审批人为空时的处理方式 * - * @param assigners 节点计算的待审批人集合, 可能为空 - * @param flowElement 当前节点 - * @param execution 当前执行实例 + * @param assigners 节点计算的待审批人集合, 可能为空 + * @param flowElement 当前节点 + * @param execution 当前执行实例 */ private void emptyAssigneeHandle(List assigners, FlowElement flowElement, DelegateExecution execution) { diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/listener/EngineAlarmClearEventListener.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/listener/EngineAlarmClearEventListener.java new file mode 100644 index 000000000..927f9dcbb --- /dev/null +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/listener/EngineAlarmClearEventListener.java @@ -0,0 +1,25 @@ +package cn.axzo.workflow.core.engine.listener; + +import lombok.extern.slf4j.Slf4j; +import org.flowable.engine.delegate.DelegateExecution; +import org.flowable.engine.delegate.ExecutionListener; +import org.springframework.cloud.context.config.annotation.RefreshScope; +import org.springframework.stereotype.Component; + +/** + * 部分有告警设置的,在节点正常执行后,将清除告警 + * + * @author wangli + * @since 2025-04-24 16:03 + */ +@Component +@RefreshScope +@Slf4j +@Deprecated +public class EngineAlarmClearEventListener implements ExecutionListener { + private static final long serialVersionUID = -4246836140144129539L; + + @Override + public void notify(DelegateExecution execution) { + } +} diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/listener/EngineNodeTimeoutAlterDelegate.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/listener/EngineNodeTimeoutAlterDelegate.java new file mode 100644 index 000000000..2ebf3ef0e --- /dev/null +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/listener/EngineNodeTimeoutAlterDelegate.java @@ -0,0 +1,25 @@ +package cn.axzo.workflow.core.engine.listener; + +import lombok.extern.slf4j.Slf4j; +import org.flowable.engine.delegate.DelegateExecution; +import org.flowable.engine.delegate.JavaDelegate; +import org.springframework.cloud.context.config.annotation.RefreshScope; +import org.springframework.stereotype.Component; + +/** + * 节点运行超时告警 + * + * @author wangli + * @since 2025-04-24 14:21 + */ +@Component +@RefreshScope +@Slf4j +@Deprecated +public class EngineNodeTimeoutAlterDelegate implements JavaDelegate { + + @Override + public void execute(DelegateExecution execution) { + } + +} diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/tx/listener/AddTimerJobTransactionListener.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/tx/listener/AddTimerJobTransactionListener.java index 92612305f..561c1fb69 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/tx/listener/AddTimerJobTransactionListener.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/tx/listener/AddTimerJobTransactionListener.java @@ -22,7 +22,7 @@ public class AddTimerJobTransactionListener implements TransactionListener { @Override public void execute(CommandContext commandContext) { - log.info("add timer job listener. instanceId: {}, activityId: {}, timeCycle: {}", dto.getProcessInstanceId(), dto.getActivityId(), dto.getTimeCycle()); + log.info("add timer job listener. instanceId: {}, activityId: {}, delayTime: {}, timeUnit: {}", dto.getProcessInstanceId(), dto.getActivityId(), dto.getDelayTime(), dto.getTimeUnit()); ProcessEngineConfigurationImpl processEngineConfiguration = CommandContextUtil.getProcessEngineConfiguration(commandContext); processEngineConfiguration.getCommandExecutor().execute(new CustomAddTimerJobCmd(dto)); diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/listener/impl/InternalBpmnActivityEventListener_lo_Listener.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/listener/impl/InternalBpmnActivityEventListener_lo_Listener.java index a72a4a268..cde40df9d 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/listener/impl/InternalBpmnActivityEventListener_lo_Listener.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/listener/impl/InternalBpmnActivityEventListener_lo_Listener.java @@ -7,7 +7,6 @@ import cn.axzo.workflow.core.common.context.ActivityOperationContext; import cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper; import cn.axzo.workflow.core.conf.SupportRefreshProperties; import cn.axzo.workflow.core.engine.tx.listener.AddTimerJobTransactionListener; -import cn.axzo.workflow.core.engine.tx.listener.DeleteTimerJobTransactionListener; import cn.axzo.workflow.core.listener.AbstractBpmnEventListener; import cn.axzo.workflow.core.listener.BpmnActivityEventListener; import lombok.AllArgsConstructor; @@ -91,7 +90,8 @@ public class InternalBpmnActivityEventListener_lo_Listener extends AbstractBpmnE TermNodeAddTimerJobDTO addTimerJobDTO = new TermNodeAddTimerJobDTO(); addTimerJobDTO.setProcessInstanceId(execution.getProcessInstanceId()); addTimerJobDTO.setActivityId(execution.getCurrentActivityId()); - addTimerJobDTO.setTimeCycle("R100/PT" + refreshProperties.getAlterInterval() + timeUnit); + addTimerJobDTO.setDelayTime(refreshProperties.getAlterInterval()); + addTimerJobDTO.setTimeUnit(timeUnit); Context.getTransactionContext().addTransactionListener(TransactionState.COMMITTED, new AddTimerJobTransactionListener(addTimerJobDTO)); @@ -104,27 +104,4 @@ public class InternalBpmnActivityEventListener_lo_Listener extends AbstractBpmnE }); } - /** - * 节点已取消 - * - * @param execution - */ - @Override - public void onEnd(DelegateExecution execution) { -// ProcessEngineConfigurationImpl processEngineConfiguration = CommandContextUtil.getProcessEngineConfiguration(); -// ManagementService managementService = processEngineConfiguration.getManagementService(); -// Job timerJob = managementService.createTimerJobQuery() -// .elementId(execution.getCurrentActivityId()) -// .processInstanceId(execution.getProcessInstanceId()) -// .singleResult(); -// if (Objects.nonNull(timerJob)) { -// CommandContextUtil.getTimerJobService().deleteTimerJob((TimerJobEntity) timerJob); -// } - TermNodePausingDTO dto = new TermNodePausingDTO(); - dto.setActivityId(execution.getCurrentActivityId()); - dto.setProcessInstanceId(execution.getProcessInstanceId()); - dto.setRetries(1); - Context.getTransactionContext().addTransactionListener(TransactionState.COMMITTED, - new DeleteTimerJobTransactionListener(dto)); - } } diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/FormCoreService.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/FormCoreService.java index 2729776e5..918d4d65e 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/FormCoreService.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/FormCoreService.java @@ -3,9 +3,12 @@ package cn.axzo.workflow.core.service; import cn.axzo.workflow.common.model.dto.BpmnFormRelationSearchDTO; import cn.axzo.workflow.common.model.request.form.definition.StartFormSearchDTO; import cn.axzo.workflow.common.model.request.form.instance.FormDetailDTO; +import cn.axzo.workflow.common.model.request.form.instance.FromDataSearchDTO; import cn.axzo.workflow.common.model.response.form.FormVO; import cn.axzo.workflow.common.model.response.form.definition.FormDefinitionVO; +import cn.axzo.workflow.common.model.response.form.instance.FormDataVO; import cn.axzo.workflow.common.model.response.form.instance.FormInstanceVO; +import com.alibaba.fastjson.JSONObject; import java.util.List; @@ -22,4 +25,6 @@ public interface FormCoreService { FormDefinitionVO getStartForm(StartFormSearchDTO dto); FormInstanceVO getFormInstance(FormDetailDTO dto); + + List getFormData(FromDataSearchDTO dto); } diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/CategoryServiceImpl.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/CategoryServiceImpl.java index 3de68514c..a9b68997e 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/CategoryServiceImpl.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/CategoryServiceImpl.java @@ -221,14 +221,17 @@ public class CategoryServiceImpl extends ServiceImpl .eq(StringUtils.isNotBlank(dto.getDictType()), ExtAxDict::getType, dto.getDictType()) .like(StringUtils.isNotBlank(dto.getLabel()), ExtAxDict::getLabel, dto.getLabel()) .eq(StringUtils.isNotBlank(dto.getValue()), ExtAxDict::getValue, dto.getValue()) + .in(!CollectionUtils.isEmpty(dto.getValues()), ExtAxDict::getValue, dto.getValues()) .eq(Objects.nonNull(dto.getStatus()), ExtAxDict::getStatus, dto.getStatus()) .eq(StringUtils.isNotBlank(dto.getWorkspaceTypeCode()), ExtAxDict::getWorkspaceTypeCode, dto.getWorkspaceTypeCode()) + .in(!CollectionUtils.isEmpty(dto.getWorkspaceTypeCodes()), ExtAxDict::getWorkspaceTypeCode, dto.getWorkspaceTypeCodes()) .eq(ExtAxDict::getTenantId, dto.getTenantId()) .eq(dto.getBusinessType() != null, ExtAxDict::getBusinessType, dto.getBusinessType()) + .in(!CollectionUtils.isEmpty(dto.getBusinessTypes()), ExtAxDict::getBusinessType, dto.getBusinessTypes()) .eq(ExtAxDict::getIsDelete, 0) .orderByDesc(Objects.equals(dto.getOrderCreateAt(), "desc"), ExtAxDict::getCreateAt); - ; + ; List extAxDicts = dictMapper.selectList(queryWrapper); return categoryConverter.toVos(extAxDicts); } diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/ExtAxModelDocServiceImpl.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/ExtAxModelDocServiceImpl.java index 750eb912f..d6abfab99 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/ExtAxModelDocServiceImpl.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/ExtAxModelDocServiceImpl.java @@ -78,7 +78,7 @@ public class ExtAxModelDocServiceImpl implements ExtAxModelDocService { public List docList(DocQueryDTO dto) { CommandExecutor commandExecutor = springProcessEngineConfiguration.getCommandExecutor(); return commandExecutor.execute(new CustomGetModelDocsCmd(dto.getProcessInstanceId(), - dto.getProcessDefinitionKey(), dto.getTenantId(), extAxModelDocMapper, extAxReModelService)); + dto.getProcessDefinitionKey(), dto.getProcessDefinitionKeys(), dto.getTenantId(), extAxModelDocMapper, extAxReModelService)); } @Override diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/FormCoreServiceImpl.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/FormCoreServiceImpl.java index bc7c8b9b1..00e3d3c3f 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/FormCoreServiceImpl.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/FormCoreServiceImpl.java @@ -1,13 +1,16 @@ package cn.axzo.workflow.core.service.impl; +import cn.axzo.workflow.common.enums.FormFieldTypeEnum; import cn.axzo.workflow.common.exception.WorkflowEngineException; import cn.axzo.workflow.common.model.dto.BpmnFormRelationSearchDTO; import cn.axzo.workflow.common.model.request.form.definition.StartFormSearchDTO; import cn.axzo.workflow.common.model.request.form.instance.FormDetailDTO; +import cn.axzo.workflow.common.model.request.form.instance.FromDataSearchDTO; import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessDefinitionVO; import cn.axzo.workflow.common.model.response.category.CategoryItemVO; import cn.axzo.workflow.common.model.response.form.FormVO; import cn.axzo.workflow.common.model.response.form.definition.FormDefinitionVO; +import cn.axzo.workflow.common.model.response.form.instance.FormDataVO; import cn.axzo.workflow.common.model.response.form.instance.FormInstanceVO; import cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper; import cn.axzo.workflow.core.common.utils.FormHelper; @@ -28,12 +31,17 @@ import org.flowable.engine.impl.cmd.GetBpmnModelCmd; import org.flowable.form.api.FormInfo; import org.flowable.form.api.FormInstanceInfo; import org.flowable.form.api.FormRepositoryService; +import org.flowable.form.model.FormContainer; import org.flowable.form.model.FormField; import org.flowable.form.model.SimpleFormModel; import org.flowable.spring.SpringProcessEngineConfiguration; import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; import javax.annotation.Resource; +import java.text.Normalizer; +import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -130,4 +138,41 @@ public class FormCoreServiceImpl implements FormCoreService { bpmnProcessTaskForEsService, dto.getAssigner(), dto.getProcessInstanceId(), dto.getTaskId(), dto.getShowOriginDefaultValue())); return formInstanceConverter.toVo(formInstanceInfo); } + + @Override + public List getFormData(FromDataSearchDTO dto) { + CommandExecutor commandExecutor = springProcessEngineConfiguration.getCommandExecutor(); + FormInstanceInfo formInstanceInfo = commandExecutor.execute(new GetFormInstanceAndPermissionCmd(bpmnFormRelationService, + bpmnProcessTaskForEsService, null, dto.getProcessInstanceId(), dto.getTaskId(), true)); + List fields = null; + if (Objects.isNull(formInstanceInfo) + || Objects.isNull(formInstanceInfo.getFormModel()) + || (formInstanceInfo.getFormModel() instanceof SimpleFormModel) && CollectionUtils.isEmpty(fields = ((SimpleFormModel) formInstanceInfo.getFormModel()).getFields())) { + return Collections.emptyList(); + } + + if (!CollectionUtils.isEmpty(fields)) { + List dataList = new ArrayList<>(); + fields.forEach(i -> recursiveConvert(i, dataList)); + return dataList; + } + return Collections.emptyList(); + } + + private void recursiveConvert(FormField field, List formDataList) { + if (Objects.isNull(field)) { + return; + } + if (field instanceof FormContainer) { + ((FormContainer) field).getFields().forEach(subField -> subField.forEach(i -> recursiveConvert(i, formDataList))); + } else { + FormDataVO formDataVO = new FormDataVO(); + formDataVO.setFieldId(field.getId()); + formDataVO.setFieldType(FormFieldTypeEnum.valueOfType(field.getType())); + // TODO 根据不同数据类型,进行数据转码 + formDataVO.setFieldValue(FormFieldTypeEnum.parseValue(field.getType(), field.getValue(), field.getParams())); + formDataList.add(formDataVO); + } + } + } diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/util/DingTalkUtils.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/util/DingTalkUtils.java index 2d096f46b..0b53baa5b 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/util/DingTalkUtils.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/util/DingTalkUtils.java @@ -145,6 +145,7 @@ public class DingTalkUtils { OapiRobotSendRequest.Markdown markdown = new OapiRobotSendRequest.Markdown(); markdown.setTitle("Notice 业务节点长时间停止告警, Env: " + profile); markdown.setText("#### [" + profile + "]业务节点长时间停止\n" + + "> 审批业务: " + alterDTO.getProcessDefinitionName() + "(" + alterDTO.getProcessDefinitionKey() + ")" + "\n\n" + "> 节点相关信息: " + JSONUtil.toJsonStr(alterDTO) + "\n\n" + "> ##### [点击查看审批日志](" + getWebUrl(profile) + "/#/workflow/examples?processInstanceId=" + processInstanceId + ") \n\n" + "> ##### 提示:如果以上地址提示未登录,请在对应环境 OMS 系统登录后并点击审批管理的功能后,再使用。或者复制实例 ID 到 OMS 中手动查询 \n\n" + @@ -174,7 +175,7 @@ public class DingTalkUtils { OapiRobotSendRequest.Markdown markdown = new OapiRobotSendRequest.Markdown(); markdown.setTitle("Notice 审批模板节点预检查告警, Env: " + profile); markdown.setText("#### [" + profile + "]审批模板节点预检查告警\n" + -// "> 相关信息: " + JSONUtil.toJsonStr(alterDTO) + "\n\n" + + "> 审批业务: " + alterDTO.getProcessDefinitionName() + "(" + alterDTO.getProcessDefinitionKey() + ")" + "\n\n" + "> 实例 ID:" + alterDTO.getProcessInstanceId() + "\n\n" + "> 检测节点 ID:" + alterDTO.getActivityId() + "\n\n" + "> ##### 错误信息:" + alterDTO.getErrorMsg() + "\n\n" + diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/TransferToAdminTaskAssigneeSelector.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/TransferToAdminTaskAssigneeSelector.java index 274d7ec2e..bdaba5815 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/TransferToAdminTaskAssigneeSelector.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/TransferToAdminTaskAssigneeSelector.java @@ -146,10 +146,13 @@ public class TransferToAdminTaskAssigneeSelector extends AbstractBpmnTaskAssigne req.setWorkspaceAdmin(true); } }); - + boolean flag = false; + if (CollectionUtils.isEmpty(req.getCooperateTypes())) { + flag = true; + } List flowTaskAssigners = parseApiResult(() -> flowSupportApi.listTaskAssignerAdminV2(req), - "审批节点: " + flowElement.getId() + ", 通过管理员查询审批人", + "审批节点: " + flowElement.getId() + ", 通过管理员查询审批人" + (flag ? "需要重新发布选择节点配置" : ""), "cn.axzo.karma.client.feign.FlowSupportApi#listTaskAssignerAdminV2", req); diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/TestController.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/TestController.java index 8f4a09a4f..e02158409 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/TestController.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/TestController.java @@ -2,12 +2,14 @@ package cn.axzo.workflow.server.controller.web; import cn.axzo.framework.domain.ServiceException; import cn.axzo.workflow.client.feign.bpmn.ProcessInstanceApi; +import cn.axzo.workflow.common.model.dto.VariableObjectDTO; import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceAbortDTO; import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceQueryDTO; import cn.axzo.workflow.common.model.request.form.definition.FormContentSearchDTO; import cn.axzo.workflow.common.model.request.form.instance.FormInstanceSearchDTO; import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstanceVO; import cn.axzo.workflow.common.model.response.bpmn.process.ProcessNodeDetailVO; +import cn.axzo.workflow.core.engine.cmd.CustomGetProcessInstanceVariablesToObjectCmd; import cn.axzo.workflow.core.repository.entity.ExtAxBpmnFormRelation; import cn.axzo.workflow.core.service.BpmnProcessInstanceService; import cn.axzo.workflow.core.service.ExtAxBpmnFormRelationService; @@ -18,8 +20,10 @@ import cn.axzo.workflow.server.common.util.ShellUtil; import cn.axzo.workflow.server.xxljob.EsIndexOperationJobHandler; import cn.axzo.workflow.server.xxljob.SpecifyProcessInstanceSyncEsJobHandler; import cn.azxo.framework.common.model.CommonResponse; +import com.alibaba.fastjson.JSON; import lombok.extern.slf4j.Slf4j; import org.flowable.bpmn.model.FlowElement; +import org.flowable.common.engine.impl.interceptor.CommandExecutor; import org.flowable.common.engine.impl.util.IoUtil; import org.flowable.engine.HistoryService; import org.flowable.engine.RepositoryService; @@ -368,5 +372,13 @@ public class TestController { specifyProcessInstanceSyncEsJobHandler.execute(processInstanceId); return CommonResponse.success(); } + + @GetMapping("/wps/variables") + public CommonResponse getWpsVariables(@RequestParam String processInstanceId) { + CommandExecutor commandExecutor = processEngineConfiguration.getCommandExecutor(); + List wpsVariables = + commandExecutor.execute(new CustomGetProcessInstanceVariablesToObjectCmd(processInstanceId)); + return CommonResponse.success(JSON.toJSONString(wpsVariables)); + } } diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessModelController.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessModelController.java index d1d6b13d6..7941e2574 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessModelController.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessModelController.java @@ -511,7 +511,7 @@ public class BpmnProcessModelController implements ProcessModelApi { @Operation(summary = "根据业务 ID 获取模型文档列表,自动适配公共模板和代运营") @PostMapping(value = "/doc/list") public CommonResponse> docList(@Validated @RequestBody DocQueryDTO dto) { - if (!StringUtils.hasText(dto.getProcessInstanceId()) && !StringUtils.hasText(dto.getProcessDefinitionKey())) { + if (!StringUtils.hasText(dto.getProcessInstanceId()) && (!StringUtils.hasText(dto.getProcessDefinitionKey()) && CollectionUtils.isEmpty(dto.getProcessDefinitionKeys()))) { throw new WorkflowEngineException(MODEL_FILE_QUERY_ERROR); } return success(modelDocService.docList(dto)); diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/form/FormAdminController.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/form/FormAdminController.java index 9460e19a4..35c7c3d9e 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/form/FormAdminController.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/form/FormAdminController.java @@ -5,8 +5,10 @@ import cn.axzo.workflow.common.model.dto.BpmnFormRelationSearchDTO; import cn.axzo.workflow.common.model.request.form.definition.StartFormSearchDTO; import cn.axzo.workflow.common.model.request.form.instance.FormDetailDTO; import cn.axzo.workflow.common.model.request.form.instance.FormSearchDTO; +import cn.axzo.workflow.common.model.request.form.instance.FromDataSearchDTO; import cn.axzo.workflow.common.model.response.form.FormVO; import cn.axzo.workflow.common.model.response.form.definition.FormDefinitionVO; +import cn.axzo.workflow.common.model.response.form.instance.FormDataVO; import cn.axzo.workflow.common.model.response.form.instance.FormInstanceVO; import cn.axzo.workflow.core.service.FormCoreService; import cn.axzo.workflow.server.common.annotation.ErrorReporter; @@ -60,4 +62,10 @@ public class FormAdminController implements FormAdminApi { public CommonResponse getFormInstance(@Validated @RequestBody FormDetailDTO dto) { return success(formCoreService.getFormInstance(dto)); } + + @Operation(summary = "获取指定表单审批的实例数据") + @PostMapping("/instance/form/data") + public CommonResponse> getFormData(@Validated @RequestBody FromDataSearchDTO dto) { + return success(formCoreService.getFormData(dto)); + } }