From 700f9d0da314a4ea701fe9f68d305b67d72ec5fb Mon Sep 17 00:00:00 2001
From: longz <longzhaoz@qq.com>
Date: 星期三, 08 七月 2026 15:08:37 +0800
Subject: [PATCH] 各类修复fix

---
 backend/src/main/java/com/sinata/appointment/service/StaffManageApplicationService.java |  156 +++++++++++++++++++++++++++++++++++++--------------
 1 files changed, 113 insertions(+), 43 deletions(-)

diff --git a/backend/src/main/java/com/sinata/appointment/service/StaffManageApplicationService.java b/backend/src/main/java/com/sinata/appointment/service/StaffManageApplicationService.java
index 3b5e5b0..7e8acfc 100644
--- a/backend/src/main/java/com/sinata/appointment/service/StaffManageApplicationService.java
+++ b/backend/src/main/java/com/sinata/appointment/service/StaffManageApplicationService.java
@@ -45,6 +45,7 @@
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
@@ -131,7 +132,7 @@
         q.like(StringUtils.hasText(staffNo), MpUser::getStaffNo, staffNo != null ? staffNo.trim() : null);
         q.like(StringUtils.hasText(mobile), MpUser::getMobile, mobile != null ? mobile.trim() : null);
         if ("LEADER".equalsIgnoreCase(position)) {
-            q.eq(MpUser::getDeptLeaderFlag, true);
+            q.apply("1 = 0");
         } else if ("STAFF".equalsIgnoreCase(position)) {
             q.and(
                     w ->
@@ -165,9 +166,12 @@
             }
             userIds.add(u.getId());
         }
+        List<SysDept> allDepts = sysDeptMapper.selectList(
+                new LambdaQueryWrapper<SysDept>().eq(SysDept::getDelFlag, 0));
+        Map<Long, String> deptPaths = buildDeptPathById(allDepts);
         Map<Long, String> deptNames = deptNamesByIds(deptIds);
         Map<Long, String> groupDisplay = groupDisplayByMpUserIds(userIds);
-        return p.convert(u -> toListVo(u, deptNames, groupDisplay.getOrDefault(u.getId(), "—")));
+        return p.convert(u -> toListVo(u, deptNames, deptPaths, groupDisplay.getOrDefault(u.getId(), "—")));
     }
 
     private Set<Long> mpUserIdsInStaffGroup(Long staffGroupId) {
@@ -363,7 +367,7 @@
         u.setMobile(mobileRaw);
         u.setAvatarUrl(trimToNull(req.getAvatarUrl()));
         u.setDeptId(req.getDeptId());
-        u.setDeptLeaderFlag(Boolean.TRUE.equals(req.getDeptLeader()));
+        u.setDeptLeaderFlag(false);
         u.setStatus(1);
         mpUserMapper.insert(u);
         MpUser fresh = mpUserMapper.selectById(u.getId());
@@ -398,7 +402,7 @@
         u.setAvatarUrl(trimToNull(req.getAvatarUrl()));
         u.setMobile(mobileRaw);
         u.setDeptId(req.getDeptId());
-        u.setDeptLeaderFlag(Boolean.TRUE.equals(req.getDeptLeader()));
+        u.setDeptLeaderFlag(false);
         mpUserMapper.updateById(u);
     }
 
@@ -476,11 +480,13 @@
                                 .eq(SysDept::getStatus, 1)
                                 .orderByAsc(SysDept::getSortOrder)
                                 .orderByAsc(SysDept::getId));
-        List<String> deptNames =
+        Map<Long, String> deptPathById = buildDeptPathById(depts);
+        List<String> deptPaths =
                 depts.stream()
-                        .map(SysDept::getDeptName)
+                        .map(SysDept::getId)
+                        .map(deptPathById::get)
                         .filter(StringUtils::hasText)
-                        .map(String::trim)
+                        .distinct()
                         .toList();
         List<String> groupNames = loadActiveGroupNames();
 
@@ -489,8 +495,8 @@
         ex.setRealName("张三");
         ex.setStaffNo("EMP001");
         ex.setMobile("13800138000");
-        if (!deptNames.isEmpty()) {
-            ex.setDept(deptNames.get(0));
+        if (!deptPaths.isEmpty()) {
+            ex.setDept(deptPaths.get(0));
         }
         ex.setPosition("员工");
         if (!groupNames.isEmpty()) {
@@ -506,16 +512,16 @@
                             .registerWriteHandler(new HideDictSheetHandler())
                             .build();
             try {
-                var dictSheet = EasyExcel.writerSheet("字典").needHead(false).build();
-                writer.write(buildDictRows(deptNames, groupNames), dictSheet);
-
                 var dataSheet =
                         EasyExcel.writerSheet("员工导入")
                                 .head(StaffImportExcelRow.class)
                                 .registerWriteHandler(
-                                        new StaffTemplateDropdownHandler(deptNames, groupNames))
+                                        new StaffTemplateDropdownHandler(deptPaths, groupNames))
                                 .build();
                 writer.write(demo, dataSheet);
+
+                var dictSheet = EasyExcel.writerSheet("字典").needHead(false).build();
+                writer.write(buildDictRows(deptPaths, groupNames), dictSheet);
             } finally {
                 writer.finish();
             }
@@ -531,15 +537,22 @@
             vo.getErrors().add("文件为空");
             return vo;
         }
-        Map<String, Long> deptNameToId = new HashMap<>();
+        Map<String, Long> deptPathToId = new HashMap<>();
+        Map<String, List<Long>> deptNameToIds = new HashMap<>();
         List<SysDept> depts =
                 sysDeptMapper.selectList(
                         new LambdaQueryWrapper<SysDept>()
                                 .eq(SysDept::getDelFlag, 0)
                                 .eq(SysDept::getStatus, 1));
+        Map<Long, String> deptPathById = buildDeptPathById(depts);
         for (SysDept d : depts) {
+            String path = deptPathById.get(d.getId());
+            if (StringUtils.hasText(path)) {
+                deptPathToId.put(path.trim(), d.getId());
+            }
             if (StringUtils.hasText(d.getDeptName())) {
-                deptNameToId.put(d.getDeptName().trim(), d.getId());
+                String deptName = d.getDeptName().trim();
+                deptNameToIds.computeIfAbsent(deptName, k -> new ArrayList<>()).add(d.getId());
             }
         }
 
@@ -551,7 +564,7 @@
                         public void invoke(StaffImportExcelRow row, AnalysisContext context) {
                             rowIndex++;
                             try {
-                                handleImportRow(rowIndex, row, deptNameToId);
+                                handleImportRow(rowIndex, row, deptPathToId, deptNameToIds);
                                 vo.setSuccess(vo.getSuccess() + 1);
                             } catch (StopRowException ignored) {
                             } catch (BizException e) {
@@ -574,7 +587,11 @@
         return vo;
     }
 
-    private void handleImportRow(int lineNo, StaffImportExcelRow row, Map<String, Long> deptNameToId) {
+    private void handleImportRow(
+            int lineNo,
+            StaffImportExcelRow row,
+            Map<String, Long> deptPathToId,
+            Map<String, List<Long>> deptNameToIds) {
         String name = row.getRealName() == null ? "" : row.getRealName().trim();
         String staffNo = row.getStaffNo() == null ? "" : row.getStaffNo().trim();
         String mobile = row.getMobile() == null ? "" : row.getMobile().trim();
@@ -595,15 +612,15 @@
             throw new BizException(BizErrorCode.AUTH_INVALID_CREDENTIALS, "员工姓名、联系方式、所属部门不能为空");
         }
 
-        Long deptId = parseDeptId(dept, deptNameToId);
-        boolean leader = parseDeptLeader(position);
+        Long deptId = parseDeptId(dept, deptPathToId, deptNameToIds);
+        parseDeptLeader(position);
 
         StaffCreateRequest req = new StaffCreateRequest();
         req.setNickName(name);
         req.setStaffNo(StringUtils.hasText(staffNo) ? staffNo : null);
         req.setMobile(mobile);
         req.setDeptId(deptId);
-        req.setDeptLeader(leader);
+        req.setDeptLeader(false);
         Map<String, Object> created = create(req);
         Object idObj = created.get("id");
         Long uid = idObj instanceof Number ? ((Number) idObj).longValue() : null;
@@ -614,12 +631,12 @@
 
     private static final class StopRowException extends RuntimeException {}
 
-    private static List<List<String>> buildDictRows(List<String> deptNames, List<String> groupNames) {
-        int max = Math.max(Math.max(deptNames.size(), groupNames.size()), 2);
+    private static List<List<String>> buildDictRows(List<String> deptPaths, List<String> groupNames) {
+        int max = Math.max(Math.max(deptPaths.size(), groupNames.size()), 2);
         List<List<String>> rows = new ArrayList<>();
         for (int i = 0; i < max; i++) {
-            String dept = i < deptNames.size() ? deptNames.get(i) : "";
-            String pos = i == 0 ? "部门负责人" : (i == 1 ? "员工" : "");
+            String dept = i < deptPaths.size() ? deptPaths.get(i) : "";
+            String pos = i == 0 ? "员工" : "";
             String grp = i < groupNames.size() ? groupNames.get(i) : "";
             rows.add(java.util.Arrays.asList(dept, pos, grp));
         }
@@ -638,11 +655,11 @@
     }
 
     private static final class StaffTemplateDropdownHandler implements SheetWriteHandler {
-        private final List<String> deptNames;
+        private final List<String> deptPaths;
         private final List<String> groupNames;
 
-        private StaffTemplateDropdownHandler(List<String> deptNames, List<String> groupNames) {
-            this.deptNames = deptNames != null ? deptNames : List.of();
+        private StaffTemplateDropdownHandler(List<String> deptPaths, List<String> groupNames) {
+            this.deptPaths = deptPaths != null ? deptPaths : List.of();
             this.groupNames = groupNames != null ? groupNames : List.of();
         }
 
@@ -651,14 +668,14 @@
             Sheet sheet = writeSheetHolder.getSheet();
             Workbook wb = writeWorkbookHolder.getWorkbook();
 
-            if (!deptNames.isEmpty()) {
+            if (!deptPaths.isEmpty()) {
                 Name deptRange = wb.createName();
                 deptRange.setNameName("dept_list");
-                deptRange.setRefersToFormula("字典!$A$1:$A$" + deptNames.size());
+                deptRange.setRefersToFormula("字典!$A$1:$A$" + deptPaths.size());
             }
             Name posRange = wb.createName();
             posRange.setNameName("pos_list");
-            posRange.setRefersToFormula("字典!$B$1:$B$2");
+            posRange.setRefersToFormula("字典!$B$1:$B$1");
             if (!groupNames.isEmpty()) {
                 Name groupRange = wb.createName();
                 groupRange.setNameName("group_list");
@@ -669,7 +686,7 @@
             int startRow = 1;
             int endRow = 500;
 
-            if (!deptNames.isEmpty()) {
+            if (!deptPaths.isEmpty()) {
                 DataValidationConstraint deptConstraint = helper.createFormulaListConstraint("dept_list");
                 CellRangeAddressList deptAddr = new CellRangeAddressList(startRow, endRow, 3, 3);
                 DataValidation dvDept = helper.createValidation(deptConstraint, deptAddr);
@@ -693,7 +710,8 @@
         }
     }
 
-    private static Long parseDeptId(String dept, Map<String, Long> deptNameToId) {
+    private static Long parseDeptId(
+            String dept, Map<String, Long> deptPathToId, Map<String, List<Long>> deptNameToIds) {
         if (!StringUtils.hasText(dept)) {
             return null;
         }
@@ -702,11 +720,64 @@
             return Long.parseLong(t);
         } catch (Exception ignored) {
         }
-        Long id = deptNameToId.get(t);
-        if (id == null) {
-            throw new BizException(BizErrorCode.AUTH_INVALID_CREDENTIALS, "所属部门不存在: " + t);
+        Long pathMatchedId = deptPathToId.get(t);
+        if (pathMatchedId != null) {
+            return pathMatchedId;
         }
-        return id;
+        List<Long> nameMatchedIds = deptNameToIds.getOrDefault(t, List.of());
+        if (nameMatchedIds.size() == 1) {
+            return nameMatchedIds.get(0);
+        }
+        if (nameMatchedIds.size() > 1) {
+            throw new BizException(
+                    BizErrorCode.AUTH_INVALID_CREDENTIALS,
+                    "所属部门名称重复,请使用全路径(示例:A公司/财务部): " + t);
+        }
+        throw new BizException(BizErrorCode.AUTH_INVALID_CREDENTIALS, "所属部门不存在: " + t);
+    }
+
+    private static Map<Long, String> buildDeptPathById(List<SysDept> depts) {
+        if (depts == null || depts.isEmpty()) {
+            return Map.of();
+        }
+        Map<Long, SysDept> byId = new LinkedHashMap<>();
+        for (SysDept dept : depts) {
+            byId.put(dept.getId(), dept);
+        }
+        Map<Long, String> cache = new HashMap<>();
+        for (SysDept dept : depts) {
+            resolveDeptPath(dept.getId(), byId, cache, new HashSet<>());
+        }
+        return cache;
+    }
+
+    private static String resolveDeptPath(
+            Long deptId,
+            Map<Long, SysDept> byId,
+            Map<Long, String> cache,
+            Set<Long> visiting) {
+        if (deptId == null || deptId <= 0) {
+            return "";
+        }
+        String cached = cache.get(deptId);
+        if (cached != null) {
+            return cached;
+        }
+        SysDept current = byId.get(deptId);
+        if (current == null) {
+            return "";
+        }
+        String self = StringUtils.hasText(current.getDeptName()) ? current.getDeptName().trim() : "";
+        Long parentId = current.getParentId();
+        if (parentId == null || parentId <= 0 || parentId.equals(deptId) || !visiting.add(deptId)) {
+            cache.put(deptId, self);
+            return self;
+        }
+        String parentPath = resolveDeptPath(parentId, byId, cache, visiting);
+        visiting.remove(deptId);
+        String path = StringUtils.hasText(parentPath) ? (parentPath + "/" + self) : self;
+        cache.put(deptId, path);
+        return path;
     }
 
     private static boolean parseDeptLeader(String position) {
@@ -714,9 +785,6 @@
             return false;
         }
         String t = position.trim();
-        if ("部门负责人".equals(t) || "LEADER".equalsIgnoreCase(t)) {
-            return true;
-        }
         if ("员工".equals(t) || "STAFF".equalsIgnoreCase(t)) {
             return false;
         }
@@ -732,7 +800,7 @@
         exist.setAvatarUrl(trimToNull(req.getAvatarUrl()));
         exist.setMobile(mobileRaw);
         exist.setDeptId(req.getDeptId());
-        exist.setDeptLeaderFlag(Boolean.TRUE.equals(req.getDeptLeader()));
+        exist.setDeptLeaderFlag(false);
         exist.setStatus(1);
         mpUserMapper.updateById(exist);
     }
@@ -810,7 +878,7 @@
         return m;
     }
 
-    private StaffListVo toListVo(MpUser u, Map<Long, String> deptNames, String groupDisplay) {
+    private StaffListVo toListVo(MpUser u, Map<Long, String> deptNames, Map<Long, String> deptPaths, String groupDisplay) {
         StaffListVo vo = new StaffListVo();
         vo.setId(u.getId());
         vo.setUuid(u.getUuid());
@@ -821,7 +889,9 @@
         vo.setDeptId(u.getDeptId());
         vo.setDeptName(
                 u.getDeptId() == null ? "—" : deptNames.getOrDefault(u.getDeptId(), "—"));
-        vo.setPositionLabel(Boolean.TRUE.equals(u.getDeptLeaderFlag()) ? "部门负责人" : "员工");
+        vo.setDeptPath(
+                u.getDeptId() == null ? "—" : deptPaths.getOrDefault(u.getDeptId(), "—"));
+        vo.setPositionLabel("员工");
         vo.setGroupDisplay(groupDisplay);
         vo.setStatus(u.getStatus() == null ? 1 : u.getStatus());
         vo.setCreateTime(u.getCreateTime());
@@ -837,7 +907,7 @@
         vo.setAvatarUrl(u.getAvatarUrl());
         vo.setMobile(u.getMobile());
         vo.setDeptId(u.getDeptId());
-        vo.setDeptLeader(Boolean.TRUE.equals(u.getDeptLeaderFlag()));
+        vo.setDeptLeader(false);
         vo.setStatus(u.getStatus() == null ? 1 : u.getStatus());
         vo.setGroupNames(loadGroupNamesForUser(u.getId()));
         return vo;

--
Gitblit v1.7.1