diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/NodeExtVo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/NodeExtVo.java new file mode 100644 index 000000000..5fb3380b4 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/NodeExtVo.java @@ -0,0 +1,45 @@ +package org.dromara.workflow.domain.vo; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * Node 扩展属性解析结果 VO + *

+ * 用于封装从扩展属性 JSON 中解析出的各类信息,包括按钮权限、抄送对象和自定义参数。 + * + * @author AprilWind + */ +@Data +public class NodeExtVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 按钮权限列表 + *

+ * 根据扩展属性中 ButtonPermissionEnum 类型的数据生成,每个元素表示一个按钮及其是否勾选。 + */ + private List buttonPermissions; + + /** + * 抄送对象 ID 集合 + *

+ * 根据扩展属性中 CopySettingEnum 类型的数据生成,存储需要抄送的对象 ID + */ + private Set copySettings; + + /** + * 自定义参数 Map + *

+ * 根据扩展属性中 VariablesEnum 类型的数据生成,存储 key=value 格式的自定义参数 + */ + private Map variables; + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IFlwNodeExtService.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IFlwNodeExtService.java index 959516535..2ccc6a73e 100644 --- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IFlwNodeExtService.java +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IFlwNodeExtService.java @@ -1,8 +1,6 @@ package org.dromara.workflow.service; -import org.dromara.workflow.domain.vo.ButtonPermissionVo; - -import java.util.List; +import org.dromara.workflow.domain.vo.NodeExtVo; /** * 流程节点扩展属性 服务层 @@ -12,11 +10,23 @@ import java.util.List; public interface IFlwNodeExtService { /** - * 从扩展属性构建按钮权限列表:根据 ext 中记录的权限值,标记每个按钮是否勾选 + * 解析扩展属性 JSON 并构建 Node 扩展属性对象 + *

+ * 根据传入的 JSON 字符串,将扩展属性分为三类: + * 1. ButtonPermissionEnum:解析为按钮权限列表,标记每个按钮是否勾选 + * 2. CopySettingEnum:解析为抄送对象 ID 集合 + * 3. VariablesEnum:解析为自定义参数 Map + * + *

示例 JSON: + * [ + * {"code": "ButtonPermissionEnum", "value": "back,termination"}, + * {"code": "CopySettingEnum", "value": "1"}, + * {"code": "VariablesEnum", "value": "key1=value1,key2=value2"} + * ] * * @param ext 扩展属性 JSON 字符串 - * @return 按钮权限 VO 列表 + * @return NodeExtVo 对象,封装按钮权限列表、抄送对象集合和自定义参数 Map */ - List buildButtonPermissionsFromExt(String ext); + NodeExtVo parseNodeExt(String ext); } diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwNodeExtServiceImpl.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwNodeExtServiceImpl.java index f5e712757..b5f4c6deb 100644 --- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwNodeExtServiceImpl.java +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwNodeExtServiceImpl.java @@ -1,8 +1,8 @@ package org.dromara.workflow.service.impl; import cn.hutool.core.convert.Convert; +import cn.hutool.core.lang.Dict; import cn.hutool.core.util.ObjectUtil; -import cn.hutool.core.util.StrUtil; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.dromara.common.core.domain.dto.DictTypeDTO; @@ -17,12 +17,12 @@ import org.dromara.workflow.common.enums.CopySettingEnum; import org.dromara.workflow.common.enums.NodeExtEnum; import org.dromara.workflow.common.enums.VariablesEnum; import org.dromara.workflow.domain.vo.ButtonPermissionVo; +import org.dromara.workflow.domain.vo.NodeExtVo; import org.dromara.workflow.service.IFlwNodeExtService; import org.springframework.stereotype.Service; import java.util.*; import java.util.stream.Collectors; -import java.util.stream.Stream; /** * 流程设计器-节点扩展属性 @@ -187,73 +187,71 @@ public class FlwNodeExtServiceImpl implements NodeExtService, IFlwNodeExtService } /** - * 从扩展属性构建按钮权限列表:根据 ext 中记录的权限值,标记每个按钮是否勾选 + * 解析扩展属性 JSON 并构建 Node 扩展属性对象 + *

+ * 根据传入的 JSON 字符串,将扩展属性分为三类: + * 1. ButtonPermissionEnum:解析为按钮权限列表,标记每个按钮是否勾选 + * 2. CopySettingEnum:解析为抄送对象 ID 集合 + * 3. VariablesEnum:解析为自定义参数 Map + * + *

示例 JSON: + * [ + * {"code": "ButtonPermissionEnum", "value": "back,termination"}, + * {"code": "CopySettingEnum", "value": "1"}, + * {"code": "VariablesEnum", "value": "key1=value1,key2=value2"} + * ] * * @param ext 扩展属性 JSON 字符串 - * @return 按钮权限 VO 列表 + * @return NodeExtVo 对象,封装按钮权限列表、抄送对象集合和自定义参数 Map */ @Override - public List buildButtonPermissionsFromExt(String ext) { - // 解析 ext 为 Map>,用于标记权限 - Map> permissionMap = JsonUtils.parseArray(ext, ButtonPermissionVo.class) - .stream() - .collect(Collectors.toMap( - ButtonPermissionVo::getCode, - item -> StringUtils.splitList(item.getValue()).stream() - .map(String::trim) - .filter(StrUtil::isNotBlank) - .collect(Collectors.toSet()), - (a, b) -> b, - HashMap::new - )); + public NodeExtVo parseNodeExt(String ext) { + NodeExtVo nodeExtVo = new NodeExtVo(); - // 构建按钮权限列表,标记哪些按钮在 permissionMap 中出现(表示已勾选) - return buildPermissionsFromSources(permissionMap, List.of(ButtonPermissionEnum.class)); - } + // 解析 JSON 为 Dict 列表 + List nodeExtMap = JsonUtils.parseArrayMap(ext); - /** - * 将权限映射与按钮权限来源(枚举类或字典类型)进行匹配,生成权限视图列表 - *

- * 使用说明: - * - sources 支持传入多个来源类型,支持 NodeExtEnum 枚举类 或 字典类型字符串(dictType) - * - 若需要扩展更多按钮权限,只需在 sources 中新增对应的枚举类或字典类型 - *

- * 示例: - * buildPermissionsFromSources(permissionMap, List.of(ButtonPermissionEnum.class, "custom_button_dict")); - * - * @param permissionMap 权限映射 - * @param sources 枚举类或字典类型列表 - * @return 按钮权限视图对象列表 - */ - @SuppressWarnings("unchecked cast") - private List buildPermissionsFromSources(Map> permissionMap, List sources) { - return sources.stream() - .flatMap(source -> { - if (source instanceof Class clazz && NodeExtEnum.class.isAssignableFrom(clazz)) { - Set selectedSet = permissionMap.getOrDefault(clazz.getSimpleName(), Collections.emptySet()); - return extractDictItems(this.buildChildNode((Class) clazz), selectedSet).stream(); - } else if (source instanceof String dictType) { - Set selectedSet = permissionMap.getOrDefault(dictType, Collections.emptySet()); - return extractDictItems(this.buildChildNode(dictType), selectedSet).stream(); - } - return Stream.empty(); - }).toList(); - } + for (Dict nodeExt : nodeExtMap) { + String code = nodeExt.getStr("code"); + String value = nodeExt.getStr("value"); - /** - * 从节点子项中提取字典项,并构建按钮权限视图对象列表 - * - * @param childNode 子节点 - * @param selectedSet 已选中的值集 - * @return 按钮权限视图对象列表 - */ - private List extractDictItems(NodeExt.ChildNode childNode, Set selectedSet) { - return Optional.ofNullable(childNode) - .map(NodeExt.ChildNode::getDict) - .orElse(List.of()) - .stream() - .map(dict -> new ButtonPermissionVo(dict.getValue(), selectedSet.contains(dict.getValue()))) - .toList(); + if (ButtonPermissionEnum.class.getSimpleName().equals(code)) { + // 解析按钮权限 + // 将 value 拆分为 Set,便于精确匹配 + Set buttonSet = StringUtils.str2Set(value, StringUtils.SEPARATOR); + + // 获取按钮字典配置 + NodeExt.ChildNode childNode = buildChildNode(ButtonPermissionEnum.class); + + // 构建 ButtonPermissionVo 列表 + List buttonList = Optional.ofNullable(childNode) + .map(NodeExt.ChildNode::getDict) + .orElse(List.of()) + .stream() + .map(dict -> new ButtonPermissionVo(dict.getValue(), buttonSet.contains(dict.getValue()))) + .toList(); + + nodeExtVo.setButtonPermissions(buttonList); + + } else if (CopySettingEnum.class.getSimpleName().equals(code)) { + // 解析抄送对象 ID 集合 + nodeExtVo.setCopySettings(StringUtils.str2Set(value, StringUtils.SEPARATOR)); + + } else if (VariablesEnum.class.getSimpleName().equals(code)) { + // 解析自定义参数 + // 将 key=value 字符串拆分为 Map + Map variables = Arrays.stream(StringUtils.split(value, StringUtils.SEPARATOR)) + .map(s -> StringUtils.split(s, "=")) + .filter(arr -> arr.length == 2) + .collect(Collectors.toMap(arr -> arr[0], arr -> arr[1])); + + nodeExtVo.setVariables(variables); + } else { + // 未知扩展类型,记录日志 + log.warn("未知扩展类型:code={}, value={}", code, value); + } + } + return nodeExtVo; } } diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwTaskServiceImpl.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwTaskServiceImpl.java index 22b78680f..9963d5328 100644 --- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwTaskServiceImpl.java +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwTaskServiceImpl.java @@ -48,6 +48,7 @@ import org.dromara.workflow.domain.FlowInstanceBizExt; import org.dromara.workflow.domain.bo.*; import org.dromara.workflow.domain.vo.FlowHisTaskVo; import org.dromara.workflow.domain.vo.FlowTaskVo; +import org.dromara.workflow.domain.vo.NodeExtVo; import org.dromara.workflow.mapper.FlwCategoryMapper; import org.dromara.workflow.mapper.FlwInstanceBizExtMapper; import org.dromara.workflow.mapper.FlwTaskMapper; @@ -597,8 +598,9 @@ public class FlwTaskServiceImpl implements IFlwTaskService { if (ObjectUtil.isNull(flowNode)) { throw new NullPointerException("当前【" + flowTaskVo.getNodeCode() + "】节点编码不存在"); } + NodeExtVo nodeExtVo = flwNodeExtService.parseNodeExt(flowNode.getExt()); //设置按钮权限 - flowTaskVo.setButtonList(flwNodeExtService.buildButtonPermissionsFromExt(flowNode.getExt())); + flowTaskVo.setButtonList(nodeExtVo.getButtonPermissions()); flowTaskVo.setNodeRatio(flowNode.getNodeRatio()); flowTaskVo.setApplyNode(flowNode.getNodeCode().equals(flwCommonService.applyNodeCode(task.getDefinitionId()))); return flowTaskVo;