fix(ops): 修复工单location字段重复和parent_path格式问题
Some checks failed
Java CI with Maven / build (11) (push) Has been cancelled
Java CI with Maven / build (17) (push) Has been cancelled
Java CI with Maven / build (8) (push) Has been cancelled

1. 修改 parent_path 格式为以 "/" 开头(如:/1/2/3)
   - buildParentPath: 父级是根节点时返回 "/1" 而非 "1"

2. 修复 buildAreaPath 方法的去重逻辑
   - 从名称层面去重改为 ID 层面去重
   - 避免误删不同ID但名称相同的合法情况
   - 只去除数据错误导致的重复ID
   - 添加警告日志记录重复ID

3. 调整 isDescendant 方法以适配新的 parent_path 格式
   - 简化判断逻辑,移除冗余的 startsWith 检查

4. 更新测试用例以匹配新格式
   - Mock数据: parentPath("10") -> parentPath("/10")
   - 期望值: "10/1" -> "/10/1"

5. 统一 location 路径格式(不带前导斜杠)
   - 示例: "徐汇万科中心一期/A座写字楼/11楼/电梯厅"

变更影响:
- ops_bus_area.parent_path: "1" -> "/1", "1/2" -> "/1/2"
- ops_order.location: 无前导斜杠

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
lzh
2026-02-10 16:14:59 +08:00
parent 631612951c
commit 113e90c726
3 changed files with 37 additions and 18 deletions

View File

@@ -30,6 +30,7 @@ import org.springframework.transaction.annotation.Transactional;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
@@ -485,22 +486,34 @@ public class CleanOrderServiceImpl implements CleanOrderService {
}
})
.map(Long::parseLong)
.filter(pid -> !pid.equals(areaId)) // 排除当前区域,避免重复
.filter(pid -> !pid.equals(areaId)) // 排除当前区域,避免循环引用
.collect(Collectors.toList());
// 5. 无有效父级,直接返回区域名称
if (parentIds.isEmpty()) {
// 5. 在ID层面去重相邻重复的ID只去除数据错误导致的重复保留不同ID的相同名称
List<Long> deduplicatedIds = new ArrayList<>();
Long lastId = null;
for (Long parentId : parentIds) {
if (!parentId.equals(lastId)) {
deduplicatedIds.add(parentId);
lastId = parentId;
} else {
log.warn("检测到parent_path中重复的ID: areaId={}, duplicateId={}", areaId, parentId);
}
}
// 6. 无有效父级,直接返回区域名称
if (deduplicatedIds.isEmpty()) {
return area.getAreaName();
}
// 6. 批量查询所有父级区域(避免 N+1 查询)
List<OpsBusAreaDO> parents = opsBusAreaMapper.selectBatchIds(parentIds);
// 7. 批量查询所有父级区域(避免 N+1 查询)
List<OpsBusAreaDO> parents = opsBusAreaMapper.selectBatchIds(deduplicatedIds);
if (parents == null || parents.isEmpty()) {
log.warn("未找到父级区域: areaId={}, parentIds={}", areaId, parentIds);
log.warn("未找到父级区域: areaId={}, parentIds={}", areaId, deduplicatedIds);
return area.getAreaName();
}
// 7. 构建ID到区域的映射
// 8. 构建ID到区域的映射
Map<Long, String> parentNameMap = parents.stream()
.collect(Collectors.toMap(
OpsBusAreaDO::getId,
@@ -508,13 +521,18 @@ public class CleanOrderServiceImpl implements CleanOrderService {
(existing, replacement) -> existing // 处理重复key
));
// 8. 按顺序拼接区域路径
String path = parentIds.stream()
// 9. 按顺序拼接区域路径保持ID顺序
List<String> pathSegments = deduplicatedIds.stream()
.filter(parentNameMap::containsKey) // 过滤掉不存在的父级
.map(parentNameMap::get)
.collect(Collectors.joining("/"));
.collect(Collectors.toList());
// 9. 拼接当前区域名称
return StrUtil.isNotBlank(path) ? path + "/" + area.getAreaName() : area.getAreaName();
// 10. 拼接完整路径
String path = String.join("/", pathSegments);
if (StrUtil.isBlank(path)) {
return area.getAreaName();
}
return path + "/" + area.getAreaName();
}
}

View File

@@ -170,7 +170,7 @@ public class OpsBusAreaServiceImpl implements OpsBusAreaService {
return null;
}
if (parent.getParentPath() == null || parent.getParentPath().isEmpty()) {
return String.valueOf(parentId);
return "/" + parentId;
}
return parent.getParentPath() + "/" + parentId;
}
@@ -187,9 +187,10 @@ public class OpsBusAreaServiceImpl implements OpsBusAreaService {
if (target == null || target.getParentPath() == null) {
return false;
}
return target.getParentPath().contains("/" + sourceId + "/")
|| target.getParentPath().startsWith(sourceId + "/")
|| target.getParentPath().endsWith("/" + sourceId);
// parent_path 格式:/1/2/3
// 判断 sourceId 是否在 parent_path 中
String path = target.getParentPath();
return path.contains("/" + sourceId + "/") || path.endsWith("/" + sourceId);
}
@Override

View File

@@ -149,7 +149,7 @@ class OpsBusAreaServiceTest {
OpsBusAreaDO parentArea = OpsBusAreaDO.builder()
.id(1L)
.parentPath("10")
.parentPath("/10") // parent_path 现在以 / 开头
.build();
when(opsBusAreaMapper.selectById(1L)).thenReturn(parentArea);
@@ -166,7 +166,7 @@ class OpsBusAreaServiceTest {
assertNotNull(areaId);
verify(opsBusAreaMapper, times(1)).insert(argThat((OpsBusAreaDO area) ->
"A栋".equals(area.getAreaName()) &&
"10/1".equals(area.getParentPath()) // PBT: parent_path 不变性
"/10/1".equals(area.getParentPath()) // PBT: parent_path 以 / 开头
));
}