From e84ef0f24433ab39032d9077af6b28d166190d49 Mon Sep 17 00:00:00 2001 From: cst61 Date: Tue, 19 May 2026 21:25:07 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9E=84=E5=BB=BA=E7=94=A8=E6=88=B7=E6=A0=91?= =?UTF-8?q?=E5=BD=A2=E7=BB=93=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../LbDepartmentUserController.java | 12 ++ .../rj/service/ILbDepartmentUserService.java | 5 + .../impl/LbAssessmentApplyServiceImpl.java | 4 +- .../impl/LbDepartmentUserServiceImpl.java | 151 ++++++++++++++++++ 4 files changed, 170 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/rj/controller/LbDepartmentUserController.java b/src/main/java/com/rj/controller/LbDepartmentUserController.java index a20ad87..bceac21 100644 --- a/src/main/java/com/rj/controller/LbDepartmentUserController.java +++ b/src/main/java/com/rj/controller/LbDepartmentUserController.java @@ -120,4 +120,16 @@ public class LbDepartmentUserController { } return ResponseEntity.badRequest().body(result); } + + @GetMapping("/tree") + @Operation(summary = "部门用户树形结构") + public ResponseEntity> tree( + @Parameter(description = "租户id", required = true) @RequestParam String tenantId) { + Map result = lbDepartmentUserService.getDepartmentUserTree(tenantId); + Boolean success = (Boolean) result.get("success"); + if (success != null && success) { + return ResponseEntity.ok(result); + } + return ResponseEntity.badRequest().body(result); + } } diff --git a/src/main/java/com/rj/service/ILbDepartmentUserService.java b/src/main/java/com/rj/service/ILbDepartmentUserService.java index 6e142c8..a049900 100644 --- a/src/main/java/com/rj/service/ILbDepartmentUserService.java +++ b/src/main/java/com/rj/service/ILbDepartmentUserService.java @@ -35,4 +35,9 @@ public interface ILbDepartmentUserService extends IService { * 从 lb_user 同步到 lb_department_user,并按 pid 构建 org_chain 上级链条。 */ Map syncFromLbUser(String tenantId); + + /** + * 按租户查询部门用户并构建父子树(parent_id 对应 lb_user.pid)。 + */ + Map getDepartmentUserTree(String tenantId); } diff --git a/src/main/java/com/rj/service/impl/LbAssessmentApplyServiceImpl.java b/src/main/java/com/rj/service/impl/LbAssessmentApplyServiceImpl.java index b1fe24c..359ad4d 100644 --- a/src/main/java/com/rj/service/impl/LbAssessmentApplyServiceImpl.java +++ b/src/main/java/com/rj/service/impl/LbAssessmentApplyServiceImpl.java @@ -433,7 +433,7 @@ public class LbAssessmentApplyServiceImpl String moderatorDateTimeText = formatModeratorConnectDateTime(record.getApplicationDatetime()); StringBuilder sb = new StringBuilder(); - sb.append(teacherName).append(" 老师,您好!\n"); + sb.append(teacherName).append(" ,您好!\n"); if (!assessmentDateTimeText.isEmpty()) { sb.append(assessmentDateTimeText).append("由您主评\n"); } else { @@ -442,7 +442,7 @@ public class LbAssessmentApplyServiceImpl sb.append("申评人: ").append(applicantName).append('\n'); sb.append("同事: ").append(colleagueName).append('\n'); sb.append("团队长: ").append(teamLeaderName).append('\n'); - sb.append("评估老师: ").append(teacherName).append("老师\n"); + sb.append("评估老师: ").append(teacherName).append("\n"); sb.append("主持人: ").append(moderatorName); if (!moderatorDateTimeText.isEmpty()) { sb.append(" ").append(moderatorDateTimeText); diff --git a/src/main/java/com/rj/service/impl/LbDepartmentUserServiceImpl.java b/src/main/java/com/rj/service/impl/LbDepartmentUserServiceImpl.java index d8ab0f2..21a7725 100644 --- a/src/main/java/com/rj/service/impl/LbDepartmentUserServiceImpl.java +++ b/src/main/java/com/rj/service/impl/LbDepartmentUserServiceImpl.java @@ -17,7 +17,9 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.util.ArrayList; +import java.util.Comparator; import java.util.HashSet; +import java.util.LinkedHashMap; import java.util.List; import java.time.LocalDate; import java.time.LocalDateTime; @@ -582,4 +584,153 @@ public class LbDepartmentUserServiceImpl extends ServiceImpl getDepartmentUserTree(String tenantId) { + Map result = new HashMap<>(); + try { + if (tenantId == null || tenantId.trim().isEmpty()) { + result.put("success", false); + result.put("message", "租户id不能为空"); + return result; + } + String tenantIdTrim = tenantId.trim(); + + List deptUsers = this.list( + new LambdaQueryWrapper() + .eq(LbDepartmentUser::getTenantId, tenantIdTrim)); + if (deptUsers == null || deptUsers.isEmpty()) { + result.put("success", true); + result.put("message", "查询成功"); + result.put("data", new ArrayList<>()); + result.put("total", 0); + result.put("tenantId", tenantIdTrim); + return result; + } + + Map userRecordMap = new LinkedHashMap<>(); + for (LbDepartmentUser row : deptUsers) { + String uid = trimToNull(row.getUserId()); + if (uid == null) { + continue; + } + LbDepartmentUser existing = userRecordMap.get(uid); + if (existing == null || isNewerDepartmentUser(row, existing)) { + userRecordMap.put(uid, row); + } + } + + Map userIdByRecordId = new HashMap<>(); + Set allUserIds = new HashSet<>(userRecordMap.keySet()); + for (LbDepartmentUser row : deptUsers) { + String rowId = trimToNull(row.getId()); + String uid = trimToNull(row.getUserId()); + if (rowId != null && uid != null) { + userIdByRecordId.put(rowId, uid); + } + } + + Map parentByUserId = new HashMap<>(); + for (LbDepartmentUser row : userRecordMap.values()) { + String uid = row.getUserId().trim(); + String parentUserId = resolveParentUserId(row, allUserIds, userIdByRecordId); + if (parentUserId != null) { + parentByUserId.put(uid, parentUserId); + } + } + + Map> nodeByUserId = new LinkedHashMap<>(); + for (LbDepartmentUser row : userRecordMap.values()) { + nodeByUserId.put(row.getUserId().trim(), toDepartmentUserTreeNode(row)); + } + + List> treeRoots = new ArrayList<>(); + for (Map.Entry> entry : nodeByUserId.entrySet()) { + String userId = entry.getKey(); + Map node = entry.getValue(); + String parentUserId = parentByUserId.get(userId); + Map parentNode = parentUserId == null ? null : nodeByUserId.get(parentUserId); + if (parentNode == null) { + treeRoots.add(node); + continue; + } + @SuppressWarnings("unchecked") + List> children = (List>) parentNode.get("children"); + children.add(node); + } + sortDepartmentUserTreeByName(treeRoots); + + result.put("success", true); + result.put("message", "查询成功"); + result.put("data", treeRoots); + result.put("total", nodeByUserId.size()); + result.put("tenantId", tenantIdTrim); + return result; + } catch (Exception e) { + result.put("success", false); + result.put("message", "查询树形结构异常:" + e.getMessage()); + return result; + } + } + + /** + * parent_id 兼容两种存法:父 user_id,或父记录 id(UUID)。 + */ + private static String resolveParentUserId(LbDepartmentUser row, + Set allUserIds, + Map userIdByRecordId) { + String parentRef = trimToNull(row.getParentId()); + if (parentRef == null) { + return null; + } + if (allUserIds.contains(parentRef)) { + return parentRef; + } + return userIdByRecordId.get(parentRef); + } + + private static Map toDepartmentUserTreeNode(LbDepartmentUser row) { + Map node = new LinkedHashMap<>(); + node.put("userId", trimToNull(row.getUserId())); + node.put("name", trimToNull(row.getName())); + node.put("phone", trimToNull(row.getPhone())); + node.put("joinDate", row.getJoinDate()); + node.put("children", new ArrayList>()); + return node; + } + + private static boolean isNewerDepartmentUser(LbDepartmentUser candidate, LbDepartmentUser existing) { + LocalDateTime candidateTime = candidate.getUpdateTime() != null + ? candidate.getUpdateTime() : candidate.getCreateTime(); + LocalDateTime existingTime = existing.getUpdateTime() != null + ? existing.getUpdateTime() : existing.getCreateTime(); + if (candidateTime == null) { + return false; + } + if (existingTime == null) { + return true; + } + return candidateTime.isAfter(existingTime); + } + + private static void sortDepartmentUserTreeByName(List> nodes) { + nodes.sort(Comparator.comparing( + (Map m) -> (String) m.get("name"), + Comparator.nullsLast(String::compareTo))); + for (Map node : nodes) { + @SuppressWarnings("unchecked") + List> children = (List>) node.get("children"); + if (children != null && !children.isEmpty()) { + sortDepartmentUserTreeByName(children); + } + } + } + + private static String trimToNull(String value) { + if (value == null) { + return null; + } + String trimmed = value.trim(); + return trimmed.isEmpty() ? null : trimmed; + } }