feat(platform): sync dashboard customer time window
This commit is contained in:
@@ -154,6 +154,16 @@ function dayRangeText(dateFrom?: string, dateTo?: string) {
|
||||
return days <= 0 ? '同日或倒置时间窗' : `${days} 天窗口`;
|
||||
}
|
||||
|
||||
function naturalDayRangeText(dateFrom?: string, dateTo?: string) {
|
||||
if (!dateFrom && !dateTo) return '未限定时间';
|
||||
if (!dateFrom || !dateTo) return '单边时间窗';
|
||||
const start = new Date(`${dateFrom}T00:00:00+08:00`).getTime();
|
||||
const end = new Date(`${dateTo}T00:00:00+08:00`).getTime();
|
||||
if (!Number.isFinite(start) || !Number.isFinite(end)) return '时间格式待确认';
|
||||
const days = Math.max(0, Math.round((end - start) / 86400000)) + 1;
|
||||
return days <= 0 ? '同日或倒置时间窗' : `${days} 天窗口`;
|
||||
}
|
||||
|
||||
function priorityIssueVehicleLabel(row: QualityIssueRow) {
|
||||
const identity = row.vin?.trim() && row.vin !== 'unknown' ? row.vin.trim() : row.phone?.trim();
|
||||
return [row.plate?.trim(), identity].filter(Boolean).join(' / ') || row.sourceEndpoint || '-';
|
||||
@@ -261,6 +271,14 @@ function sourceConsistencyAction(row: VehicleCoverageRow, onFilter: (filters: Re
|
||||
return <Tag color={color}>{label}</Tag>;
|
||||
}
|
||||
|
||||
function defaultTimeMonitorFilters() {
|
||||
const today = todayDateString();
|
||||
return {
|
||||
dateFrom: previousDateString(today),
|
||||
dateTo: today
|
||||
};
|
||||
}
|
||||
|
||||
export function Dashboard({
|
||||
onOpenVehicle,
|
||||
onOpenQuality,
|
||||
@@ -268,7 +286,8 @@ export function Dashboard({
|
||||
onOpenRealtime,
|
||||
onOpenVehicles,
|
||||
onOpenHistory,
|
||||
onOpenMileage
|
||||
onOpenMileage,
|
||||
customerTimeWindow
|
||||
}: {
|
||||
onOpenVehicle: (vin: string, protocol?: string) => void;
|
||||
onOpenQuality: (filters?: Record<string, string>) => void;
|
||||
@@ -277,6 +296,7 @@ export function Dashboard({
|
||||
onOpenVehicles: (filters?: Record<string, string>) => void;
|
||||
onOpenHistory: (filters?: Record<string, string>) => void;
|
||||
onOpenMileage: (filters?: Record<string, string>) => void;
|
||||
customerTimeWindow?: Record<string, string>;
|
||||
}) {
|
||||
const [summary, setSummary] = useState<DashboardSummary | null>(null);
|
||||
const [serviceSummary, setServiceSummary] = useState<VehicleServiceSummary | null>(null);
|
||||
@@ -284,13 +304,7 @@ export function Dashboard({
|
||||
const [locations, setLocations] = useState<VehicleRealtimeRow[]>([]);
|
||||
const [qualityIssues, setQualityIssues] = useState<QualityIssueRow[]>([]);
|
||||
const [opsHealth, setOpsHealth] = useState<OpsHealth | null>(null);
|
||||
const [timeMonitorFilters, setTimeMonitorFilters] = useState<Record<string, string>>(() => {
|
||||
const today = todayDateString();
|
||||
return {
|
||||
dateFrom: previousDateString(today),
|
||||
dateTo: today
|
||||
};
|
||||
});
|
||||
const [timeMonitorFilters, setTimeMonitorFilters] = useState<Record<string, string>>(defaultTimeMonitorFilters);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [coverageLoading, setCoverageLoading] = useState(false);
|
||||
const [coverageServiceStatusTitle, setCoverageServiceStatusTitle] = useState('');
|
||||
@@ -343,6 +357,25 @@ export function Dashboard({
|
||||
.finally(() => setLoading(false));
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
const dateFrom = customerTimeWindow?.dateFrom?.trim();
|
||||
const dateTo = customerTimeWindow?.dateTo?.trim();
|
||||
if (!dateFrom && !dateTo) {
|
||||
return;
|
||||
}
|
||||
setTimeMonitorFilters((previous) => {
|
||||
const next = {
|
||||
...previous,
|
||||
dateFrom: dateFrom ?? '',
|
||||
dateTo: dateTo ?? ''
|
||||
};
|
||||
if (previous.dateFrom === next.dateFrom && previous.dateTo === next.dateTo) {
|
||||
return previous;
|
||||
}
|
||||
return next;
|
||||
});
|
||||
}, [customerTimeWindow?.dateFrom, customerTimeWindow?.dateTo]);
|
||||
|
||||
const serviceActionQueue = useMemo<Array<{ label: string; count: number; filters: Record<string, string>; detail: string }>>(() => {
|
||||
const items: Array<{ label: string; count: number; filters: Record<string, string>; detail: string }> = [];
|
||||
if ((serviceSummary?.noDataVehicles ?? 0) > 0) {
|
||||
@@ -873,7 +906,14 @@ export function Dashboard({
|
||||
}
|
||||
];
|
||||
const timeMonitorScopeValue = timeMonitorScope();
|
||||
const timeMonitorWindowLabel = dayRangeText(timeMonitorScopeValue.dateFrom, timeMonitorScopeValue.dateTo);
|
||||
const usesCustomerTimeWindow = Boolean(
|
||||
(customerTimeWindow?.dateFrom || customerTimeWindow?.dateTo)
|
||||
&& customerTimeWindow?.dateFrom === timeMonitorScopeValue.dateFrom
|
||||
&& customerTimeWindow?.dateTo === timeMonitorScopeValue.dateTo
|
||||
);
|
||||
const timeMonitorWindowLabel = usesCustomerTimeWindow
|
||||
? naturalDayRangeText(timeMonitorScopeValue.dateFrom, timeMonitorScopeValue.dateTo)
|
||||
: dayRangeText(timeMonitorScopeValue.dateFrom, timeMonitorScopeValue.dateTo);
|
||||
const timeMonitorChecklist = [
|
||||
{
|
||||
label: '范围可解释',
|
||||
@@ -1003,7 +1043,7 @@ export function Dashboard({
|
||||
{
|
||||
step: '1',
|
||||
label: '锁定范围',
|
||||
value: dayRangeText(timeMonitorScopeValue.dateFrom, timeMonitorScopeValue.dateTo),
|
||||
value: timeMonitorWindowLabel,
|
||||
detail: timeMonitorScopeValue.keyword ? `单车 ${timeMonitorScopeValue.keyword}` : '先确认车辆或车辆池,再应用同一时间窗。',
|
||||
action: '应用时间窗',
|
||||
color: timeMonitorHasRange ? 'green' as const : 'orange' as const,
|
||||
|
||||
Reference in New Issue
Block a user