@xfe-repo/web-components 1.6.1 → 1.7.0
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/dist/index.css +0 -24
- package/dist/index.js +4 -6
- package/dist/index.mjs +4 -6
- package/package.json +6 -5
- package/skills/GUIDE.md +78 -0
- package/skills/SKILL.md +78 -0
- package/skills/TEMPLATE.md +170 -0
- package/skills/references/ApiService.md +136 -0
- package/skills/references/CInput.md +196 -0
- package/skills/references/CTable.md +274 -0
- package/skills/references/CVideo.md +94 -0
- package/skills/references/Clock.md +53 -0
- package/skills/references/ConfigProvider.md +198 -0
- package/skills/references/Countdown.md +109 -0
- package/skills/references/Counter.md +75 -0
- package/skills/references/Currency.md +112 -0
- package/skills/references/EffectAddressCascade.md +110 -0
- package/skills/references/EffectBrandSelect.md +231 -0
- package/skills/references/EffectBrandTransfer.md +143 -0
- package/skills/references/EffectCategoryCascade.md +228 -0
- package/skills/references/EffectFileUpload.md +349 -0
- package/skills/references/EffectLabelSelect.md +222 -0
- package/skills/references/EffectMerchantSelect.md +183 -0
- package/skills/references/EffectReservoirSelect.md +178 -0
- package/skills/references/EffectScopeSelect.md +220 -0
- package/skills/references/EffectSeriesSelect.md +205 -0
- package/skills/references/EffectSeriesSelectV2.md +154 -0
- package/skills/references/EffectSkuRecognize.md +149 -0
- package/skills/references/EffectSkuSelect.md +251 -0
- package/skills/references/EffectSkuTable.md +184 -0
- package/skills/references/EffectSpuSelect.md +189 -0
- package/skills/references/EffectStaffSelect.md +150 -0
- package/skills/references/EffectWarehouseSelect.md +183 -0
- package/skills/references/EffectWithFilePanel.md +205 -0
- package/skills/references/FileUpload.md +126 -0
- package/skills/references/Iconfont.md +31 -0
- package/skills/references/Loading.md +68 -0
- package/skills/references/MultiWindow.md +145 -0
- package/skills/references/OSSImage.md +230 -0
- package/skills/references/PrivacyField.md +90 -0
- package/skills/references/QRCode.md +148 -0
- package/skills/references/RichTextEditor.md +119 -0
- package/skills/references/SearchForm.md +270 -0
- package/skills/references/SearchList.md +128 -0
- package/skills/references/WithModal.md +328 -0
- package/skills/references/WithPanel.md +307 -0
- package/skills/references/commonFn.md +254 -0
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
# CInput
|
|
2
|
+
|
|
3
|
+
> 增强版 Input 输入框,在 antd Input 基础上默认启用失焦自动 trim,适用于表单场景防止用户输入前后空格。
|
|
4
|
+
|
|
5
|
+
## 导入
|
|
6
|
+
|
|
7
|
+
```tsx
|
|
8
|
+
import { CInput } from '@xfe-repo/web-components'
|
|
9
|
+
import type { CInputProps, CTextAreaProps, CSearchProps } from '@xfe-repo/web-components'
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## 基本用法
|
|
13
|
+
|
|
14
|
+
```tsx
|
|
15
|
+
import { CInput } from '@xfe-repo/web-components'
|
|
16
|
+
import { Form } from 'antd'
|
|
17
|
+
|
|
18
|
+
function MyForm() {
|
|
19
|
+
return (
|
|
20
|
+
<Form>
|
|
21
|
+
<Form.Item name="name" label="名称">
|
|
22
|
+
<CInput placeholder="失焦时自动去除首尾空格" />
|
|
23
|
+
</Form.Item>
|
|
24
|
+
</Form>
|
|
25
|
+
)
|
|
26
|
+
}
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### 搜索栏标准用法
|
|
30
|
+
|
|
31
|
+
在 SearchForm/SearchList 中使用 CInput 作为搜索输入(最高频场景):
|
|
32
|
+
|
|
33
|
+
```tsx
|
|
34
|
+
<SearchForm form={form} filter={filter} onFinish={onFinish}>
|
|
35
|
+
<Form.Item name="orderNo" label="订单号">
|
|
36
|
+
<CInput placeholder="请输入" allowClear style={{ width: 200 }} />
|
|
37
|
+
</Form.Item>
|
|
38
|
+
<Form.Item name="productName" label="商品名">
|
|
39
|
+
<CInput placeholder="请输入" allowClear style={{ width: 200 }} />
|
|
40
|
+
</Form.Item>
|
|
41
|
+
</SearchForm>
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
> 💡 搜索栏中 CInput 的标准 prop 组合:`placeholder` + `allowClear` + `style={{ width: N }}`。`autoTrim` 默认启用,无需手动设置。
|
|
45
|
+
|
|
46
|
+
> 💡 常用 prop 补充:`suffix` 添加单位后缀(如 `suffix="元"` 或 `suffix="%"`),`readOnly` + `variant="borderless"` 实现只读展示。
|
|
47
|
+
|
|
48
|
+
## 进阶用法
|
|
49
|
+
|
|
50
|
+
### 禁用自动 trim
|
|
51
|
+
|
|
52
|
+
```tsx
|
|
53
|
+
<CInput autoTrim={false} placeholder="不会自动去除空格" />
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### 使用 TextArea 子组件
|
|
57
|
+
|
|
58
|
+
```tsx
|
|
59
|
+
<CInput.TextArea rows={4} placeholder="多行输入,同样支持 autoTrim" />
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### 使用 Search 子组件
|
|
63
|
+
|
|
64
|
+
Search 子组件在 `onSearch` 回调中也会自动 trim 搜索值。
|
|
65
|
+
|
|
66
|
+
```tsx
|
|
67
|
+
<CInput.Search placeholder="搜索" onSearch={(value) => console.log('已 trim 的搜索值:', value)} />
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### CInput.Group 区间表达式
|
|
71
|
+
|
|
72
|
+
用 disabled CInput 作为数学符号分隔符,构建价格/数量区间输入:
|
|
73
|
+
|
|
74
|
+
```tsx
|
|
75
|
+
<CInput.Group compact>
|
|
76
|
+
<CInput placeholder="[" disabled style={{ width: 30 }} />
|
|
77
|
+
<Form.Item name="priceMin" noStyle>
|
|
78
|
+
<InputNumber style={{ width: 100 }} placeholder="最低" />
|
|
79
|
+
</Form.Item>
|
|
80
|
+
<CInput placeholder="~" disabled style={{ width: 36 }} />
|
|
81
|
+
<Form.Item name="priceMax" noStyle>
|
|
82
|
+
<InputNumber style={{ width: 100 }} placeholder="最高" />
|
|
83
|
+
</Form.Item>
|
|
84
|
+
<CInput placeholder=")" disabled style={{ width: 30 }} />
|
|
85
|
+
</CInput.Group>
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### 扫码输入场景
|
|
89
|
+
|
|
90
|
+
仓库扫码场景的标准 prop 组合:
|
|
91
|
+
|
|
92
|
+
```tsx
|
|
93
|
+
<CInput placeholder="扫描可获得 / 手动输入" autoFocus autoComplete="off" allowClear />
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
> 💡 扫码场景必须设置 `autoComplete="off"` 禁用浏览器自动填充,`autoFocus` 自动聚焦方便操作。
|
|
97
|
+
|
|
98
|
+
### Space.Compact 组合输入
|
|
99
|
+
|
|
100
|
+
Select + CInput 组成复合输入(如"链接类型 + URL"):
|
|
101
|
+
|
|
102
|
+
```tsx
|
|
103
|
+
<Space.Compact>
|
|
104
|
+
<Form.Item name="linkType" noStyle>
|
|
105
|
+
<Select
|
|
106
|
+
style={{ width: 120 }}
|
|
107
|
+
options={[
|
|
108
|
+
{ label: '商品链接', value: 'product' },
|
|
109
|
+
{ label: '外部链接', value: 'external' },
|
|
110
|
+
]}
|
|
111
|
+
/>
|
|
112
|
+
</Form.Item>
|
|
113
|
+
<Form.Item name="linkUrl" noStyle>
|
|
114
|
+
<CInput placeholder="请输入链接" style={{ width: 300 }} />
|
|
115
|
+
</Form.Item>
|
|
116
|
+
</Space.Compact>
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### 登录场景
|
|
120
|
+
|
|
121
|
+
```tsx
|
|
122
|
+
<CInput prefix={<PhoneOutlined />} placeholder="手机号" maxLength={11} />
|
|
123
|
+
<CInput prefix={<LockOutlined />} type="password" placeholder="验证码" />
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### CInput.TextArea 标准用法
|
|
127
|
+
|
|
128
|
+
```tsx
|
|
129
|
+
<Form.Item name="remark" label="备注">
|
|
130
|
+
<CInput.TextArea rows={4} maxLength={200} showCount placeholder="请输入" />
|
|
131
|
+
</Form.Item>
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
> 💡 TextArea 标准组合:`rows`(展示行数)+ `maxLength`(字符限制)+ `showCount`(显示已输入字数)。
|
|
135
|
+
|
|
136
|
+
## Props
|
|
137
|
+
|
|
138
|
+
### CInputProps
|
|
139
|
+
|
|
140
|
+
```typescript
|
|
141
|
+
export interface CInputProps extends InputProps {
|
|
142
|
+
/** 是否在失焦时自动去掉首尾空格,默认 true */
|
|
143
|
+
autoTrim?: boolean
|
|
144
|
+
}
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
| 属性 | 类型 | 必填 | 默认值 | 说明 |
|
|
148
|
+
| ------------- | ------------ | ---- | ------ | ---------------------------- |
|
|
149
|
+
| autoTrim | `boolean` | 否 | `true` | 是否在失焦时自动去除首尾空格 |
|
|
150
|
+
| ...inputProps | `InputProps` | 否 | - | 所有 antd Input 属性 |
|
|
151
|
+
|
|
152
|
+
### CTextAreaProps
|
|
153
|
+
|
|
154
|
+
```typescript
|
|
155
|
+
export interface CTextAreaProps extends TextAreaProps {
|
|
156
|
+
autoTrim?: boolean
|
|
157
|
+
}
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
### CSearchProps
|
|
161
|
+
|
|
162
|
+
```typescript
|
|
163
|
+
export interface CSearchProps extends SearchProps {
|
|
164
|
+
autoTrim?: boolean
|
|
165
|
+
}
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
## 子组件
|
|
169
|
+
|
|
170
|
+
| 子组件 | 类型 | 说明 |
|
|
171
|
+
| ----------------- | ------------------------------------------- | -------------------------------------- |
|
|
172
|
+
| `CInput.TextArea` | `ForwardRefExoticComponent<CTextAreaProps>` | 多行输入框,支持 autoTrim |
|
|
173
|
+
| `CInput.Search` | `ForwardRefExoticComponent<CSearchProps>` | 搜索输入框,onSearch 回调也会自动 trim |
|
|
174
|
+
| `CInput.Group` | `typeof Input.Group` | 直接透传 antd 的 Input.Group |
|
|
175
|
+
|
|
176
|
+
## 常见陷阱
|
|
177
|
+
|
|
178
|
+
- ❌ 在 Form 中使用原生 `Input`,用户输入 `" 张三 "` 提交时带空格:
|
|
179
|
+
```tsx
|
|
180
|
+
<Form.Item name="name">
|
|
181
|
+
<Input /> {/* 不会自动 trim */}
|
|
182
|
+
</Form.Item>
|
|
183
|
+
```
|
|
184
|
+
- ✅ 使用 `CInput` 替代,失焦时自动 trim 并通过 onChange 同步到 Form:
|
|
185
|
+
```tsx
|
|
186
|
+
<Form.Item name="name">
|
|
187
|
+
<CInput /> {/* 失焦时自动 trim,Form 值同步更新 */}
|
|
188
|
+
</Form.Item>
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
## 相关组件
|
|
192
|
+
|
|
193
|
+
| 场景 | 组件 | 说明 |
|
|
194
|
+
| -------- | -------------- | ---------------------------------------- |
|
|
195
|
+
| 搜索表单 | `SearchForm` | 表单容器,内部可使用 CInput 作为输入组件 |
|
|
196
|
+
| 隐私字段 | `PrivacyField` | 展示脱敏数据,非输入场景 |
|
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
# CTable
|
|
2
|
+
|
|
3
|
+
> 增强表格组件,基于 antd Table 扩展了拖拽排序功能,通过 `enableDrag` 一键切换普通表格和可排序表格。
|
|
4
|
+
|
|
5
|
+
## 导入
|
|
6
|
+
|
|
7
|
+
```tsx
|
|
8
|
+
import { CTable, getCTable } from '@xfe-repo/web-components'
|
|
9
|
+
import type { CTableProps, TableDragEndEvent } from '@xfe-repo/web-components'
|
|
10
|
+
|
|
11
|
+
// dashboard 项目标准别名
|
|
12
|
+
import { CTable as TypeTable } from '@xfe-repo/web-components'
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## 基本用法
|
|
16
|
+
|
|
17
|
+
普通表格模式,与 antd Table 完全一致:
|
|
18
|
+
|
|
19
|
+
```tsx
|
|
20
|
+
import { CTable } from '@xfe-repo/web-components'
|
|
21
|
+
|
|
22
|
+
function MyPage() {
|
|
23
|
+
const columns = [
|
|
24
|
+
{ title: '名称', dataIndex: 'name' },
|
|
25
|
+
{ title: '年龄', dataIndex: 'age' },
|
|
26
|
+
]
|
|
27
|
+
|
|
28
|
+
return <CTable dataSource={data} columns={columns} rowKey="id" />
|
|
29
|
+
}
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### 直接泛型用法
|
|
33
|
+
|
|
34
|
+
无需 `getCTable` 工厂函数,直接使用泛型参数:
|
|
35
|
+
|
|
36
|
+
```tsx
|
|
37
|
+
<CTable<UserRecord> dataSource={users} columns={columns} rowKey="id" />
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### TypeTable 别名 + JSX Column 模式
|
|
41
|
+
|
|
42
|
+
dashboard 项目约定使用 `TypeTable` 别名,配合 JSX Column 声明列:
|
|
43
|
+
|
|
44
|
+
```tsx
|
|
45
|
+
import { CTable as TypeTable } from '@xfe-repo/web-components'
|
|
46
|
+
|
|
47
|
+
function OrderList({ tableProps }: { tableProps: CTableProps<OrderItem> }) {
|
|
48
|
+
return (
|
|
49
|
+
<TypeTable<OrderItem> {...tableProps} rowKey="orderNo">
|
|
50
|
+
<TypeTable.Column<OrderItem> title="订单号" render={renderOrderNo} align="center" />
|
|
51
|
+
<TypeTable.Column<OrderItem> title="金额" render={renderPrice} align="center" />
|
|
52
|
+
<TypeTable.Column<OrderItem> title="操作" render={renderAction} align="right" />
|
|
53
|
+
</TypeTable>
|
|
54
|
+
)
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
> 💡 `TypeTable` 只是 `CTable` 的别名,功能完全一致。使用 JSX Column 方式可以获得更好的 TypeScript 类型推导。
|
|
59
|
+
|
|
60
|
+
## 进阶用法
|
|
61
|
+
|
|
62
|
+
### 拖拽排序
|
|
63
|
+
|
|
64
|
+
开启 `enableDrag` 后自动切换为拖拽排序表格,需要提供 `onSortEnd` 回调和 `CTable.DragHandle` 拖拽手柄:
|
|
65
|
+
|
|
66
|
+
```tsx
|
|
67
|
+
import { CTable } from '@xfe-repo/web-components'
|
|
68
|
+
import type { TableDragEndEvent } from '@xfe-repo/web-components'
|
|
69
|
+
import { arrayMove } from '@dnd-kit/sortable'
|
|
70
|
+
|
|
71
|
+
function SortableTable() {
|
|
72
|
+
const [data, setData] = useState(initialData)
|
|
73
|
+
|
|
74
|
+
const columns = [
|
|
75
|
+
{
|
|
76
|
+
title: '排序',
|
|
77
|
+
width: 60,
|
|
78
|
+
render: () => <CTable.DragHandle />,
|
|
79
|
+
},
|
|
80
|
+
{ title: '名称', dataIndex: 'name' },
|
|
81
|
+
{ title: '描述', dataIndex: 'description' },
|
|
82
|
+
]
|
|
83
|
+
|
|
84
|
+
const handleSortEnd = (event: TableDragEndEvent) => {
|
|
85
|
+
const { active, over } = event
|
|
86
|
+
if (active.id !== over?.id) {
|
|
87
|
+
const oldIndex = data.findIndex((i) => i.id === active.id)
|
|
88
|
+
const newIndex = data.findIndex((i) => i.id === over?.id)
|
|
89
|
+
setData(arrayMove(data, oldIndex, newIndex))
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return <CTable enableDrag dataSource={data} columns={columns} rowKey="id" onSortEnd={handleSortEnd} />
|
|
94
|
+
}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### 行选择(rowSelection)
|
|
98
|
+
|
|
99
|
+
```tsx
|
|
100
|
+
const [selectedRowKeys, setSelectedRowKeys] = useState<string[]>([])
|
|
101
|
+
|
|
102
|
+
const rowSelection = {
|
|
103
|
+
selectedRowKeys,
|
|
104
|
+
onChange: (keys: string[]) => setSelectedRowKeys(keys),
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
<CTable
|
|
108
|
+
dataSource={dataSource}
|
|
109
|
+
columns={columns}
|
|
110
|
+
rowKey="id"
|
|
111
|
+
rowSelection={rowSelection}
|
|
112
|
+
/>
|
|
113
|
+
|
|
114
|
+
// 获取选中项
|
|
115
|
+
<Button onClick={() => handleBatch(selectedRowKeys)}>
|
|
116
|
+
批量操作({selectedRowKeys.length})
|
|
117
|
+
</Button>
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### 使用 CTable.Column 声明列
|
|
121
|
+
|
|
122
|
+
```tsx
|
|
123
|
+
<CTable dataSource={data} rowKey="id">
|
|
124
|
+
<CTable.Column title="名称" dataIndex="name" />
|
|
125
|
+
<CTable.Column title="年龄" dataIndex="age" />
|
|
126
|
+
</CTable>
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### 使用 getCTable 获得泛型类型推导
|
|
130
|
+
|
|
131
|
+
`getCTable<T>()` 返回带有完整类型推导的 CTable 组件:
|
|
132
|
+
|
|
133
|
+
```tsx
|
|
134
|
+
import { getCTable } from '@xfe-repo/web-components'
|
|
135
|
+
|
|
136
|
+
interface UserRecord {
|
|
137
|
+
id: number
|
|
138
|
+
name: string
|
|
139
|
+
age: number
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const UserTable = getCTable<UserRecord>()
|
|
143
|
+
|
|
144
|
+
function MyPage() {
|
|
145
|
+
return (
|
|
146
|
+
<UserTable
|
|
147
|
+
dataSource={users}
|
|
148
|
+
columns={[
|
|
149
|
+
{ title: '名称', dataIndex: 'name' }, // dataIndex 有类型提示
|
|
150
|
+
{ title: '年龄', dataIndex: 'age' },
|
|
151
|
+
]}
|
|
152
|
+
rowKey="id"
|
|
153
|
+
/>
|
|
154
|
+
)
|
|
155
|
+
}
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
## Props
|
|
159
|
+
|
|
160
|
+
```typescript
|
|
161
|
+
export type CTableProps<T> = SortTableProps<T> & {
|
|
162
|
+
enableDrag?: boolean
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
export type SortTableProps<T> = TableProps<T> & {
|
|
166
|
+
onSortEnd?: (event: TableDragEndEvent) => void
|
|
167
|
+
/** @deprecated 拼写兼容,后续请统一使用 onSortEnd */
|
|
168
|
+
onShortEnd?: (event: TableDragEndEvent) => void
|
|
169
|
+
}
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
| 属性 | 类型 | 必填 | 默认值 | 说明 |
|
|
173
|
+
| ------------- | ------------------------------------ | ------------ | ------- | ---------------------------------------- |
|
|
174
|
+
| enableDrag | `boolean` | 否 | `false` | 是否启用拖拽排序模式 |
|
|
175
|
+
| onSortEnd | `(event: TableDragEndEvent) => void` | 否 | - | 拖拽排序结束回调(仅 enableDrag 时生效) |
|
|
176
|
+
| onShortEnd | `(event: TableDragEndEvent) => void` | 否 | - | ⚠️ 已废弃,`onSortEnd` 的拼写兼容 |
|
|
177
|
+
| rowKey | `string \| ((record: T) => string)` | 是(拖拽时) | - | 行唯一标识,拖拽模式下必须提供 |
|
|
178
|
+
| ...tableProps | `TableProps<T>` | 否 | - | 所有 antd Table 属性 |
|
|
179
|
+
|
|
180
|
+
## 导出类型
|
|
181
|
+
|
|
182
|
+
```typescript
|
|
183
|
+
// 拖拽事件类型(来自 @dnd-kit/core 的 DragEndEvent)
|
|
184
|
+
export type TableDragEndEvent = DragEndEvent
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
## 子组件
|
|
188
|
+
|
|
189
|
+
| 子组件 | 说明 |
|
|
190
|
+
| ------------------- | ------------------------------------------------------ |
|
|
191
|
+
| `CTable.Column` | antd Table.Column,用于 JSX 声明列 |
|
|
192
|
+
| `CTable.DragHandle` | 拖拽手柄按钮,渲染 HolderOutlined 图标,`cursor: move` |
|
|
193
|
+
|
|
194
|
+
### CTable.DragHandle
|
|
195
|
+
|
|
196
|
+
拖拽手柄组件,无需传入 Props,自动从 DraggableRow 上下文获取拖拽监听器。只能在 `enableDrag` 模式下的列 `render` 中使用。
|
|
197
|
+
|
|
198
|
+
```tsx
|
|
199
|
+
{
|
|
200
|
+
title: '排序',
|
|
201
|
+
width: 60,
|
|
202
|
+
render: () => <CTable.DragHandle />,
|
|
203
|
+
}
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
## 工厂函数
|
|
207
|
+
|
|
208
|
+
### getCTable\<T\>()
|
|
209
|
+
|
|
210
|
+
返回带有泛型的 CTable 组件,包含 `Column` 和 `DragHandle` 子组件:
|
|
211
|
+
|
|
212
|
+
```typescript
|
|
213
|
+
function getCTable<T extends object>(): FC<CTableProps<T>> & {
|
|
214
|
+
Column: FC<ColumnProps<T>>
|
|
215
|
+
DragHandle: typeof DragHandle
|
|
216
|
+
[key: string]: any
|
|
217
|
+
}
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
## 常见陷阱
|
|
221
|
+
|
|
222
|
+
- ❌ 开启 `enableDrag` 但未提供 `rowKey`——拖拽排序依赖 rowKey 生成排序标识:
|
|
223
|
+
```tsx
|
|
224
|
+
<CTable enableDrag dataSource={data} columns={columns} />
|
|
225
|
+
// 运行时错误:无法识别拖拽行
|
|
226
|
+
```
|
|
227
|
+
- ✅ 拖拽模式下必须提供 `rowKey`:
|
|
228
|
+
|
|
229
|
+
```tsx
|
|
230
|
+
<CTable enableDrag dataSource={data} columns={columns} rowKey="id" />
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
- ❌ 使用 `onShortEnd` 回调——这是一个拼写错误的遗留 API,已被标记为 `@deprecated`
|
|
234
|
+
- ✅ 使用 `onSortEnd` 替代
|
|
235
|
+
|
|
236
|
+
- ❌ 在非 `enableDrag` 模式下使用 `CTable.DragHandle`——手柄依赖 DraggableRow 上下文
|
|
237
|
+
- ✅ `DragHandle` 仅在 `enableDrag={true}` 时使用
|
|
238
|
+
|
|
239
|
+
- ❌ 拖拽模式下忘记用 `arrayMove` 等工具重排数据——`onSortEnd` 只提供事件,不会自动修改 dataSource
|
|
240
|
+
- ✅ 在 `onSortEnd` 中手动更新 dataSource 顺序
|
|
241
|
+
|
|
242
|
+
- ❌ 在组件函数体内调用 `getCTable`,每次 render 创建新实例导致闪烁:
|
|
243
|
+
```tsx
|
|
244
|
+
function MyComponent() {
|
|
245
|
+
const TypedTable = getCTable<ItemType>() // ❌ 每次 render 都重建
|
|
246
|
+
return <TypedTable ... />
|
|
247
|
+
}
|
|
248
|
+
```
|
|
249
|
+
- ✅ 在模块顶层调用,或直接使用 `<CTable<T>>`:
|
|
250
|
+
```tsx
|
|
251
|
+
const TypedTable = getCTable<ItemType>() // ✅ 模块顶层,只创建一次
|
|
252
|
+
function MyComponent() {
|
|
253
|
+
return <TypedTable ... />
|
|
254
|
+
}
|
|
255
|
+
// 或者直接:
|
|
256
|
+
function MyComponent() {
|
|
257
|
+
return <CTable<ItemType> ... /> // ✅ 推荐
|
|
258
|
+
}
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
## 使用提示
|
|
262
|
+
|
|
263
|
+
> 💡 超过半数场景传 `pagination={false}` 禁用内置分页(使用外部分页组件或 Redux 分页逻辑)。
|
|
264
|
+
|
|
265
|
+
> 💡 拖拽序号列常见写法:`render: (_, __, index) => <Space><CTable.DragHandle />{index + 1}</Space>`
|
|
266
|
+
|
|
267
|
+
> 💡 列排序:`{ sorter: true, sortOrder: sortedInfo.order }` 配合 `onChange` 回调处理排序。
|
|
268
|
+
|
|
269
|
+
## 相关组件
|
|
270
|
+
|
|
271
|
+
| 场景 | 组件 | 说明 |
|
|
272
|
+
| ------------ | --------------------- | ---------------------------- |
|
|
273
|
+
| 通用表格配置 | `getCommonTableProps` | 提供预设的表格公共 Props |
|
|
274
|
+
| 搜索列表 | `SearchList` | 集成搜索表单和分页的列表组件 |
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# CVideo
|
|
2
|
+
|
|
3
|
+
> 视频播放器组件,基于 video.js 封装,支持 MP4 和 HLS (m3u8) 格式,附带弹窗播放高阶组件。
|
|
4
|
+
|
|
5
|
+
## 导入
|
|
6
|
+
|
|
7
|
+
```tsx
|
|
8
|
+
import { CVideo, WithCVideoModal } from '@xfe-repo/web-components'
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## 基本用法
|
|
12
|
+
|
|
13
|
+
```tsx
|
|
14
|
+
import { CVideo } from '@xfe-repo/web-components'
|
|
15
|
+
|
|
16
|
+
function VideoPlayer() {
|
|
17
|
+
return <CVideo src="https://example.com/video.mp4" width={640} height={360} />
|
|
18
|
+
}
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## 进阶用法
|
|
22
|
+
|
|
23
|
+
### 弹窗播放
|
|
24
|
+
|
|
25
|
+
使用 `WithCVideoModal` 包裹触发元素,点击后弹窗播放视频。
|
|
26
|
+
|
|
27
|
+
```tsx
|
|
28
|
+
import { WithCVideoModal } from '@xfe-repo/web-components'
|
|
29
|
+
import { Button } from 'antd'
|
|
30
|
+
|
|
31
|
+
function VideoPreview() {
|
|
32
|
+
return (
|
|
33
|
+
<WithCVideoModal videoSrc="https://example.com/video.mp4" title="视频预览" width={640} height={360}>
|
|
34
|
+
<Button>播放视频</Button>
|
|
35
|
+
</WithCVideoModal>
|
|
36
|
+
)
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### 播放 HLS 流
|
|
41
|
+
|
|
42
|
+
```tsx
|
|
43
|
+
<CVideo src="https://example.com/stream.m3u8" />
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Props
|
|
47
|
+
|
|
48
|
+
### CVideoProps
|
|
49
|
+
|
|
50
|
+
```typescript
|
|
51
|
+
interface CVideoProps {
|
|
52
|
+
src: string
|
|
53
|
+
width?: number
|
|
54
|
+
height?: number
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
| 属性 | 类型 | 必填 | 默认值 | 说明 |
|
|
59
|
+
| ------ | -------- | ---- | ------ | ---------------------------- |
|
|
60
|
+
| src | `string` | 是 | - | 视频地址,支持 .mp4 和 .m3u8 |
|
|
61
|
+
| width | `number` | 否 | `320` | 播放器宽度 |
|
|
62
|
+
| height | `number` | 否 | `320` | 播放器高度 |
|
|
63
|
+
|
|
64
|
+
### WithCVideoModalProps
|
|
65
|
+
|
|
66
|
+
```typescript
|
|
67
|
+
interface WithCVideoModalProps {
|
|
68
|
+
children: ReactElement
|
|
69
|
+
videoSrc: string
|
|
70
|
+
title?: string
|
|
71
|
+
width?: number
|
|
72
|
+
height?: number
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
| 属性 | 类型 | 必填 | 默认值 | 说明 |
|
|
77
|
+
| -------- | -------------- | ---- | ------------ | ---------------------------- |
|
|
78
|
+
| children | `ReactElement` | 是 | - | 触发元素,点击后打开视频弹窗 |
|
|
79
|
+
| videoSrc | `string` | 是 | - | 视频地址 |
|
|
80
|
+
| title | `string` | 否 | `'视频切片'` | 弹窗标题 |
|
|
81
|
+
| width | `number` | 否 | `480` | 视频播放器宽度 |
|
|
82
|
+
| height | `number` | 否 | `320` | 视频播放器高度 |
|
|
83
|
+
|
|
84
|
+
## 常见陷阱
|
|
85
|
+
|
|
86
|
+
- ❌ `src` 为空字符串时,组件会显示 "请检查视频地址" 文本而非空白
|
|
87
|
+
- ✅ 在传入前判断 src 是否有效,避免展示提示文本
|
|
88
|
+
|
|
89
|
+
## 相关组件
|
|
90
|
+
|
|
91
|
+
| 场景 | 组件 | 说明 |
|
|
92
|
+
| -------- | ----------- | --------------------------------------- |
|
|
93
|
+
| 弹窗容器 | `WithModal` | WithCVideoModal 内部基于 WithModal 实现 |
|
|
94
|
+
| 图片展示 | `OSSImage` | 图片场景使用 OSSImage |
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# Clock
|
|
2
|
+
|
|
3
|
+
> 实时时钟组件,每秒更新一次,支持自定义格式化字符串。
|
|
4
|
+
|
|
5
|
+
## 导入
|
|
6
|
+
|
|
7
|
+
```tsx
|
|
8
|
+
import { Clock, formatClock } from '@xfe-repo/web-components'
|
|
9
|
+
import type { ClockProps } from '@xfe-repo/web-components'
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## 基本用法
|
|
13
|
+
|
|
14
|
+
```tsx
|
|
15
|
+
import { Clock } from '@xfe-repo/web-components'
|
|
16
|
+
|
|
17
|
+
function Header() {
|
|
18
|
+
return <Clock /> {/* 输出:3月15日 14:30:05 */}
|
|
19
|
+
}
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## 进阶用法
|
|
23
|
+
|
|
24
|
+
### 自定义格式
|
|
25
|
+
|
|
26
|
+
```tsx
|
|
27
|
+
<Clock formatStr="HH:MM:SS" /> {/* 14:30:05 */}
|
|
28
|
+
<Clock formatStr="mm/DD HH:MM" /> {/* 3/15 14:30 */}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Props
|
|
32
|
+
|
|
33
|
+
```typescript
|
|
34
|
+
export interface ClockProps {
|
|
35
|
+
formatStr?: string
|
|
36
|
+
className?: string
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
| 属性 | 类型 | 必填 | 默认值 | 说明 |
|
|
41
|
+
| --------- | -------- | ---- | --------------------- | ---------------------------------------- |
|
|
42
|
+
| formatStr | `string` | 否 | `'mm月DD日 HH:MM:SS'` | 格式化字符串,支持 mm/DD/HH/MM/SS 占位符 |
|
|
43
|
+
| className | `string` | 否 | - | 自定义 className |
|
|
44
|
+
|
|
45
|
+
## 导出类型
|
|
46
|
+
|
|
47
|
+
### formatClock
|
|
48
|
+
|
|
49
|
+
```typescript
|
|
50
|
+
export const formatClock: (date: Date, formatStr?: string) => string
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
独立的格式化函数,可在非组件场景使用。
|