✨ 异常详情下发配载单、子运单与可调整站点
This commit is contained in:
+205
-4
@@ -61,10 +61,12 @@ import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
@@ -605,8 +607,7 @@ public class ExceptionDisposalServiceImpl
|
||||
int childCount = childWaybillCount(loading.getWaybillIdsJson());
|
||||
for (Station station : stations) {
|
||||
for (String tag : station.tags()) {
|
||||
String digits = tag.replaceAll("\\D+", "");
|
||||
int order = Func.isEmpty(digits) ? 0 : Func.toInt(digits, 0);
|
||||
int order = tagOrder(tag);
|
||||
if (order < 1 || order > childCount) {
|
||||
throw new ServiceException("路线节点未关联子运单");
|
||||
}
|
||||
@@ -631,7 +632,7 @@ public class ExceptionDisposalServiceImpl
|
||||
/** 配载单当前路线的站点地址:优先站点行,没有站点行时回退到发货 / 途经 / 到货地址三列 */
|
||||
private List<String> loadingStationAddresses(LoadingManage loading) {
|
||||
List<String> addresses = new ArrayList<>();
|
||||
for (Map<String, Object> row : jsonObjectList(loading.getRouteJson())) {
|
||||
for (Map<String, Object> row : loadingStationRows(loading)) {
|
||||
addAddress(addresses, text(row.get("address")));
|
||||
}
|
||||
if (!addresses.isEmpty()) {
|
||||
@@ -978,7 +979,7 @@ public class ExceptionDisposalServiceImpl
|
||||
return vo;
|
||||
}
|
||||
|
||||
/** 按关联运单补齐详情页路线 / 货物展示字段 */
|
||||
/** 按关联运单补齐详情页路线 / 货物 / 配载单展示字段 */
|
||||
private void fillRouteAndCargo(ExceptionDisposalVO vo, Long waybillId) {
|
||||
if (vo == null || waybillId == null) {
|
||||
return;
|
||||
@@ -996,6 +997,206 @@ public class ExceptionDisposalServiceImpl
|
||||
cargo.put("name", Func.toStr(waybill.getCargoName(), ""));
|
||||
cargo.put("weight", formatWeight(waybill.getQuantity(), waybill.getQuantityUnit()));
|
||||
vo.setCargo(cargo);
|
||||
|
||||
fillRouteNodes(vo, waybill);
|
||||
}
|
||||
|
||||
/**
|
||||
* 详情页的可编辑站点与配载单信息。
|
||||
* <p>
|
||||
* 配载单是这趟车的执行主体,站点取它的站点行;运单没有配载单号、或配载单已被删除 / 解绑时退回
|
||||
* 运单自己的路线段——历史异常仍要能打开,不能因为配载单不在了就打不开详情。
|
||||
*/
|
||||
private void fillRouteNodes(ExceptionDisposalVO vo, Waybill waybill) {
|
||||
LoadingManage loading = findLoading(waybill.getLoadingNo());
|
||||
if (loading == null) {
|
||||
vo.setChildWaybillNos(new ArrayList<>());
|
||||
vo.setRouteNodes(waybillRouteNodes(waybill));
|
||||
return;
|
||||
}
|
||||
Map<Integer, Waybill> childWaybills = childWaybillsByOrder(loading);
|
||||
vo.setLoadingNo(loading.getLoadingNo());
|
||||
vo.setChildWaybillNos(childWaybillNos(childWaybills));
|
||||
List<Map<String, Object>> rows = loadingStationRows(loading);
|
||||
vo.setRouteNodes(loadingRouteNodes(rows, childWaybills));
|
||||
vo.setRoute(loadingRoute(rows, loading, waybill));
|
||||
}
|
||||
|
||||
/** 配载单的站点行:只有带地址的行才算一个站,缺地址的历史行不参与 */
|
||||
private List<Map<String, Object>> loadingStationRows(LoadingManage loading) {
|
||||
List<Map<String, Object>> rows = new ArrayList<>();
|
||||
for (Map<String, Object> row : jsonObjectList(loading.getRouteJson())) {
|
||||
if (Func.isNotBlank(text(row.get("address")))) {
|
||||
rows.add(row);
|
||||
}
|
||||
}
|
||||
return rows;
|
||||
}
|
||||
|
||||
private List<ExceptionDisposalVO.RouteNode> loadingRouteNodes(List<Map<String, Object>> rows,
|
||||
Map<Integer, Waybill> childWaybills) {
|
||||
List<ExceptionDisposalVO.RouteNode> nodes = new ArrayList<>(rows.size());
|
||||
for (Map<String, Object> row : rows) {
|
||||
List<String> tags = stringList(row.get("tags"));
|
||||
ExceptionDisposalVO.RouteNode node = new ExceptionDisposalVO.RouteNode();
|
||||
node.setAddress(text(row.get("address")));
|
||||
node.setTags(tags);
|
||||
node.setProjects(stationProjects(tags, childWaybills));
|
||||
nodes.add(node);
|
||||
}
|
||||
return stationKinds(nodes);
|
||||
}
|
||||
|
||||
/**
|
||||
* 没有配载单时从路线段推导站点:首段出发地是首站,其后每段的到达地各成一站。
|
||||
* 地址口径与改路线时的比对一致(地址优先、站名兜底),否则用户什么都没改直接提交也会被判成改过地址。
|
||||
*/
|
||||
private List<ExceptionDisposalVO.RouteNode> waybillRouteNodes(Waybill waybill) {
|
||||
List<ExceptionDisposalVO.RouteNode> nodes = new ArrayList<>();
|
||||
for (String address : waybillStationAddresses(waybill)) {
|
||||
if (Func.isBlank(address)) {
|
||||
continue;
|
||||
}
|
||||
ExceptionDisposalVO.RouteNode node = new ExceptionDisposalVO.RouteNode();
|
||||
node.setAddress(address);
|
||||
node.setTags(new ArrayList<>());
|
||||
node.setProjects(new ArrayList<>());
|
||||
nodes.add(node);
|
||||
}
|
||||
return stationKinds(nodes);
|
||||
}
|
||||
|
||||
/** 站序声明:首站 start、末站 end、其余 transit;不足两个站就没有首末可言,不给前端调整入口 */
|
||||
private List<ExceptionDisposalVO.RouteNode> stationKinds(List<ExceptionDisposalVO.RouteNode> nodes) {
|
||||
if (nodes.size() < 2) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
for (int index = 0; index < nodes.size(); index++) {
|
||||
nodes.get(index).setKind(index == 0 ? NODE_KIND_START
|
||||
: (index == nodes.size() - 1 ? NODE_KIND_END : NODE_KIND_TRANSIT));
|
||||
}
|
||||
return nodes;
|
||||
}
|
||||
|
||||
/**
|
||||
* 站点标记指向配载单运单集合里的第 N 张子运单,取其项目名去重。
|
||||
* 标记对不上子运单(越界、子运单已不存在)时跳过,一个坏标记不该让整个详情打不开。
|
||||
*/
|
||||
private List<String> stationProjects(List<String> tags, Map<Integer, Waybill> childWaybills) {
|
||||
Set<String> projects = new LinkedHashSet<>();
|
||||
for (String tag : tags) {
|
||||
Waybill child = childWaybills.get(tagOrder(tag) - 1);
|
||||
if (child == null) {
|
||||
continue;
|
||||
}
|
||||
String projectName = Func.toStr(child.getProjectName(), "").trim();
|
||||
if (Func.isNotBlank(projectName)) {
|
||||
projects.add(projectName);
|
||||
}
|
||||
}
|
||||
return new ArrayList<>(projects);
|
||||
}
|
||||
|
||||
/**
|
||||
* 按配载单运单集合的位次取子运单,位次从 0 起(站点标记里的 N 减一)。
|
||||
* 位次不能因为某张子运单查不到而前移,否则标记会指到别的子运单上。
|
||||
*/
|
||||
private Map<Integer, Waybill> childWaybillsByOrder(LoadingManage loading) {
|
||||
Map<Integer, Waybill> childWaybills = new LinkedHashMap<>();
|
||||
List<Long> waybillIds = waybillIds(loading.getWaybillIdsJson());
|
||||
List<Long> queryIds = waybillIds.stream().filter(Objects::nonNull).distinct().toList();
|
||||
if (queryIds.isEmpty()) {
|
||||
return childWaybills;
|
||||
}
|
||||
Map<Long, Waybill> waybillsById = new HashMap<>();
|
||||
List<Waybill> found = waybillService.listByIds(queryIds);
|
||||
if (found != null) {
|
||||
for (Waybill child : found) {
|
||||
if (child != null && !Objects.equals(child.getIsDeleted(), 1)) {
|
||||
waybillsById.put(child.getId(), child);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int order = 0; order < waybillIds.size(); order++) {
|
||||
Waybill child = waybillsById.get(waybillIds.get(order));
|
||||
if (child != null) {
|
||||
childWaybills.put(order, child);
|
||||
}
|
||||
}
|
||||
return childWaybills;
|
||||
}
|
||||
|
||||
/** 配载单运单集合的元素是运单主键;元素不是主键时留空占位,后面的位次不能因此前移 */
|
||||
private List<Long> waybillIds(String waybillIdsJson) {
|
||||
List<Long> waybillIds = new ArrayList<>();
|
||||
if (Func.isBlank(waybillIdsJson)) {
|
||||
return waybillIds;
|
||||
}
|
||||
try {
|
||||
Object parsed = JsonUtil.parse(waybillIdsJson, List.class);
|
||||
if (parsed instanceof List<?> list) {
|
||||
for (Object item : list) {
|
||||
long waybillId = Func.toLong(text(item), 0L);
|
||||
waybillIds.add(waybillId > 0 ? waybillId : null);
|
||||
}
|
||||
}
|
||||
} catch (Exception ignored) {
|
||||
// 运单集合坏了就没有子运单可言,详情退回运单自己的路线,不影响打开
|
||||
return new ArrayList<>();
|
||||
}
|
||||
return waybillIds;
|
||||
}
|
||||
|
||||
/** 子运单号按配载单运单集合的顺序给出;查不到的子运单跳过,不占位 */
|
||||
private List<String> childWaybillNos(Map<Integer, Waybill> childWaybills) {
|
||||
List<String> childWaybillNos = new ArrayList<>(childWaybills.size());
|
||||
for (Waybill child : childWaybills.values()) {
|
||||
String waybillNo = Func.toStr(child.getWaybillNo(), "").trim();
|
||||
if (Func.isNotBlank(waybillNo)) {
|
||||
childWaybillNos.add(waybillNo);
|
||||
}
|
||||
}
|
||||
return childWaybillNos;
|
||||
}
|
||||
|
||||
/** 有配载单时路线摘要取这趟车自己的首末站:站点行的展示地址优先,没有站点行回落到地址列 */
|
||||
private Map<String, String> loadingRoute(List<Map<String, Object>> rows, LoadingManage loading, Waybill waybill) {
|
||||
String start;
|
||||
String end;
|
||||
if (rows.isEmpty()) {
|
||||
start = firstNonBlank(loading.getDepartureAddress(), waybill.getDepartureName(), "");
|
||||
end = firstNonBlank(loading.getArrivalAddress(), waybill.getArrivalName(), "");
|
||||
} else {
|
||||
start = stationDisplayAddress(rows.get(0));
|
||||
end = stationDisplayAddress(rows.get(rows.size() - 1));
|
||||
}
|
||||
Map<String, String> route = new HashMap<>(2);
|
||||
route.put("start", start);
|
||||
route.put("end", end);
|
||||
return route;
|
||||
}
|
||||
|
||||
private String stationDisplayAddress(Map<String, Object> row) {
|
||||
return firstNonBlank(text(row.get("displayAddress")), text(row.get("address")), "");
|
||||
}
|
||||
|
||||
/** 站点标记里的数字是配载单运单集合里的位次(1 起),取不到数字时返回 0 */
|
||||
private int tagOrder(String tag) {
|
||||
String digits = Func.toStr(tag, "").replaceAll("\\D+", "");
|
||||
return Func.isEmpty(digits) ? 0 : Func.toInt(digits, 0);
|
||||
}
|
||||
|
||||
private List<String> stringList(Object value) {
|
||||
List<String> texts = new ArrayList<>();
|
||||
if (value instanceof List<?> list) {
|
||||
for (Object item : list) {
|
||||
String text = text(item);
|
||||
if (Func.isNotBlank(text)) {
|
||||
texts.add(text);
|
||||
}
|
||||
}
|
||||
}
|
||||
return texts;
|
||||
}
|
||||
|
||||
private String formatWeight(BigDecimal quantity, String unit) {
|
||||
|
||||
Reference in New Issue
Block a user