feat(assets): 展示近七天资产趋势并支持业务回溯归档
This commit is contained in:
@@ -2,15 +2,16 @@ import { filterAssetVehiclesByPermission, maskCustomerNames } from '../../auth/p
|
||||
import type { AuthUser } from '../../auth/types.js';
|
||||
import type { Vehicle, VehicleRow } from '../../types.js';
|
||||
import { isOperatingVehicle, isInventoryVehicle, transformRow } from '../vehicles/model.js';
|
||||
import { CAPTURE_WINDOW_MS, monthCutoff, shanghaiTimestamp, type HistoryCounts, type HistoryPoint } from '../../../shared/assets/history.js';
|
||||
import { CAPTURE_WINDOW_MS, historyCutoff, shanghaiTimestamp, type HistoryCounts, type HistoryPoint } from '../../../shared/assets/history.js';
|
||||
|
||||
export interface HistoryVehicle extends Vehicle {
|
||||
businessBasis?: string;
|
||||
vehicleStatus: string | null;
|
||||
disposition: 'operating' | 'inventory';
|
||||
}
|
||||
export interface HistoryBatch {
|
||||
id: string; month: string; status: 'COMPLETE' | 'FAILED' | 'MISSED';
|
||||
source: 'AUTO' | 'IMPORT'; scheduledFor: string; capturedAt: string | null;
|
||||
source: 'AUTO' | 'IMPORT' | '业务回溯'; scheduledFor: string; capturedAt: string | null;
|
||||
counts: HistoryCounts;
|
||||
}
|
||||
export interface HistorySettings { enabledAt: string }
|
||||
@@ -47,9 +48,9 @@ export function counts(vehicles: Vehicle[]): HistoryCounts {
|
||||
return { total: vehicles.length, operating: vehicles.filter(isOperatingVehicle).length, inventory: vehicles.filter(isInventoryVehicle).length };
|
||||
}
|
||||
export function makePoint(month: string, now: Date, batch?: HistoryBatch, data?: HistoryVehicle[], live?: HistoryVehicle[], annual = false): HistoryPoint {
|
||||
const cutoff = batch ? new Date(batch.scheduledFor) : monthCutoff(month);
|
||||
const cutoff = batch ? new Date(batch.scheduledFor) : historyCutoff(month);
|
||||
let state: HistoryPoint['state'] = 'MISSING';
|
||||
if (cutoff > now) state = month.slice(0, 4) === shanghaiTimestamp(now).slice(0, 4) && (annual || month === shanghaiTimestamp(now).slice(0, 7)) ? 'LIVE' : 'FUTURE';
|
||||
if (cutoff > now) state = month.slice(0, 4) === shanghaiTimestamp(now).slice(0, 4) && (annual || month === shanghaiTimestamp(now).slice(0, month.length)) ? 'LIVE' : 'FUTURE';
|
||||
else if (batch?.status === 'COMPLETE') state = 'ARCHIVED';
|
||||
else if (batch?.status === 'FAILED') state = 'FAILED';
|
||||
else if (now.getTime() < cutoff.getTime() + CAPTURE_WINDOW_MS && batch?.status !== 'MISSED') state = 'CAPTURING';
|
||||
@@ -57,9 +58,9 @@ export function makePoint(month: string, now: Date, batch?: HistoryBatch, data?:
|
||||
const pointCounts = state === 'ARCHIVED' ? counts(data || []) : state === 'LIVE' ? counts(live || []) : null;
|
||||
return {
|
||||
period: annual ? month.slice(0, 4) : month,
|
||||
label: annual ? `${month.slice(0, 4)}年` : `${Number(month.slice(5))}月`, month,
|
||||
label: annual ? `${month.slice(0, 4)}年` : month.length === 10 ? month.slice(5).replace('-', '/') : `${Number(month.slice(5))}月`, month: month.slice(0, 7),
|
||||
scheduledFor: batch?.scheduledFor || shanghaiTimestamp(cutoff),
|
||||
asOf: state === 'LIVE' ? shanghaiTimestamp(now) : state === 'ARCHIVED' ? batch!.capturedAt : null,
|
||||
asOf: state === 'LIVE' ? shanghaiTimestamp(now) : state === 'ARCHIVED' ? (batch!.source === '业务回溯' ? batch!.scheduledFor : batch!.capturedAt) : null,
|
||||
state, source: state === 'LIVE' ? 'LIVE' : state === 'ARCHIVED' ? batch!.source : null,
|
||||
batchId: state === 'ARCHIVED' ? batch!.id : null, counts: pointCounts,
|
||||
difference: null, comparisonLabel: '暂无可比数据', detailAvailable: available,
|
||||
@@ -75,7 +76,7 @@ export function comparePoint(point: HistoryPoint, previous: HistoryPoint | undef
|
||||
} : null } } : {}),
|
||||
comparisonLabel: comparable ? `推算值较${annual ? '上年年末' : '上月末'}` : '推算与实时或正式快照口径不同,暂无可比数据' };
|
||||
}
|
||||
const label = annual ? '上年末' : '上月末';
|
||||
const label = annual ? '上年末' : point.period.length === 10 ? '昨日' : '上月末';
|
||||
return { ...point, difference: point.counts && previous?.counts ? {
|
||||
total: point.counts.total - previous.counts.total,
|
||||
inventory: point.counts.inventory - previous.counts.inventory,
|
||||
|
||||
Reference in New Issue
Block a user