feat(platform): persist history filters in route
This commit is contained in:
@@ -11,7 +11,7 @@ type HistoryFilters = {
|
||||
dateFrom?: string;
|
||||
dateTo?: string;
|
||||
fields?: string;
|
||||
includeFields?: boolean;
|
||||
includeFields?: boolean | string;
|
||||
};
|
||||
|
||||
const defaultFilters: HistoryFilters = {
|
||||
@@ -39,19 +39,37 @@ function normalizeHistoryTab(value?: string): HistoryTabKey {
|
||||
return value === 'raw' ? 'raw' : 'location';
|
||||
}
|
||||
|
||||
function isIncludeFieldsEnabled(value?: boolean | string) {
|
||||
return value === true || value === 'true';
|
||||
}
|
||||
|
||||
function mergeInitialFilters(initialVin: string, initialProtocol?: string, initialFilters: Record<string, string> = {}): HistoryFilters {
|
||||
return {
|
||||
...defaultFilters,
|
||||
keyword: initialVin || defaultFilters.keyword,
|
||||
protocol: initialProtocol,
|
||||
...initialFilters,
|
||||
includeFields: isIncludeFieldsEnabled(initialFilters.includeFields)
|
||||
};
|
||||
}
|
||||
|
||||
export function History({
|
||||
initialVin,
|
||||
initialProtocol,
|
||||
initialTab,
|
||||
initialFilters = {},
|
||||
onFiltersChange,
|
||||
onOpenVehicle
|
||||
}: {
|
||||
initialVin: string;
|
||||
initialProtocol?: string;
|
||||
initialTab?: string;
|
||||
initialFilters?: Record<string, string>;
|
||||
onFiltersChange?: (filters: HistoryFilters, tab?: HistoryTabKey) => void;
|
||||
onOpenVehicle: (vin: string, protocol?: string) => void;
|
||||
}) {
|
||||
const initialFilters = { ...defaultFilters, keyword: initialVin || defaultFilters.keyword, protocol: initialProtocol };
|
||||
const [filters, setFilters] = useState<HistoryFilters>(initialFilters);
|
||||
const initialHistoryFilters = mergeInitialFilters(initialVin, initialProtocol, initialFilters);
|
||||
const [filters, setFilters] = useState<HistoryFilters>(initialHistoryFilters);
|
||||
const [activeTab, setActiveTab] = useState<HistoryTabKey>(normalizeHistoryTab(initialTab));
|
||||
const [locations, setLocations] = useState<Page<HistoryLocationRow>>(defaultPage);
|
||||
const [rawFrames, setRawFrames] = useState<Page<RawFrameRow>>(defaultPage);
|
||||
@@ -67,7 +85,7 @@ export function History({
|
||||
if (nextFilters.protocol?.trim()) params.set('protocol', nextFilters.protocol.trim());
|
||||
if (nextFilters.dateFrom?.trim()) params.set('dateFrom', nextFilters.dateFrom.trim());
|
||||
if (nextFilters.dateTo?.trim()) params.set('dateTo', nextFilters.dateTo.trim());
|
||||
if (raw && nextFilters.includeFields) params.set('includeFields', 'true');
|
||||
if (raw && isIncludeFieldsEnabled(nextFilters.includeFields)) params.set('includeFields', 'true');
|
||||
if (raw && nextFilters.fields?.trim()) params.set('fields', nextFilters.fields.trim());
|
||||
return params;
|
||||
};
|
||||
@@ -78,7 +96,7 @@ export function History({
|
||||
if (nextFilters.protocol?.trim()) query.protocol = nextFilters.protocol.trim();
|
||||
if (nextFilters.dateFrom?.trim()) query.dateFrom = nextFilters.dateFrom.trim();
|
||||
if (nextFilters.dateTo?.trim()) query.dateTo = nextFilters.dateTo.trim();
|
||||
if (nextFilters.includeFields) query.includeFields = true;
|
||||
if (isIncludeFieldsEnabled(nextFilters.includeFields)) query.includeFields = true;
|
||||
const fields = splitFields(nextFilters.fields);
|
||||
if (fields.length > 0) query.fields = fields;
|
||||
return query;
|
||||
@@ -116,24 +134,32 @@ export function History({
|
||||
includeFields: Boolean(values.includeFields)
|
||||
};
|
||||
setFilters(nextFilters);
|
||||
onFiltersChange?.(nextFilters, activeTab);
|
||||
loadLocations(nextFilters, 1, locationPagination.pageSize);
|
||||
loadRawFrames(nextFilters, 1, rawPagination.pageSize);
|
||||
};
|
||||
|
||||
const reset = () => {
|
||||
const nextFilters = { ...defaultFilters, keyword: initialVin || defaultFilters.keyword, protocol: initialProtocol };
|
||||
const nextFilters = mergeInitialFilters(initialVin, initialProtocol, {});
|
||||
setFilters(nextFilters);
|
||||
onFiltersChange?.(nextFilters, activeTab);
|
||||
loadLocations(nextFilters, 1, locationPagination.pageSize);
|
||||
loadRawFrames(nextFilters, 1, rawPagination.pageSize);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const nextFilters = { ...defaultFilters, keyword: initialVin || defaultFilters.keyword, protocol: initialProtocol };
|
||||
const nextFilters = mergeInitialFilters(initialVin, initialProtocol, initialFilters);
|
||||
setFilters(nextFilters);
|
||||
setActiveTab(normalizeHistoryTab(initialTab));
|
||||
loadLocations(nextFilters, 1, locationPagination.pageSize);
|
||||
loadRawFrames(nextFilters, 1, rawPagination.pageSize);
|
||||
}, [initialVin, initialProtocol, initialTab]);
|
||||
}, [initialVin, initialProtocol, initialTab, JSON.stringify(initialFilters)]);
|
||||
|
||||
const changeTab = (key: string) => {
|
||||
const nextTab = normalizeHistoryTab(String(key));
|
||||
setActiveTab(nextTab);
|
||||
onFiltersChange?.(filters, nextTab);
|
||||
};
|
||||
|
||||
const rawFieldCount = useMemo(() => Object.keys(selectedRaw?.parsedFields ?? {}).length, [selectedRaw]);
|
||||
const currentVehicleKeyword = filters.keyword?.trim() ?? '';
|
||||
@@ -156,7 +182,7 @@ export function History({
|
||||
<Typography.Text type="tertiary">历史位置和 RAW 帧按当前车辆与来源范围查询。</Typography.Text>
|
||||
</div>
|
||||
<Card bordered>
|
||||
<Form key={`${filters.keyword ?? ''}-${filters.protocol ?? ''}-${filters.includeFields ? 'fields' : 'light'}`} initValues={filters} layout="horizontal" onSubmit={(values) => submit(values)}>
|
||||
<Form key={JSON.stringify(filters)} initValues={filters} layout="horizontal" onSubmit={(values) => submit(values)}>
|
||||
<Form.Input field="keyword" label="车辆关键词" placeholder="VIN / 车牌 / 手机号" style={{ width: 260 }} />
|
||||
<Form.Select field="protocol" label="数据来源" placeholder="全部来源" style={{ width: 190 }}>
|
||||
<Select.Option value="GB32960">GB32960</Select.Option>
|
||||
@@ -182,7 +208,7 @@ export function History({
|
||||
</Form>
|
||||
</Card>
|
||||
<Card bordered style={{ marginTop: 16 }}>
|
||||
<Tabs activeKey={activeTab} onChange={(key) => setActiveTab(normalizeHistoryTab(String(key)))}>
|
||||
<Tabs activeKey={activeTab} onChange={(key) => changeTab(String(key))}>
|
||||
<Tabs.TabPane tab="位置历史" itemKey="location">
|
||||
<Table
|
||||
rowKey="deviceTime"
|
||||
|
||||
Reference in New Issue
Block a user