@vue-ui-kit/ant 2.0.3 → 2.0.5

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.
@@ -1,6 +1,533 @@
1
- <script lang="ts" setup>
1
+ <script
2
+ lang="ts"
3
+ setup
4
+ generic="D extends Recordable = Recordable, F extends Recordable = Recordable"
5
+ name="PCanvasGrid"
6
+ >
2
7
  import PCanvasTable from './PCanvasTable.vue';
8
+ import {
9
+ computed,
10
+ useAttrs,
11
+ ref,
12
+ Ref,
13
+ reactive,
14
+ onMounted,
15
+ watch,
16
+ toRefs,
17
+ onBeforeUnmount,
18
+ } from 'vue';
19
+ import {
20
+ debounce,
21
+ get,
22
+ isBoolean,
23
+ isFunction,
24
+ isObject,
25
+ isString,
26
+ omit,
27
+ toNumber,
28
+ uniq,
29
+ } from 'xe-utils';
30
+ import {
31
+ CanvasColumnProps,
32
+ PCanvasGridProps,
33
+ PCanvasTableInstance,
34
+ PFormItemProps,
35
+ ResponsePathConfig,
36
+ } from '#/antProxy';
37
+ import { v4 as uuid_v4 } from 'uuid';
38
+ import { isGoodValue } from '@/utils/is';
39
+ import PFormCol from '@/components/PFormCol.vue';
40
+ import { defaultLabelCol } from '@/utils/core';
41
+ import Icon from '@/renders/Icon';
42
+ import { $confirm, $error, $success, $warning } from '@/hooks/useMessage';
43
+ import {
44
+ Button as AButton,
45
+ Form as AForm,
46
+ Row as ARow,
47
+ Spin as ASpin,
48
+ Pagination as APagination,
49
+ } from 'ant-design-vue';
50
+ import { DownOutlined } from '@ant-design/icons-vue';
51
+ import { getCanvasTableDefaults, getGridDefaults } from '@/utils/config';
52
+ import { eachTree } from '@/utils/treeHelper';
53
+ const props = defineProps<PCanvasGridProps<D, F>>();
54
+ const attrs = useAttrs();
55
+ const emit = defineEmits<{
56
+ (
57
+ event: 'toolbarButtonClick',
58
+ data: { data: D[]; code: string; selectedKeys: Array<string | number>; records: D[] },
59
+ ): void;
60
+ (
61
+ event: 'toolbarToolClick',
62
+ data: { data: D[]; code: string; selectedKeys: Array<string | number>; records: D[] },
63
+ ): void;
64
+ (event: 'pick', data: { row: D; field: string }): void;
65
+ (event: 'resetQuery'): void;
66
+ }>();
67
+
68
+ const { formConfig, pageConfig, columns, toolbarConfig, proxyConfig, config, selectConfig } =
69
+ toRefs(props);
70
+ const gridDefaults = getGridDefaults();
71
+ const canvasTableDefaults = getCanvasTableDefaults();
72
+ const renderFormKey = ref(uuid_v4());
73
+ const queryFormData = ref<Partial<F>>({}) as Ref<Partial<F>>;
74
+ const propsWithDefaults = computed(() => ({
75
+ ...props,
76
+ config: {
77
+ ...canvasTableDefaults,
78
+ ...props.config,
79
+ },
80
+ lazyReset: props.lazyReset ?? gridDefaults.lazyReset ?? false,
81
+ fitCanvasHeight: props.fitHeight ?? gridDefaults.fitCanvasHeight ?? 100,
82
+ }));
83
+ const mode = computed<'list' | 'pagination' | 'bad'>(() =>
84
+ proxyConfig.value && proxyConfig.value.ajax
85
+ ? pageConfig.value
86
+ ? 'pagination'
87
+ : 'list'
88
+ : 'bad',
89
+ );
90
+ const pg = computed(() =>
91
+ mode.value === 'pagination'
92
+ ? {
93
+ current: pagination.page,
94
+ total: totalCount.value,
95
+ pageSize: pagination.size,
96
+ responsive: false,
97
+ showSizeChanger: true,
98
+ showTotal: (total: number) => `共${total}条数据`,
99
+ }
100
+ : false,
101
+ );
102
+
103
+ const fc = computed(() => omit({ labelCol: defaultLabelCol, ...formConfig.value }, ['items']));
104
+ const loading = reactive({
105
+ toolbar: false,
106
+ form: false,
107
+ table: false,
108
+ });
109
+ const pagination = reactive<IPage>({
110
+ page: 1,
111
+ size: pageConfig.value?.pageSize ?? 10,
112
+ });
113
+ const dataSeed = ref(0);
114
+ const totalCount = ref(0);
115
+ const tableData = ref<D[]>([]) as Ref<D[]>;
116
+ const formEl = ref<InstanceType<typeof AForm>>();
117
+ const canvasTableRef = ref<PCanvasTableInstance<D>>();
118
+ const boxEl = ref<HTMLDivElement>();
119
+ const pFormWrapper = ref<HTMLDivElement>();
120
+ const renderHeight = ref(500);
121
+ /* 分页时缓存的跨页选择数据,风险:数据可能会更新导致串页,读取计算的时候要去重 */
122
+ const pageSelections = ref<{
123
+ [key: number]: D[];
124
+ }>({});
125
+ const handleSelectionChange = (selection: D[]) => {
126
+ pageSelections.value[pagination.page] = selection;
127
+ };
128
+
129
+ const codeLoadings = reactive<Record<string, boolean>>(
130
+ [
131
+ ...(props.toolbarConfig?.buttons?.map((m) => m.code) ?? []).filter((f) => f),
132
+ ...(props.toolbarConfig?.tools?.map((m) => m.code) ?? []).filter((f) => f),
133
+ ].reduce(
134
+ (acc, cur) => {
135
+ acc[cur!] = false;
136
+ return acc;
137
+ },
138
+ {} as Record<string, boolean>,
139
+ ),
140
+ );
141
+ const setBtnLoading = (code: string, value: boolean) => {
142
+ codeLoadings[code] = value;
143
+ };
144
+ const setLoadings = (value: boolean | Record<string, boolean>) => {
145
+ if (isObject(value)) {
146
+ /* 判断value的toolbar和form 有则更新loading对应值,再判断value的table字段,有则canvasTableRef.value.setLoading*/
147
+ if (Object.prototype.hasOwnProperty.call(value, 'toolbar')) {
148
+ loading.toolbar = value.toolbar;
149
+ }
150
+ if (Object.prototype.hasOwnProperty.call(value, 'form')) {
151
+ loading.form = value.form;
152
+ }
153
+ if (Object.prototype.hasOwnProperty.call(value, 'table')) {
154
+ loading.table = value.table;
155
+ }
156
+ } else if (isBoolean(value)) {
157
+ loading.form = value;
158
+ loading.toolbar = value;
159
+ loading.table = value;
160
+ }
161
+ };
162
+ const selectedRecords = computed<D[]>(() =>
163
+ uniq(
164
+ Object.values(pageSelections.value).flat(),
165
+ (f) => f[props.config?.ROW_KEY ?? 'id'] as string | number,
166
+ ),
167
+ );
168
+ const handleFormSubmit = () => {
169
+ resetPage();
170
+ };
171
+ const selectedRowKeys = computed<Array<string | number>>(() =>
172
+ selectedRecords.value.map((f) => f[props.config?.ROW_KEY ?? 'id'] as string | number),
173
+ );
174
+ const handleResponse = (response: Recordable, pathConfig?: ResponsePathConfig<D>) =>
175
+ pathConfig
176
+ ? {
177
+ list: isString(pathConfig.list)
178
+ ? get(response, pathConfig.list)
179
+ : isFunction(pathConfig.list)
180
+ ? pathConfig.list(response)
181
+ : undefined,
182
+ total: isString(pathConfig.total)
183
+ ? get(response, pathConfig.total)
184
+ : isFunction(pathConfig.total)
185
+ ? pathConfig.total(response)
186
+ : undefined,
187
+ result: isString(pathConfig.result)
188
+ ? get(response, pathConfig.result)
189
+ : isFunction(pathConfig.result)
190
+ ? pathConfig.result(response)
191
+ : undefined,
192
+ message: isString(pathConfig.message)
193
+ ? get(response, pathConfig.message)
194
+ : isFunction(pathConfig.message)
195
+ ? pathConfig.message(response)
196
+ : undefined,
197
+ }
198
+ : {
199
+ list: response,
200
+ };
201
+ const toolBtnClick = (code: string) => {
202
+ emit('toolbarButtonClick', {
203
+ data: tableData.value,
204
+ code,
205
+ selectedKeys: selectedRowKeys.value,
206
+ records: selectedRecords.value,
207
+ });
208
+ innerToolbarHandler(code);
209
+ };
210
+ const debounceToolBtnClick = debounce(toolBtnClick, 100);
211
+ const toolBtnMenuClick = ({ key }) => debounceToolBtnClick(key);
212
+ const toolToolClick = (code: string) => {
213
+ emit('toolbarToolClick', {
214
+ data: tableData.value,
215
+ code,
216
+ selectedKeys: selectedRowKeys.value,
217
+ records: selectedRecords.value,
218
+ });
219
+ innerToolbarHandler(code);
220
+ };
221
+ const debounceToolToolClick = debounce(toolToolClick, 100);
222
+
223
+ const fetchData = () =>
224
+ new Promise<D[]>((resolve) => {
225
+ if (mode.value !== 'bad') {
226
+ setLoadings({ table: true, form: true });
227
+ const { ajax } = proxyConfig.value!;
228
+ ajax
229
+ .query({
230
+ form: queryFormData.value,
231
+ page: pagination,
232
+ })
233
+ .then((response) => {
234
+ const { list, total, result, message } = handleResponse(
235
+ response,
236
+ proxyConfig.value!.response,
237
+ );
238
+ if (list) {
239
+ tableData.value = list as D[];
240
+ dataSeed.value++;
241
+ } else if (result) {
242
+ tableData.value = result as D[];
243
+ totalCount.value = total ?? result.length;
244
+ dataSeed.value++;
245
+ } else {
246
+ tableData.value = [];
247
+ dataSeed.value++;
248
+ if (message) {
249
+ $warning(message);
250
+ }
251
+ }
252
+ resolve(tableData.value as D[]);
253
+ })
254
+ .catch((e) => {
255
+ console.error('fetchData error', e);
256
+ resolve([] as D[]);
257
+ })
258
+ .finally(() => {
259
+ setLoadings({ table: false, form: false });
260
+ });
261
+ }
262
+ });
263
+ const handleTableChange = (current: number, pageSize: number) => {
264
+ pagination.page = current;
265
+ pagination.size = pageSize;
266
+ return fetchData();
267
+ };
268
+ const resetPage = () => {
269
+ pagination.page = 1;
270
+ pageSelections.value = {};
271
+ return fetchData();
272
+ };
273
+ const debounceFetchData = debounce(fetchData, 160);
274
+ const passQuery = (params: Partial<F>, lazy?: boolean) => {
275
+ Object.assign(queryFormData.value, params);
276
+ pagination.page = 1;
277
+ return lazy ? Promise.resolve() : debounceFetchData();
278
+ };
279
+ const innerToolbarHandler = (code: string) => {
280
+ const { ajax } = proxyConfig.value!;
281
+ switch (code) {
282
+ case 'multiDelete':
283
+ if (ajax.multiDelete) {
284
+ if (selectedRowKeys.value.length > 0) {
285
+ $confirm({
286
+ title: '警告',
287
+ content: '确认删除选中的数据吗?',
288
+ }).then(() => {
289
+ setLoadings({ table: true, toolbar: true });
290
+ ajax.multiDelete!(selectedRowKeys.value)
291
+ .then(() => {
292
+ $success('删除成功');
293
+ resetPage();
294
+ })
295
+ .catch(() => {
296
+ $error('删除失败');
297
+ })
298
+ .finally(() => {
299
+ setLoadings({ table: false, toolbar: false });
300
+ codeLoadings.multiDelete = false;
301
+ });
302
+ });
303
+ } else {
304
+ $warning('请选择要删除的数据');
305
+ }
306
+ }
307
+ break;
308
+ }
309
+ };
310
+ const finalColumns = computed<CanvasColumnProps<D>[]>(() =>
311
+ selectConfig.value?.multiple
312
+ ? [
313
+ {
314
+ type: 'selection',
315
+ width: 40,
316
+ widthFillDisable: true,
317
+ title: '',
318
+ },
319
+ ...columns.value,
320
+ ]
321
+ : columns.value,
322
+ );
323
+ const resetQueryFormData = (lazy?: boolean) => {
324
+ if (formConfig.value && formConfig.value.items.length > 0) {
325
+ if (formConfig.value.customReset) {
326
+ formConfig.value.customReset();
327
+ } else {
328
+ const obj: Partial<F> = {};
329
+ eachTree(formConfig.value.items, (item) => {
330
+ if (item.field && item.itemRender) {
331
+ if (isGoodValue(item.itemRender.defaultValue)) {
332
+ obj[item.field as keyof F] = item.itemRender.defaultValue;
333
+ } else {
334
+ obj[item.field as keyof F] = undefined;
335
+ }
336
+ } else if (item.field && item.slots) {
337
+ if (isGoodValue(item.slots.defaultValue)) {
338
+ obj[item.field as keyof F] = item.slots.defaultValue;
339
+ } else {
340
+ obj[item.field as keyof F] = undefined;
341
+ }
342
+ }
343
+ });
344
+ queryFormData.value = obj;
345
+ }
346
+ emit('resetQuery');
347
+ }
348
+
349
+ pagination.page = 1;
350
+ if (!lazy) {
351
+ debounceFetchData();
352
+ }
353
+ };
354
+ const reload = () => {
355
+ pageSelections.value = {};
356
+ return resetQueryFormData();
357
+ };
358
+ const resizeTable = () => {
359
+ const pNode = boxEl.value?.parentElement;
360
+ const ph = pNode ? window.getComputedStyle(pNode).height : '0px';
361
+ const formOriginHeight = pFormWrapper.value
362
+ ? window.getComputedStyle(pFormWrapper.value).height
363
+ : '0px';
364
+ const formHeight = formOriginHeight.includes('px')
365
+ ? toNumber(formOriginHeight.replace('px', ''))
366
+ : 0;
367
+ const showCountHeight = selectConfig.value?.showCount ? 22 : 0;
368
+ renderHeight.value =
369
+ toNumber(ph.replace('px', '')) -
370
+ propsWithDefaults.value.fitCanvasHeight -
371
+ (props.toolbarConfig ? 30 : 0) -
372
+ formHeight -
373
+ showCountHeight;
374
+ };
375
+ let observer: MutationObserver;
376
+ onMounted(() => {
377
+ resizeTable();
378
+ window.addEventListener('resize', resizeTable);
379
+ // 还需要在组件根节点由不可见转为可见时重新计算高度(display:none等样式控制时)
380
+ observer = new MutationObserver((mutations) => {
381
+ mutations.forEach((mutation) => {
382
+ if (mutation.type === 'attributes' && mutation.attributeName === 'style') {
383
+ const el = mutation.target as HTMLElement;
384
+ const style = window.getComputedStyle(el);
385
+ if (style.display !== 'none') {
386
+ resizeTable();
387
+ }
388
+ }
389
+ });
390
+ });
391
+ if (boxEl.value) {
392
+ observer.observe(boxEl.value, { attributes: true, attributeFilter: ['style'] });
393
+ }
394
+ resetQueryFormData(props.manualFetch);
395
+ });
396
+ onBeforeUnmount(() => {
397
+ window.removeEventListener('resize', resizeTable);
398
+ observer.disconnect();
399
+ });
400
+ defineExpose({
401
+ commitProxy: {
402
+ query: debounceFetchData,
403
+ reload,
404
+ reloadPage: resetPage,
405
+ passQuery,
406
+ },
407
+ $canvasTable: computed(() => canvasTableRef.value),
408
+ selectedRowKeys,
409
+ setBtnLoading,
410
+ selectedRecords,
411
+ $form: computed(() => formEl.value),
412
+ getFormData: () => queryFormData.value,
413
+ setLoadings,
414
+ resizeTable,
415
+ });
3
416
  </script>
4
417
  <template>
5
- <div>todo</div>
418
+ <div ref="boxEl" class="h-full p-wrapper flex flex-col gap-8px overflow-y-auto" v-bind="attrs">
419
+ <div v-if="mode === 'bad'">请检查配置</div>
420
+ <template v-else>
421
+ <div
422
+ v-if="formConfig?.items?.some((s: PFormItemProps<F>) => s.field && s.itemRender)"
423
+ class="p-pane p-form-wrapper"
424
+ ref="pFormWrapper"
425
+ >
426
+ <a-spin :spinning="loading.form">
427
+ <a-form
428
+ :key="renderFormKey"
429
+ ref="formEl"
430
+ :model="queryFormData"
431
+ v-bind="fc"
432
+ @submit="handleFormSubmit"
433
+ >
434
+ <a-row :gutter="[6, 12]">
435
+ <p-form-col
436
+ v-for="(item, idx) in formConfig!.items"
437
+ :key="`_col_${item.field || idx}`"
438
+ :form-data="queryFormData"
439
+ :item="item as PFormItemProps<Partial<F>>"
440
+ @reset="resetQueryFormData(propsWithDefaults.lazyReset)"
441
+ />
442
+ </a-row>
443
+ </a-form>
444
+ </a-spin>
445
+ </div>
446
+ <div
447
+ v-if="toolbarConfig"
448
+ class="p-canvas-toolbar-wrapper flex items-center w-full justify-between p-theme-bg pt-8px px-16px"
449
+ >
450
+ <div class="flex items-center flex-1 gap-4px">
451
+ <template v-if="toolbarConfig.buttons && toolbarConfig.buttons.length > 0">
452
+ <template v-for="(btn, idx) in toolbarConfig.buttons" :key="idx">
453
+ <a-dropdown v-if="btn.dropdowns && btn.dropdowns.length">
454
+ <template #overlay>
455
+ <a-menu @click="toolBtnMenuClick">
456
+ <a-menu-item v-for="sub in btn.dropdowns" :key="sub.code"
457
+ >{{ sub.content }}
458
+ </a-menu-item>
459
+ </a-menu>
460
+ </template>
461
+ <a-button
462
+ :type="btn.type"
463
+ :size="btn.size ?? 'middle'"
464
+ :disabled="toolbarConfig.disabled || btn.disabled"
465
+ :loading="loading.toolbar || (!!btn.code && codeLoadings[btn.code])"
466
+ >
467
+ <Icon v-if="btn.icon" :icon="btn.icon" />
468
+ {{ btn.content }}
469
+ <DownOutlined />
470
+ </a-button>
471
+ </a-dropdown>
472
+ <a-button
473
+ v-else-if="btn.code"
474
+ :type="btn.type"
475
+ :size="btn.size ?? 'middle'"
476
+ :disabled="toolbarConfig.disabled || btn.disabled"
477
+ :loading="loading.toolbar || (!!btn.code && codeLoadings[btn.code])"
478
+ @click="debounceToolBtnClick(btn.code)"
479
+ >
480
+ <Icon v-if="btn.icon" :icon="btn.icon" />
481
+ {{ btn.content }}
482
+ </a-button>
483
+ <div v-else></div>
484
+ </template>
485
+ </template>
486
+ </div>
487
+ <span class="flex items-center gap-4px">
488
+ <template v-if="toolbarConfig.tools && toolbarConfig.tools.length > 0">
489
+ <a-button
490
+ v-for="(tool, idx) in toolbarConfig.tools"
491
+ :key="idx"
492
+ :type="tool.type"
493
+ :size="tool.size ?? 'middle'"
494
+ :disabled="toolbarConfig.disabled || tool.disabled"
495
+ @click="debounceToolToolClick(tool.code)"
496
+ :loading="loading.toolbar || (!!tool.code && codeLoadings[tool.code])"
497
+ >
498
+ <Icon :icon="tool.icon" />
499
+ </a-button>
500
+ </template>
501
+ </span>
502
+ </div>
503
+ <div :class="`p-pane flex-1 h-0 p-inner-scroll`">
504
+ <div
505
+ v-if="selectConfig?.multiple && selectConfig.showCount"
506
+ class="w-full text-slate-5 pl-4"
507
+ >
508
+ 已选:{{ selectedRowKeys.length }}
509
+ </div>
510
+ <p-canvas-table
511
+ ref="canvasTableRef"
512
+ :columns="finalColumns"
513
+ :config="{
514
+ ...config,
515
+ HEIGHT: renderHeight,
516
+ }"
517
+ @selection-change="handleSelectionChange"
518
+ :data="tableData"
519
+ :loading="loading.table"
520
+ />
521
+ <a-pagination
522
+ class="p-canvas-pagination"
523
+ v-if="mode === 'pagination'"
524
+ size="small"
525
+ :current="pagination.page"
526
+ :page-size="pagination.size"
527
+ :total="totalCount"
528
+ @change="handleTableChange"
529
+ />
530
+ </div>
531
+ </template>
532
+ </div>
6
533
  </template>
@@ -20,16 +20,28 @@
20
20
  import type { CanvasColumnProps, CanvasTableProps, FormatterFunc, CellRender } from '#/antProxy';
21
21
  import { v4 as uuidv4 } from 'uuid';
22
22
  import { antFormatters } from '@/utils/AFormatters';
23
+ import { getCanvasTableDefaults } from '@/utils/config';
23
24
 
24
25
  const emit = defineEmits<{
25
26
  (e: 'change', value: any[]): void; // 需要默认实现change,不能动态绑定
27
+ (e: 'selectionChange', value: T[]): void;
26
28
  (e: 'ready', value: EVirtTable): void;
27
29
  }>();
28
- const defaultConfig = {
29
- DISABLED: true,
30
- };
30
+
31
31
  const selectedRecords = ref<T[]>([]);
32
- const props = defineProps<CanvasTableProps<T, B>>();
32
+ const props = withDefaults(defineProps<CanvasTableProps<T, B>>(), {
33
+ config: () => ({}),
34
+ });
35
+ // 应用默认值 - 参考PGrid的模式
36
+ const canvasTableDefaults = getCanvasTableDefaults();
37
+ const propsWithDefaults = computed(() => ({
38
+ ...props,
39
+ config: {
40
+ DISABLED: true, // 内部写死的默认配置
41
+ ...canvasTableDefaults, // 全局配置
42
+ ...props.config, // 用户传入的配置
43
+ },
44
+ }));
33
45
  let eVirtTable: EVirtTable | null = null;
34
46
  const attrs = useAttrs();
35
47
  const eVirtTableRef = ref(null);
@@ -129,10 +141,7 @@
129
141
  return;
130
142
  }
131
143
  eVirtTable = new EVirtTable(eVirtTableRef.value, {
132
- config: {
133
- ...defaultConfig,
134
- ...props.config,
135
- },
144
+ config: propsWithDefaults.value.config,
136
145
  columns: props.columns.map((col) => parseToEVirtColumn(col)),
137
146
  data: props.data,
138
147
  footerData: props.footerData,
@@ -167,6 +176,7 @@
167
176
  });
168
177
  eVirtTable.on('selectionChange', (selection) => {
169
178
  selectedRecords.value = selection;
179
+ emit('selectionChange', selection);
170
180
  });
171
181
  emit('ready', eVirtTable);
172
182
  });
@@ -181,7 +191,7 @@
181
191
  return document.body;
182
192
  };
183
193
  watch(
184
- props.data,
194
+ () => props.data,
185
195
  (newValue) => {
186
196
  eVirtTable?.loadData(newValue);
187
197
  },
@@ -197,7 +207,7 @@
197
207
  { deep: true },
198
208
  );
199
209
  watch(
200
- () => props.config,
210
+ () => propsWithDefaults.value.config,
201
211
  (newValue) => {
202
212
  eVirtTable?.loadConfig(newValue);
203
213
  },
@@ -210,9 +220,21 @@
210
220
  },
211
221
  { deep: true },
212
222
  );
223
+ watch(
224
+ () => props.loading,
225
+ (n, p) => {
226
+ if (n !== p) {
227
+ eVirtTable?.setLoading(n);
228
+ }
229
+ },
230
+ { immediate: true },
231
+ );
213
232
  defineExpose({
214
233
  $table: eVirtTable,
215
234
  selectedRecords: computed(() => selectedRecords.value),
235
+ reloadData: () => {
236
+ eVirtTable?.loadData(props.data);
237
+ },
216
238
  });
217
239
  </script>
218
240
  <template>
@@ -272,7 +294,7 @@
272
294
  >
273
295
  <div :style="view.style" v-for="view in wrapper.views" :key="view.key">
274
296
  <div
275
- class="cell"
297
+ class="canvas-cell"
276
298
  v-for="cell in view.cells"
277
299
  :key="`${cell.rowKey}_${cell.key}`"
278
300
  :style="cell.style"
@@ -280,6 +302,7 @@
280
302
  <component
281
303
  v-if="typeof cell.render === 'function'"
282
304
  :is="cell.render(cell)"
305
+ :bordered="false"
283
306
  ></component>
284
307
  <template
285
308
  v-else-if="typeof cell.render === 'string' && cell.render.startsWith('slot:')"
@@ -138,8 +138,8 @@
138
138
  });
139
139
  return cols;
140
140
  });
141
- const formEl = ref();
142
- const tableEl = ref();
141
+ const formEl = ref<InstanceType<typeof AForm>>();
142
+ const tableEl = ref<InstanceType<typeof ATable>>();
143
143
  const renderFormKey = ref(uuid_v4());
144
144
  const renderTableKey = ref(uuid_v4());
145
145