mirror of
				https://github.com/dromara/RuoYi-Vue-Plus.git
				synced 2025-11-04 08:13:44 +08:00 
			
		
		
		
	update 优化工作流权限按钮获取,若需要扩展更多按钮权限,只需在 sources 中新增对应的枚举类或字典类型
This commit is contained in:
		@@ -12,18 +12,18 @@ import java.io.Serializable;
 | 
			
		||||
 * @date 2025-02-28
 | 
			
		||||
 */
 | 
			
		||||
@Data
 | 
			
		||||
public class ButtonPermission implements Serializable {
 | 
			
		||||
public class ButtonPermissionVo implements Serializable {
 | 
			
		||||
 | 
			
		||||
    @Serial
 | 
			
		||||
    private static final long serialVersionUID = 1L;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 枚举路径
 | 
			
		||||
     * 唯一编码
 | 
			
		||||
     */
 | 
			
		||||
    private String code;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 按钮编码
 | 
			
		||||
     * 选项值
 | 
			
		||||
     */
 | 
			
		||||
    private String value;
 | 
			
		||||
 | 
			
		||||
@@ -31,4 +31,13 @@ public class ButtonPermission implements Serializable {
 | 
			
		||||
     * 是否显示
 | 
			
		||||
     */
 | 
			
		||||
    private boolean show;
 | 
			
		||||
 | 
			
		||||
    public ButtonPermissionVo() {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public ButtonPermissionVo(String code, boolean show) {
 | 
			
		||||
        this.code = code;
 | 
			
		||||
        this.show = show;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -1,20 +1,16 @@
 | 
			
		||||
package org.dromara.workflow.domain.vo;
 | 
			
		||||
 | 
			
		||||
import cn.hutool.core.collection.CollUtil;
 | 
			
		||||
import cn.hutool.json.JSONUtil;
 | 
			
		||||
import lombok.Data;
 | 
			
		||||
import org.dromara.common.core.utils.StringUtils;
 | 
			
		||||
import org.dromara.common.translation.annotation.Translation;
 | 
			
		||||
import org.dromara.common.translation.constant.TransConstant;
 | 
			
		||||
import org.dromara.warm.flow.core.entity.User;
 | 
			
		||||
import org.dromara.workflow.common.constant.FlowConstant;
 | 
			
		||||
import org.dromara.workflow.common.enums.ButtonPermissionEnum;
 | 
			
		||||
 | 
			
		||||
import java.io.Serial;
 | 
			
		||||
import java.io.Serializable;
 | 
			
		||||
import java.math.BigDecimal;
 | 
			
		||||
import java.util.*;
 | 
			
		||||
import java.util.stream.Collectors;
 | 
			
		||||
import java.util.Date;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 任务视图
 | 
			
		||||
@@ -186,30 +182,6 @@ public class FlowTaskVo implements Serializable {
 | 
			
		||||
    /**
 | 
			
		||||
     * 按钮权限
 | 
			
		||||
     */
 | 
			
		||||
    private List<ButtonPermission> buttonList;
 | 
			
		||||
    private List<ButtonPermissionVo> buttonList;
 | 
			
		||||
 | 
			
		||||
    public List<ButtonPermission> getButtonList(String ext) {
 | 
			
		||||
        List<ButtonPermission> buttonPermissions = Arrays.stream(ButtonPermissionEnum.values())
 | 
			
		||||
            .map(value -> {
 | 
			
		||||
                ButtonPermission buttonPermission = new ButtonPermission();
 | 
			
		||||
                buttonPermission.setCode(value.getValue());
 | 
			
		||||
                buttonPermission.setShow(false);
 | 
			
		||||
                return buttonPermission;
 | 
			
		||||
            })
 | 
			
		||||
            .collect(Collectors.toList());
 | 
			
		||||
        if (StringUtils.isNotBlank(ext)) {
 | 
			
		||||
            List<ButtonPermission> buttonCodeList = JSONUtil.toList(JSONUtil.parseArray(ext), ButtonPermission.class);
 | 
			
		||||
            if (CollUtil.isNotEmpty(buttonCodeList)) {
 | 
			
		||||
                Optional<ButtonPermission> firstPermission = buttonCodeList.stream().findFirst();
 | 
			
		||||
                firstPermission.ifPresent(permission -> {
 | 
			
		||||
                    Set<String> codeSet = Arrays.stream(permission.getValue().split(","))
 | 
			
		||||
                        .map(String::trim)
 | 
			
		||||
                        .filter(code -> !code.isEmpty())
 | 
			
		||||
                        .collect(Collectors.toSet());
 | 
			
		||||
                    buttonPermissions.forEach(bp -> bp.setShow(codeSet.contains(bp.getCode())));
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return buttonPermissions;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,22 @@
 | 
			
		||||
package org.dromara.workflow.service;
 | 
			
		||||
 | 
			
		||||
import org.dromara.workflow.domain.vo.ButtonPermissionVo;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 流程节点扩展属性 服务层
 | 
			
		||||
 *
 | 
			
		||||
 * @author AprilWind
 | 
			
		||||
 */
 | 
			
		||||
public interface IFlwNodeExtService {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 从扩展属性构建按钮权限列表:根据 ext 中记录的权限值,标记每个按钮是否勾选
 | 
			
		||||
     *
 | 
			
		||||
     * @param ext 扩展属性 JSON 字符串
 | 
			
		||||
     * @return 按钮权限 VO 列表
 | 
			
		||||
     */
 | 
			
		||||
    List<ButtonPermissionVo> buildButtonPermissionsFromExt(String ext);
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -191,7 +191,7 @@ public class FlwDefinitionServiceImpl implements IFlwDefinitionService {
 | 
			
		||||
            List<FlowDefinition> flowDefinitions = flowDefinitionMapper.selectByIds(StreamUtils.toList(flowHisTasks, FlowHisTask::getDefinitionId));
 | 
			
		||||
            if (CollUtil.isNotEmpty(flowDefinitions)) {
 | 
			
		||||
                String join = StreamUtils.join(flowDefinitions, FlowDefinition::getFlowCode);
 | 
			
		||||
                log.error("流程定义【{}】已被使用不可被删除!", join);
 | 
			
		||||
                log.info("流程定义【{}】已被使用不可被删除!", join);
 | 
			
		||||
                throw new ServiceException("流程定义【" + join + "】已被使用不可被删除!");
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -2,18 +2,25 @@ package org.dromara.workflow.service.impl;
 | 
			
		||||
 | 
			
		||||
import cn.hutool.core.convert.Convert;
 | 
			
		||||
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;
 | 
			
		||||
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.ui.service.NodeExtService;
 | 
			
		||||
import org.dromara.warm.flow.ui.vo.NodeExt;
 | 
			
		||||
import org.dromara.workflow.common.ConditionalOnEnable;
 | 
			
		||||
import org.dromara.workflow.common.enums.ButtonPermissionEnum;
 | 
			
		||||
import org.dromara.workflow.common.enums.NodeExtEnum;
 | 
			
		||||
import org.dromara.workflow.domain.vo.ButtonPermissionVo;
 | 
			
		||||
import org.dromara.workflow.service.IFlwNodeExtService;
 | 
			
		||||
import org.springframework.stereotype.Service;
 | 
			
		||||
 | 
			
		||||
import java.util.*;
 | 
			
		||||
import java.util.stream.Collectors;
 | 
			
		||||
import java.util.stream.Stream;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 流程设计器-节点扩展属性
 | 
			
		||||
@@ -24,14 +31,15 @@ import java.util.*;
 | 
			
		||||
@Slf4j
 | 
			
		||||
@RequiredArgsConstructor
 | 
			
		||||
@Service
 | 
			
		||||
public class FlwNodeExtServiceImpl implements NodeExtService {
 | 
			
		||||
public class FlwNodeExtServiceImpl implements NodeExtService, IFlwNodeExtService {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 存储不同 dictType 对应的配置信息
 | 
			
		||||
     */
 | 
			
		||||
    private static final Map<String, ButtonPermission> CHILD_NODE_MAP = new HashMap<>();
 | 
			
		||||
 | 
			
		||||
    record ButtonPermission(String label, Integer type, Boolean must, Boolean multiple) {}
 | 
			
		||||
    record ButtonPermission(String label, Integer type, Boolean must, Boolean multiple) {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static {
 | 
			
		||||
        CHILD_NODE_MAP.put(ButtonPermissionEnum.class.getSimpleName(),
 | 
			
		||||
@@ -162,4 +170,74 @@ public class FlwNodeExtServiceImpl implements NodeExtService {
 | 
			
		||||
        return childNode;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 从扩展属性构建按钮权限列表:根据 ext 中记录的权限值,标记每个按钮是否勾选
 | 
			
		||||
     *
 | 
			
		||||
     * @param ext 扩展属性 JSON 字符串
 | 
			
		||||
     * @return 按钮权限 VO 列表
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public List<ButtonPermissionVo> buildButtonPermissionsFromExt(String ext) {
 | 
			
		||||
        // 解析 ext 为 Map<code, Set<value>>,用于标记权限
 | 
			
		||||
        Map<String, Set<String>> 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
 | 
			
		||||
            ));
 | 
			
		||||
 | 
			
		||||
        // 构建按钮权限列表,标记哪些按钮在 permissionMap 中出现(表示已勾选)
 | 
			
		||||
        return buildPermissionsFromSources(permissionMap, List.of(ButtonPermissionEnum.class));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 将权限映射与按钮权限来源(枚举类或字典类型)进行匹配,生成权限视图列表
 | 
			
		||||
     * <p>
 | 
			
		||||
     * 使用说明:
 | 
			
		||||
     * - sources 支持传入多个来源类型,支持 NodeExtEnum 枚举类 或 字典类型字符串(dictType)
 | 
			
		||||
     * - 若需要扩展更多按钮权限,只需在 sources 中新增对应的枚举类或字典类型
 | 
			
		||||
     * <p>
 | 
			
		||||
     * 示例:
 | 
			
		||||
     * buildPermissionsFromSources(permissionMap, List.of(ButtonPermissionEnum.class, "custom_button_dict"));
 | 
			
		||||
     *
 | 
			
		||||
     * @param permissionMap 权限映射
 | 
			
		||||
     * @param sources       枚举类或字典类型列表
 | 
			
		||||
     * @return 按钮权限视图对象列表
 | 
			
		||||
     */
 | 
			
		||||
    @SuppressWarnings("unchecked cast")
 | 
			
		||||
    private List<ButtonPermissionVo> buildPermissionsFromSources(Map<String, Set<String>> permissionMap, List<Object> sources) {
 | 
			
		||||
        return sources.stream()
 | 
			
		||||
            .flatMap(source -> {
 | 
			
		||||
                if (source instanceof Class<?> clazz && NodeExtEnum.class.isAssignableFrom(clazz)) {
 | 
			
		||||
                    Set<String> selectedSet = permissionMap.getOrDefault(clazz.getSimpleName(), Collections.emptySet());
 | 
			
		||||
                    return extractDictItems(this.buildChildNode((Class<? extends NodeExtEnum>) clazz), selectedSet).stream();
 | 
			
		||||
                } else if (source instanceof String dictType) {
 | 
			
		||||
                    Set<String> selectedSet = permissionMap.getOrDefault(dictType, Collections.emptySet());
 | 
			
		||||
                    return extractDictItems(this.buildChildNode(dictType), selectedSet).stream();
 | 
			
		||||
                }
 | 
			
		||||
                return Stream.empty();
 | 
			
		||||
            }).toList();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 从节点子项中提取字典项,并构建按钮权限视图对象列表
 | 
			
		||||
     *
 | 
			
		||||
     * @param childNode   子节点
 | 
			
		||||
     * @param selectedSet 已选中的值集
 | 
			
		||||
     * @return 按钮权限视图对象列表
 | 
			
		||||
     */
 | 
			
		||||
    private List<ButtonPermissionVo> extractDictItems(NodeExt.ChildNode childNode, Set<String> selectedSet) {
 | 
			
		||||
        return Optional.ofNullable(childNode)
 | 
			
		||||
            .map(NodeExt.ChildNode::getDict)
 | 
			
		||||
            .orElse(List.of())
 | 
			
		||||
            .stream()
 | 
			
		||||
            .map(dict -> new ButtonPermissionVo(dict.getValue(), selectedSet.contains(dict.getValue())))
 | 
			
		||||
            .toList();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -48,6 +48,7 @@ import org.dromara.workflow.handler.WorkflowPermissionHandler;
 | 
			
		||||
import org.dromara.workflow.mapper.FlwCategoryMapper;
 | 
			
		||||
import org.dromara.workflow.mapper.FlwTaskMapper;
 | 
			
		||||
import org.dromara.workflow.service.IFlwCommonService;
 | 
			
		||||
import org.dromara.workflow.service.IFlwNodeExtService;
 | 
			
		||||
import org.dromara.workflow.service.IFlwTaskAssigneeService;
 | 
			
		||||
import org.dromara.workflow.service.IFlwTaskService;
 | 
			
		||||
import org.springframework.stereotype.Service;
 | 
			
		||||
@@ -86,6 +87,7 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
 | 
			
		||||
    private final FlowNodeMapper flowNodeMapper;
 | 
			
		||||
    private final IFlwTaskAssigneeService flwTaskAssigneeService;
 | 
			
		||||
    private final IFlwCommonService flwCommonService;
 | 
			
		||||
    private final IFlwNodeExtService flwNodeExtService;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 启动任务
 | 
			
		||||
@@ -561,12 +563,12 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
 | 
			
		||||
        flowTaskVo.setFlowCode(definition.getFlowCode());
 | 
			
		||||
        flowTaskVo.setFlowName(definition.getFlowName());
 | 
			
		||||
        flowTaskVo.setBusinessId(instance.getBusinessId());
 | 
			
		||||
        //设置按钮权限
 | 
			
		||||
        FlowNode flowNode = getByNodeCode(flowTaskVo.getNodeCode(), instance.getDefinitionId());
 | 
			
		||||
        FlowNode flowNode = this.getByNodeCode(flowTaskVo.getNodeCode(), instance.getDefinitionId());
 | 
			
		||||
        if (ObjectUtil.isNull(flowNode)) {
 | 
			
		||||
            throw new NullPointerException("当前【" + flowTaskVo.getNodeCode() + "】节点编码不存在");
 | 
			
		||||
        }
 | 
			
		||||
        flowTaskVo.setButtonList(flowTaskVo.getButtonList(flowNode.getExt()));
 | 
			
		||||
        //设置按钮权限
 | 
			
		||||
        flowTaskVo.setButtonList(flwNodeExtService.buildButtonPermissionsFromExt(flowNode.getExt()));
 | 
			
		||||
        flowTaskVo.setNodeRatio(flowNode.getNodeRatio());
 | 
			
		||||
        flowTaskVo.setApplyNode(flowNode.getNodeCode().equals(flwCommonService.applyNodeCode(task.getDefinitionId())));
 | 
			
		||||
        return flowTaskVo;
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user