feat: preserve mileage assessment years
This commit is contained in:
@@ -49,6 +49,10 @@ function getTargetAssessment(target: TargetSummary, selectedYear?: number): Targ
|
||||
return target.yearlyAssessments.find(item => item.yearNumber === selectedYear) || target.yearlyAssessments[0];
|
||||
}
|
||||
|
||||
function resolveAssessmentYear(target: TargetSummary, requestedYear?: number): number | undefined {
|
||||
return getTargetAssessment(target, requestedYear)?.yearNumber;
|
||||
}
|
||||
|
||||
function fmtDateLabel(date: string | null): string {
|
||||
if (!date) return '';
|
||||
const [year, month, day] = date.split('-');
|
||||
@@ -96,10 +100,12 @@ export default function StatisticsView() {
|
||||
const [viewAllLoading, setViewAllLoading] = useState(false);
|
||||
const [viewAllHistoricalVehicles, setViewAllHistoricalVehicles] = useState<TargetVehicle[] | null>(null);
|
||||
const targetVehicleRequestsRef = useRef(new Set<number>());
|
||||
const initialDrillContextRef = useRef(drillContext);
|
||||
|
||||
const selectedTarget = targets.find(t => t.id === selectedTargetId);
|
||||
const selectedTargetVehicles = selectedTargetId === null ? [] : targetVehiclesMap[selectedTargetId] || [];
|
||||
const selectedAssessment = selectedTarget ? getTargetAssessment(selectedTarget, assessmentYearMap[selectedTarget.id]) : null;
|
||||
const selectedAssessmentYear = selectedAssessment?.yearNumber;
|
||||
const selectedCompletion = selectedAssessment?.completionRate ?? selectedTarget?.avgCompletion ?? 0;
|
||||
const selectedRemaining = selectedAssessment?.remaining ?? 0;
|
||||
const selectedDaysLeft = selectedAssessment?.daysLeft ?? selectedTarget?.daysLeft ?? 0;
|
||||
@@ -136,6 +142,10 @@ export default function StatisticsView() {
|
||||
}, []);
|
||||
|
||||
const selectTarget = useCallback((targetId: number) => {
|
||||
const target = targets.find(item => item.id === targetId);
|
||||
const assessmentYear = target
|
||||
? resolveAssessmentYear(target, assessmentYearMap[targetId])
|
||||
: undefined;
|
||||
setSelectedTargetId(targetId);
|
||||
setExpandedTargetId(targetId);
|
||||
setViewAllTargetId(null);
|
||||
@@ -143,9 +153,10 @@ export default function StatisticsView() {
|
||||
commitDrillContext({
|
||||
level: 'overview',
|
||||
targetId,
|
||||
assessmentYear,
|
||||
sourcePriority: ['instrument'],
|
||||
}, 'replace');
|
||||
}, [commitDrillContext]);
|
||||
}, [assessmentYearMap, commitDrillContext, targets]);
|
||||
|
||||
const openAttributionGroup = useCallback((value: string) => {
|
||||
if (selectedTargetId === null) return;
|
||||
@@ -157,11 +168,29 @@ export default function StatisticsView() {
|
||||
commitDrillContext({
|
||||
level: 'breakdown',
|
||||
targetId: selectedTargetId,
|
||||
assessmentYear: selectedAssessmentYear,
|
||||
dimension: attributionDimension,
|
||||
dimensionValue: value,
|
||||
sourcePriority: ['instrument'],
|
||||
}, 'push');
|
||||
}, [attributionDimension, commitDrillContext, selectedTarget?.targetName, selectedTargetId]);
|
||||
}, [attributionDimension, commitDrillContext, selectedAssessmentYear, selectedTarget?.targetName, selectedTargetId]);
|
||||
|
||||
const openTargetVehicles = useCallback((target: TargetSummary) => {
|
||||
const assessmentYear = resolveAssessmentYear(target, assessmentYearMap[target.id]);
|
||||
setViewAllTargetId(target.id);
|
||||
setViewAllTargetName(target.targetName);
|
||||
setViewAllSearch('');
|
||||
setViewAllDate(getDefaultDate());
|
||||
setViewAllHistoricalVehicles(null);
|
||||
commitDrillContext({
|
||||
level: 'breakdown',
|
||||
targetId: target.id,
|
||||
assessmentYear,
|
||||
dimension: 'assessment-target',
|
||||
dimensionValue: target.targetName,
|
||||
sourcePriority: ['instrument'],
|
||||
}, 'push');
|
||||
}, [assessmentYearMap, commitDrillContext]);
|
||||
|
||||
const closeVehiclePanel = useCallback(() => {
|
||||
setViewAllTargetId(null);
|
||||
@@ -170,10 +199,11 @@ export default function StatisticsView() {
|
||||
commitDrillContext({
|
||||
level: 'overview',
|
||||
targetId: selectedTargetId || undefined,
|
||||
assessmentYear: selectedAssessmentYear,
|
||||
sourcePriority: ['instrument'],
|
||||
}, 'replace');
|
||||
}
|
||||
}, [commitDrillContext, drillContext.level, selectedTargetId]);
|
||||
}, [commitDrillContext, drillContext.level, selectedAssessmentYear, selectedTargetId]);
|
||||
|
||||
const openVehicleDiagnostic = useCallback((vehicle: TargetVehicle) => {
|
||||
const url = buildMileageDrillUrl(
|
||||
@@ -181,6 +211,7 @@ export default function StatisticsView() {
|
||||
{
|
||||
level: 'vehicle',
|
||||
targetId: viewAllTargetId || selectedTargetId || undefined,
|
||||
assessmentYear: selectedAssessmentYear,
|
||||
plate: vehicle.plateNumber,
|
||||
startDate: viewAllDate,
|
||||
endDate: viewAllDate,
|
||||
@@ -189,11 +220,12 @@ export default function StatisticsView() {
|
||||
);
|
||||
window.history.pushState(null, '', url);
|
||||
window.dispatchEvent(new HashChangeEvent('hashchange'));
|
||||
}, [selectedTargetId, viewAllDate, viewAllTargetId]);
|
||||
}, [selectedAssessmentYear, selectedTargetId, viewAllDate, viewAllTargetId]);
|
||||
|
||||
// Load targets on mount
|
||||
useEffect(() => {
|
||||
fetchTargets().then(data => {
|
||||
const initialContext = initialDrillContextRef.current;
|
||||
const focused = data.find(item => item.targetName.includes('羚牛136')) || data[0];
|
||||
const ordered = focused
|
||||
? [focused, ...data.filter(item => item.id !== focused.id)]
|
||||
@@ -203,7 +235,20 @@ export default function StatisticsView() {
|
||||
if (initialTarget) {
|
||||
setSelectedTargetId(initialTarget.id);
|
||||
setExpandedTargetId(initialTarget.id);
|
||||
setAssessmentYearMap(Object.fromEntries(ordered.map(item => [item.id, item.yearlyAssessments[0]?.yearNumber || 1])));
|
||||
const initialYears = Object.fromEntries(ordered.map(item => [
|
||||
item.id,
|
||||
resolveAssessmentYear(item, item.id === initialContext.targetId ? initialContext.assessmentYear : undefined) || 1,
|
||||
]));
|
||||
setAssessmentYearMap(initialYears);
|
||||
|
||||
if (initialContext.targetId === initialTarget.id) {
|
||||
const resolvedYear = initialYears[initialTarget.id];
|
||||
if (resolvedYear && resolvedYear !== initialContext.assessmentYear) {
|
||||
const normalizedContext = { ...initialContext, assessmentYear: resolvedYear };
|
||||
window.history.replaceState(null, '', buildMileageDrillUrl(window.location, normalizedContext));
|
||||
setDrillContext(normalizedContext);
|
||||
}
|
||||
}
|
||||
}
|
||||
}).catch(() => {});
|
||||
}, []);
|
||||
@@ -236,7 +281,14 @@ export default function StatisticsView() {
|
||||
const handlePopState = () => {
|
||||
const next = parseMileageDrillContext(window.location.search);
|
||||
setDrillContext(next);
|
||||
if (next.targetId) setSelectedTargetId(next.targetId);
|
||||
if (next.targetId) {
|
||||
setSelectedTargetId(next.targetId);
|
||||
const target = targets.find(item => item.id === next.targetId);
|
||||
const resolvedYear = target ? resolveAssessmentYear(target, next.assessmentYear) : undefined;
|
||||
if (resolvedYear) {
|
||||
setAssessmentYearMap(prev => ({ ...prev, [next.targetId!]: resolvedYear }));
|
||||
}
|
||||
}
|
||||
if (next.level === 'breakdown' && next.targetId && next.dimensionValue) {
|
||||
setAttributionDimension(next.dimension === 'customer' ? 'customer' : 'department');
|
||||
setViewAllTargetId(next.targetId);
|
||||
@@ -246,7 +298,7 @@ export default function StatisticsView() {
|
||||
};
|
||||
window.addEventListener('popstate', handlePopState);
|
||||
return () => window.removeEventListener('popstate', handlePopState);
|
||||
}, []);
|
||||
}, [targets]);
|
||||
|
||||
const viewAllVehicles = useMemo(() => {
|
||||
const vehicles = viewAllHistoricalVehicles
|
||||
@@ -536,7 +588,13 @@ export default function StatisticsView() {
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
onChange={(e) => {
|
||||
e.stopPropagation();
|
||||
setAssessmentYearMap(prev => ({ ...prev, [target.id]: Number(e.target.value) }));
|
||||
const assessmentYear = Number(e.target.value);
|
||||
setAssessmentYearMap(prev => ({ ...prev, [target.id]: assessmentYear }));
|
||||
commitDrillContext({
|
||||
...drillContext,
|
||||
targetId: target.id,
|
||||
assessmentYear,
|
||||
}, 'replace');
|
||||
}}
|
||||
className="bg-white border border-blue-100 rounded-lg px-2 py-1 text-[10px] font-bold text-blue-700 outline-none"
|
||||
>
|
||||
@@ -625,9 +683,7 @@ export default function StatisticsView() {
|
||||
<button
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
setViewAllTargetId(target.id);
|
||||
setViewAllTargetName(target.targetName);
|
||||
setViewAllDate(getDefaultDate());
|
||||
openTargetVehicles(target);
|
||||
}}
|
||||
className="text-[8px] text-blue-500 font-bold hover:underline"
|
||||
>
|
||||
@@ -803,8 +859,10 @@ export default function StatisticsView() {
|
||||
<h3 className="text-lg font-black text-slate-900">
|
||||
{viewAllTargetName || selectedTarget?.targetName || '考核车辆'}
|
||||
</h3>
|
||||
<p className="text-xs font-bold text-slate-400 uppercase tracking-widest mt-1">车辆实时明细清单</p>
|
||||
{selectedBreakdownValue && (
|
||||
<p className="mt-1 text-xs font-bold uppercase tracking-widest text-slate-400">
|
||||
{selectedAssessment ? `${selectedAssessment.label} · ` : ''}车辆实时明细清单
|
||||
</p>
|
||||
{selectedBreakdownValue && drillContext.dimension !== 'assessment-target' && (
|
||||
<p className="mt-1 text-[10px] font-bold text-blue-600">{selectedBreakdownValue}</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user