feat: flag mileage target coverage gaps

This commit is contained in:
kkfluous
2026-08-07 17:52:49 +08:00
parent bca0f7fe82
commit d1ed3903fe
6 changed files with 74 additions and 2 deletions
+19 -1
View File
@@ -6,7 +6,7 @@ import {
Cell, LabelList,
} from 'recharts';
import {
Truck, ChevronDown, Maximize2, Minimize2,
AlertTriangle, Truck, ChevronDown, Maximize2, Minimize2,
Search, ArrowUpDown, X, RotateCcw, Calendar,
} from 'lucide-react';
import type { TargetSummary, TargetVehicle, TargetYearlyAssessment, TrendPoint } from './types';
@@ -14,6 +14,7 @@ import { fetchTargets, fetchTargetVehicles, fetchTrend } from './api';
import Blur from '../../components/Blur';
import { weightedCompletionRate } from '../../shared/analytics/metrics';
import { formatMileageSnapshotDateTime } from './data-freshness';
import { assessVehicleCoverage } from './assessment-coverage';
import MileageAttributionView from './MileageAttributionView';
import {
filterAttributionVehicles,
@@ -94,6 +95,9 @@ export default function StatisticsView() {
const selectedTarget = targets.find(t => t.id === selectedTargetId);
const selectedTargetVehicles = selectedTargetId === null ? [] : targetVehiclesMap[selectedTargetId] || [];
const selectedAssessment = selectedTarget ? getTargetAssessment(selectedTarget, assessmentYearMap[selectedTarget.id]) : null;
const selectedCoverage = selectedTarget
? assessVehicleCoverage(selectedTarget.declaredVehicleCount, selectedTarget.vehicleCount)
: null;
const selectedAssessmentYear = selectedAssessment?.yearNumber;
const selectedCompletion = selectedAssessment?.completionRate ?? selectedTarget?.avgCompletion ?? 0;
const selectedRemaining = selectedAssessment?.remaining ?? 0;
@@ -361,6 +365,20 @@ export default function StatisticsView() {
</motion.div>
)}
{selectedTarget && selectedCoverage && selectedCoverage.status !== 'matched' && (
<div role="alert" className="flex items-start gap-2 rounded-xl border border-amber-200 bg-amber-50 px-3 py-2 text-amber-900">
<AlertTriangle size={15} className="mt-0.5 shrink-0 text-amber-600" />
<div className="min-w-0 text-[11px] font-bold leading-5">
<span className="font-black"></span>
{selectedCoverage.declaredCount} {selectedCoverage.activeCount}
{selectedCoverage.status === 'missing'
? `缺少 ${Math.abs(selectedCoverage.difference)}`
: `超出 ${selectedCoverage.difference}`}
</div>
</div>
)}
{selectedTarget && (
<MileageAttributionView
vehicles={selectedTargetVehicles}