@dazhicheng/ui 1.5.213 → 1.5.216

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 (33) hide show
  1. package/dist/components/tt-form/src/config.js +44 -42
  2. package/dist/components/tt-form/src/form-render/FormField.vue2.js +67 -70
  3. package/dist/components/tt-form/src/form-render/FormFieldContact.d.ts +9 -0
  4. package/dist/components/tt-form/src/form-render/FormFieldContact.js +28 -25
  5. package/dist/components/tt-form/src/form-render/array-register/FormArrayRegister.d.ts +3 -0
  6. package/dist/components/tt-form/src/form-render/array-register/FormArrayRegister.js +20 -18
  7. package/dist/components/tt-form/src/form-render/array-register/props.d.ts +4 -0
  8. package/dist/components/tt-form/src/form-render/array-register/props.js +1 -0
  9. package/dist/components/tt-form/src/form-render/array-register/types.d.ts +4 -0
  10. package/dist/components/tt-form/src/form-render/dependencies.d.ts +5 -0
  11. package/dist/components/tt-form/src/form-render/dependencies.js +77 -39
  12. package/dist/components/tt-form/src/group-form/GroupForm.vue.d.ts +15 -7
  13. package/dist/components/tt-form/src/group-form/GroupForm.vue2.js +120 -104
  14. package/dist/components/tt-form/src/group-form/GroupSection.vue.d.ts +1 -0
  15. package/dist/components/tt-form/src/group-form/GroupSection.vue2.js +68 -64
  16. package/dist/components/tt-form/src/group-form/LazyFormField.vue.d.ts +1 -0
  17. package/dist/components/tt-form/src/group-form/LazyFormField.vue.js +131 -101
  18. package/dist/components/tt-form/src/group-form/groupFormApi.d.ts +110 -46
  19. package/dist/components/tt-form/src/group-form/groupFormApi.js +465 -314
  20. package/dist/components/tt-form/src/group-form/lazyContext.d.ts +15 -13
  21. package/dist/components/tt-form/src/group-form/lazyContext.js +42 -26
  22. package/dist/components/tt-form/src/group-form/types.d.ts +13 -3
  23. package/dist/components/tt-form/src/group-form/useGroupForm.js +47 -50
  24. package/dist/components/tt-form/src/hooks/useFieldArray.js +101 -93
  25. package/dist/components/tt-form/src/hooks/useSelectCollapse.js +47 -47
  26. package/dist/components/tt-form/src/types.d.ts +3 -5
  27. package/dist/components/tt-modal-form/index.vue.js +12 -11
  28. package/dist/components/tt-radio-group/index.d.ts +5 -1
  29. package/dist/components/tt-radio-group/index.vue.d.ts +8 -1
  30. package/dist/components/tt-radio-group/index.vue.js +31 -33
  31. package/dist/components/tt-table/src/TableForm.vue.js +3 -2
  32. package/dist/style.css +1 -1
  33. package/package.json +3 -3
@@ -12,6 +12,7 @@ declare function __VLS_template(): {
12
12
  type __VLS_TemplateResult = ReturnType<typeof __VLS_template>;
13
13
  declare const __VLS_component: import('vue').DefineComponent<LazyFormFieldProps, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<LazyFormFieldProps> & Readonly<{}>, {
14
14
  rules: import('../types').FormSchemaRuleType;
15
+ progressive: boolean;
15
16
  rootMargin: string;
16
17
  fieldClass: string;
17
18
  root: Element | null;
@@ -1,22 +1,22 @@
1
- import { defineComponent as D, inject as A, computed as U, ref as B, watch as Y, useTemplateRef as j, shallowRef as K, onMounted as O, onBeforeUnmount as G, createElementBlock as S, openBlock as h, normalizeClass as m, unref as n, createBlock as V, createCommentVNode as J, mergeProps as Q, withCtx as x, renderSlot as W, normalizeProps as X, guardReactiveProps as Z, normalizeStyle as N, createElementVNode as ee, createVNode as T, nextTick as z } from "vue";
2
- import { ElSkeleton as te, ElSkeletonItem as L } from "element-plus";
1
+ import { defineComponent as Y, inject as K, computed as O, ref as A, watch as S, useTemplateRef as G, shallowRef as J, onMounted as Q, onBeforeUnmount as W, createElementBlock as q, openBlock as h, normalizeClass as p, unref as i, createBlock as x, createCommentVNode as X, mergeProps as Z, withCtx as T, renderSlot as ee, normalizeProps as te, guardReactiveProps as ne, normalizeStyle as V, createElementVNode as oe, createVNode as N, nextTick as re } from "vue";
2
+ import { ElSkeleton as le, ElSkeletonItem as z } from "element-plus";
3
3
  import "../../../../node_modules/.pnpm/vue-types@5.1.3_vue@3.5.21_typescript@5.9.3_/node_modules/vue-types/shim/index.modern.js";
4
- import { useDesign as re } from "../../../../packages/hooks/src/useDesign.js";
4
+ import { useDesign as ie } from "../../../../packages/hooks/src/useDesign.js";
5
5
  import "axios";
6
- import { isFunction as oe, isBoolean as le } from "../../../../packages/utils/src/is.js";
7
- import { clnm as ne } from "../../../../packages/utils/src/tool.js";
6
+ import { isFunction as se, isBoolean as ae } from "../../../../packages/utils/src/is.js";
7
+ import { clnm as ue } from "../../../../packages/utils/src/tool.js";
8
8
  import "../../../../node_modules/.pnpm/decimal.js@10.6.0/node_modules/decimal.js/decimal.js";
9
9
  import "../../../../node_modules/.pnpm/crypto-js@4.2.0/node_modules/crypto-js/aes.js";
10
10
  import "../../../../node_modules/.pnpm/crypto-js@4.2.0/node_modules/crypto-js/enc-utf8.js";
11
11
  import "../../../../node_modules/.pnpm/crypto-js@4.2.0/node_modules/crypto-js/mode-ecb.js";
12
12
  import "../../../../node_modules/.pnpm/crypto-js@4.2.0/node_modules/crypto-js/pad-pkcs7.js";
13
13
  import "lodash-es";
14
- import { useFormValues as ie } from "vee-validate";
15
- import se from "../form-render/FormField.vue2.js";
16
- import { injectRenderFormProps as ae } from "../form-render/context.js";
17
- import { VIRTUAL_ERROR_CACHE_KEY as ue, RENDER_SCHEDULER_KEY as fe } from "./lazyContext.js";
18
- import { resolveValueByFieldName as ce } from "../form-render/dependencies.js";
19
- const Se = /* @__PURE__ */ D({
14
+ import { useFormValues as fe } from "vee-validate";
15
+ import ce from "../form-render/FormField.vue2.js";
16
+ import { injectRenderFormProps as me } from "../form-render/context.js";
17
+ import { RENDER_SCHEDULER_KEY as de } from "./lazyContext.js";
18
+ import { resolveValueByFieldName as pe } from "../form-render/dependencies.js";
19
+ const ve = ["data-field-anchor"], Te = /* @__PURE__ */ Y({
20
20
  name: "LazyFormField",
21
21
  inheritAttrs: !1,
22
22
  __name: "LazyFormField",
@@ -26,137 +26,167 @@ const Se = /* @__PURE__ */ D({
26
26
  fieldClass: { default: "" },
27
27
  root: { default: null },
28
28
  rootMargin: { default: "200px 0px" },
29
+ progressive: { type: Boolean, default: !1 },
29
30
  estimateHeight: { default: 52 },
30
31
  skeleton: { type: Boolean, default: !0 },
31
32
  skeletonAnimated: { type: Boolean, default: !0 }
32
33
  },
33
- setup(q) {
34
- const { prefixCls: s } = re("lazy-form-field"), d = q, g = ae().form, p = d.fieldProps.fieldName, v = A(ue, void 0), _ = A(fe, void 0), C = ie(), k = U(() => d.fieldProps.dependencies), i = B(!0);
35
- Y(
34
+ setup(L) {
35
+ const { prefixCls: u } = ie("lazy-form-field"), a = L, I = me().form, b = a.fieldProps.fieldName, o = K(de, void 0), P = fe(), C = O(() => a.fieldProps.dependencies), l = A(!0);
36
+ let v = 0;
37
+ S(
36
38
  () => {
37
- var r;
38
- const e = k.value;
39
- if ((r = e == null ? void 0 : e.triggerFields) != null && r.length)
40
- return e.triggerFields.map((t) => ce(C.value, t));
39
+ var n;
40
+ const e = C.value;
41
+ if ((n = e == null ? void 0 : e.triggerFields) != null && n.length)
42
+ return e.triggerFields.map((t) => pe(P.value, t));
41
43
  },
42
44
  async () => {
43
- const e = k.value;
44
- if (!e || e.if === void 0) {
45
- i.value = !0;
45
+ const e = ++v, n = C.value;
46
+ if (!n || n.if === void 0) {
47
+ if (e !== v) return;
48
+ l.value = !0;
46
49
  return;
47
50
  }
48
- oe(e.if) ? i.value = !!await e.if(C.value, g) : le(e.if) && (i.value = e.if);
51
+ if (se(n.if)) {
52
+ const t = !!await n.if(P.value, I);
53
+ if (e !== v) return;
54
+ l.value = t;
55
+ } else if (ae(n.if)) {
56
+ if (e !== v) return;
57
+ l.value = n.if;
58
+ }
49
59
  },
50
60
  { deep: !0, immediate: !0 }
51
61
  );
52
- const o = j("containerRef"), u = B(!1);
53
- let f = !1;
54
- const E = `${s}--offscreen`, H = K(d.estimateHeight);
55
- let a = null, l = null, y = null;
56
- async function I() {
57
- if (!g || !p) return;
58
- const r = v == null ? void 0 : v.get(p);
59
- r && (v.delete(p), await z(), g.setFieldError(p, r));
60
- }
62
+ const s = G("containerRef"), f = A(!1);
63
+ let m = !1;
64
+ const H = `${u}--offscreen`, M = J(a.estimateHeight);
65
+ let c = null, r = null, y = null;
61
66
  function w(e) {
62
- let r = e.parentElement;
63
- for (; r; ) {
64
- const t = getComputedStyle(r).overflowY;
65
- if (t === "auto" || t === "scroll") return r;
66
- r = r.parentElement;
67
+ let n = e.parentElement;
68
+ for (; n; ) {
69
+ const t = getComputedStyle(n).overflowY;
70
+ if (t === "auto" || t === "scroll") return n;
71
+ n = n.parentElement;
67
72
  }
68
73
  return null;
69
74
  }
70
- function P() {
71
- const e = o.value;
72
- if (!e || u.value) return;
73
- const r = e.offsetHeight;
74
- e.style.height = `${r}px`, e.style.overflow = "hidden", u.value = !0, I(), z(() => {
75
+ function k() {
76
+ const e = s.value;
77
+ if (!e || f.value) return;
78
+ const n = e.offsetHeight;
79
+ e.style.height = `${n}px`, e.style.overflow = "hidden", f.value = !0, re(() => {
75
80
  requestAnimationFrame(() => {
76
- const t = o.value;
81
+ const t = s.value;
77
82
  if (!t) return;
78
- const $ = t.scrollHeight - r;
79
- t.style.height = "", t.style.overflow = "", !(Math.abs($) <= 2) && requestAnimationFrame(() => {
80
- const R = o.value;
83
+ const E = t.scrollHeight - n;
84
+ t.style.height = "", t.style.overflow = "", !(Math.abs(E) <= 2) && requestAnimationFrame(() => {
85
+ const R = s.value;
81
86
  if (!R) return;
82
- const F = y ?? w(R);
83
- if (!F) return;
84
- const M = R.getBoundingClientRect().top, b = F.getBoundingClientRect().top;
85
- M < b && (F.scrollTop += $);
87
+ const _ = y ?? w(R);
88
+ if (!_) return;
89
+ const j = R.getBoundingClientRect().top, U = _.getBoundingClientRect().top;
90
+ j < U && (_.scrollTop += E);
86
91
  });
87
92
  });
88
93
  });
89
94
  }
90
- return O(() => {
91
- o.value && (y = w(o.value), a = new IntersectionObserver(
92
- (e) => {
93
- const r = e[0];
94
- if (r)
95
- if (r.isIntersecting) {
96
- f = !0;
97
- const t = o.value;
98
- t && (t.style.minHeight = "", t.classList.remove(E)), !u.value && !l && i.value && (l = _ ? _.request(() => {
99
- l = null, !(!f || !i.value) && P();
100
- }) : (() => {
101
- const c = requestAnimationFrame(() => {
102
- l = null, !(!f || !i.value) && P();
103
- });
104
- return () => cancelAnimationFrame(c);
105
- })());
106
- } else
107
- f = !1, u.value && o.value && requestAnimationFrame(() => {
108
- if (f) return;
109
- const t = o.value;
110
- if (!(t != null && t.isConnected)) return;
111
- const c = t.offsetHeight;
112
- c !== 0 && (t.style.minHeight = `${c}px`, t.classList.add(E));
113
- }), l && (l(), l = null);
114
- },
115
- {
116
- root: y,
117
- rootMargin: d.rootMargin
95
+ let F = !1, g = !1;
96
+ function $() {
97
+ r = null, l.value && (F = !0, o == null || o.trackMount(), k());
98
+ }
99
+ function B() {
100
+ f.value || r || !l.value || (r = o ? o.request($) : (() => {
101
+ const e = requestAnimationFrame($);
102
+ return () => cancelAnimationFrame(e);
103
+ })());
104
+ }
105
+ function D() {
106
+ !a.progressive || g || !F || (g = !0, o == null || o.settleMount());
107
+ }
108
+ return S(l, (e) => {
109
+ a.progressive && e && B();
110
+ }), Q(() => {
111
+ if (s.value) {
112
+ if (y = w(s.value), a.progressive) {
113
+ B();
114
+ return;
118
115
  }
119
- ), a.observe(o.value));
120
- }), G(() => {
121
- l && (l(), l = null), a == null || a.disconnect(), a = null;
122
- }), (e, r) => (h(), S("div", {
116
+ c = new IntersectionObserver(
117
+ (e) => {
118
+ const n = e[0];
119
+ if (n)
120
+ if (n.isIntersecting) {
121
+ m = !0;
122
+ const t = s.value;
123
+ t && (t.style.minHeight = "", t.classList.remove(H)), !f.value && !r && l.value && (r = o ? o.request(() => {
124
+ r = null, !(!m || !l.value) && k();
125
+ }) : (() => {
126
+ const d = requestAnimationFrame(() => {
127
+ r = null, !(!m || !l.value) && k();
128
+ });
129
+ return () => cancelAnimationFrame(d);
130
+ })());
131
+ } else
132
+ m = !1, f.value && s.value && requestAnimationFrame(() => {
133
+ if (m) return;
134
+ const t = s.value;
135
+ if (!(t != null && t.isConnected)) return;
136
+ const d = t.offsetHeight;
137
+ d !== 0 && (t.style.minHeight = `${d}px`, t.classList.add(H));
138
+ }), r && (r(), r = null);
139
+ },
140
+ {
141
+ root: y,
142
+ rootMargin: a.rootMargin
143
+ }
144
+ ), c.observe(s.value);
145
+ }
146
+ }), W(() => {
147
+ r && (r(), r = null), a.progressive && F && !g && (g = !0, o == null || o.settleMount()), c == null || c.disconnect(), c = null;
148
+ }), (e, n) => (h(), q("div", {
123
149
  ref_key: "containerRef",
124
- ref: o,
125
- class: m(n(ne)(n(s), e.fieldClass, { [`${n(s)}--hidden`]: !i.value }))
150
+ ref: s,
151
+ "data-field-anchor": i(b),
152
+ class: p(i(ue)(i(u), e.fieldClass, { [`${i(u)}--hidden`]: !l.value }))
126
153
  }, [
127
- u.value ? (h(), V(se, Q({ key: 0 }, e.fieldProps, { rules: e.rules }), {
128
- default: x((t) => [
129
- W(e.$slots, "default", X(Z(t)))
154
+ f.value ? (h(), x(ce, Z({ key: 0 }, e.fieldProps, {
155
+ rules: e.rules,
156
+ onVnodeMounted: D
157
+ }), {
158
+ default: T((t) => [
159
+ ee(e.$slots, "default", te(ne(t)))
130
160
  ]),
131
161
  _: 3
132
- }, 16, ["rules"])) : e.skeleton && i.value ? (h(), V(n(te), {
162
+ }, 16, ["rules"])) : e.skeleton && l.value ? (h(), x(i(le), {
133
163
  key: 1,
134
164
  animated: e.skeletonAnimated,
135
- class: m(`${n(s)}__skeleton`),
136
- style: N({ minHeight: `${H.value}px` })
165
+ class: p(`${i(u)}__skeleton`),
166
+ style: V({ minHeight: `${M.value}px` })
137
167
  }, {
138
- template: x(() => [
139
- ee("div", {
140
- class: m(`${n(s)}__row`)
168
+ template: T(() => [
169
+ oe("div", {
170
+ class: p(`${i(u)}__row`)
141
171
  }, [
142
- T(n(L), {
172
+ N(i(z), {
143
173
  variant: "text",
144
- class: m(`${n(s)}__label`)
174
+ class: p(`${i(u)}__label`)
145
175
  }, null, 8, ["class"]),
146
- T(n(L), {
176
+ N(i(z), {
147
177
  variant: "rect",
148
- class: m(`${n(s)}__control`)
178
+ class: p(`${i(u)}__control`)
149
179
  }, null, 8, ["class"])
150
180
  ], 2)
151
181
  ]),
152
182
  _: 1
153
- }, 8, ["animated", "class", "style"])) : i.value ? (h(), S("div", {
183
+ }, 8, ["animated", "class", "style"])) : l.value ? (h(), q("div", {
154
184
  key: 2,
155
- style: N({ height: `${H.value}px` })
156
- }, null, 4)) : J("", !0)
157
- ], 2));
185
+ style: V({ height: `${M.value}px` })
186
+ }, null, 4)) : X("", !0)
187
+ ], 10, ve));
158
188
  }
159
189
  });
160
190
  export {
161
- Se as default
191
+ Te as default
162
192
  };
@@ -1,4 +1,4 @@
1
- import { FormState, GenericObject, ResetFormOpts, ValidationOptions } from 'vee-validate';
1
+ import { FormState, FormValidationResult, GenericObject, ResetFormOpts, ValidationOptions } from 'vee-validate';
2
2
  import { Ref } from 'vue';
3
3
  import { FormApi } from '../formApi';
4
4
  import { TtFormProps } from '../types';
@@ -10,6 +10,8 @@ import { InsertPosition } from './utils';
10
10
  export declare class GroupFormApi extends FormApi {
11
11
  /** 是否启用虚拟化(IntersectionObserver 懒渲染) */
12
12
  readonly virtual: boolean;
13
+ /** 是否启用渐进式挂载(分批后台挂载全部字段,挂载后常驻 DOM,用于操作全量 DOM 场景) */
14
+ readonly progressive: boolean;
13
15
  /** 构造时的导航锚点默认配置,作为 store 未设置时的 fallback */
14
16
  private readonly _defaultNavAnchorProps;
15
17
  /** 校验失败时是否自动滚动到第一个有错误的分组,默认 true */
@@ -28,12 +30,14 @@ export declare class GroupFormApi extends FormApi {
28
30
  readonly hiddenGroupKeys: Set<string>;
29
31
  /** 当前被 ifShow 隐藏的字段名集合 */
30
32
  readonly hiddenFieldNames: Set<string>;
31
- /** 导航各分组的错误数量,validate 后自动更新 */
33
+ /**
34
+ * 导航各分组的错误数量(派生自 vee-validate 的 form.errors,已内置合并挂载 pathState 与未挂载 extraErrorsBag)。
35
+ * 通过 computed 惰性求值:读取时依赖收集 form.errors,任何 setFieldError / validate 之后
36
+ * 只要 form.errors 变化,导航栏渲染时自动重算,无需手动同步。
37
+ */
32
38
  readonly navErrorCounts: Record<string, number>;
33
- /** 共享错误缓存,validate 写入 LazyFormField 挂载时读取恢复 */
34
- readonly errorCacheMap: Map<string, string>;
35
- /** 重置信号,递增时通知所有 LazyFormField 清空 cachedError */
36
- readonly resetSignal: Ref<number, number>;
39
+ /** navErrorCounts 的响应式来源,reactive Proxy 在读取时依赖注入到此 computed */
40
+ private _navErrorCountsRef;
37
41
  /** 初始传入的分组 schema(用于 fallback) */
38
42
  private readonly _initialGroupSchema;
39
43
  /** 初始展平后的 flatSchema(用于 fallback) */
@@ -52,13 +56,25 @@ export declare class GroupFormApi extends FormApi {
52
56
  private _groupKeySet;
53
57
  /** 是否已执行过 validate,用于控制导航栏错误同步是否需要重新校验未挂载字段 */
54
58
  private _hasValidated;
59
+ /** 导航错误同步在单个宏任务窗口内的累计趟数,用于防御非确定性动态规则导致的 errors↔navCount 回环 */
60
+ private _navSyncPassCount;
61
+ /** 是否已安排本窗口的计数重置(宏任务后清零) */
62
+ private _navSyncResetScheduled;
63
+ /** 本轮回环告警是否已输出,避免刷屏 */
64
+ private _navSyncLoopWarned;
55
65
  /** VirtualGroupForm 组件实例引用,由 useGroupForm 的 h() 渲染时赋值 */
56
66
  groupFormRef: Ref<{
57
67
  scrollToGroup?: ((key: string) => void) | undefined;
68
+ scrollToField?: ((fieldName: string) => void) | undefined;
69
+ whenAllRendered?: (() => Promise<void>) | undefined;
58
70
  } | null, {
59
71
  scrollToGroup?: (key: string) => void;
72
+ scrollToField?: (fieldName: string) => void;
73
+ whenAllRendered?: () => Promise<void>;
60
74
  } | {
61
75
  scrollToGroup?: ((key: string) => void) | undefined;
76
+ scrollToField?: ((fieldName: string) => void) | undefined;
77
+ whenAllRendered?: (() => Promise<void>) | undefined;
62
78
  } | null>;
63
79
  /**
64
80
  * @description 响应式读取 store 状态,由 useGroupForm 在运行时注入实现
@@ -87,7 +103,7 @@ export declare class GroupFormApi extends FormApi {
87
103
  */
88
104
  protected getFieldNamesForSetValuesFilter(): string[];
89
105
  /**
90
- * @description schema 中移除字段后清空 vee 值/错误,并同步清理虚拟列表 errorCacheMap
106
+ * @description schema 中移除字段后清空 vee 值/错误,并注销对应数组字段句柄
91
107
  * @param {string[]} removedFieldNames 已移除的 fieldName 列表
92
108
  */
93
109
  onRemovedSchemaFields(removedFieldNames: string[]): void;
@@ -103,7 +119,30 @@ export declare class GroupFormApi extends FormApi {
103
119
  * @example
104
120
  * await formApi.validate(undefined, false);
105
121
  */
106
- validate(opts?: Partial<ValidationOptions>, scrollToError?: boolean): Promise<import('vee-validate').FormValidationResult<GenericObject, GenericObject>>;
122
+ validate(_opts?: Partial<ValidationOptions>, scrollToError?: boolean): Promise<FormValidationResult<GenericObject, GenericObject>>;
123
+ /**
124
+ * @description 对收集到的可见字段逐个用 vee-validate 底层 `validate()` 校验,独立字段并发执行。
125
+ * 规则引擎与挂载态字段完全一致(含 defineRule 自定义规则、zod typed schema、跨字段 target 解析)。
126
+ * @param {ResolvedValidationField[]} fields - 待校验字段清单
127
+ * @param {Record<string, any>} values - 整表值,透传给 vee-validate 做跨字段规则解析
128
+ * @returns {Promise<Record<string, string>>} 字段名 → 首条错误信息(仅含校验失败字段)
129
+ */
130
+ private _runFieldValidations;
131
+ /**
132
+ * @description 把校验结果写回 vee-validate 的错误状态(唯一错误 sink)。
133
+ * 带 diff 保护:只有当目标错误与当前 form.errors 不一致时才写,避免触发 useGroupForm 里
134
+ * `watch(form.errors)` → syncNavErrorCountsFromForm 的无谓回环,并保证回环在有限趟内收敛。
135
+ * @param {ResolvedValidationField[]} fields - 本轮参与校验的字段(决定要清空/设置哪些字段)
136
+ * @param {Record<string, string>} errorMap - 字段名 → 错误信息
137
+ */
138
+ private _applyFieldErrors;
139
+ /**
140
+ * @description 清空全部字段错误(含 vee-validate extraErrorsBag 里从未挂载过的残留)。
141
+ * vee-validate 的 resetForm 只遍历已挂载的 pathState,不会清 extraErrorsBag 里未挂载路径的错误,
142
+ * 因此这里显式遍历「展平 schema 顶层字段 + 当前 form.errors 的全部 key(含未挂载/数组行路径)」
143
+ * 逐个 setFieldError(undefined),保证重置后未挂载字段的残留错误也被清掉。
144
+ */
145
+ private _clearAllFieldErrors;
107
146
  /**
108
147
  * @description 校验并提交表单
109
148
  * @returns {Promise<any>} 提交结果,校验失败时返回 undefined
@@ -116,7 +155,7 @@ export declare class GroupFormApi extends FormApi {
116
155
  */
117
156
  resetForm(state?: Partial<FormState<GenericObject>>, opts?: Partial<ResetFormOpts>): Promise<void>;
118
157
  /**
119
- * @description 重置校验状态(含清空虚拟字段错误缓存和导航错误计数)
158
+ * @description 重置校验状态(同时清空虚拟字段错误缓存;navErrorCounts 由 form.errors 派生,自动更新)
120
159
  */
121
160
  resetValidate(): Promise<void>;
122
161
  /**
@@ -130,6 +169,18 @@ export declare class GroupFormApi extends FormApi {
130
169
  * @param {string} key - 分组 key
131
170
  */
132
171
  scrollToGroup(key: string): void;
172
+ /**
173
+ * @description 滚动到指定字段(借助 LazyFormField 容器的 data-field-anchor 锚点,未挂载也可定位)。
174
+ * 主要用于「无分组、且虚拟懒渲染尚未挂载」的字段——它们没有分组锚点,基类按 [name] 也找不到 DOM。
175
+ * @param {string} fieldName - 字段名(完整路径)
176
+ */
177
+ scrollToField(fieldName: string): void;
178
+ /**
179
+ * @description 等待渐进式挂载完成(所有字段已渲染进 DOM)。用于需要操作全量 DOM 的场景
180
+ * (截图、导出、爬虫等)前调用。非 progressive 模式下立即 resolve。
181
+ * @returns {Promise<void>}
182
+ */
183
+ whenAllRendered(): Promise<void>;
133
184
  /**
134
185
  * @description 切换分组折叠状态
135
186
  * @param {string} key - 分组 key
@@ -146,7 +197,7 @@ export declare class GroupFormApi extends FormApi {
146
197
  * group 隐藏时额外维护 {@link hiddenGroupKeys} 供导航和渲染判断;
147
198
  * group / row 隐藏时都会清空其下字段校验,并把字段加入 {@link hiddenFieldNames},使隐藏字段不参与校验。
148
199
  * 可见性变化后在下一帧调用 {@link syncNavErrorCountsFromForm},使「先 validate 再隐藏再显示」时
149
- * 导航徽标、{@link errorCacheMap} 与表单项错误展示保持一致。
200
+ * 导航徽标与表单项错误展示保持一致。
150
201
  * @param {string} key - 分组 key
151
202
  * @param {boolean} visible - 是否可见
152
203
  * @param {string[]} [fieldNames] - 兼容旧内部调用的字段名列表,传入时按字段集合显隐处理
@@ -217,40 +268,46 @@ export declare class GroupFormApi extends FormApi {
217
268
  */
218
269
  removeGroups(groupKey: string[] | string): void;
219
270
  /**
220
- * @description 合并 vee-validate 实时 errors 与虚拟列表未挂载字段的 errorCacheMap,用于导航徽标与输入联动
221
- * @returns {Record<string, string>} 合并后的错误映射
271
+ * @description 读取 vee-validate 的实时 errors(已内置合并挂载字段 pathState 与未挂载字段 extraErrorsBag),
272
+ * 剔除隐藏字段后作为导航徽标计数来源。不再需要外挂 errorCacheMap——未挂载字段的错误由 setFieldError
273
+ * 直接写入 vee-validate 的 extraErrorsBag,天然进入 form.errors。
274
+ * @returns {Record<string, string>} 过滤隐藏字段后的错误映射
222
275
  */
223
276
  private _mergeErrorsForNav;
224
277
  /**
225
- * @description 同步导航错误计数。
226
- * 当开启虚拟列表且已执行过 validate 时,会重新对未挂载字段做可见性检查和校验,
227
- * 确保 dependencies 条件变化后错误计数实时更新。
278
+ * @description 刷新未挂载字段的校验错误,使 dependencies 条件变化后导航徽标即时反映。
279
+ * 注:`navErrorCounts` 是依赖 form.errors 的 computed 派生量,会自动重算,此方法只负责在
280
+ * 「已 validate 过」的虚拟列表场景下,重算可见字段错误并写回 form.errors(未挂载字段落 extraErrorsBag)。
281
+ * 非虚拟化 / 未 validate 过时直接返回,computed 会自然反映 form.errors 现状。
228
282
  */
229
283
  syncNavErrorCountsFromForm(): Promise<void>;
230
284
  /**
231
- * @description 清空导航各分组的错误计数
285
+ * @description 校验失败后滚动到第一个错误字段所属的分组。
286
+ * 按 fields 的文档顺序取第一个出错字段(不是遍历分组"是否含任意错误",避免总是命中最外层祖先分组),
287
+ * 定位到该字段直接所属的最内层分组,并展开其整条折叠的祖先链,保证目标在 DOM 中且可见。
288
+ * @param {ResolvedValidationField[]} fields - 本轮参与校验的字段(已按文档顺序)
289
+ * @param {Record<string, string>} errorMap - 字段名 → 错误信息
232
290
  */
233
- private _clearNavErrorCounts;
291
+ private _scrollToFirstErrorField;
234
292
  /**
235
- * @description 校验失败后展开包含错误的分组,并滚动到该分组标题
236
- * @param {Record<string, string>} errors - 合并后的所有错误
237
- */
238
- private _scrollToFirstErrorGroup;
239
- /**
240
- * @description 从校验结果中剔除属于隐藏字段集合的错误,并重新判定 valid 状态
241
- * @param {object} result - 校验结果
242
- * @returns {object} 过滤后的校验结果
293
+ * @description 解析字段在未挂载状态下应使用的有效校验规则:优先取 dependencies.rules 的动态结果,
294
+ * 为空时回退到静态 schema.rules;两者都为空时,若 dependencies.required 为真则视为 "required"。
295
+ * 与 FormField.vue 中 currentRules / fieldRules 的计算逻辑保持一致,避免虚拟列表下未挂载字段
296
+ * 因为只写了 dependencies.required(未写静态 rules)而被漏判为合法。
297
+ * @param {FormSchema} schema - 字段 schema
298
+ * @param {Record<string, any>} values - 当前表单值
299
+ * @returns {Promise<FormSchemaRuleType | undefined>} 有效校验规则
243
300
  */
244
- private _stripHiddenFieldErrors;
245
301
  /**
246
- * @description 对单个字段值执行 rules 校验(纯数据,不挂载组件)。
247
- * 支持字符串规则("required" / "selectRequired")和 Zod schema。
248
- * @param {unknown} value - 字段值
249
- * @param {FormSchemaRuleType | undefined} rules - 校验规则
250
- * @param {string} fieldName - 字段名
251
- * @returns {Promise<string | undefined>} 错误信息,无错误返回 undefined
302
+ * @description 安全执行用户提供的 dependencies 异步回调:捕获异常并降级,避免单个字段的回调抛错
303
+ * (或 reject)拖垮整表校验 / 导航同步。故障隔离到字段级,出错时用给定回退值并告警。
304
+ * @param {() => T | Promise<T>} fn - 用户回调
305
+ * @param {T} fallback - 出错时的回退值
306
+ * @param {string} context - 日志上下文(字段名 + 回调类型)
307
+ * @returns {Promise<T>}
252
308
  */
253
- private _validateFieldValue;
309
+ private _safeInvoke;
310
+ private _resolveEffectiveRules;
254
311
  /**
255
312
  * @description 检查字段的 dependencies 条件,判断字段在当前值下是否应该被校验。
256
313
  * 与 FormField.vue 保持一致:visible = !hide && isIf && isShow
@@ -260,17 +317,25 @@ export declare class GroupFormApi extends FormApi {
260
317
  */
261
318
  private _isFieldVisible;
262
319
  /**
263
- * @description 对所有未挂载的字段做纯值校验,补充到 validate 结果中,
264
- * 并将错误写入 errorCacheMap 以便 LazyFormField 挂载时恢复。
265
- * 会跳过因 dependencies.if 条件不满足而不应渲染的字段,与原始表单校验行为一致。
266
- * @param {object} validateResult - 父类 validate 返回的校验结果
267
- * @returns {Promise<object>} 补充未挂载字段错误后的校验结果
320
+ * @description 收集当前需要校验的全部可见字段(顶层字段 + 数组行递归展开的行内字段)。
321
+ * 统一 validate / syncNavErrorCountsFromForm 的字段来源,避免两份平行遍历逻辑走偏。
322
+ * - 顶层字段:遍历展平 schema,逐个走 {@link _isFieldVisible} 过滤(hide / dependencies.if / dependencies.show / 隐藏分组)。
323
+ * - 数组字段(useArraySchema):字段自身规则按普通字段收集(与未挂载路径旧行为一致,也顺带覆盖挂载态),
324
+ * 再从 form.values 取当前数组值,按行调用 {@link resolveArraySchemasForRuntime}(safeMutations 只读,无副作用)
325
+ * 展开行内字段,递归处理嵌套数组。行内字段路径与 FormArrayRegister 渲染时的注册键完全一致。
326
+ * @param {Record<string, any>} values - 当前表单值
327
+ * @returns {Promise<ResolvedValidationField[]>} 扁平化的待校验字段清单
268
328
  */
269
- private _validateUnmountedFields;
329
+ private _collectValidationFields;
270
330
  /**
271
- * @description 清空所有缓存的错误并递增重置信号
331
+ * @description 递归收集单个 schema 节点的可校验字段。普通字段直接产出;
332
+ * 数组字段先产出自身规则,再按当前值逐行展开行内字段(含嵌套数组)。
333
+ * @param {FormSchema} schema - 字段 schema(顶层或行内)
334
+ * @param {string} fieldName - 该字段的完整路径(行内字段已拼好数组下标路径)
335
+ * @param {Record<string, any>} values - 当前表单值
336
+ * @returns {Promise<ResolvedValidationField[]>} 该节点(含数组行内字段)产出的字段清单,按文档顺序排列
272
337
  */
273
- private _clearAllCachedErrors;
338
+ private _collectFieldRecursive;
274
339
  /**
275
340
  * @description 收集分组 key 及其所有子分组 key(去重)
276
341
  * @param keys - 起始分组 key 列表
@@ -286,13 +351,12 @@ export declare class GroupFormApi extends FormApi {
286
351
  * @description 根据错误映射更新导航各分组的错误计数
287
352
  * @param {Record<string, string>} errors - 字段错误映射
288
353
  */
289
- private _updateNavErrorCounts;
290
354
  /**
291
- * @description 根据错误字段找到第一个包含错误的分组 key(按 schema 定义顺序)
292
- * @param {Record<string, string>} errors - 错误字段映射
293
- * @returns {string | undefined} 第一个有错误的分组 key
355
+ * @description 计算导航各分组的错误数量(纯函数:读入 form.errors,返回 { groupKey: count })。
356
+ * 仅在 {@link _navErrorCountsRef} computed getter 中调用;不再对外暴露 push 式更新入口。
357
+ * @returns {Record<string, number>} 各分组的错误数量
294
358
  */
295
- private _findFirstErrorGroupKey;
359
+ private _computeNavErrorCounts;
296
360
  /**
297
361
  * @description 获取指定分组下的字段名列表,默认会获取该分组下的所有字段
298
362
  * @param {string} key - 分组 key