@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,198 @@
|
|
|
1
|
+
# ConfigProvider
|
|
2
|
+
|
|
3
|
+
> 全局配置提供者,集成 Ant Design 配置、API 服务、国际化和主题,是所有 Effect 组件的运行基础。
|
|
4
|
+
|
|
5
|
+
## 导入
|
|
6
|
+
|
|
7
|
+
```tsx
|
|
8
|
+
import { ConfigProvider, ConfigContext } from '@xfe-repo/web-components'
|
|
9
|
+
import type { ConfigProviderProps, IApiPayload, IConfigContext } from '@xfe-repo/web-components'
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## 基本用法
|
|
13
|
+
|
|
14
|
+
```tsx
|
|
15
|
+
import { ConfigProvider } from '@xfe-repo/web-components'
|
|
16
|
+
import zhCN from 'antd/locale/zh_CN'
|
|
17
|
+
|
|
18
|
+
function App() {
|
|
19
|
+
return (
|
|
20
|
+
<ConfigProvider
|
|
21
|
+
locale={zhCN}
|
|
22
|
+
apiPayload={{
|
|
23
|
+
jwt: jwtInstance,
|
|
24
|
+
apiEnv: 'production',
|
|
25
|
+
business: 'eshetang',
|
|
26
|
+
getUserToken: () => localStorage.getItem('token') || '',
|
|
27
|
+
setUserToken: (token) => localStorage.setItem('token', token),
|
|
28
|
+
removeUserToken: () => localStorage.removeItem('token'),
|
|
29
|
+
}}
|
|
30
|
+
>
|
|
31
|
+
<YourApp />
|
|
32
|
+
</ConfigProvider>
|
|
33
|
+
)
|
|
34
|
+
}
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## 进阶用法
|
|
38
|
+
|
|
39
|
+
### 自定义 API 服务
|
|
40
|
+
|
|
41
|
+
通过 `apiService` 覆盖默认的 SaaS BFF 服务实现,适用于非标准后端或 Mock 场景。自定义方法会与默认 `saasApiService` 合并(浅合并,自定义优先)。
|
|
42
|
+
|
|
43
|
+
```tsx
|
|
44
|
+
import { ConfigProvider } from '@xfe-repo/web-components'
|
|
45
|
+
|
|
46
|
+
const customApiService = {
|
|
47
|
+
categoryListToTree: async (params, config) => {
|
|
48
|
+
// 自定义分类树接口实现
|
|
49
|
+
return await myCustomApi.getCategoryTree(params)
|
|
50
|
+
},
|
|
51
|
+
brandComboBox: async (params, config) => {
|
|
52
|
+
// 自定义品牌下拉接口实现
|
|
53
|
+
return await myCustomApi.getBrands(params)
|
|
54
|
+
},
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function App() {
|
|
58
|
+
return (
|
|
59
|
+
<ConfigProvider apiService={customApiService}>
|
|
60
|
+
<YourApp />
|
|
61
|
+
</ConfigProvider>
|
|
62
|
+
)
|
|
63
|
+
}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### 在子组件中消费 Context
|
|
67
|
+
|
|
68
|
+
```tsx
|
|
69
|
+
import { useContext } from 'react'
|
|
70
|
+
import { ConfigContext } from '@xfe-repo/web-components'
|
|
71
|
+
|
|
72
|
+
function MyComponent() {
|
|
73
|
+
const configContext = useContext(ConfigContext)
|
|
74
|
+
|
|
75
|
+
// 获取 API 服务和认证信息
|
|
76
|
+
const { apiService, apiPayload } = configContext!
|
|
77
|
+
const token = apiPayload.getUserToken?.()
|
|
78
|
+
|
|
79
|
+
return <div>当前环境:{apiPayload.apiEnv}</div>
|
|
80
|
+
}
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## Props
|
|
84
|
+
|
|
85
|
+
```typescript
|
|
86
|
+
interface ConfigProviderProps {
|
|
87
|
+
/** SaaS BFF 认证信息,使用自定义 apiService 时可不传 */
|
|
88
|
+
apiPayload?: Partial<IApiPayload>
|
|
89
|
+
/** 自定义 API 服务实现,会覆盖默认的 SaaS BFF 服务 */
|
|
90
|
+
apiService?: Partial<IApiService>
|
|
91
|
+
/** antd 国际化语言包 */
|
|
92
|
+
locale?: Locale
|
|
93
|
+
/** antd 主题配置 */
|
|
94
|
+
theme?: ThemeConfig
|
|
95
|
+
/** antd App 组件的 className */
|
|
96
|
+
className?: string
|
|
97
|
+
/** 子组件 */
|
|
98
|
+
children: React.ReactNode
|
|
99
|
+
}
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
| 属性 | 类型 | 必填 | 默认值 | 说明 |
|
|
103
|
+
| ---------- | ---------------------- | ---- | ---------------- | ----------------------------------------------- |
|
|
104
|
+
| apiPayload | `Partial<IApiPayload>` | 否 | `{}` | SaaS BFF 认证信息,包含 JWT、环境、Token 管理等 |
|
|
105
|
+
| apiService | `Partial<IApiService>` | 否 | `saasApiService` | 自定义 API 服务,与默认实现浅合并 |
|
|
106
|
+
| locale | `Locale` | 否 | - | antd 国际化语言包 |
|
|
107
|
+
| theme | `ThemeConfig` | 否 | - | antd 主题配置 |
|
|
108
|
+
| className | `string` | 否 | - | 传递给 antd App 组件的 className |
|
|
109
|
+
| children | `React.ReactNode` | 是 | - | 子组件 |
|
|
110
|
+
|
|
111
|
+
## 导出类型
|
|
112
|
+
|
|
113
|
+
### IApiPayload
|
|
114
|
+
|
|
115
|
+
API 认证载荷,包含运行环境和 Token 管理方法:
|
|
116
|
+
|
|
117
|
+
```typescript
|
|
118
|
+
type IApiPayload = {
|
|
119
|
+
jwt: JWT // JWT 实例(来自 @xfe-repo/web-service)
|
|
120
|
+
apiEnv: ApiEnv // API 环境标识(来自 @xfe-repo/web-utils/env)
|
|
121
|
+
business: Business // 业务线标识(来自 @xfe-repo/web-utils/env)
|
|
122
|
+
getUserToken: () => string // 获取当前用户 Token
|
|
123
|
+
setUserToken: (token: string) => void // 设置用户 Token
|
|
124
|
+
removeUserToken: () => void // 移除用户 Token
|
|
125
|
+
}
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### IApiService
|
|
129
|
+
|
|
130
|
+
API 服务接口,定义了所有 Effect 组件内部调用的接口方法:
|
|
131
|
+
|
|
132
|
+
```typescript
|
|
133
|
+
interface IApiService {
|
|
134
|
+
categoryListToTree: Request<InQueryCategoryListToTree, OutListToTreeCategoryDto> // 分类树
|
|
135
|
+
brandComboBox: Request<InQueryBrandComboBox, OutComboBoxBrandDto> // 品牌下拉
|
|
136
|
+
seriesComboBox: Request<InQuerySeriesComboBox, OutComboBoxSeriesDto> // 系列下拉
|
|
137
|
+
seriesList: Request<InQuerySeriesList, OutListSeriesDto> // 系列列表
|
|
138
|
+
skuFindOne: Request<InPathSkuFindOne, OutFindOneSkuDto> // SKU 详情
|
|
139
|
+
skuListV2: Request<InQuerySkuListV2, OutListSkuV2Dto> // SKU 列表
|
|
140
|
+
spuList: Request<InQuerySpuList, OutListSpuDto> // SPU 列表
|
|
141
|
+
productImageSpuSkuList: Request<InQueryProductImageSpuSkuList, OutListProductImageSpuSkuDto> // 商品图片列表
|
|
142
|
+
uploadUploadFile: Request<InUploadFileDto, OutUploadFileDto> // 文件上传
|
|
143
|
+
uploadRemoteCreate: Request<InRemoteCreateDto, OutRemoteCreateDto> // 远程文件创建
|
|
144
|
+
commonAddressList: Request<InPathCommonAddressList, OutAddressListDto> // 地址列表
|
|
145
|
+
storeComboBox: Request<InPathStoreComboBox & InQueryStoreComboBox, OutComboBoxWarehouseStoreDto> // 仓库下拉
|
|
146
|
+
reservoirList: Request<InQueryReservoirList, OutListReservoirDto> // 库区列表
|
|
147
|
+
shelveList: Request<InQueryShelveList, OutShelveListV2Dto> // 货架列表
|
|
148
|
+
merchantList: Request<InMerchantListBusDto, OutMerchantListBusDto> // 商户列表
|
|
149
|
+
businessList: Request<InQueryBusinessList, OutListBusDto> // 业务线列表
|
|
150
|
+
}
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
### IConfigContext
|
|
154
|
+
|
|
155
|
+
Context 值类型:
|
|
156
|
+
|
|
157
|
+
```typescript
|
|
158
|
+
type IConfigContext = {
|
|
159
|
+
apiPayload: Partial<IApiPayload>
|
|
160
|
+
apiService: IApiService
|
|
161
|
+
}
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
### ConfigContext
|
|
165
|
+
|
|
166
|
+
```typescript
|
|
167
|
+
const ConfigContext: React.Context<IConfigContext | null>
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
## 常见陷阱
|
|
171
|
+
|
|
172
|
+
- ❌ 未在应用入口包裹 `ConfigProvider`,直接使用 Effect 组件:
|
|
173
|
+
```tsx
|
|
174
|
+
// 所有 Effect 组件会因为缺少 Context 而报错
|
|
175
|
+
<EffectBrandSelect />
|
|
176
|
+
```
|
|
177
|
+
- ✅ 在应用最外层包裹 `ConfigProvider`:
|
|
178
|
+
|
|
179
|
+
```tsx
|
|
180
|
+
<ConfigProvider apiPayload={payload}>
|
|
181
|
+
<EffectBrandSelect />
|
|
182
|
+
</ConfigProvider>
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
- ❌ 传入完整的 `apiService` 对象但遗漏了某些方法 —— 不会报错但运行时调用缺失方法会崩溃
|
|
186
|
+
- ✅ 只覆盖需要自定义的方法,其余自动使用默认的 `saasApiService`:
|
|
187
|
+
```tsx
|
|
188
|
+
<ConfigProvider apiService={{ brandComboBox: myBrandApi }}>
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
## 相关组件
|
|
192
|
+
|
|
193
|
+
| 场景 | 组件 | 说明 |
|
|
194
|
+
| -------- | ----------------------- | ------------------------------------------------------ |
|
|
195
|
+
| 品牌选择 | `EffectBrandSelect` | 依赖 ConfigProvider 提供 apiService.brandComboBox |
|
|
196
|
+
| 分类选择 | `EffectCategoryCascade` | 依赖 ConfigProvider 提供 apiService.categoryListToTree |
|
|
197
|
+
| 文件上传 | `EffectFileUpload` | 依赖 ConfigProvider 提供 apiService.uploadUploadFile |
|
|
198
|
+
| 商品范围 | `EffectScopeSelect` | 内部聚合多个 Effect 组件,间接依赖 ConfigProvider |
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# Countdown
|
|
2
|
+
|
|
3
|
+
> 倒计时组件,支持 `date`(天时分秒格式)和 `second`(纯秒数)两种展示模式。
|
|
4
|
+
|
|
5
|
+
## 导入
|
|
6
|
+
|
|
7
|
+
```tsx
|
|
8
|
+
import { Countdown, formatDate } from '@xfe-repo/web-components'
|
|
9
|
+
import type { CountdownProps } from '@xfe-repo/web-components'
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## 基本用法
|
|
13
|
+
|
|
14
|
+
### 秒数模式(默认)
|
|
15
|
+
|
|
16
|
+
```tsx
|
|
17
|
+
import { Countdown } from '@xfe-repo/web-components'
|
|
18
|
+
|
|
19
|
+
function Timer() {
|
|
20
|
+
return <Countdown init={60} /> {/* 显示: 60, 59, 58... */}
|
|
21
|
+
}
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
### 日期模式
|
|
25
|
+
|
|
26
|
+
```tsx
|
|
27
|
+
<Countdown init={3661} mode="date" /> {/* 显示: 0天01:01:01 */}
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## 进阶用法
|
|
31
|
+
|
|
32
|
+
### 自定义结束文案
|
|
33
|
+
|
|
34
|
+
```tsx
|
|
35
|
+
<Countdown
|
|
36
|
+
init={10}
|
|
37
|
+
mode="date"
|
|
38
|
+
onEnd={() => '已过期'} // 倒计时结束后显示"已过期"
|
|
39
|
+
/>
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### 监听每秒变化
|
|
43
|
+
|
|
44
|
+
```tsx
|
|
45
|
+
<Countdown
|
|
46
|
+
init={300}
|
|
47
|
+
mode="date"
|
|
48
|
+
onInterval={(remainSeconds) => {
|
|
49
|
+
if (remainSeconds <= 10) {
|
|
50
|
+
console.log('即将过期')
|
|
51
|
+
}
|
|
52
|
+
}}
|
|
53
|
+
/>
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### 自定义日期格式
|
|
57
|
+
|
|
58
|
+
```tsx
|
|
59
|
+
<Countdown
|
|
60
|
+
init={7200}
|
|
61
|
+
mode="date"
|
|
62
|
+
// 显示: 02小时00分00秒
|
|
63
|
+
formatStr="HH小时MM分SS秒"
|
|
64
|
+
/>
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Props
|
|
68
|
+
|
|
69
|
+
```typescript
|
|
70
|
+
export interface CountdownProps {
|
|
71
|
+
init: number | string
|
|
72
|
+
onEnd?: () => string | void
|
|
73
|
+
onInterval?: (s: number) => string | void
|
|
74
|
+
mode?: 'date' | 'second'
|
|
75
|
+
formatStr?: string
|
|
76
|
+
className?: string
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
| 属性 | 类型 | 必填 | 默认值 | 说明 |
|
|
81
|
+
| ---------- | ------------------------------- | ---- | ---------------- | ----------------------------------------------------- |
|
|
82
|
+
| init | `number \| string` | 是 | - | 初始倒计时秒数,或直接显示的字符串 |
|
|
83
|
+
| mode | `'date' \| 'second'` | 否 | - | 展示模式。`date` 格式化为天时分秒;不传则直接显示秒数 |
|
|
84
|
+
| formatStr | `string` | 否 | `'DD天HH:MM:SS'` | 日期模式的格式字符串,支持 DD/HH/MM/SS |
|
|
85
|
+
| onEnd | `() => string \| void` | 否 | - | 倒计时结束回调,返回字符串则替换显示内容 |
|
|
86
|
+
| onInterval | `(s: number) => string \| void` | 否 | - | 每秒触发,参数为剩余秒数 |
|
|
87
|
+
| className | `string` | 否 | - | 自定义 className |
|
|
88
|
+
|
|
89
|
+
## 导出类型
|
|
90
|
+
|
|
91
|
+
### formatDate
|
|
92
|
+
|
|
93
|
+
```typescript
|
|
94
|
+
export function formatDate(s: number, formatStr?: string): string
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
独立的秒数格式化函数,将秒数转换为 `DD天HH:MM:SS` 格式。
|
|
98
|
+
|
|
99
|
+
## 常见陷阱
|
|
100
|
+
|
|
101
|
+
- ❌ `init` 传入字符串类型时,倒计时不会启动,仅静态展示该字符串
|
|
102
|
+
- ✅ 需要倒计时功能必须传入 `number` 类型
|
|
103
|
+
|
|
104
|
+
## 相关组件
|
|
105
|
+
|
|
106
|
+
| 场景 | 组件 | 说明 |
|
|
107
|
+
| -------- | --------- | ----------------- |
|
|
108
|
+
| 正向计时 | `Counter` | 从 0 开始递增计数 |
|
|
109
|
+
| 实时时钟 | `Clock` | 展示当前时间 |
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# Counter
|
|
2
|
+
|
|
3
|
+
> 正向计数器组件,`loading` 为 true 时开始从初始值递增,停止时触发结束回调。
|
|
4
|
+
|
|
5
|
+
## 导入
|
|
6
|
+
|
|
7
|
+
```tsx
|
|
8
|
+
import { Counter } from '@xfe-repo/web-components'
|
|
9
|
+
import type { CounterProps } from '@xfe-repo/web-components'
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## 基本用法
|
|
13
|
+
|
|
14
|
+
```tsx
|
|
15
|
+
import { Counter } from '@xfe-repo/web-components'
|
|
16
|
+
import { useState } from 'react'
|
|
17
|
+
|
|
18
|
+
function Timer() {
|
|
19
|
+
const [running, setRunning] = useState(false)
|
|
20
|
+
|
|
21
|
+
return (
|
|
22
|
+
<div>
|
|
23
|
+
<Counter loading={running} />
|
|
24
|
+
<button onClick={() => setRunning(!running)}>{running ? '停止' : '开始'}</button>
|
|
25
|
+
</div>
|
|
26
|
+
)
|
|
27
|
+
}
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## 进阶用法
|
|
31
|
+
|
|
32
|
+
### 自定义递增步长
|
|
33
|
+
|
|
34
|
+
```tsx
|
|
35
|
+
<Counter loading={true} interval={5} /> {/* 每秒增加 5 */}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### 结束回调
|
|
39
|
+
|
|
40
|
+
```tsx
|
|
41
|
+
<Counter
|
|
42
|
+
loading={isProcessing}
|
|
43
|
+
onEnd={() => '已完成'} // loading 变为 false 时显示"已完成"
|
|
44
|
+
onInterval={(value) => console.log('当前计数:', value)}
|
|
45
|
+
/>
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Props
|
|
49
|
+
|
|
50
|
+
```typescript
|
|
51
|
+
export interface CounterProps {
|
|
52
|
+
loading: boolean
|
|
53
|
+
onEnd?: () => string | void
|
|
54
|
+
onInterval?: (s: number) => string | void
|
|
55
|
+
interval?: number
|
|
56
|
+
className?: string
|
|
57
|
+
init?: number | string
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
| 属性 | 类型 | 必填 | 默认值 | 说明 |
|
|
62
|
+
| ---------- | ------------------------------- | ---- | ------ | ------------------------------------ |
|
|
63
|
+
| loading | `boolean` | 是 | - | 是否正在计数 |
|
|
64
|
+
| init | `number \| string` | 否 | `0` | 初始值 |
|
|
65
|
+
| interval | `number` | 否 | `1` | 每秒递增的步长 |
|
|
66
|
+
| onEnd | `() => string \| void` | 否 | - | 停止时回调,返回字符串则替换显示内容 |
|
|
67
|
+
| onInterval | `(s: number) => string \| void` | 否 | - | 每秒触发,参数为当前计数值 |
|
|
68
|
+
| className | `string` | 否 | - | 自定义 className |
|
|
69
|
+
|
|
70
|
+
## 相关组件
|
|
71
|
+
|
|
72
|
+
| 场景 | 组件 | 说明 |
|
|
73
|
+
| -------- | ----------- | ------------------ |
|
|
74
|
+
| 倒计时 | `Countdown` | 从指定秒数递减到 0 |
|
|
75
|
+
| 实时时钟 | `Clock` | 展示当前时间 |
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
# Currency
|
|
2
|
+
|
|
3
|
+
> 金额展示组件,支持分/角/元单位自动换算,统一以"¥"前缀展示。
|
|
4
|
+
|
|
5
|
+
## 导入
|
|
6
|
+
|
|
7
|
+
```tsx
|
|
8
|
+
import { Currency } from '@xfe-repo/web-components'
|
|
9
|
+
import type { CurrencyProps, CurrencyUnit } from '@xfe-repo/web-components'
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## 基本用法
|
|
13
|
+
|
|
14
|
+
```tsx
|
|
15
|
+
import { Currency } from '@xfe-repo/web-components'
|
|
16
|
+
|
|
17
|
+
// 后端返回金额单位为"分"
|
|
18
|
+
function Price() {
|
|
19
|
+
return <Currency>{9990}</Currency> {/* 显示: ¥99.90 */}
|
|
20
|
+
}
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
> ⚠️ **`unit` 默认为 `'fen'`(分)**。如果后端返回的金额单位已经是"元",必须显式设置 `unit="yuan"`,否则金额将被放大 100 倍。
|
|
24
|
+
|
|
25
|
+
## 进阶用法
|
|
26
|
+
|
|
27
|
+
### 指定单位
|
|
28
|
+
|
|
29
|
+
```tsx
|
|
30
|
+
<Currency unit="yuan">{99.9}</Currency> {/* 显示: ¥99.90 */}
|
|
31
|
+
<Currency unit="jiao">{999}</Currency> {/* 显示: ¥99.90 */}
|
|
32
|
+
<Currency unit="fen">{9990}</Currency> {/* 显示: ¥99.90 */}
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### 自定义小数位
|
|
36
|
+
|
|
37
|
+
```tsx
|
|
38
|
+
<Currency toFixed={0}>{9990}</Currency> {/* 显示: ¥100 */}
|
|
39
|
+
<Currency toFixed={3}>{9990}</Currency> {/* 显示: ¥99.900 */}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### 空值和脱敏值处理
|
|
43
|
+
|
|
44
|
+
```tsx
|
|
45
|
+
<Currency>{undefined}</Currency> {/* 显示: -- */}
|
|
46
|
+
<Currency>{null}</Currency> {/* 显示: -- */}
|
|
47
|
+
<Currency>{'***'}</Currency> {/* 显示: ¥ *** */}
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### 在 Table 列渲染中使用
|
|
51
|
+
|
|
52
|
+
最常见场景(85%+ 使用率):
|
|
53
|
+
|
|
54
|
+
```tsx
|
|
55
|
+
const columns = [
|
|
56
|
+
{
|
|
57
|
+
title: '金额',
|
|
58
|
+
dataIndex: 'amount',
|
|
59
|
+
render: (amount: number) => <Currency>{amount}</Currency>,
|
|
60
|
+
align: 'center' as const,
|
|
61
|
+
},
|
|
62
|
+
]
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Props
|
|
66
|
+
|
|
67
|
+
```typescript
|
|
68
|
+
export type CurrencyUnit = 'yuan' | 'jiao' | 'fen'
|
|
69
|
+
|
|
70
|
+
export interface CurrencyProps {
|
|
71
|
+
unit?: CurrencyUnit
|
|
72
|
+
toFixed?: number
|
|
73
|
+
children?: number | string
|
|
74
|
+
className?: string
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
| 属性 | 类型 | 必填 | 默认值 | 说明 |
|
|
79
|
+
| --------- | --------------------------- | ---- | ------- | ------------------------------------- |
|
|
80
|
+
| unit | `'yuan' \| 'jiao' \| 'fen'` | 否 | `'fen'` | 金额单位,自动换算为元 |
|
|
81
|
+
| toFixed | `number` | 否 | `2` | 保留的小数位数 |
|
|
82
|
+
| children | `number \| string` | 否 | - | 金额值,为 null/undefined 时显示 `--` |
|
|
83
|
+
| className | `string` | 否 | - | 自定义 className |
|
|
84
|
+
|
|
85
|
+
## 常见陷阱
|
|
86
|
+
|
|
87
|
+
- ❌ 后端返回"元"但未指定 unit,金额放大 100 倍:
|
|
88
|
+
```tsx
|
|
89
|
+
// 后端返回 price = 99.9 (元)
|
|
90
|
+
<Currency>{price}</Currency> {/* 显示: ¥0.99 — 错误! */}
|
|
91
|
+
```
|
|
92
|
+
- ✅ 根据后端单位正确设置 unit:
|
|
93
|
+
|
|
94
|
+
```tsx
|
|
95
|
+
<Currency unit="yuan">{price}</Currency> {/* 显示: ¥99.90 — 正确 */}
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
- ⚠️ 空值防御:`children` 为 `null`/`undefined` 时显示为 `--`。如需区分"未填写"与"零元",应在外层判断:
|
|
99
|
+
```tsx
|
|
100
|
+
render: (amount) => (amount != null ? <Currency>{amount}</Currency> : '-')
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### 汇总金额
|
|
104
|
+
|
|
105
|
+
```tsx
|
|
106
|
+
const total = items.reduce((sum, item) => sum + (item.amount ?? 0), 0)
|
|
107
|
+
<Currency>{total}</Currency>
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## 导出类型
|
|
111
|
+
|
|
112
|
+
> 类型定义见上方 Props 部分的 `CurrencyUnit`。
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
# EffectAddressCascade
|
|
2
|
+
|
|
3
|
+
> 省市区三级地址级联选择器,基于 Ant Design Cascader 实现异步按需加载,数据通过 `apiService.commonAddressList` 自动获取。
|
|
4
|
+
|
|
5
|
+
## 导入
|
|
6
|
+
|
|
7
|
+
```tsx
|
|
8
|
+
import { EffectAddressCascade } from '@xfe-repo/web-components'
|
|
9
|
+
import type { SelectItem } from '@xfe-repo/web-components'
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## 基本用法
|
|
13
|
+
|
|
14
|
+
```tsx
|
|
15
|
+
import { EffectAddressCascade } from '@xfe-repo/web-components'
|
|
16
|
+
import type { SelectItem } from '@xfe-repo/web-components'
|
|
17
|
+
|
|
18
|
+
function MyForm() {
|
|
19
|
+
const handleChange = (selectedList?: SelectItem[]) => {
|
|
20
|
+
// selectedList: [{ value: '省ID', label: '省名', index: 0 }, { value: '市ID', label: '市名', index: 1 }, ...]
|
|
21
|
+
console.log('选中地址:', selectedList)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
return <EffectAddressCascade onChange={handleChange} />
|
|
25
|
+
}
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## 进阶用法
|
|
29
|
+
|
|
30
|
+
### 设置默认值
|
|
31
|
+
|
|
32
|
+
通过 `defaultValue` 传入省、市、区的 ID 数组来设置初始选中值:
|
|
33
|
+
|
|
34
|
+
```tsx
|
|
35
|
+
<EffectAddressCascade defaultValue={['110000', '110100', '110101']} onChange={(selectedList) => console.log(selectedList)} />
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### 禁用状态
|
|
39
|
+
|
|
40
|
+
```tsx
|
|
41
|
+
<EffectAddressCascade disabled defaultValue={['110000', '110100', '110101']} />
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Props
|
|
45
|
+
|
|
46
|
+
```typescript
|
|
47
|
+
type SelectItem = { value: string; label: string; index: number }
|
|
48
|
+
|
|
49
|
+
type Props = {
|
|
50
|
+
className?: string
|
|
51
|
+
onChange?: (value?: SelectItem[]) => void
|
|
52
|
+
defaultValue?: string[]
|
|
53
|
+
disabled?: boolean
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
| 属性 | 类型 | 必填 | 默认值 | 说明 |
|
|
58
|
+
| ------------ | -------------------------------- | ---- | ------ | ---------------------------------- |
|
|
59
|
+
| onChange | `(value?: SelectItem[]) => void` | 否 | - | 选中值变化回调,返回各级选中项数组 |
|
|
60
|
+
| defaultValue | `string[]` | 否 | - | 默认选中值,省/市/区 ID 组成的数组 |
|
|
61
|
+
| disabled | `boolean` | 否 | - | 禁用状态 |
|
|
62
|
+
| className | `string` | 否 | - | 自定义样式类名 |
|
|
63
|
+
|
|
64
|
+
## 导出类型
|
|
65
|
+
|
|
66
|
+
```typescript
|
|
67
|
+
// 选中项数据结构
|
|
68
|
+
export type SelectItem = {
|
|
69
|
+
value: string // 地区 ID
|
|
70
|
+
label: string // 地区名称
|
|
71
|
+
index: number // 在当前级别选项列表中的索引
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## API 数据源
|
|
76
|
+
|
|
77
|
+
- **内部接口**:`apiService.commonAddressList`
|
|
78
|
+
- **请求参数**:`{ pid: string }`(父级地区 ID,首次加载传空字符串获取省份列表)
|
|
79
|
+
- **加载方式**:异步按需加载(`loadData`),选中省后加载市,选中市后加载区
|
|
80
|
+
- **可覆盖**:通过 `<ConfigProvider apiService={{ commonAddressList: customFn }}>` 替换默认实现
|
|
81
|
+
|
|
82
|
+
## 常见陷阱
|
|
83
|
+
|
|
84
|
+
- ❌ 期望 `onChange` 返回字符串数组(如 `['省ID', '市ID', '区ID']`):
|
|
85
|
+
```tsx
|
|
86
|
+
// onChange 返回的是 SelectItem[] 对象数组,不是简单字符串数组
|
|
87
|
+
```
|
|
88
|
+
- ✅ 从 `SelectItem[]` 中提取所需字段:
|
|
89
|
+
|
|
90
|
+
```tsx
|
|
91
|
+
<EffectAddressCascade
|
|
92
|
+
onChange={(selectedList) => {
|
|
93
|
+
const ids = selectedList?.map((item) => item.value) // ['110000', '110100', '110101']
|
|
94
|
+
const names = selectedList?.map((item) => item.label) // ['北京', '北京市', '东城区']
|
|
95
|
+
}}
|
|
96
|
+
/>
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
- ❌ 将组件当作受控组件使用(无 `value` prop)
|
|
100
|
+
- ✅ 本组件仅支持 `defaultValue` 设置初始值,不支持受控模式
|
|
101
|
+
|
|
102
|
+
## 使用提示
|
|
103
|
+
|
|
104
|
+
> 💡 与 Form.Item 集成时可能需要 `valuePropName="defaultValue"` 解决非受控模式兼容问题。
|
|
105
|
+
|
|
106
|
+
## 相关组件
|
|
107
|
+
|
|
108
|
+
| 场景 | 组件 | 说明 |
|
|
109
|
+
| -------- | ---------------- | -------------------------------------------- |
|
|
110
|
+
| API 配置 | `ConfigProvider` | 提供 `apiService.commonAddressList` 接口实现 |
|