@aspire-ui/element-component-pro 1.0.28 → 1.0.29

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/dist/index.d.ts CHANGED
@@ -3316,6 +3316,8 @@ declare const _default: {
3316
3316
  getModelValue: () => Record<string, unknown>[];
3317
3317
  setModelValue: (val: Record<string, unknown>[]) => void;
3318
3318
  getFormRef: () => import('./types').FormInstance | null;
3319
+ getRow: (index: number) => Record<string, unknown>;
3320
+ setRow: (index: number, row: Record<string, unknown>) => void;
3319
3321
  }> & import('vue/types/v3-component-options').ExtractComputedReturns<{}> & import('vue').ComponentCustomProperties & Readonly<import('vue').ExtractPropTypes<{
3320
3322
  disabled: {
3321
3323
  type: import('vue').PropType<boolean>;
@@ -3527,6 +3529,8 @@ declare const _default: {
3527
3529
  getModelValue: () => Record<string, unknown>[];
3528
3530
  setModelValue: (val: Record<string, unknown>[]) => void;
3529
3531
  getFormRef: () => import('./types').FormInstance | null;
3532
+ getRow: (index: number) => Record<string, unknown>;
3533
+ setRow: (index: number, row: Record<string, unknown>) => void;
3530
3534
  }, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {
3531
3535
  "update:modelValue": (v: Record<string, unknown>[]) => void;
3532
3536
  "add-row": () => void;
@@ -304,7 +304,7 @@ export interface ProTableFormColumn {
304
304
  /**
305
305
  * 透传给单元格组件。`component === 'formatted-number'` 时在此传入
306
306
  * `integerDigits`、`decimalPlaces`、`rounding`、`inputLimit` 等。
307
- * 支持函数形式,参数为 { row, value, column, action },返回要合并到组件上的属性。
307
+ * 支持函数形式,参数为 { row, value, column, index, formActionType },返回要合并到组件上的属性。
308
308
  */
309
309
  componentProps?: Record<string, unknown> | ((params: CellComponentPropsParams) => Record<string, unknown>);
310
310
  /** 动态校验规则 */
@@ -360,7 +360,7 @@ export interface ProTableFormColumnChild {
360
360
  /**
361
361
  * 透传给单元格组件。`component === 'formatted-number'` 时在此传入
362
362
  * `integerDigits`、`decimalPlaces`、`rounding`、`inputLimit` 等。
363
- * 支持函数形式,参数为 { row, value, column, action },返回要合并到组件上的属性。
363
+ * 支持函数形式,参数为 { row, value, column, index, formActionType },返回要合并到组件上的属性。
364
364
  */
365
365
  componentProps?: Record<string, unknown> | ((params: CellComponentPropsParams) => Record<string, unknown>);
366
366
  rules?: unknown[];
@@ -478,12 +478,18 @@ export interface ProTableFormActionType {
478
478
  setModelValue: (val: Record<string, unknown>[]) => void;
479
479
  /** 获取 el-form 实例(可用于滚动、聚焦等高级操作) */
480
480
  getFormRef: () => FormInstance | null;
481
+ /** 获取指定行 */
482
+ getRow: (index: number) => Record<string, unknown>;
483
+ /** 设置指定行 */
484
+ setRow: (index: number, row: Record<string, unknown>) => void;
481
485
  }
482
486
  /** componentProps 函数的参数类型 */
483
487
  export interface CellComponentPropsParams {
484
488
  row: Record<string, unknown>;
485
489
  value: unknown;
490
+ /** 当前单元格所在行的索引 */
491
+ index?: number;
486
492
  column: ProTableFormColumn | ProTableFormColumnChild;
487
- /** ProTableForm 操作实例,可调用 validate、addRow、removeRow 等 */
488
- action: ProTableFormActionType;
493
+ /** ProTableForm 操作实例 */
494
+ formActionType: ProTableFormActionType;
489
495
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aspire-ui/element-component-pro",
3
- "version": "1.0.28",
3
+ "version": "1.0.29",
4
4
  "description": "Element UI 二次封装组件库,基于 Vue 2.7 + TypeScript + setup 语法糖,实现 VbenAdmin 风格的 Pro 组件",
5
5
  "type": "module",
6
6
  "main": "./dist/element-component-pro.umd.js",
@@ -384,6 +384,7 @@ const updateSchema = async (data: Partial<ProFormSchema> | Partial<ProFormSchema
384
384
  const idx = innerSchemas.value.findIndex((s) => s.field === item.field)
385
385
  if (idx >= 0) innerSchemas.value[idx] = { ...innerSchemas.value[idx], ...item }
386
386
  })
387
+ initForm()
387
388
  }
388
389
 
389
390
  const appendSchemaByField = async (schema: ProFormSchema, prefixField?: string, first?: boolean) => {
@@ -4,7 +4,7 @@
4
4
  v-if="col.component === 'select'"
5
5
  :value="value"
6
6
  v-bind="cellBind"
7
- :placeholder="placeholder"
7
+ :placeholder="cellBind.placeholder || placeholder"
8
8
  v-on="mergedEvents('change', 'clear')"
9
9
  >
10
10
  <el-option
@@ -50,7 +50,7 @@
50
50
  end-placeholder="结束日期"
51
51
  value-format="yyyy-MM-dd"
52
52
  v-bind="cellBind"
53
- :placeholder="placeholder"
53
+ :placeholder="cellBind.placeholder || placeholder"
54
54
  v-on="mergedEvents('change')"
55
55
  />
56
56
  <!-- api-select -->
@@ -58,7 +58,7 @@
58
58
  v-else-if="col.component === 'api-select'"
59
59
  :value="value"
60
60
  v-bind="cellBind"
61
- :placeholder="placeholder"
61
+ :placeholder="cellBind.placeholder || placeholder"
62
62
  v-on="mergedEvents('change')"
63
63
  />
64
64
  <!-- tree-select -->
@@ -66,7 +66,7 @@
66
66
  v-else-if="col.component === 'tree-select'"
67
67
  :value="value"
68
68
  v-bind="cellBind"
69
- :placeholder="placeholder"
69
+ :placeholder="cellBind.placeholder || placeholder"
70
70
  v-on="mergedEvents('change')"
71
71
  />
72
72
  <!-- 其余 el-* 组件(input / input-number / formatted-number / date-picker / switch / cascader) -->
@@ -75,13 +75,13 @@
75
75
  :is="cellComp"
76
76
  :value="value"
77
77
  v-bind="cellBind"
78
- :placeholder="placeholder"
79
- v-on="mergedEvents('input')"
78
+ :placeholder="cellBind.placeholder || placeholder"
79
+ v-on="mergedEvents('input', 'change')"
80
80
  />
81
81
  </template>
82
82
 
83
83
  <script setup lang="ts">
84
- import { computed } from 'vue'
84
+ import { computed, nextTick } from 'vue'
85
85
  import ApiSelect from '../ProForm/ApiSelect.vue'
86
86
  import TreeSelect from '../ProForm/TreeSelect.vue'
87
87
  import FormattedNumberInput from '../ProForm/FormattedNumberInput.vue'
@@ -90,12 +90,14 @@ import type { ProTableFormColumn, ProTableFormColumnChild, ProTableFormActionTyp
90
90
  const props = defineProps<{
91
91
  col: ProTableFormColumn | ProTableFormColumnChild
92
92
  value: unknown
93
- /** 当前行数据,用于 dynamicComponentProps 动态求值 */
93
+ /** 当前行数据,用于 componentProps 动态求值 */
94
94
  row?: Record<string, unknown>
95
+ /** 当前行索引 */
96
+ index?: number
95
97
  size?: 'medium' | 'small' | 'large'
96
98
  placeholder?: string
97
99
  /** ProTableForm 操作实例 */
98
- action?: ProTableFormActionType
100
+ formActionType?: ProTableFormActionType
99
101
  }>()
100
102
 
101
103
  const emit = defineEmits<{ (e: 'update', v: unknown): void }>()
@@ -119,23 +121,54 @@ const cellComp = computed(() => {
119
121
  return map[props.col.component as string] || 'el-input'
120
122
  })
121
123
 
122
- /** All v-bind props, with onXxx event handlers stripped out */
123
- const cellBind = computed<Record<string, unknown>>(() => {
124
- let staticProps: Record<string, unknown> = {}
125
- let dynamicProps: Record<string, unknown> = {}
124
+ /**
125
+ * componentProps 求值结果缓存(仅在 props 变化时重新计算)。
126
+ * cellBind cellEvents 都从同一个缓存中读取,保证求值只发生一次,
127
+ * 避免同一渲染周期中生成两份不同的 handler 闭包导致双重触发。
128
+ */
129
+ const componentPropsResult = computed<{
130
+ bind: Record<string, unknown>
131
+ /** 用户 componentProps 中的事件处理器(onXxx → xxx),尚未与 emit 合并 */
132
+ userEvents: Record<string, (...args: unknown[]) => unknown>
133
+ }>(() => {
134
+ let raw: Record<string, unknown> = {}
126
135
 
127
- const cp = props.col.componentProps
128
- if (typeof cp === 'function') {
129
- dynamicProps = cp({ row: props.row ?? {}, value: props.value, column: props.col as any, action: props.action as any })
136
+ if (typeof props.col.componentProps === 'function') {
137
+ const row = props.row ?? {} as Record<string, unknown>
138
+ const formActionType = props.formActionType as ProTableFormActionType
139
+ raw = props.col.componentProps({
140
+ row,
141
+ value: props.value,
142
+ index: props.index,
143
+ column: props.col as never,
144
+ formActionType,
145
+ })
130
146
  } else {
131
- staticProps = cp ?? {}
147
+ raw = props.col.componentProps ?? {}
132
148
  }
133
149
 
134
- const base: Record<string, unknown> = { size: props.size }
135
- for (const [key, val] of Object.entries({ ...staticProps, ...dynamicProps })) {
136
- if (/^on[A-Za-z]/.test(key) && typeof val === 'function') continue
137
- base[key] = val
150
+ const bind: Record<string, unknown> = {}
151
+ const userEvents: Record<string, (...args: unknown[]) => unknown> = {}
152
+
153
+ for (const [key, val] of Object.entries(raw)) {
154
+ if (/^on[A-Za-z]/.test(key) && typeof val === 'function') {
155
+ const eventName = key[2].toLowerCase() + key.slice(3)
156
+ userEvents[eventName] = val as (...args: unknown[]) => unknown
157
+ } else {
158
+ bind[key] = val
159
+ }
138
160
  }
161
+
162
+ return { bind, userEvents }
163
+ })
164
+
165
+ /** v-bind 的属性(排除 onXxx 事件) */
166
+ const cellBind = computed<Record<string, unknown>>(() => {
167
+ void props.value // 追踪响应式
168
+ void props.row // 追踪响应式
169
+ void props.formActionType // 追踪响应式
170
+
171
+ const base: Record<string, unknown> = { size: props.size, ...componentPropsResult.value.bind }
139
172
  if (props.col.component === 'formatted-number') {
140
173
  return { integerDigits: 5, decimalPlaces: 6, rounding: 'round', inputLimit: true, ...base }
141
174
  }
@@ -147,35 +180,17 @@ const cellBind = computed<Record<string, unknown>>(() => {
147
180
  return base
148
181
  })
149
182
 
150
- /**
151
- * Event handlers from componentProps (onXxx → xxx).
152
- * componentProps 中的 onChange/onInput 等会经过 v-on 绑定,
153
- * 不再通过 v-bind 直接作为 DOM 属性展开,避免触发 el-form 整行重校验。
154
- */
183
+ /** componentProps 中的事件处理器(onXxx → xxx) */
155
184
  const cellEvents = computed<Record<string, (...args: unknown[]) => unknown>>(() => {
156
- let staticProps: Record<string, unknown> = {}
157
- let dynamicProps: Record<string, unknown> = {}
158
-
159
- const cp = props.col.componentProps
160
- if (typeof cp === 'function') {
161
- dynamicProps = cp({ row: props.row ?? {}, value: props.value, column: props.col as any, action: props.action as any })
162
- } else {
163
- staticProps = cp ?? {}
164
- }
165
-
166
- const events: Record<string, (...args: unknown[]) => unknown> = {}
167
- for (const [key, val] of Object.entries({ ...staticProps, ...dynamicProps })) {
168
- if (/^on[A-Za-z]/.test(key) && typeof val === 'function') {
169
- const eventName = key[2].toLowerCase() + key.slice(3)
170
- events[eventName] = val as (...args: unknown[]) => unknown
171
- }
172
- }
173
- return events
185
+ void props.value // 追踪响应式
186
+ void props.row // 追踪响应式
187
+ void props.formActionType // 追踪响应式
188
+ return componentPropsResult.value.userEvents
174
189
  })
175
190
 
176
191
  /**
177
- * Merges cellEvents (from componentProps) with the internal emit bridge.
178
- * componentProps listeners fire first, then emit('update') updates the row value.
192
+ * 合并 cellEvents 与内部 emit('update')
193
+ * componentProps handler 先执行(可调用 formActionType.setModelValue 做联动),再 emit('update') 更新行值。
179
194
  * clear 事件特殊处理:用户 handler 先执行,再 emit(undefined) 清空值。
180
195
  */
181
196
  const mergedEvents = (...internalEvents: Array<'input' | 'change' | 'clear'>) => {
@@ -183,8 +198,11 @@ const mergedEvents = (...internalEvents: Array<'input' | 'change' | 'clear'>) =>
183
198
  for (const internalEvent of internalEvents) {
184
199
  const userHandler = cellEvents.value[internalEvent]
185
200
  handlers[internalEvent] = (arg: unknown) => {
186
- if (userHandler) userHandler(arg)
201
+ // if (userHandler) userHandler(arg)
187
202
  emit('update', internalEvent === 'clear' ? undefined : arg)
203
+ nextTick(()=>{
204
+ if (userHandler) userHandler(arg)
205
+ })
188
206
  }
189
207
  }
190
208
  return handlers
@@ -124,9 +124,10 @@
124
124
  :col="child"
125
125
  :value="getCellValue(slotProps.row, col, child.key)"
126
126
  :row="slotProps.row"
127
+ :index="slotProps.$index"
127
128
  :size="size"
128
129
  :placeholder="col.placeholder || metricPlaceholder"
129
- :action="action"
130
+ :formActionType="action"
130
131
  @update="setCellValue(slotProps.row, col, child.key, $event)"
131
132
  />
132
133
  </el-form-item>
@@ -203,9 +204,10 @@
203
204
  :col="col"
204
205
  :value="getCellValue(slotProps.row, col)"
205
206
  :row="slotProps.row"
207
+ :index="slotProps.$index"
206
208
  :size="size"
207
209
  :placeholder="col.placeholder || metricPlaceholder"
208
- :action="action"
210
+ :formActionType="action"
209
211
  @update="setCellValue(slotProps.row, col, undefined, $event)"
210
212
  />
211
213
  </el-form-item>
@@ -363,6 +365,8 @@ const {
363
365
  setCellValue,
364
366
  handleAddRow,
365
367
  handleRemoveRow,
368
+ getRow,
369
+ setRow,
366
370
  validate,
367
371
  clearValidate,
368
372
  } = useProTableForm({
@@ -412,6 +416,8 @@ const action = {
412
416
  getModelValue: () => [...currentModelValue.value],
413
417
  setModelValue: (val: Record<string, unknown>[]) => emit('update:modelValue', val),
414
418
  getFormRef: () => formRef.value,
419
+ getRow,
420
+ setRow,
415
421
  }
416
422
 
417
423
  defineExpose(action)
@@ -61,6 +61,10 @@ export interface UseProTableFormReturn {
61
61
  handleAddRow: () => void
62
62
  handleRemoveRow: (index: number) => void
63
63
 
64
+ // --- 行读写(供 action 暴露) ---
65
+ getRow: (index: number) => Record<string, unknown>
66
+ setRow: (index: number, row: Record<string, unknown>) => void
67
+
64
68
  // --- el-form 实例方法 ---
65
69
  validate: () => Promise<boolean>
66
70
  clearValidate: (propsArg?: string | string[]) => void
@@ -205,6 +209,23 @@ export function useProTableForm(options: ProTableFormOptions): UseProTableFormRe
205
209
  emitNext(next)
206
210
  }
207
211
 
212
+ /**
213
+ * 按索引获取行数据。
214
+ */
215
+ function getRow(index: number): Record<string, unknown> {
216
+ return currentModelValue.value[index] ?? {}
217
+ }
218
+
219
+ /**
220
+ * 按索引替换行数据(触发 update:modelValue)。
221
+ */
222
+ function setRow(index: number, row: Record<string, unknown>): void {
223
+ if (index < 0 || index >= currentModelValue.value.length) return
224
+ const next = cloneRows()
225
+ next[index] = row
226
+ emitNext(next)
227
+ }
228
+
208
229
  const canDeleteRow = computed(() => {
209
230
  return currentModelValue.value.length > (props.minRows ?? 0)
210
231
  })
@@ -435,6 +456,10 @@ export function useProTableForm(options: ProTableFormOptions): UseProTableFormRe
435
456
  handleAddRow,
436
457
  handleRemoveRow,
437
458
 
459
+ // 行读写
460
+ getRow,
461
+ setRow,
462
+
438
463
  // el-form 实例方法
439
464
  validate,
440
465
  clearValidate,
@@ -350,7 +350,7 @@ export interface ProTableFormColumn {
350
350
  /**
351
351
  * 透传给单元格组件。`component === 'formatted-number'` 时在此传入
352
352
  * `integerDigits`、`decimalPlaces`、`rounding`、`inputLimit` 等。
353
- * 支持函数形式,参数为 { row, value, column, action },返回要合并到组件上的属性。
353
+ * 支持函数形式,参数为 { row, value, column, index, formActionType },返回要合并到组件上的属性。
354
354
  */
355
355
  componentProps?: Record<string, unknown> | ((params: CellComponentPropsParams) => Record<string, unknown>)
356
356
  /** 动态校验规则 */
@@ -407,7 +407,7 @@ export interface ProTableFormColumnChild {
407
407
  /**
408
408
  * 透传给单元格组件。`component === 'formatted-number'` 时在此传入
409
409
  * `integerDigits`、`decimalPlaces`、`rounding`、`inputLimit` 等。
410
- * 支持函数形式,参数为 { row, value, column, action },返回要合并到组件上的属性。
410
+ * 支持函数形式,参数为 { row, value, column, index, formActionType },返回要合并到组件上的属性。
411
411
  */
412
412
  componentProps?: Record<string, unknown> | ((params: CellComponentPropsParams) => Record<string, unknown>)
413
413
  rules?: unknown[]
@@ -515,14 +515,20 @@ export interface ProTableFormActionType {
515
515
  setModelValue: (val: Record<string, unknown>[]) => void
516
516
  /** 获取 el-form 实例(可用于滚动、聚焦等高级操作) */
517
517
  getFormRef: () => FormInstance | null
518
+ /** 获取指定行 */
519
+ getRow: (index: number) => Record<string, unknown>
520
+ /** 设置指定行 */
521
+ setRow: (index: number, row: Record<string, unknown>) => void
518
522
  }
519
523
 
520
524
  /** componentProps 函数的参数类型 */
521
525
  export interface CellComponentPropsParams {
522
526
  row: Record<string, unknown>
523
527
  value: unknown
528
+ /** 当前单元格所在行的索引 */
529
+ index?: number
524
530
  column: ProTableFormColumn | ProTableFormColumnChild
525
- /** ProTableForm 操作实例,可调用 validate、addRow、removeRow 等 */
526
- action: ProTableFormActionType
531
+ /** ProTableForm 操作实例 */
532
+ formActionType: ProTableFormActionType
527
533
  }
528
534