diff --git a/src/modules/mileage/MonitoringView.tsx b/src/modules/mileage/MonitoringView.tsx
index 78694ab..723f505 100644
--- a/src/modules/mileage/MonitoringView.tsx
+++ b/src/modules/mileage/MonitoringView.tsx
@@ -12,6 +12,12 @@ import PlateMultiSelect from './PlateMultiSelect';
import { exportMileageXlsx } from './xlsx-export';
import VehicleDetailModal from './VehicleDetailModal';
+const HIGH_MILEAGE_ALERT_TARGETS = new Set([
+ '交投40辆4.5T普货',
+ '交投190辆4.5T冷链车',
+]);
+const HIGH_MILEAGE_ALERT_KM = 800;
+
const SearchableSelect = ({
options,
value,
@@ -137,6 +143,12 @@ export default function MonitoringView() {
const departments = filterOptions.departments;
const plateNumbers = filterOptions.plates;
+ const isHighMileageAlert = useCallback((v: MonitoringVehicle) => {
+ const inAlertTarget = v.targetNames?.some(name => HIGH_MILEAGE_ALERT_TARGETS.has(name))
+ || HIGH_MILEAGE_ALERT_TARGETS.has(filterTargetName);
+ return inAlertTarget && Math.max(0, v.dailyKm || 0) >= HIGH_MILEAGE_ALERT_KM;
+ }, [filterTargetName]);
+
// 加载首页数据
const loadFirstPage = useCallback(() => {
setPageLoading(true);
@@ -525,7 +537,9 @@ export default function MonitoringView() {
- {fullscreenVehicles.map((v) => (
+ {fullscreenVehicles.map((v) => {
+ const highMileageAlert = isHighMileageAlert(v);
+ return (
|
@@ -535,8 +549,8 @@ export default function MonitoringView() {
| {v.rentStatus || '-'} |
{v.department || '-'} |
-
- {(v.isDataSynced || v.totalKm != null) ? <>{Math.max(0, v.dailyKm || 0).toLocaleString()} km> : 未对接}
+
+ {(v.isDataSynced || v.totalKm != null) ? <>{Math.max(0, v.dailyKm || 0).toLocaleString()} km> : 未对接}
|
@@ -545,7 +559,8 @@ export default function MonitoringView() {
|
- ))}
+ );
+ })}
@@ -896,7 +911,9 @@ export default function MonitoringView() {
)}
- {filteredVehicles.map((v) => (
+ {filteredVehicles.map((v) => {
+ const highMileageAlert = isHighMileageAlert(v);
+ return (
)}
今
-
- {(v.isDataSynced || v.totalKm != null) ? <>{Math.max(0, v.dailyKm || 0).toLocaleString()}
km> :
未对接}
+
+ {(v.isDataSynced || v.totalKm != null) ? <>{Math.max(0, v.dailyKm || 0).toLocaleString()} km> : 未对接}
@@ -942,7 +959,8 @@ export default function MonitoringView() {
- ))}
+ );
+ })}
{filteredVehicles.length === 0 && !loadingMore && (
diff --git a/src/modules/mileage/types.ts b/src/modules/mileage/types.ts
index e7371ca..4207619 100644
--- a/src/modules/mileage/types.ts
+++ b/src/modules/mileage/types.ts
@@ -13,6 +13,7 @@ export interface MonitoringVehicle {
entity: string | null;
project: string | null;
region: string | null;
+ targetNames: string[];
}
export interface MonitoringStats {
diff --git a/src/server/routes/mileage/cache.ts b/src/server/routes/mileage/cache.ts
index 10c7e5d..5bce187 100644
--- a/src/server/routes/mileage/cache.ts
+++ b/src/server/routes/mileage/cache.ts
@@ -65,6 +65,41 @@ interface MileageRow {
source: string;
}
+interface TargetRow {
+ id: number;
+ target_name: string;
+ plate_number: string;
+}
+
+async function fetchTargetRows(): Promise {
+ return pool.execute(
+ `SELECT t.id, t.target_name, v.plate_number
+ FROM tab_mileage_assessment_target t
+ JOIN tab_mileage_assessment_vehicle v ON v.target_id = t.id AND v.is_deleted = 0
+ WHERE t.is_deleted = 0`
+ ).then(([rows]) => rows as TargetRow[]);
+}
+
+function buildTargetPlatesMap(targetRows: TargetRow[]): Map> {
+ const targetPlatesMap = new Map>();
+ for (const r of targetRows) {
+ const set = targetPlatesMap.get(r.target_name) || new Set();
+ set.add(r.plate_number);
+ targetPlatesMap.set(r.target_name, set);
+ }
+ return targetPlatesMap;
+}
+
+function buildPlateTargetNamesMap(targetRows: TargetRow[]): Map {
+ const map = new Map();
+ for (const r of targetRows) {
+ const list = map.get(r.plate_number) || [];
+ list.push(r.target_name);
+ map.set(r.plate_number, list);
+ }
+ return map;
+}
+
async function fetchBizTotalMileageMap(): Promise