${spring-ai.groupId}
spring-ai-tika-document-reader
diff --git a/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/config/YudaoAiAutoConfiguration.java b/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/config/YudaoAiAutoConfiguration.java
index 79a1f345b4..0d2620b0cb 100644
--- a/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/config/YudaoAiAutoConfiguration.java
+++ b/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/config/YudaoAiAutoConfiguration.java
@@ -2,8 +2,6 @@ package cn.iocoder.yudao.framework.ai.config;
import cn.iocoder.yudao.framework.ai.core.factory.AiModelFactory;
import cn.iocoder.yudao.framework.ai.core.factory.AiModelFactoryImpl;
-import cn.iocoder.yudao.framework.ai.core.factory.AiVectorStoreFactory;
-import cn.iocoder.yudao.framework.ai.core.factory.AiVectorStoreFactoryImpl;
import cn.iocoder.yudao.framework.ai.core.model.deepseek.DeepSeekChatModel;
import cn.iocoder.yudao.framework.ai.core.model.deepseek.DeepSeekChatOptions;
import cn.iocoder.yudao.framework.ai.core.model.midjourney.api.MidjourneyApi;
@@ -38,11 +36,6 @@ public class YudaoAiAutoConfiguration {
return new AiModelFactoryImpl();
}
- @Bean
- public AiVectorStoreFactory aiVectorFactory() {
- return new AiVectorStoreFactoryImpl();
- }
-
// ========== 各种 AI Client 创建 ==========
@@ -89,7 +82,7 @@ public class YudaoAiAutoConfiguration {
// TODO @xin 免费版本
// @Bean
// @Lazy // TODO 芋艿:临时注释,避免无法启动」
-// public EmbeddingModel transformersEmbeddingClient() {
+// public TransformersEmbeddingModel transformersEmbeddingClient() {
// return new TransformersEmbeddingModel(MetadataMode.EMBED);
// }
@@ -98,23 +91,24 @@ public class YudaoAiAutoConfiguration {
*/
// @Bean
// @Lazy // TODO 芋艿:临时注释,避免无法启动
-// public RedisVectorStore vectorStore(TongYiTextEmbeddingModel tongYiTextEmbeddingModel, RedisVectorStoreProperties properties,
+// public RedisVectorStore vectorStore(TransformersEmbeddingModel embeddingModel, RedisVectorStoreProperties properties,
// RedisProperties redisProperties) {
// var config = RedisVectorStore.RedisVectorStoreConfig.builder()
// .withIndexName(properties.getIndex())
// .withPrefix(properties.getPrefix())
+// .withMetadataFields(new RedisVectorStore.MetadataField("knowledgeId", Schema.FieldType.NUMERIC))
// .build();
//
-// RedisVectorStore redisVectorStore = new RedisVectorStore(config, tongYiTextEmbeddingModel,
+// RedisVectorStore redisVectorStore = new RedisVectorStore(config, embeddingModel,
// new JedisPooled(redisProperties.getHost(), redisProperties.getPort()),
// properties.isInitializeSchema());
// redisVectorStore.afterPropertiesSet();
// return redisVectorStore;
// }
-
@Bean
@Lazy // TODO 芋艿:临时注释,避免无法启动
public TokenTextSplitter tokenTextSplitter() {
+ //TODO @xin 配置提取
return new TokenTextSplitter(500, 100, 5, 10000, true);
}
diff --git a/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/factory/AiModelFactory.java b/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/factory/AiModelFactory.java
index 7e84653759..243c4ae4bc 100644
--- a/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/factory/AiModelFactory.java
+++ b/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/factory/AiModelFactory.java
@@ -6,6 +6,7 @@ import cn.iocoder.yudao.framework.ai.core.model.suno.api.SunoApi;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.ai.image.ImageModel;
+import org.springframework.ai.vectorstore.VectorStore;
/**
* AI Model 模型工厂的接口类
@@ -92,4 +93,17 @@ public interface AiModelFactory {
*/
EmbeddingModel getOrCreateEmbeddingModel(AiPlatformEnum platform, String apiKey, String url);
+ /**
+ * 基于指定配置,获得 VectorStore 对象
+ *
+ * 如果不存在,则进行创建
+ *
+ * @param embeddingModel 嵌入模型
+ * @param platform 平台
+ * @param apiKey API KEY
+ * @param url API URL
+ * @return VectorStore 对象
+ */
+ VectorStore getOrCreateVectorStore(EmbeddingModel embeddingModel, AiPlatformEnum platform, String apiKey, String url);
+
}
diff --git a/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/factory/AiModelFactoryImpl.java b/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/factory/AiModelFactoryImpl.java
index aa46c45f22..7acd247691 100644
--- a/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/factory/AiModelFactoryImpl.java
+++ b/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/factory/AiModelFactoryImpl.java
@@ -13,6 +13,7 @@ import cn.iocoder.yudao.framework.ai.core.model.deepseek.DeepSeekChatModel;
import cn.iocoder.yudao.framework.ai.core.model.midjourney.api.MidjourneyApi;
import cn.iocoder.yudao.framework.ai.core.model.suno.api.SunoApi;
import cn.iocoder.yudao.framework.ai.core.model.xinghuo.XingHuoChatModel;
+import cn.iocoder.yudao.framework.common.util.spring.SpringUtils;
import com.alibaba.cloud.ai.tongyi.TongYiAutoConfiguration;
import com.alibaba.cloud.ai.tongyi.TongYiConnectionProperties;
import com.alibaba.cloud.ai.tongyi.chat.TongYiChatModel;
@@ -54,13 +55,18 @@ import org.springframework.ai.qianfan.api.QianFanApi;
import org.springframework.ai.qianfan.api.QianFanImageApi;
import org.springframework.ai.stabilityai.StabilityAiImageModel;
import org.springframework.ai.stabilityai.api.StabilityAiApi;
+import org.springframework.ai.vectorstore.RedisVectorStore;
+import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.ai.zhipuai.ZhiPuAiChatModel;
import org.springframework.ai.zhipuai.ZhiPuAiImageModel;
import org.springframework.ai.zhipuai.api.ZhiPuAiApi;
import org.springframework.ai.zhipuai.api.ZhiPuAiImageApi;
+import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
import org.springframework.retry.support.RetryTemplate;
import org.springframework.web.client.ResponseErrorHandler;
import org.springframework.web.client.RestClient;
+import redis.clients.jedis.JedisPooled;
+import redis.clients.jedis.search.Schema;
import java.util.List;
@@ -191,6 +197,25 @@ public class AiModelFactoryImpl implements AiModelFactory {
});
}
+ @Override
+ public VectorStore getOrCreateVectorStore(EmbeddingModel embeddingModel, AiPlatformEnum platform, String apiKey, String url) {
+ String cacheKey = buildClientCacheKey(VectorStore.class, platform, apiKey, url);
+ return Singleton.get(cacheKey, (Func0) () -> {
+ String prefix = StrUtil.format("{}#{}:", platform.getPlatform(), apiKey);
+ var config = RedisVectorStore.RedisVectorStoreConfig.builder()
+ .withIndexName(cacheKey)
+ .withPrefix(prefix)
+ .withMetadataFields(new RedisVectorStore.MetadataField("knowledgeId", Schema.FieldType.NUMERIC))
+ .build();
+ RedisProperties redisProperties = SpringUtils.getBean(RedisProperties.class);
+ RedisVectorStore redisVectorStore = new RedisVectorStore(config, embeddingModel,
+ new JedisPooled(redisProperties.getHost(), redisProperties.getPort()),
+ true);
+ redisVectorStore.afterPropertiesSet();
+ return redisVectorStore;
+ });
+ }
+
private static String buildClientCacheKey(Class> clazz, Object... params) {
if (ArrayUtil.isEmpty(params)) {
return clazz.getName();
diff --git a/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/factory/AiVectorStoreFactory.java b/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/factory/AiVectorStoreFactory.java
deleted file mode 100644
index dad58a2c00..0000000000
--- a/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/factory/AiVectorStoreFactory.java
+++ /dev/null
@@ -1,28 +0,0 @@
-package cn.iocoder.yudao.framework.ai.core.factory;
-
-import cn.iocoder.yudao.framework.ai.core.enums.AiPlatformEnum;
-import org.springframework.ai.embedding.EmbeddingModel;
-import org.springframework.ai.vectorstore.VectorStore;
-
-// TODO @xin:也放到 AiModelFactory 里面好了,后续改成 AiFactory
-/**
- * AI Vector 模型工厂的接口类
- *
- * @author xiaoxin
- */
-public interface AiVectorStoreFactory {
-
- /**
- * 基于指定配置,获得 VectorStore 对象
- *
- * 如果不存在,则进行创建
- *
- * @param embeddingModel 嵌入模型
- * @param platform 平台
- * @param apiKey API KEY
- * @param url API URL
- * @return VectorStore 对象
- */
- VectorStore getOrCreateVectorStore(EmbeddingModel embeddingModel, AiPlatformEnum platform, String apiKey, String url);
-
-}
diff --git a/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/factory/AiVectorStoreFactoryImpl.java b/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/factory/AiVectorStoreFactoryImpl.java
deleted file mode 100644
index ec04c5e888..0000000000
--- a/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/factory/AiVectorStoreFactoryImpl.java
+++ /dev/null
@@ -1,52 +0,0 @@
-package cn.iocoder.yudao.framework.ai.core.factory;
-
-import cn.hutool.core.lang.Singleton;
-import cn.hutool.core.lang.func.Func0;
-import cn.hutool.core.util.ArrayUtil;
-import cn.hutool.core.util.StrUtil;
-import cn.iocoder.yudao.framework.ai.core.enums.AiPlatformEnum;
-import cn.iocoder.yudao.framework.common.util.spring.SpringUtils;
-import org.springframework.ai.embedding.EmbeddingModel;
-import org.springframework.ai.vectorstore.RedisVectorStore;
-import org.springframework.ai.vectorstore.VectorStore;
-import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
-import redis.clients.jedis.JedisPooled;
-
-/**
- * AI Vector 模型工厂的实现类
- * 使用 redisVectorStore 实现 VectorStore
- *
- * @author xiaoxin
- */
-public class AiVectorStoreFactoryImpl implements AiVectorStoreFactory {
-
- @Override
- public VectorStore getOrCreateVectorStore(EmbeddingModel embeddingModel, AiPlatformEnum platform, String apiKey, String url) {
- String cacheKey = buildClientCacheKey(VectorStore.class, platform, apiKey, url);
- return Singleton.get(cacheKey, (Func0) () -> {
- // TODO 芋艿 @xin 这两个配置取哪好呢
- // TODO 不同模型的向量维度可能会不一样,目前看貌似是以 index 来做区分的,维度不一样存不到一个 index 上
- // TODO 回复:好的哈
- String index = "default-index";
- String prefix = "default:";
- var config = RedisVectorStore.RedisVectorStoreConfig.builder()
- .withIndexName(index)
- .withPrefix(prefix)
- .build();
- RedisProperties redisProperties = SpringUtils.getBean(RedisProperties.class);
- RedisVectorStore redisVectorStore = new RedisVectorStore(config, embeddingModel,
- new JedisPooled(redisProperties.getHost(), redisProperties.getPort()),
- true);
- redisVectorStore.afterPropertiesSet();
- return redisVectorStore;
- });
- }
-
- private static String buildClientCacheKey(Class> clazz, Object... params) {
- if (ArrayUtil.isEmpty(params)) {
- return clazz.getName();
- }
- return StrUtil.format("{}#{}", clazz.getName(), ArrayUtil.join(params, "_"));
- }
-
-}
diff --git a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/ErrorCodeConstants.java b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/ErrorCodeConstants.java
index ec167719cc..6e32decc04 100644
--- a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/ErrorCodeConstants.java
+++ b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/ErrorCodeConstants.java
@@ -23,6 +23,7 @@ public interface ErrorCodeConstants {
"原因:用户任务({})未配置审批人,请点击【流程设计】按钮,选择该它的【任务(审批人)】进行配置");
ErrorCode MODEL_DEPLOY_FAIL_BPMN_START_EVENT_NOT_EXISTS = new ErrorCode(1_009_002_005, "部署流程失败,原因:BPMN 流程图中,没有开始事件");
ErrorCode MODEL_DEPLOY_FAIL_BPMN_USER_TASK_NAME_NOT_EXISTS = new ErrorCode(1_009_002_006, "部署流程失败,原因:BPMN 流程图中,用户任务({})的名字不存在");
+ ErrorCode MODEL_UPDATE_FAIL_NOT_MANAGER = new ErrorCode(1_009_002_007, "操作流程失败,原因:你不是该流程的管理员");
// ========== 流程定义 1-009-003-000 ==========
ErrorCode PROCESS_DEFINITION_KEY_NOT_MATCH = new ErrorCode(1_009_003_000, "流程定义的标识期望是({}),当前是({}),请修改 BPMN 流程图");
@@ -36,6 +37,7 @@ public interface ErrorCodeConstants {
ErrorCode PROCESS_INSTANCE_CANCEL_FAIL_NOT_SELF = new ErrorCode(1_009_004_002, "流程取消失败,该流程不是你发起的");
ErrorCode PROCESS_INSTANCE_START_USER_SELECT_ASSIGNEES_NOT_CONFIG = new ErrorCode(1_009_004_003, "审批任务({})的审批人未配置");
ErrorCode PROCESS_INSTANCE_START_USER_SELECT_ASSIGNEES_NOT_EXISTS = new ErrorCode(1_009_004_004, "审批任务({})的审批人({})不存在");
+ ErrorCode PROCESS_INSTANCE_START_USER_CAN_START = new ErrorCode(1_009_004_005, "发起流程失败,你没有权限发起该流程");
// ========== 流程任务 1-009-005-000 ==========
ErrorCode TASK_OPERATE_FAIL_ASSIGN_NOT_SELF = new ErrorCode(1_009_005_001, "操作失败,原因:该任务的审批人不是你");
diff --git a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmBoundaryEventType.java b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmBoundaryEventType.java
new file mode 100644
index 0000000000..537e03e03c
--- /dev/null
+++ b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmBoundaryEventType.java
@@ -0,0 +1,25 @@
+package cn.iocoder.yudao.module.bpm.enums.definition;
+
+import cn.hutool.core.util.ArrayUtil;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * BPM 边界事件 (boundary event) 自定义类型枚举
+ *
+ * @author jason
+ */
+@Getter
+@AllArgsConstructor
+public enum BpmBoundaryEventType {
+
+ USER_TASK_TIMEOUT(1,"用户任务超时");
+
+ private final Integer type;
+ private final String name;
+
+ public static BpmBoundaryEventType typeOf(Integer type) {
+ return ArrayUtil.firstMatch(eventType -> eventType.getType().equals(type), values());
+ }
+
+}
diff --git a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmFieldPermissionEnum.java b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmFieldPermissionEnum.java
new file mode 100644
index 0000000000..5a9b4b26af
--- /dev/null
+++ b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmFieldPermissionEnum.java
@@ -0,0 +1,33 @@
+package cn.iocoder.yudao.module.bpm.enums.definition;
+
+import cn.hutool.core.util.ArrayUtil;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * BPM 表单权限的枚举
+ *
+ * @author jason
+ */
+@Getter
+@AllArgsConstructor
+public enum BpmFieldPermissionEnum {
+
+ READ(1, "只读"),
+ WRITE(2, "可编辑"),
+ NONE(3, "隐藏");
+
+ /**
+ * 权限
+ */
+ private final Integer permission;
+ /**
+ * 名字
+ */
+ private final String name;
+
+ public static BpmFieldPermissionEnum valueOf(Integer permission) {
+ return ArrayUtil.firstMatch(item -> item.getPermission().equals(permission), values());
+ }
+
+}
diff --git a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmModelTypeEnum.java b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmModelTypeEnum.java
new file mode 100644
index 0000000000..9863a44e87
--- /dev/null
+++ b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmModelTypeEnum.java
@@ -0,0 +1,31 @@
+package cn.iocoder.yudao.module.bpm.enums.definition;
+
+import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+import java.util.Arrays;
+
+/**
+ * BPM 模型的类型的枚举
+ *
+ * @author 芋道源码
+ */
+@Getter
+@AllArgsConstructor
+public enum BpmModelTypeEnum implements IntArrayValuable {
+
+ BPMN(10, "BPMN 设计器"), // https://bpmn.io/toolkit/bpmn-js/
+ SIMPLE(20, "SIMPLE 设计器"); // 参考钉钉、飞书工作流的设计器
+
+ public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(BpmModelTypeEnum::getType).toArray();
+
+ private final Integer type;
+ private final String name;
+
+ @Override
+ public int[] array() {
+ return ARRAYS;
+ }
+
+}
\ No newline at end of file
diff --git a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmSimpleModeConditionType.java b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmSimpleModeConditionType.java
new file mode 100644
index 0000000000..234ec7e47b
--- /dev/null
+++ b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmSimpleModeConditionType.java
@@ -0,0 +1,36 @@
+package cn.iocoder.yudao.module.bpm.enums.definition;
+
+import cn.hutool.core.util.ArrayUtil;
+import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+import java.util.Arrays;
+
+/**
+ * 仿钉钉的流程器设计器条件节点的条件类型
+ *
+ * @author jason
+ */
+@Getter
+@AllArgsConstructor
+public enum BpmSimpleModeConditionType implements IntArrayValuable {
+
+ EXPRESSION(1, "条件表达式"),
+ RULE(2, "条件规则");
+
+ public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(BpmSimpleModeConditionType::getType).toArray();
+
+ private final Integer type;
+
+ private final String name;
+
+ public static BpmSimpleModeConditionType valueOf(Integer type) {
+ return ArrayUtil.firstMatch(nodeType -> nodeType.getType().equals(type), values());
+ }
+
+ @Override
+ public int[] array() {
+ return ARRAYS;
+ }
+}
diff --git a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmSimpleModelNodeType.java b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmSimpleModelNodeType.java
new file mode 100644
index 0000000000..36ad0e5ee1
--- /dev/null
+++ b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmSimpleModelNodeType.java
@@ -0,0 +1,76 @@
+package cn.iocoder.yudao.module.bpm.enums.definition;
+
+import cn.hutool.core.util.ArrayUtil;
+import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+import java.util.Arrays;
+import java.util.Objects;
+
+/**
+ * 仿钉钉的流程器设计器的模型节点类型
+ *
+ * @author jason
+ */
+@Getter
+@AllArgsConstructor
+public enum BpmSimpleModelNodeType implements IntArrayValuable {
+
+ // 0 ~ 1 开始和结束
+ START_NODE(0, "startEvent", "开始节点"),
+ END_NODE(1, "endEvent", "结束节点"),
+
+ // 10 ~ 49 各种节点
+ START_USER_NODE(10, "userTask", "发起人节点"), // 发起人节点。前端的开始节点,Id 固定
+ APPROVE_NODE(11, "userTask", "审批人节点"),
+ COPY_NODE(12, "serviceTask", "抄送人节点"),
+
+ // 50 ~ 条件分支
+ CONDITION_NODE(50, "sequenceFlow", "条件节点"), // 用于构建流转条件的表达式
+ CONDITION_BRANCH_NODE(51, " “parallelGateway”", "条件分支节点"), // TODO @jason:是不是改成叫 条件分支?
+ PARALLEL_BRANCH_NODE(52, "exclusiveGateway", "并行分支节点"), // TODO @jason:是不是一个 并行分支 ?就可以啦? 后面是否去掉并行网关。只用包容网关
+ INCLUSIVE_BRANCH_NODE(53, "inclusiveGateway", "包容分支节点"),
+ // TODO @jason:建议整合 join,最终只有 条件分支、并行分支、包容分支,三种~
+ // TODO @芋艿。 感觉还是分开好理解一点,也好处理一点。前端结构中把聚合节点显示并传过来。
+ ;
+
+ public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(BpmSimpleModelNodeType::getType).toArray();
+
+ public static final String BPMN_USER_TASK_TYPE = "userTask";
+
+ private final Integer type;
+ private final String bpmnType;
+ private final String name;
+
+ /**
+ * 判断是否为分支节点
+ *
+ * @param type 节点类型
+ */
+ public static boolean isBranchNode(Integer type) {
+ return Objects.equals(CONDITION_BRANCH_NODE.getType(), type)
+ || Objects.equals(PARALLEL_BRANCH_NODE.getType(), type)
+ || Objects.equals(INCLUSIVE_BRANCH_NODE.getType(), type);
+ }
+
+ /**
+ * 判断是否需要记录的节点
+ *
+ * @param bpmnType bpmn节点类型
+ */
+ public static boolean isRecordNode(String bpmnType) {
+ return Objects.equals(APPROVE_NODE.getBpmnType(), bpmnType)
+ || Objects.equals(END_NODE.getBpmnType(), bpmnType);
+ }
+
+ public static BpmSimpleModelNodeType valueOf(Integer type) {
+ return ArrayUtil.firstMatch(nodeType -> nodeType.getType().equals(type), values());
+ }
+
+ @Override
+ public int[] array() {
+ return ARRAYS;
+ }
+
+}
diff --git a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmUserTaskApproveMethodEnum.java b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmUserTaskApproveMethodEnum.java
new file mode 100644
index 0000000000..9d4dd63af6
--- /dev/null
+++ b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmUserTaskApproveMethodEnum.java
@@ -0,0 +1,44 @@
+package cn.iocoder.yudao.module.bpm.enums.definition;
+
+import cn.hutool.core.util.ArrayUtil;
+import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+import java.util.Arrays;
+
+/**
+ * BPM 多人审批方式的枚举
+ *
+ * @author jason
+ */
+@Getter
+@AllArgsConstructor
+public enum BpmUserTaskApproveMethodEnum implements IntArrayValuable {
+
+ RANDOM(1, "随机挑选一人审批"),
+ RATIO(2, "多人会签(按通过比例)"), // 会签(按通过比例)
+ ANY(3, "多人或签(一人通过或拒绝)"), // 或签(通过只需一人,拒绝只需一人)
+ SEQUENTIAL(4, "依次审批"); // 依次审批
+
+ /**
+ * 审批方式
+ */
+ private final Integer method;
+
+ /**
+ * 名字
+ */
+ private final String name;
+
+ public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(BpmUserTaskApproveMethodEnum::getMethod).toArray();
+
+ public static BpmUserTaskApproveMethodEnum valueOf(Integer method) {
+ return ArrayUtil.firstMatch(item -> item.getMethod().equals(method), values());
+ }
+
+ @Override
+ public int[] array() {
+ return ARRAYS;
+ }
+}
diff --git a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmUserTaskApproveTypeEnum.java b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmUserTaskApproveTypeEnum.java
new file mode 100644
index 0000000000..fa6dba665a
--- /dev/null
+++ b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmUserTaskApproveTypeEnum.java
@@ -0,0 +1,31 @@
+package cn.iocoder.yudao.module.bpm.enums.definition;
+
+import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+import java.util.Arrays;
+
+/**
+ * 用户任务的审批类型枚举
+ *
+ * @author 芋道源码
+ */
+@Getter
+@AllArgsConstructor
+public enum BpmUserTaskApproveTypeEnum implements IntArrayValuable {
+
+ USER(1), // 人工审批
+ AUTO_APPROVE(2), // 自动通过
+ AUTO_REJECT(3); // 自动拒绝
+
+ public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(BpmUserTaskApproveTypeEnum::getType).toArray();
+
+ private final Integer type;
+
+ @Override
+ public int[] array() {
+ return ARRAYS;
+ }
+
+}
diff --git a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmUserTaskAssignEmptyHandlerTypeEnum.java b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmUserTaskAssignEmptyHandlerTypeEnum.java
new file mode 100644
index 0000000000..7a7242a494
--- /dev/null
+++ b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmUserTaskAssignEmptyHandlerTypeEnum.java
@@ -0,0 +1,33 @@
+package cn.iocoder.yudao.module.bpm.enums.definition;
+
+import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+import java.util.Arrays;
+
+/**
+ * BPM 用户任务的审批人为空时,处理类型枚举
+ *
+ * @author 芋道源码
+ */
+@RequiredArgsConstructor
+@Getter
+public enum BpmUserTaskAssignEmptyHandlerTypeEnum implements IntArrayValuable {
+
+ APPROVE(1), // 自动通过
+ REJECT(2), // 自动拒绝
+ ASSIGN_USER(3), // 指定人员审批
+ ASSIGN_ADMIN(4), // 转交给流程管理员
+ ;
+
+ public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(BpmUserTaskAssignEmptyHandlerTypeEnum::getType).toArray();
+
+ private final Integer type;
+
+ @Override
+ public int[] array() {
+ return ARRAYS;
+ }
+
+}
diff --git a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmUserTaskAssignStartUserHandlerTypeEnum.java b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmUserTaskAssignStartUserHandlerTypeEnum.java
new file mode 100644
index 0000000000..5012815027
--- /dev/null
+++ b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmUserTaskAssignStartUserHandlerTypeEnum.java
@@ -0,0 +1,31 @@
+package cn.iocoder.yudao.module.bpm.enums.definition;
+
+import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+import java.util.Arrays;
+
+/**
+ * BPM 用户任务的审批人与发起人相同时,处理类型枚举
+ *
+ * @author 芋道源码
+ */
+@RequiredArgsConstructor
+@Getter
+public enum BpmUserTaskAssignStartUserHandlerTypeEnum implements IntArrayValuable {
+
+ START_USER_AUDIT(1), // 由发起人对自己审批
+ SKIP(2), // 自动跳过【参考飞书】:1)如果当前节点还有其他审批人,则交由其他审批人进行审批;2)如果当前节点没有其他审批人,则该节点自动通过
+ TRANSFER_DEPT_LEADER(3); // 转交给部门负责人审批【参考飞书】:若部门负责人为空,则自动通过
+
+ public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(BpmUserTaskAssignStartUserHandlerTypeEnum::getType).toArray();
+
+ private final Integer type;
+
+ @Override
+ public int[] array() {
+ return ARRAYS;
+ }
+
+}
diff --git a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmUserTaskRejectHandlerType.java b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmUserTaskRejectHandlerType.java
new file mode 100644
index 0000000000..f2d48f7d9a
--- /dev/null
+++ b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmUserTaskRejectHandlerType.java
@@ -0,0 +1,35 @@
+package cn.iocoder.yudao.module.bpm.enums.definition;
+
+import cn.hutool.core.util.ArrayUtil;
+import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+import java.util.Arrays;
+
+/**
+ * BPM 用户任务拒绝处理类型枚举
+ *
+ * @author jason
+ */
+@Getter
+@AllArgsConstructor
+public enum BpmUserTaskRejectHandlerType implements IntArrayValuable {
+
+ FINISH_PROCESS_INSTANCE(1, "终止流程"),
+ RETURN_USER_TASK(2, "驳回到指定任务节点");
+
+ private final Integer type;
+ private final String name;
+
+ public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(BpmUserTaskRejectHandlerType::getType).toArray();
+
+ public static BpmUserTaskRejectHandlerType typeOf(Integer type) {
+ return ArrayUtil.firstMatch(item -> item.getType().equals(type), values());
+ }
+
+ @Override
+ public int[] array() {
+ return ARRAYS;
+ }
+}
diff --git a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmUserTaskTimeoutHandlerTypeEnum.java b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmUserTaskTimeoutHandlerTypeEnum.java
new file mode 100644
index 0000000000..0d56c9b379
--- /dev/null
+++ b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmUserTaskTimeoutHandlerTypeEnum.java
@@ -0,0 +1,32 @@
+package cn.iocoder.yudao.module.bpm.enums.definition;
+
+import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+import java.util.Arrays;
+
+/**
+ * 用户任务超时处理类型枚举
+ *
+ * @author jason
+ */
+@Getter
+@AllArgsConstructor
+public enum BpmUserTaskTimeoutHandlerTypeEnum implements IntArrayValuable {
+
+ REMINDER(1,"自动提醒"),
+ APPROVE(2, "自动同意"),
+ REJECT(3, "自动拒绝");
+
+ private final Integer type;
+ private final String name;
+
+ public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(BpmUserTaskTimeoutHandlerTypeEnum::getType).toArray();
+
+ @Override
+ public int[] array() {
+ return ARRAYS;
+ }
+
+}
diff --git a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/message/BpmMessageEnum.java b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/message/BpmMessageEnum.java
index 79001fccd3..abec70276e 100644
--- a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/message/BpmMessageEnum.java
+++ b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/message/BpmMessageEnum.java
@@ -14,7 +14,8 @@ public enum BpmMessageEnum {
PROCESS_INSTANCE_APPROVE("bpm_process_instance_approve"), // 流程任务被审批通过时,发送给申请人
PROCESS_INSTANCE_REJECT("bpm_process_instance_reject"), // 流程任务被审批不通过时,发送给申请人
- TASK_ASSIGNED("bpm_task_assigned"); // 任务被分配时,发送给审批人
+ TASK_ASSIGNED("bpm_task_assigned"), // 任务被分配时,发送给审批人
+ TASK_TIMEOUT("bpm_task_timeout"); // 任务审批超时时,发送给审批人
/**
* 短信模板的标识
diff --git a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmProcessInstanceStatusEnum.java b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmProcessInstanceStatusEnum.java
index 720d4f13e8..c635e92baa 100644
--- a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmProcessInstanceStatusEnum.java
+++ b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmProcessInstanceStatusEnum.java
@@ -1,6 +1,7 @@
package cn.iocoder.yudao.module.bpm.enums.task;
import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
+import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
import lombok.AllArgsConstructor;
import lombok.Getter;
@@ -15,6 +16,7 @@ import java.util.Arrays;
@AllArgsConstructor
public enum BpmProcessInstanceStatusEnum implements IntArrayValuable {
+ NOT_START(-1, "未开始"),
RUNNING(1, "审批中"),
APPROVE(2, "审批通过"),
REJECT(3, "审批不通过"),
@@ -36,4 +38,9 @@ public enum BpmProcessInstanceStatusEnum implements IntArrayValuable {
return ARRAYS;
}
+ public static boolean isProcessEndStatus(Integer status) {
+ return ObjectUtils.equalsAny(status,
+ APPROVE.getStatus(), REJECT.getStatus(), CANCEL.getStatus());
+ }
+
}
diff --git a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmDeleteReasonEnum.java b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmReasonEnum.java
similarity index 56%
rename from yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmDeleteReasonEnum.java
rename to yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmReasonEnum.java
index 802b9d8904..5ea8c41871 100644
--- a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmDeleteReasonEnum.java
+++ b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmReasonEnum.java
@@ -5,13 +5,13 @@ import lombok.AllArgsConstructor;
import lombok.Getter;
/**
- * 流程实例/任务的删除原因枚举
+ * 流程实例/任务的的处理原因枚举
*
* @author 芋道源码
*/
@Getter
@AllArgsConstructor
-public enum BpmDeleteReasonEnum {
+public enum BpmReasonEnum {
// ========== 流程实例的独有原因 ==========
@@ -22,6 +22,16 @@ public enum BpmDeleteReasonEnum {
// ========== 流程任务的独有原因 ==========
CANCEL_BY_SYSTEM("系统自动取消"), // 场景:非常多,比如说:1)多任务审批已经满足条件,无需审批该任务;2)流程实例被取消,无需审批该任务;等等
+ TIMEOUT_APPROVE("审批超时,系统自动通过"),
+ TIMEOUT_REJECT("审批超时,系统自动不通过"),
+ ASSIGN_START_USER_APPROVE("审批人与提交人为同一人时,自动通过"),
+ ASSIGN_START_USER_APPROVE_WHEN_SKIP("审批人与提交人为同一人时,自动通过"),
+ ASSIGN_START_USER_APPROVE_WHEN_DEPT_LEADER_NOT_FOUND("审批人与提交人为同一人时,找不到部门负责人,自动通过"),
+ ASSIGN_START_USER_TRANSFER_DEPT_LEADER("审批人与提交人为同一人时,转交给部门负责人审批"),
+ ASSIGN_EMPTY_APPROVE("审批人为空,自动通过"),
+ ASSIGN_EMPTY_REJECT("审批人为空,自动不通过"),
+ APPROVE_TYPE_AUTO_APPROVE("非人工审核,自动通过"),
+ APPROVE_TYPE_AUTO_REJECT("非人工审核,自动不通过"),
;
private final String reason;
@@ -36,10 +46,4 @@ public enum BpmDeleteReasonEnum {
return StrUtil.format(reason, args);
}
- // ========== 逻辑 ==========
-
- public static boolean isRejectReason(String reason) {
- return StrUtil.startWith(reason, "审批不通过任务,原因:");
- }
-
}
diff --git a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmTaskStatusEnum.java b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmTaskStatusEnum.java
index 40a385a582..f577fc020f 100644
--- a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmTaskStatusEnum.java
+++ b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmTaskStatusEnum.java
@@ -13,6 +13,7 @@ import lombok.Getter;
@AllArgsConstructor
public enum BpmTaskStatusEnum {
+ NOT_START(-1, "未开始"),
RUNNING(1, "审批中"),
APPROVE(2, "审批通过"),
REJECT(3, "审批不通过"),
diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/base/package-info.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/base/package-info.java
new file mode 100644
index 0000000000..41ce65081f
--- /dev/null
+++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/base/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * 基础包,放一些通用的 VO 类
+ */
+package cn.iocoder.yudao.module.bpm.controller.admin.base;
diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/base/user/UserSimpleBaseVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/base/user/UserSimpleBaseVO.java
new file mode 100644
index 0000000000..e245b3026b
--- /dev/null
+++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/base/user/UserSimpleBaseVO.java
@@ -0,0 +1,19 @@
+package cn.iocoder.yudao.module.bpm.controller.admin.base.user;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+@Schema(description = "用户精简信息 VO")
+@Data
+public class UserSimpleBaseVO {
+
+ @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+ private Long id;
+
+ @Schema(description = "用户昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿")
+ private String nickname;
+
+ @Schema(description = "用户头像", example = "https://www.iocoder.cn/1.png")
+ private String avatar;
+
+}
\ No newline at end of file
diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/BpmModelController.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/BpmModelController.java
index 4095450233..28398a702f 100644
--- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/BpmModelController.java
+++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/BpmModelController.java
@@ -4,10 +4,9 @@ import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
-import cn.iocoder.yudao.framework.common.util.io.IoUtils;
-import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
-import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.*;
+import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.simple.BpmSimpleModelNodeVO;
+import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.simple.BpmSimpleModelUpdateReqVO;
import cn.iocoder.yudao.module.bpm.convert.definition.BpmModelConvert;
import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmCategoryDO;
import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmFormDO;
@@ -15,10 +14,13 @@ import cn.iocoder.yudao.module.bpm.service.definition.BpmCategoryService;
import cn.iocoder.yudao.module.bpm.service.definition.BpmFormService;
import cn.iocoder.yudao.module.bpm.service.definition.BpmModelService;
import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessDefinitionService;
-import cn.iocoder.yudao.module.bpm.service.definition.dto.BpmModelMetaInfoRespDTO;
+import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
+import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.annotation.Resource;
+import jakarta.validation.Valid;
import org.flowable.engine.repository.Deployment;
import org.flowable.engine.repository.Model;
import org.flowable.engine.repository.ProcessDefinition;
@@ -26,17 +28,15 @@ import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
-import javax.annotation.Resource;
-import javax.validation.Valid;
-import java.io.IOException;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.stream.Stream;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
-import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
-import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
+import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
@Tag(name = "管理后台 - 流程模型")
@RestController
@@ -53,6 +53,9 @@ public class BpmModelController {
@Resource
private BpmProcessDefinitionService processDefinitionService;
+ @Resource
+ private AdminUserApi adminUserApi;
+
@GetMapping("/page")
@Operation(summary = "获得模型分页")
public CommonResult> getModelPage(BpmModelPageReqVO pageVO) {
@@ -64,7 +67,7 @@ public class BpmModelController {
// 拼接数据
// 获得 Form 表单
Set formIds = convertSet(pageResult.getList(), model -> {
- BpmModelMetaInfoRespDTO metaInfo = JsonUtils.parseObject(model.getMetaInfo(), BpmModelMetaInfoRespDTO.class);
+ BpmModelMetaInfoVO metaInfo = BpmModelConvert.INSTANCE.parseMetaInfo(model);
return metaInfo != null ? metaInfo.getFormId() : null;
});
Map formMap = formService.getFormMap(formIds);
@@ -78,7 +81,14 @@ public class BpmModelController {
// 获得 ProcessDefinition Map
List processDefinitions = processDefinitionService.getProcessDefinitionListByDeploymentIds(deploymentIds);
Map processDefinitionMap = convertMap(processDefinitions, ProcessDefinition::getDeploymentId);
- return success(BpmModelConvert.INSTANCE.buildModelPage(pageResult, formMap, categoryMap, deploymentMap, processDefinitionMap));
+ // 获得 User Map
+ Set userIds = convertSetByFlatMap(pageResult.getList(), model -> {
+ BpmModelMetaInfoVO metaInfo = BpmModelConvert.INSTANCE.parseMetaInfo(model);
+ return metaInfo != null ? metaInfo.getStartUserIds().stream() : Stream.empty();
+ });
+ Map userMap = adminUserApi.getUserMap(userIds);
+ return success(BpmModelConvert.INSTANCE.buildModelPage(pageResult,
+ formMap, categoryMap, deploymentMap, processDefinitionMap, userMap));
}
@GetMapping("/get")
@@ -97,34 +107,24 @@ public class BpmModelController {
@PostMapping("/create")
@Operation(summary = "新建模型")
@PreAuthorize("@ss.hasPermission('bpm:model:create')")
- public CommonResult createModel(@Valid @RequestBody BpmModelCreateReqVO createRetVO) {
- return success(modelService.createModel(createRetVO, null));
+ public CommonResult createModel(@Valid @RequestBody BpmModelSaveReqVO createRetVO) {
+ return success(modelService.createModel(createRetVO));
}
@PutMapping("/update")
@Operation(summary = "修改模型")
@PreAuthorize("@ss.hasPermission('bpm:model:update')")
- public CommonResult updateModel(@Valid @RequestBody BpmModelUpdateReqVO modelVO) {
- modelService.updateModel(modelVO);
+ public CommonResult updateModel(@Valid @RequestBody BpmModelSaveReqVO modelVO) {
+ modelService.updateModel(getLoginUserId(), modelVO);
return success(true);
}
- @PostMapping("/import")
- @Operation(summary = "导入模型")
- @PreAuthorize("@ss.hasPermission('bpm:model:import')")
- public CommonResult importModel(@Valid BpmModeImportReqVO importReqVO) throws IOException {
- BpmModelCreateReqVO createReqVO = BeanUtils.toBean(importReqVO, BpmModelCreateReqVO.class);
- // 读取文件
- String bpmnXml = IoUtils.readUtf8(importReqVO.getBpmnFile().getInputStream(), false);
- return success(modelService.createModel(createReqVO, bpmnXml));
- }
-
@PostMapping("/deploy")
@Operation(summary = "部署模型")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('bpm:model:deploy')")
public CommonResult deployModel(@RequestParam("id") String id) {
- modelService.deployModel(id);
+ modelService.deployModel(getLoginUserId(), id);
return success(true);
}
@@ -132,7 +132,15 @@ public class BpmModelController {
@Operation(summary = "修改模型的状态", description = "实际更新的部署的流程定义的状态")
@PreAuthorize("@ss.hasPermission('bpm:model:update')")
public CommonResult updateModelState(@Valid @RequestBody BpmModelUpdateStateReqVO reqVO) {
- modelService.updateModelState(reqVO.getId(), reqVO.getState());
+ modelService.updateModelState(getLoginUserId(), reqVO.getId(), reqVO.getState());
+ return success(true);
+ }
+
+ @PutMapping("/update-bpmn")
+ @Operation(summary = "修改模型的 BPMN")
+ @PreAuthorize("@ss.hasPermission('bpm:model:update')")
+ public CommonResult updateModelBpmn(@Valid @RequestBody BpmModeUpdateBpmnReqVO reqVO) {
+ modelService.updateModelBpmnXml(reqVO.getId(), reqVO.getBpmnXml());
return success(true);
}
@@ -141,8 +149,25 @@ public class BpmModelController {
@Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('bpm:model:delete')")
public CommonResult deleteModel(@RequestParam("id") String id) {
- modelService.deleteModel(id);
+ modelService.deleteModel(getLoginUserId(), id);
return success(true);
}
+ // ========== 仿钉钉/飞书的精简模型 =========
+
+ @GetMapping("/simple/get")
+ @Operation(summary = "获得仿钉钉流程设计模型")
+ @Parameter(name = "modelId", description = "流程模型编号", required = true, example = "a2c5eee0-eb6c-11ee-abf4-0c37967c420a")
+ public CommonResult getSimpleModel(@RequestParam("id") String modelId){
+ return success(modelService.getSimpleModel(modelId));
+ }
+
+ @PostMapping("/simple/update")
+ @Operation(summary = "保存仿钉钉流程设计模型")
+ @PreAuthorize("@ss.hasPermission('bpm:model:update')")
+ public CommonResult updateSimpleModel(@Valid @RequestBody BpmSimpleModelUpdateReqVO reqVO) {
+ modelService.updateSimpleModel(getLoginUserId(), reqVO);
+ return success(Boolean.TRUE);
+ }
+
}
diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/BpmProcessDefinitionController.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/BpmProcessDefinitionController.java
index 72b0a6183b..41368d27de 100644
--- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/BpmProcessDefinitionController.java
+++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/BpmProcessDefinitionController.java
@@ -34,6 +34,7 @@ import java.util.Map;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
+import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
@Tag(name = "管理后台 - 流程定义")
@RestController
@@ -79,14 +80,23 @@ public class BpmProcessDefinitionController {
@Parameter(name = "suspensionState", description = "挂起状态", required = true, example = "1") // 参见 Flowable SuspensionState 枚举
public CommonResult> getProcessDefinitionList(
@RequestParam("suspensionState") Integer suspensionState) {
+ // 1.1 获得开启的流程定义
List list = processDefinitionService.getProcessDefinitionListBySuspensionState(suspensionState);
if (CollUtil.isEmpty(list)) {
return success(Collections.emptyList());
}
-
- // 获得 BpmProcessDefinitionInfoDO Map
+ // 1.2 移除不可见的流程定义
Map processDefinitionMap = processDefinitionService.getProcessDefinitionInfoMap(
convertSet(list, ProcessDefinition::getId));
+ Long userId = getLoginUserId();
+ list.removeIf(processDefinition -> {
+ BpmProcessDefinitionInfoDO processDefinitionInfo = processDefinitionMap.get(processDefinition.getId());
+ return processDefinitionInfo == null // 不存在
+ || Boolean.FALSE.equals(processDefinitionInfo.getVisible()) // visible 不可见
+ || !processDefinitionService.canUserStartProcessDefinition(processDefinitionInfo, userId); // 无权限发起
+ });
+
+ // 2. 拼接 VO 返回
return success(BpmProcessDefinitionConvert.INSTANCE.buildProcessDefinitionList(
list, null, processDefinitionMap, null, null));
}
diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModeImportReqVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModeImportReqVO.java
deleted file mode 100644
index 0b549ca9a1..0000000000
--- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModeImportReqVO.java
+++ /dev/null
@@ -1,19 +0,0 @@
-package cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model;
-
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.Data;
-import lombok.EqualsAndHashCode;
-import lombok.ToString;
-import org.springframework.web.multipart.MultipartFile;
-
-import javax.validation.constraints.NotNull;
-
-@Schema(description = "管理后台 - 流程模型的导入 Request VO 相比流程模型的新建来说,只是多了一个 bpmnFile 文件")
-@Data
-public class BpmModeImportReqVO extends BpmModelCreateReqVO {
-
- @Schema(description = "BPMN 文件", requiredMode = Schema.RequiredMode.REQUIRED)
- @NotNull(message = "BPMN 文件不能为空")
- private MultipartFile bpmnFile;
-
-}
diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModeUpdateBpmnReqVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModeUpdateBpmnReqVO.java
new file mode 100644
index 0000000000..55d7533d61
--- /dev/null
+++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModeUpdateBpmnReqVO.java
@@ -0,0 +1,19 @@
+package cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.NotEmpty;
+import lombok.Data;
+
+@Schema(description = "管理后台 - 流程模型的更新 BPMN XML Request VO")
+@Data
+public class BpmModeUpdateBpmnReqVO {
+
+ @Schema(description = "流程编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+ @NotEmpty(message = "流程编号不能为空")
+ private String id;
+
+ @Schema(description = "BPMN XML", requiredMode = Schema.RequiredMode.REQUIRED)
+ @NotEmpty(message = "BPMN XML 不能为空")
+ private String bpmnXml;
+
+}
diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModelMetaInfoVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModelMetaInfoVO.java
new file mode 100644
index 0000000000..fa82ab1e6c
--- /dev/null
+++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModelMetaInfoVO.java
@@ -0,0 +1,62 @@
+package cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model;
+
+import cn.iocoder.yudao.framework.common.validation.InEnum;
+import cn.iocoder.yudao.module.bpm.enums.definition.BpmModelFormTypeEnum;
+import cn.iocoder.yudao.module.bpm.enums.definition.BpmModelTypeEnum;
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.NotEmpty;
+import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+import org.hibernate.validator.constraints.URL;
+
+import java.util.List;
+
+/**
+ * BPM 流程 MetaInfo Response DTO
+ * 主要用于 { Model#setMetaInfo(String)} 的存储
+ *
+ * 最终,它的字段和 {@link cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionInfoDO} 是一致的
+ *
+ * @author 芋道源码
+ */
+@Data
+public class BpmModelMetaInfoVO {
+
+ @Schema(description = "流程图标", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/yudao.jpg")
+ @NotEmpty(message = "流程图标不能为空")
+ @URL(message = "流程图标格式不正确")
+ private String icon;
+
+ @Schema(description = "流程描述", example = "我是描述")
+ private String description;
+
+ @Schema(description = "流程类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
+ @InEnum(BpmModelTypeEnum.class)
+ @NotNull(message = "流程类型不能为空")
+ private Integer type;
+
+ @Schema(description = "表单类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
+ @InEnum(BpmModelFormTypeEnum.class)
+ @NotNull(message = "表单类型不能为空")
+ private Integer formType;
+ @Schema(description = "表单编号", example = "1024")
+ private Long formId; // formType 为 NORMAL 使用,必须非空
+ @Schema(description = "自定义表单的提交路径,使用 Vue 的路由地址",
+ example = "/bpm/oa/leave/create")
+ private String formCustomCreatePath; // 表单类型为 CUSTOM 时,必须非空
+ @Schema(description = "自定义表单的查看路径,使用 Vue 的路由地址",
+ example = "/bpm/oa/leave/view")
+ private String formCustomViewPath; // 表单类型为 CUSTOM 时,必须非空
+
+ @Schema(description = "是否可见", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
+ @NotNull(message = "是否可见不能为空")
+ private Boolean visible;
+
+ @Schema(description = "可发起用户编号数组", example = "[1,2,3]")
+ private List startUserIds;
+
+ @Schema(description = "可管理用户编号数组", requiredMode = Schema.RequiredMode.REQUIRED, example = "[2,4,6]")
+ @NotEmpty(message = "可管理用户编号数组不能为空")
+ private List managerUserIds;
+
+}
diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModelRespVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModelRespVO.java
index aad2015c7e..c828b64638 100644
--- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModelRespVO.java
+++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModelRespVO.java
@@ -1,14 +1,16 @@
package cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model;
+import cn.iocoder.yudao.module.bpm.controller.admin.base.user.UserSimpleBaseVO;
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionRespVO;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.time.LocalDateTime;
+import java.util.List;
@Schema(description = "管理后台 - 流程模型 Response VO")
@Data
-public class BpmModelRespVO {
+public class BpmModelRespVO extends BpmModelMetaInfoVO {
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
private String id;
@@ -22,33 +24,23 @@ public class BpmModelRespVO {
@Schema(description = "流程图标", example = "https://www.iocoder.cn/yudao.jpg")
private String icon;
- @Schema(description = "流程描述", example = "我是描述")
- private String description;
-
@Schema(description = "流程分类编码", example = "1")
private String category;
@Schema(description = "流程分类名字", example = "请假")
private String categoryName;
- @Schema(description = "表单类型-参见 bpm_model_form_type 数据字典", example = "1")
- private Integer formType;
-
- @Schema(description = "表单编号", example = "1024")
- private Long formId; // 在表单类型为 {@link BpmModelFormTypeEnum#CUSTOM} 时,必须非空
@Schema(description = "表单名字", example = "请假表单")
private String formName;
- @Schema(description = "自定义表单的提交路径", example = "/bpm/oa/leave/create")
- private String formCustomCreatePath; // 使用 Vue 的路由地址-在表单类型为 {@link BpmModelFormTypeEnum#CUSTOM} 时,必须非空
- @Schema(description = "自定义表单的查看路径", example = "/bpm/oa/leave/view")
- private String formCustomViewPath; // ,使用 Vue 的路由地址-在表单类型为 {@link BpmModelFormTypeEnum#CUSTOM} 时,必须非空
-
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
private LocalDateTime createTime;
@Schema(description = "BPMN XML", requiredMode = Schema.RequiredMode.REQUIRED)
private String bpmnXml;
+ @Schema(description = "可发起的用户数组")
+ private List startUsers;
+
/**
* 最新部署的流程定义
*/
diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModelCreateReqVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModelSaveReqVO.java
similarity index 61%
rename from yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModelCreateReqVO.java
rename to yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModelSaveReqVO.java
index 39e4844f71..dd15e67ae7 100644
--- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModelCreateReqVO.java
+++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModelSaveReqVO.java
@@ -1,15 +1,15 @@
package cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model;
import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.NotEmpty;
import lombok.Data;
-import lombok.EqualsAndHashCode;
-import lombok.ToString;
-import javax.validation.constraints.NotEmpty;
-
-@Schema(description = "管理后台 - 流程模型的创建 Request VO")
+@Schema(description = "管理后台 - 流程模型的保存 Request VO")
@Data
-public class BpmModelCreateReqVO {
+public class BpmModelSaveReqVO extends BpmModelMetaInfoVO {
+
+ @Schema(description = "编号", example = "1024")
+ private String id;
@Schema(description = "流程标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "process_yudao")
@NotEmpty(message = "流程标识不能为空")
@@ -19,7 +19,7 @@ public class BpmModelCreateReqVO {
@NotEmpty(message = "流程名称不能为空")
private String name;
- @Schema(description = "流程描述", example = "我是描述")
- private String description;
+ @Schema(description = "流程分类", example = "1")
+ private String category;
}
diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModelUpdateReqVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModelUpdateReqVO.java
deleted file mode 100644
index 231ead168b..0000000000
--- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModelUpdateReqVO.java
+++ /dev/null
@@ -1,47 +0,0 @@
-package cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model;
-
-import cn.iocoder.yudao.framework.common.validation.InEnum;
-import cn.iocoder.yudao.module.bpm.enums.definition.BpmModelFormTypeEnum;
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.Data;
-import org.hibernate.validator.constraints.URL;
-
-import javax.validation.constraints.NotEmpty;
-
-@Schema(description = "管理后台 - 流程模型的更新 Request VO")
-@Data
-public class BpmModelUpdateReqVO {
-
- @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
- @NotEmpty(message = "编号不能为空")
- private String id;
-
- @Schema(description = "流程名称", example = "芋道")
- private String name;
-
- @Schema(description = "流程图标", example = "https://www.iocoder.cn/yudao.jpg")
- @URL(message = "流程图标格式不正确")
- private String icon;
-
- @Schema(description = "流程描述", example = "我是描述")
- private String description;
-
- @Schema(description = "流程分类", example = "1")
- private String category;
-
- @Schema(description = "BPMN XML", requiredMode = Schema.RequiredMode.REQUIRED)
- private String bpmnXml;
-
- @Schema(description = "表单类型-参见 bpm_model_form_type 数据字典", example = "1")
- @InEnum(BpmModelFormTypeEnum.class)
- private Integer formType;
- @Schema(description = "表单编号-在表单类型为 {@link BpmModelFormTypeEnum#CUSTOM} 时,必须非空", example = "1024")
- private Long formId;
- @Schema(description = "自定义表单的提交路径,使用 Vue 的路由地址-在表单类型为 {@link BpmModelFormTypeEnum#CUSTOM} 时,必须非空",
- example = "/bpm/oa/leave/create")
- private String formCustomCreatePath;
- @Schema(description = "自定义表单的查看路径,使用 Vue 的路由地址-在表单类型为 {@link BpmModelFormTypeEnum#CUSTOM} 时,必须非空",
- example = "/bpm/oa/leave/view")
- private String formCustomViewPath;
-
-}
diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/simple/BpmSimpleModelNodeVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/simple/BpmSimpleModelNodeVO.java
new file mode 100644
index 0000000000..502511753b
--- /dev/null
+++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/simple/BpmSimpleModelNodeVO.java
@@ -0,0 +1,220 @@
+package cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.simple;
+
+import cn.iocoder.yudao.framework.common.validation.InEnum;
+import cn.iocoder.yudao.module.bpm.enums.definition.*;
+import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmTaskCandidateStrategyEnum;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.Valid;
+import jakarta.validation.constraints.NotEmpty;
+import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+
+import java.util.List;
+import java.util.Map;
+
+@Schema(description = "管理后台 - 仿钉钉流程设计模型节点 VO")
+@Data
+@JsonInclude(JsonInclude.Include.NON_NULL)
+public class BpmSimpleModelNodeVO {
+
+ @Schema(description = "模型节点编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "StartEvent_1")
+ @NotEmpty(message = "模型节点编号不能为空")
+ private String id;
+
+ @Schema(description = "模型节点类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+ @NotNull(message = "模型节点类型不能为空")
+ @InEnum(BpmSimpleModelNodeType.class)
+ private Integer type;
+
+ @Schema(description = "模型节点名称", example = "领导审批")
+ private String name;
+
+ // TODO @jason:和 gpt 大模型对了下这个字段的命名,貌似叫 displayText 合适点。可以等最后我们全局替换下。(优先级:低)
+ @Schema(description = "节点展示内容", example = "指定成员: 芋道源码")
+ private String showText;
+
+ @Schema(description = "子节点")
+ private BpmSimpleModelNodeVO childNode; // 补充说明:在该模型下,子节点有且仅有一个,不会有多个
+
+ @Schema(description = "条件节点")
+ private List conditionNodes; // 补充说明:有且仅有条件、并行、包容等分支会使用
+
+ @Schema(description = "条件类型", example = "1")
+ @InEnum(BpmSimpleModeConditionType.class)
+ private Integer conditionType; // 仅用于条件节点 BpmSimpleModelNodeType.CONDITION_NODE
+
+ @Schema(description = "条件表达式", example = "${day>3}")
+ private String conditionExpression; // 仅用于条件节点 BpmSimpleModelNodeType.CONDITION_NODE
+
+ @Schema(description = "是否默认条件", example = "true")
+ private Boolean defaultFlow; // 仅用于条件节点 BpmSimpleModelNodeType.CONDITION_NODE
+ /**
+ * 条件组
+ */
+ private ConditionGroups conditionGroups; // 仅用于条件节点 BpmSimpleModelNodeType.CONDITION_NODE
+
+ @Schema(description = "候选人策略", example = "30")
+ @InEnum(BpmTaskCandidateStrategyEnum.class)
+ private Integer candidateStrategy; // 用于审批,抄送节点
+
+ @Schema(description = "候选人参数")
+ private String candidateParam; // 用于审批,抄送节点
+
+ @Schema(description = "审批节点类型", example = "1")
+ @InEnum(BpmUserTaskApproveTypeEnum.class)
+ private Integer approveType; // 用于审批节点
+
+ @Schema(description = "多人审批方式", example = "1")
+ @InEnum(BpmUserTaskApproveMethodEnum.class)
+ private Integer approveMethod; // 用于审批节点
+
+ @Schema(description = "通过比例", example = "100")
+ private Integer approveRatio; // 通过比例,当多人审批方式为:多人会签(按通过比例) 需要设置
+
+ @Schema(description = "表单权限", example = "[]")
+ private List