package org.dromara.workflow.service.impl;
|
|
import cn.hutool.core.bean.BeanUtil;
|
import cn.hutool.core.collection.CollUtil;
|
import cn.hutool.core.convert.Convert;
|
import cn.hutool.core.lang.Pair;
|
import cn.hutool.core.map.MapUtil;
|
import cn.hutool.core.util.StrUtil;
|
import lombok.RequiredArgsConstructor;
|
import lombok.extern.slf4j.Slf4j;
|
import org.dromara.common.core.domain.dto.DeptDTO;
|
import org.dromara.common.core.domain.dto.TaskAssigneeDTO;
|
import org.dromara.common.core.domain.dto.UserDTO;
|
import org.dromara.common.core.domain.model.TaskAssigneeBody;
|
import org.dromara.common.core.enums.FormatsType;
|
import org.dromara.common.core.service.*;
|
import org.dromara.common.core.utils.DateUtils;
|
import org.dromara.common.core.utils.StreamUtils;
|
import org.dromara.common.core.utils.StringUtils;
|
import org.dromara.warm.flow.ui.dto.HandlerFunDto;
|
import org.dromara.warm.flow.ui.dto.HandlerQuery;
|
import org.dromara.warm.flow.ui.dto.TreeFunDto;
|
import org.dromara.warm.flow.ui.service.HandlerSelectService;
|
import org.dromara.warm.flow.ui.vo.HandlerFeedBackVo;
|
import org.dromara.warm.flow.ui.vo.HandlerSelectVo;
|
import org.dromara.workflow.common.ConditionalOnEnable;
|
import org.dromara.workflow.common.enums.TaskAssigneeEnum;
|
import org.dromara.workflow.service.IFlwSpelService;
|
import org.dromara.workflow.service.IFlwTaskAssigneeService;
|
import org.springframework.stereotype.Service;
|
|
import java.util.*;
|
import java.util.stream.Collectors;
|
|
/**
|
* 流程设计器-获取办理人权限设置列表
|
*
|
* @author AprilWind
|
*/
|
@ConditionalOnEnable
|
@Slf4j
|
@RequiredArgsConstructor
|
@Service
|
public class FlwTaskAssigneeServiceImpl implements IFlwTaskAssigneeService, HandlerSelectService {
|
|
private static final String DEFAULT_GROUP_NAME = "默认分组";
|
private final TaskAssigneeService taskAssigneeService;
|
private final UserService userService;
|
private final DeptService deptService;
|
private final RoleService roleService;
|
private final PostService postService;
|
private final IFlwSpelService spelService;
|
|
/**
|
* 获取办理人权限设置列表tabs页签
|
*
|
* @return tabs页签
|
*/
|
@Override
|
public List<String> getHandlerType() {
|
return TaskAssigneeEnum.getAssigneeTypeList();
|
}
|
|
/**
|
* 获取办理列表, 同时构建左侧部门树状结构
|
*
|
* @param query 查询条件
|
* @return HandlerSelectVo
|
*/
|
@Override
|
public HandlerSelectVo getHandlerSelect(HandlerQuery query) {
|
// 获取任务办理类型
|
TaskAssigneeEnum type = TaskAssigneeEnum.fromDesc(query.getHandlerType());
|
// 转换查询条件为 TaskAssigneeBody
|
TaskAssigneeBody taskQuery = BeanUtil.toBean(query, TaskAssigneeBody.class);
|
|
// 统一查询并构建业务数据
|
TaskAssigneeDTO dto = fetchTaskAssigneeData(type, taskQuery);
|
List<DeptDTO> depts = fetchDeptData(type);
|
|
return getHandlerSelectVo(buildHandlerData(dto, type), buildDeptTree(depts));
|
}
|
|
/**
|
* 办理人权限名称回显
|
*
|
* @param storageIds 入库主键集合
|
* @return 结果
|
*/
|
@Override
|
public List<HandlerFeedBackVo> handlerFeedback(List<String> storageIds) {
|
if (CollUtil.isEmpty(storageIds)) {
|
return Collections.emptyList();
|
}
|
// 解析并归类 ID,同时记录原始顺序和对应解析结果
|
Map<TaskAssigneeEnum, List<String>> typeIdMap = new EnumMap<>(TaskAssigneeEnum.class);
|
Map<String, Pair<TaskAssigneeEnum, String>> parsedMap = new LinkedHashMap<>();
|
for (String storageId : storageIds) {
|
Pair<TaskAssigneeEnum, String> parsed = this.parseStorageId(storageId);
|
parsedMap.put(storageId, parsed);
|
if (parsed != null) {
|
typeIdMap.computeIfAbsent(parsed.getKey(), k -> new ArrayList<>()).add(parsed.getValue());
|
}
|
}
|
|
// 查询所有类型对应的 ID 名称映射
|
Map<TaskAssigneeEnum, Map<String, String>> nameMap = new EnumMap<>(TaskAssigneeEnum.class);
|
typeIdMap.forEach((type, ids) -> nameMap.put(type, this.getNamesByType(type, ids)));
|
// 组装返回结果,保持原始顺序
|
return parsedMap.entrySet().stream()
|
.map(entry -> {
|
String storageId = entry.getKey();
|
Pair<TaskAssigneeEnum, String> parsed = entry.getValue();
|
String handlerName = (parsed == null) ? null
|
: nameMap.getOrDefault(parsed.getKey(), Collections.emptyMap())
|
.get(parsed.getValue());
|
return new HandlerFeedBackVo(storageId, handlerName);
|
}).toList();
|
}
|
|
/**
|
* 根据任务办理类型查询对应的数据
|
*/
|
private TaskAssigneeDTO fetchTaskAssigneeData(TaskAssigneeEnum type, TaskAssigneeBody taskQuery) {
|
return switch (type) {
|
case USER -> taskAssigneeService.selectUsersByTaskAssigneeList(taskQuery);
|
case ROLE -> taskAssigneeService.selectRolesByTaskAssigneeList(taskQuery);
|
case DEPT -> taskAssigneeService.selectDeptsByTaskAssigneeList(taskQuery);
|
case POST -> taskAssigneeService.selectPostsByTaskAssigneeList(taskQuery);
|
case SPEL -> spelService.selectSpelByTaskAssigneeList(taskQuery);
|
};
|
}
|
|
/**
|
* 根据任务办理类型获取部门数据
|
*/
|
private List<DeptDTO> fetchDeptData(TaskAssigneeEnum type) {
|
if (type.needsDeptService()) {
|
return deptService.selectDeptsByList();
|
}
|
return new ArrayList<>();
|
}
|
|
/**
|
* 获取权限分组名称
|
*
|
* @param type 任务分配人枚举
|
* @param groupName 权限分组
|
* @return 权限分组名称
|
*/
|
private String getGroupName(TaskAssigneeEnum type, String groupName) {
|
if (StringUtils.isEmpty(groupName)) {
|
return DEFAULT_GROUP_NAME;
|
}
|
if (type.needsDeptService()) {
|
return deptService.selectDeptNameByIds(groupName);
|
}
|
return DEFAULT_GROUP_NAME;
|
}
|
|
/**
|
* 构建部门树状结构
|
*/
|
private TreeFunDto<DeptDTO> buildDeptTree(List<DeptDTO> depts) {
|
return new TreeFunDto<>(depts)
|
.setId(dept -> Convert.toStr(dept.getDeptId()))
|
.setName(DeptDTO::getDeptName)
|
.setParentId(dept -> Convert.toStr(dept.getParentId()));
|
}
|
|
/**
|
* 构建任务办理人数据
|
*/
|
private HandlerFunDto<TaskAssigneeDTO.TaskHandler> buildHandlerData(TaskAssigneeDTO dto, TaskAssigneeEnum type) {
|
return new HandlerFunDto<>(dto.getList(), dto.getTotal())
|
.setStorageId(assignee -> type.getCode() + assignee.getStorageId())
|
.setHandlerCode(assignee -> StringUtils.blankToDefault(assignee.getHandlerCode(), "无"))
|
.setHandlerName(assignee -> StringUtils.blankToDefault(assignee.getHandlerName(), "无"))
|
.setGroupName(assignee -> this.getGroupName(type, assignee.getGroupName()))
|
.setCreateTime(assignee -> DateUtils.parseDateToStr(FormatsType.YYYY_MM_DD_HH_MM_SS, assignee.getCreateTime()));
|
}
|
|
/**
|
* 批量解析多个存储标识符(storageIds),按类型分类并合并查询用户列表
|
* 输入格式支持多个以逗号分隔的标识(如 "user:123,role:456,789")
|
* 会自动去重返回结果,非法格式的标识将被忽略
|
*
|
* @param storageIds 多个存储标识符字符串(逗号分隔)
|
* @return 合并后的用户列表,去重后返回,非法格式的标识将被跳过
|
*/
|
@Override
|
public List<UserDTO> fetchUsersByStorageIds(String storageIds) {
|
if (StringUtils.isEmpty(storageIds)) {
|
return List.of();
|
}
|
Map<TaskAssigneeEnum, List<String>> typeIdMap = new EnumMap<>(TaskAssigneeEnum.class);
|
for (String storageId : storageIds.split(StringUtils.SEPARATOR)) {
|
Pair<TaskAssigneeEnum, String> parsed = this.parseStorageId(storageId);
|
if (parsed != null) {
|
typeIdMap.computeIfAbsent(parsed.getKey(), k -> new ArrayList<>()).add(parsed.getValue());
|
}
|
}
|
return typeIdMap.entrySet().stream()
|
.flatMap(entry -> this.getUsersByType(entry.getKey(), entry.getValue()).stream())
|
.distinct()
|
.toList();
|
}
|
|
/**
|
* 根据指定的任务分配类型(TaskAssigneeEnum)和 ID 列表,获取对应的用户信息列表
|
*
|
* @param type 任务分配类型,表示用户、角色、部门或其他(TaskAssigneeEnum 枚举值)
|
* @param ids 与指定分配类型关联的 ID 列表(例如用户ID、角色ID、部门ID等)
|
* @return 返回包含用户信息的列表。如果类型为用户(USER),则通过用户ID列表查询;
|
* 如果类型为角色(ROLE),则通过角色ID列表查询;
|
* 如果类型为部门(DEPT),则通过部门ID列表查询;
|
* 如果类型为岗位(POST)或无法识别的类型,则返回空列表
|
*/
|
private List<UserDTO> getUsersByType(TaskAssigneeEnum type, List<String> ids) {
|
if (type == TaskAssigneeEnum.SPEL) {
|
return new ArrayList<>();
|
}
|
List<Long> longIds = StreamUtils.toList(ids, Convert::toLong);
|
return switch (type) {
|
case USER -> userService.selectListByIds(longIds);
|
case ROLE -> userService.selectUsersByRoleIds(longIds);
|
case DEPT -> userService.selectUsersByDeptIds(longIds);
|
case POST -> userService.selectUsersByPostIds(longIds);
|
default -> new ArrayList<>();
|
};
|
}
|
|
/**
|
* 根据任务分配类型和对应 ID 列表,批量查询名称映射关系
|
*
|
* @param type 分配类型(用户、角色、部门、岗位)
|
* @param ids ID 列表(如用户ID、角色ID等)
|
* @return 返回 Map,其中 key 为 ID,value 为对应的名称
|
*/
|
private Map<String, String> getNamesByType(TaskAssigneeEnum type, List<String> ids) {
|
if (type == TaskAssigneeEnum.SPEL) {
|
return spelService.selectRemarksBySpels(ids);
|
}
|
|
List<Long> longIds = StreamUtils.toList(ids, Convert::toLong);
|
Map<Long, String> rawMap = switch (type) {
|
case USER -> userService.selectUserNamesByIds(longIds);
|
case ROLE -> roleService.selectRoleNamesByIds(longIds);
|
case DEPT -> deptService.selectDeptNamesByIds(longIds);
|
case POST -> postService.selectPostNamesByIds(longIds);
|
default -> Collections.emptyMap();
|
};
|
if (MapUtil.isEmpty(rawMap)) {
|
return Collections.emptyMap();
|
}
|
return rawMap.entrySet()
|
.stream()
|
.collect(Collectors.toMap(
|
e -> Convert.toStr(e.getKey()),
|
Map.Entry::getValue
|
));
|
}
|
|
/**
|
* 解析 storageId 字符串,返回类型和ID的组合
|
*
|
* @param storageId 例如 "user:123" 或 "456"
|
* @return Pair(TaskAssigneeEnum, Long),如果格式非法返回 null
|
*/
|
private Pair<TaskAssigneeEnum, String> parseStorageId(String storageId) {
|
if (StringUtils.isBlank(storageId)) {
|
return null;
|
}
|
if (TaskAssigneeEnum.isSpelExpression(storageId)) {
|
return Pair.of(TaskAssigneeEnum.SPEL, storageId);
|
}
|
try {
|
String[] parts = storageId.split(StrUtil.COLON, 2);
|
if (parts.length < 2) {
|
return Pair.of(TaskAssigneeEnum.USER, parts[0]);
|
} else {
|
TaskAssigneeEnum type = TaskAssigneeEnum.fromCode(parts[0] + StrUtil.COLON);
|
return Pair.of(type, parts[1]);
|
}
|
} catch (Exception e) {
|
log.warn("解析 storageId 失败,格式非法:{},错误信息:{}", storageId, e.getMessage());
|
return null;
|
}
|
}
|
|
}
|