@deepstorm/cli 0.1.0 → 0.2.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 (25) hide show
  1. package/dist/config-schema.json +1 -1
  2. package/dist/registry.json +65 -5
  3. package/dist/skills/reef-gen-frontend/variants/react/steps.md +31 -0
  4. package/dist/skills/reef-gen-frontend/variants/vue/steps.md +34 -0
  5. package/dist/skills/reef-style-frontend/fragments/test/vitest-react/examples/testing.md +283 -0
  6. package/dist/skills/reef-style-frontend/fragments/test/vitest-react/quick-reference.md +152 -0
  7. package/dist/skills/reef-style-frontend/fragments/test/vitest-vue/examples/testing.md +457 -0
  8. package/dist/skills/reef-style-frontend/fragments/test/vitest-vue/quick-reference.md +186 -0
  9. package/dist/skills/reef-style-frontend/fragments/ui-lib/antd/examples/ui-components.md +257 -0
  10. package/dist/skills/reef-style-frontend/fragments/ui-lib/antd/quick-reference.md +166 -0
  11. package/dist/skills/reef-style-frontend/fragments/ui-lib/antd-vue/examples/ui-components.md +353 -0
  12. package/dist/skills/reef-style-frontend/fragments/ui-lib/antd-vue/quick-reference.md +267 -0
  13. package/dist/skills/reef-style-frontend/variants/react/examples/code-wrapping.md +124 -0
  14. package/dist/skills/reef-style-frontend/variants/react/examples/component-types-pipes.md +195 -0
  15. package/dist/skills/reef-style-frontend/variants/react/examples/entity-types.md +127 -0
  16. package/dist/skills/reef-style-frontend/variants/react/examples/forms-layer.md +251 -0
  17. package/dist/skills/reef-style-frontend/variants/react/examples/service-routing.md +226 -0
  18. package/dist/skills/reef-style-frontend/variants/react/quick-reference.md +118 -0
  19. package/dist/skills/reef-style-frontend/variants/vue/examples/code-wrapping.md +162 -0
  20. package/dist/skills/reef-style-frontend/variants/vue/examples/component-types-pipes.md +270 -0
  21. package/dist/skills/reef-style-frontend/variants/vue/examples/entity-types.md +145 -0
  22. package/dist/skills/reef-style-frontend/variants/vue/examples/forms-layer.md +231 -0
  23. package/dist/skills/reef-style-frontend/variants/vue/examples/service-routing.md +224 -0
  24. package/dist/skills/reef-style-frontend/variants/vue/quick-reference.md +145 -0
  25. package/package.json +3 -1
@@ -0,0 +1,124 @@
1
+ # React/JSX 代码折行规则
2
+
3
+ 遵循 90 列限制,以下是 React 专有的折行场景。
4
+
5
+ ## JSX 属性换行
6
+
7
+ 单个属性保持在行内;3 个及以上属性每个占一行:
8
+
9
+ ```tsx
10
+ // ✅ 单属性行内
11
+ <Button type="primary">提交</Button>
12
+
13
+ // ✅ 2 个属性行内
14
+ <Button type="primary" loading={submitting}>提交</Button>
15
+
16
+ // ✅ 3+ 属性换行排列
17
+ <Table
18
+ dataSource={users}
19
+ columns={columns}
20
+ rowKey="id"
21
+ loading={loading}
22
+ pagination={{ pageSize: 20 }}
23
+ onChange={handlePageChange}
24
+ />
25
+ ```
26
+
27
+ ## 自闭合标签
28
+
29
+ 无子元素时使用自闭合标签,属性换行规则同上:
30
+
31
+ ```tsx
32
+ // ✅ 无属性
33
+ <Divider />
34
+
35
+ // ✅ 多属性
36
+ <DatePicker
37
+ value={date}
38
+ onChange={setDate}
39
+ format="YYYY-MM-DD"
40
+ />
41
+ ```
42
+
43
+ ## 条件渲染换行
44
+
45
+ ```tsx
46
+ // ✅ 简单的三元表达式保持行内
47
+ return <div>{loading ? <Spin /> : <UserTable users={users} />}</div>
48
+
49
+ // ✅ 复杂条件使用 && 或三元换行
50
+ return (
51
+ <div>
52
+ {error && (
53
+ <Alert
54
+ type="error"
55
+ message={error.message}
56
+ closable
57
+ onClose={clearError}
58
+ />
59
+ )}
60
+ {!loading && !error && <UserTable users={users} />}
61
+ </div>
62
+ )
63
+ ```
64
+
65
+ ## Hook 声明
66
+
67
+ ```tsx
68
+ // ✅ Hook 声明连续排列,按逻辑分组
69
+ const [users, setUsers] = useState<User[]>([])
70
+ const [loading, setLoading] = useState(true)
71
+ const [search, setSearch] = useState('')
72
+
73
+ // useEffect 依赖较长时换行
74
+ useEffect(() => {
75
+ fetchUsers(search)
76
+ }, [search]) // 短依赖数组行内
77
+
78
+ // ✅ 长依赖数组换行
79
+ useEffect(() => {
80
+ fetchFilteredUsers({ search, role, status, page, size })
81
+ }, [
82
+ search,
83
+ role,
84
+ status,
85
+ page,
86
+ size,
87
+ ])
88
+ ```
89
+
90
+ ## 函数 Props 换行
91
+
92
+ ```tsx
93
+ // ✅ 短函数表达式行内
94
+ <Button onClick={() => setIsOpen(true)}>打开</Button>
95
+
96
+ // ✅ 多行函数体换行
97
+ <Modal
98
+ title="确认删除"
99
+ open={isOpen}
100
+ onOk={async () => {
101
+ await deleteUser(id)
102
+ message.success('删除成功')
103
+ setIsOpen(false)
104
+ onDeleted?.()
105
+ }}
106
+ onCancel={() => setIsOpen(false)}
107
+ >
108
+ <p>确定要删除该用户吗?</p>
109
+ </Modal>
110
+ ```
111
+
112
+ ## 类型定义换行
113
+
114
+ ```tsx
115
+ // ✅ Props 类型每个属性一行
116
+ interface UserFormProps {
117
+ user?: User
118
+ onSubmit: (values: CreateUserRequest) => Promise<void>
119
+ onCancel: () => void
120
+ }
121
+
122
+ // ✅ 联合类型换行
123
+ type UserStatus = 'active' | 'inactive' | 'locked' | 'pending'
124
+ ```
@@ -0,0 +1,195 @@
1
+ # React 组件模式示例
2
+
3
+ React 中 Pipe 的概念通过自定义 Hook、工具函数或组件组合实现。
4
+
5
+ ## 自定义 Hook 替代 Pipe(数据转换)
6
+
7
+ Angular Pipe 在 React 中用自定义 Hook 或纯函数替代:
8
+
9
+ ```tsx
10
+ // ✅ 方案1: 纯函数(无状态转换)
11
+ function formatDate(date: string | Date, format: 'short' | 'long' = 'short'): string {
12
+ const d = typeof date === 'string' ? new Date(date) : date
13
+ if (format === 'short') {
14
+ return d.toLocaleDateString('zh-CN')
15
+ }
16
+ return d.toLocaleDateString('zh-CN', {
17
+ year: 'numeric', month: 'long', day: 'numeric',
18
+ hour: '2-digit', minute: '2-digit',
19
+ })
20
+ }
21
+
22
+ function formatCurrency(amount: number, currency = 'CNY'): string {
23
+ return new Intl.NumberFormat('zh-CN', {
24
+ style: 'currency',
25
+ currency,
26
+ }).format(amount)
27
+ }
28
+
29
+ // 使用
30
+ const UserList: React.FC = () => {
31
+ const { users } = useUsers()
32
+ return (
33
+ <Table
34
+ dataSource={users}
35
+ columns={[
36
+ { title: '创建时间', dataIndex: 'createdAt', render: (v: string) => formatDate(v, 'short') },
37
+ { title: '金额', dataIndex: 'amount', render: (v: number) => formatCurrency(v) },
38
+ ]}
39
+ />
40
+ )
41
+ }
42
+
43
+ // ✅ 方案2: 自定义 Hook(有状态转换 — 如搜索/过滤)
44
+ function useUserFilter(users: User[], search: string): User[] {
45
+ return useMemo(() => {
46
+ if (!search.trim()) return users
47
+ const q = search.toLowerCase()
48
+ return users.filter(
49
+ u => u.username.toLowerCase().includes(q) || u.email.toLowerCase().includes(q)
50
+ )
51
+ }, [users, search])
52
+ }
53
+ ```
54
+
55
+ ## 高阶组件(HOC)— 权限控制
56
+
57
+ ```tsx
58
+ // hoc/withAuth.tsx
59
+ interface WithAuthProps {
60
+ requiredRole?: UserRole
61
+ }
62
+
63
+ export function withAuth<P extends object>(
64
+ Component: React.ComponentType<P>,
65
+ options?: WithAuthProps
66
+ ) {
67
+ const AuthenticatedComponent: React.FC<P> = (props) => {
68
+ const { user, loading } = useAuth()
69
+
70
+ if (loading) return <Spin />
71
+ if (!user) return <Navigate to="/login" replace />
72
+
73
+ if (options?.requiredRole && user.role !== options.requiredRole) {
74
+ return <Result status="403" title="无权限访问" />
75
+ }
76
+
77
+ return <Component {...props} />
78
+ }
79
+
80
+ AuthenticatedComponent.displayName = `withAuth(${Component.displayName || Component.name})`
81
+ return AuthenticatedComponent
82
+ }
83
+
84
+ // 使用
85
+ const AdminDashboard = withAuth(Dashboard, { requiredRole: UserRole.Admin })
86
+ ```
87
+
88
+ ## 组件组合模式
89
+
90
+ ```tsx
91
+ // ✅ 复合组件模式(Compound Component)
92
+ interface CardComposition {
93
+ Header: React.FC<{ title: string }>
94
+ Body: React.FC<{ children: React.ReactNode }>
95
+ Footer: React.FC<{ children: React.ReactNode }>
96
+ }
97
+
98
+ const Card: React.FC<{ children: React.ReactNode }> & CardComposition = ({ children }) => (
99
+ <Card className="rounded-lg border shadow-sm">{children}</Card>
100
+ )
101
+
102
+ Card.Header = ({ title }) => (
103
+ <div className="border-b px-4 py-3 font-medium">{title}</div>
104
+ )
105
+ Card.Body = ({ children }) => (
106
+ <div className="px-4 py-3">{children}</div>
107
+ )
108
+ Card.Footer = ({ children }) => (
109
+ <div className="border-t px-4 py-3 flex justify-end gap-2">{children}</div>
110
+ )
111
+
112
+ // 使用
113
+ <Card>
114
+ <Card.Header title="用户信息" />
115
+ <Card.Body>
116
+ <p>用户名: {user.username}</p>
117
+ <p>邮箱: {user.email}</p>
118
+ </Card.Body>
119
+ <Card.Footer>
120
+ <Button onClick={onCancel}>取消</Button>
121
+ <Button type="primary" onClick={onSave}>保存</Button>
122
+ </Card.Footer>
123
+ </Card>
124
+ ```
125
+
126
+ ## Render Props 模式
127
+
128
+ ```tsx
129
+ // 数据获取 Render Props(复用数据加载逻辑)
130
+ interface DataLoaderProps<T> {
131
+ fetchFn: () => Promise<T>
132
+ children: (result: { data: T | null; loading: boolean; error: Error | null }) => React.ReactNode
133
+ }
134
+
135
+ function DataLoader<T>({ fetchFn, children }: DataLoaderProps<T>) {
136
+ const [data, setData] = useState<T | null>(null)
137
+ const [loading, setLoading] = useState(true)
138
+ const [error, setError] = useState<Error | null>(null)
139
+
140
+ useEffect(() => {
141
+ fetchFn()
142
+ .then(setData)
143
+ .catch(setError)
144
+ .finally(() => setLoading(false))
145
+ }, [])
146
+
147
+ return <>{children({ data, loading, error })}</>
148
+ }
149
+
150
+ // 使用
151
+ <DataLoader fetchFn={() => userService.getById(id)}>
152
+ {({ data: user, loading, error }) => {
153
+ if (loading) return <Skeleton active />
154
+ if (error) return <Alert type="error" message={error.message} />
155
+ return <UserForm user={user} />
156
+ }}
157
+ </DataLoader>
158
+ ```
159
+
160
+ ## Discriminated Union 组件模式
161
+
162
+ ```tsx
163
+ // 多形态组件 - 根据 type 渲染不同 UI
164
+ type NotificationCardProps =
165
+ | { type: 'success'; message: string }
166
+ | { type: 'error'; message: string; errorCode?: string }
167
+ | { type: 'confirm'; message: string; onConfirm: () => void; onCancel: () => void }
168
+
169
+ const NotificationCard: React.FC<NotificationCardProps> = (props) => {
170
+ switch (props.type) {
171
+ case 'success':
172
+ return <Alert type="success" message={props.message} showIcon />
173
+ case 'error':
174
+ return (
175
+ <Alert
176
+ type="error"
177
+ message={props.message}
178
+ description={props.errorCode ? `错误码: ${props.errorCode}` : undefined}
179
+ showIcon
180
+ />
181
+ )
182
+ case 'confirm':
183
+ return (
184
+ <Modal
185
+ open
186
+ title="确认"
187
+ onOk={props.onConfirm}
188
+ onCancel={props.onCancel}
189
+ >
190
+ <p>{props.message}</p>
191
+ </Modal>
192
+ )
193
+ }
194
+ }
195
+ ```
@@ -0,0 +1,127 @@
1
+ # React 实体类型定义示例
2
+
3
+ ## 基础实体层次
4
+
5
+ ```tsx
6
+ // shared/types/entity.ts
7
+ export interface ImmutableEntity {
8
+ readonly id: string
9
+ readonly createdAt: string
10
+ readonly updatedAt: string
11
+ }
12
+
13
+ export interface Entity extends ImmutableEntity {
14
+ version: number
15
+ }
16
+
17
+ export interface Auditable<T> extends Entity {
18
+ createdBy: T
19
+ updatedBy: T
20
+ }
21
+
22
+ export interface ImmutableAuditable<T> extends ImmutableEntity {
23
+ createdBy: T
24
+ }
25
+ ```
26
+
27
+ ## API 响应类型
28
+
29
+ ```tsx
30
+ // shared/types/api.ts
31
+ export interface PageResponse<T> {
32
+ content: T[]
33
+ totalElements: number
34
+ totalPages: number
35
+ number: number
36
+ size: number
37
+ first: boolean
38
+ last: boolean
39
+ }
40
+
41
+ export interface ApiError {
42
+ code: string
43
+ message: string
44
+ details?: Record<string, string[]>
45
+ }
46
+ ```
47
+
48
+ ## 业务实体示例
49
+
50
+ ```tsx
51
+ // shared/types/user.ts
52
+ export interface User extends Auditable<string> {
53
+ username: string
54
+ email: string
55
+ displayName: string
56
+ avatar?: string
57
+ role: UserRole
58
+ active: boolean
59
+ }
60
+
61
+ export enum UserRole {
62
+ Admin = 'ADMIN',
63
+ Editor = 'EDITOR',
64
+ Viewer = 'VIEWER',
65
+ }
66
+
67
+ export interface CreateUserRequest {
68
+ username: string
69
+ email: string
70
+ displayName: string
71
+ role: UserRole
72
+ }
73
+
74
+ export interface UpdateUserRequest {
75
+ email?: string
76
+ displayName?: string
77
+ role?: UserRole
78
+ }
79
+ ```
80
+
81
+ ## 组件 Props 类型
82
+
83
+ ```tsx
84
+ // 通用组件:具名导出 + interface Props
85
+ export interface UserAvatarProps {
86
+ user: Pick<User, 'username' | 'avatar'>
87
+ size?: 'sm' | 'md' | 'lg'
88
+ onClick?: () => void
89
+ }
90
+
91
+ export const UserAvatar: React.FC<UserAvatarProps> = ({ user, size = 'md', onClick }) => {
92
+ return (
93
+ <Avatar
94
+ src={user.avatar}
95
+ alt={user.username}
96
+ size={size === 'sm' ? 24 : size === 'md' ? 32 : 48}
97
+ onClick={onClick}
98
+ style={{ cursor: onClick ? 'pointer' : 'default' }}
99
+ />
100
+ )
101
+ }
102
+
103
+ // 页面组件:默认导出 + Props 从路由参数推断
104
+ export interface UserListPageProps {
105
+ // 可由 React Router loader 数据注入
106
+ }
107
+
108
+ const UserListPage: React.FC<UserListPageProps> = () => {
109
+ const { users, loading } = useUsers()
110
+ return <UserTable users={users} loading={loading} />
111
+ }
112
+ export default UserListPage
113
+ ```
114
+
115
+ ## Discriminated Union 类型
116
+
117
+ ```tsx
118
+ // 用于多状态组件
119
+ export type NotificationType = 'success' | 'error' | 'warning' | 'info'
120
+
121
+ export interface NotificationConfig {
122
+ type: NotificationType
123
+ title: string
124
+ message: string
125
+ duration?: number
126
+ }
127
+ ```
@@ -0,0 +1,251 @@
1
+ # React 表单模式(Ant Design Form)
2
+
3
+ ## 基础表单
4
+
5
+ ```tsx
6
+ interface CreateUserFormValues {
7
+ username: string
8
+ email: string
9
+ displayName: string
10
+ role: UserRole
11
+ }
12
+
13
+ const CreateUserForm: React.FC = () => {
14
+ const [form] = Form.useForm<CreateUserFormValues>()
15
+ const [loading, setLoading] = useState(false)
16
+
17
+ const handleSubmit = async (values: CreateUserFormValues) => {
18
+ setLoading(true)
19
+ try {
20
+ await createUser(values)
21
+ message.success('用户创建成功')
22
+ form.resetFields()
23
+ } catch (err) {
24
+ // Ant Design Form 会自动捕获校验错误
25
+ message.error('创建失败,请重试')
26
+ } finally {
27
+ setLoading(false)
28
+ }
29
+ }
30
+
31
+ return (
32
+ <Form
33
+ form={form}
34
+ layout="vertical"
35
+ onFinish={handleSubmit}
36
+ autoComplete="off"
37
+ >
38
+ <Form.Item
39
+ name="username"
40
+ label="用户名"
41
+ rules={[
42
+ { required: true, message: '请输入用户名' },
43
+ { min: 3, max: 32, message: '用户名长度 3-32 个字符' },
44
+ ]}
45
+ >
46
+ <Input placeholder="请输入用户名" />
47
+ </Form.Item>
48
+
49
+ <Form.Item
50
+ name="email"
51
+ label="邮箱"
52
+ rules={[
53
+ { required: true, message: '请输入邮箱' },
54
+ { type: 'email', message: '请输入有效的邮箱地址' },
55
+ ]}
56
+ >
57
+ <Input placeholder="请输入邮箱" />
58
+ </Form.Item>
59
+
60
+ <Form.Item
61
+ name="displayName"
62
+ label="显示名称"
63
+ rules={[{ required: true, message: '请输入显示名称' }]}
64
+ >
65
+ <Input placeholder="请输入显示名称" />
66
+ </Form.Item>
67
+
68
+ <Form.Item
69
+ name="role"
70
+ label="角色"
71
+ rules={[{ required: true, message: '请选择角色' }]}
72
+ >
73
+ <Select placeholder="请选择角色">
74
+ <Select.Option value="ADMIN">管理员</Select.Option>
75
+ <Select.Option value="EDITOR">编辑</Select.Option>
76
+ <Select.Option value="VIEWER">查看者</Select.Option>
77
+ </Select>
78
+ </Form.Item>
79
+
80
+ <Form.Item>
81
+ <Button type="primary" htmlType="submit" loading={loading}>
82
+ 创建
83
+ </Button>
84
+ </Form.Item>
85
+ </Form>
86
+ )
87
+ }
88
+ ```
89
+
90
+ ## 编辑表单(初始值)
91
+
92
+ ```tsx
93
+ interface EditUserFormProps {
94
+ user: User
95
+ onSuccess: () => void
96
+ }
97
+
98
+ const EditUserForm: React.FC<EditUserFormProps> = ({ user, onSuccess }) => {
99
+ const [form] = Form.useForm()
100
+ const [loading, setLoading] = useState(false)
101
+
102
+ // 初始值填充
103
+ useEffect(() => {
104
+ form.setFieldsValue({
105
+ displayName: user.displayName,
106
+ email: user.email,
107
+ role: user.role,
108
+ })
109
+ }, [user, form])
110
+
111
+ const handleSubmit = async (values: Partial<CreateUserRequest>) => {
112
+ setLoading(true)
113
+ try {
114
+ await updateUser(user.id, values)
115
+ message.success('用户信息已更新')
116
+ onSuccess()
117
+ } catch {
118
+ message.error('更新失败')
119
+ } finally {
120
+ setLoading(false)
121
+ }
122
+ }
123
+
124
+ return (
125
+ <Form
126
+ form={form}
127
+ layout="vertical"
128
+ onFinish={handleSubmit}
129
+ >
130
+ {/* 用户名只读展示 */}
131
+ <Form.Item label="用户名">
132
+ <Input value={user.username} disabled />
133
+ </Form.Item>
134
+
135
+ <Form.Item
136
+ name="email"
137
+ label="邮箱"
138
+ rules={[{ type: 'email' }]}
139
+ >
140
+ <Input />
141
+ </Form.Item>
142
+
143
+ <Form.Item
144
+ name="displayName"
145
+ label="显示名称"
146
+ >
147
+ <Input />
148
+ </Form.Item>
149
+
150
+ <Form.Item
151
+ name="role"
152
+ label="角色"
153
+ >
154
+ <Select>
155
+ <Select.Option value="ADMIN">管理员</Select.Option>
156
+ <Select.Option value="EDITOR">编辑</Select.Option>
157
+ <Select.Option value="VIEWER">查看者</Select.Option>
158
+ </Select>
159
+ </Form.Item>
160
+
161
+ <Form.Item>
162
+ <Button type="primary" htmlType="submit" loading={loading}>
163
+ 保存
164
+ </Button>
165
+ </Form.Item>
166
+ </Form>
167
+ )
168
+ }
169
+ ```
170
+
171
+ ## 搜索表单(非受控 + 联动 Table)
172
+
173
+ ```tsx
174
+ const UserListPage: React.FC = () => {
175
+ const [searchForm] = Form.useForm()
176
+ const [query, setQuery] = useState<Record<string, string>>({})
177
+
178
+ const handleSearch = (values: Record<string, string>) => {
179
+ // 过滤空值
180
+ const filtered = Object.fromEntries(
181
+ Object.entries(values).filter(([, v]) => v !== undefined && v !== '')
182
+ )
183
+ setQuery(filtered)
184
+ }
185
+
186
+ const handleReset = () => {
187
+ searchForm.resetFields()
188
+ setQuery({})
189
+ }
190
+
191
+ return (
192
+ <div>
193
+ <Form
194
+ form={searchForm}
195
+ layout="inline"
196
+ onFinish={handleSearch}
197
+ >
198
+ <Form.Item name="keyword">
199
+ <Input.Search placeholder="搜索用户名/邮箱" onSearch={() => searchForm.submit()} />
200
+ </Form.Item>
201
+ <Form.Item name="role">
202
+ <Select placeholder="角色" allowClear style={{ width: 120 }}>
203
+ <Select.Option value="ADMIN">管理员</Select.Option>
204
+ <Select.Option value="EDITOR">编辑</Select.Option>
205
+ </Select>
206
+ </Form.Item>
207
+ <Form.Item name="status">
208
+ <Select placeholder="状态" allowClear style={{ width: 120 }}>
209
+ <Select.Option value="active">活跃</Select.Option>
210
+ <Select.Option value="inactive">停用</Select.Option>
211
+ </Select>
212
+ </Form.Item>
213
+ <Form.Item>
214
+ <Button type="primary" htmlType="submit">查询</Button>
215
+ <Button onClick={handleReset} style={{ marginLeft: 8 }}>重置</Button>
216
+ </Form.Item>
217
+ </Form>
218
+
219
+ <UserTable query={query} />
220
+ </div>
221
+ )
222
+ }
223
+ ```
224
+
225
+ ## 全局校验信息配置
226
+
227
+ ```tsx
228
+ // 在应用入口统一配置校验信息
229
+ import { ConfigProvider } from 'antd'
230
+
231
+ const App: React.FC = () => (
232
+ <ConfigProvider
233
+ form={{
234
+ validateMessages: {
235
+ required: "'${label}' 是必填项",
236
+ types: {
237
+ email: "'${label}' 不是有效的邮箱地址",
238
+ number: "'${label}' 不是有效的数字",
239
+ },
240
+ string: {
241
+ min: "'${label}' 最少 ${min} 个字符",
242
+ max: "'${label}' 最多 ${max} 个字符",
243
+ range: "'${label}' 长度在 ${min} 到 ${max} 之间",
244
+ },
245
+ },
246
+ }}
247
+ >
248
+ {/* Router 和页面内容 */}
249
+ </ConfigProvider>
250
+ )
251
+ ```