From 62cf6f46650009aa5c06afc98e8d8426ec19d583 Mon Sep 17 00:00:00 2001 From: dream-weave <62940878+dream-weave@users.noreply.github.com> Date: Fri, 28 Aug 2026 16:02:51 +0800 Subject: [PATCH] =?UTF-8?q?fix(@vben-core/form-ui):=20=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=E5=B5=8C=E5=A5=97=E9=83=A8=E5=88=86=E6=9B=B4=E6=96=B0=E4=B8=8E?= =?UTF-8?q?=E9=87=8D=E5=A4=8D=E5=88=9D=E5=A7=8B=E5=8C=96=E7=BB=91=E5=AE=9A?= =?UTF-8?q?=E6=AE=8B=E7=95=99=20(#8315)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix(@vben-core/form-ui): fix partial updates and bindings * fix(@vben-core/form-ui): guard cyclic patches and restore api docs table --- docs/src/components/common-ui/vben-form.md | 6 +- docs/src/en/components/common-ui/vben-form.md | 4 + .../ui-kit/form-ui/__tests__/config.test.ts | 62 ++++++++ .../ui-kit/form-ui/__tests__/form-api.test.ts | 149 ++++++++++++++++++ .../__tests__/form-integration.test.ts | 39 +++++ .../form-ui/__tests__/form-types.test.ts | 9 +- packages/@core/ui-kit/form-ui/src/config.ts | 36 ++++- packages/@core/ui-kit/form-ui/src/form-api.ts | 63 ++++++-- packages/@core/ui-kit/form-ui/src/types.ts | 9 ++ 9 files changed, 356 insertions(+), 21 deletions(-) create mode 100644 packages/@core/ui-kit/form-ui/__tests__/config.test.ts diff --git a/docs/src/components/common-ui/vben-form.md b/docs/src/components/common-ui/vben-form.md index 3e4415600..1a2df1ab3 100644 --- a/docs/src/components/common-ui/vben-form.md +++ b/docs/src/components/common-ui/vben-form.md @@ -42,6 +42,8 @@ outline: deep 每个应用都有不同的 UI 框架,所以在应用的 `src/adapter/form` 和 `src/adapter/component` 内部,你可以根据自己的需求,进行组件适配。下面是 `Ant Design Vue` 的适配器示例代码,可根据注释查看说明: +必须先初始化组件适配器,再调用 `setupVbenForm`。每次调用都会以当前全局组件注册表重建组件及模型属性映射;重复初始化时,已从注册表移除的组件会同步清理,内置组件及其默认绑定保持不变。 + ::: details ant design vue 表单适配器 ```ts @@ -417,7 +419,7 @@ useVbenForm 返回的第二个参数,是一个对象,包含了一些表单 | validateAndSubmit | 校验通过后提交表单 | `() => Promise` | - | | reset | 重置表单 | `(state?: FormResetState, options?: FormResetOptions) => Promise` | - | | clearValidation | 清空指定字段或全部校验,并取消进行中的异步校验 | `(fieldNames?: FormFieldName \| FormFieldName[]) => Promise` | - | -| setValues | 设置表单组件值,默认会过滤不在 schema 中定义的字段 | `(fields: Partial, filterFields?: boolean, shouldValidate?: boolean) => Promise` | - | +| setValues | 深层补丁更新表单值,默认会过滤不在 schema 中定义的字段 | `(fields: FormValuePatch, filterFields?: boolean, shouldValidate?: boolean) => Promise` | - | | setSubmitValues | 通过 codec.decode 回填完整提交值 | `(values: TSubmitValues, filterFields?: boolean, shouldValidate?: boolean) => Promise` | - | | getValues | 获取经过 codec.encode 或旧格式化管道的提交值 | `() => Promise` | - | | getRawValues | 获取未格式化的独立表单值快照 | `() => Promise` | - | @@ -434,6 +436,8 @@ useVbenForm 返回的第二个参数,是一个对象,包含了一些表单 | getFieldComponentRef | 获取指定字段的组件实例 | `(fieldName: string)=>T` | >5.5.3 | | getFocusedField | 获取当前已获得焦点的字段 | `()=>string\|undefined` | >5.5.3 | +`setValues` 在默认的 `filterFields=true` 模式下会将普通对象作为深层补丁合并,因此更新 `profile.email` 时会保留 `profile` 下其他已声明字段和默认值。数组、日期、Day.js、`null`、`undefined` 等叶值仍会整体覆盖。需要替换整个对象分支时,请使用 `setFieldValue('profile', nextProfile)`;需要绕过 schema 字段过滤时,可以将 `filterFields` 设为 `false`。 + 旧命名 `submitForm`、`validateAndSubmitForm`、`resetForm`、`resetValidate` 分别对应 `submit`、`validateAndSubmit`、`reset`、`clearValidation`。它们仍可调用,但已标记 `@deprecated`,开发环境每个旧名称只警告一次,生产环境静默。 ### FormContextApi 响应式读取 diff --git a/docs/src/en/components/common-ui/vben-form.md b/docs/src/en/components/common-ui/vben-form.md index 6e09df010..e12c8d587 100644 --- a/docs/src/en/components/common-ui/vben-form.md +++ b/docs/src/en/components/common-ui/vben-form.md @@ -41,6 +41,8 @@ The current adapter pattern is: - map special `v-model:*` prop names through `modelPropNameMap` - keep the form empty state aligned with the actual UI library behavior +Each `setupVbenForm` call rebuilds the component and model-prop mappings from the current shared component registry. Repeated setup removes components that are no longer registered while preserving built-in components and their default bindings. + ### Form Adapter Example ```ts @@ -227,6 +229,8 @@ Create the form through `useVbenForm`: Use `useVbenForm` to declare component-facing form values and submission values separately. Schema, slots, selectors, and `setValues` use `TFormValues`; `getValues()` and `submit()` return `Promise`, while `submit()` only accepts an optional native `Event`; the first `handleSubmit` argument is `TSubmitValues`. Pass one generic when both shapes are identical. +`setValues` accepts a deep `FormValuePatch`. With the default `filterFields=true`, plain objects are merged as patches before fields outside the schema are removed, so updating `profile.email` preserves declared sibling fields and defaults under `profile`. Arrays, dates, Day.js values, `null`, and `undefined` replace the corresponding value atomically. Use `setFieldValue('profile', nextProfile)` to replace an entire object branch, or set `filterFields` to `false` to bypass schema filtering. + ```vue