@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.
Files changed (47) hide show
  1. package/dist/index.css +0 -24
  2. package/dist/index.js +4 -6
  3. package/dist/index.mjs +4 -6
  4. package/package.json +6 -5
  5. package/skills/GUIDE.md +78 -0
  6. package/skills/SKILL.md +78 -0
  7. package/skills/TEMPLATE.md +170 -0
  8. package/skills/references/ApiService.md +136 -0
  9. package/skills/references/CInput.md +196 -0
  10. package/skills/references/CTable.md +274 -0
  11. package/skills/references/CVideo.md +94 -0
  12. package/skills/references/Clock.md +53 -0
  13. package/skills/references/ConfigProvider.md +198 -0
  14. package/skills/references/Countdown.md +109 -0
  15. package/skills/references/Counter.md +75 -0
  16. package/skills/references/Currency.md +112 -0
  17. package/skills/references/EffectAddressCascade.md +110 -0
  18. package/skills/references/EffectBrandSelect.md +231 -0
  19. package/skills/references/EffectBrandTransfer.md +143 -0
  20. package/skills/references/EffectCategoryCascade.md +228 -0
  21. package/skills/references/EffectFileUpload.md +349 -0
  22. package/skills/references/EffectLabelSelect.md +222 -0
  23. package/skills/references/EffectMerchantSelect.md +183 -0
  24. package/skills/references/EffectReservoirSelect.md +178 -0
  25. package/skills/references/EffectScopeSelect.md +220 -0
  26. package/skills/references/EffectSeriesSelect.md +205 -0
  27. package/skills/references/EffectSeriesSelectV2.md +154 -0
  28. package/skills/references/EffectSkuRecognize.md +149 -0
  29. package/skills/references/EffectSkuSelect.md +251 -0
  30. package/skills/references/EffectSkuTable.md +184 -0
  31. package/skills/references/EffectSpuSelect.md +189 -0
  32. package/skills/references/EffectStaffSelect.md +150 -0
  33. package/skills/references/EffectWarehouseSelect.md +183 -0
  34. package/skills/references/EffectWithFilePanel.md +205 -0
  35. package/skills/references/FileUpload.md +126 -0
  36. package/skills/references/Iconfont.md +31 -0
  37. package/skills/references/Loading.md +68 -0
  38. package/skills/references/MultiWindow.md +145 -0
  39. package/skills/references/OSSImage.md +230 -0
  40. package/skills/references/PrivacyField.md +90 -0
  41. package/skills/references/QRCode.md +148 -0
  42. package/skills/references/RichTextEditor.md +119 -0
  43. package/skills/references/SearchForm.md +270 -0
  44. package/skills/references/SearchList.md +128 -0
  45. package/skills/references/WithModal.md +328 -0
  46. package/skills/references/WithPanel.md +307 -0
  47. 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
+ 独立的格式化函数,可在非组件场景使用。