From 1afddbe531bf9e058e232080c0c5e109dc4a1216 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E7=A7=A6=E9=B8=BF=E5=B1=95?= <18031053041@163.com>
Date: Fri, 8 May 2026 23:09:56 +0800
Subject: [PATCH] =?UTF-8?q?BI=E5=AE=9A=E6=97=B6=E4=BB=BB=E5=8A=A1=E4=BF=AE?=
=?UTF-8?q?=E6=94=B9?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../main/java/com/mhd/bi/BiApplication.java | 2 +
.../mapper/BiSnapshotWriteMapper.java | 15 +
.../BiReportSnapshotSyncScheduler.java | 28 ++
.../service/BiReportSnapshotSyncService.java | 98 ++++++
.../BiSnapshotWeeklyRandomDataBuilder.java | 308 ++++++++++++++++++
.../facadeApi/biReport/BiReportApi.java | 12 +
mhd-bi/src/main/resources/bootstrap.yml | 14 +-
.../biSnapshotSync/BiSnapshotWriteMapper.xml | 20 ++
8 files changed, 487 insertions(+), 10 deletions(-)
create mode 100644 mhd-bi/src/main/java/com/mhd/bi/domain/biSnapshotSync/repository/mapper/BiSnapshotWriteMapper.java
create mode 100644 mhd-bi/src/main/java/com/mhd/bi/domain/biSnapshotSync/scheduler/BiReportSnapshotSyncScheduler.java
create mode 100644 mhd-bi/src/main/java/com/mhd/bi/domain/biSnapshotSync/service/BiReportSnapshotSyncService.java
create mode 100644 mhd-bi/src/main/java/com/mhd/bi/domain/biSnapshotSync/support/BiSnapshotWeeklyRandomDataBuilder.java
create mode 100644 mhd-bi/src/main/resources/mapper/biSnapshotSync/BiSnapshotWriteMapper.xml
diff --git a/mhd-bi/src/main/java/com/mhd/bi/BiApplication.java b/mhd-bi/src/main/java/com/mhd/bi/BiApplication.java
index dc87a6747..8c79d5d2c 100644
--- a/mhd-bi/src/main/java/com/mhd/bi/BiApplication.java
+++ b/mhd-bi/src/main/java/com/mhd/bi/BiApplication.java
@@ -9,6 +9,7 @@ import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.Import;
import org.springframework.scheduling.annotation.EnableAsync;
+import org.springframework.scheduling.annotation.EnableScheduling;
@SpringBootApplication(scanBasePackages = {"com.mhd", "com.mhd.bi"})
@EnableDiscoveryClient
@@ -16,6 +17,7 @@ import org.springframework.scheduling.annotation.EnableAsync;
@MapperScan("com.mhd.bi.domain.**.mapper")
@Import({SetFeildValueAspect.class, CommonService.class})
@EnableAsync
+@EnableScheduling
public class BiApplication {
public static void main(String[] args) {
diff --git a/mhd-bi/src/main/java/com/mhd/bi/domain/biSnapshotSync/repository/mapper/BiSnapshotWriteMapper.java b/mhd-bi/src/main/java/com/mhd/bi/domain/biSnapshotSync/repository/mapper/BiSnapshotWriteMapper.java
new file mode 100644
index 000000000..a6ca1a03e
--- /dev/null
+++ b/mhd-bi/src/main/java/com/mhd/bi/domain/biSnapshotSync/repository/mapper/BiSnapshotWriteMapper.java
@@ -0,0 +1,15 @@
+package com.mhd.bi.domain.biSnapshotSync.repository.mapper;
+
+import org.apache.ibatis.annotations.Param;
+
+/**
+ * 三张 BI 快照表写入(定时同步任务使用)
+ */
+public interface BiSnapshotWriteMapper {
+
+ int insertComprehensiveSnapshot(@Param("payloadJson") String payloadJson, @Param("remark") String remark);
+
+ int insertWarehouseTransportSnapshot(@Param("payloadJson") String payloadJson, @Param("remark") String remark);
+
+ int insertPlatformSurveillanceSnapshot(@Param("payloadJson") String payloadJson, @Param("remark") String remark);
+}
diff --git a/mhd-bi/src/main/java/com/mhd/bi/domain/biSnapshotSync/scheduler/BiReportSnapshotSyncScheduler.java b/mhd-bi/src/main/java/com/mhd/bi/domain/biSnapshotSync/scheduler/BiReportSnapshotSyncScheduler.java
new file mode 100644
index 000000000..f0229dac5
--- /dev/null
+++ b/mhd-bi/src/main/java/com/mhd/bi/domain/biSnapshotSync/scheduler/BiReportSnapshotSyncScheduler.java
@@ -0,0 +1,28 @@
+package com.mhd.bi.domain.biSnapshotSync.scheduler;
+
+import com.mhd.bi.domain.biSnapshotSync.service.BiReportSnapshotSyncService;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Component;
+
+/**
+ * 定时将业务快照写入 BI_COMPREHENSIVE_SNAPSHOT / BI_WAREHOUSE_TRANSPORT_SNAPSHOT / BI_PLATFORM_SURVEILLANCE_SNAPSHOT。
+ *
默认关闭,需在配置中设置 {@code mhd.bi.snapshot-sync.enabled=true}。
+ */
+@Slf4j
+@Component
+@RequiredArgsConstructor
+@ConditionalOnProperty(prefix = "mhd.bi.snapshot-sync", name = "enabled", havingValue = "true")
+public class BiReportSnapshotSyncScheduler {
+
+ private final BiReportSnapshotSyncService biReportSnapshotSyncService;
+
+ @Scheduled(cron = "${mhd.bi.snapshot-sync.cron:0 0 2 * * ?}")
+ public void runSnapshotSync() {
+ log.info("BI 报表快照定时同步开始");
+ biReportSnapshotSyncService.syncAllSnapshots();
+ log.info("BI 报表快照定时同步结束");
+ }
+}
diff --git a/mhd-bi/src/main/java/com/mhd/bi/domain/biSnapshotSync/service/BiReportSnapshotSyncService.java b/mhd-bi/src/main/java/com/mhd/bi/domain/biSnapshotSync/service/BiReportSnapshotSyncService.java
new file mode 100644
index 000000000..e12fb6477
--- /dev/null
+++ b/mhd-bi/src/main/java/com/mhd/bi/domain/biSnapshotSync/service/BiReportSnapshotSyncService.java
@@ -0,0 +1,98 @@
+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.interfaces.facadeApi.biReport.vo.ComprehensiveSituationVO;
+import com.mhd.bi.interfaces.facadeApi.biReport.vo.WarehouseTransportSituationVO;
+import com.mhd.bi.interfaces.facadeApi.biReport.vo.platform.PlatformSurveillanceVO;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+import java.util.Random;
+
+/**
+ * BI 三张快照表定时同步。
+ * 当前(临时):{@code build*} 使用 {@link BiSnapshotWeeklyRandomDataBuilder},每次执行使用新的 {@link Random},
+ * 故同一天多次手动触发、以及每次定时任务执行,生成的模拟数据均不相同(仍在基准 ±20% 内)。
+ * 后续改造:在三个 {@code build*} 中改为查库/Feign 聚合真实业务并组装 VO。
+ */
+@Slf4j
+@Service
+@RequiredArgsConstructor
+public class BiReportSnapshotSyncService {
+
+ private static final String REMARK_SYNC = "scheduled snapshot-sync";
+
+ private final BiSnapshotWriteMapper biSnapshotWriteMapper;
+ private final ObjectMapper objectMapper;
+
+ /**
+ * 依次同步三张快照;单表失败不影响其它表,只记日志。
+ */
+ public void syncAllSnapshots() {
+ syncComprehensiveSnapshot();
+ syncWarehouseTransportSnapshot();
+ syncPlatformSurveillanceSnapshot();
+ }
+
+ public void syncComprehensiveSnapshot() {
+ try {
+ ComprehensiveSituationVO vo = buildComprehensiveSnapshot();
+ String json = objectMapper.writeValueAsString(vo);
+ int rows = biSnapshotWriteMapper.insertComprehensiveSnapshot(json, REMARK_SYNC);
+ if (rows < 1) {
+ log.warn("BI 综合态势快照 INSERT 影响行数为 {},请确认 NGWL_TEST_BI.BI_COMPREHENSIVE_SNAPSHOT 权限及库是否一致", rows);
+ }
+ log.info("BI 综合态势快照已写入, affectedRows={}", rows);
+ } catch (Exception e) {
+ log.error("BI 综合态势快照同步失败", e);
+ }
+ }
+
+ public void syncWarehouseTransportSnapshot() {
+ try {
+ WarehouseTransportSituationVO vo = buildWarehouseTransportSnapshot();
+ String json = objectMapper.writeValueAsString(vo);
+ int rows = biSnapshotWriteMapper.insertWarehouseTransportSnapshot(json, REMARK_SYNC);
+ if (rows < 1) {
+ log.warn("BI 仓储运输快照 INSERT 影响行数为 {},请确认 NGWL_TEST_BI.BI_WAREHOUSE_TRANSPORT_SNAPSHOT", rows);
+ }
+ log.info("BI 仓储运输快照已写入, affectedRows={}", rows);
+ } catch (Exception e) {
+ log.error("BI 仓储运输快照同步失败", e);
+ }
+ }
+
+ public void syncPlatformSurveillanceSnapshot() {
+ try {
+ PlatformSurveillanceVO vo = buildPlatformSurveillanceSnapshot();
+ String json = objectMapper.writeValueAsString(vo);
+ int rows = biSnapshotWriteMapper.insertPlatformSurveillanceSnapshot(json, REMARK_SYNC);
+ if (rows < 1) {
+ log.warn("BI 月台监测快照 INSERT 影响行数为 {},请确认 NGWL_TEST_BI.BI_PLATFORM_SURVEILLANCE_SNAPSHOT", rows);
+ }
+ log.info("BI 月台监测快照已写入, affectedRows={}", rows);
+ } catch (Exception e) {
+ log.error("BI 月台监测快照同步失败", e);
+ }
+ }
+
+ /**
+ * TODO 业务落地:改为查询真实数据组装 VO。临时实现见 {@link BiSnapshotWeeklyRandomDataBuilder#comprehensive(Random)}。
+ */
+ protected ComprehensiveSituationVO buildComprehensiveSnapshot() {
+ return BiSnapshotWeeklyRandomDataBuilder.comprehensive(new Random());
+ }
+
+ /** TODO 业务落地:改为查询真实数据。临时实现见 {@link BiSnapshotWeeklyRandomDataBuilder#warehouseTransport(Random)}。 */
+ protected WarehouseTransportSituationVO buildWarehouseTransportSnapshot() {
+ return BiSnapshotWeeklyRandomDataBuilder.warehouseTransport(new Random());
+ }
+
+ /** TODO 业务落地:改为查询真实数据。临时实现见 {@link BiSnapshotWeeklyRandomDataBuilder#platformSurveillance(Random)}。 */
+ protected PlatformSurveillanceVO buildPlatformSurveillanceSnapshot() {
+ return BiSnapshotWeeklyRandomDataBuilder.platformSurveillance(new Random());
+ }
+}
diff --git a/mhd-bi/src/main/java/com/mhd/bi/domain/biSnapshotSync/support/BiSnapshotWeeklyRandomDataBuilder.java b/mhd-bi/src/main/java/com/mhd/bi/domain/biSnapshotSync/support/BiSnapshotWeeklyRandomDataBuilder.java
new file mode 100644
index 000000000..4b8eba8d3
--- /dev/null
+++ b/mhd-bi/src/main/java/com/mhd/bi/domain/biSnapshotSync/support/BiSnapshotWeeklyRandomDataBuilder.java
@@ -0,0 +1,308 @@
+package com.mhd.bi.domain.biSnapshotSync.support;
+
+import com.mhd.bi.interfaces.facadeApi.biReport.vo.ComprehensiveSituationVO;
+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.platform.*;
+
+import java.time.LocalDate;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Random;
+import java.util.stream.Collectors;
+
+/**
+ * 临时:在基准 ±20% 内生成模拟快照(基准对齐 insert_bi_snapshots_alternate_row_dm)。
+ * 调用 {@link #comprehensive(Random)} 等时须传入 {@link Random}:每次 {@code new Random()} 则每次结果不同;
+ * 若需可重复(如单测),可传入 {@link #randomForDate(java.time.LocalDate, long)} 等有固定种子的实例。
+ */
+public final class BiSnapshotWeeklyRandomDataBuilder {
+
+ private BiSnapshotWeeklyRandomDataBuilder() {
+ }
+
+ /**
+ * 固定种子(如同日多次一致),适用于单元测试等;生产模拟同步请使用 {@code new Random()}。
+ */
+ public static Random randomForDate(LocalDate date, long salt) {
+ long epochDay = date.toEpochDay();
+ salt = salt % 1000000007L;
+ return new Random(epochDay * 1_000_003L + salt * 7919L);
+ }
+
+ /**
+ * @deprecated 请使用 {@link #randomForDate(LocalDate, long)};历史方法名保留兼容,现已按「自然日」而非 ISO 周。
+ */
+ @Deprecated
+ public static Random randomForWeekOf(LocalDate date, long salt) {
+ return randomForDate(date, salt);
+ }
+
+ @Deprecated
+ public static Random randomForWeekOf(LocalDate date) {
+ return randomForDate(date, 0L);
+ }
+
+ private static double jitterFactor(Random r) {
+ return 0.8 + r.nextDouble() * 0.4;
+ }
+
+ static int jitterInt(int base, Random r) {
+ return (int) Math.round(base * jitterFactor(r));
+ }
+
+ static long jitterLong(long base, Random r) {
+ return Math.round(base * jitterFactor(r));
+ }
+
+ static double jitterDouble(double base, Random r) {
+ return Math.round(base * jitterFactor(r) * 10.0) / 10.0;
+ }
+
+ static int jitterPercentInt(int base, Random r) {
+ return Math.min(100, Math.max(0, jitterInt(base, r)));
+ }
+
+ private static double jitterPercentDouble(double base, Random r) {
+ double v = base * jitterFactor(r);
+ return Math.min(100.0, Math.max(0.0, Math.round(v * 10.0) / 10.0));
+ }
+
+ private static List jitterIntArray(int[] arr, Random r) {
+ return Arrays.stream(arr).map(v -> jitterInt(v, r)).boxed().collect(Collectors.toList());
+ }
+
+ public static ComprehensiveSituationVO comprehensive(Random r) {
+ return ComprehensiveSituationVO.builder()
+ .valueAddedServiceIncome(jitterLong(Baseline.COMP_INCOME, r))
+ .inventoryTurnover(Math.max(1, jitterInt(Baseline.COMP_TURNOVER, r)))
+ .orderCount(Math.max(0, jitterInt(Baseline.COMP_ORDERS, r)))
+ .vehicleUtilizationRate(jitterPercentDouble(Baseline.COMP_VEHICLE_PCT, r))
+ .fuelConsumptionPerHundredKm(Math.max(1, jitterInt(Baseline.COMP_FUEL, r)))
+ .incomeTrend(jitterIntArray(Baseline.COMP_INCOME_TREND, r))
+ .build();
+ }
+
+ public static WarehouseTransportSituationVO warehouseTransport(Random r) {
+ List dock = new ArrayList<>();
+ for (int v : Baseline.W_DOCK) {
+ dock.add(jitterPercentInt(v, r));
+ }
+ List custAmt = new ArrayList<>();
+ for (int v : Baseline.W_CUST_AMT) {
+ custAmt.add(jitterInt(v, r));
+ }
+ return WarehouseTransportSituationVO.builder()
+ .warehouseDistributionOnTimeRate(jitterPercentDouble(Baseline.W_WH_RATE, r))
+ .currentYearOrders(jitterLong(Baseline.W_YEAR_ORD, r))
+ .currentQuarterOrders(Math.max(0, jitterInt(Baseline.W_Q_ORD, r)))
+ .currentMonthOrders(Math.max(0, jitterInt(Baseline.W_M_ORD, r)))
+ .warehouseOrderTrend(jitterIntArray(Baseline.W_WH_TREND, r))
+ .throughput(jitterIntArray(Baseline.W_THROUGH, r))
+ .currentMonthTurnoverRate(Math.max(1, jitterInt(Baseline.W_M_TOR, r)))
+ .currentYearTurnoverRate(Math.max(1, jitterInt(Baseline.W_Y_TOR, r)))
+ .inventoryTurnoverTrend(jitterIntArray(Baseline.W_INV_TR, r))
+ .totalTransportIncome(Math.max(0, jitterInt(Baseline.W_INCOME, r)))
+ .orderCount(Math.max(0, jitterInt(Baseline.W_ORD, r)))
+ .transportTrips(Math.max(0, jitterInt(Baseline.W_TRIPS, r)))
+ .annualTransportVolume(Math.max(0, jitterInt(Baseline.W_VOL, r)))
+ .transportOrderTotal(Math.max(0, jitterInt(Baseline.W_TOT, r)))
+ .crossBorderTransportOrder(Math.max(0, jitterInt(Baseline.W_CB, r)))
+ .domesticTransportOrder(Math.max(0, jitterInt(Baseline.W_DM, r)))
+ .transportTripsTrend(jitterIntArray(Baseline.W_TRIP_TR, r))
+ .vehicleUtilizationRate(jitterIntArray(Baseline.W_VEH_UT, r))
+ .warehouseDockSyncRate(dock)
+ .customerContributionRank(CustomerContributionRankVO.builder()
+ .customerName(Arrays.asList(Baseline.W_CUST_NAMES))
+ .customerAmount(custAmt)
+ .build())
+ .build();
+ }
+
+ public static PlatformSurveillanceVO platformSurveillance(Random r) {
+ List vehicles = new ArrayList<>();
+ for (String[] row : Baseline.P_PLATES) {
+ int dur = jitterInt(Integer.parseInt(row[3]), r);
+ vehicles.add(PlatformVehicleItemVO.builder()
+ .plateNumber(row[0])
+ .status(row[1])
+ .platformId(row[2])
+ .platformDuration(Math.max(1, dur))
+ .build());
+ }
+
+ EfficiencyStatisticsVO eff = EfficiencyStatisticsVO.builder()
+ .entryOvertimeRate(jitterPercentInt(Baseline.P_ENT_OT, r))
+ .overtimeCount(Math.max(0, jitterInt(Baseline.P_OT_CNT, r)))
+ .platformOnTimeRate(jitterPercentInt(Baseline.P_PL_OT, r))
+ .avgPlatformDuration(Math.max(0.1, jitterDouble(Baseline.P_AVG_PL, r)))
+ .yardOnTimeRate(jitterPercentInt(Baseline.P_YD_OT, r))
+ .avgYardDuration(Math.max(0.1, jitterDouble(Baseline.P_AVG_YD, r)))
+ .build();
+
+ PlatformOverviewVO overview = PlatformOverviewVO.builder()
+ .totalPlatforms(Math.max(1, jitterInt(Baseline.P_TOT_PL, r)))
+ .currentOccupancyRate(jitterPercentInt(Baseline.P_OCC, r))
+ .operatingPlatforms(Math.max(0, jitterInt(Baseline.P_OP, r)))
+ .todayTasks(Math.max(0, jitterInt(Baseline.P_TASKS, r)))
+ .build();
+
+ VehicleStatusVO vs = VehicleStatusVO.builder()
+ .todayReservedVehicles(Math.max(0, jitterInt(Baseline.P_RESV, r)))
+ .notCheckedIn(Math.max(0, jitterInt(Baseline.P_NC, r)))
+ .operatingVehicles(Math.max(0, jitterInt(Baseline.P_OPV, r)))
+ .completedVehicles(Math.max(0, jitterInt(Baseline.P_DONE, r)))
+ .build();
+
+ List avgTrend = new ArrayList<>();
+ for (int i = 0; i < Baseline.P_MO_LABELS.length; i++) {
+ avgTrend.add(AvgOperationDurationTrendItemVO.builder()
+ .month(Baseline.P_MO_LABELS[i])
+ .yardDuration(Math.max(0.0, jitterDouble(Baseline.P_YD_D[i], r)))
+ .platformDuration(Math.max(0.0, jitterDouble(Baseline.P_PL_D[i], r)))
+ .build());
+ }
+
+ MonthlyTaskStatisticsVO monthly = MonthlyTaskStatisticsVO.builder()
+ .taskTotal(Math.max(0, jitterInt(Baseline.P_MT_TOT, r)))
+ .taskTotalYoY(jitterInt(Baseline.P_MT_YOY, r))
+ .avgTaskDuration(Math.max(0.1, jitterDouble(Baseline.P_MT_AVG, r)))
+ .avgDurationYoY(jitterInt(Baseline.P_MT_AVG_YOY, r))
+ .taskCompletionRate(jitterPercentInt(Baseline.P_MT_CR, r))
+ .completionRateYoY(jitterInt(Baseline.P_MT_CR_YOY, r))
+ .build();
+
+ List load = new ArrayList<>();
+ for (int i = 0; i < Baseline.P_LOAD_T.length; i++) {
+ load.add(TaskLoadItemVO.builder()
+ .time(Baseline.P_LOAD_T[i])
+ .taskCount(Math.max(0, jitterInt(Baseline.P_LOAD_C[i], r)))
+ .build());
+ }
+
+ List alarmTrend = new ArrayList<>();
+ for (int i = 0; i < Baseline.P_AL_D.length; i++) {
+ alarmTrend.add(PlatformAlarmTrendItemVO.builder()
+ .date(Baseline.P_AL_D[i])
+ .alarmCount(Math.max(0, jitterInt(Baseline.P_AL_C[i], r)))
+ .build());
+ }
+
+ List typeCounts = new ArrayList<>();
+ for (int i = 0; i < Baseline.P_TT_TYPES.length; i++) {
+ typeCounts.add(TaskTypeCountItemVO.builder()
+ .type(Baseline.P_TT_TYPES[i])
+ .count(Math.max(0, jitterInt(Baseline.P_TT_CNT[i], r)))
+ .build());
+ }
+
+ int todayAl = Math.max(0, jitterInt(Baseline.P_AL_TOT, r));
+ int handled = Math.max(0, jitterInt(Baseline.P_AL_H, r));
+ handled = Math.min(handled, todayAl);
+ int unhandled = Math.max(0, todayAl - handled);
+
+ List dist = new ArrayList<>();
+ for (int i = 0; i < Baseline.P_DIST_T.length; i++) {
+ dist.add(PlatformAlarmDistItemVO.builder()
+ .type(Baseline.P_DIST_T[i])
+ .count(Math.max(0, jitterInt(Baseline.P_DIST_C[i], r)))
+ .build());
+ }
+
+ return PlatformSurveillanceVO.builder()
+ .vehicles(vehicles)
+ .efficiencyStatistics(eff)
+ .platformOverview(overview)
+ .vehicleStatus(vs)
+ .avgOperationDurationTrend(avgTrend)
+ .monthlyTaskStatistics(monthly)
+ .taskLoadStatistics(load)
+ .platformAlarmTrend(alarmTrend)
+ .taskTypeStatistics(TaskTypeStatisticsVO.builder()
+ .totalTasks(Math.max(0, jitterInt(Baseline.P_TT_TOT, r)))
+ .taskTypes(typeCounts)
+ .build())
+ .platformAlarmStatistics(PlatformAlarmStatisticsVO.builder()
+ .todayAlarmTotal(todayAl)
+ .handled(handled)
+ .unhandled(unhandled)
+ .build())
+ .platformAlarmDistribution(dist)
+ .build();
+ }
+
+ /**
+ * 基准与 SQL 脚本 alternate sample 一致
+ */
+ private static final class Baseline {
+ static final long COMP_INCOME = 6_185_000L;
+ static final int COMP_TURNOVER = 18;
+ static final int COMP_ORDERS = 50_120;
+ static final double COMP_VEHICLE_PCT = 93.2;
+ static final int COMP_FUEL = 12;
+ static final int[] COMP_INCOME_TREND = {195, 248, 302, 415, 366, 488};
+
+ static final double W_WH_RATE = 96.8;
+ static final long W_YEAR_ORD = 612_800L;
+ static final int W_Q_ORD = 198_600;
+ static final int W_M_ORD = 28_440;
+ static final int[] W_WH_TREND = {82, 91, 77, 68, 103, 89};
+ static final int[] W_THROUGH = {18, 11, 26, 15, 9, 21};
+ static final int W_M_TOR = 4;
+ static final int W_Y_TOR = 5;
+ static final int[] W_INV_TR = {16, 19, 11, 24, 18, 14};
+ static final int W_INCOME = 7_230;
+ static final int W_ORD = 912;
+ static final int W_TRIPS = 601;
+ static final int W_VOL = 22;
+ static final int W_TOT = 5_100;
+ static final int W_CB = 2_680;
+ static final int W_DM = 2_420;
+ static final int[] W_TRIP_TR = {120, 95, 210, 155, 88, 175};
+ static final int[] W_VEH_UT = {520, 410, 380, 500, 590, 480};
+ static final int[] W_DOCK = {96, 91, 82, 75, 99, 88};
+ static final String[] W_CUST_NAMES = {"华东冷链", "华南汽配", "西南快消", "华北家电", "跨境达"};
+ static final int[] W_CUST_AMT = {198, 172, 205, 189, 221};
+
+ static final String[][] P_PLATES = {
+ {"粤A12345", "待入场", "#12", "88"},
+ {"闽D99887", "作业中", "#07", "142"},
+ {"粤B66220", "已离园", "#29", "201"}
+ };
+ static final int P_ENT_OT = 42;
+ static final int P_OT_CNT = 28;
+ static final int P_PL_OT = 88;
+ static final double P_AVG_PL = 3.8;
+ static final int P_YD_OT = 91;
+ static final double P_AVG_YD = 5.2;
+ static final int P_TOT_PL = 58;
+ static final int P_OCC = 62;
+ static final int P_OP = 31;
+ static final int P_TASKS = 418;
+ static final int P_RESV = 2_850;
+ static final int P_NC = 920;
+ static final int P_OPV = 1_180;
+ static final int P_DONE = 1_420;
+ static final String[] P_MO_LABELS = {"5月", "6月", "7月"};
+ static final double[] P_YD_D = {12, 16, 19};
+ static final double[] P_PL_D = {19, 21, 18};
+ static final int P_MT_TOT = 1_820;
+ static final int P_MT_YOY = 8;
+ static final double P_MT_AVG = 5.1;
+ static final int P_MT_AVG_YOY = -3;
+ static final int P_MT_CR = 97;
+ static final int P_MT_CR_YOY = 2;
+ static final String[] P_LOAD_T = {"8时", "10时", "14时"};
+ static final int[] P_LOAD_C = {45, 120, 156};
+ static final String[] P_AL_D = {"1日", "2日", "3日"};
+ static final int[] P_AL_C = {6, 9, 4};
+ static final int P_TT_TOT = 5_100;
+ static final String[] P_TT_TYPES = {"干线发车", "城配到仓", "跨境保税"};
+ static final int[] P_TT_CNT = {2_100, 1_800, 1_200};
+ static final int P_AL_TOT = 9;
+ static final int P_AL_H = 8;
+ static final String[] P_DIST_T = {"仓储-温湿度", "月台-停留超时", "园区-证件异常"};
+ static final int[] P_DIST_C = {120, 95, 77};
+ }
+}
diff --git a/mhd-bi/src/main/java/com/mhd/bi/interfaces/facadeApi/biReport/BiReportApi.java b/mhd-bi/src/main/java/com/mhd/bi/interfaces/facadeApi/biReport/BiReportApi.java
index 753219b74..2923cf61d 100644
--- a/mhd-bi/src/main/java/com/mhd/bi/interfaces/facadeApi/biReport/BiReportApi.java
+++ b/mhd-bi/src/main/java/com/mhd/bi/interfaces/facadeApi/biReport/BiReportApi.java
@@ -1,5 +1,6 @@
package com.mhd.bi.interfaces.facadeApi.biReport;
+import com.mhd.bi.domain.biSnapshotSync.service.BiReportSnapshotSyncService;
import com.mhd.bi.domain.biComprehensive.service.BiComprehensiveReportService;
import com.mhd.bi.domain.biPlatformSurveillance.service.BiPlatformSurveillanceReportService;
import com.mhd.bi.domain.biWarehouseTransport.service.BiWarehouseTransportReportService;
@@ -14,6 +15,7 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@@ -36,6 +38,16 @@ public class BiReportApi extends BaseController {
@Autowired
private BiPlatformSurveillanceReportService biPlatformSurveillanceReportService;
+ @Autowired
+ private BiReportSnapshotSyncService biReportSnapshotSyncService;
+
+
+ @ApiOperation(value = "手动触发快照同步", notes = "立即写入三张快照表;须带 X-BI-Access-Token")
+ @PostMapping("/snapshotSync/run")
+ public BiApiResult runSnapshotSyncOnce() {
+ biReportSnapshotSyncService.syncAllSnapshots();
+ return BiApiResult.ok(null);
+ }
/**
* 综合态势指标查询(按照 del_flag=1,按 create_time 最新一条)
diff --git a/mhd-bi/src/main/resources/bootstrap.yml b/mhd-bi/src/main/resources/bootstrap.yml
index 0ae3bc43a..2870a4169 100644
--- a/mhd-bi/src/main/resources/bootstrap.yml
+++ b/mhd-bi/src/main/resources/bootstrap.yml
@@ -1,12 +1,6 @@
# Tomcat
server:
port: 8021
-
-# BI 报表开放接口(/biReport):请求头 X-BI-Access-Token 须与 mhd.bi.access-token 一致
-mhd:
- bi:
- access-token: BI_TOKEN_8x7kL9mN2pQr5vWy3zA6cB
-
# Spring
spring:
application:
@@ -18,9 +12,9 @@ spring:
cloud:
nacos:
discovery:
-# server-addr: 127.0.0.1:8848
+ server-addr: 127.0.0.1:8848
# 线上测试环境配置 容器名+端口号
- server-addr: 10.33.0.129:6010
+# server-addr: 10.33.0.129:6010
# server-addr: 10.102.192.5:6848
# username: nacos
# password: manhuoda@2023
@@ -29,9 +23,9 @@ spring:
# username: nacos
# password: manhuoda@2023
config:
-# server-addr: 127.0.0.1:8848
+ server-addr: 127.0.0.1:8848
# 线上测试环境配置 容器名+端口号
- server-addr: 10.33.0.129:6010
+# server-addr: 10.33.0.129:6010
# server-addr: 10.102.192.5:6848
# username: nacos
# password: manhuoda@2023
diff --git a/mhd-bi/src/main/resources/mapper/biSnapshotSync/BiSnapshotWriteMapper.xml b/mhd-bi/src/main/resources/mapper/biSnapshotSync/BiSnapshotWriteMapper.xml
new file mode 100644
index 000000000..ffd318cc0
--- /dev/null
+++ b/mhd-bi/src/main/resources/mapper/biSnapshotSync/BiSnapshotWriteMapper.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+ insert into NGWL_TEST_BI.BI_COMPREHENSIVE_SNAPSHOT (PAYLOAD_JSON, CREATE_TIME, UPDATE_TIME, DEL_FLAG, REMARK)
+ values (#{payloadJson}, SYSDATE, SYSDATE, 1, #{remark})
+
+
+
+ insert into NGWL_TEST_BI.BI_WAREHOUSE_TRANSPORT_SNAPSHOT (PAYLOAD_JSON, CREATE_TIME, UPDATE_TIME, DEL_FLAG, REMARK)
+ values (#{payloadJson}, SYSDATE, SYSDATE, 1, #{remark})
+
+
+
+ insert into NGWL_TEST_BI.BI_PLATFORM_SURVEILLANCE_SNAPSHOT (PAYLOAD_JSON, CREATE_TIME, UPDATE_TIME, DEL_FLAG, REMARK)
+ values (#{payloadJson}, SYSDATE, SYSDATE, 1, #{remark})
+
+