From a39f6446d7954cea78d61d9f7254096c5296631e Mon Sep 17 00:00:00 2001
From: kiki1373639299
Date: Sun, 21 Sep 2025 19:00:26 +0800
Subject: [PATCH] =?UTF-8?q?fix(system/dept):=20=E4=BF=AE=E5=A4=8D=E7=B3=BB?=
=?UTF-8?q?=E7=BB=9F=E7=94=A8=E6=88=B7=E5=AF=BC=E5=85=A5=E6=8F=90=E7=A4=BA?=
=?UTF-8?q?=E3=80=90=E5=AD=98=E5=9C=A8=E6=97=A0=E6=95=88=E9=83=A8=E9=97=A8?=
=?UTF-8?q?=E3=80=91=E4=B8=94=E6=96=B0=E5=A2=9E=E6=94=AF=E6=8C=81=E5=A4=9A?=
=?UTF-8?q?=E7=BA=A7=E9=83=A8=E9=97=A8=E5=AF=BC=E5=85=A5?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Co-authored-by: kiki1373639299
# message auto-generated for no-merge-commit merge:
merge import-uesr into dev
fix: 修复系统用户导入提示【存在无效部门】且新增支持多级部门导入
Created-by: kiki1373639299
Commit-by: kiki1373639299
Merged-by: Charles_7c
Description:
## PR 类型
- [ ] 新 feature
- [X] Bug 修复
- [ ] 功能增强
- [ ] 文档变更
- [ ] 代码样式变更
- [ ] 重构
- [ ] 性能改进
- [ ] 单元测试
- [ ] CI/CD
- [ ] 其他
## PR 目的
## 解决方案
## PR 测试
## Changelog
| 模块 | Changelog | Related issues |
|-----|-----------| -------------- |
| 系统管理 - 用户导入 | 修复:解决用户导入时部门名称重复导致的"存在无效部门"错误,支持不同公司下同名部门区分 | Fixes #ICUHCT |
| 系统管理 - 用户导入 | 新增:支持多级部门导入功能,使用冒号(:)分隔层级,如公司A:研发部:前端组,优化错误提示和代码结构 | |
## 其他信息
## 提交前确认
- [X] PR 代码经过了完整测试,并且通过了代码规范检查
- [X] 已经完整填写 Changelog,并链接到了相关 issues
- [X] PR 代码将要提交到 dev 分支
See merge request: continew/continew-admin!13
---
.../main/resources/templates/import/user.xlsx | Bin 10085 -> 11943 bytes
.../admin/system/service/DeptService.java | 3 +-
.../system/service/impl/DeptServiceImpl.java | 7 +-
.../system/service/impl/UserServiceImpl.java | 140 +++++++++++++++++-
4 files changed, 138 insertions(+), 12 deletions(-)
diff --git a/continew-server/src/main/resources/templates/import/user.xlsx b/continew-server/src/main/resources/templates/import/user.xlsx
index 03a9360f3ee9da50a287a10994be9f2ecb92ab83..bfff1337aa663885d3a0af97a5bc122593ab1897 100644
GIT binary patch
delta 8256
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
delta 6533
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
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);
+ }
}