BI运输运营专区接口查询

This commit is contained in:
秦鸿展
2026-05-18 16:13:04 +08:00
parent 9fcacbf9af
commit 986808af9a
34 changed files with 992 additions and 18 deletions
@@ -6,6 +6,7 @@ import com.mhd.bi.interfaces.facadeApi.biReport.vo.CustomerContributionRankVO;
import com.mhd.bi.interfaces.facadeApi.biReport.vo.WarehouseTransportSituationVO;
import com.mhd.bi.interfaces.facadeApi.biReport.vo.overall.*;
import com.mhd.bi.interfaces.facadeApi.biReport.vo.platform.*;
import com.mhd.bi.interfaces.facadeApi.biReport.vo.transportZone.*;
import com.mhd.bi.interfaces.facadeApi.biReport.vo.warehouseZone.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
@@ -161,9 +162,48 @@ public final class BiReportSnapshotMapperSupport {
.utilizationRate(WhRealTimeGaugeVO.builder().value("").comparison("").trend("").build())
.rentalRate(WhRealTimeGaugeVO.builder().value("").comparison("").trend("").build())
.build())
.mapPopup(WhMapPopupVO.builder()
.warehouseName("").totalArea("").totalSku(0).todayOrders(0)
.utilizationRate("").rentalRate("").build())
.map(WhWarehouseMapVO.builder()
.legend("")
.nodes(Collections.emptyList())
.build())
.build();
}
public static TransportOperationZoneVO emptyTransportOperationZone() {
TrCapacityCountVO emptyCount = TrCapacityCountVO.builder()
.total(0).todayNew(0).yesterdayNew(0).build();
return TransportOperationZoneVO.builder()
.updateTime("")
.dashboardTitle("")
.activeTab("")
.orderStatistics(TrOrderStatisticsVO.builder().title("").total(0L).trend("").build())
.transportStats(TrTransportStatsVO.builder()
.title("").tripCount(0).volume(0d).volumeUnit("").build())
.orderTypeChart(TrOrderTypeChartVO.builder()
.title("").type("").data(Collections.emptyList()).build())
.tripCountTrend(TrTypedChartVO.builder()
.title("").type("").unit(null).data(Collections.emptyList()).build())
.orderTrend(TrTypedChartVO.builder()
.title("").type("").unit("").data(Collections.emptyList()).build())
.volumeTrend(TrTypedChartVO.builder()
.title("").type("").unit("").data(Collections.emptyList()).build())
.map(TrVehicleMapVO.builder()
.title("")
.legend(TrMapLegendVO.builder().idle(0).working(0).build())
.nodes(Collections.emptyList())
.build())
.enterpriseOperation(TrEnterpriseOperationVO.builder()
.title("").columns(Collections.emptyList()).list(Collections.emptyList()).build())
.capacityStatus(TrCapacityStatusVO.builder()
.title("").staff(emptyCount).vehicles(emptyCount).build())
.cargoCategory(TrCargoCategoryVO.builder()
.title("").totalOrders("").data(Collections.emptyList()).build())
.onTimeRate(TrTypedChartVO.builder()
.title("").type("").unit("").data(Collections.emptyList()).build())
.vehicleUtilization(TrBarChartVO.builder()
.title("").unit("").data(Collections.emptyList()).build())
.transportSummary(TrTransportSummaryVO.builder()
.title("").safeMileage("").avgDeliveryTime("").build())
.build();
}
}
@@ -16,4 +16,6 @@ public interface BiSnapshotWriteMapper {
int insertOverallOperationSnapshot(@Param("payloadJson") String payloadJson, @Param("remark") String remark);
int insertWarehouseOperationZoneSnapshot(@Param("payloadJson") String payloadJson, @Param("remark") String remark);
int insertTransportOperationZoneSnapshot(@Param("payloadJson") String payloadJson, @Param("remark") String remark);
}
@@ -8,7 +8,7 @@ import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
/**
* 定时将业务快照写入 BI_COMPREHENSIVE_SNAPSHOT / BI_WAREHOUSE_TRANSPORT_SNAPSHOT / BI_PLATFORM_SURVEILLANCE_SNAPSHOT / BI_OVERALL_OPERATION_SNAPSHOT / BI_WAREHOUSE_OPERATION_ZONE_SNAPSHOT。
* 定时将业务快照写入 BI_COMPREHENSIVE_SNAPSHOT / BI_WAREHOUSE_TRANSPORT_SNAPSHOT / BI_PLATFORM_SURVEILLANCE_SNAPSHOT / BI_OVERALL_OPERATION_SNAPSHOT / BI_WAREHOUSE_OPERATION_ZONE_SNAPSHOT / BI_TRANSPORT_OPERATION_ZONE_SNAPSHOT
* <p>默认关闭,需在配置中设置 {@code mhd.bi.snapshot-sync.enabled=true}。</p>
*/
@Slf4j
@@ -3,11 +3,13 @@ package com.mhd.bi.domain.biSnapshotSync.service;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.mhd.bi.domain.biSnapshotSync.repository.mapper.BiSnapshotWriteMapper;
import com.mhd.bi.domain.biSnapshotSync.support.BiSnapshotWeeklyRandomDataBuilder;
import com.mhd.bi.domain.biTransportOperationZone.support.TransportOperationZoneDemoData;
import com.mhd.bi.domain.biWarehouseOperationZone.support.WarehouseOperationZoneDemoData;
import com.mhd.bi.interfaces.facadeApi.biReport.vo.ComprehensiveSituationVO;
import com.mhd.bi.interfaces.facadeApi.biReport.vo.WarehouseTransportSituationVO;
import com.mhd.bi.interfaces.facadeApi.biReport.vo.overall.OverallOperationSituationVO;
import com.mhd.bi.interfaces.facadeApi.biReport.vo.platform.PlatformSurveillanceVO;
import com.mhd.bi.interfaces.facadeApi.biReport.vo.transportZone.TransportOperationZoneVO;
import com.mhd.bi.interfaces.facadeApi.biReport.vo.warehouseZone.WarehouseOperationZoneVO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@@ -16,7 +18,7 @@ import org.springframework.stereotype.Service;
import java.util.Random;
/**
* BI 快照表定时同步(综合态势 / 仓储运输 / 月台监测 / 总体运营态势 / 仓储运营专区)。
* BI 快照表定时同步(综合态势 / 仓储运输 / 月台监测 / 总体运营态势 / 仓储运营专区 / 运输运营专区)。
* <p><b>当前(临时)</b>{@code build*} 使用 {@link BiSnapshotWeeklyRandomDataBuilder},每次执行使用新的 {@link Random}
* 故<b>同一天多次手动触发、以及每次定时任务执行</b>,生成的模拟数据均<b>不相同</b>(仍在基准 ±20% 内)。</p>
* <p><b>后续改造</b>:在各 {@code build*} 中改为查库/Feign 聚合真实业务并组装 VO。</p>
@@ -40,6 +42,7 @@ public class BiReportSnapshotSyncService {
syncPlatformSurveillanceSnapshot();
syncOverallOperationSnapshot();
syncWarehouseOperationZoneSnapshot();
syncTransportOperationZoneSnapshot();
}
public void syncComprehensiveSnapshot() {
@@ -142,4 +145,25 @@ public class BiReportSnapshotSyncService {
protected WarehouseOperationZoneVO buildWarehouseOperationZoneSnapshot() {
return WarehouseOperationZoneDemoData.build();
}
public void syncTransportOperationZoneSnapshot() {
try {
TransportOperationZoneVO vo = buildTransportOperationZoneSnapshot();
String json = objectMapper.writeValueAsString(vo);
int rows = biSnapshotWriteMapper.insertTransportOperationZoneSnapshot(json, REMARK_SYNC);
if (rows < 1) {
log.warn("BI 运输运营专区快照 INSERT 影响行数为 {},请确认 NGWL_TEST_BI.BI_TRANSPORT_OPERATION_ZONE_SNAPSHOT", rows);
}
log.info("BI 运输运营专区快照已写入, affectedRows={}", rows);
} catch (Exception e) {
log.error("BI 运输运营专区快照同步失败", e);
}
}
/**
* TODO 业务落地:改为查询真实数据组装 VO。当前为 {@link TransportOperationZoneDemoData} 静态示例。
*/
protected TransportOperationZoneVO buildTransportOperationZoneSnapshot() {
return TransportOperationZoneDemoData.build();
}
}
@@ -0,0 +1,20 @@
package com.mhd.bi.domain.biTransportOperationZone.repository.mapper;
import com.mhd.bi.domain.biReport.support.BiReportSnapshotMapperSupport;
import com.mhd.bi.interfaces.facadeApi.biReport.vo.transportZone.TransportOperationZoneVO;
/**
* 运输运营专区:取 NGWL_TEST_BI.BI_TRANSPORT_OPERATION_ZONE_SNAPSHOT 最新 PAYLOAD_JSON 并解析。
*/
public interface BiTransportOperationZoneReportMapper {
String selectLatestPayloadJson();
default TransportOperationZoneVO loadLatestTransportOperationZone() {
return BiReportSnapshotMapperSupport.parsePayload(
selectLatestPayloadJson(),
TransportOperationZoneVO.class,
BiReportSnapshotMapperSupport::emptyTransportOperationZone,
"运输运营专区");
}
}
@@ -0,0 +1,21 @@
package com.mhd.bi.domain.biTransportOperationZone.service;
import com.mhd.bi.domain.biTransportOperationZone.repository.mapper.BiTransportOperationZoneReportMapper;
import com.mhd.bi.interfaces.facadeApi.biReport.vo.transportZone.TransportOperationZoneVO;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
/**
* 南光物流业务经营分析 · 运输运营专区
*/
@Service
public class BiTransportOperationZoneReportService {
@Resource
private BiTransportOperationZoneReportMapper biTransportOperationZoneReportMapper;
public TransportOperationZoneVO loadLatestTransportOperationZone() {
return biTransportOperationZoneReportMapper.loadLatestTransportOperationZone();
}
}
@@ -0,0 +1,164 @@
package com.mhd.bi.domain.biTransportOperationZone.support;
import com.mhd.bi.interfaces.facadeApi.biReport.vo.transportZone.*;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
/**
* 运输运营专区快照演示数据(对齐大屏示例 JSON;后续可改为真实聚合)。
*/
public final class TransportOperationZoneDemoData {
private static final DateTimeFormatter UPDATE_TIME_FMT = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
private TransportOperationZoneDemoData() {
}
public static TransportOperationZoneVO build() {
List<TrOrderTypeMonthItemVO> orderTypeData = Arrays.asList(
TrOrderTypeMonthItemVO.builder().month("1月").crossBorder(30).domestic(25).build(),
TrOrderTypeMonthItemVO.builder().month("2月").crossBorder(40).domestic(35).build(),
TrOrderTypeMonthItemVO.builder().month("3月").crossBorder(20).domestic(30).build(),
TrOrderTypeMonthItemVO.builder().month("4月").crossBorder(35).domestic(40).build(),
TrOrderTypeMonthItemVO.builder().month("5月").crossBorder(50).domestic(45).build(),
TrOrderTypeMonthItemVO.builder().month("6月").crossBorder(60).domestic(55).build(),
TrOrderTypeMonthItemVO.builder().month("7月").crossBorder(70).domestic(65).build()
);
List<TrMonthValuePointVO> tripTrend = Arrays.asList(
point("1月", 120), point("2月", 150), point("3月", 220),
point("4月", 100), point("5月", 140), point("6月", 180)
);
List<TrMonthValuePointVO> orderTrend = Arrays.asList(
point("1月", 100), point("2月", 140), point("3月", 230),
point("4月", 100), point("5月", 140), point("6月", 190)
);
List<TrMonthValuePointVO> volumeTrend = Arrays.asList(
point("1月", 95), point("2月", 90), point("3月", 80),
point("4月", 65), point("5月", 92), point("6月", 88)
);
List<TrMonthValuePointVO> onTimeRate = Arrays.asList(
point("1月", 98), point("2月", 96), point("3月", 85),
point("4月", 70), point("5月", 92), point("6月", 90)
);
List<TrMonthValuePointVO> vehicleUtil = Arrays.asList(
point("1月", 600), point("2月", 460), point("3月", 390),
point("4月", 470), point("5月", 450), point("6月", 620)
);
List<TrEnterpriseRowVO> enterpriseList = Arrays.asList(
row("NO.1", "供应商A", "268.25万", "2400单", 95),
row("NO.2", "供应商B", "258.15万", "1800单", 98),
row("NO.3", "供应商C", "242.32万", "1200单", 13),
row("NO.4", "供应商D", "231.54万", "800单", 12),
row("NO.5", "供应商E", "220.90万", "567单", 15)
);
List<TrCargoCategoryItemVO> cargoItems = Arrays.asList(
TrCargoCategoryItemVO.builder().name("危化").value(25).color("green").build(),
TrCargoCategoryItemVO.builder().name("普货").value(25).color("blue").build(),
TrCargoCategoryItemVO.builder().name("冻品").value(50).color("orange").build()
);
TrMapNodeVO mapNode = TrMapNodeVO.builder()
.id(1L)
.name("通宇作业车辆")
.location(Arrays.asList(113.55, 22.25))
.status("working")
.detail(TrMapNodeDetailVO.builder()
.title("作业详情")
.licensePlate("粤A88888")
.businessUnit("通宇")
.loadingPlace("珠海")
.destination("澳门")
.currentLocation("珠海市")
.updateTime("2026年4月15日 17:52")
.build())
.build();
return TransportOperationZoneVO.builder()
.updateTime(LocalDateTime.now().format(UPDATE_TIME_FMT))
.dashboardTitle("南光物流业务经营分析")
.activeTab("运输运营专区")
.orderStatistics(TrOrderStatisticsVO.builder()
.title("订单统计")
.total(4361L)
.trend("+12.5%")
.build())
.transportStats(TrTransportStatsVO.builder()
.title("运输统计")
.tripCount(240)
.volume(2.6)
.volumeUnit("万吨")
.build())
.orderTypeChart(TrOrderTypeChartVO.builder()
.title("订单类型")
.type("area")
.data(orderTypeData)
.build())
.tripCountTrend(chart("车次趋势", "line", null, tripTrend))
.orderTrend(chart("订单趋势", "area", "", orderTrend))
.volumeTrend(chart("货量趋势", "area", "%", volumeTrend))
.map(TrVehicleMapVO.builder()
.title("车辆实时监控")
.legend(TrMapLegendVO.builder().idle(80).working(200).build())
.nodes(Collections.singletonList(mapNode))
.build())
.enterpriseOperation(TrEnterpriseOperationVO.builder()
.title("企业运营")
.columns(Arrays.asList("序号", "企业名称", "货运量", "处理单量", "准时配送率"))
.list(enterpriseList)
.build())
.capacityStatus(TrCapacityStatusVO.builder()
.title("运力情况")
.staff(capacityCount(718, 0, 0))
.vehicles(capacityCount(507, 0, 0))
.build())
.cargoCategory(TrCargoCategoryVO.builder()
.title("货物品类")
.totalOrders("1000单")
.data(cargoItems)
.build())
.onTimeRate(chart("准时配送率", "line", "%", onTimeRate))
.vehicleUtilization(TrBarChartVO.builder()
.title("出车利用率")
.unit("车次/辆")
.data(vehicleUtil)
.build())
.transportSummary(TrTransportSummaryVO.builder()
.title("运输统计")
.safeMileage("240万公里")
.avgDeliveryTime("平均4小时送达")
.build())
.build();
}
private static TrMonthValuePointVO point(String month, int value) {
return TrMonthValuePointVO.builder().month(month).value(value).build();
}
private static TrTypedChartVO chart(String title, String type, String unit, List<TrMonthValuePointVO> data) {
return TrTypedChartVO.builder().title(title).type(type).unit(unit).data(data).build();
}
private static TrCapacityCountVO capacityCount(int total, int todayNew, int yesterdayNew) {
return TrCapacityCountVO.builder()
.total(total).todayNew(todayNew).yesterdayNew(yesterdayNew).build();
}
private static TrEnterpriseRowVO row(String rank, String name, String volume,
String processedOrders, int onTimeRate) {
return TrEnterpriseRowVO.builder()
.rank(rank).name(name).volume(volume)
.processedOrders(processedOrders).onTimeRate(onTimeRate)
.build();
}
}
@@ -126,13 +126,38 @@ public final class WarehouseOperationZoneDemoData {
.trend("up")
.build())
.build())
.mapPopup(WhMapPopupVO.builder()
.warehouseName("通宇保税")
.totalArea("2000m2")
.totalSku(668)
.todayOrders(237)
.utilizationRate("85%")
.rentalRate("37.1%")
.map(WhWarehouseMapVO.builder()
.legend("")
.nodes(Arrays.asList(
mapNode(1L, "君华仓", 113.52, 22.30,
"君华保税仓", "12000m²", 520, 2400, "82%", "36.5%"),
mapNode(2L, "通宇仓", 113.55, 22.25,
"通宇保税仓", "2000m²", 668, 237, "85%", "37.1%"),
mapNode(3L, "横琴仓", 113.54, 22.12,
"横琴保税仓", "3500m²", 445, 1200, "78%", "42.0%"),
mapNode(4L, "新南仓", 113.58, 22.20,
"新南保税仓", "2800m²", 390, 800, "80%", "35.8%"),
mapNode(5L, "谷丰仓", 113.48, 22.22,
"谷丰保税仓", "4500m²", 512, 567, "76%", "33.2%")
))
.build())
.build();
}
private static WhMapNodeVO mapNode(long id, String name, double lng, double lat,
String warehouseName, String totalArea, int totalSku,
int todayOrders, String utilizationRate, String rentalRate) {
return WhMapNodeVO.builder()
.id(id)
.name(name)
.location(Arrays.asList(lng, lat))
.detail(WhMapPopupVO.builder()
.warehouseName(warehouseName)
.totalArea(totalArea)
.totalSku(totalSku)
.todayOrders(todayOrders)
.utilizationRate(utilizationRate)
.rentalRate(rentalRate)
.build())
.build();
}