Merge remote-tracking branch 'websoft/dev'

This commit is contained in:
2026-10-26 10:12:11 +08:00
14 changed files with 214 additions and 26 deletions
@@ -1055,6 +1055,7 @@ public class DriverWaybillServiceImpl implements IDriverWaybillService {
card.setCargos(withDetail ? cargoLines(cargos) : null);
card.setTransportType(toTransportTypeLabel(waybill.getTransportType()));
card.setTransportOrgType(Func.isNotBlank(waybill.getLoadingNo()) ? TRANSPORT_LOAD : TRANSPORT_COMMON);
card.setMultimodal(Func.isNotBlank(waybill.getMasterNo()));
card.setPlanShipTime(formatLocalDateYmd(waybill.getEstimatedStartTime()));
card.setPlanFinishTime(formatLocalDateYmd(waybill.getEstimatedEndTime()));
card.setRemark(Func.toStr(waybill.getRemark(), ""));
@@ -1141,6 +1142,7 @@ public class DriverWaybillServiceImpl implements IDriverWaybillService {
card.setRequireAccept(trip.getRequireAccept());
card.setAcceptStatus(trip.getAcceptStatus());
card.setTransportOrgType(trip.getTransportOrgType());
card.setMultimodal(trip.getMultimodal());
card.setTransportType(toTransportTypeLabel(trip.getTransportType()));
card.setDriverName(Func.toStr(trip.getDriverName(), ""));
card.setDriverPhone(Func.toStr(trip.getDriverPhone(), ""));
@@ -1649,7 +1651,7 @@ public class DriverWaybillServiceImpl implements IDriverWaybillService {
// 里程同样只在末位卡采集:末位判定与上面同一个变量,避免两处各算一次走偏。
if (lastPunchNode && lastNodeNeedsMileage) {
vo.setNeedMileage(true);
vo.setMileage(waybill.getMileage());
vo.setMileage(TransportBusinessSupport.mileageText(waybill.getMileage()));
}
if (done) {
if (punched.getPunchTime() != null) {
@@ -445,6 +445,7 @@ public class ManageWaybillServiceImpl implements IManageWaybillService {
detail.setTransportMode(Func.toStr(trip.getTransportType(), ""));
detail.setTransportType(toTransportTypeLabel(Func.toStr(trip.getTransportType(), "")));
detail.setTransportOrgType(Func.isEmpty(trip.getLoadingNo()) ? TRANSPORT_COMMON : TRANSPORT_LOAD);
detail.setMultimodal(Boolean.TRUE.equals(trip.getMultimodal()));
detail.setTripId(trip.getId());
detail.setLoadingNo(Func.toStr(trip.getLoadingNo(), ""));
detail.setTripNo(Func.toStr(trip.getTripNo(), ""));
@@ -504,6 +505,7 @@ public class ManageWaybillServiceImpl implements IManageWaybillService {
detail.setLoadingNo(loading.getLoadingNo());
detail.setTripNo(loading.getLoadingNo());
detail.setTransportOrgType(TRANSPORT_LOAD);
detail.setMultimodal(children.stream().anyMatch(child -> Func.isNotBlank(child.getMasterNo())));
detail.setViaName(TripStationAssembler.transitName(stations));
detail.setStationCount(stations.size());
detail.setStations(stations);
@@ -538,6 +540,7 @@ public class ManageWaybillServiceImpl implements IManageWaybillService {
detail.setTransportMode(Func.toStr(loading.getTransportType(), ""));
detail.setTransportType(toTransportTypeLabel(Func.toStr(loading.getTransportType(), "")));
detail.setTransportOrgType(TRANSPORT_LOAD);
detail.setMultimodal(children.stream().anyMatch(child -> Func.isNotBlank(child.getMasterNo())));
detail.setTripId(String.valueOf(loading.getId()));
detail.setLoadingNo(loading.getLoadingNo());
detail.setTripNo(loading.getLoadingNo());
@@ -777,6 +780,7 @@ public class ManageWaybillServiceImpl implements IManageWaybillService {
detail.setTransportMode(mode);
detail.setTransportType(toTransportTypeLabel(mode));
detail.setTransportOrgType(Func.isNotBlank(waybill.getLoadingNo()) ? TRANSPORT_LOAD : TRANSPORT_COMMON);
detail.setMultimodal(Func.isNotBlank(waybill.getMasterNo()));
detail.setFromName(formatPlaceName(waybill.getDepartureName(), mode));
detail.setToName(formatPlaceName(waybill.getArrivalName(), mode));
@@ -79,9 +79,10 @@ public class TripQueryServiceImpl implements ITripQueryService {
private static final int DEFAULT_PAGE_SIZE = 10;
private static final int MAX_PAGE_SIZE = 50;
/** 运输组织类型:有配载单为公路配载,否则普通运输 */
/** 运输类型:有配载单为配载运输,挂多联总单为多式联运,两者都没有为普通运输 */
private static final String TRANSPORT_LOAD = "load";
private static final String TRANSPORT_COMMON = "common";
private static final String TRANSPORT_MULTIMODAL = "multimodal";
/** 未配载运次的键前缀:与 TripAggregation.SQL_TRIP_KEY 的 W 前缀同一个口径 */
private static final String LONE_KEY_PREFIX = "W";
@@ -185,8 +186,8 @@ public class TripQueryServiceImpl implements ITripQueryService {
/**
* 全部可见运次:一次取回运单行后在服务层分组、分档、筛选并按排序键倒序
* <p>
* 分档用过程配置与接单态推导,于是 Tab 与卡片必然同档;行级筛选(组织类型 / 异常 / 创建时间)落在库层,
* 命中的行同时决定这一趟车的子单集合与分档。
* 分档用过程配置与接单态推导,于是 Tab 与卡片必然同档;异常与创建时间按整趟车的子单集合判,
* 运输类型也在这里判——三者都不在库层筛行,否则一趟车会被劈成两半、三档数目加起来对不上全部。
*/
private List<TripRows> trips(TripQueryVO condition) {
Map<String, List<Waybill>> grouped = new LinkedHashMap<>();
@@ -202,7 +203,7 @@ public class TripQueryServiceImpl implements ITripQueryService {
return;
}
List<Waybill> children = sortedChildren(rows);
if (!inScope(children, condition)) {
if (!matchesOrgType(children, condition.getTransportOrgType()) || !inScope(children, condition)) {
return;
}
boolean requireAccept = TripAggregation.requiresAccept(children);
@@ -244,6 +245,8 @@ public class TripQueryServiceImpl implements ITripQueryService {
Waybill::getDepartureName, Waybill::getDepartureAddress, Waybill::getArrivalName,
Waybill::getArrivalAddress, Waybill::getDriverName, Waybill::getDriverPhone, Waybill::getVehicleNo,
Waybill::getCustomerName, Waybill::getTransportType, Waybill::getTaskRemark,
// 运输类型的三态靠它派生,行级筛选也按它判,必须随行取回
Waybill::getMasterNo,
// 未配载运次没有配载单可依,计划时间要取运单自己的,故必须随行取回
Waybill::getEstimatedStartTime, Waybill::getEstimatedEndTime, Waybill::getCreateTime)
.in(Waybill::getBusinessStatus, TripAggregation.CHILD_STATUSES)
@@ -252,7 +255,6 @@ public class TripQueryServiceImpl implements ITripQueryService {
applyScope(wrapper, condition);
applyDeptScope(wrapper, condition);
applyProjectScope(wrapper, condition);
applyOrgTypeFilter(wrapper, condition);
applyKeyword(wrapper, condition.getKeyword());
List<Waybill> rows = waybillService.list(wrapper);
applyLiveProcessConfig(rows);
@@ -285,15 +287,25 @@ public class TripQueryServiceImpl implements ITripQueryService {
}
/**
* 运输组织类型按子单行筛:它在同一趟车里必然是同一个值(配载的每张子单带同一个配载单号,
* 未配载的每张自成一趟车),所以这一层不会把一趟车拆开。
* 运输类型按整趟车判,三档互斥且覆盖全部运次:普通 = 不挂配载单也不挂总单,
* 配载 = 挂配载单且整趟车没挂总单,多式联运 = 任一子单挂总单(不问有没有配载)。
* <p>
* 不能按子单行筛:一张配载单可以混装挂总单与不挂总单的运单,行级筛会让同一趟车同时落进
* 配载与多式联运两档,而每档里只剩命中的那部分子单——卡片上的运单数、货物与重量都会缩水,
* 三个档的数目加起来也对不上「全部」。判据只能落在取回后的整趟车集合上。
*/
private void applyOrgTypeFilter(LambdaQueryWrapper<Waybill> wrapper, TripQueryVO condition) {
if (TRANSPORT_LOAD.equals(condition.getTransportOrgType())) {
wrapper.apply("IFNULL(loading_no, '') <> ''");
} else if (TRANSPORT_COMMON.equals(condition.getTransportOrgType())) {
wrapper.apply("IFNULL(loading_no, '') = ''");
private static boolean matchesOrgType(List<Waybill> children, String transportOrgType) {
if (Func.isBlank(transportOrgType)) {
return true;
}
boolean multimodal = children.stream().anyMatch(child -> Func.isNotBlank(child.getMasterNo()));
boolean loaded = children.stream().anyMatch(child -> Func.isNotBlank(child.getLoadingNo()));
return switch (transportOrgType) {
case TRANSPORT_MULTIMODAL -> multimodal;
case TRANSPORT_LOAD -> loaded && !multimodal;
case TRANSPORT_COMMON -> !loaded && !multimodal;
default -> true;
};
}
/**
@@ -530,6 +542,8 @@ public class TripQueryServiceImpl implements ITripQueryService {
trip.setLoadingNo(loading.getLoadingNo());
trip.setTripNo(loading.getLoadingNo());
trip.setTransportOrgType(TRANSPORT_LOAD);
// 多式联运与配载可叠加:任一子单挂总单即算这趟车含多式联运
trip.setMultimodal(children.stream().anyMatch(child -> Func.isNotBlank(child.getMasterNo())));
trip.setDriverName(Func.toStr(loading.getDriverName(), ""));
trip.setDriverPhone(Func.toStr(loading.getDriverPhone(), ""));
trip.setVehicleNo(Func.toStr(loading.getVehicleNo(), ""));
@@ -562,6 +576,7 @@ public class TripQueryServiceImpl implements ITripQueryService {
trip.setId(tripIdOf(waybill.getId()));
trip.setTripNo(waybill.getWaybillNo());
trip.setTransportOrgType(TRANSPORT_COMMON);
trip.setMultimodal(Func.isNotBlank(waybill.getMasterNo()));
trip.setDriverName(Func.toStr(waybill.getDriverName(), ""));
trip.setDriverPhone(Func.toStr(waybill.getDriverPhone(), ""));
trip.setVehicleNo(Func.toStr(waybill.getVehicleNo(), ""));
@@ -442,7 +442,7 @@ public class WaybillServiceImpl extends BaseServiceImpl<WaybillMapper, Waybill>
item.setType(isTransit ? "enroute" : "node");
if (lastNodeNeedsMileage && !isTransit && lastPunchKey.equals(nodeCode)) {
item.setNeedMileage(true);
item.setMileage(waybill.getMileage());
item.setMileage(TransportBusinessSupport.mileageText(waybill.getMileage()));
item.setMileageLocked(punchMileageLocked);
}
item.setExceptionFlag(false);
@@ -282,4 +282,13 @@ public final class TransportBusinessSupport {
return mileage;
}
/**
* 里程回显文本:去掉列上 decimal(18,2) 带来的尾随零,使 "200.00" 下发为 "200"。
* <p>
* 客户端按正整数校验里程,回显成两位小数会被当成非法值拒掉——不清零就等于「原样回填不能提交」。
*/
public static String mileageText(BigDecimal mileage) {
return mileage == null ? null : mileage.stripTrailingZeros().toPlainString();
}
}