fix: restore BI quick date state
This commit is contained in:
@@ -152,6 +152,7 @@ SUM(fee) / NULLIF(SUM(kwh), 0)
|
|||||||
- 已完成 ETC 记录/账单视图、日期、搜索和分页 URL 状态,以及超范围页码自动纠正。
|
- 已完成 ETC 记录/账单视图、日期、搜索和分页 URL 状态,以及超范围页码自动纠正。
|
||||||
- 已统一共享加载、空数据和故障组件的顶层卡片与明细内联边界,消除能源明细中的嵌套状态卡片。
|
- 已统一共享加载、空数据和故障组件的顶层卡片与明细内联边界,消除能源明细中的嵌套状态卡片。
|
||||||
- 已统一电能、氢能和 ETC 日期范围输入;电能与氢能共用快捷区间算法和单一输入事件路径。
|
- 已统一电能、氢能和 ETC 日期范围输入;电能与氢能共用快捷区间算法和单一输入事件路径。
|
||||||
|
- 电能与氢能可根据 URL 日期恢复快捷区间选中态;过期区间自动归为自定义,避免标签与统计日期不一致。
|
||||||
- 已完成并发同参 GET 去重。
|
- 已完成并发同参 GET 去重。
|
||||||
|
|
||||||
### 阶段 B:核心下钻闭环
|
### 阶段 B:核心下钻闭环
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import AnalysisDateFilters from './AnalysisDateFilters';
|
|||||||
import {
|
import {
|
||||||
dateRangeModeLabel,
|
dateRangeModeLabel,
|
||||||
getQuickDateRange,
|
getQuickDateRange,
|
||||||
|
inferDateRangeMode,
|
||||||
normalizeDateRange,
|
normalizeDateRange,
|
||||||
type DateRangeMode,
|
type DateRangeMode,
|
||||||
} from './date-range';
|
} from './date-range';
|
||||||
@@ -24,12 +25,15 @@ export default function ElectricDaily() {
|
|||||||
parseElectricDrillContext(window.location.search)
|
parseElectricDrillContext(window.location.search)
|
||||||
));
|
));
|
||||||
const [customer, setCustomer] = useState<ElectricVehicleScope>(drillContext.vehicleScope);
|
const [customer, setCustomer] = useState<ElectricVehicleScope>(drillContext.vehicleScope);
|
||||||
const [pick, setPick] = useState<DateRangeMode>(() => (
|
const [pick, setPick] = useState<DateRangeMode>(() => {
|
||||||
drillContext.startDate && drillContext.endDate || drillContext.selectedDate ? 'custom' : 'last15'
|
if (drillContext.startDate && drillContext.endDate) {
|
||||||
));
|
return inferDateRangeMode(drillContext.startDate, drillContext.endDate);
|
||||||
|
}
|
||||||
|
return 'last15';
|
||||||
|
});
|
||||||
const [dateRange, setDateRange] = useState(() => {
|
const [dateRange, setDateRange] = useState(() => {
|
||||||
if (drillContext.startDate && drillContext.endDate) {
|
if (drillContext.startDate && drillContext.endDate) {
|
||||||
return { start: drillContext.startDate, end: drillContext.endDate };
|
return normalizeDateRange(drillContext.startDate, drillContext.endDate);
|
||||||
}
|
}
|
||||||
if (drillContext.selectedDate) {
|
if (drillContext.selectedDate) {
|
||||||
return { start: drillContext.selectedDate, end: drillContext.selectedDate };
|
return { start: drillContext.selectedDate, end: drillContext.selectedDate };
|
||||||
@@ -118,7 +122,7 @@ export default function ElectricDaily() {
|
|||||||
const nextRange = { ...dateRange, [field]: value };
|
const nextRange = { ...dateRange, [field]: value };
|
||||||
const normalized = normalizeDateRange(nextRange.start, nextRange.end);
|
const normalized = normalizeDateRange(nextRange.start, nextRange.end);
|
||||||
setPick('custom');
|
setPick('custom');
|
||||||
setDateRange(nextRange);
|
setDateRange(normalized);
|
||||||
commitDrillContext({
|
commitDrillContext({
|
||||||
vehicleScope: customer,
|
vehicleScope: customer,
|
||||||
startDate: normalized.start,
|
startDate: normalized.start,
|
||||||
@@ -152,8 +156,9 @@ export default function ElectricDaily() {
|
|||||||
setDrillContext(next);
|
setDrillContext(next);
|
||||||
setCustomer(next.vehicleScope);
|
setCustomer(next.vehicleScope);
|
||||||
if (next.startDate && next.endDate) {
|
if (next.startDate && next.endDate) {
|
||||||
setPick('custom');
|
const normalized = normalizeDateRange(next.startDate, next.endDate);
|
||||||
setDateRange({ start: next.startDate, end: next.endDate });
|
setPick(inferDateRangeMode(normalized.start, normalized.end));
|
||||||
|
setDateRange(normalized);
|
||||||
} else if (next.selectedDate) {
|
} else if (next.selectedDate) {
|
||||||
setPick('custom');
|
setPick('custom');
|
||||||
setDateRange({ start: next.selectedDate, end: next.selectedDate });
|
setDateRange({ start: next.selectedDate, end: next.selectedDate });
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import AnalysisDateFilters from './AnalysisDateFilters';
|
|||||||
import {
|
import {
|
||||||
dateRangeModeLabel,
|
dateRangeModeLabel,
|
||||||
getQuickDateRange,
|
getQuickDateRange,
|
||||||
|
inferDateRangeMode,
|
||||||
normalizeDateRange,
|
normalizeDateRange,
|
||||||
type DateRangeMode,
|
type DateRangeMode,
|
||||||
} from './date-range';
|
} from './date-range';
|
||||||
@@ -26,11 +27,13 @@ export default function HydrogenDaily() {
|
|||||||
parseHydrogenDrillContext(window.location.search)
|
parseHydrogenDrillContext(window.location.search)
|
||||||
));
|
));
|
||||||
const [pick, setPick] = useState<DateRangeMode>(() => (
|
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(() => (
|
const [dateRange, setDateRange] = useState(() => (
|
||||||
drillContext.startDate && drillContext.endDate
|
drillContext.startDate && drillContext.endDate
|
||||||
? { start: drillContext.startDate, end: drillContext.endDate }
|
? normalizeDateRange(drillContext.startDate, drillContext.endDate)
|
||||||
: getQuickDateRange('last15')
|
: getQuickDateRange('last15')
|
||||||
));
|
));
|
||||||
const [customer, setCustomer] = useState<CustomerType>(drillContext.vehicleScope);
|
const [customer, setCustomer] = useState<CustomerType>(drillContext.vehicleScope);
|
||||||
@@ -108,8 +111,8 @@ export default function HydrogenDaily() {
|
|||||||
if (!value) return;
|
if (!value) return;
|
||||||
const nextRange = { ...dateRange, [field]: value };
|
const nextRange = { ...dateRange, [field]: value };
|
||||||
setPick('custom');
|
setPick('custom');
|
||||||
setDateRange(nextRange);
|
|
||||||
const normalized = normalizeDateRange(nextRange.start, nextRange.end);
|
const normalized = normalizeDateRange(nextRange.start, nextRange.end);
|
||||||
|
setDateRange(normalized);
|
||||||
commitDrillContext({
|
commitDrillContext({
|
||||||
...drillContext,
|
...drillContext,
|
||||||
vehicleScope: customer,
|
vehicleScope: customer,
|
||||||
@@ -171,8 +174,9 @@ export default function HydrogenDaily() {
|
|||||||
setDrillContext(next);
|
setDrillContext(next);
|
||||||
setCustomer(next.vehicleScope);
|
setCustomer(next.vehicleScope);
|
||||||
if (next.startDate && next.endDate) {
|
if (next.startDate && next.endDate) {
|
||||||
setPick('custom');
|
const normalized = normalizeDateRange(next.startDate, next.endDate);
|
||||||
setDateRange({ start: next.startDate, end: next.endDate });
|
setPick(inferDateRangeMode(normalized.start, normalized.end));
|
||||||
|
setDateRange(normalized);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
window.addEventListener('popstate', handlePopState);
|
window.addEventListener('popstate', handlePopState);
|
||||||
|
|||||||
@@ -1,6 +1,11 @@
|
|||||||
import assert from 'node:assert/strict';
|
import assert from 'node:assert/strict';
|
||||||
import test from 'node:test';
|
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);
|
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('thisMonth'), '本月');
|
||||||
assert.equal(dateRangeModeLabel('custom'), '自定义区间');
|
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',
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|||||||
@@ -40,6 +40,15 @@ export function normalizeDateRange(start: string, end: string): DateRangeValue {
|
|||||||
return start <= end ? { start, end } : { start: end, end: start };
|
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 {
|
export function dateRangeModeLabel(mode: DateRangeMode): string {
|
||||||
return mode === 'custom' ? '自定义区间' : LABELS[mode];
|
return mode === 'custom' ? '自定义区间' : LABELS[mode];
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user