@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.
- package/package.json +6 -5
- package/skills/xfe-web-components/GUIDE.md +78 -0
- package/skills/xfe-web-components/SKILL.md +78 -0
- package/skills/xfe-web-components/TEMPLATE.md +170 -0
- package/skills/xfe-web-components/references/ApiService.md +136 -0
- package/skills/xfe-web-components/references/CInput.md +196 -0
- package/skills/xfe-web-components/references/CTable.md +274 -0
- package/skills/xfe-web-components/references/CVideo.md +94 -0
- package/skills/xfe-web-components/references/Clock.md +53 -0
- package/skills/xfe-web-components/references/ConfigProvider.md +198 -0
- package/skills/xfe-web-components/references/Countdown.md +109 -0
- package/skills/xfe-web-components/references/Counter.md +75 -0
- package/skills/xfe-web-components/references/Currency.md +112 -0
- package/skills/xfe-web-components/references/EffectAddressCascade.md +110 -0
- package/skills/xfe-web-components/references/EffectBrandSelect.md +231 -0
- package/skills/xfe-web-components/references/EffectBrandTransfer.md +143 -0
- package/skills/xfe-web-components/references/EffectCategoryCascade.md +227 -0
- package/skills/xfe-web-components/references/EffectFileUpload.md +348 -0
- package/skills/xfe-web-components/references/EffectLabelSelect.md +222 -0
- package/skills/xfe-web-components/references/EffectMerchantSelect.md +183 -0
- package/skills/xfe-web-components/references/EffectReservoirSelect.md +178 -0
- package/skills/xfe-web-components/references/EffectScopeSelect.md +220 -0
- package/skills/xfe-web-components/references/EffectSeriesSelect.md +204 -0
- package/skills/xfe-web-components/references/EffectSeriesSelectV2.md +154 -0
- package/skills/xfe-web-components/references/EffectSkuRecognize.md +149 -0
- package/skills/xfe-web-components/references/EffectSkuSelect.md +251 -0
- package/skills/xfe-web-components/references/EffectSkuTable.md +184 -0
- package/skills/xfe-web-components/references/EffectSpuSelect.md +189 -0
- package/skills/xfe-web-components/references/EffectStaffSelect.md +150 -0
- package/skills/xfe-web-components/references/EffectWarehouseSelect.md +183 -0
- package/skills/xfe-web-components/references/EffectWithFilePanel.md +205 -0
- package/skills/xfe-web-components/references/FileUpload.md +126 -0
- package/skills/xfe-web-components/references/Iconfont.md +31 -0
- package/skills/xfe-web-components/references/Loading.md +68 -0
- package/skills/xfe-web-components/references/MultiWindow.md +145 -0
- package/skills/xfe-web-components/references/OSSImage.md +230 -0
- package/skills/xfe-web-components/references/PrivacyField.md +90 -0
- package/skills/xfe-web-components/references/QRCode.md +148 -0
- package/skills/xfe-web-components/references/RichTextEditor.md +119 -0
- package/skills/xfe-web-components/references/SearchForm.md +270 -0
- package/skills/xfe-web-components/references/SearchList.md +128 -0
- package/skills/xfe-web-components/references/WithModal.md +328 -0
- package/skills/xfe-web-components/references/WithPanel.md +307 -0
- 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 同步的搜索表单 |
|