@vue-ui-kit/ant 2.4.6 → 2.5.1
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/cjs/index.js +16 -4
- package/dist/es/index.js +2488 -1855
- package/dist/index.d.ts +3049 -761
- package/dist/style.css +3 -0
- package/dist/style.scss +464 -461
- package/package.json +85 -82
- package/src/declarations/antProxy.ts +48 -0
- package/src/index.ts +5 -1
- package/src/packages/components/PCanvasGrid.vue +147 -42
- package/src/packages/components/PDescription.vue +50 -0
- package/src/packages/components/PDescriptionContent.tsx +46 -0
- package/src/packages/components/PGrid.vue +3 -0
- package/src/packages/renders/Icon.ts +3 -3
- package/src/packages/store/renderStore.tsx +51 -2
- package/src/packages/styles/index.scss +464 -461
package/package.json
CHANGED
|
@@ -1,82 +1,85 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@vue-ui-kit/ant",
|
|
3
|
-
"version": "2.
|
|
4
|
-
"description": "Vue3 UI Kit based on Ant Design",
|
|
5
|
-
"type": "module",
|
|
6
|
-
"main": "./dist/cjs/index.js",
|
|
7
|
-
"module": "./dist/es/index.js",
|
|
8
|
-
"types": "./dist/index.d.ts",
|
|
9
|
-
"style": "./dist/style.css",
|
|
10
|
-
"sass": "./dist/style.scss",
|
|
11
|
-
"exports": {
|
|
12
|
-
".": {
|
|
13
|
-
"require": "./dist/cjs/index.js",
|
|
14
|
-
"import": "./dist/es/index.js",
|
|
15
|
-
"types": "./dist/index.d.ts"
|
|
16
|
-
},
|
|
17
|
-
"./style.css": "./dist/style.css",
|
|
18
|
-
"./style.scss": "./src/packages/styles/index.scss",
|
|
19
|
-
"./dist/style.scss": "./dist/style.scss",
|
|
20
|
-
"./dist/style.css": "./dist/style.css"
|
|
21
|
-
},
|
|
22
|
-
"files": [
|
|
23
|
-
"dist",
|
|
24
|
-
"src",
|
|
25
|
-
"README.md",
|
|
26
|
-
"README.zh.md",
|
|
27
|
-
"tsconfig.json"
|
|
28
|
-
],
|
|
29
|
-
"scripts": {
|
|
30
|
-
"dev": "vue-tsc --noEmit --skipLibCheck & vite",
|
|
31
|
-
"
|
|
32
|
-
"
|
|
33
|
-
"
|
|
34
|
-
"
|
|
35
|
-
"lint:
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
"
|
|
40
|
-
"
|
|
41
|
-
"ant",
|
|
42
|
-
"
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
"
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
"
|
|
51
|
-
"
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
"ant-design-vue": ">=
|
|
56
|
-
"vue": ">=
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
"
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
"@
|
|
65
|
-
"@commitlint/
|
|
66
|
-
"@
|
|
67
|
-
"@vitejs/plugin-vue": "^6.0.5",
|
|
68
|
-
"@vitejs/plugin-vue-jsx": "^5.1.5",
|
|
69
|
-
"ant-design-vue": "^4.2.3",
|
|
70
|
-
"esbuild": "^0.28.0",
|
|
71
|
-
"husky": "^9.1.5",
|
|
72
|
-
"lint-staged": "^15.2.9",
|
|
73
|
-
"prettier": "^3.3.3",
|
|
74
|
-
"rimraf": "^6.0.1",
|
|
75
|
-
"sass": "^1.77.8",
|
|
76
|
-
"
|
|
77
|
-
"
|
|
78
|
-
"
|
|
79
|
-
"vite
|
|
80
|
-
"
|
|
81
|
-
|
|
82
|
-
|
|
1
|
+
{
|
|
2
|
+
"name": "@vue-ui-kit/ant",
|
|
3
|
+
"version": "2.5.1",
|
|
4
|
+
"description": "Vue3 UI Kit based on Ant Design",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/cjs/index.js",
|
|
7
|
+
"module": "./dist/es/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"style": "./dist/style.css",
|
|
10
|
+
"sass": "./dist/style.scss",
|
|
11
|
+
"exports": {
|
|
12
|
+
".": {
|
|
13
|
+
"require": "./dist/cjs/index.js",
|
|
14
|
+
"import": "./dist/es/index.js",
|
|
15
|
+
"types": "./dist/index.d.ts"
|
|
16
|
+
},
|
|
17
|
+
"./style.css": "./dist/style.css",
|
|
18
|
+
"./style.scss": "./src/packages/styles/index.scss",
|
|
19
|
+
"./dist/style.scss": "./dist/style.scss",
|
|
20
|
+
"./dist/style.css": "./dist/style.css"
|
|
21
|
+
},
|
|
22
|
+
"files": [
|
|
23
|
+
"dist",
|
|
24
|
+
"src",
|
|
25
|
+
"README.md",
|
|
26
|
+
"README.zh.md",
|
|
27
|
+
"tsconfig.json"
|
|
28
|
+
],
|
|
29
|
+
"scripts": {
|
|
30
|
+
"dev": "ts-patch uninstall && vue-tsc --noEmit --skipLibCheck & vite",
|
|
31
|
+
"typecheck": "ts-patch uninstall && vue-tsc --noEmit --skipLibCheck",
|
|
32
|
+
"build": "ts-patch install && vite build && sass src/packages/styles/index.scss dist/style.css --no-source-map",
|
|
33
|
+
"prepack": "rimraf dist && pnpm build",
|
|
34
|
+
"prepare": "husky",
|
|
35
|
+
"lint:lint-staged": "lint-staged",
|
|
36
|
+
"lint:prettier": "prettier --write \"src/**/*.{js,json,tsx,css,less,scss,vue,html,md}\""
|
|
37
|
+
},
|
|
38
|
+
"keywords": [
|
|
39
|
+
"vue3",
|
|
40
|
+
"ui kit",
|
|
41
|
+
"ant design",
|
|
42
|
+
"ant",
|
|
43
|
+
"antdv"
|
|
44
|
+
],
|
|
45
|
+
"author": {
|
|
46
|
+
"name": "adoin",
|
|
47
|
+
"email": "adoin@qq.com"
|
|
48
|
+
},
|
|
49
|
+
"dependencies": {
|
|
50
|
+
"e-virt-table": "^1.4.1",
|
|
51
|
+
"uuid": "^11.1.1",
|
|
52
|
+
"xe-utils": "^3.7.6"
|
|
53
|
+
},
|
|
54
|
+
"peerDependencies": {
|
|
55
|
+
"@ant-design/icons-vue": ">=7.0.0",
|
|
56
|
+
"ant-design-vue": ">=4.0.0",
|
|
57
|
+
"vue": ">=3.2.0"
|
|
58
|
+
},
|
|
59
|
+
"license": "GPL",
|
|
60
|
+
"engines": {
|
|
61
|
+
"node": "^20.19.0 || >=22.12.0"
|
|
62
|
+
},
|
|
63
|
+
"devDependencies": {
|
|
64
|
+
"@ant-design/icons-vue": ">=7.0.0",
|
|
65
|
+
"@commitlint/cli": "^21.0.0",
|
|
66
|
+
"@commitlint/config-conventional": "^21.0.0",
|
|
67
|
+
"@vitejs/plugin-vue": "^6.0.5",
|
|
68
|
+
"@vitejs/plugin-vue-jsx": "^5.1.5",
|
|
69
|
+
"ant-design-vue": "^4.2.3",
|
|
70
|
+
"esbuild": "^0.28.0",
|
|
71
|
+
"husky": "^9.1.5",
|
|
72
|
+
"lint-staged": "^15.2.9",
|
|
73
|
+
"prettier": "^3.3.3",
|
|
74
|
+
"rimraf": "^6.0.1",
|
|
75
|
+
"sass": "^1.77.8",
|
|
76
|
+
"scroll-into-view-if-needed": "^2.2.31",
|
|
77
|
+
"ts-patch": "^3.2.1",
|
|
78
|
+
"typescript-transform-paths": "^3.5.0",
|
|
79
|
+
"vite": "^8.0.8",
|
|
80
|
+
"vite-plugin-dts": "^4.5.4",
|
|
81
|
+
"vue": "^3.5.33",
|
|
82
|
+
"vue-tsc": "3.3.5",
|
|
83
|
+
"vue-types": "^3.0.2"
|
|
84
|
+
}
|
|
85
|
+
}
|
|
@@ -80,6 +80,38 @@ export interface PFormProps<F extends Recordable = Recordable> extends FormProps
|
|
|
80
80
|
customReset?: () => void;
|
|
81
81
|
}
|
|
82
82
|
|
|
83
|
+
export interface PDescriptionItemProps<D extends Recordable = Recordable> {
|
|
84
|
+
field?: string;
|
|
85
|
+
label?: string;
|
|
86
|
+
span?: number;
|
|
87
|
+
labelStyle?: Recordable;
|
|
88
|
+
contentStyle?: Recordable;
|
|
89
|
+
/** 只读展示渲染器,派发到 renderStore.renderDefault */
|
|
90
|
+
readonlyRender?: ItemRender;
|
|
91
|
+
slots?: {
|
|
92
|
+
label?: () => any;
|
|
93
|
+
default?: ({ data, field }: { data: D; field?: string }) => any;
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export interface PDescriptionProps<D extends Recordable = Recordable> {
|
|
98
|
+
/** 数据源 */
|
|
99
|
+
data: D;
|
|
100
|
+
items: PDescriptionItemProps<D>[];
|
|
101
|
+
/** 透传 a-descriptions */
|
|
102
|
+
title?: string;
|
|
103
|
+
extra?: string;
|
|
104
|
+
bordered?: boolean;
|
|
105
|
+
size?: 'default' | 'small' | 'middle';
|
|
106
|
+
column?: number | Partial<Record<'xxs' | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'xxl', number>>;
|
|
107
|
+
layout?: 'horizontal' | 'vertical';
|
|
108
|
+
colon?: boolean;
|
|
109
|
+
labelStyle?: Recordable;
|
|
110
|
+
contentStyle?: Recordable;
|
|
111
|
+
/** 缺省占位,row[field] 为空时展示 */
|
|
112
|
+
emptyText?: string;
|
|
113
|
+
}
|
|
114
|
+
|
|
83
115
|
export interface PBlockProps<F extends Recordable = Recordable> {
|
|
84
116
|
name?: string;
|
|
85
117
|
getFormSetting: (data: Partial<F>) => PFormProps<Partial<F>>;
|
|
@@ -314,6 +346,12 @@ export interface RenderFormParams<F extends Recordable = Recordable> {
|
|
|
314
346
|
field?: string;
|
|
315
347
|
}
|
|
316
348
|
|
|
349
|
+
export interface RenderReadonlyParams<D extends Recordable = Recordable> {
|
|
350
|
+
data: D;
|
|
351
|
+
field?: string;
|
|
352
|
+
title?: string;
|
|
353
|
+
}
|
|
354
|
+
|
|
317
355
|
export interface RenderTableParams<D extends Recordable = Recordable> {
|
|
318
356
|
data?: D[];
|
|
319
357
|
row: D;
|
|
@@ -389,6 +427,16 @@ export interface PCanvasGridProps<
|
|
|
389
427
|
* 适应展示区到页面顶部的高度,通常和容器最上的y值有关(正比)
|
|
390
428
|
*/
|
|
391
429
|
fitHeight?: number;
|
|
430
|
+
/**
|
|
431
|
+
* 开启后组件根节点按视口从其左上角铺满宽高,与 PGrid 的 autoBoxSize 行为一致。
|
|
432
|
+
* 外层未声明固定高度、需组件自身占满可视区域时使用。
|
|
433
|
+
*/
|
|
434
|
+
autoBoxSize?: boolean;
|
|
435
|
+
/**
|
|
436
|
+
* `autoBoxSize` 时距视口右侧/底部的预留像素;数字或 `"12px"` 同时作用于两侧;对象可分别指定 `right` / `bottom`。
|
|
437
|
+
* 未传时使用 `setUIKitConfig({ grid: { autoBoxSizeOffset } })` 的全局值。
|
|
438
|
+
*/
|
|
439
|
+
autoBoxSizeOffset?: number | string | { right?: number; bottom?: number };
|
|
392
440
|
}
|
|
393
441
|
export interface PGridInstance<
|
|
394
442
|
D extends Recordable = Recordable,
|
package/src/index.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { App } from 'vue';
|
|
2
|
+
import type { Component } from 'vue';
|
|
2
3
|
import PForm from '@/components/PForm.vue';
|
|
3
4
|
import PGrid from '@/components/PGrid.vue';
|
|
4
5
|
import PCanvasTable from '@/components/PCanvasTable.vue';
|
|
@@ -6,6 +7,7 @@ import PCanvasGrid from '@/components/PCanvasGrid.vue';
|
|
|
6
7
|
import PFormGroup from '@/components/PFormGroup.vue';
|
|
7
8
|
import PGroupBlock from '@/components/PGroupBlock.vue';
|
|
8
9
|
import PromisePicker from '@/components/PromisePicker.vue';
|
|
10
|
+
import PDescription from '@/components/PDescription.vue';
|
|
9
11
|
import { addFormatter } from '@/utils/AFormatters';
|
|
10
12
|
import { addRender } from '@/store/renderStore';
|
|
11
13
|
import {
|
|
@@ -29,9 +31,10 @@ export default {
|
|
|
29
31
|
app.component('PGrid', PGrid);
|
|
30
32
|
app.component('PCanvasTable', PCanvasTable);
|
|
31
33
|
app.component('PCanvasGrid', PCanvasGrid);
|
|
32
|
-
app.component('PFormGroup', PFormGroup);
|
|
34
|
+
app.component('PFormGroup', PFormGroup as unknown as Component);
|
|
33
35
|
app.component('PGroupBlock', PGroupBlock);
|
|
34
36
|
app.component('PromisePicker', PromisePicker);
|
|
37
|
+
app.component('PDescription', PDescription);
|
|
35
38
|
},
|
|
36
39
|
addFormatter,
|
|
37
40
|
addRender,
|
|
@@ -62,6 +65,7 @@ export {
|
|
|
62
65
|
PFormGroup,
|
|
63
66
|
PGroupBlock,
|
|
64
67
|
PromisePicker,
|
|
68
|
+
PDescription,
|
|
65
69
|
addFormatter,
|
|
66
70
|
addRender,
|
|
67
71
|
};
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
Ref,
|
|
13
13
|
reactive,
|
|
14
14
|
onMounted,
|
|
15
|
+
nextTick,
|
|
15
16
|
toRefs,
|
|
16
17
|
onBeforeUnmount,
|
|
17
18
|
watch,
|
|
@@ -39,10 +40,17 @@
|
|
|
39
40
|
} from 'ant-design-vue';
|
|
40
41
|
import { DownOutlined } from '@ant-design/icons-vue';
|
|
41
42
|
import { getCanvasTableDefaults, getGridDefaults } from '@/utils/config';
|
|
43
|
+
import {
|
|
44
|
+
createAutoViewportBoxController,
|
|
45
|
+
parseAutoViewportBoxOffset,
|
|
46
|
+
type AutoViewportBoxController,
|
|
47
|
+
type AutoViewportBoxOffsetInput,
|
|
48
|
+
} from '@/utils/autoViewportBox';
|
|
42
49
|
import { eachTree } from '@/utils/treeHelper';
|
|
43
50
|
const props = withDefaults(defineProps<PCanvasGridProps<D, F>>(), {
|
|
44
51
|
lazyReset: () => getGridDefaults().lazyReset ?? false,
|
|
45
|
-
fitHeight: () => getGridDefaults().fitCanvasHeight ??
|
|
52
|
+
fitHeight: () => getGridDefaults().fitCanvasHeight ?? 0,
|
|
53
|
+
autoBoxSize: false,
|
|
46
54
|
});
|
|
47
55
|
const attrs = useAttrs();
|
|
48
56
|
const emit = defineEmits<{
|
|
@@ -61,6 +69,15 @@
|
|
|
61
69
|
const { formConfig, pageConfig, columns, toolbarConfig, proxyConfig, config, staticConfig } =
|
|
62
70
|
toRefs(props);
|
|
63
71
|
const canvasTableDefaults = getCanvasTableDefaults();
|
|
72
|
+
|
|
73
|
+
/** 局部 `autoBoxSizeOffset` 优先,否则用 `getGridDefaults().autoBoxSizeOffset`(`setUIKitConfig`) */
|
|
74
|
+
const resolvedAutoBoxSizeOffset = computed<AutoViewportBoxOffsetInput>(() => {
|
|
75
|
+
const local = props.autoBoxSizeOffset;
|
|
76
|
+
if (local !== undefined && local !== null) {
|
|
77
|
+
return local;
|
|
78
|
+
}
|
|
79
|
+
return getGridDefaults().autoBoxSizeOffset as AutoViewportBoxOffsetInput;
|
|
80
|
+
});
|
|
64
81
|
const renderFormKey = ref(uuid_v4());
|
|
65
82
|
const queryFormData = ref<Partial<F>>({}) as Ref<Partial<F>>;
|
|
66
83
|
|
|
@@ -110,6 +127,8 @@
|
|
|
110
127
|
const boxEl = ref<HTMLDivElement>();
|
|
111
128
|
const pFormWrapper = ref<HTMLDivElement>();
|
|
112
129
|
const tableWrapperEl = ref<HTMLDivElement>();
|
|
130
|
+
const tableBodyEl = ref<HTMLDivElement>();
|
|
131
|
+
const tableFooterEl = ref<HTMLDivElement>();
|
|
113
132
|
const renderHeight = ref(500);
|
|
114
133
|
/* 分页时缓存的跨页选择数据,风险:数据可能会更新导致串页,读取计算的时候要去重 */
|
|
115
134
|
const pageSelections = ref<{
|
|
@@ -376,14 +395,59 @@
|
|
|
376
395
|
pageSelections.value = {};
|
|
377
396
|
return resetQueryFormData();
|
|
378
397
|
};
|
|
398
|
+
|
|
399
|
+
const renderContent = (content: string | (() => any)) => {
|
|
400
|
+
if (isFunction(content)) {
|
|
401
|
+
return content();
|
|
402
|
+
}
|
|
403
|
+
return content;
|
|
404
|
+
};
|
|
405
|
+
const isStringContent = (content: any) => isString(content);
|
|
406
|
+
|
|
407
|
+
let autoViewportBoxCtrl: AutoViewportBoxController | null = null;
|
|
408
|
+
const clearAutoViewportBox = () => {
|
|
409
|
+
autoViewportBoxCtrl?.destroy();
|
|
410
|
+
autoViewportBoxCtrl = null;
|
|
411
|
+
};
|
|
412
|
+
const syncAutoViewportBox = () => {
|
|
413
|
+
clearAutoViewportBox();
|
|
414
|
+
if (!props.autoBoxSize || !boxEl.value) return;
|
|
415
|
+
autoViewportBoxCtrl = createAutoViewportBoxController(
|
|
416
|
+
() => boxEl.value ?? undefined,
|
|
417
|
+
() => parseAutoViewportBoxOffset(resolvedAutoBoxSizeOffset.value),
|
|
418
|
+
{
|
|
419
|
+
onLayout: () => {
|
|
420
|
+
nextTick(() => resizeTable());
|
|
421
|
+
},
|
|
422
|
+
},
|
|
423
|
+
);
|
|
424
|
+
autoViewportBoxCtrl.attach();
|
|
425
|
+
};
|
|
426
|
+
|
|
427
|
+
watch(
|
|
428
|
+
() => props.autoBoxSize,
|
|
429
|
+
(on) => {
|
|
430
|
+
if (!on) clearAutoViewportBox();
|
|
431
|
+
else nextTick(() => syncAutoViewportBox());
|
|
432
|
+
},
|
|
433
|
+
);
|
|
434
|
+
watch(
|
|
435
|
+
resolvedAutoBoxSizeOffset,
|
|
436
|
+
() => {
|
|
437
|
+
if (props.autoBoxSize) autoViewportBoxCtrl?.update();
|
|
438
|
+
},
|
|
439
|
+
{ deep: true },
|
|
440
|
+
);
|
|
441
|
+
|
|
379
442
|
let resizeRaf: number | null = null;
|
|
380
443
|
const resizeTable = () => {
|
|
381
444
|
if (resizeRaf) cancelAnimationFrame(resizeRaf);
|
|
382
445
|
resizeRaf = requestAnimationFrame(() => {
|
|
383
446
|
resizeRaf = null;
|
|
384
|
-
if (!
|
|
385
|
-
const
|
|
386
|
-
|
|
447
|
+
if (!tableBodyEl.value) return;
|
|
448
|
+
const bodyH = tableBodyEl.value.clientHeight;
|
|
449
|
+
const reserve = props.fitHeight ?? 0;
|
|
450
|
+
renderHeight.value = Math.max(bodyH - reserve, 100);
|
|
387
451
|
});
|
|
388
452
|
};
|
|
389
453
|
|
|
@@ -401,8 +465,12 @@
|
|
|
401
465
|
{ immediate: true },
|
|
402
466
|
);
|
|
403
467
|
|
|
468
|
+
// 分页/已选区域高度变化时重算
|
|
469
|
+
watch(mode, () => nextTick(() => resizeTable()));
|
|
470
|
+
|
|
404
471
|
let observer: MutationObserver;
|
|
405
472
|
let boxElResizeObserver: ResizeObserver | null = null;
|
|
473
|
+
let tableBodyResizeObserver: ResizeObserver | null = null;
|
|
406
474
|
onMounted(() => {
|
|
407
475
|
resizeTable();
|
|
408
476
|
window.addEventListener('resize', resizeTable);
|
|
@@ -428,7 +496,16 @@
|
|
|
428
496
|
ancestor = ancestor.parentElement;
|
|
429
497
|
}
|
|
430
498
|
}
|
|
499
|
+
// 直接观察实际承载 canvas 的内层盒子,避免 padding/footer 干扰
|
|
500
|
+
tableBodyResizeObserver = new ResizeObserver(() => resizeTable());
|
|
501
|
+
if (tableBodyEl.value) {
|
|
502
|
+
tableBodyResizeObserver.observe(tableBodyEl.value);
|
|
503
|
+
}
|
|
431
504
|
resetQueryFormData(props.manualFetch);
|
|
505
|
+
nextTick(() => {
|
|
506
|
+
if (props.autoBoxSize) syncAutoViewportBox();
|
|
507
|
+
resizeTable();
|
|
508
|
+
});
|
|
432
509
|
});
|
|
433
510
|
onBeforeUnmount(() => {
|
|
434
511
|
if (resizeRaf) cancelAnimationFrame(resizeRaf);
|
|
@@ -436,6 +513,8 @@
|
|
|
436
513
|
observer.disconnect();
|
|
437
514
|
formWrapperResizeObserver?.disconnect();
|
|
438
515
|
boxElResizeObserver?.disconnect();
|
|
516
|
+
tableBodyResizeObserver?.disconnect();
|
|
517
|
+
clearAutoViewportBox();
|
|
439
518
|
});
|
|
440
519
|
defineExpose({
|
|
441
520
|
commitProxy: {
|
|
@@ -456,7 +535,14 @@
|
|
|
456
535
|
});
|
|
457
536
|
</script>
|
|
458
537
|
<template>
|
|
459
|
-
<div
|
|
538
|
+
<div
|
|
539
|
+
ref="boxEl"
|
|
540
|
+
:class="[
|
|
541
|
+
'p-wrapper flex flex-col gap-8px overflow-y-auto',
|
|
542
|
+
autoBoxSize ? 'min-h-0 min-w-0 flex-1 w-full' : 'h-full',
|
|
543
|
+
]"
|
|
544
|
+
v-bind="attrs"
|
|
545
|
+
>
|
|
460
546
|
<div v-if="mode === 'bad'">请检查配置</div>
|
|
461
547
|
<template v-else>
|
|
462
548
|
<div
|
|
@@ -509,9 +595,14 @@
|
|
|
509
595
|
:ghost="btn.ghost"
|
|
510
596
|
:block="btn.block"
|
|
511
597
|
>
|
|
512
|
-
<
|
|
513
|
-
|
|
514
|
-
|
|
598
|
+
<div class="flex items-center gap-4px">
|
|
599
|
+
<Icon v-if="btn.icon" :icon="btn.icon" />
|
|
600
|
+
<template v-if="btn.content && isStringContent(renderContent(btn.content))">
|
|
601
|
+
{{ renderContent(btn.content) }}
|
|
602
|
+
</template>
|
|
603
|
+
<component v-else-if="btn.content" :is="renderContent(btn.content)" />
|
|
604
|
+
<DownOutlined />
|
|
605
|
+
</div>
|
|
515
606
|
</a-button>
|
|
516
607
|
</a-dropdown>
|
|
517
608
|
<a-button
|
|
@@ -526,8 +617,13 @@
|
|
|
526
617
|
:block="btn.block"
|
|
527
618
|
@click="debounceToolBtnClick(btn.code)"
|
|
528
619
|
>
|
|
529
|
-
<
|
|
530
|
-
|
|
620
|
+
<div class="flex items-center gap-4px">
|
|
621
|
+
<Icon v-if="btn.icon" :icon="btn.icon" />
|
|
622
|
+
<template v-if="btn.content && isStringContent(renderContent(btn.content))">
|
|
623
|
+
{{ renderContent(btn.content) }}
|
|
624
|
+
</template>
|
|
625
|
+
<component v-else-if="btn.content" :is="renderContent(btn.content)" />
|
|
626
|
+
</div>
|
|
531
627
|
</a-button>
|
|
532
628
|
<div v-else></div>
|
|
533
629
|
</template>
|
|
@@ -548,43 +644,52 @@
|
|
|
548
644
|
@click="debounceToolToolClick(tool.code)"
|
|
549
645
|
:loading="loading.toolbar || (!!tool.code && codeLoadings[tool.code])"
|
|
550
646
|
>
|
|
551
|
-
<
|
|
552
|
-
|
|
647
|
+
<div class="flex items-center gap-4px">
|
|
648
|
+
<Icon v-if="tool.icon" :icon="tool.icon" />
|
|
649
|
+
<template v-if="tool.content && isStringContent(renderContent(tool.content))">
|
|
650
|
+
{{ renderContent(tool.content) }}
|
|
651
|
+
</template>
|
|
652
|
+
<component v-else-if="tool.content" :is="renderContent(tool.content)" />
|
|
653
|
+
</div>
|
|
553
654
|
</a-button>
|
|
554
655
|
</template>
|
|
555
656
|
</span>
|
|
556
657
|
</div>
|
|
557
|
-
<div ref="tableWrapperEl"
|
|
558
|
-
<div
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
658
|
+
<div ref="tableWrapperEl" class="p-pane flex-1 h-0 min-h-0 flex flex-col p-inner-scroll">
|
|
659
|
+
<div ref="tableBodyEl" class="flex-1 min-h-0 overflow-hidden">
|
|
660
|
+
<p-canvas-table
|
|
661
|
+
ref="canvasTableRef"
|
|
662
|
+
:columns="finalColumns"
|
|
663
|
+
:config="{
|
|
664
|
+
...propsWithDefaults.config,
|
|
665
|
+
HEIGHT: renderHeight,
|
|
666
|
+
}"
|
|
667
|
+
:data="tableData"
|
|
668
|
+
:loading="loading.table"
|
|
669
|
+
@selection-change="handleSelectionChange"
|
|
670
|
+
>
|
|
671
|
+
<template v-for="(_, name) in $slots" #[name]="slotProps">
|
|
672
|
+
<slot :name="name" v-bind="slotProps"></slot>
|
|
673
|
+
</template>
|
|
674
|
+
</p-canvas-table>
|
|
675
|
+
</div>
|
|
676
|
+
<div ref="tableFooterEl" class="flex-shrink-0">
|
|
677
|
+
<div
|
|
678
|
+
v-if="staticConfig?.selectable && staticConfig.showCount"
|
|
679
|
+
class="w-full text-slate-5 pl-4"
|
|
680
|
+
>
|
|
681
|
+
已选:{{ selectedRowKeys.length }}
|
|
682
|
+
</div>
|
|
683
|
+
<a-pagination
|
|
684
|
+
class="p-canvas-pagination"
|
|
685
|
+
v-if="mode === 'pagination'"
|
|
686
|
+
size="small"
|
|
687
|
+
:current="pagination.page"
|
|
688
|
+
:page-size="pagination.size"
|
|
689
|
+
:total="totalCount"
|
|
690
|
+
@change="handleTableChange"
|
|
691
|
+
/>
|
|
563
692
|
</div>
|
|
564
|
-
<p-canvas-table
|
|
565
|
-
ref="canvasTableRef"
|
|
566
|
-
:columns="finalColumns"
|
|
567
|
-
:config="{
|
|
568
|
-
...propsWithDefaults.config,
|
|
569
|
-
HEIGHT: renderHeight,
|
|
570
|
-
}"
|
|
571
|
-
:data="tableData"
|
|
572
|
-
:loading="loading.table"
|
|
573
|
-
@selection-change="handleSelectionChange"
|
|
574
|
-
>
|
|
575
|
-
<template v-for="(_, name) in $slots" #[name]="slotProps">
|
|
576
|
-
<slot :name="name" v-bind="slotProps"></slot>
|
|
577
|
-
</template>
|
|
578
|
-
</p-canvas-table>
|
|
579
|
-
<a-pagination
|
|
580
|
-
class="p-canvas-pagination"
|
|
581
|
-
v-if="mode === 'pagination'"
|
|
582
|
-
size="small"
|
|
583
|
-
:current="pagination.page"
|
|
584
|
-
:page-size="pagination.size"
|
|
585
|
-
:total="totalCount"
|
|
586
|
-
@change="handleTableChange"
|
|
587
|
-
/>
|
|
588
693
|
</div>
|
|
589
694
|
</template>
|
|
590
695
|
</div>
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
<script lang="ts" setup generic="D extends Recordable = Recordable" name="PDescription">
|
|
2
|
+
import { computed } from 'vue';
|
|
3
|
+
import type { PDescriptionProps } from '#/antProxy';
|
|
4
|
+
import PDescriptionContent from '@/components/PDescriptionContent';
|
|
5
|
+
|
|
6
|
+
const props = withDefaults(defineProps<PDescriptionProps<D>>(), {
|
|
7
|
+
bordered: false,
|
|
8
|
+
column: 3,
|
|
9
|
+
size: 'default',
|
|
10
|
+
layout: 'horizontal',
|
|
11
|
+
colon: true,
|
|
12
|
+
emptyText: '-',
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
const descAttrs = computed(() => ({
|
|
16
|
+
title: props.title,
|
|
17
|
+
extra: props.extra,
|
|
18
|
+
bordered: props.bordered,
|
|
19
|
+
size: props.size,
|
|
20
|
+
column: props.column,
|
|
21
|
+
layout: props.layout,
|
|
22
|
+
colon: props.colon,
|
|
23
|
+
labelStyle: props.labelStyle,
|
|
24
|
+
contentStyle: props.contentStyle,
|
|
25
|
+
}));
|
|
26
|
+
</script>
|
|
27
|
+
<template>
|
|
28
|
+
<a-descriptions v-bind="descAttrs" class="p-description">
|
|
29
|
+
<template v-if="$slots.title || title" #title>
|
|
30
|
+
<slot name="title">{{ title }}</slot>
|
|
31
|
+
</template>
|
|
32
|
+
<template v-if="$slots.extra || extra" #extra>
|
|
33
|
+
<slot name="extra">{{ extra }}</slot>
|
|
34
|
+
</template>
|
|
35
|
+
|
|
36
|
+
<a-descriptions-item
|
|
37
|
+
v-for="(item, idx) in items"
|
|
38
|
+
:key="`_desc_${item.field ?? idx}`"
|
|
39
|
+
:label="item.label"
|
|
40
|
+
:span="item.span"
|
|
41
|
+
:label-style="item.labelStyle"
|
|
42
|
+
:content-style="item.contentStyle"
|
|
43
|
+
>
|
|
44
|
+
<template v-if="item.slots?.label" #label>
|
|
45
|
+
<component :is="item.slots.label" />
|
|
46
|
+
</template>
|
|
47
|
+
<p-description-content :item="item" :data="data" :empty-text="emptyText || '-'" />
|
|
48
|
+
</a-descriptions-item>
|
|
49
|
+
</a-descriptions>
|
|
50
|
+
</template>
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { defineComponent } from 'vue';
|
|
2
|
+
import type { PDescriptionItemProps } from '#/antProxy';
|
|
3
|
+
import renderStore from '@/store/renderStore';
|
|
4
|
+
import { isGoodValue } from '@/utils/is';
|
|
5
|
+
|
|
6
|
+
export default defineComponent(
|
|
7
|
+
<D extends Recordable = Recordable>(props: {
|
|
8
|
+
item: PDescriptionItemProps<D>;
|
|
9
|
+
data: D;
|
|
10
|
+
emptyText: string;
|
|
11
|
+
}) => {
|
|
12
|
+
return () => {
|
|
13
|
+
const { item, data, emptyText } = props;
|
|
14
|
+
|
|
15
|
+
// 1. 插槽优先
|
|
16
|
+
if (item.slots?.default) {
|
|
17
|
+
return item.slots.default({ data, field: item.field });
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// 2. readonlyRender 派发到 renderReadonly(专为只读语境设计的渲染维度)
|
|
21
|
+
if (item.readonlyRender?.name) {
|
|
22
|
+
const r = item.readonlyRender;
|
|
23
|
+
const node =
|
|
24
|
+
renderStore.renders[r.name]?.renderReadonly?.(
|
|
25
|
+
r,
|
|
26
|
+
{
|
|
27
|
+
data,
|
|
28
|
+
field: item.field,
|
|
29
|
+
title: item.label,
|
|
30
|
+
},
|
|
31
|
+
{},
|
|
32
|
+
) ?? null;
|
|
33
|
+
if (node !== null) return node;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// 3. 原值;空值用 emptyText
|
|
37
|
+
if (!item.field) return emptyText;
|
|
38
|
+
const v = (data as Recordable)?.[item.field];
|
|
39
|
+
return isGoodValue(v) ? v : emptyText;
|
|
40
|
+
};
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
name: 'PDescriptionContent',
|
|
44
|
+
props: ['item', 'data', 'emptyText'],
|
|
45
|
+
},
|
|
46
|
+
);
|
|
@@ -5,6 +5,9 @@
|
|
|
5
5
|
setup
|
|
6
6
|
>
|
|
7
7
|
import { ColumnProps, PFormItemProps, PGridProps, ResponsePathConfig } from '#/antProxy';
|
|
8
|
+
// 锚定 ant-design-vue 间接依赖的类型路径,避免 vue-tsc 推断默认导出时引用 .pnpm 物理路径触发 TS2742
|
|
9
|
+
import type {} from 'scroll-into-view-if-needed';
|
|
10
|
+
import type {} from 'vue-types';
|
|
8
11
|
import PFormCol from '@/components/PFormCol.vue';
|
|
9
12
|
import RenderDefaultSlots from '@/components/RenderDefaultSlots';
|
|
10
13
|
import RenderTitleSlots from '@/components/RenderTitleSlots';
|