@xfe-repo/web-components 1.6.2 → 1.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/package.json +6 -5
  2. package/skills/xfe-web-components/GUIDE.md +78 -0
  3. package/skills/xfe-web-components/SKILL.md +78 -0
  4. package/skills/xfe-web-components/TEMPLATE.md +170 -0
  5. package/skills/xfe-web-components/references/ApiService.md +136 -0
  6. package/skills/xfe-web-components/references/CInput.md +196 -0
  7. package/skills/xfe-web-components/references/CTable.md +274 -0
  8. package/skills/xfe-web-components/references/CVideo.md +94 -0
  9. package/skills/xfe-web-components/references/Clock.md +53 -0
  10. package/skills/xfe-web-components/references/ConfigProvider.md +198 -0
  11. package/skills/xfe-web-components/references/Countdown.md +109 -0
  12. package/skills/xfe-web-components/references/Counter.md +75 -0
  13. package/skills/xfe-web-components/references/Currency.md +112 -0
  14. package/skills/xfe-web-components/references/EffectAddressCascade.md +110 -0
  15. package/skills/xfe-web-components/references/EffectBrandSelect.md +231 -0
  16. package/skills/xfe-web-components/references/EffectBrandTransfer.md +143 -0
  17. package/skills/xfe-web-components/references/EffectCategoryCascade.md +227 -0
  18. package/skills/xfe-web-components/references/EffectFileUpload.md +348 -0
  19. package/skills/xfe-web-components/references/EffectLabelSelect.md +222 -0
  20. package/skills/xfe-web-components/references/EffectMerchantSelect.md +183 -0
  21. package/skills/xfe-web-components/references/EffectReservoirSelect.md +178 -0
  22. package/skills/xfe-web-components/references/EffectScopeSelect.md +220 -0
  23. package/skills/xfe-web-components/references/EffectSeriesSelect.md +204 -0
  24. package/skills/xfe-web-components/references/EffectSeriesSelectV2.md +154 -0
  25. package/skills/xfe-web-components/references/EffectSkuRecognize.md +149 -0
  26. package/skills/xfe-web-components/references/EffectSkuSelect.md +251 -0
  27. package/skills/xfe-web-components/references/EffectSkuTable.md +184 -0
  28. package/skills/xfe-web-components/references/EffectSpuSelect.md +189 -0
  29. package/skills/xfe-web-components/references/EffectStaffSelect.md +150 -0
  30. package/skills/xfe-web-components/references/EffectWarehouseSelect.md +183 -0
  31. package/skills/xfe-web-components/references/EffectWithFilePanel.md +205 -0
  32. package/skills/xfe-web-components/references/FileUpload.md +126 -0
  33. package/skills/xfe-web-components/references/Iconfont.md +31 -0
  34. package/skills/xfe-web-components/references/Loading.md +68 -0
  35. package/skills/xfe-web-components/references/MultiWindow.md +145 -0
  36. package/skills/xfe-web-components/references/OSSImage.md +230 -0
  37. package/skills/xfe-web-components/references/PrivacyField.md +90 -0
  38. package/skills/xfe-web-components/references/QRCode.md +148 -0
  39. package/skills/xfe-web-components/references/RichTextEditor.md +119 -0
  40. package/skills/xfe-web-components/references/SearchForm.md +270 -0
  41. package/skills/xfe-web-components/references/SearchList.md +128 -0
  42. package/skills/xfe-web-components/references/WithModal.md +328 -0
  43. package/skills/xfe-web-components/references/WithPanel.md +307 -0
  44. package/skills/xfe-web-components/references/commonFn.md +254 -0
@@ -0,0 +1,119 @@
1
+ # RichTextEditor
2
+
3
+ > 富文本编辑器,基于 TipTap 封装,支持加粗、斜体、下划线、删除线、标题、文字颜色、背景高亮、撤销重做,可选图片插入。
4
+
5
+ ## 导入
6
+
7
+ ```tsx
8
+ import { RichTextEditor } from '@xfe-repo/web-components'
9
+ import type { RichTextEditorProps } from '@xfe-repo/web-components'
10
+ ```
11
+
12
+ ## 基本用法
13
+
14
+ ```tsx
15
+ import { RichTextEditor } from '@xfe-repo/web-components'
16
+
17
+ function Editor() {
18
+ const [content, setContent] = useState('')
19
+
20
+ return <RichTextEditor defaultValue="<p>初始内容</p>" onChange={(html) => setContent(html)} />
21
+ }
22
+ ```
23
+
24
+ ### Form.Item 集成
25
+
26
+ ```tsx
27
+ <Form.Item name="content" label="内容">
28
+ <RichTextEditor />
29
+ </Form.Item>
30
+ ```
31
+
32
+ > 💡 RichTextEditor 兼容 Form.Item 受控模式,value/onChange 由 Form 自动注入。
33
+
34
+ ## 进阶用法
35
+
36
+ ### 禁用编辑
37
+
38
+ ```tsx
39
+ <RichTextEditor value={htmlContent} disabled />
40
+ ```
41
+
42
+ ### 自定义占位文案
43
+
44
+ ```tsx
45
+ <RichTextEditor placeholder="请输入商品描述..." onChange={setContent} />
46
+ ```
47
+
48
+ ### 启用图片插入
49
+
50
+ 需要在 `ConfigProvider` 内使用,图片会自动上传到 OSS。
51
+
52
+ ```tsx
53
+ <RichTextEditor defaultValue={content} onChange={setContent} enableImageInsert />
54
+ ```
55
+
56
+ ### 自定义图片按钮图标
57
+
58
+ ```tsx
59
+ <RichTextEditor enableImageInsert imageInsertIcon={<PictureOutlined />} onChange={setContent} />
60
+ ```
61
+
62
+ ## Props
63
+
64
+ ```typescript
65
+ export interface RichTextEditorProps {
66
+ defaultValue?: string
67
+ onChange?: (value: string) => void
68
+ value?: string
69
+ disabled?: boolean
70
+ placeholder?: string
71
+ enableImageInsert?: boolean
72
+ imageInsertIcon?: React.ReactNode
73
+ }
74
+ ```
75
+
76
+ | 属性 | 类型 | 必填 | 默认值 | 说明 |
77
+ | ----------------- | ------------------------- | ---- | --------------------- | ----------------------------------------- |
78
+ | defaultValue | `string` | 否 | - | 初始 HTML 内容(与 value 二选一) |
79
+ | value | `string` | 否 | - | HTML 内容(与 defaultValue 二选一) |
80
+ | onChange | `(value: string) => void` | 否 | - | 编辑器失焦时触发,参数为 HTML 字符串 |
81
+ | disabled | `boolean` | 否 | - | 是否禁用编辑 |
82
+ | placeholder | `string` | 否 | `'请输入内容'` | 占位文案 |
83
+ | enableImageInsert | `boolean` | 否 | `false` | 是否启用图片插入(工具栏按钮 + 粘贴图片) |
84
+ | imageInsertIcon | `React.ReactNode` | 否 | `<PictureOutlined />` | 自定义图片插入按钮图标 |
85
+
86
+ ## 导出类型
87
+
88
+ ### replaceRgbWithHex
89
+
90
+ ```typescript
91
+ export const replaceRgbWithHex: (value: string) => string
92
+ ```
93
+
94
+ 将 HTML 中的 `rgb(r,g,b)` 颜色值转换为 `#rrggbb` 格式。编辑器 onChange 输出时自动调用。
95
+
96
+ ## 注意事项
97
+
98
+ - 编辑器底部会自动显示 **字数统计**(格式:`字数 : N`),无需额外配置
99
+ - 图片插入支持的格式:**jpeg、jpg、png、gif、webp**,不支持的格式会提示错误
100
+ - 插入的图片样式约束为 `max-width: 100%; max-height: 200px`
101
+ - 图片上传过程中再次粘贴图片会被阻止(提示"正在上传中,请稍候..."),需等当前上传完成
102
+
103
+ ## 常见陷阱
104
+
105
+ - ❌ `onChange` 在 **失焦** 时触发而非实时输入,如果编辑器内容为空 `<p></p>` 则回调空字符串 `''`
106
+ - ✅ 需要实时获取内容,考虑通过 TipTap 的 `onUpdate` 自行扩展
107
+
108
+ - ❌ 启用 `enableImageInsert` 时,图片上传依赖 `ConfigProvider` 提供的 `apiService.uploadUploadFile`
109
+ - ✅ 确保在 `ConfigProvider` 内使用,且已配置 `apiPayload`
110
+
111
+ - ❌ 同时传 `value` 和 `defaultValue` 时,优先使用 `defaultValue`
112
+ - ✅ 建议只传其中一个
113
+
114
+ ## 相关组件
115
+
116
+ | 场景 | 组件 | 说明 |
117
+ | -------- | ------------------ | --------------------------- |
118
+ | 图片上传 | `EffectFileUpload` | 独立的文件上传组件 |
119
+ | 全局配置 | `ConfigProvider` | 提供图片上传所需的 API 服务 |
@@ -0,0 +1,270 @@
1
+ # SearchForm
2
+
3
+ > 搜索表单组件,提供统一的搜索表单布局和操作按钮,支持完整表单模式和内容模式(Content 子组件)。
4
+
5
+ ## 导入
6
+
7
+ ```tsx
8
+ import { SearchForm, SearchFormContent, useSearchFormStyle } from '@xfe-repo/web-components'
9
+ import type { SearchFormProps, SearchFormContentProps } from '@xfe-repo/web-components'
10
+ ```
11
+
12
+ ## 基本用法
13
+
14
+ ### 完整表单模式
15
+
16
+ 组件内部自动包裹 `<Form>`,提供 inline 布局和统一样式。
17
+
18
+ ```tsx
19
+ import { SearchForm } from '@xfe-repo/web-components'
20
+ import { Form, Input, Select } from 'antd'
21
+
22
+ function OrderSearch({ filter, onFinish, onReset }) {
23
+ const [form] = Form.useForm()
24
+
25
+ return (
26
+ <SearchForm form={form} filter={filter} onFinish={onFinish} onReset={onReset} className="my-search">
27
+ <Form.Item name="orderNo" label="订单号">
28
+ <Input placeholder="请输入" />
29
+ </Form.Item>
30
+ <Form.Item name="status" label="状态">
31
+ <Select options={statusOptions} />
32
+ </Form.Item>
33
+ </SearchForm>
34
+ )
35
+ }
36
+ ```
37
+
38
+ ### 内容模式(Content Only)
39
+
40
+ 当不传 `className`、`layout`、`style` 等 Form 属性时,自动降级为内容模式(不包裹 `<Form>`),需要自行在外部包裹 `<Form>`。
41
+
42
+ ```tsx
43
+ import { SearchForm } from '@xfe-repo/web-components'
44
+
45
+ function OrderSearch({ filter }) {
46
+ const [form] = Form.useForm()
47
+
48
+ return (
49
+ <Form form={form} onFinish={handleSearch}>
50
+ <SearchForm filter={filter} form={form}>
51
+ <Form.Item name="orderNo" label="订单号">
52
+ <Input />
53
+ </Form.Item>
54
+ </SearchForm>
55
+ </Form>
56
+ )
57
+ }
58
+ ```
59
+
60
+ ## 进阶用法
61
+
62
+ ### 显式使用 SearchFormContent
63
+
64
+ 适用于跨包场景(避免 antd Context 隔离问题),需要放在消费方自己的 `<Form>` 内部。
65
+
66
+ ```tsx
67
+ import { SearchFormContent } from '@xfe-repo/web-components'
68
+
69
+ function OrderSearch({ filter }) {
70
+ const [form] = Form.useForm()
71
+
72
+ return (
73
+ <Form form={form} onFinish={handleSearch}>
74
+ <SearchFormContent filter={filter} form={form}>
75
+ <Form.Item name="keyword" label="关键词">
76
+ <Input />
77
+ </Form.Item>
78
+ </SearchFormContent>
79
+ </Form>
80
+ )
81
+ }
82
+ ```
83
+
84
+ ### Redux 标准模式
85
+
86
+ 业务项目中的标准使用模式 — 配合 Redux 管理搜索状态:
87
+
88
+ ```tsx
89
+ import { useAppSelector, useAppDispatch } from '@/store'
90
+ import { selectFilter, effectSearch } from './slice'
91
+
92
+ function OrderList() {
93
+ const [form] = Form.useForm()
94
+ const filter = useAppSelector(selectFilter)
95
+ const dispatch = useAppDispatch()
96
+
97
+ const handleFinish = (values) => {
98
+ dispatch(effectSearch({ ...values, page: 1 }))
99
+ }
100
+
101
+ const handleReset = () => {
102
+ dispatch(effectSearch(initialState.filter))
103
+ }
104
+
105
+ return (
106
+ <SearchForm form={form} filter={filter} onFinish={handleFinish} onReset={handleReset}>
107
+ <Form.Item name="orderNo" label="订单号">
108
+ <CInput placeholder="请输入" allowClear />
109
+ </Form.Item>
110
+ </SearchForm>
111
+ )
112
+ }
113
+ ```
114
+
115
+ > 💡 标准三件套:`selectFilter`(读取 Redux 搜索条件)→ `effectSearch`(触发搜索 action)→ `initialState.filter`(重置时恢复初始值)。
116
+
117
+ ### 自定义操作按钮
118
+
119
+ ```tsx
120
+ <SearchForm filter={filter} form={form} operations={<Button>导出</Button>}>
121
+ {/* 表单项 */}
122
+ </SearchForm>
123
+ ```
124
+
125
+ ### 隐藏重置按钮
126
+
127
+ ```tsx
128
+ <SearchForm filter={filter} form={form} showReset={false}>
129
+ {/* 表单项 */}
130
+ </SearchForm>
131
+ ```
132
+
133
+ ### 自定义确认按钮文案
134
+
135
+ ```tsx
136
+ <SearchForm filter={filter} form={form} confirmText="搜索">
137
+ {/* 表单项 */}
138
+ </SearchForm>
139
+ ```
140
+
141
+ ### 使用 useSearchFormStyle
142
+
143
+ 在需要自定义 Form 但保持一致样式时使用。
144
+
145
+ ```tsx
146
+ import { useSearchFormStyle } from '@xfe-repo/web-components'
147
+
148
+ function CustomSearch() {
149
+ const searchFormStyle = useSearchFormStyle()
150
+
151
+ return (
152
+ <Form className={searchFormStyle.className} layout={searchFormStyle.layout} style={searchFormStyle.style}>
153
+ {/* 表单内容 */}
154
+ </Form>
155
+ )
156
+ }
157
+ ```
158
+
159
+ ## Props
160
+
161
+ ### SearchFormProps
162
+
163
+ ```typescript
164
+ export type SearchFormProps<T extends object = any> = SearchFormBaseProps<T> &
165
+ Omit<FormProps<T>, 'children'> & {
166
+ contentOnly?: boolean
167
+ }
168
+
169
+ type SearchFormBaseProps<T> = {
170
+ children: ReactNode
171
+ operations?: ReactNode
172
+ showReset?: boolean
173
+ confirmText?: string
174
+ filter: T
175
+ form?: FormInstance<T>
176
+ }
177
+ ```
178
+
179
+ | 属性 | 类型 | 必填 | 默认值 | 说明 |
180
+ | ------------ | ------------------------------ | ---- | -------- | ---------------------------------------------------- |
181
+ | filter | `T` | 是 | - | 筛选条件对象,变更时自动同步到表单 |
182
+ | form | `FormInstance<T>` | 否 | - | antd Form 实例 |
183
+ | children | `ReactNode` | 是 | - | 表单项 |
184
+ | showReset | `boolean` | 否 | `true` | 是否显示重置按钮 |
185
+ | confirmText | `string` | 否 | `'确认'` | 确认按钮文案 |
186
+ | operations | `ReactNode` | 否 | - | 额外操作按钮(渲染在确认/重置按钮后) |
187
+ | contentOnly | `boolean` | 否 | - | 是否显式使用内容模式(不包裹 Form) |
188
+ | onFinish | `(values: T) => void` | 否 | - | 表单提交回调,点击"确认"按钮触发(继承自 FormProps) |
189
+ | onReset | `(e: React.FormEvent) => void` | 否 | - | 表单重置回调,点击"重置"按钮触发(继承自 FormProps) |
190
+ | ...formProps | `FormProps` | 否 | - | 所有 antd Form 属性 |
191
+
192
+ ## 子组件
193
+
194
+ | 子组件 | 说明 |
195
+ | ------------------- | ------------------------------------------------------ |
196
+ | `SearchFormContent` | 纯内容组件(无 Form 包裹),适用于自行管理 Form 的场景 |
197
+
198
+ ## 导出类型
199
+
200
+ ### useSearchFormStyle
201
+
202
+ ```typescript
203
+ export const useSearchFormStyle: () => {
204
+ className: string
205
+ layout: 'inline'
206
+ style: React.CSSProperties
207
+ }
208
+ ```
209
+
210
+ 返回搜索表单的标准样式配置(inline 布局、背景色、圆角、内边距)。
211
+
212
+ ## 使用模式
213
+
214
+ ### 常见表单字段组合
215
+
216
+ 除了 CInput,SearchForm 中常用的字段类型:
217
+
218
+ ```tsx
219
+ <SearchForm form={form} filter={filter} onFinish={onFinish} onReset={onReset}>
220
+ <Form.Item name="orderNo" label="订单号">
221
+ <CInput placeholder="请输入" allowClear />
222
+ </Form.Item>
223
+ <Form.Item name="categoryIds" label="分类">
224
+ <EffectCategoryCascade changeOnSelect style={{ width: 200 }} />
225
+ </Form.Item>
226
+ <Form.Item name="dateRange" label="日期" normalize={commonDateRangePickerNormalize} getValueProps={commonDateRangePickerGetValueProps}>
227
+ <DatePicker.RangePicker />
228
+ </Form.Item>
229
+ <Form.Item name="status" label="状态">
230
+ <Select options={statusOptions} allowClear style={{ width: 150 }} />
231
+ </Form.Item>
232
+ </SearchForm>
233
+ ```
234
+
235
+ ### 字段联动
236
+
237
+ 分类→品牌级联场景:
238
+
239
+ ```tsx
240
+ const categoryIds = Form.useWatch('categoryIds', form)
241
+ const categoryId = categoryIds?.at(-1)
242
+
243
+ <Form.Item name="brandId" label="品牌">
244
+ <EffectBrandSelect categoryId={categoryId} key={categoryId} />
245
+ </Form.Item>
246
+ ```
247
+
248
+ > 💡 **日期字段标准化**:使用 `normalize={commonDateRangePickerNormalize}` 和 `getValueProps={commonDateRangePickerGetValueProps}` 处理 DatePicker 与 Redux 之间的 dayjs 序列化。详见 [commonFn](./commonFn.md)。
249
+
250
+ > 💡 `operations` 区域支持根据权限条件渲染操作按钮(如 `buttonConfig.canExport && <Button>导出</Button>`)。
251
+
252
+ ## 常见陷阱
253
+
254
+ - ❌ 在跨包场景中使用完整表单模式,antd Context 可能隔离导致 Form 功能异常:
255
+ ```tsx
256
+ // 组件库和业务代码的 antd 版本/实例不一致
257
+ <SearchForm form={form} filter={filter} className="search">
258
+ ```
259
+ - ✅ 跨包场景使用 `SearchFormContent` 或 `contentOnly`,由消费方包裹 `<Form>`:
260
+ ```tsx
261
+ <Form form={form}>
262
+ <SearchFormContent filter={filter} form={form}>
263
+ ```
264
+
265
+ ## 相关组件
266
+
267
+ | 场景 | 组件 | 说明 |
268
+ | ------------ | ------------ | ----------------------------------- |
269
+ | 简单搜索列表 | `SearchList` | 更轻量的搜索容器,只有查询/重置按钮 |
270
+ | 增强输入框 | `CInput` | 搜索表单中常用的自动 trim 输入框 |
@@ -0,0 +1,128 @@
1
+ # SearchList
2
+
3
+ > 搜索列表容器,提供查询和重置按钮的简单布局,需要配合外部 `<Form>` 使用。
4
+
5
+ ## 导入
6
+
7
+ ```tsx
8
+ import { SearchList } from '@xfe-repo/web-components'
9
+ import type { SearchListProps } from '@xfe-repo/web-components'
10
+ ```
11
+
12
+ ## 基本用法
13
+
14
+ > SearchList 需要放在外部 `<Form>` 内使用。children 内部约定使用 `div.search_item > div.label + Form.Item(noStyle)` 的结构,确保搜索项的标签和输入控件对齐。
15
+
16
+ ```tsx
17
+ import { SearchList } from '@xfe-repo/web-components'
18
+ import { CInput } from '@xfe-repo/web-components'
19
+ import { Form } from 'antd'
20
+
21
+ function OrderFilter({ filter, onFinish, onReset }) {
22
+ const [form] = Form.useForm()
23
+
24
+ return (
25
+ <Form form={form} onFinish={onFinish} onReset={onReset}>
26
+ <SearchList showReset>
27
+ <div className={styles.search_item}>
28
+ <div className={styles.label}>订单号 :</div>
29
+ <Form.Item name="orderNo" noStyle initialValue={filter.orderNo}>
30
+ <CInput placeholder="请输入" allowClear />
31
+ </Form.Item>
32
+ </div>
33
+ <div className={styles.search_item}>
34
+ <div className={styles.label}>状态 :</div>
35
+ <Form.Item name="status" noStyle initialValue={filter.status}>
36
+ <Select options={statusOptions} allowClear placeholder="请选择" />
37
+ </Form.Item>
38
+ </div>
39
+ </SearchList>
40
+ </Form>
41
+ )
42
+ }
43
+ ```
44
+
45
+ ## 进阶用法
46
+
47
+ ### 隐藏查询按钮
48
+
49
+ ```tsx
50
+ <SearchList hideSearch>
51
+ <Form.Item name="keyword">
52
+ <Input />
53
+ </Form.Item>
54
+ </SearchList>
55
+ ```
56
+
57
+ ### 自定义操作按钮
58
+
59
+ ```tsx
60
+ <SearchList buttonChildren={<Button onClick={handleExport}>导出</Button>}>
61
+ <Form.Item name="keyword">
62
+ <Input />
63
+ </Form.Item>
64
+ </SearchList>
65
+ ```
66
+
67
+ ## Props
68
+
69
+ ```typescript
70
+ export type SearchListProps = {
71
+ showReset?: boolean
72
+ hideSearch?: boolean
73
+ children: ReactNode
74
+ buttonChildren?: ReactNode
75
+ }
76
+ ```
77
+
78
+ | 属性 | 类型 | 必填 | 默认值 | 说明 |
79
+ | -------------- | ----------- | ---- | ------ | -------------------------------- |
80
+ | children | `ReactNode` | 是 | - | 表单项内容 |
81
+ | showReset | `boolean` | 否 | - | 是否显示重置按钮 |
82
+ | hideSearch | `boolean` | 否 | - | 是否隐藏查询按钮 |
83
+ | buttonChildren | `ReactNode` | 否 | - | 额外操作按钮(渲染在查询按钮前) |
84
+
85
+ ### onReset 处理
86
+
87
+ 89% 场景启用 `showReset`,需提供 `onReset` 处理函数:
88
+
89
+ ```tsx
90
+ <Form
91
+ form={form}
92
+ onFinish={(values) => dispatch(effectSearch({ ...values, page: 1 }))}
93
+ onReset={() => dispatch(effectSearch(initialState.filter))}
94
+ >
95
+ <SearchList showReset>{/* 搜索项 */}</SearchList>
96
+ </Form>
97
+ ```
98
+
99
+ ### Redux filter 同步
100
+
101
+ 当 Redux filter 变化时(如翻页),需同步更新表单:
102
+
103
+ ```tsx
104
+ useEffect(() => {
105
+ form.resetFields()
106
+ }, [filter])
107
+ ```
108
+
109
+ > 💡 日期字段需配合 `normalize` 和 `getValueProps` 处理 dayjs 序列化,用法同 SearchForm。详见 [commonFn](./commonFn.md)。
110
+
111
+ > 💡 `hideSearch` 和 `buttonChildren` 业务使用率 <2%,大部分场景无需关注。
112
+
113
+ ## 常见陷阱
114
+
115
+ - ❌ Form.Item 不加 `noStyle`,导致额外的 margin-bottom 破坏搜索栏布局:
116
+ ```tsx
117
+ <Form.Item name="keyword"> {/* 会有 24px 下边距 */}
118
+ ```
119
+ - ✅ 始终使用 `noStyle`,由外层 div.search_item 控制布局:
120
+ ```tsx
121
+ <Form.Item name="keyword" noStyle>
122
+ ```
123
+
124
+ ## 相关组件
125
+
126
+ | 场景 | 组件 | 说明 |
127
+ | ------------ | ------------ | ---------------------------------- |
128
+ | 完整搜索表单 | `SearchForm` | 带表单包裹和 filter 同步的搜索表单 |