构建用户树形结构
This commit is contained in:
@@ -120,4 +120,16 @@ public class LbDepartmentUserController {
|
|||||||
}
|
}
|
||||||
return ResponseEntity.badRequest().body(result);
|
return ResponseEntity.badRequest().body(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GetMapping("/tree")
|
||||||
|
@Operation(summary = "部门用户树形结构")
|
||||||
|
public ResponseEntity<Map<String, Object>> tree(
|
||||||
|
@Parameter(description = "租户id", required = true) @RequestParam String tenantId) {
|
||||||
|
Map<String, Object> result = lbDepartmentUserService.getDepartmentUserTree(tenantId);
|
||||||
|
Boolean success = (Boolean) result.get("success");
|
||||||
|
if (success != null && success) {
|
||||||
|
return ResponseEntity.ok(result);
|
||||||
|
}
|
||||||
|
return ResponseEntity.badRequest().body(result);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,4 +35,9 @@ public interface ILbDepartmentUserService extends IService<LbDepartmentUser> {
|
|||||||
* 从 lb_user 同步到 lb_department_user,并按 pid 构建 org_chain 上级链条。
|
* 从 lb_user 同步到 lb_department_user,并按 pid 构建 org_chain 上级链条。
|
||||||
*/
|
*/
|
||||||
Map<String, Object> syncFromLbUser(String tenantId);
|
Map<String, Object> syncFromLbUser(String tenantId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按租户查询部门用户并构建父子树(parent_id 对应 lb_user.pid)。
|
||||||
|
*/
|
||||||
|
Map<String, Object> getDepartmentUserTree(String tenantId);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -433,7 +433,7 @@ public class LbAssessmentApplyServiceImpl
|
|||||||
String moderatorDateTimeText = formatModeratorConnectDateTime(record.getApplicationDatetime());
|
String moderatorDateTimeText = formatModeratorConnectDateTime(record.getApplicationDatetime());
|
||||||
|
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
sb.append(teacherName).append(" 老师,您好!\n");
|
sb.append(teacherName).append(" ,您好!\n");
|
||||||
if (!assessmentDateTimeText.isEmpty()) {
|
if (!assessmentDateTimeText.isEmpty()) {
|
||||||
sb.append(assessmentDateTimeText).append("由您主评\n");
|
sb.append(assessmentDateTimeText).append("由您主评\n");
|
||||||
} else {
|
} else {
|
||||||
@@ -442,7 +442,7 @@ public class LbAssessmentApplyServiceImpl
|
|||||||
sb.append("申评人: ").append(applicantName).append('\n');
|
sb.append("申评人: ").append(applicantName).append('\n');
|
||||||
sb.append("同事: ").append(colleagueName).append('\n');
|
sb.append("同事: ").append(colleagueName).append('\n');
|
||||||
sb.append("团队长: ").append(teamLeaderName).append('\n');
|
sb.append("团队长: ").append(teamLeaderName).append('\n');
|
||||||
sb.append("评估老师: ").append(teacherName).append("老师\n");
|
sb.append("评估老师: ").append(teacherName).append("\n");
|
||||||
sb.append("主持人: ").append(moderatorName);
|
sb.append("主持人: ").append(moderatorName);
|
||||||
if (!moderatorDateTimeText.isEmpty()) {
|
if (!moderatorDateTimeText.isEmpty()) {
|
||||||
sb.append(" ").append(moderatorDateTimeText);
|
sb.append(" ").append(moderatorDateTimeText);
|
||||||
|
|||||||
@@ -17,7 +17,9 @@ import org.springframework.stereotype.Service;
|
|||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Comparator;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
@@ -582,4 +584,153 @@ public class LbDepartmentUserServiceImpl extends ServiceImpl<LbDepartmentUserMap
|
|||||||
}
|
}
|
||||||
return user.getId() == null ? null : String.valueOf(user.getId());
|
return user.getId() == null ? null : String.valueOf(user.getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, Object> getDepartmentUserTree(String tenantId) {
|
||||||
|
Map<String, Object> 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<LbDepartmentUser> deptUsers = this.list(
|
||||||
|
new LambdaQueryWrapper<LbDepartmentUser>()
|
||||||
|
.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<String, LbDepartmentUser> 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<String, String> userIdByRecordId = new HashMap<>();
|
||||||
|
Set<String> 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<String, String> 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<String, Map<String, Object>> nodeByUserId = new LinkedHashMap<>();
|
||||||
|
for (LbDepartmentUser row : userRecordMap.values()) {
|
||||||
|
nodeByUserId.put(row.getUserId().trim(), toDepartmentUserTreeNode(row));
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Map<String, Object>> treeRoots = new ArrayList<>();
|
||||||
|
for (Map.Entry<String, Map<String, Object>> entry : nodeByUserId.entrySet()) {
|
||||||
|
String userId = entry.getKey();
|
||||||
|
Map<String, Object> node = entry.getValue();
|
||||||
|
String parentUserId = parentByUserId.get(userId);
|
||||||
|
Map<String, Object> parentNode = parentUserId == null ? null : nodeByUserId.get(parentUserId);
|
||||||
|
if (parentNode == null) {
|
||||||
|
treeRoots.add(node);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
List<Map<String, Object>> children = (List<Map<String, Object>>) 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<String> allUserIds,
|
||||||
|
Map<String, String> userIdByRecordId) {
|
||||||
|
String parentRef = trimToNull(row.getParentId());
|
||||||
|
if (parentRef == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (allUserIds.contains(parentRef)) {
|
||||||
|
return parentRef;
|
||||||
|
}
|
||||||
|
return userIdByRecordId.get(parentRef);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Map<String, Object> toDepartmentUserTreeNode(LbDepartmentUser row) {
|
||||||
|
Map<String, Object> 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<Map<String, Object>>());
|
||||||
|
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<Map<String, Object>> nodes) {
|
||||||
|
nodes.sort(Comparator.comparing(
|
||||||
|
(Map<String, Object> m) -> (String) m.get("name"),
|
||||||
|
Comparator.nullsLast(String::compareTo)));
|
||||||
|
for (Map<String, Object> node : nodes) {
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
List<Map<String, Object>> children = (List<Map<String, Object>>) 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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user