fix: restore BI quick date state

This commit is contained in:
kkfluous
2026-08-07 16:49:42 +08:00
parent 3d57787e61
commit ea9c9212e2
5 changed files with 48 additions and 13 deletions
+1
View File
@@ -152,6 +152,7 @@ SUM(fee) / NULLIF(SUM(kwh), 0)
- 已完成 ETC 记录/账单视图、日期、搜索和分页 URL 状态,以及超范围页码自动纠正。
- 已统一共享加载、空数据和故障组件的顶层卡片与明细内联边界,消除能源明细中的嵌套状态卡片。
- 已统一电能、氢能和 ETC 日期范围输入;电能与氢能共用快捷区间算法和单一输入事件路径。
- 电能与氢能可根据 URL 日期恢复快捷区间选中态;过期区间自动归为自定义,避免标签与统计日期不一致。
- 已完成并发同参 GET 去重。
### 阶段 B:核心下钻闭环
+12 -7
View File
@@ -15,6 +15,7 @@ import AnalysisDateFilters from './AnalysisDateFilters';
import {
dateRangeModeLabel,
getQuickDateRange,
inferDateRangeMode,
normalizeDateRange,
type DateRangeMode,
} from './date-range';
@@ -24,12 +25,15 @@ export default function ElectricDaily() {
parseElectricDrillContext(window.location.search)
));
const [customer, setCustomer] = useState<ElectricVehicleScope>(drillContext.vehicleScope);
const [pick, setPick] = useState<DateRangeMode>(() => (
drillContext.startDate && drillContext.endDate || drillContext.selectedDate ? 'custom' : 'last15'
));
const [pick, setPick] = useState<DateRangeMode>(() => {
if (drillContext.startDate && drillContext.endDate) {
return inferDateRangeMode(drillContext.startDate, drillContext.endDate);
}
return 'last15';
});
const [dateRange, setDateRange] = useState(() => {
if (drillContext.startDate && drillContext.endDate) {
return { start: drillContext.startDate, end: drillContext.endDate };
return normalizeDateRange(drillContext.startDate, drillContext.endDate);
}
if (drillContext.selectedDate) {
return { start: drillContext.selectedDate, end: drillContext.selectedDate };
@@ -118,7 +122,7 @@ export default function ElectricDaily() {
const nextRange = { ...dateRange, [field]: value };
const normalized = normalizeDateRange(nextRange.start, nextRange.end);
setPick('custom');
setDateRange(nextRange);
setDateRange(normalized);
commitDrillContext({
vehicleScope: customer,
startDate: normalized.start,
@@ -152,8 +156,9 @@ export default function ElectricDaily() {
setDrillContext(next);
setCustomer(next.vehicleScope);
if (next.startDate && next.endDate) {
setPick('custom');
setDateRange({ start: next.startDate, end: next.endDate });
const normalized = normalizeDateRange(next.startDate, next.endDate);
setPick(inferDateRangeMode(normalized.start, normalized.end));
setDateRange(normalized);
} else if (next.selectedDate) {
setPick('custom');
setDateRange({ start: next.selectedDate, end: next.selectedDate });
+9 -5
View File
@@ -17,6 +17,7 @@ import AnalysisDateFilters from './AnalysisDateFilters';
import {
dateRangeModeLabel,
getQuickDateRange,
inferDateRangeMode,
normalizeDateRange,
type DateRangeMode,
} from './date-range';
@@ -26,11 +27,13 @@ export default function HydrogenDaily() {
parseHydrogenDrillContext(window.location.search)
));
const [pick, setPick] = useState<DateRangeMode>(() => (
drillContext.startDate && drillContext.endDate ? 'custom' : 'last15'
drillContext.startDate && drillContext.endDate
? inferDateRangeMode(drillContext.startDate, drillContext.endDate)
: 'last15'
));
const [dateRange, setDateRange] = useState(() => (
drillContext.startDate && drillContext.endDate
? { start: drillContext.startDate, end: drillContext.endDate }
? normalizeDateRange(drillContext.startDate, drillContext.endDate)
: getQuickDateRange('last15')
));
const [customer, setCustomer] = useState<CustomerType>(drillContext.vehicleScope);
@@ -108,8 +111,8 @@ export default function HydrogenDaily() {
if (!value) return;
const nextRange = { ...dateRange, [field]: value };
setPick('custom');
setDateRange(nextRange);
const normalized = normalizeDateRange(nextRange.start, nextRange.end);
setDateRange(normalized);
commitDrillContext({
...drillContext,
vehicleScope: customer,
@@ -171,8 +174,9 @@ export default function HydrogenDaily() {
setDrillContext(next);
setCustomer(next.vehicleScope);
if (next.startDate && next.endDate) {
setPick('custom');
setDateRange({ start: next.startDate, end: next.endDate });
const normalized = normalizeDateRange(next.startDate, next.endDate);
setPick(inferDateRangeMode(normalized.start, normalized.end));
setDateRange(normalized);
}
};
window.addEventListener('popstate', handlePopState);
+17 -1
View File
@@ -1,6 +1,11 @@
import assert from 'node:assert/strict';
import test from 'node:test';
import { dateRangeModeLabel, getQuickDateRange, normalizeDateRange } from './date-range.js';
import {
dateRangeModeLabel,
getQuickDateRange,
inferDateRangeMode,
normalizeDateRange,
} from './date-range.js';
const FRIDAY = new Date(2026, 7, 7, 16, 30, 0);
@@ -15,3 +20,14 @@ test('normalizes date order and publishes consistent labels', () => {
assert.equal(dateRangeModeLabel('thisMonth'), '本月');
assert.equal(dateRangeModeLabel('custom'), '自定义区间');
});
test('restores a quick mode only while URL dates still match that calendar range', () => {
assert.equal(inferDateRangeMode('2026-08-03', '2026-08-07', FRIDAY), 'thisWeek');
assert.equal(inferDateRangeMode('2026-08-01', '2026-08-07', FRIDAY), 'thisMonth');
assert.equal(inferDateRangeMode('2026-08-07', '2026-07-24', FRIDAY), 'last15');
assert.equal(inferDateRangeMode('2026-08-01', '2026-08-06', FRIDAY), 'custom');
assert.equal(
inferDateRangeMode('2026-08-01', '2026-08-07', new Date(2026, 7, 8, 9, 0, 0)),
'custom',
);
});
+9
View File
@@ -40,6 +40,15 @@ export function normalizeDateRange(start: string, end: string): DateRangeValue {
return start <= end ? { start, end } : { start: end, end: start };
}
export function inferDateRangeMode(start: string, end: string, now = new Date()): DateRangeMode {
const range = normalizeDateRange(start, end);
const match = QUICK_DATE_OPTIONS.find(({ id }) => {
const quickRange = getQuickDateRange(id, now);
return quickRange.start === range.start && quickRange.end === range.end;
});
return match?.id ?? 'custom';
}
export function dateRangeModeLabel(mode: DateRangeMode): string {
return mode === 'custom' ? '自定义区间' : LABELS[mode];
}