@zy-frontend/form-core 2.0.6

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/README.md ADDED
@@ -0,0 +1,422 @@
1
+ # 配置化表单
2
+
3
+ ## 特点
4
+
5
+ - 👍简洁的配置规则
6
+ - 📦与UI库解耦,兼容多端,可自定义样式
7
+ - ⚙️支持主动/被动联动,可实现复杂的字段/表单间的联动关系
8
+ - ⚔️支持单表单、多表单两种模式
9
+ - 🛡️支持分级字段校验
10
+ - ☁️支持远程加载选项列表
11
+
12
+ ## 使用
13
+
14
+ ### 安装
15
+
16
+ ```sh
17
+ npm i -S @zy/form-core
18
+ ```
19
+
20
+ ### 使用示例
21
+
22
+ 单表单场景:
23
+ ```html
24
+ <script setup lang="ts">
25
+ import { ZYForm } from '@zy/form-core'
26
+ import formConfig from './form-config.json'
27
+ import { ElForm, ElFormItem, ElInput } from 'element-plus'
28
+
29
+ // 表单数据
30
+ const formData = ref({})
31
+ // 表单字段组件
32
+ const components = {
33
+ form: ElForm,
34
+ formItem: ElFormItem,
35
+ input: ElInput,
36
+ }
37
+ // 请求方法
38
+ const requestFn: RequestFunction = async (
39
+ keyPath,
40
+ value,
41
+ url,
42
+ extraParams,
43
+ componentParams = {},
44
+ ) => {
45
+ const res: Option[] = await getSelectOptions(url, extraParams, componentParams.query)
46
+ return res
47
+ }
48
+ </script>
49
+
50
+ <template>
51
+ <ZYForm
52
+ ref="formRef"
53
+ v-model="formData"
54
+ :config="formConfig"
55
+ :components="components"
56
+ :requestFn="requestFn"
57
+ />
58
+ </template>
59
+ ```
60
+
61
+ 多表单场景:
62
+ ```html
63
+ <script setup lang="ts">
64
+ import { ZYFormGroup } from '@zy/form-core'
65
+ import formConfig from './form-config.json'
66
+ import { ElForm, ElFormItem, ElInput } from 'element-plus'
67
+
68
+ // 表单数据
69
+ const formData = ref({})
70
+ // 表单字段组件
71
+ const components = {
72
+ form: ElForm,
73
+ formItem: ElFormItem,
74
+ input: ElInput,
75
+ }
76
+ // 请求方法
77
+ const requestFn: RequestFunction = async (
78
+ keyPath,
79
+ value,
80
+ url,
81
+ extraParams,
82
+ componentParams = {},
83
+ ) => {
84
+ const res: Option[] = await getSelectOptions(url, extraParams, componentParams.query)
85
+ return res
86
+ }
87
+ </script>
88
+
89
+ <template>
90
+ <ZYFormGroup
91
+ ref="formRef"
92
+ v-model="formData"
93
+ :config="formConfig"
94
+ :components="components"
95
+ :requestFn="requestFn"
96
+ />
97
+ </template>
98
+ ```
99
+
100
+ ### API
101
+
102
+ #### Form Attributes
103
+
104
+ | 属性名 | 说明 | 类型 | 是否必填 | 默认值 |
105
+ | ----------------- | --------------------------------------------------------------------------- | --------------- | -------- | ------ |
106
+ | v-model | 表单数据 | object | 是 | |
107
+ | config | 表单配置 | Form[] | 是 | |
108
+ | formKey | 表单唯一key | string | 是 | |
109
+ | components | 表单字段组件集合 | UIComponents | 是 | |
110
+ | requestFn | 请求方法,使用场景包括远程选项获取、文件上传等 | RequestFunction | 否 | |
111
+ | scenario | 场景:用带指定前缀的属性覆盖原属性,如scenario为pc时,会用pc-props覆盖props | string | 否 | |
112
+ | requiredFieldOnly | 是否只显示必填字段 | boolean | 否 | false |
113
+ | disabled | 禁用 | boolean | 否 | false |
114
+ | readonly | 只读 | boolean | 否 | false |
115
+
116
+ #### Form Methods
117
+
118
+ | 方法名 | 说明 | 类型 |
119
+ | -------------- | ---------------------- | ---------------------------------------------- |
120
+ | initFormData | 更新表单数据 | (newData?: Record<string, any>) => void |
121
+ | resetFormValue | 重置表单数据 | () => void |
122
+ | validate | 表单校验,支持分级校验 | (maxLevel: number = Infinity, fields: string[] = []) => Promise<void> |
123
+ | clearValidate | 清空表单校验 | () => void |
124
+ | getFormData | 获取表单数据 | () => Record<string, any> |
125
+
126
+ #### Form Events
127
+
128
+ | 事件名 | 说明 | 回调参数 |
129
+ | ---------- | -------------------------- | ---------------------------------------------------- |
130
+ | change | 当表单字段值发生改变时触发 | (keyPath: string, fieldValue: any) |
131
+ | blur | 当表单字段失去焦点时触发 | (e: FocusEvent, keyPath: string, fieldValue: any) |
132
+ | keyupEnter | 当enter键按下时触发 | (e: KeyboardEvent, keyPath: string, fieldValue: any) |
133
+ | mounted | 表单加载后触发 | |
134
+
135
+ #### FormGroup Attributes
136
+
137
+ | 属性名 | 说明 | 类型 | 是否必填 | 默认值 |
138
+ | ----------------- | --------------------------------------------------------------------------- | --------------- | -------- | ------ |
139
+ | v-model | 表单数据 | object | 是 | |
140
+ | config | 表单配置 | Form[] | 是 | |
141
+ | components | 表单字段组件集合 | UIComponents | 是 | |
142
+ | requestFn | 请求方法,使用场景包括远程选项获取、文件上传等 | RequestFunction | 否 | |
143
+ | scenario | 场景:用带指定前缀的属性覆盖原属性,如scenario为pc时,会用pc-props覆盖props | string | 否 | |
144
+ | requiredFieldOnly | 是否只显示必填字段 | boolean | 否 | false |
145
+ | disabled | 禁用 | boolean | 否 | false |
146
+ | readonly | 只读 | boolean | 否 | false |
147
+ | defaultTabKey | 默认激活的tab的key | string | 否 | |
148
+
149
+ #### FormGroup Methods
150
+
151
+ | 方法名 | 说明 | 类型 |
152
+ | -------------- | ---------------------- | ---------------------------------------------- |
153
+ | initFormData | 更新表单数据 | (newData?: Record<string, any>) => void |
154
+ | resetFormValue | 重置表单数据 | (formKey?: string | string[]) => void |
155
+ | validate | 表单校验,支持分级校验 | (formKey?: string | string[], maxLevel?: number) => Promise<void> |
156
+ | clearValidate | 清空表单校验 | (formKey?: string | string[]) => void |
157
+ | getFormData | 获取表单数据 | () => Record<string, any> |
158
+
159
+ #### FormGroup Events
160
+
161
+ | 事件名 | 说明 | 回调参数 |
162
+ | ---------- | -------------------------- | ---------------------------------------------------- |
163
+ | change | 当表单字段值发生改变时触发 | (keyPath: string, fieldValue: any) |
164
+ | tabChange | 切换tab时触发 | (...args: any) 传递Tab组件emit的所有参数 |
165
+ | blur | 当表单字段失去焦点时触发 | (e: FocusEvent, keyPath: string, fieldValue: any) |
166
+ | keyupEnter | 当enter键按下时触发 | (e: KeyboardEvent, keyPath: string, fieldValue: any) |
167
+ | mounted | 表单加载后触发 | |
168
+
169
+ ### 表单配置
170
+
171
+ #### 类型声明
172
+
173
+ ```typescript
174
+ export interface Form {
175
+ key: string // 表单唯一键
176
+ title?: string // 表单标题,多表单模式下必填
177
+ props?: FormProps // 表单组件props
178
+ show?: boolean // 显示/隐藏
179
+ gutter?: FormGutter // 表单项间距
180
+ fields: Field[] // 表单项数组
181
+ preScript?: string | PreScriptFunction // 表单数据前置处理脚本
182
+ postScript?: string | PostScriptFunction // 表单数据后置处理脚本
183
+ [key: string]: any
184
+ }
185
+
186
+ export type PreScriptFunction = (
187
+ formData: Ref<Record<string, any>>, // 当前表单数据
188
+ formConfig: UnwrapNestedRefs<Form>, // 当前表单配置
189
+ ) => void
190
+ export type PostScriptFunction = (
191
+ formData: Ref<Record<string, any>>, // 当前表单数据
192
+ formConfig: UnwrapNestedRefs<Form>, // 当前表单配置
193
+ ) => Record<string, any>
194
+
195
+ export type FormGutter = {
196
+ horizontal?: number | string // 表单项横向间距(默认单位px)
197
+ vertical?: number | string // 表单项纵向间距(默认单位px)
198
+ [key: string]: any
199
+ }
200
+
201
+ export interface FormProps {
202
+ labelPosition?: FormLabelPosition // 表单项标签位置
203
+ labelWidth?: string | number // 表单项标签宽度
204
+ hideRequiredAsterisk?: boolean // 是否隐藏必填星号
205
+ disabled?: boolean // 表单禁用
206
+ [key: string]: any
207
+ }
208
+ export type FormLabelPosition = 'left' | 'right' | 'top'
209
+
210
+ export interface Field {
211
+ key: string // 字段键,在当前表单中需唯一
212
+ formKey?: string // 所属表单键,自动赋值,无需填写
213
+ span?: number // 表单项占据的栅格列数,最小1,最大24(默认24)
214
+ label?: Label | string // 标签
215
+ description?: string // 字段描述
216
+ props?: Record<string, any> // 表单项组件props
217
+ type: FieldType // 字段类型
218
+ defaultValue?: any // 默认值
219
+ show?: boolean // 显示/隐藏
220
+ disabled?: boolean | IsFieldDisabled | string // 禁用/启用,支持传入动态计算方法
221
+ rules?: Rule[] // 校验逻辑集合
222
+ component?: Component // 组件
223
+ actions?: Array<Action | ActionHandler | string> // 主动联动配置
224
+ subscribers?: Subscriber[] // 被动联动配置
225
+ datetimeFormatPattern?: string // 日期格式,仅当表单为只读且字段type为datetime时生效
226
+ className?: string // 自定义类名
227
+ advancedConfig?: AdvancedConfig // 高级配置项
228
+ [key: string]: any
229
+ }
230
+
231
+ export interface Label {
232
+ text?: string // 标签文本
233
+ width?: string // 标签宽度,会覆盖表单的labelWidth
234
+ [key: string]: any
235
+ }
236
+
237
+ // 校验逻辑,继承自async-validator的RuleItem类型
238
+ export interface Rule extends Omit<RuleItem, 'validator'> {
239
+ level?: number // 规则级别,数值越小优先级越高,默认0
240
+ validator?: string | ValidatorFunction | Validator // 表单验证函数/对象
241
+ trigger?: string | string[] // 触发方式
242
+ }
243
+ export type ValidatorFunction = (
244
+ rule: any,
245
+ value: any,
246
+ callback: any,
247
+ formData: UnwrapNestedRefs<Record<string, any>>, // 当前表单数据
248
+ formConfig: UnwrapNestedRefs<Form>, // 当前表单配置
249
+ validatorParams: { rule: any; value: any; callback: any },
250
+ formGroupData: UnwrapNestedRefs<Record<string, any>>,
251
+ depValues?: any[], // 依赖项值的集合,作为Validator的校验函数时有值
252
+ ) => void
253
+ export interface Validator {
254
+ name?: string // 名称
255
+ deps: string[] // 依赖项,格式为formKey.fieldKey
256
+ handler: string | ValidatorFunction // 校验函数
257
+ }
258
+
259
+ export interface Component {
260
+ type: ComponentType // 组件类型
261
+ props?: Record<string, any> // 组件props
262
+ options?: Option[] // 组件选项集合
263
+ remote?: ComponentRemote | boolean // 远程请求配置
264
+ [key: string]: any
265
+ }
266
+ export interface ComponentRemote {
267
+ url?: string // 远程请求URL,执行requestFn时会作为参数传入
268
+ extraParams?: Record<string, string | number | boolean> // 远程请求参数,执行requestFn时会作为参数传入
269
+ [key: string]: any
270
+ }
271
+
272
+ export type Option = {
273
+ value: string | number | boolean | Record<string, any>
274
+ label: string
275
+ disabled?: boolean
276
+ [key: string]: any
277
+ }
278
+ export type LabelPosition = 'top' | 'right' | 'left'
279
+ export type FieldType =
280
+ | 'boolean'
281
+ | 'string'
282
+ | 'number'
283
+ | 'array'
284
+ | 'object'
285
+ | 'datetime'
286
+ | 'images'
287
+ | 'null'
288
+ | 'container'
289
+ | 'invisible'
290
+ export type IsFieldDisabled = (fieldValue: any, formData: any, fieldConfig: Field) => boolean
291
+ // 组件类型
292
+ export enum ComponentTypeEnum {
293
+ Input = 'input',
294
+ InputNumber = 'inputNumber',
295
+ Select = 'select',
296
+ MultiSelect = 'multiSelect',
297
+ Cascader = 'cascader',
298
+ Radio = 'radio',
299
+ Checkbox = 'checkbox',
300
+ Switch = 'switch',
301
+ DatePicker = 'datePicker',
302
+ DateTimePicker = 'dateTimePicker',
303
+ Upload = 'upload',
304
+ DynamicTable = 'dynamicTable',
305
+ DynamicForm = 'dynamicForm',
306
+ DynamicTabs = 'dynamicTabs',
307
+ Title = 'title',
308
+ Collapse = 'collapse',
309
+ ImageList = 'imageList',
310
+ }
311
+ export type ComponentType = ComponentTypeEnum | string
312
+
313
+ // 被动联动配置
314
+ export interface Subscriber {
315
+ name?: string // 名称
316
+ immediate?: boolean // 是否在数据初始化后立即触发
317
+ deps: string[] // 依赖项,格式为formKey.fieldKey
318
+ handler: SubscriberHandler | string // 联动函数
319
+ }
320
+ export type SubscriberHandler = (
321
+ depValues: any[], // 依赖项值的集合
322
+ formKey: string, // 当前表单key
323
+ formData: Record<string, any>, // 当前所有表单数据
324
+ fieldConfig: Field, // 当前字段配置
325
+ ) => void
326
+ export type Action = {
327
+ name?: string // 名称
328
+ immediate?: boolean // 是否在数据初始化后立即触发
329
+ handler: string | ActionHandler // 联动函数
330
+ }
331
+ export type ActionHandler = (
332
+ fieldValue: any, // 当前字段的值
333
+ formKey: string, // 当前表单key
334
+ formData: Record<string, any>, // 当前所有表单数据
335
+ formConfig: Record<string, FormWithFieldMap>, // 所有表单配置的Map
336
+ oldFieldValue: any, // 当前字段的旧值
337
+ ) => void
338
+ export type FormWithFieldMap = { fieldMap: Record<string, Field> } & Form
339
+
340
+ // 高级配置项
341
+ export type AdvancedConfig = {
342
+ skipAutoDataReset?: boolean // 是否跳过自动数据重置,默认false
343
+ }
344
+
345
+ // UI组件
346
+ export interface UIComponents extends Record<ComponentType, any> {
347
+ form: any // 表单组件
348
+ formItem: any // 表单项组件
349
+ tabs?: any // 标签页组件,用于多表单模式
350
+ collapse?: any // 折叠面板根组件
351
+ collapseItem?: any // 折叠面板子组件
352
+ [key: string]: any
353
+ }
354
+
355
+ export type RemoteResponse = Option[] | Promise<Option[]> | any
356
+ export interface RequestContext {
357
+ requestId: number // 当前组件内递增的请求标识,用于识别过期响应
358
+ signal?: AbortSignal // 新请求替换旧请求或组件卸载时触发
359
+ }
360
+ // 远程请求方法
361
+ export type RequestFunction = (
362
+ keyPath: string, // 字段键路径,格式为formKey.fieldKey
363
+ value: any, // 字段值
364
+ url?: string, // 字段remote里配置的远程请求URL
365
+ extraParams?: Record<string, string | number | boolean>, // 字段remote里配置的远程请求参数
366
+ componentParams?: Record<string, any>, // 由UI组件传入的参数,如Select组件的query、Upload组件的file等
367
+ context?: RequestContext, // 请求上下文,用于取消请求及识别过期响应
368
+ ) => RemoteResponse
369
+ export type RemoteMethod = (
370
+ componentParams?: Record<string, any>,
371
+ context?: RequestContext,
372
+ ) => Option[] | Promise<Option[]> // 远程选项获取方法
373
+ export type UploadResponse = any | Promise<any>
374
+ export type UploadMethod = (
375
+ componentParams?: Record<string, any>,
376
+ context?: RequestContext,
377
+ ) => UploadResponse // 上传文件方法
378
+ export type FileRemoveMethod = (
379
+ componentParams?: Record<string, any>,
380
+ context?: RequestContext,
381
+ ) => Promise<void> | void // 文件删除方法
382
+ ```
383
+
384
+ 远程查询和上传应将 `context.signal` 传给 `fetch`、Axios 等请求库。组件会在新查询替换旧查询、文件删除或组件卸载时触发取消;不支持取消的实现也必须避免使用过期响应回写状态。
385
+
386
+ Axios 示例:
387
+
388
+ ```typescript
389
+ const requestFn: RequestFunction = async (
390
+ keyPath,
391
+ value,
392
+ url,
393
+ extraParams,
394
+ componentParams,
395
+ context,
396
+ ) => {
397
+ const { data } = await axios.get(url || '', {
398
+ params: {
399
+ ...extraParams,
400
+ ...componentParams,
401
+ },
402
+ signal: context?.signal,
403
+ })
404
+
405
+ return data
406
+ }
407
+ ```
408
+
409
+ ### 自定义组件
410
+
411
+ 提供一个对象,通过键名匹配自定义组件
412
+
413
+ ```javascript
414
+ {
415
+ // ...
416
+ components: {
417
+ // 自定义组件(示例)
418
+ // ref: https://elemefe.github.io/element-react/#/zh-CN/component/form
419
+ 'ZYInput': Input,
420
+ }
421
+ }
422
+ ```