update warm-flow 升级 1.8.2

This commit is contained in:
AprilWind
2025-10-16 16:24:06 +08:00
parent 3623fc33d9
commit 7800b1259f
13 changed files with 499 additions and 60 deletions

View File

@@ -72,8 +72,8 @@ public class WorkflowGlobalListener implements GlobalListener {
public void start(ListenerVariable listenerVariable) {
String ext = listenerVariable.getNode().getExt();
if (StringUtils.isNotBlank(ext)) {
NodeExtVo nodeExt = nodeExtService.parseNodeExt(ext);
Map<String, Object> variable = listenerVariable.getVariable();
NodeExtVo nodeExt = nodeExtService.parseNodeExt(ext, variable);
Set<String> copyList = nodeExt.getCopySettings();
if (CollUtil.isNotEmpty(copyList)) {
List<FlowCopyBo> list = StreamUtils.toList(copyList, x -> {
@@ -180,12 +180,14 @@ public class WorkflowGlobalListener implements GlobalListener {
}
if (variable.containsKey(FlowConstant.FLOW_COPY_LIST)) {
List<FlowCopyBo> flowCopyList = MapUtil.get(variable, FlowConstant.FLOW_COPY_LIST, new TypeReference<>() {});
List<FlowCopyBo> flowCopyList = MapUtil.get(variable, FlowConstant.FLOW_COPY_LIST, new TypeReference<>() {
});
// 添加抄送人
flwTaskService.setCopy(task, flowCopyList);
}
if (variable.containsKey(FlowConstant.MESSAGE_TYPE)) {
List<String> messageType = MapUtil.get(variable, FlowConstant.MESSAGE_TYPE, new TypeReference<>() {});
List<String> messageType = MapUtil.get(variable, FlowConstant.MESSAGE_TYPE, new TypeReference<>() {
});
String notice = MapUtil.getStr(variable, FlowConstant.MESSAGE_NOTICE);
flwCommonService.sendMessage(definition.getFlowName(), instance.getId(), messageType, notice);
}

View File

@@ -2,6 +2,8 @@ package org.dromara.workflow.service;
import org.dromara.workflow.domain.vo.NodeExtVo;
import java.util.Map;
/**
* 流程节点扩展属性 服务层
*
@@ -24,9 +26,10 @@ public interface IFlwNodeExtService {
* {"code": "VariablesEnum", "value": "key1=value1,key2=value2"}
* ]
*
* @param ext 扩展属性 JSON 字符串
* @param ext 扩展属性 JSON 字符串
* @param variable 流程变量
* @return NodeExtVo 对象,封装按钮权限列表、抄送对象集合和自定义参数 Map
*/
NodeExtVo parseNodeExt(String ext);
NodeExtVo parseNodeExt(String ext, Map<String, Object> variable);
}

View File

@@ -9,6 +9,9 @@ import org.dromara.common.core.domain.dto.DictTypeDTO;
import org.dromara.common.core.service.DictService;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.json.utils.JsonUtils;
import org.dromara.warm.flow.core.FlowEngine;
import org.dromara.warm.flow.core.utils.CollUtil;
import org.dromara.warm.flow.core.utils.ExpressionUtil;
import org.dromara.warm.flow.ui.service.NodeExtService;
import org.dromara.warm.flow.ui.vo.NodeExt;
import org.dromara.workflow.common.ConditionalOnEnable;
@@ -45,7 +48,7 @@ public class FlwNodeExtServiceImpl implements NodeExtService, IFlwNodeExtService
CopySettingEnum.class.getSimpleName(),
Map.of(
"label", "抄送对象",
"type", 2,
"type", 5,
"must", false,
"multiple", false,
"desc", "设置该节点的抄送办理人"
@@ -56,7 +59,7 @@ public class FlwNodeExtServiceImpl implements NodeExtService, IFlwNodeExtService
"type", 2,
"must", false,
"multiple", false,
"desc", "节点执行时可以使用的自定义参数"
"desc", "节点执行时可设置自定义参数多个参数以逗号分隔key1=value1,key2=value2"
),
ButtonPermissionEnum.class.getSimpleName(),
Map.of(
@@ -137,7 +140,7 @@ public class FlwNodeExtServiceImpl implements NodeExtService, IFlwNodeExtService
childNode.setCode(simpleName);
// label名称
childNode.setLabel(Convert.toStr(map.get("label")));
// 1输入框 2文本域 3下拉框 4选择框
// 1输入框 2文本域 3下拉框 4选择框 5用户选择器
childNode.setType(Convert.toInt(map.get("type"), 1));
// 是否必填
childNode.setMust(Convert.toBool(map.get("must"), false));
@@ -170,7 +173,7 @@ public class FlwNodeExtServiceImpl implements NodeExtService, IFlwNodeExtService
childNode.setCode(dictType);
// label名称
childNode.setLabel(dictTypeDTO.getDictName());
// 1输入框 2文本域 3下拉框 4选择框
// 1输入框 2文本域 3下拉框 4选择框 5用户选择器
childNode.setType(3);
// 是否必填
childNode.setMust(false);
@@ -197,15 +200,16 @@ public class FlwNodeExtServiceImpl implements NodeExtService, IFlwNodeExtService
* <p>示例 JSON
* [
* {"code": "ButtonPermissionEnum", "value": "back,termination"},
* {"code": "CopySettingEnum", "value": "1"},
* {"code": "CopySettingEnum", "value": "1,3,4,#{@spelRuleComponent.selectDeptLeaderById(#deptId", "#roleId)}"},
* {"code": "VariablesEnum", "value": "key1=value1,key2=value2"}
* ]
*
* @param ext 扩展属性 JSON 字符串
* @param ext 扩展属性 JSON 字符串
* @param variable 流程变量
* @return NodeExtVo 对象,封装按钮权限列表、抄送对象集合和自定义参数 Map
*/
@Override
public NodeExtVo parseNodeExt(String ext) {
public NodeExtVo parseNodeExt(String ext, Map<String, Object> variable) {
NodeExtVo nodeExtVo = new NodeExtVo();
// 解析 JSON 为 Dict 列表
@@ -234,8 +238,20 @@ public class FlwNodeExtServiceImpl implements NodeExtService, IFlwNodeExtService
nodeExtVo.setButtonPermissions(buttonList);
} else if (CopySettingEnum.class.getSimpleName().equals(code)) {
List<String> permissions = spelSmartSplit(value).stream()
.map(s -> {
List<String> result = ExpressionUtil.evalVariable(s, variable);
if (CollUtil.isNotEmpty(result)) {
return result;
}
return Collections.singletonList(s);
}).filter(Objects::nonNull)
.flatMap(List::stream)
.distinct()
.collect(Collectors.toList());
List<String> copySettings = FlowEngine.permissionHandler().convertPermissions(permissions);
// 解析抄送对象 ID 集合
nodeExtVo.setCopySettings(StringUtils.str2Set(value, StringUtils.SEPARATOR));
nodeExtVo.setCopySettings(new HashSet<>(copySettings));
} else if (VariablesEnum.class.getSimpleName().equals(code)) {
// 解析自定义参数
@@ -254,4 +270,82 @@ public class FlwNodeExtServiceImpl implements NodeExtService, IFlwNodeExtService
return nodeExtVo;
}
/**
* 按逗号分割字符串,但保留 #{...} 表达式和字符串常量中的逗号
*/
private static List<String> spelSmartSplit(String str) {
List<String> result = new ArrayList<>();
if (str == null || str.trim().isEmpty()) {
return result;
}
StringBuilder token = new StringBuilder();
// #{...} 的嵌套深度
int depth = 0;
// 是否在字符串常量中(" 或 '
boolean inString = false;
// 当前字符串引号类型
char stringQuote = 0;
for (int i = 0; i < str.length(); i++) {
char c = str.charAt(i);
// 检测进入 SpEL 表达式 #{...}
if (!inString && c == '#' && depth == 0 && checkNext(str, i, '{')) {
depth++;
token.append("#{");
// 跳过 {
i++;
continue;
}
// 在表达式中遇到 { 或 } 改变嵌套深度
if (!inString && depth > 0) {
if (c == '{') {
depth++;
} else if (c == '}') {
depth--;
}
token.append(c);
continue;
}
// 检测字符串开始/结束
if (depth > 0 && (c == '"' || c == '\'')) {
if (!inString) {
inString = true;
stringQuote = c;
} else if (stringQuote == c) {
inString = false;
}
token.append(c);
continue;
}
// 外层逗号才分割
if (c == ',' && depth == 0 && !inString) {
String part = token.toString().trim();
if (!part.isEmpty()) {
result.add(part);
}
token.setLength(0);
continue;
}
token.append(c);
}
// 添加最后一个
String part = token.toString().trim();
if (!part.isEmpty()) {
result.add(part);
}
return result;
}
private static boolean checkNext(String str, int index, char expected) {
return index + 1 < str.length() && str.charAt(index + 1) == expected;
}
}

View File

@@ -598,7 +598,7 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
if (ObjectUtil.isNull(flowNode)) {
throw new NullPointerException("当前【" + flowTaskVo.getNodeCode() + "】节点编码不存在");
}
NodeExtVo nodeExtVo = flwNodeExtService.parseNodeExt(flowNode.getExt());
NodeExtVo nodeExtVo = flwNodeExtService.parseNodeExt(flowNode.getExt(), instance.getVariableMap());
//设置按钮权限
flowTaskVo.setButtonList(nodeExtVo.getButtonPermissions());
if (CollUtil.isNotEmpty(nodeExtVo.getCopySettings())) {