@aspire-ui/element-component-pro 1.0.13 → 1.0.15

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.
@@ -0,0 +1,555 @@
1
+ <template>
2
+ <div class="ecp-pro-table-form">
3
+ <el-form
4
+ ref="formRef"
5
+ :model="modelValue"
6
+ :rules="mergedRules"
7
+ :label-width="labelWidth"
8
+ class="ecp-pro-table-form__form"
9
+ >
10
+ <el-table
11
+ :data="tableRows"
12
+ :border="bordered"
13
+ :row-key="rowKeyFn"
14
+ header-cell-class-name="ecp-pro-table-form__header-cell"
15
+ class="ecp-pro-table-form__table"
16
+ >
17
+ <!-- 首列:维度 / 友商名称(可插槽自定义) -->
18
+ <el-table-column
19
+ v-if="showFirstColumnComputed"
20
+ :min-width="firstColMinWidth"
21
+ :fixed="firstColumnFixed"
22
+ >
23
+ <template #header>
24
+ <slot name="firstColumnHeader">
25
+ <span class="ecp-pro-table-form__th-text">
26
+ <span class="ecp-pro-table-form__req">*</span>{{ firstColumnTitle }}
27
+ </span>
28
+ </slot>
29
+ </template>
30
+ <template #default="slotProps">
31
+ <slot name="firstColumn" v-bind="firstColumnScope(slotProps)">
32
+ <template v-if="slotProps.row._type === 'fixed'">
33
+ <span class="ecp-pro-table-form__fixed-label">{{ slotProps.row.rowLabel }}</span>
34
+ </template>
35
+ <el-form-item
36
+ v-else
37
+ :prop="competitorNameProp(slotProps.row._index)"
38
+ class="ecp-pro-table-form__cell-item"
39
+ >
40
+ <el-input
41
+ :value="getCompetitorName(slotProps.row._index)"
42
+ :placeholder="competitorNamePlaceholder"
43
+ @input="setCompetitorName(slotProps.row._index, $event)"
44
+ />
45
+ </el-form-item>
46
+ </slot>
47
+ </template>
48
+ </el-table-column>
49
+
50
+ <!-- 数据列:内置 input / formatted-number 或插槽 cell-{slotName} -->
51
+ <el-table-column
52
+ v-for="col in columns"
53
+ :key="col.key"
54
+ :min-width="col.minWidth || col.width || 120"
55
+ :width="col.width"
56
+ >
57
+ <template #header>
58
+ <slot :name="'header-' + col.key" :column="col">
59
+ <span class="ecp-pro-table-form__th-text">
60
+ <span v-if="col.required" class="ecp-pro-table-form__req">*</span>{{ col.title }}
61
+ </span>
62
+ </slot>
63
+ </template>
64
+ <template #default="slotProps">
65
+ <!-- 完全自定义列 -->
66
+ <template v-if="col.component === 'slot' && col.slotName">
67
+ <el-form-item
68
+ v-if="slotProps.row._type === 'fixed'"
69
+ :prop="fixedMetricProp(slotProps.row.rowKey, col.key)"
70
+ class="ecp-pro-table-form__cell-item"
71
+ >
72
+ <slot
73
+ :name="'cell-' + col.slotName"
74
+ :column="col"
75
+ :row="slotProps.row"
76
+ :value="getCellValue(slotProps.row, col)"
77
+ :update-value="slotUpdateHandler(slotProps, col)"
78
+ />
79
+ </el-form-item>
80
+ <el-form-item
81
+ v-else
82
+ :prop="competitorMetricProp(slotProps.row._index, col.key)"
83
+ class="ecp-pro-table-form__cell-item"
84
+ >
85
+ <slot
86
+ :name="'cell-' + col.slotName"
87
+ :column="col"
88
+ :row="slotProps.row"
89
+ :value="getCellValue(slotProps.row, col)"
90
+ :update-value="slotUpdateHandler(slotProps, col)"
91
+ />
92
+ </el-form-item>
93
+ </template>
94
+ <!-- 内置组件 -->
95
+ <template v-else>
96
+ <el-form-item
97
+ v-if="slotProps.row._type === 'fixed'"
98
+ :prop="fixedMetricProp(slotProps.row.rowKey, col.key)"
99
+ class="ecp-pro-table-form__cell-item"
100
+ >
101
+ <component
102
+ :is="cellComponent(col)"
103
+ :value="getFixedMetric(slotProps.row.rowKey, col.key)"
104
+ v-bind="cellBind(col)"
105
+ :placeholder="col.placeholder || metricPlaceholder"
106
+ @input="setFixedMetric(slotProps.row.rowKey, col.key, $event)"
107
+ />
108
+ </el-form-item>
109
+ <el-form-item
110
+ v-else
111
+ :prop="competitorMetricProp(slotProps.row._index, col.key)"
112
+ class="ecp-pro-table-form__cell-item"
113
+ >
114
+ <component
115
+ :is="cellComponent(col)"
116
+ :value="getCompetitorMetric(slotProps.row._index, col.key)"
117
+ v-bind="cellBind(col)"
118
+ :placeholder="col.placeholder || metricPlaceholder"
119
+ @input="setCompetitorMetric(slotProps.row._index, col.key, $event)"
120
+ />
121
+ </el-form-item>
122
+ </template>
123
+ </template>
124
+ </el-table-column>
125
+
126
+ <!-- 操作列:表头 / 行内均可插槽 -->
127
+ <el-table-column v-if="showActionColumn" v-bind="actionColumnBind">
128
+ <template #header>
129
+ <slot name="actionHeader">
130
+ <span v-if="actionColumn?.title" class="ecp-pro-table-form__action-title">{{ actionColumn.title }}</span>
131
+ <el-button type="text" class="ecp-pro-table-form__add-btn" @click="addCompetitor">
132
+ {{ addCompetitorText }}
133
+ </el-button>
134
+ </slot>
135
+ </template>
136
+ <template #default="slotProps">
137
+ <slot
138
+ name="action"
139
+ :row="slotProps.row"
140
+ :can-delete="canDeleteCompetitor"
141
+ :add-competitor="addCompetitor"
142
+ :remove-competitor="removeCompetitor"
143
+ >
144
+ <el-button
145
+ v-if="slotProps.row._type === 'competitor'"
146
+ type="text"
147
+ class="ecp-pro-table-form__del-btn"
148
+ :disabled="!canDeleteCompetitor"
149
+ @click="removeCompetitor(slotProps.row._index)"
150
+ >
151
+ 删除
152
+ </el-button>
153
+ <el-button v-else type="text" class="ecp-pro-table-form__del-btn" disabled>
154
+ 删除
155
+ </el-button>
156
+ </slot>
157
+ </template>
158
+ </el-table-column>
159
+ </el-table>
160
+ </el-form>
161
+ </div>
162
+ </template>
163
+
164
+ <script lang="ts">
165
+ /**
166
+ * Vue 2 默认 v-model 绑定 value + input;本组件使用 modelValue(与 Vue 3 一致),需显式声明 model。
167
+ */
168
+ export default {
169
+ name: 'ProTableForm',
170
+ model: {
171
+ prop: 'modelValue',
172
+ event: 'update:modelValue',
173
+ },
174
+ }
175
+ </script>
176
+
177
+ <script setup lang="ts">
178
+ import { computed, ref } from 'vue'
179
+ import FormattedNumberInput from '../ProForm/FormattedNumberInput.vue'
180
+ import type { ProTableFormActionColumn, ProTableFormColumn, ProTableFormFixedRow } from './types'
181
+
182
+ const props = withDefaults(
183
+ defineProps<{
184
+ modelValue?: Record<string, unknown>
185
+ columns: ProTableFormColumn[]
186
+ fixedRows: ProTableFormFixedRow[]
187
+ competitorsKey?: string
188
+ competitorNameKey?: string
189
+ firstColumnTitle?: string
190
+ competitorNamePlaceholder?: string
191
+ metricPlaceholder?: string
192
+ addCompetitorText?: string
193
+ minCompetitors?: number
194
+ rules?: Record<string, unknown>
195
+ labelWidth?: string
196
+ bordered?: boolean
197
+ firstColMinWidth?: number
198
+ actionWidth?: number
199
+ showFirstColumn?: boolean
200
+ showActionColumn?: boolean
201
+ actionColumn?: ProTableFormActionColumn
202
+ }>(),
203
+ {
204
+ modelValue: () => ({}),
205
+ competitorsKey: 'competitors',
206
+ competitorNameKey: 'name',
207
+ firstColumnTitle: '维度/友商',
208
+ competitorNamePlaceholder: '请输入友商名称',
209
+ metricPlaceholder: '请输入',
210
+ addCompetitorText: '+新增友商',
211
+ minCompetitors: 0,
212
+ labelWidth: '0',
213
+ bordered: true,
214
+ firstColMinWidth: 160,
215
+ actionWidth: 120,
216
+ showFirstColumn: true,
217
+ showActionColumn: true,
218
+ }
219
+ )
220
+
221
+ const emit = defineEmits<{
222
+ (e: 'update:modelValue', v: Record<string, unknown>): void
223
+ }>()
224
+
225
+ const formRef = ref<{ validate: (cb?: (valid: boolean) => void) => Promise<unknown> | void; clearValidate: (p?: string | string[]) => void } | null>(null)
226
+
227
+ const ck = () => props.competitorsKey ?? 'competitors'
228
+ const nk = () => props.competitorNameKey ?? 'name'
229
+
230
+ /** 有固定行时必须保留首列 */
231
+ const showFirstColumnComputed = computed(() => {
232
+ if (props.fixedRows.length > 0) return true
233
+ return props.showFirstColumn !== false
234
+ })
235
+
236
+ const firstColumnFixed = computed(() => 'left' as const)
237
+
238
+ const actionColumnBind = computed(() => {
239
+ const ac = props.actionColumn
240
+ return {
241
+ width: ac?.width ?? props.actionWidth,
242
+ minWidth: ac?.minWidth,
243
+ align: ac?.align ?? 'center',
244
+ fixed: ac?.fixed === undefined ? 'right' : ac.fixed,
245
+ }
246
+ })
247
+
248
+ function rowKeyFn(row: TableRow) {
249
+ return row._type === 'fixed' ? `f-${row.rowKey}` : `c-${row._index}`
250
+ }
251
+
252
+ type TableRow =
253
+ | { _type: 'fixed'; rowKey: string; rowLabel: string }
254
+ | { _type: 'competitor'; _index: number }
255
+
256
+ const tableRows = computed<TableRow[]>(() => {
257
+ const rows: TableRow[] = []
258
+ props.fixedRows.forEach((fr) => {
259
+ rows.push({
260
+ _type: 'fixed',
261
+ rowKey: fr.rowKey,
262
+ rowLabel: fr.label,
263
+ })
264
+ })
265
+ const mv = props.modelValue
266
+ const list = (mv && typeof mv === 'object' ? (mv[ck()] as Record<string, unknown>[] | undefined) : undefined) ?? []
267
+ list.forEach((_, i) => {
268
+ rows.push({ _type: 'competitor', _index: i })
269
+ })
270
+ return rows
271
+ })
272
+
273
+ const canDeleteCompetitor = computed(() => {
274
+ const mv = props.modelValue
275
+ const n = ((mv && typeof mv === 'object' ? (mv[ck()] as unknown[]) : undefined) ?? []).length
276
+ return n > props.minCompetitors
277
+ })
278
+
279
+ function cloneModel(): Record<string, unknown> {
280
+ const m = props.modelValue
281
+ if (!m || typeof m !== 'object') {
282
+ return {}
283
+ }
284
+ return JSON.parse(JSON.stringify(m)) as Record<string, unknown>
285
+ }
286
+
287
+ function ensureFixedBlock(rowKey: string): Record<string, unknown> {
288
+ const mv = props.modelValue
289
+ if (!mv || typeof mv !== 'object') {
290
+ const o: Record<string, unknown> = {}
291
+ for (const c of props.columns) {
292
+ o[c.key] = ''
293
+ }
294
+ return o
295
+ }
296
+ const m = mv[rowKey]
297
+ if (m && typeof m === 'object' && !Array.isArray(m)) return m as Record<string, unknown>
298
+ const o: Record<string, unknown> = {}
299
+ for (const c of props.columns) {
300
+ o[c.key] = ''
301
+ }
302
+ return o
303
+ }
304
+
305
+ function emitNext(next: Record<string, unknown>) {
306
+ emit('update:modelValue', next)
307
+ }
308
+
309
+ function getFixedMetric(rowKey: string, key: string): unknown {
310
+ const block = ensureFixedBlock(rowKey)
311
+ return block[key] ?? ''
312
+ }
313
+
314
+ function setFixedMetric(rowKey: string, key: string, val: unknown) {
315
+ const next = cloneModel()
316
+ const b = { ...((next[rowKey] as Record<string, unknown>) || {}) }
317
+ b[key] = val
318
+ next[rowKey] = b
319
+ emitNext(next)
320
+ }
321
+
322
+ function competitorList(): Record<string, unknown>[] {
323
+ const mv = props.modelValue
324
+ if (!mv || typeof mv !== 'object') {
325
+ return []
326
+ }
327
+ const list = mv[ck()]
328
+ if (!Array.isArray(list)) return []
329
+ return list as Record<string, unknown>[]
330
+ }
331
+
332
+ function getCompetitorName(index: number): string {
333
+ const row = competitorList()[index]
334
+ const key = nk()
335
+ return row ? String(row[key] ?? '') : ''
336
+ }
337
+
338
+ function setCompetitorName(index: number, val: string) {
339
+ const next = cloneModel()
340
+ const list = [...competitorList()]
341
+ const row = { ...(list[index] || {}) }
342
+ row[nk()] = val
343
+ list[index] = row
344
+ next[ck()] = list
345
+ emitNext(next)
346
+ }
347
+
348
+ function getCompetitorMetric(index: number, key: string): unknown {
349
+ const row = competitorList()[index]
350
+ return row ? row[key] ?? '' : ''
351
+ }
352
+
353
+ function setCompetitorMetric(index: number, key: string, val: unknown) {
354
+ const next = cloneModel()
355
+ const list = [...competitorList()]
356
+ const row = { ...(list[index] || {}) }
357
+ row[key] = val
358
+ list[index] = row
359
+ next[ck()] = list
360
+ emitNext(next)
361
+ }
362
+
363
+ function getCellValue(tableRow: TableRow, col: ProTableFormColumn): unknown {
364
+ if (tableRow._type === 'fixed') {
365
+ return getFixedMetric(tableRow.rowKey, col.key)
366
+ }
367
+ return getCompetitorMetric(tableRow._index, col.key)
368
+ }
369
+
370
+ function setCellValue(tableRow: TableRow, col: ProTableFormColumn, val: unknown) {
371
+ if (tableRow._type === 'fixed') {
372
+ setFixedMetric(tableRow.rowKey, col.key, val)
373
+ } else {
374
+ setCompetitorMetric(tableRow._index, col.key, val)
375
+ }
376
+ }
377
+
378
+ /** 供插槽列 update-value 绑定,避免模板内箭头参数隐式 any */
379
+ function slotUpdateHandler(slotProps: { row: TableRow }, col: ProTableFormColumn) {
380
+ return (v: unknown) => setCellValue(slotProps.row, col, v)
381
+ }
382
+
383
+ function emptyCompetitorRow(): Record<string, unknown> {
384
+ const o: Record<string, unknown> = { [nk()]: '' }
385
+ for (const c of props.columns) {
386
+ o[c.key] = ''
387
+ }
388
+ return o
389
+ }
390
+
391
+ function addCompetitor() {
392
+ const next = cloneModel()
393
+ const list = [...competitorList()]
394
+ list.push(emptyCompetitorRow())
395
+ next[ck()] = list
396
+ emitNext(next)
397
+ }
398
+
399
+ function removeCompetitor(index: number) {
400
+ if (!canDeleteCompetitor.value) return
401
+ const next = cloneModel()
402
+ const list = [...competitorList()]
403
+ list.splice(index, 1)
404
+ next[ck()] = list
405
+ emitNext(next)
406
+ }
407
+
408
+ function fixedMetricProp(rowKey: string, key: string) {
409
+ return `${rowKey}.${key}`
410
+ }
411
+
412
+ function competitorNameProp(index: number) {
413
+ return `${ck()}.${index}.${nk()}`
414
+ }
415
+
416
+ function competitorMetricProp(index: number, key: string) {
417
+ return `${ck()}.${index}.${key}`
418
+ }
419
+
420
+ function cellComponent(col: ProTableFormColumn) {
421
+ return col.component === 'formatted-number' ? FormattedNumberInput : 'el-input'
422
+ }
423
+
424
+ function cellBind(col: ProTableFormColumn): Record<string, unknown> {
425
+ const cp = col.componentProps || {}
426
+ if (col.component === 'formatted-number') {
427
+ return {
428
+ integerDigits: 5,
429
+ decimalPlaces: 6,
430
+ rounding: 'round',
431
+ inputLimit: true,
432
+ ...cp,
433
+ }
434
+ }
435
+ return { ...cp }
436
+ }
437
+
438
+ function firstColumnScope(slotProps: { row: TableRow }) {
439
+ const r = slotProps.row
440
+ if (r._type === 'fixed') {
441
+ return {
442
+ row: r,
443
+ rowType: 'fixed' as const,
444
+ rowKey: r.rowKey,
445
+ rowLabel: r.rowLabel,
446
+ }
447
+ }
448
+ const idx = r._index
449
+ return {
450
+ row: r,
451
+ rowType: 'competitor' as const,
452
+ rowIndex: idx,
453
+ value: getCompetitorName(idx),
454
+ updateValue: (v: string) => setCompetitorName(idx, v),
455
+ }
456
+ }
457
+
458
+ const mergedRules = computed(() => {
459
+ const r: Record<string, unknown[]> = {}
460
+ const req = (title: string) => [{ required: true, message: `请输入${title}`, trigger: 'blur' }]
461
+
462
+ for (const fr of props.fixedRows) {
463
+ for (const col of props.columns) {
464
+ if (col.rules) {
465
+ r[`${fr.rowKey}.${col.key}`] = col.rules as unknown[]
466
+ } else if (col.required) {
467
+ r[`${fr.rowKey}.${col.key}`] = req(col.title)
468
+ }
469
+ }
470
+ }
471
+ const list = competitorList()
472
+ list.forEach((_, i) => {
473
+ r[`${ck()}.${i}.${nk()}`] = req('友商名称')
474
+ for (const col of props.columns) {
475
+ if (col.rules) {
476
+ r[`${ck()}.${i}.${col.key}`] = col.rules as unknown[]
477
+ } else if (col.required) {
478
+ r[`${ck()}.${i}.${col.key}`] = req(col.title)
479
+ }
480
+ }
481
+ })
482
+ return { ...r, ...(props.rules || {}) }
483
+ })
484
+
485
+ function validate(): Promise<boolean> {
486
+ return new Promise((resolve) => {
487
+ const f = formRef.value
488
+ if (!f || typeof f.validate !== 'function') {
489
+ resolve(true)
490
+ return
491
+ }
492
+ f.validate((valid: boolean) => {
493
+ resolve(valid)
494
+ })
495
+ })
496
+ }
497
+
498
+ function clearValidate(propsArg?: string | string[]) {
499
+ formRef.value?.clearValidate?.(propsArg)
500
+ }
501
+
502
+ defineExpose({
503
+ validate,
504
+ clearValidate,
505
+ addCompetitor,
506
+ removeCompetitor,
507
+ })
508
+ </script>
509
+
510
+ <style scoped>
511
+ .ecp-pro-table-form__form :deep(.el-form-item) {
512
+ margin-bottom: 0;
513
+ }
514
+ .ecp-pro-table-form__cell-item {
515
+ width: 100%;
516
+ }
517
+ .ecp-pro-table-form__cell-item :deep(.el-form-item__content) {
518
+ margin-left: 0 !important;
519
+ line-height: normal;
520
+ }
521
+ .ecp-pro-table-form__fixed-label {
522
+ color: #303133;
523
+ font-size: 14px;
524
+ }
525
+ .ecp-pro-table-form__req {
526
+ color: #f56c6c;
527
+ margin-right: 2px;
528
+ }
529
+ .ecp-pro-table-form__th-text {
530
+ font-weight: 500;
531
+ color: #606266;
532
+ }
533
+ .ecp-pro-table-form__action-title {
534
+ margin-right: 8px;
535
+ font-size: 13px;
536
+ color: #606266;
537
+ }
538
+ .ecp-pro-table-form__add-btn {
539
+ padding: 0;
540
+ font-size: 14px;
541
+ }
542
+ .ecp-pro-table-form__del-btn {
543
+ padding: 0;
544
+ color: #909399;
545
+ }
546
+ .ecp-pro-table-form__del-btn:not(:disabled) {
547
+ color: #409eff;
548
+ }
549
+ </style>
550
+
551
+ <style>
552
+ .ecp-pro-table-form .ecp-pro-table-form__header-cell {
553
+ background: #f5f7fa !important;
554
+ }
555
+ </style>
@@ -0,0 +1,9 @@
1
+ import ProTableForm from './ProTableForm.vue'
2
+ export { ProTableForm }
3
+ export type {
4
+ ProTableFormColumn,
5
+ ProTableFormFixedRow,
6
+ ProTableFormProps,
7
+ ProTableFormActionColumn,
8
+ } from './types'
9
+ export default ProTableForm
@@ -0,0 +1,72 @@
1
+ /** 指标列(或含友商名称等任意 key) */
2
+ export interface ProTableFormColumn {
3
+ /** 对应 model 中对象字段名 */
4
+ key: string
5
+ title: string
6
+ required?: boolean
7
+ /**
8
+ * 单元格渲染方式:
9
+ * - input / formatted-number:内置
10
+ * - slot:使用具名插槽 `cell-{slotName}` 完全自定义
11
+ */
12
+ component?: 'input' | 'formatted-number' | 'slot'
13
+ /**
14
+ * component 为 slot 时必填,对应插槽名为 `cell-{slotName}`(如 slotName: 'score' → #cell-score)
15
+ */
16
+ slotName?: string
17
+ placeholder?: string
18
+ width?: number
19
+ minWidth?: number
20
+ /**
21
+ * 透传给单元格组件。`component === 'formatted-number'` 时在此传入
22
+ * `integerDigits`、`decimalPlaces`、`rounding`、`inputLimit` 等(与 FormattedNumberInput / ProForm 一致)。
23
+ */
24
+ componentProps?: Record<string, unknown>
25
+ /** 覆盖该列默认必填规则(与 Element 表单 rules 一致) */
26
+ rules?: unknown[]
27
+ }
28
+
29
+ /** 固定行(首列为文案,不可删) */
30
+ export interface ProTableFormFixedRow {
31
+ rowKey: string
32
+ label: string
33
+ }
34
+
35
+ /** 操作列配置(showActionColumn 为 true 时生效) */
36
+ export interface ProTableFormActionColumn {
37
+ width?: number
38
+ minWidth?: number
39
+ align?: 'left' | 'center' | 'right'
40
+ fixed?: boolean | 'left' | 'right'
41
+ /** 表头文案,使用默认「新增」按钮时显示在按钮左侧,可留空 */
42
+ title?: string
43
+ }
44
+
45
+ export interface ProTableFormProps {
46
+ modelValue?: Record<string, unknown>
47
+ columns: ProTableFormColumn[]
48
+ fixedRows: ProTableFormFixedRow[]
49
+ competitorsKey?: string
50
+ /** 友商行「名称」字段,默认 name */
51
+ competitorNameKey?: string
52
+ firstColumnTitle?: string
53
+ competitorNamePlaceholder?: string
54
+ metricPlaceholder?: string
55
+ addCompetitorText?: string
56
+ minCompetitors?: number
57
+ rules?: Record<string, unknown>
58
+ labelWidth?: string
59
+ bordered?: boolean
60
+ firstColMinWidth?: number
61
+ /**
62
+ * 是否展示首列(维度/友商)。存在 fixedRows 时强制为 true。
63
+ * 无固定行且为 false 时隐藏首列,需在 columns 中自行配置名称等字段。
64
+ */
65
+ showFirstColumn?: boolean
66
+ /** 是否展示操作列,默认 true */
67
+ showActionColumn?: boolean
68
+ /** 操作列宽度(showActionColumn 时) */
69
+ actionWidth?: number
70
+ /** 操作列详细配置 */
71
+ actionColumn?: ProTableFormActionColumn
72
+ }
package/src/index.ts CHANGED
@@ -2,6 +2,7 @@ import type { VueConstructor } from 'vue'
2
2
  import ProTable, { TableAction } from './ProTable'
3
3
  import ProForm, { ProFormItem, FormActions, FormattedNumberInput } from './ProForm'
4
4
  import ProDescriptions from './ProDescriptions'
5
+ import { ProTableForm } from './ProTableForm'
5
6
  import { useForm } from './ProForm/useForm'
6
7
  import { useDescription } from './ProDescriptions/useDescription'
7
8
  import { useProTable } from './ProTable/useProTable'
@@ -10,6 +11,13 @@ import { useComponentSetting } from './useComponentSetting'
10
11
  export { ProForm, ProFormItem, FormActions, FormattedNumberInput, useForm }
11
12
  export { ProTable, useProTable, TableAction }
12
13
  export { ProDescriptions, useDescription }
14
+ export { ProTableForm }
15
+ export type {
16
+ ProTableFormColumn,
17
+ ProTableFormFixedRow,
18
+ ProTableFormProps,
19
+ ProTableFormActionColumn,
20
+ } from './ProTableForm/types'
13
21
  export { useComponentSetting }
14
22
  export type { UseComponentSettingReturn } from './useComponentSetting'
15
23
  export type { UseProTableReturn, UseProTablePropsReactive } from './ProTable/useProTable'
@@ -26,6 +34,7 @@ const components = [
26
34
  { name: 'FormActions', component: FormActions },
27
35
  { name: 'FormattedNumberInput', component: FormattedNumberInput },
28
36
  { name: 'ProDescriptions', component: ProDescriptions },
37
+ { name: 'ProTableForm', component: ProTableForm },
29
38
  ]
30
39
 
31
40
  export function install(Vue: VueConstructor) {
@@ -41,4 +50,5 @@ export default {
41
50
  ProDescriptions,
42
51
  TableAction,
43
52
  FormattedNumberInput,
53
+ ProTableForm,
44
54
  }