safety-eval-service-frontend/.cursor/skills/search-state-persistence/SKILL.md

175 lines
4.7 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

---
name: "search-state-persistence"
description: "Search state persistence via tools.router.query. Invoke when implementing search/table pages with SearchForm + Table + pagination that need to preserve query params across refreshes."
---
# 搜索状态持久化
通过 `tools.router.query` 实现搜索条件持久化,刷新页面后搜索条件和分页状态保留在 URL 查询参数中。
## 核心 API
```js
import { tools } from "@cqsjjb/jjb-common-lib";
const { router } = tools;
```
`router.query` 是一个响应式对象,对其赋值会同步更新 URL 查询参数。
## 完整模式
```jsx
import React, { useState, useEffect } from "react";
import { Button, Form, Select, Space, Table, Tag } from "antd";
import PageLayout from "@cqsjjb/jjb-react-admin-component/PageLayout";
import SearchForm from "~/components/SearchForm";
import ControlWrapper from "@cqsjjb/jjb-react-admin-component/ControlWrapper";
import { AntdTableFuncControl } from "@cqsjjb/jjb-common-decorator/antd";
import { tools } from "@cqsjjb/jjb-common-lib";
const { router } = tools;
const MyPage = (props) => {
const [form] = Form.useForm();
const [loading, setLoading] = useState(false);
/** 搜索/刷新数据 */
const handleSearch = () => {
setLoading(true);
// 实际请求...
setTimeout(() => setLoading(false), 500);
};
/** 重置搜索 */
const handleReset = (values) => {
router.query = {
...router.query,
...values,
current: 1,
size: 10,
};
handleSearch();
};
/** 初始化:将 URL 中的查询条件回填到表单 */
useEffect(() => {
form.setFieldsValue(router.query);
}, []);
const columns = [
// ...列定义
];
return (
<PageLayout title="页面标题">
<SearchForm
style={{ marginBottom: 24 }}
form={form}
loading={loading}
formLine={[
<Form.Item key="fieldName" name="fieldName">
<ControlWrapper.Input label="字段名" placeholder="请输入" allowClear />
</Form.Item>,
]}
onReset={handleReset}
onFinish={(values) => {
router.query = {
...router.query,
...values,
current: 1,
size: 10,
};
handleSearch();
}}
/>
<Table
rowKey="id"
columns={columns}
dataSource={data}
scroll={{ y: props.scrollY }}
loading={loading}
pagination={{
total: total,
showSizeChanger: true,
showQuickJumper: true,
showTotal: (total) => `共 ${total} 条`,
current: router.query.current,
pageSize: router.query.size,
onChange: (page, pageSize) => {
router.query = {
...router.query,
current: page,
size: pageSize,
};
handleSearch();
},
}}
/>
</PageLayout>
);
};
export default AntdTableFuncControl(MyPage);
```
## 关键规则
### 1. 初始化回填
`useEffect` 中将 `router.query` 的值回填到表单,确保刷新后表单显示与 URL 一致:
```js
useEffect(() => {
form.setFieldsValue(router.query);
}, []);
```
**注意**`router.query` 中所有值均为字符串,而 `DatePicker` / `RangePicker` 需要 `dayjs` 对象。当表单包含日期字段时,必须手动转换:
```js
useEffect(() => {
searchForm.setFieldsValue({
...router.query,
dateRange:
router.query.startTime && router.query.endTime
? [dayjs(router.query.startTime), dayjs(router.query.endTime)]
: undefined,
});
}, []);
```
### 2. 搜索/重置写入
搜索提交(`onFinish`) 和重置(`onReset`) 时,将表单值与默认分页合并写入 `router.query`
```js
router.query = {
...router.query,
...values, // 表单值
current: 1, // 重置到第一页
pageSize: 10, // 默认页大小
};
```
### 3. 翻页写入
分页变化时,仅更新 `current``pageSize`,保留已有搜索条件:
```js
onChange: (page, pageSize) => {
router.query = {
...router.query, // 保留已有搜索条件
current: page,
pageSize,
};
handleSearch();
};
```
### 4. 组件装饰器
页面组件必须用 `AntdTableFuncControl` 包裹以支持表格功能:
```js
export default AntdTableFuncControl(MyPage);
```
## 注意事项
- `router.query` 是响应式的:赋值会触发 URL 更新,且刷新后值仍然保留
- `router.query` 中所有值均为字符串类型URL query 的特性),使用 `current``pageSize` 时注意隐式类型转换
- 默认值 `current: 1, pageSize: 10` 是约定,可根据实际需求修改
- `onReset` 回调的 `values` 参数是重置后的表单值(所有字段清空/恢复默认后的值)