构造属性结构
This commit is contained in:
@@ -3,6 +3,7 @@ package com.rj.service.impl;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.rj.dto.LbBuyerTradeStats;
|
||||
import com.rj.entity.LbDailyUserTrade;
|
||||
import com.rj.entity.LbDepartmentUser;
|
||||
import com.rj.entity.LbOrderRow;
|
||||
@@ -492,27 +493,7 @@ public class LbDepartmentUserServiceImpl extends ServiceImpl<LbDepartmentUserMap
|
||||
}
|
||||
}
|
||||
|
||||
Set<String> tradeActiveUserIds = new HashSet<>();
|
||||
Map<String, LbOrderRow> latestOrderByBuyerId = new HashMap<>();
|
||||
List<LbOrderRow> orderRows = lbOrderRowMapper.selectList(
|
||||
new LambdaQueryWrapper<LbOrderRow>()
|
||||
.eq(LbOrderRow::getTenantId, tenantIdTrim)
|
||||
.eq(LbOrderRow::getDataType, ORDER_DATA_TYPE_DETAIL)
|
||||
.isNotNull(LbOrderRow::getBuyerId)
|
||||
.isNotNull(LbOrderRow::getPayTime));
|
||||
if (orderRows != null) {
|
||||
for (LbOrderRow row : orderRows) {
|
||||
if (!isPaidOrderRow(row)) {
|
||||
continue;
|
||||
}
|
||||
String buyerUserId = String.valueOf(row.getBuyerId());
|
||||
tradeActiveUserIds.add(buyerUserId);
|
||||
LbOrderRow prev = latestOrderByBuyerId.get(buyerUserId);
|
||||
if (prev == null || isOrderPayTimeNewer(row, prev)) {
|
||||
latestOrderByBuyerId.put(buyerUserId, row);
|
||||
}
|
||||
}
|
||||
}
|
||||
Map<String, LbBuyerTradeStats> tradeStatsByUserId = loadBuyerTradeStatsFromOrderRow(tenantIdTrim);
|
||||
|
||||
List<LbDepartmentUser> toInsert = new ArrayList<>();
|
||||
List<LbDepartmentUser> toUpdate = new ArrayList<>();
|
||||
@@ -556,16 +537,17 @@ public class LbDepartmentUserServiceImpl extends ServiceImpl<LbDepartmentUserMap
|
||||
entity.setOrgChain(buildOrgChain(lbUser.getId(), userById));
|
||||
|
||||
|
||||
LbOrderRow latestOrder = latestOrderByBuyerId.get(userId);
|
||||
if (latestOrder != null) {
|
||||
entity.setLastTradeDate(parseOrderTimeToDate(latestOrder.getPayTime()));
|
||||
entity.setLastBuyAmt(latestOrder.getTotalMoney());
|
||||
LbBuyerTradeStats tradeStats = tradeStatsByUserId.get(userId);
|
||||
if (tradeStats != null) {
|
||||
entity.setLastTradeDate(parseOrderTimeToDate(tradeStats.getPayTime()));
|
||||
entity.setLastBuyAmt(tradeStats.getTotalMoney());
|
||||
entity.setIsActive(1);
|
||||
} else {
|
||||
entity.setLastTradeDate(null);
|
||||
entity.setLastBuyAmt(null);
|
||||
entity.setIsActive(0);
|
||||
}
|
||||
entity.setUpdateTime(now);
|
||||
entity.setIsActive(tradeActiveUserIds.contains(userId) ? 1 : 0);
|
||||
|
||||
if (isInsert) {
|
||||
toInsert.add(entity);
|
||||
@@ -654,7 +636,7 @@ public class LbDepartmentUserServiceImpl extends ServiceImpl<LbDepartmentUserMap
|
||||
.replace(ORG_CHAIN_NODE_SEPARATOR, "");
|
||||
}
|
||||
|
||||
private String resolveDisplayName(LbUser user) {
|
||||
private static String resolveDisplayName(LbUser user) {
|
||||
if (user.getNickname() != null && !user.getNickname().trim().isEmpty()) {
|
||||
return user.getNickname().trim();
|
||||
}
|
||||
@@ -675,19 +657,9 @@ public class LbDepartmentUserServiceImpl extends ServiceImpl<LbDepartmentUserMap
|
||||
}
|
||||
String tenantIdTrim = tenantId.trim();
|
||||
|
||||
LambdaQueryWrapper<LbDepartmentUser> queryWrapper = new LambdaQueryWrapper<LbDepartmentUser>()
|
||||
.eq(LbDepartmentUser::getTenantId, tenantIdTrim);
|
||||
if (isActive != null) {
|
||||
queryWrapper.eq(LbDepartmentUser::getIsActive, isActive);
|
||||
}
|
||||
if (joinDate != null) {
|
||||
queryWrapper.gt(LbDepartmentUser::getJoinDate, joinDate);
|
||||
}
|
||||
if (lastTradeDate != null) {
|
||||
queryWrapper.gt(LbDepartmentUser::getLastTradeDate, lastTradeDate);
|
||||
}
|
||||
List<LbDepartmentUser> deptUsers = this.list(queryWrapper);
|
||||
if (deptUsers == null || deptUsers.isEmpty()) {
|
||||
List<LbUser> lbUsers = lbUserMapper.selectList(
|
||||
new LambdaQueryWrapper<LbUser>().eq(LbUser::getTenantId, tenantIdTrim));
|
||||
if (lbUsers == null || lbUsers.isEmpty()) {
|
||||
result.put("success", true);
|
||||
result.put("message", "查询成功");
|
||||
result.put("data", new ArrayList<>());
|
||||
@@ -696,40 +668,67 @@ public class LbDepartmentUserServiceImpl extends ServiceImpl<LbDepartmentUserMap
|
||||
return result;
|
||||
}
|
||||
|
||||
Map<String, LbDepartmentUser> userRecordMap = new LinkedHashMap<>();
|
||||
for (LbDepartmentUser row : deptUsers) {
|
||||
String uid = trimToNull(row.getUserId());
|
||||
if (uid == null) {
|
||||
Map<String, LbUser> userById = new LinkedHashMap<>();
|
||||
for (LbUser lbUser : lbUsers) {
|
||||
if (lbUser.getId() != null) {
|
||||
userById.put(String.valueOf(lbUser.getId()), lbUser);
|
||||
}
|
||||
}
|
||||
|
||||
Map<String, LbBuyerTradeStats> tradeStatsByUserId = loadBuyerTradeStatsFromOrderRow(tenantIdTrim);
|
||||
boolean hasFilter = isActive != null || joinDate != null || lastTradeDate != null;
|
||||
|
||||
Set<String> matchedUserIds = new HashSet<>();
|
||||
Map<String, LocalDate> joinDateByUserId = new HashMap<>();
|
||||
Map<String, LocalDate> lastTradeDateByUserId = new HashMap<>();
|
||||
Map<String, BigDecimal> lastBuyAmtByUserId = new HashMap<>();
|
||||
Map<String, Integer> isActiveByUserId = new HashMap<>();
|
||||
for (LbUser lbUser : lbUsers) {
|
||||
if (lbUser.getId() == null) {
|
||||
continue;
|
||||
}
|
||||
LbDepartmentUser existing = userRecordMap.get(uid);
|
||||
if (existing == null || isNewerDepartmentUser(row, existing)) {
|
||||
userRecordMap.put(uid, row);
|
||||
String userId = String.valueOf(lbUser.getId());
|
||||
LocalDate userJoinDate = lbUser.getJoinTime() != null
|
||||
? lbUser.getJoinTime().toLocalDate() : null;
|
||||
LbBuyerTradeStats tradeStats = tradeStatsByUserId.get(userId);
|
||||
LocalDate userLastTradeDate = tradeStats == null
|
||||
? null : parseOrderTimeToDate(tradeStats.getPayTime());
|
||||
BigDecimal userLastBuyAmt = tradeStats == null ? null : tradeStats.getTotalMoney();
|
||||
int userIsActive = tradeStats == null ? 0 : 1;
|
||||
|
||||
joinDateByUserId.put(userId, userJoinDate);
|
||||
lastTradeDateByUserId.put(userId, userLastTradeDate);
|
||||
lastBuyAmtByUserId.put(userId, userLastBuyAmt);
|
||||
isActiveByUserId.put(userId, userIsActive);
|
||||
|
||||
if (!hasFilter || matchesTreeFilter(
|
||||
userIsActive, userJoinDate, userLastTradeDate, isActive, joinDate, lastTradeDate)) {
|
||||
matchedUserIds.add(userId);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
Set<String> visibleUserIds = hasFilter
|
||||
? includeAncestorUserIds(matchedUserIds, userById)
|
||||
: new HashSet<>(userById.keySet());
|
||||
|
||||
Map<String, Map<String, Object>> nodeByUserId = new LinkedHashMap<>();
|
||||
for (LbDepartmentUser row : userRecordMap.values()) {
|
||||
nodeByUserId.put(row.getUserId().trim(), toDepartmentUserTreeNode(row));
|
||||
Map<String, String> parentByUserId = new HashMap<>();
|
||||
for (String userId : visibleUserIds) {
|
||||
LbUser lbUser = userById.get(userId);
|
||||
if (lbUser == null) {
|
||||
continue;
|
||||
}
|
||||
nodeByUserId.put(userId, toLbUserTreeNode(
|
||||
lbUser,
|
||||
joinDateByUserId.get(userId),
|
||||
lastTradeDateByUserId.get(userId),
|
||||
lastBuyAmtByUserId.get(userId),
|
||||
isActiveByUserId.getOrDefault(userId, 0)));
|
||||
|
||||
String parentUserId = resolveLbUserParentId(lbUser, userById);
|
||||
if (parentUserId != null && visibleUserIds.contains(parentUserId)) {
|
||||
parentByUserId.put(userId, parentUserId);
|
||||
}
|
||||
}
|
||||
|
||||
List<Map<String, Object>> treeRoots = new ArrayList<>();
|
||||
@@ -747,11 +746,12 @@ public class LbDepartmentUserServiceImpl extends ServiceImpl<LbDepartmentUserMap
|
||||
children.add(node);
|
||||
}
|
||||
sortDepartmentUserTreeByName(treeRoots);
|
||||
List<Map<String, Object>> treeData = skipFirstTreeLevel(treeRoots);
|
||||
|
||||
result.put("success", true);
|
||||
result.put("message", "查询成功");
|
||||
result.put("data", treeRoots);
|
||||
result.put("total", nodeByUserId.size());
|
||||
result.put("data", treeData);
|
||||
result.put("total", countTreeNodes(treeData));
|
||||
result.put("tenantId", tenantIdTrim);
|
||||
return result;
|
||||
} catch (Exception e) {
|
||||
@@ -762,46 +762,122 @@ public class LbDepartmentUserServiceImpl extends ServiceImpl<LbDepartmentUserMap
|
||||
}
|
||||
|
||||
/**
|
||||
* parent_id 兼容两种存法:父 user_id,或父记录 id(UUID)。
|
||||
* 去掉第 1 级根节点,将其 children 提升为返回给前端的顶层。
|
||||
*/
|
||||
private static String resolveParentUserId(LbDepartmentUser row,
|
||||
Set<String> allUserIds,
|
||||
Map<String, String> userIdByRecordId) {
|
||||
String parentRef = trimToNull(row.getParentId());
|
||||
if (parentRef == null) {
|
||||
return null;
|
||||
private static List<Map<String, Object>> skipFirstTreeLevel(List<Map<String, Object>> treeRoots) {
|
||||
List<Map<String, Object>> result = new ArrayList<>();
|
||||
for (Map<String, Object> root : treeRoots) {
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Map<String, Object>> children = (List<Map<String, Object>>) root.get("children");
|
||||
if (children != null && !children.isEmpty()) {
|
||||
result.addAll(children);
|
||||
}
|
||||
}
|
||||
if (allUserIds.contains(parentRef)) {
|
||||
return parentRef;
|
||||
}
|
||||
return userIdByRecordId.get(parentRef);
|
||||
sortDepartmentUserTreeByName(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
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("lastTradeDate", row.getLastTradeDate());
|
||||
node.put("lastBuyAmt", row.getLastBuyAmt());
|
||||
node.put("isActive", row.getIsActive());
|
||||
node.put("children", new ArrayList<Map<String, Object>>());
|
||||
return node;
|
||||
private static int countTreeNodes(List<Map<String, Object>> nodes) {
|
||||
int count = 0;
|
||||
for (Map<String, Object> node : nodes) {
|
||||
count++;
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Map<String, Object>> children = (List<Map<String, Object>>) node.get("children");
|
||||
if (children != null && !children.isEmpty()) {
|
||||
count += countTreeNodes(children);
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
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) {
|
||||
private static boolean matchesTreeFilter(int userIsActive,
|
||||
LocalDate userJoinDate,
|
||||
LocalDate userLastTradeDate,
|
||||
Integer isActive,
|
||||
LocalDate joinDate,
|
||||
LocalDate lastTradeDate) {
|
||||
if (isActive != null && userIsActive != isActive) {
|
||||
return false;
|
||||
}
|
||||
if (existingTime == null) {
|
||||
return true;
|
||||
if (joinDate != null && (userJoinDate == null || !userJoinDate.isAfter(joinDate))) {
|
||||
return false;
|
||||
}
|
||||
return candidateTime.isAfter(existingTime);
|
||||
return lastTradeDate == null
|
||||
|| (userLastTradeDate != null && userLastTradeDate.isAfter(lastTradeDate));
|
||||
}
|
||||
|
||||
/**
|
||||
* 筛选命中用户时,沿 lb_user.pid 向上补全祖先,避免子节点因上级被筛掉而挂错层级。
|
||||
*/
|
||||
private static Set<String> includeAncestorUserIds(Set<String> userIds, Map<String, LbUser> userById) {
|
||||
Set<String> expanded = new HashSet<>(userIds);
|
||||
for (String userId : userIds) {
|
||||
LbUser current = userById.get(userId);
|
||||
Set<Long> visited = new HashSet<>();
|
||||
while (current != null) {
|
||||
Long pid = current.getPid();
|
||||
if (pid == null || pid <= 0 || !visited.add(pid)) {
|
||||
break;
|
||||
}
|
||||
String parentUserId = String.valueOf(pid);
|
||||
if (!userById.containsKey(parentUserId)) {
|
||||
break;
|
||||
}
|
||||
expanded.add(parentUserId);
|
||||
current = userById.get(parentUserId);
|
||||
}
|
||||
}
|
||||
return expanded;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从 lb_user.pid 解析上级 userId;pid 必须在同租户用户索引中存在。
|
||||
*/
|
||||
private static String resolveLbUserParentId(LbUser user, Map<String, LbUser> userById) {
|
||||
if (user == null || user.getPid() == null || user.getPid() <= 0) {
|
||||
return null;
|
||||
}
|
||||
String parentUserId = String.valueOf(user.getPid());
|
||||
return userById.containsKey(parentUserId) ? parentUserId : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 一次 SQL 从 lb_order_row 汇总每位买家的最新已支付订单统计。
|
||||
*/
|
||||
private Map<String, LbBuyerTradeStats> loadBuyerTradeStatsFromOrderRow(String tenantId) {
|
||||
List<LbBuyerTradeStats> rows = lbOrderRowMapper.selectLatestPaidStatsByTenantId(
|
||||
tenantId, ORDER_DATA_TYPE_DETAIL);
|
||||
Map<String, LbBuyerTradeStats> statsByUserId = new HashMap<>();
|
||||
if (rows == null || rows.isEmpty()) {
|
||||
return statsByUserId;
|
||||
}
|
||||
for (LbBuyerTradeStats row : rows) {
|
||||
if (row.getBuyerId() == null) {
|
||||
continue;
|
||||
}
|
||||
statsByUserId.put(String.valueOf(row.getBuyerId()), row);
|
||||
}
|
||||
return statsByUserId;
|
||||
}
|
||||
|
||||
private static Map<String, Object> toLbUserTreeNode(LbUser user,
|
||||
LocalDate joinDate,
|
||||
LocalDate lastTradeDate,
|
||||
BigDecimal lastBuyAmt,
|
||||
int isActive) {
|
||||
Map<String, Object> node = new LinkedHashMap<>();
|
||||
node.put("userId", user.getId() == null ? null : String.valueOf(user.getId()));
|
||||
node.put("name", trimToNull(resolveDisplayName(user)));
|
||||
node.put("phone", trimToNull(user.getMobile()));
|
||||
Long pid = user.getPid();
|
||||
node.put("parentId", pid == null || pid <= 0 ? null : String.valueOf(pid));
|
||||
node.put("parentName", trimToNull(user.getPname()));
|
||||
node.put("joinDate", joinDate);
|
||||
node.put("lastTradeDate", lastTradeDate);
|
||||
node.put("lastBuyAmt", lastBuyAmt);
|
||||
node.put("isActive", isActive);
|
||||
node.put("children", new ArrayList<Map<String, Object>>());
|
||||
return node;
|
||||
}
|
||||
|
||||
private static void sortDepartmentUserTreeByName(List<Map<String, Object>> nodes) {
|
||||
|
||||
Reference in New Issue
Block a user