@qin-ui/antd-vue-pro 2.4.0 → 2.4.2

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 (154) hide show
  1. package/api.json +1 -1
  2. package/es/antd-vue-pro.css +11 -11
  3. package/es/components/component-provider/components/index.vue.d.ts.map +1 -0
  4. package/es/{src/components → components}/component-provider/constants/index.d.ts +2 -2
  5. package/es/components/component-provider/constants/index.d.ts.map +1 -0
  6. package/es/components/component-provider/index.d.ts.map +1 -0
  7. package/es/components/component-provider/types/index.d.ts.map +1 -0
  8. package/es/components/form/components/BaseField/index.vue.d.ts.map +1 -0
  9. package/es/{src/components → components}/form/components/BaseField/utils/index.d.ts +1 -0
  10. package/es/components/form/components/BaseField/utils/index.d.ts.map +1 -0
  11. package/es/components/form/components/BaseFormItem/index.vue.d.ts.map +1 -0
  12. package/es/components/form/components/ContainerFragment/index.vue.d.ts.map +1 -0
  13. package/es/components/form/components/ProForm/index.vue.d.ts.map +1 -0
  14. package/es/components/form/components/SlotComponent/index.vue.d.ts.map +1 -0
  15. package/es/components/form/components/index.d.ts.map +1 -0
  16. package/es/components/form/constants/index.d.ts.map +1 -0
  17. package/es/components/form/hooks/index.d.ts.map +1 -0
  18. package/es/components/form/hooks/useFields.d.ts.map +1 -0
  19. package/es/components/form/hooks/useForm.d.ts.map +1 -0
  20. package/es/components/form/hooks/useFormRef.d.ts.map +1 -0
  21. package/es/components/form/hooks/useGroupFieldAttrs.d.ts.map +1 -0
  22. package/es/components/form/index.d.ts.map +1 -0
  23. package/es/components/form/types/index.d.ts.map +1 -0
  24. package/es/components/table/components/ColumnControl.vue.d.ts.map +1 -0
  25. package/es/components/table/components/DefaultSearchFormContainer.vue.d.ts.map +1 -0
  26. package/es/components/table/components/DefaultTableContainer.vue.d.ts.map +1 -0
  27. package/es/{src/components → components}/table/components/ProTable.vue.d.ts +4 -1
  28. package/es/components/table/components/ProTable.vue.d.ts.map +1 -0
  29. package/es/components/table/components/SearchForm.vue.d.ts.map +1 -0
  30. package/es/components/table/components/SizeControl.vue.d.ts.map +1 -0
  31. package/es/components/table/components/icons/ColumnHeightOutlined.vue.d.ts.map +1 -0
  32. package/es/components/table/components/icons/DownOutlined.vue.d.ts.map +1 -0
  33. package/es/components/table/components/icons/FilterOutlined.vue.d.ts.map +1 -0
  34. package/es/components/table/components/index.d.ts.map +1 -0
  35. package/es/components/table/hooks/index.d.ts.map +1 -0
  36. package/es/components/table/hooks/useTable.d.ts.map +1 -0
  37. package/es/components/table/index.d.ts.map +1 -0
  38. package/es/{src/components → components}/table/types/index.d.ts +1 -1
  39. package/es/components/table/types/index.d.ts.map +1 -0
  40. package/es/index.d.ts.map +1 -0
  41. package/es/index.js +111 -229
  42. package/es/index.js.map +1 -1
  43. package/es/{src/locale → locale}/index.d.ts +1 -1
  44. package/es/locale/index.d.ts.map +1 -0
  45. package/es/shared/core/index.d.ts +6 -0
  46. package/es/shared/core/index.d.ts.map +1 -0
  47. package/es/shared/ui/index.d.ts.map +1 -0
  48. package/package.json +2 -2
  49. package/src/components/component-provider/components/index.vue +4 -3
  50. package/src/components/component-provider/constants/index.ts +4 -3
  51. package/src/components/form/components/BaseField/index.vue +3 -6
  52. package/src/components/form/components/BaseField/utils/index.ts +11 -0
  53. package/src/components/form/components/BaseFormItem/index.vue +2 -1
  54. package/src/components/form/components/ProForm/index.vue +23 -23
  55. package/src/components/form/hooks/useGroupFieldAttrs.ts +9 -3
  56. package/src/components/table/components/ColumnControl.vue +8 -10
  57. package/src/components/table/components/ProTable.vue +74 -31
  58. package/src/components/table/components/SearchForm.vue +8 -182
  59. package/src/components/table/types/index.ts +1 -1
  60. package/src/locale/index.ts +1 -1
  61. package/src/shared/core/index.ts +11 -0
  62. package/es/__tests__/BaseField.spec.d.ts +0 -2
  63. package/es/__tests__/BaseField.spec.d.ts.map +0 -1
  64. package/es/__tests__/BaseFormItem.spec.d.ts +0 -2
  65. package/es/__tests__/BaseFormItem.spec.d.ts.map +0 -1
  66. package/es/__tests__/ProForm.spec.d.ts +0 -2
  67. package/es/__tests__/ProForm.spec.d.ts.map +0 -1
  68. package/es/__tests__/ProTable.spec.d.ts +0 -2
  69. package/es/__tests__/ProTable.spec.d.ts.map +0 -1
  70. package/es/__tests__/SearchForm.spec.d.ts +0 -2
  71. package/es/__tests__/SearchForm.spec.d.ts.map +0 -1
  72. package/es/__tests__/controls.spec.d.ts +0 -2
  73. package/es/__tests__/controls.spec.d.ts.map +0 -1
  74. package/es/__tests__/helpers/fixtures.d.ts +0 -15
  75. package/es/__tests__/helpers/fixtures.d.ts.map +0 -1
  76. package/es/__tests__/helpers/mount.d.ts +0 -38
  77. package/es/__tests__/helpers/mount.d.ts.map +0 -1
  78. package/es/__tests__/hooks-locale.spec.d.ts +0 -2
  79. package/es/__tests__/hooks-locale.spec.d.ts.map +0 -1
  80. package/es/__tests__/index.spec.d.ts +0 -2
  81. package/es/__tests__/index.spec.d.ts.map +0 -1
  82. package/es/__tests__/integration.spec.d.ts +0 -2
  83. package/es/__tests__/integration.spec.d.ts.map +0 -1
  84. package/es/__tests__/setup.d.ts +0 -14
  85. package/es/__tests__/setup.d.ts.map +0 -1
  86. package/es/src/components/component-provider/components/index.vue.d.ts.map +0 -1
  87. package/es/src/components/component-provider/constants/index.d.ts.map +0 -1
  88. package/es/src/components/component-provider/index.d.ts.map +0 -1
  89. package/es/src/components/component-provider/types/index.d.ts.map +0 -1
  90. package/es/src/components/form/components/BaseField/index.vue.d.ts.map +0 -1
  91. package/es/src/components/form/components/BaseField/utils/index.d.ts.map +0 -1
  92. package/es/src/components/form/components/BaseFormItem/index.vue.d.ts.map +0 -1
  93. package/es/src/components/form/components/ContainerFragment/index.vue.d.ts.map +0 -1
  94. package/es/src/components/form/components/ProForm/index.vue.d.ts.map +0 -1
  95. package/es/src/components/form/components/SlotComponent/index.vue.d.ts.map +0 -1
  96. package/es/src/components/form/components/index.d.ts.map +0 -1
  97. package/es/src/components/form/constants/index.d.ts.map +0 -1
  98. package/es/src/components/form/hooks/index.d.ts.map +0 -1
  99. package/es/src/components/form/hooks/useFields.d.ts.map +0 -1
  100. package/es/src/components/form/hooks/useForm.d.ts.map +0 -1
  101. package/es/src/components/form/hooks/useFormRef.d.ts.map +0 -1
  102. package/es/src/components/form/hooks/useGroupFieldAttrs.d.ts.map +0 -1
  103. package/es/src/components/form/index.d.ts.map +0 -1
  104. package/es/src/components/form/types/index.d.ts.map +0 -1
  105. package/es/src/components/table/components/ColumnControl.vue.d.ts.map +0 -1
  106. package/es/src/components/table/components/DefaultSearchFormContainer.vue.d.ts.map +0 -1
  107. package/es/src/components/table/components/DefaultTableContainer.vue.d.ts.map +0 -1
  108. package/es/src/components/table/components/ProTable.vue.d.ts.map +0 -1
  109. package/es/src/components/table/components/SearchForm.vue.d.ts.map +0 -1
  110. package/es/src/components/table/components/SizeControl.vue.d.ts.map +0 -1
  111. package/es/src/components/table/components/icons/ColumnHeightOutlined.vue.d.ts.map +0 -1
  112. package/es/src/components/table/components/icons/DownOutlined.vue.d.ts.map +0 -1
  113. package/es/src/components/table/components/icons/FilterOutlined.vue.d.ts.map +0 -1
  114. package/es/src/components/table/components/index.d.ts.map +0 -1
  115. package/es/src/components/table/hooks/index.d.ts.map +0 -1
  116. package/es/src/components/table/hooks/useTable.d.ts.map +0 -1
  117. package/es/src/components/table/index.d.ts.map +0 -1
  118. package/es/src/components/table/types/index.d.ts.map +0 -1
  119. package/es/src/index.d.ts.map +0 -1
  120. package/es/src/locale/index.d.ts.map +0 -1
  121. package/es/src/shared/core/index.d.ts +0 -6
  122. package/es/src/shared/core/index.d.ts.map +0 -1
  123. package/es/src/shared/ui/index.d.ts.map +0 -1
  124. /package/es/{src/components → components}/component-provider/components/index.vue.d.ts +0 -0
  125. /package/es/{src/components → components}/component-provider/index.d.ts +0 -0
  126. /package/es/{src/components → components}/component-provider/types/index.d.ts +0 -0
  127. /package/es/{src/components → components}/form/components/BaseField/index.vue.d.ts +0 -0
  128. /package/es/{src/components → components}/form/components/BaseFormItem/index.vue.d.ts +0 -0
  129. /package/es/{src/components → components}/form/components/ContainerFragment/index.vue.d.ts +0 -0
  130. /package/es/{src/components → components}/form/components/ProForm/index.vue.d.ts +0 -0
  131. /package/es/{src/components → components}/form/components/SlotComponent/index.vue.d.ts +0 -0
  132. /package/es/{src/components → components}/form/components/index.d.ts +0 -0
  133. /package/es/{src/components → components}/form/constants/index.d.ts +0 -0
  134. /package/es/{src/components → components}/form/hooks/index.d.ts +0 -0
  135. /package/es/{src/components → components}/form/hooks/useFields.d.ts +0 -0
  136. /package/es/{src/components → components}/form/hooks/useForm.d.ts +0 -0
  137. /package/es/{src/components → components}/form/hooks/useFormRef.d.ts +0 -0
  138. /package/es/{src/components → components}/form/hooks/useGroupFieldAttrs.d.ts +0 -0
  139. /package/es/{src/components → components}/form/index.d.ts +0 -0
  140. /package/es/{src/components → components}/form/types/index.d.ts +0 -0
  141. /package/es/{src/components → components}/table/components/ColumnControl.vue.d.ts +0 -0
  142. /package/es/{src/components → components}/table/components/DefaultSearchFormContainer.vue.d.ts +0 -0
  143. /package/es/{src/components → components}/table/components/DefaultTableContainer.vue.d.ts +0 -0
  144. /package/es/{src/components → components}/table/components/SearchForm.vue.d.ts +0 -0
  145. /package/es/{src/components → components}/table/components/SizeControl.vue.d.ts +0 -0
  146. /package/es/{src/components → components}/table/components/icons/ColumnHeightOutlined.vue.d.ts +0 -0
  147. /package/es/{src/components → components}/table/components/icons/DownOutlined.vue.d.ts +0 -0
  148. /package/es/{src/components → components}/table/components/icons/FilterOutlined.vue.d.ts +0 -0
  149. /package/es/{src/components → components}/table/components/index.d.ts +0 -0
  150. /package/es/{src/components → components}/table/hooks/index.d.ts +0 -0
  151. /package/es/{src/components → components}/table/hooks/useTable.d.ts +0 -0
  152. /package/es/{src/components → components}/table/index.d.ts +0 -0
  153. /package/es/{src/index.d.ts → index.d.ts} +0 -0
  154. /package/es/{src/shared → shared}/ui/index.d.ts +0 -0
@@ -1,5 +1,5 @@
1
1
  import { InjectionKey, MaybeRef } from 'vue';
2
- import { zhCN, zhTW, enUS, ProLocale, ProLocaleName } from '@qin-ui/pro-components-core';
2
+ import { zhCN, zhTW, enUS, ProLocale, ProLocaleName } from '../shared/core';
3
3
  export { zhCN, zhTW, enUS };
4
4
  export type { ProLocale };
5
5
  /** ProComponentProvider 通过该 key 注入局部覆盖文案 */
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/locale/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAIL,KAAK,YAAY,EACjB,KAAK,QAAQ,EACd,MAAM,KAAK,CAAC;AACb,OAAO,EACL,IAAI,EACJ,IAAI,EACJ,IAAI,EAGJ,KAAK,SAAS,EACd,KAAK,aAAa,EACnB,MAAM,gBAAgB,CAAC;AAGxB,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;AAE5B,YAAY,EAAE,SAAS,EAAE,CAAC;AAE1B,4CAA4C;AAC5C,eAAO,MAAM,iBAAiB,EAAE,YAAY,CAC1C,QAAQ,CAAC,OAAO,CAAC,SAAS,CAAC,GAAG,SAAS,CAAC,CAClB,CAAC;AAEzB;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,SAAS;aAWJ,MAAM,WAAW,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,KAAG,MAAM;;CAQ1E,CAAC"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * 统一 re-export @qin-ui/pro-components-core,包内所有文件通过此文件引入 core 内容,
3
+ * 避免直接散列依赖 @qin-ui/pro-components-core,便于将来统一维护。
4
+ */
5
+ export { useForm, createFormProxy, useTable, useSearchFormExpand, useFields, useFormData, useFormRef, InjectionFormKey, InjectionFormSlotsKey, getObject, get, set, normalizePathKey, toPath, camelizeProperties, cloneDeep, pick, isPlainObject, isPromise, zhCN, zhTW, enUS, format, resolveLocaleName, type ProLocale, type ProLocaleName, type ProLocaleKey, type Data, type Path, type Paths, type KeyExpandString, type ExtendWithAny, type DeepPartial, type PageParam, type Fields, type Form, type Table, type UseFieldsReturn, type UseFormDataReturn, type UseFormRefReturn, } from '@qin-ui/pro-components-core';
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/shared/core/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAEL,OAAO,EACP,eAAe,EACf,QAAQ,EACR,mBAAmB,EACnB,SAAS,EACT,WAAW,EACX,UAAU,EAEV,gBAAgB,EAChB,qBAAqB,EAErB,SAAS,EACT,GAAG,EACH,GAAG,EACH,gBAAgB,EAChB,MAAM,EACN,kBAAkB,EAClB,SAAS,EACT,IAAI,EACJ,aAAa,EACb,SAAS,EAET,IAAI,EACJ,IAAI,EACJ,IAAI,EACJ,MAAM,EACN,iBAAiB,EACjB,KAAK,SAAS,EACd,KAAK,aAAa,EAClB,KAAK,YAAY,EAEjB,KAAK,IAAI,EACT,KAAK,IAAI,EACT,KAAK,KAAK,EACV,KAAK,eAAe,EACpB,KAAK,aAAa,EAClB,KAAK,WAAW,EAChB,KAAK,SAAS,EACd,KAAK,MAAM,EACX,KAAK,IAAI,EACT,KAAK,KAAK,EACV,KAAK,eAAe,EACpB,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,GACtB,MAAM,6BAA6B,CAAC"}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/shared/ui/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,IAAI,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAC9D,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,4BAA4B,CAAC;AAE1D,OAAO,EACL,KAAK,EACL,IAAI,EACJ,QAAQ,EACR,GAAG,IAAI,IAAI,EACX,GAAG,IAAI,QAAQ,EACf,KAAK,EACL,KAAK,EACL,WAAW,EACX,QAAQ,EACR,IAAI,EACJ,QAAQ,EACR,QAAQ,EACR,MAAM,EACN,QAAQ,EACR,aAAa,EACb,UAAU,EACV,KAAK,EACL,WAAW,EACX,aAAa,EACb,WAAW,EACX,UAAU,EACV,MAAM,EACN,MAAM,EACN,MAAM,EACN,QAAQ,EACR,UAAU,EACV,QAAQ,EACR,UAAU,EACV,WAAW,EACX,KAAK,gBAAgB,EACrB,KAAK,YAAY,EACjB,KAAK,QAAQ,IAAI,SAAS,EAC1B,KAAK,QAAQ,IAAI,aAAa,EAC9B,KAAK,aAAa,EAClB,KAAK,UAAU,EACf,KAAK,eAAe,GACrB,MAAM,gBAAgB,CAAC;AAExB,OAAO,EAAE,KAAK,UAAU,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AACtE,OAAO,EAAE,KAAK,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AACtE,OAAO,EAAE,sBAAsB,EAAE,MAAM,2CAA2C,CAAC;AACnF,OAAO,EACL,iBAAiB,EACjB,mBAAmB,GACpB,MAAM,mDAAmD,CAAC;AAC3D,OAAO,EAAE,QAAQ,IAAI,aAAa,EAAE,MAAM,4BAA4B,CAAC;AACvE,OAAO,EACL,aAAa,EACb,wBAAwB,GACzB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,kCAAkC,CAAC;AACjE,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,sCAAsC,CAAC;AAEzE,MAAM,MAAM,SAAS,GAAG,IAAI,CAAC,UAAU,EAAE,oBAAoB,CAAC,GAAG;IAC/D,kBAAkB,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;CAC7C,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@qin-ui/antd-vue-pro",
3
- "version": "2.4.0",
3
+ "version": "2.4.2",
4
4
  "description": "二次封装antd vue组件",
5
5
  "bin": {
6
6
  "antd-vue-pro": "./bin/init-ai.mjs"
@@ -43,7 +43,7 @@
43
43
  "dependencies": {
44
44
  "scroll-into-view-if-needed": "^3.1.0",
45
45
  "vue-component-type-helpers": "^3.2.5",
46
- "@qin-ui/pro-components-core": "^2.0.0"
46
+ "@qin-ui/pro-components-core": "^2.0.1"
47
47
  },
48
48
  "devDependencies": {
49
49
  "@vue/test-utils": "^2.4.11",
@@ -109,9 +109,10 @@ if (props.componentVars) {
109
109
  }
110
110
 
111
111
  // 注入自定义组件映射,BaseField 在解析组件时会优先使用此映射
112
- if (props.componentMap) {
113
- provide(INJECT_COMPONENTS, props.componentMap);
114
- }
112
+ provide(
113
+ INJECT_COMPONENTS,
114
+ computed(() => props.componentMap)
115
+ );
115
116
 
116
117
  // 注入内置文案覆盖,useLocale 在解析文案时会优先使用
117
118
  provide(
@@ -1,12 +1,13 @@
1
1
  import { RequiredComponentVars } from '../types';
2
- import { InjectionKey, Component } from 'vue';
2
+ import { InjectionKey, Component, type ComputedRef } from 'vue';
3
3
 
4
4
  const getPopupContainer = (triggerNode: any) =>
5
5
  triggerNode.closest?.("form[class*='-form']") ||
6
6
  (typeof document !== 'undefined' ? document.body : undefined);
7
7
 
8
8
  export const INJECT_COMPONENTS: InjectionKey<
9
- Partial<Record<string, Component>>
9
+ | ComputedRef<Partial<Record<string, Component>> | undefined>
10
+ | Partial<Record<string, Component>>
10
11
  > = Symbol('INJECT_COMPONENTS');
11
12
 
12
13
  export type InjectConfigEntry<T = any> = {
@@ -70,7 +71,7 @@ export const INJECT_CONFIG: {
70
71
  injectionKey: Symbol(''),
71
72
  default: {
72
73
  max: 10 ** 15 - 1,
73
- min: -(10 ** 15 + 1),
74
+ min: -(10 ** 15 - 1),
74
75
  controls: false,
75
76
  style: { width: '100%' },
76
77
  },
@@ -49,7 +49,7 @@ import {
49
49
  getInjectConfig,
50
50
  } from '../../../component-provider/constants';
51
51
  import { useForm } from '../../hooks/useForm';
52
- import { getInitProps } from './utils';
52
+ import { getInitProps, warnUnknownComponent } from './utils';
53
53
  import { useLocale } from '../../../../locale';
54
54
 
55
55
  defineOptions({ name: 'BaseField', inheritAttrs: false });
@@ -144,7 +144,6 @@ const groupedAttrs = computed(() => {
144
144
  initProps,
145
145
  attrs,
146
146
  { class: attrs.componentClass, style: attrs.componentStyle },
147
- { class: initProps.componentClass, style: initProps.componentStyle },
148
147
  { disabled: attrs.disabled ?? parentDisabled.value ?? initProps.disabled },
149
148
  { modelProp: effectiveModelProp }
150
149
  ) as Required<Field>;
@@ -179,12 +178,10 @@ const is = computed(() => {
179
178
  if (teleportSlot) return teleportSlot;
180
179
  if (typeof props.component === 'string') {
181
180
  const resolved =
182
- (customComponents as any)[props.component] ||
181
+ toValue(customComponents as any)?.[props.component] ||
183
182
  (componentMap as any)[props.component];
184
183
  if (resolved) return resolved;
185
- console.warn(
186
- `[pro-components] 未识别的组件类型 "${props.component}",已降级为原生元素渲染。如为自定义组件请在 componentMap 或 ProComponentProvider 中注册。`
187
- );
184
+ warnUnknownComponent(props.component);
188
185
  return props.component;
189
186
  }
190
187
  return props.component;
@@ -39,3 +39,14 @@ export const getInitProps = (
39
39
  }
40
40
  return {};
41
41
  };
42
+
43
+ /** 已告警过的未知组件名(模块级去重,避免 computed 重算导致刷屏) */
44
+ const warnedUnknownComponents = new Set<string>();
45
+
46
+ export function warnUnknownComponent(name: string) {
47
+ if (warnedUnknownComponents.has(name)) return;
48
+ warnedUnknownComponents.add(name);
49
+ console.warn(
50
+ `[pro-components] 未识别的组件类型 "${name}",已降级为原生元素渲染。如为自定义组件请在 componentMap 或 ProComponentProvider 中注册。`
51
+ );
52
+ }
@@ -51,7 +51,8 @@ const props = withDefaults(defineProps<Props>(), {
51
51
  });
52
52
 
53
53
  const validFields = computed(() =>
54
- (props.fields ?? []).filter(field => !field.hidden)
54
+ // hidden 支持 Ref/ComputedRef/getter 等响应式形态(统一使用 toValue 取值)
55
+ (props.fields ?? []).filter(field => !toValue(field.hidden))
55
56
  );
56
57
 
57
58
  useProviderDisabled(computed(() => props.disabled));
@@ -43,12 +43,24 @@
43
43
  * ```
44
44
  */
45
45
  import { Form as AForm, FormProps as AFormProps } from '../../../../shared/ui';
46
- import { computed, inject, mergeProps, provide, toValue, type Slot } from 'vue';
46
+ import {
47
+ computed,
48
+ inject,
49
+ mergeProps,
50
+ provide,
51
+ toValue,
52
+ useAttrs,
53
+ type Slot,
54
+ } from 'vue';
47
55
  import { INJECT_CONFIG } from '../../../component-provider/constants';
48
56
  import { BaseFormItem } from '..';
49
57
  import { InjectionFormKey, InjectionFormSlotsKey } from '../../constants';
50
58
  import type { Grid, VModelProps, PathProps } from '../../types';
51
- import { Path, camelizeProperties } from '../../../../shared/core';
59
+ import {
60
+ Path,
61
+ camelizeProperties,
62
+ createFormProxy,
63
+ } from '../../../../shared/core';
52
64
  import { useForm, type Form } from '../../hooks/useForm';
53
65
 
54
66
  defineOptions({ name: 'ProForm', inheritAttrs: false });
@@ -73,27 +85,9 @@ const currentForm = computed(
73
85
 
74
86
  /**
75
87
  * 表单实例代理:操作全部转发至 currentForm 当前实例;
76
- * 下游持有本代理即可,:form 运行期替换无需重绑。
88
+ * 下游持有本代理即可,:form 运行期替换无需重绑;方法具有引用记忆化。
77
89
  */
78
- const formProxy = new Proxy({} as F, {
79
- get(_, prop) {
80
- const target = currentForm.value as any;
81
- const val = target?.[prop];
82
- if (typeof val === 'function') {
83
- return (...args: any[]) => (currentForm.value as any)?.[prop]?.(...args);
84
- }
85
- return val;
86
- },
87
- set(_, prop, value) {
88
- if (currentForm.value) {
89
- (currentForm.value as any)[prop] = value;
90
- }
91
- return true;
92
- },
93
- has(_, prop) {
94
- return Boolean(currentForm.value && prop in currentForm.value);
95
- },
96
- });
90
+ const formProxy = createFormProxy(() => currentForm.value);
97
91
 
98
92
  provide(InjectionFormKey, formProxy);
99
93
 
@@ -117,6 +111,8 @@ const formKey = computed(() => getFormKey(currentForm.value as any));
117
111
  const config = INJECT_CONFIG['pro-form'];
118
112
  const injectFormConfig = inject(config.injectionKey, config.default);
119
113
 
114
+ const attrs = useAttrs();
115
+
120
116
  /**
121
117
  * 从 ProComponentProvider 获取全局配置,响应式派生以支持动态配置变更
122
118
  */
@@ -127,6 +123,10 @@ const injectAttrs = computed(() => {
127
123
  return rest;
128
124
  });
129
125
 
126
+ const formAttrs = computed(() => {
127
+ return mergeProps(injectAttrs.value, camelizeProperties(attrs));
128
+ });
129
+
130
130
  type ExtractPath<T> = T extends Form<infer D> ? Path<D> : string;
131
131
  type FieldSlotProps = VModelProps &
132
132
  PathProps & { disabled?: boolean; [x: string]: any };
@@ -146,7 +146,7 @@ provide(InjectionFormSlotsKey, slots);
146
146
  :key="formKey"
147
147
  :ref="setFormRef"
148
148
  :model="formData"
149
- v-bind="mergeProps(injectAttrs, camelizeProperties($attrs))"
149
+ v-bind="formAttrs"
150
150
  class="pro-form"
151
151
  >
152
152
  <BaseFormItem :fields="fields" :grid="props.grid" />
@@ -14,6 +14,9 @@ const formItemPropKeys = Object.keys(formItemProps()).concat([
14
14
  'formItemContainer',
15
15
  ]);
16
16
  const gridItemPropKeys = Object.keys(gridItemProps());
17
+ // 模块级 Set:字段循环内 O(1) 命中,替代数组 includes 线性扫描
18
+ const gridItemPropKeySet = new Set<string>(gridItemPropKeys);
19
+ const formItemPropKeySet = new Set<string>(formItemPropKeys);
17
20
 
18
21
  export interface GroupedField {
19
22
  path: string;
@@ -60,6 +63,7 @@ export function useGroupFieldAttrs(validFields: ComputedRef<Field[]>) {
60
63
  lg,
61
64
  xl,
62
65
  xxl,
66
+ formItemContainer: injectFormItemContainer,
63
67
  ...injectRest
64
68
  } = rawInject;
65
69
 
@@ -70,6 +74,8 @@ export function useGroupFieldAttrs(validFields: ComputedRef<Field[]>) {
70
74
  : { xs, sm, md, lg, xl, xxl, span: injectSpan };
71
75
 
72
76
  gridItemProps = fields ? { span: span ?? 24 } : initGridItemProps;
77
+ // 字段级容器优先,回退注入级配置
78
+ const container = formItemContainer ?? injectFormItemContainer;
73
79
  formItemProps = mergeProps(
74
80
  injectRest,
75
81
  { class: injectClassName, style: injectStyle },
@@ -78,9 +84,9 @@ export function useGroupFieldAttrs(validFields: ComputedRef<Field[]>) {
78
84
  );
79
85
 
80
86
  Object.keys(rest).forEach(k => {
81
- if (gridItemPropKeys.includes(k)) {
87
+ if (gridItemPropKeySet.has(k)) {
82
88
  gridItemProps[k] = rest[k];
83
- } else if (formItemPropKeys.includes(k)) {
89
+ } else if (formItemPropKeySet.has(k)) {
84
90
  formItemProps[k] = rest[k];
85
91
  } else {
86
92
  componentProps[k] = rest[k];
@@ -106,7 +112,7 @@ export function useGroupFieldAttrs(validFields: ComputedRef<Field[]>) {
106
112
  formItemProps: formItemProps as any,
107
113
  formItemSlots,
108
114
  componentProps,
109
- formItemContainer,
115
+ formItemContainer: container,
110
116
  rawField: field,
111
117
  };
112
118
  }
@@ -7,7 +7,7 @@ import {
7
7
  MenuItem,
8
8
  Checkbox,
9
9
  } from '../../../shared/ui';
10
- import { computed, onMounted, ref, watch } from 'vue';
10
+ import { computed, ref, watch } from 'vue';
11
11
  import type { Columns, ColumnControlConfig } from '../types';
12
12
  import { type Table } from '../hooks/useTable';
13
13
  import FilterOutlined from './icons/FilterOutlined.vue';
@@ -46,7 +46,11 @@ const checkedColumnsOptions = computed<
46
46
  : item.dataIndex);
47
47
  if (!rawKey || !item.title) return [];
48
48
  const key = String(rawKey);
49
- if (props.columnControl?.excludedKeys?.some(ek => String(ek) === key))
49
+ // 默认排除内部序号列 __INDEX__ 及显式指定的 excludedKeys
50
+ if (
51
+ key === '__INDEX__' ||
52
+ props.columnControl?.excludedKeys?.some(ek => String(ek) === key)
53
+ )
50
54
  return [];
51
55
  const disabled =
52
56
  props.columnControl?.disabledKeys?.some(dk => String(dk) === key) ??
@@ -121,13 +125,7 @@ watch(
121
125
  { immediate: true }
122
126
  );
123
127
 
124
- // 强制 disabledKeys 列始终展示
125
- onMounted(() => {
126
- props.columnControl?.disabledKeys?.forEach(key => {
127
- props.table?.setColumn?.(String(key), { hidden: false });
128
- });
129
- });
130
-
128
+ // disabledKeys 指定的列始终强制展示
131
129
  watch(
132
130
  () => props.columnControl?.disabledKeys,
133
131
  keys => {
@@ -135,7 +133,7 @@ watch(
135
133
  props.table?.setColumn?.(String(key), { hidden: false });
136
134
  });
137
135
  },
138
- { deep: true }
136
+ { immediate: true, deep: true }
139
137
  );
140
138
  </script>
141
139
 
@@ -74,6 +74,8 @@ import { Column, Columns, ColumnControlConfig } from '../types';
74
74
 
75
75
  defineOptions({ name: 'ProTable', inheritAttrs: false });
76
76
 
77
+ const tableProperties = Object.keys(tableProps());
78
+
77
79
  type Control = {
78
80
  sizeControl: boolean;
79
81
  columnControl: boolean | ColumnControlConfig<Path<RecordType>>;
@@ -119,8 +121,6 @@ const config = INJECT_CONFIG['pro-table'];
119
121
  const injectPropsRaw = inject(config.injectionKey, config.default);
120
122
  const injectProps = computed(() => toValue(injectPropsRaw) || {});
121
123
 
122
- const tableProperties = Object.keys(tableProps());
123
-
124
124
  const injectAttrs = computed<TableProps>(
125
125
  () => pick(injectProps.value, tableProperties) as TableProps
126
126
  );
@@ -145,14 +145,17 @@ const tableAttrs = computed<TableProps>(() => {
145
145
  const size = defineModel<TableProps['size']>('size');
146
146
  const loading = defineModel<boolean>('loading', { default: false });
147
147
 
148
- // 核心搜索方法:设置 loading 状态,调用外部 search 函数
148
+ // 递增序号做请求竞态守卫,仅最新一次请求可变更 loading
149
+ let searchSequence = 0;
149
150
  const _search = async () => {
151
+ const seq = ++searchSequence;
150
152
  const searchPromise = (props.search || attrs.onSearch)?.();
151
- if (isPromise(searchPromise)) {
152
- loading.value = true;
153
- try {
154
- await searchPromise;
155
- } finally {
153
+ if (!isPromise(searchPromise)) return;
154
+ loading.value = true;
155
+ try {
156
+ await searchPromise;
157
+ } finally {
158
+ if (seq === searchSequence) {
156
159
  loading.value = false;
157
160
  }
158
161
  }
@@ -166,8 +169,15 @@ const reset = () => {
166
169
  });
167
170
  };
168
171
 
172
+ const customSlotNames = [
173
+ 'search-form',
174
+ 'button-bar',
175
+ 'toolbar',
176
+ 'table',
177
+ ] as const;
178
+
169
179
  type CustomSlots = Readonly<
170
- Partial<Record<'search-form' | 'button-bar' | 'toolbar' | 'table', Slot>>
180
+ Partial<Record<(typeof customSlotNames)[number], Slot>>
171
181
  >;
172
182
  type TableSlots = Omit<ComponentSlots<typeof ATable>, 'bodyCell'> &
173
183
  Readonly<{
@@ -181,14 +191,30 @@ type TableSlots = Omit<ComponentSlots<typeof ATable>, 'bodyCell'> &
181
191
  type Slots = Omit<TableSlots & CustomSlots, 'default'>;
182
192
 
183
193
  const slots = defineSlots<Slots>();
184
- const {
185
- 'search-form': searchFormSlot,
186
- 'button-bar': buttonBarSlot,
187
- toolbar: toolbarSlot,
188
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
189
- table: tableSlot,
190
- ...tableSlots
191
- } = slots;
194
+ const forwardedSlotNames = () =>
195
+ (Object.keys(slots) as Array<Extract<keyof Slots, string>>).filter(
196
+ name => !customSlotNames.includes(name as any)
197
+ );
198
+
199
+ const columnRequiredSlotNames = new Set([
200
+ 'bodyCell',
201
+ 'headerCell',
202
+ 'customFilterDropdown',
203
+ 'customFilterIcon',
204
+ ]);
205
+
206
+ /**
207
+ * 判定插槽是否具备渲染条件(守卫过渡状态或空列下 column 为 undefined 的情况)
208
+ * 当列被动态隐藏或所有列均隐藏时,旧单元格销毁过渡帧或空占位中 column 可能为 undefined,
209
+ * 此时直接阻断依赖 column 的业务插槽调用,防止访问 column 属性抛出 TypeError;
210
+ * 非列依赖的表格级插槽(如 emptyText、footer、summary 等)始终正常渲染。
211
+ */
212
+ const isSlotRenderable = (name: string, scoped: any) => {
213
+ if (columnRequiredSlotNames.has(name)) {
214
+ return visibleComputedColumns.value.length > 0 && Boolean(scoped?.column);
215
+ }
216
+ return true;
217
+ };
192
218
 
193
219
  const searchPage1st = () => {
194
220
  props.table?.setPageParam?.({ current: 1 });
@@ -215,14 +241,23 @@ const computedTableContainer = computed(() => {
215
241
  type ReturnGenericParameterTypes<V> = V extends Table<any, infer R> ? R : never;
216
242
  type RecordType = ReturnGenericParameterTypes<T>;
217
243
 
218
- const renderIndex: ColumnType['customRender'] = ({ index }) => index + 1;
244
+ // 序号列随分页偏移:第 n 页首行序号 = (n-1)*pageSize + i + 1(无分页时退化为 index+1)
245
+ const getIndex = (i: number) => {
246
+ const pageParam = props.table?.pageParam;
247
+ if (pageParam && computedPagination.value !== false) {
248
+ const current = pageParam.current ?? 1;
249
+ const pageSize = pageParam.pageSize ?? 10;
250
+ return (current - 1) * pageSize + i + 1;
251
+ }
252
+ return i + 1;
253
+ };
219
254
 
220
255
  const indexColumn = computed<ColumnType>(() => ({
221
256
  title: t('table.index'),
222
- dataIndex: '_index',
223
- key: '_index',
257
+ dataIndex: '__INDEX__',
258
+ key: '__INDEX__',
224
259
  width: 80,
225
- customRender: renderIndex,
260
+ customRender: ({ index }) => getIndex(index),
226
261
  }));
227
262
 
228
263
  const computedColumns = computed<Columns<RecordType>>(() => {
@@ -275,15 +310,14 @@ const onTableChange: TableProps['onChange'] = (...args) => {
275
310
  _search();
276
311
  };
277
312
 
278
- const showSearch = computed(() => {
313
+ const searchFormVisible = computed(() => {
279
314
  const searchFields = props.table?.searchForm?.fields;
280
315
  const fieldList =
281
316
  (Array.isArray(searchFields) ? searchFields : searchFields?.value) ?? [];
282
317
  return !!(
283
- searchFormSlot ||
284
- (computedSearchFormConfig.value?.hidden !== true &&
285
- props.table?.searchForm &&
286
- fieldList.filter(item => !item.hidden).length > 0)
318
+ computedSearchFormConfig.value?.hidden !== true &&
319
+ props.table?.searchForm &&
320
+ fieldList.filter(item => !toValue(item.hidden)).length > 0
287
321
  );
288
322
  });
289
323
 
@@ -314,12 +348,17 @@ onMounted(() => {
314
348
  _search();
315
349
  }
316
350
  });
351
+
352
+ defineExpose({
353
+ /** 手动触发一次查询(与内部搜索共用 loading 竞态守卫),便于外部刷新列表 */
354
+ search: _search,
355
+ });
317
356
  </script>
318
357
 
319
358
  <template>
320
359
  <div class="pro-table" :class="attrs.class" :style="attrs.style">
321
360
  <ContainerFragment
322
- v-if="showSearch"
361
+ v-if="searchFormVisible || $slots['search-form']"
323
362
  :component="computedSearchFormConfig.container"
324
363
  >
325
364
  <slot name="search-form">
@@ -335,10 +374,10 @@ onMounted(() => {
335
374
 
336
375
  <ContainerFragment :component="computedTableContainer">
337
376
  <div class="pro-table_header">
338
- <div v-if="buttonBarSlot" class="pro-table_header_button-bar">
377
+ <div v-if="$slots['button-bar']" class="pro-table_header_button-bar">
339
378
  <slot name="button-bar" />
340
379
  </div>
341
- <div v-if="toolbarSlot" class="pro-table_header_toolbar">
380
+ <div v-if="$slots['toolbar']" class="pro-table_header_toolbar">
342
381
  <slot name="toolbar" />
343
382
  </div>
344
383
  <div
@@ -371,11 +410,15 @@ onMounted(() => {
371
410
  @change="onTableChange"
372
411
  >
373
412
  <template
374
- v-for="(_, name) of tableSlots"
413
+ v-for="name of forwardedSlotNames()"
375
414
  :key="name"
376
415
  #[name]="scoped"
377
416
  >
378
- <slot :name="name" v-bind="scoped" />
417
+ <slot
418
+ v-if="isSlotRenderable(name, scoped)"
419
+ :name="name"
420
+ v-bind="scoped"
421
+ />
379
422
  </template>
380
423
  </ATable>
381
424
  </slot>