diff --git a/continew-server/src/main/resources/templates/import/user.xlsx b/continew-server/src/main/resources/templates/import/user.xlsx index 03a9360f..bfff1337 100644 Binary files a/continew-server/src/main/resources/templates/import/user.xlsx and b/continew-server/src/main/resources/templates/import/user.xlsx differ diff --git a/continew-system/src/main/java/top/continew/admin/system/service/DeptService.java b/continew-system/src/main/java/top/continew/admin/system/service/DeptService.java index 12ef2d14..e4d45b9b 100644 --- a/continew-system/src/main/java/top/continew/admin/system/service/DeptService.java +++ b/continew-system/src/main/java/top/continew/admin/system/service/DeptService.java @@ -24,6 +24,7 @@ import top.continew.admin.system.model.resp.DeptResp; import top.continew.starter.data.service.IService; import java.util.List; +import java.util.Set; /** * 部门业务接口 @@ -55,5 +56,5 @@ public interface DeptService extends BaseService deptNames); + int countByNames(Set deptNames); } diff --git a/continew-system/src/main/java/top/continew/admin/system/service/impl/DeptServiceImpl.java b/continew-system/src/main/java/top/continew/admin/system/service/impl/DeptServiceImpl.java index aef2d9b6..86876d8a 100644 --- a/continew-system/src/main/java/top/continew/admin/system/service/impl/DeptServiceImpl.java +++ b/continew-system/src/main/java/top/continew/admin/system/service/impl/DeptServiceImpl.java @@ -38,10 +38,7 @@ import top.continew.starter.data.enums.DatabaseType; import top.continew.starter.data.util.MetaUtils; import javax.sql.DataSource; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Optional; +import java.util.*; /** * 部门业务实现 @@ -128,7 +125,7 @@ public class DeptServiceImpl extends BaseServiceImpl deptNames) { + public int countByNames(Set deptNames) { if (CollUtil.isEmpty(deptNames)) { return 0; } diff --git a/continew-system/src/main/java/top/continew/admin/system/service/impl/UserServiceImpl.java b/continew-system/src/main/java/top/continew/admin/system/service/impl/UserServiceImpl.java index e7e35ecd..16c49083 100644 --- a/continew-system/src/main/java/top/continew/admin/system/service/impl/UserServiceImpl.java +++ b/continew-system/src/main/java/top/continew/admin/system/service/impl/UserServiceImpl.java @@ -24,6 +24,8 @@ import cn.hutool.core.io.resource.ResourceUtil; import cn.hutool.core.lang.UUID; import cn.hutool.core.map.MapUtil; import cn.hutool.core.util.CharsetUtil; +import java.util.HashMap; +import java.util.Map; import cn.hutool.core.util.EnumUtil; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; @@ -264,10 +266,10 @@ public class UserServiceImpl extends BaseServiceImpl roleNames = validRowList.stream().map(UserImportRowReq::getRoleName).distinct().toList(); int existRoleCount = roleService.countByNames(roleNames); CheckUtils.throwIf(existRoleCount < roleNames.size(), "存在无效角色,请检查数据"); - // 校验是否存在无效部门 - List deptNames = CollUtils.mapToList(validRowList, UserImportRowReq::getDeptName); - int existDeptCount = deptService.countByNames(deptNames); - CheckUtils.throwIf(existDeptCount < deptNames.size(), "存在无效部门,请检查数据"); + // 校验是否存在无效部门(支持多级部门解析) + Set deptNames = CollUtils.mapToSet(validRowList, UserImportRowReq::getDeptName); + int existDeptCount = countValidMultiLevelDepts(deptNames); + CheckUtils.throwIf(existDeptCount < deptNames.size(), "存在无效部门,请检查部门名称或部门层级是否正确"); // 查询重复用户 userImportResp @@ -319,11 +321,11 @@ public class UserServiceImpl extends BaseServiceImpl roleMap = roleList.stream().collect(Collectors.toMap(RoleDO::getName, RoleDO::getId)); - List deptList = deptService.listByNames(importUserList.stream() + // 获取多级部门映射 + Map deptMap = buildMultiLevelDeptMapping(importUserList.stream() .map(UserImportRowReq::getDeptName) .distinct() .toList()); - Map deptMap = deptList.stream().collect(Collectors.toMap(DeptDO::getName, DeptDO::getId)); // 批量操作数据库集合 List insertList = new ArrayList<>(); @@ -731,4 +733,130 @@ public class UserServiceImpl extends BaseServiceImpl + * 支持多级部门路径解析,使用冒号(:)作为层级分隔符 + * 例如:公司A:研发部:前端组 或 研发部 + *

+ * + * @param deptNames 部门名称集合 + * @return 有效部门数量 + */ + private int countValidMultiLevelDepts(Set deptNames) { + CheckUtils.throwIfEmpty(deptNames, "部门名称集合不能为空"); + + int validCount = 0; + List invalidDepts = new ArrayList<>(); + + for (String deptName : deptNames) { + try { + findDeptByHierarchicalPath(deptName); + validCount++; + } catch (Exception e) { + invalidDepts.add(deptName); + } + } + + CheckUtils.throwIf(CollUtil.isNotEmpty(invalidDepts), "以下部门无效或存在歧义:{}", String.join(", ", invalidDepts)); + + return validCount; + } + + /** + * 构建多级部门映射关系 + *

+ * 将部门名称列表转换为部门名称到ID的映射,支持多级部门路径解析 + *

+ * + * @param deptNames 部门名称列表 + * @return 部门名称到ID的映射 + */ + private Map buildMultiLevelDeptMapping(List deptNames) { + CheckUtils.throwIfEmpty(deptNames, "部门名称列表不能为空"); + + Map deptMap = new HashMap<>(); + for (String deptName : deptNames) { + DeptDO dept = findDeptByHierarchicalPath(deptName); + CheckUtils.throwIfNull(dept, "部门 [{}] 不存在或存在歧义", deptName); + deptMap.put(deptName, dept.getId()); + } + return deptMap; + } + + /** + * 根据层级路径查找部门 + *

+ * 支持两种格式: + *

    + *
  • 多级部门:公司A:研发部:前端组
  • + *
  • 单级部门:研发部
  • + *
+ * 使用冒号(:)作为层级分隔符,会逐级查找对应的部门 + *

+ * + * @param deptPath 部门路径 + * @return 部门信息,未找到时返回null + */ + private DeptDO findDeptByHierarchicalPath(String deptPath) { + CheckUtils.throwIfBlank(deptPath, "部门路径不能为空"); + + // 根据是否包含冒号选择处理方式 + return deptPath.contains(":") ? findMultiLevelDept(deptPath) : findSingleLevelDept(deptPath.trim()); + } + + /** + * 查找多级部门 + *

+ * 从根部门开始逐级查找,确保部门层级关系正确 + *

+ * + * @param deptPath 多级部门路径 + * @return 部门信息,未找到时返回null + */ + private DeptDO findMultiLevelDept(String deptPath) { + String[] pathParts = deptPath.split(":"); + CheckUtils.throwIf(pathParts.length == 0, "部门路径格式错误:{}", deptPath); + + // 从根部门开始逐级查找 + DeptDO currentDept = null; + Long parentId = 0L; // 根部门的parentId为null + + for (String part : pathParts) { + String trimmedPart = part.trim(); + CheckUtils.throwIfBlank(trimmedPart, "部门路径包含空名称:{}", deptPath); + + // 查找当前层级下指定名称的部门 + currentDept = deptService.lambdaQuery() + .eq(DeptDO::getName, trimmedPart) + .eq(DeptDO::getParentId, parentId) + .one(); + + CheckUtils.throwIfNull(currentDept, "找不到部门 [{}] 在路径 [{}] 中", trimmedPart, deptPath); + parentId = currentDept.getId(); // 更新父级ID为当前部门ID + } + + return currentDept; + } + + /** + * 查找单级部门 + *

+ * 当只提供部门名称时,检查是否存在多个同名部门 + * 如果存在多个同名部门,则要求用户提供完整的层级路径 + *

+ * + * @param deptName 部门名称 + * @return 部门信息,未找到或存在歧义时返回null + */ + private DeptDO findSingleLevelDept(String deptName) { + // 查找所有同名部门 + List deptList = deptService.lambdaQuery().eq(DeptDO::getName, deptName).list(); + + CheckUtils.throwIfEmpty(deptList, "部门 [{}] 不存在", deptName); + CheckUtils.throwIf(deptList.size() > 1, "存在多个同名部门 [{}],请使用完整层级路径,如:公司名:{}", deptName, deptName); + + return deptList.get(0); + } }