@tmagic/form 1.8.0-beta.27 → 1.8.0-beta.28
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/es/containers/GroupList.vue_vue_type_script_setup_true_lang.js +26 -12
- package/dist/es/style.css +40 -14
- package/dist/es/utils/tableGroupList.js +20 -1
- package/dist/style.css +40 -14
- package/dist/themes/magic-admin.css +40 -14
- package/dist/tmagic-form.umd.cjs +50 -19
- package/package.json +4 -4
- package/src/containers/GroupList.vue +23 -2
- package/src/theme/group-list.scss +52 -27
- package/src/utils/tableGroupList.ts +28 -1
|
@@ -1,15 +1,15 @@
|
|
|
1
|
+
import { getGroupListHeaderVars } from "../utils/tableGroupList.js";
|
|
1
2
|
import GroupListItem_default from "./GroupListItem.js";
|
|
2
|
-
import { Fragment, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createSlots, defineComponent, mergeProps, normalizeClass, openBlock, renderList, renderSlot, toDisplayString, withCtx } from "vue";
|
|
3
|
+
import { Fragment, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createSlots, defineComponent, mergeProps, normalizeClass, normalizeStyle, openBlock, renderList, renderSlot, toDisplayString, withCtx } from "vue";
|
|
3
4
|
import { cloneDeep } from "lodash-es";
|
|
4
5
|
//#region packages/form/src/containers/GroupList.vue?vue&type=script&setup=true&lang.ts
|
|
5
|
-
var _hoisted_1 =
|
|
6
|
-
var _hoisted_2 =
|
|
7
|
-
var _hoisted_3 = {
|
|
6
|
+
var _hoisted_1 = ["innerHTML"];
|
|
7
|
+
var _hoisted_2 = {
|
|
8
8
|
key: 1,
|
|
9
9
|
class: "el-table__empty-block"
|
|
10
10
|
};
|
|
11
|
-
var
|
|
12
|
-
var
|
|
11
|
+
var _hoisted_3 = { class: "el-table__empty-text t-table__empty" };
|
|
12
|
+
var _hoisted_4 = { style: {
|
|
13
13
|
"display": "flex",
|
|
14
14
|
"justify-content": "flex-end",
|
|
15
15
|
"flex": "1"
|
|
@@ -54,6 +54,14 @@ var GroupList_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ define
|
|
|
54
54
|
};
|
|
55
55
|
const onAddDiffCount = () => emit("addDiffCount");
|
|
56
56
|
const asList = (value) => Array.isArray(value) ? value : [];
|
|
57
|
+
const headerVars = computed(() => getGroupListHeaderVars(props.config.header));
|
|
58
|
+
/**
|
|
59
|
+
* 取 `$slots` 而不是 `useSlots()`:宿主切换 `addable` 时插槽会增删,
|
|
60
|
+
* computed 缓存不随插槽变化失效,只有在渲染期读才拿得到最新的。
|
|
61
|
+
*/
|
|
62
|
+
const hasFooter = (slots) => !props.isCompare && Boolean(slots["toggle-button"] || slots["add-button"]);
|
|
63
|
+
/** 只有真的渲染出吸底 footer,内层列表才需要为它让位 */
|
|
64
|
+
const isFooterSticky = (slots) => hasFooter(slots) && Boolean(props.config.addButtonConfig?.sticky);
|
|
57
65
|
const currentList = computed(() => asList(props.model[props.name]));
|
|
58
66
|
/** 对比时按当前/历史较长一侧对齐,已删除的项也能渲染出来 */
|
|
59
67
|
const displayItems = computed(() => {
|
|
@@ -71,13 +79,19 @@ var GroupList_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ define
|
|
|
71
79
|
}));
|
|
72
80
|
});
|
|
73
81
|
return (_ctx, _cache) => {
|
|
74
|
-
return openBlock(), createElementBlock("div",
|
|
82
|
+
return openBlock(), createElementBlock("div", {
|
|
83
|
+
class: normalizeClass(["m-fields-group-list", {
|
|
84
|
+
"is-header-sticky": Boolean(__props.config.header?.sticky),
|
|
85
|
+
"is-footer-sticky": isFooterSticky(_ctx.$slots)
|
|
86
|
+
}]),
|
|
87
|
+
style: normalizeStyle(headerVars.value)
|
|
88
|
+
}, [
|
|
75
89
|
__props.config.extra ? (openBlock(), createElementBlock("div", {
|
|
76
90
|
key: 0,
|
|
77
91
|
innerHTML: __props.config.extra,
|
|
78
92
|
style: { "color": "rgba(0, 0, 0, 0.45)" }
|
|
79
|
-
}, null, 8,
|
|
80
|
-
!displayItems.value.length ? (openBlock(), createElementBlock("div",
|
|
93
|
+
}, null, 8, _hoisted_1)) : createCommentVNode("v-if", true),
|
|
94
|
+
!displayItems.value.length ? (openBlock(), createElementBlock("div", _hoisted_2, [createElementVNode("span", _hoisted_3, "暂无" + toDisplayString(__props.config.titlePrefix || "") + "数据", 1)])) : (openBlock(true), createElementBlock(Fragment, { key: 2 }, renderList(displayItems.value, (entry) => {
|
|
81
95
|
return openBlock(), createBlock(GroupListItem_default, {
|
|
82
96
|
key: entry.index,
|
|
83
97
|
model: entry.item,
|
|
@@ -114,11 +128,11 @@ var GroupList_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ define
|
|
|
114
128
|
"group-model"
|
|
115
129
|
]);
|
|
116
130
|
}), 128)),
|
|
117
|
-
|
|
131
|
+
hasFooter(_ctx.$slots) ? (openBlock(), createElementBlock("div", {
|
|
118
132
|
key: 3,
|
|
119
133
|
class: normalizeClass(["m-fields-group-list-footer", { "is-sticky-full": Boolean(__props.config.addButtonConfig?.sticky) }])
|
|
120
|
-
}, [renderSlot(_ctx.$slots, "toggle-button"), createElementVNode("div",
|
|
121
|
-
]);
|
|
134
|
+
}, [renderSlot(_ctx.$slots, "toggle-button"), createElementVNode("div", _hoisted_4, [renderSlot(_ctx.$slots, "add-button")])], 2)) : createCommentVNode("v-if", true)
|
|
135
|
+
], 6);
|
|
122
136
|
};
|
|
123
137
|
}
|
|
124
138
|
});
|
package/dist/es/style.css
CHANGED
|
@@ -333,18 +333,48 @@ fieldset.m-fieldset .m-form-tip {
|
|
|
333
333
|
flex-shrink: 0;
|
|
334
334
|
gap: 8px;
|
|
335
335
|
}
|
|
336
|
-
.m-fields-group-list .m-fields-group-list-item
|
|
337
|
-
|
|
336
|
+
.m-fields-group-list > .m-fields-group-list-item {
|
|
337
|
+
--m-group-list-item-footer-bottom: var(
|
|
338
|
+
--m-group-list-nested-footer-bottom,
|
|
339
|
+
0px
|
|
340
|
+
);
|
|
341
|
+
}
|
|
342
|
+
.m-fields-group-list.is-footer-sticky > .m-fields-group-list-item {
|
|
343
|
+
--m-group-list-item-footer-bottom: calc(
|
|
344
|
+
var(--m-group-list-nested-footer-bottom, 0px) +
|
|
345
|
+
var(--m-group-list-footer-height)
|
|
346
|
+
);
|
|
347
|
+
}
|
|
348
|
+
.m-fields-group-list .m-fields-group-list-item .m-fields-group-list {
|
|
349
|
+
--m-group-list-nested-footer-bottom: var(
|
|
350
|
+
--m-group-list-item-footer-bottom,
|
|
351
|
+
0px
|
|
352
|
+
);
|
|
353
|
+
}
|
|
354
|
+
.m-fields-group-list.is-header-sticky {
|
|
355
|
+
--m-group-list-nested-sticky-top: var(--m-group-list-child-list-sticky-top);
|
|
356
|
+
--m-group-list-nested-header-z: var(--m-group-list-child-list-header-z);
|
|
357
|
+
}
|
|
358
|
+
.m-fields-group-list.is-header-sticky > .m-fields-group-list-item {
|
|
359
|
+
--m-group-list-item-sticky-top: var(
|
|
360
|
+
--m-group-list-nested-sticky-top,
|
|
361
|
+
var(--m-group-list-header-sticky-top, 0px)
|
|
362
|
+
);
|
|
363
|
+
--m-group-list-item-header-z: var(--m-group-list-nested-header-z, 7);
|
|
364
|
+
--m-group-list-child-list-sticky-top: calc(
|
|
365
|
+
var(--m-group-list-item-sticky-top) + var(--m-group-list-header-height)
|
|
366
|
+
);
|
|
367
|
+
--m-group-list-child-list-header-z: calc(
|
|
368
|
+
var(--m-group-list-item-header-z) - 1
|
|
369
|
+
);
|
|
370
|
+
}
|
|
371
|
+
.m-fields-group-list.is-header-sticky > .m-fields-group-list-item > .el-card__header,
|
|
372
|
+
.m-fields-group-list.is-header-sticky > .m-fields-group-list-item > .t-card__header {
|
|
338
373
|
position: sticky;
|
|
339
|
-
top: var(--m-group-list-
|
|
340
|
-
z-index:
|
|
374
|
+
top: var(--m-group-list-item-sticky-top);
|
|
375
|
+
z-index: var(--m-group-list-item-header-z);
|
|
341
376
|
background-color: var(--m-group-list-header-bg, #fff);
|
|
342
377
|
}
|
|
343
|
-
.m-fields-group-list .m-fields-group-list-item .m-fields-group-list-item > .el-card__header,
|
|
344
|
-
.m-fields-group-list .m-fields-group-list-item .m-fields-group-list-item > .t-card__header {
|
|
345
|
-
top: calc(var(--m-group-list-header-sticky-top, 0px) + var(--m-group-list-header-height));
|
|
346
|
-
z-index: 6;
|
|
347
|
-
}
|
|
348
378
|
.m-fields-group-list .el-table__empty-block {
|
|
349
379
|
width: 100%;
|
|
350
380
|
min-height: 0;
|
|
@@ -362,7 +392,7 @@ fieldset.m-fieldset .m-form-tip {
|
|
|
362
392
|
}
|
|
363
393
|
.m-fields-group-list > .m-fields-group-list-footer.is-sticky-full {
|
|
364
394
|
position: sticky;
|
|
365
|
-
bottom:
|
|
395
|
+
bottom: var(--m-group-list-nested-footer-bottom, 0px);
|
|
366
396
|
z-index: 7;
|
|
367
397
|
margin-bottom: 0;
|
|
368
398
|
padding: var(--m-group-list-footer-padding-top) 0 var(--m-group-list-footer-padding-bottom);
|
|
@@ -376,10 +406,6 @@ fieldset.m-fieldset .m-form-tip {
|
|
|
376
406
|
width: 100%;
|
|
377
407
|
height: var(--m-group-list-footer-button-height);
|
|
378
408
|
}
|
|
379
|
-
.m-fields-group-list .m-fields-group-list-item .m-fields-group-list > .m-fields-group-list-footer.is-sticky-full {
|
|
380
|
-
bottom: var(--m-group-list-footer-height);
|
|
381
|
-
z-index: 7;
|
|
382
|
-
}
|
|
383
409
|
|
|
384
410
|
/** 最外层的groupList需要每个item需要增加空白区域界限时,增加outer-gorup_list可以实现 */
|
|
385
411
|
.m-container-group-list.outer-gorup_list > .m-fields-group-list > .m-fields-group-list-item {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { cloneDeep } from "lodash-es";
|
|
2
|
+
import { isNumber } from "@tmagic/utils";
|
|
2
3
|
//#region packages/form/src/utils/tableGroupList.ts
|
|
3
4
|
/**
|
|
4
5
|
* table / group-list 是同一份配置的两种展示形态,可以互相切换(`TableGroupList.vue`)。
|
|
@@ -9,6 +10,24 @@ import { cloneDeep } from "lodash-es";
|
|
|
9
10
|
*/
|
|
10
11
|
/** group-list 形态的 type(兼容驼峰与中划线两种写法) */
|
|
11
12
|
var isGroupListType = (type) => type === "groupList" || type === "group-list";
|
|
13
|
+
/**
|
|
14
|
+
* 归一成带单位的 CSS 长度。
|
|
15
|
+
*
|
|
16
|
+
* 配置常常来自 JSON 或表单输入,`'48'` 这类无单位数字串很常见;直接写进 CSS 变量会让
|
|
17
|
+
* 嵌套层的 `calc()` 整体失效、吸顶静默失灵,所以纯数字一律补 `px`。
|
|
18
|
+
*/
|
|
19
|
+
var toCssLength = (height) => {
|
|
20
|
+
const value = `${height ?? ""}`.trim();
|
|
21
|
+
if (!value) return void 0;
|
|
22
|
+
if (isNumber(value)) return `${value}px`;
|
|
23
|
+
return typeof height === "number" ? void 0 : value;
|
|
24
|
+
};
|
|
25
|
+
/** header.sticky 开启时把 height 写成 CSS 变量,给嵌套吸顶偏移用 */
|
|
26
|
+
var getGroupListHeaderVars = (header) => {
|
|
27
|
+
if (!header?.sticky) return void 0;
|
|
28
|
+
const height = toCssLength(header.height);
|
|
29
|
+
return height ? { "--m-group-list-header-height": height } : void 0;
|
|
30
|
+
};
|
|
12
31
|
/** 按 label 文案长度估算 label 宽度(中文按 20px、其他按 8px,最小 80px) */
|
|
13
32
|
var calcLabelWidth = (label) => {
|
|
14
33
|
if (!label) return "0px";
|
|
@@ -82,4 +101,4 @@ var makeTableColumnConfig = (column, row) => {
|
|
|
82
101
|
return newConfig;
|
|
83
102
|
};
|
|
84
103
|
//#endregion
|
|
85
|
-
export { calcLabelWidth, getGroupListRowConfig, isGroupListType, isTableColumnRendered, makeTableColumnConfig, toGroupListConfig, toTableConfig };
|
|
104
|
+
export { calcLabelWidth, getGroupListHeaderVars, getGroupListRowConfig, isGroupListType, isTableColumnRendered, makeTableColumnConfig, toGroupListConfig, toTableConfig };
|
package/dist/style.css
CHANGED
|
@@ -333,18 +333,48 @@ fieldset.m-fieldset .m-form-tip {
|
|
|
333
333
|
flex-shrink: 0;
|
|
334
334
|
gap: 8px;
|
|
335
335
|
}
|
|
336
|
-
.m-fields-group-list .m-fields-group-list-item
|
|
337
|
-
|
|
336
|
+
.m-fields-group-list > .m-fields-group-list-item {
|
|
337
|
+
--m-group-list-item-footer-bottom: var(
|
|
338
|
+
--m-group-list-nested-footer-bottom,
|
|
339
|
+
0px
|
|
340
|
+
);
|
|
341
|
+
}
|
|
342
|
+
.m-fields-group-list.is-footer-sticky > .m-fields-group-list-item {
|
|
343
|
+
--m-group-list-item-footer-bottom: calc(
|
|
344
|
+
var(--m-group-list-nested-footer-bottom, 0px) +
|
|
345
|
+
var(--m-group-list-footer-height)
|
|
346
|
+
);
|
|
347
|
+
}
|
|
348
|
+
.m-fields-group-list .m-fields-group-list-item .m-fields-group-list {
|
|
349
|
+
--m-group-list-nested-footer-bottom: var(
|
|
350
|
+
--m-group-list-item-footer-bottom,
|
|
351
|
+
0px
|
|
352
|
+
);
|
|
353
|
+
}
|
|
354
|
+
.m-fields-group-list.is-header-sticky {
|
|
355
|
+
--m-group-list-nested-sticky-top: var(--m-group-list-child-list-sticky-top);
|
|
356
|
+
--m-group-list-nested-header-z: var(--m-group-list-child-list-header-z);
|
|
357
|
+
}
|
|
358
|
+
.m-fields-group-list.is-header-sticky > .m-fields-group-list-item {
|
|
359
|
+
--m-group-list-item-sticky-top: var(
|
|
360
|
+
--m-group-list-nested-sticky-top,
|
|
361
|
+
var(--m-group-list-header-sticky-top, 0px)
|
|
362
|
+
);
|
|
363
|
+
--m-group-list-item-header-z: var(--m-group-list-nested-header-z, 7);
|
|
364
|
+
--m-group-list-child-list-sticky-top: calc(
|
|
365
|
+
var(--m-group-list-item-sticky-top) + var(--m-group-list-header-height)
|
|
366
|
+
);
|
|
367
|
+
--m-group-list-child-list-header-z: calc(
|
|
368
|
+
var(--m-group-list-item-header-z) - 1
|
|
369
|
+
);
|
|
370
|
+
}
|
|
371
|
+
.m-fields-group-list.is-header-sticky > .m-fields-group-list-item > .el-card__header,
|
|
372
|
+
.m-fields-group-list.is-header-sticky > .m-fields-group-list-item > .t-card__header {
|
|
338
373
|
position: sticky;
|
|
339
|
-
top: var(--m-group-list-
|
|
340
|
-
z-index:
|
|
374
|
+
top: var(--m-group-list-item-sticky-top);
|
|
375
|
+
z-index: var(--m-group-list-item-header-z);
|
|
341
376
|
background-color: var(--m-group-list-header-bg, #fff);
|
|
342
377
|
}
|
|
343
|
-
.m-fields-group-list .m-fields-group-list-item .m-fields-group-list-item > .el-card__header,
|
|
344
|
-
.m-fields-group-list .m-fields-group-list-item .m-fields-group-list-item > .t-card__header {
|
|
345
|
-
top: calc(var(--m-group-list-header-sticky-top, 0px) + var(--m-group-list-header-height));
|
|
346
|
-
z-index: 6;
|
|
347
|
-
}
|
|
348
378
|
.m-fields-group-list .el-table__empty-block {
|
|
349
379
|
width: 100%;
|
|
350
380
|
min-height: 0;
|
|
@@ -362,7 +392,7 @@ fieldset.m-fieldset .m-form-tip {
|
|
|
362
392
|
}
|
|
363
393
|
.m-fields-group-list > .m-fields-group-list-footer.is-sticky-full {
|
|
364
394
|
position: sticky;
|
|
365
|
-
bottom:
|
|
395
|
+
bottom: var(--m-group-list-nested-footer-bottom, 0px);
|
|
366
396
|
z-index: 7;
|
|
367
397
|
margin-bottom: 0;
|
|
368
398
|
padding: var(--m-group-list-footer-padding-top) 0 var(--m-group-list-footer-padding-bottom);
|
|
@@ -376,10 +406,6 @@ fieldset.m-fieldset .m-form-tip {
|
|
|
376
406
|
width: 100%;
|
|
377
407
|
height: var(--m-group-list-footer-button-height);
|
|
378
408
|
}
|
|
379
|
-
.m-fields-group-list .m-fields-group-list-item .m-fields-group-list > .m-fields-group-list-footer.is-sticky-full {
|
|
380
|
-
bottom: var(--m-group-list-footer-height);
|
|
381
|
-
z-index: 7;
|
|
382
|
-
}
|
|
383
409
|
|
|
384
410
|
/** 最外层的groupList需要每个item需要增加空白区域界限时,增加outer-gorup_list可以实现 */
|
|
385
411
|
.m-container-group-list.outer-gorup_list > .m-fields-group-list > .m-fields-group-list-item {
|
|
@@ -333,18 +333,48 @@ fieldset.m-fieldset .m-form-tip {
|
|
|
333
333
|
flex-shrink: 0;
|
|
334
334
|
gap: 8px;
|
|
335
335
|
}
|
|
336
|
-
.m-fields-group-list .m-fields-group-list-item
|
|
337
|
-
|
|
336
|
+
.m-fields-group-list > .m-fields-group-list-item {
|
|
337
|
+
--m-group-list-item-footer-bottom: var(
|
|
338
|
+
--m-group-list-nested-footer-bottom,
|
|
339
|
+
0px
|
|
340
|
+
);
|
|
341
|
+
}
|
|
342
|
+
.m-fields-group-list.is-footer-sticky > .m-fields-group-list-item {
|
|
343
|
+
--m-group-list-item-footer-bottom: calc(
|
|
344
|
+
var(--m-group-list-nested-footer-bottom, 0px) +
|
|
345
|
+
var(--m-group-list-footer-height)
|
|
346
|
+
);
|
|
347
|
+
}
|
|
348
|
+
.m-fields-group-list .m-fields-group-list-item .m-fields-group-list {
|
|
349
|
+
--m-group-list-nested-footer-bottom: var(
|
|
350
|
+
--m-group-list-item-footer-bottom,
|
|
351
|
+
0px
|
|
352
|
+
);
|
|
353
|
+
}
|
|
354
|
+
.m-fields-group-list.is-header-sticky {
|
|
355
|
+
--m-group-list-nested-sticky-top: var(--m-group-list-child-list-sticky-top);
|
|
356
|
+
--m-group-list-nested-header-z: var(--m-group-list-child-list-header-z);
|
|
357
|
+
}
|
|
358
|
+
.m-fields-group-list.is-header-sticky > .m-fields-group-list-item {
|
|
359
|
+
--m-group-list-item-sticky-top: var(
|
|
360
|
+
--m-group-list-nested-sticky-top,
|
|
361
|
+
var(--m-group-list-header-sticky-top, 0px)
|
|
362
|
+
);
|
|
363
|
+
--m-group-list-item-header-z: var(--m-group-list-nested-header-z, 7);
|
|
364
|
+
--m-group-list-child-list-sticky-top: calc(
|
|
365
|
+
var(--m-group-list-item-sticky-top) + var(--m-group-list-header-height)
|
|
366
|
+
);
|
|
367
|
+
--m-group-list-child-list-header-z: calc(
|
|
368
|
+
var(--m-group-list-item-header-z) - 1
|
|
369
|
+
);
|
|
370
|
+
}
|
|
371
|
+
.m-fields-group-list.is-header-sticky > .m-fields-group-list-item > .el-card__header,
|
|
372
|
+
.m-fields-group-list.is-header-sticky > .m-fields-group-list-item > .t-card__header {
|
|
338
373
|
position: sticky;
|
|
339
|
-
top: var(--m-group-list-
|
|
340
|
-
z-index:
|
|
374
|
+
top: var(--m-group-list-item-sticky-top);
|
|
375
|
+
z-index: var(--m-group-list-item-header-z);
|
|
341
376
|
background-color: var(--m-group-list-header-bg, #fff);
|
|
342
377
|
}
|
|
343
|
-
.m-fields-group-list .m-fields-group-list-item .m-fields-group-list-item > .el-card__header,
|
|
344
|
-
.m-fields-group-list .m-fields-group-list-item .m-fields-group-list-item > .t-card__header {
|
|
345
|
-
top: calc(var(--m-group-list-header-sticky-top, 0px) + var(--m-group-list-header-height));
|
|
346
|
-
z-index: 6;
|
|
347
|
-
}
|
|
348
378
|
.m-fields-group-list .el-table__empty-block {
|
|
349
379
|
width: 100%;
|
|
350
380
|
min-height: 0;
|
|
@@ -362,7 +392,7 @@ fieldset.m-fieldset .m-form-tip {
|
|
|
362
392
|
}
|
|
363
393
|
.m-fields-group-list > .m-fields-group-list-footer.is-sticky-full {
|
|
364
394
|
position: sticky;
|
|
365
|
-
bottom:
|
|
395
|
+
bottom: var(--m-group-list-nested-footer-bottom, 0px);
|
|
366
396
|
z-index: 7;
|
|
367
397
|
margin-bottom: 0;
|
|
368
398
|
padding: var(--m-group-list-footer-padding-top) 0 var(--m-group-list-footer-padding-bottom);
|
|
@@ -376,10 +406,6 @@ fieldset.m-fieldset .m-form-tip {
|
|
|
376
406
|
width: 100%;
|
|
377
407
|
height: var(--m-group-list-footer-button-height);
|
|
378
408
|
}
|
|
379
|
-
.m-fields-group-list .m-fields-group-list-item .m-fields-group-list > .m-fields-group-list-footer.is-sticky-full {
|
|
380
|
-
bottom: var(--m-group-list-footer-height);
|
|
381
|
-
z-index: 7;
|
|
382
|
-
}
|
|
383
409
|
|
|
384
410
|
/** 最外层的groupList需要每个item需要增加空白区域界限时,增加outer-gorup_list可以实现 */
|
|
385
411
|
.m-container-group-list.outer-gorup_list > .m-fields-group-list > .m-fields-group-list-item {
|
package/dist/tmagic-form.umd.cjs
CHANGED
|
@@ -3795,6 +3795,24 @@
|
|
|
3795
3795
|
*/
|
|
3796
3796
|
/** group-list 形态的 type(兼容驼峰与中划线两种写法) */
|
|
3797
3797
|
var isGroupListType = (type) => type === "groupList" || type === "group-list";
|
|
3798
|
+
/**
|
|
3799
|
+
* 归一成带单位的 CSS 长度。
|
|
3800
|
+
*
|
|
3801
|
+
* 配置常常来自 JSON 或表单输入,`'48'` 这类无单位数字串很常见;直接写进 CSS 变量会让
|
|
3802
|
+
* 嵌套层的 `calc()` 整体失效、吸顶静默失灵,所以纯数字一律补 `px`。
|
|
3803
|
+
*/
|
|
3804
|
+
var toCssLength = (height) => {
|
|
3805
|
+
const value = `${height ?? ""}`.trim();
|
|
3806
|
+
if (!value) return void 0;
|
|
3807
|
+
if ((0, _tmagic_utils.isNumber)(value)) return `${value}px`;
|
|
3808
|
+
return typeof height === "number" ? void 0 : value;
|
|
3809
|
+
};
|
|
3810
|
+
/** header.sticky 开启时把 height 写成 CSS 变量,给嵌套吸顶偏移用 */
|
|
3811
|
+
var getGroupListHeaderVars = (header) => {
|
|
3812
|
+
if (!header?.sticky) return void 0;
|
|
3813
|
+
const height = toCssLength(header.height);
|
|
3814
|
+
return height ? { "--m-group-list-header-height": height } : void 0;
|
|
3815
|
+
};
|
|
3798
3816
|
/** 按 label 文案长度估算 label 宽度(中文按 20px、其他按 8px,最小 80px) */
|
|
3799
3817
|
var calcLabelWidth = (label) => {
|
|
3800
3818
|
if (!label) return "0px";
|
|
@@ -4725,7 +4743,7 @@
|
|
|
4725
4743
|
};
|
|
4726
4744
|
var _hoisted_3$7 = ["innerHTML"];
|
|
4727
4745
|
var _hoisted_4$6 = ["innerHTML"];
|
|
4728
|
-
var _hoisted_5$
|
|
4746
|
+
var _hoisted_5$4 = ["innerHTML"];
|
|
4729
4747
|
var _hoisted_6$3 = ["innerHTML"];
|
|
4730
4748
|
var _hoisted_7$2 = ["innerHTML"];
|
|
4731
4749
|
var _hoisted_8$2 = ["innerHTML"];
|
|
@@ -5080,7 +5098,7 @@
|
|
|
5080
5098
|
key: 0,
|
|
5081
5099
|
placement: tooltip.value.placement
|
|
5082
5100
|
}, {
|
|
5083
|
-
content: (0, vue.withCtx)(() => [(0, vue.createElementVNode)("div", { innerHTML: tooltip.value.text }, null, 8, _hoisted_5$
|
|
5101
|
+
content: (0, vue.withCtx)(() => [(0, vue.createElementVNode)("div", { innerHTML: tooltip.value.text }, null, 8, _hoisted_5$4)]),
|
|
5084
5102
|
default: (0, vue.withCtx)(() => [((0, vue.openBlock)(), (0, vue.createBlock)((0, vue.resolveDynamicComponent)(tagName.value), (0, vue.mergeProps)(fieldsProps.value, {
|
|
5085
5103
|
model: __props.model,
|
|
5086
5104
|
"last-values": __props.lastValues,
|
|
@@ -6478,7 +6496,7 @@
|
|
|
6478
6496
|
var _hoisted_2$7 = ["innerHTML"];
|
|
6479
6497
|
var _hoisted_3$6 = { key: 1 };
|
|
6480
6498
|
var _hoisted_4$5 = ["innerHTML"];
|
|
6481
|
-
var _hoisted_5$
|
|
6499
|
+
var _hoisted_5$3 = ["innerHTML"];
|
|
6482
6500
|
var _hoisted_6$2 = {
|
|
6483
6501
|
key: 2,
|
|
6484
6502
|
style: { "display": "flex" }
|
|
@@ -6569,7 +6587,7 @@
|
|
|
6569
6587
|
key: 0,
|
|
6570
6588
|
innerHTML: __props.config.extra,
|
|
6571
6589
|
class: "m-form-tip"
|
|
6572
|
-
}, null, 8, _hoisted_5$
|
|
6590
|
+
}, null, 8, _hoisted_5$3)) : (0, vue.createCommentVNode)("v-if", true)])), __props.config.schematic && show.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_6$2, [(0, vue.createElementVNode)("div", _hoisted_7$1, [((0, vue.openBlock)(true), (0, vue.createElementBlock)(vue.Fragment, null, (0, vue.renderList)(__props.config.items, (item, index) => {
|
|
6573
6591
|
return (0, vue.openBlock)(), (0, vue.createBlock)(Container_default, {
|
|
6574
6592
|
key: key(item, index),
|
|
6575
6593
|
model: name.value ? __props.model[name.value] : __props.model,
|
|
@@ -6707,7 +6725,7 @@
|
|
|
6707
6725
|
style: { "display": "flex" }
|
|
6708
6726
|
};
|
|
6709
6727
|
var _hoisted_4$4 = { style: { "flex": "1" } };
|
|
6710
|
-
var _hoisted_5$
|
|
6728
|
+
var _hoisted_5$2 = ["src"];
|
|
6711
6729
|
//#endregion
|
|
6712
6730
|
//#region packages/form/src/containers/Panel.vue
|
|
6713
6731
|
var Panel_default = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
@@ -6800,7 +6818,7 @@
|
|
|
6800
6818
|
}), 128))]), (0, vue.createElementVNode)("img", {
|
|
6801
6819
|
class: "m-form-schematic",
|
|
6802
6820
|
src: __props.config.schematic
|
|
6803
|
-
}, null, 8, _hoisted_5$
|
|
6821
|
+
}, null, 8, _hoisted_5$2)])) : ((0, vue.openBlock)(true), (0, vue.createElementBlock)(vue.Fragment, { key: 1 }, (0, vue.renderList)(items.value, (item, index) => {
|
|
6804
6822
|
return (0, vue.openBlock)(), (0, vue.createBlock)(Container_default, {
|
|
6805
6823
|
key: item[(0, vue.unref)(mForm)?.keyProp || "__key"] ?? index,
|
|
6806
6824
|
config: item,
|
|
@@ -7158,7 +7176,7 @@
|
|
|
7158
7176
|
var _hoisted_2$5 = { class: "m-fields-group-list-item-title" };
|
|
7159
7177
|
var _hoisted_3$4 = ["innerHTML"];
|
|
7160
7178
|
var _hoisted_4$3 = { class: "m-fields-group-list-item-actions" };
|
|
7161
|
-
var _hoisted_5$
|
|
7179
|
+
var _hoisted_5$1 = { style: {
|
|
7162
7180
|
"text-align": "right",
|
|
7163
7181
|
"margin-top": "20px"
|
|
7164
7182
|
} };
|
|
@@ -7323,7 +7341,7 @@
|
|
|
7323
7341
|
disabled: __props.disabled
|
|
7324
7342
|
}, null, 8, ["modelValue", "disabled"]),
|
|
7325
7343
|
_cache[11] || (_cache[11] = (0, vue.createTextVNode)("行 ", -1))
|
|
7326
|
-
]), (0, vue.createElementVNode)("div", _hoisted_5$
|
|
7344
|
+
]), (0, vue.createElementVNode)("div", _hoisted_5$1, [(0, vue.createVNode)((0, vue.unref)(_tmagic_design.TMagicButton), {
|
|
7327
7345
|
size: "small",
|
|
7328
7346
|
text: "",
|
|
7329
7347
|
onClick: _cache[4] || (_cache[4] = ($event) => moveSpecifyLocationVisible.value = false)
|
|
@@ -7393,14 +7411,13 @@
|
|
|
7393
7411
|
});
|
|
7394
7412
|
//#endregion
|
|
7395
7413
|
//#region packages/form/src/containers/GroupList.vue?vue&type=script&setup=true&lang.ts
|
|
7396
|
-
var _hoisted_1$8 =
|
|
7397
|
-
var _hoisted_2$4 =
|
|
7398
|
-
var _hoisted_3$3 = {
|
|
7414
|
+
var _hoisted_1$8 = ["innerHTML"];
|
|
7415
|
+
var _hoisted_2$4 = {
|
|
7399
7416
|
key: 1,
|
|
7400
7417
|
class: "el-table__empty-block"
|
|
7401
7418
|
};
|
|
7402
|
-
var
|
|
7403
|
-
var
|
|
7419
|
+
var _hoisted_3$3 = { class: "el-table__empty-text t-table__empty" };
|
|
7420
|
+
var _hoisted_4$2 = { style: {
|
|
7404
7421
|
"display": "flex",
|
|
7405
7422
|
"justify-content": "flex-end",
|
|
7406
7423
|
"flex": "1"
|
|
@@ -7447,6 +7464,14 @@
|
|
|
7447
7464
|
};
|
|
7448
7465
|
const onAddDiffCount = () => emit("addDiffCount");
|
|
7449
7466
|
const asList = (value) => Array.isArray(value) ? value : [];
|
|
7467
|
+
const headerVars = (0, vue.computed)(() => getGroupListHeaderVars(props.config.header));
|
|
7468
|
+
/**
|
|
7469
|
+
* 取 `$slots` 而不是 `useSlots()`:宿主切换 `addable` 时插槽会增删,
|
|
7470
|
+
* computed 缓存不随插槽变化失效,只有在渲染期读才拿得到最新的。
|
|
7471
|
+
*/
|
|
7472
|
+
const hasFooter = (slots) => !props.isCompare && Boolean(slots["toggle-button"] || slots["add-button"]);
|
|
7473
|
+
/** 只有真的渲染出吸底 footer,内层列表才需要为它让位 */
|
|
7474
|
+
const isFooterSticky = (slots) => hasFooter(slots) && Boolean(props.config.addButtonConfig?.sticky);
|
|
7450
7475
|
const currentList = (0, vue.computed)(() => asList(props.model[props.name]));
|
|
7451
7476
|
/** 对比时按当前/历史较长一侧对齐,已删除的项也能渲染出来 */
|
|
7452
7477
|
const displayItems = (0, vue.computed)(() => {
|
|
@@ -7464,13 +7489,19 @@
|
|
|
7464
7489
|
}));
|
|
7465
7490
|
});
|
|
7466
7491
|
return (_ctx, _cache) => {
|
|
7467
|
-
return (0, vue.openBlock)(), (0, vue.createElementBlock)("div",
|
|
7492
|
+
return (0, vue.openBlock)(), (0, vue.createElementBlock)("div", {
|
|
7493
|
+
class: (0, vue.normalizeClass)(["m-fields-group-list", {
|
|
7494
|
+
"is-header-sticky": Boolean(__props.config.header?.sticky),
|
|
7495
|
+
"is-footer-sticky": isFooterSticky(_ctx.$slots)
|
|
7496
|
+
}]),
|
|
7497
|
+
style: (0, vue.normalizeStyle)(headerVars.value)
|
|
7498
|
+
}, [
|
|
7468
7499
|
__props.config.extra ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", {
|
|
7469
7500
|
key: 0,
|
|
7470
7501
|
innerHTML: __props.config.extra,
|
|
7471
7502
|
style: { "color": "rgba(0, 0, 0, 0.45)" }
|
|
7472
|
-
}, null, 8,
|
|
7473
|
-
!displayItems.value.length ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div",
|
|
7503
|
+
}, null, 8, _hoisted_1$8)) : (0, vue.createCommentVNode)("v-if", true),
|
|
7504
|
+
!displayItems.value.length ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_2$4, [(0, vue.createElementVNode)("span", _hoisted_3$3, "暂无" + (0, vue.toDisplayString)(__props.config.titlePrefix || "") + "数据", 1)])) : ((0, vue.openBlock)(true), (0, vue.createElementBlock)(vue.Fragment, { key: 2 }, (0, vue.renderList)(displayItems.value, (entry) => {
|
|
7474
7505
|
return (0, vue.openBlock)(), (0, vue.createBlock)(GroupListItem_default, {
|
|
7475
7506
|
key: entry.index,
|
|
7476
7507
|
model: entry.item,
|
|
@@ -7507,11 +7538,11 @@
|
|
|
7507
7538
|
"group-model"
|
|
7508
7539
|
]);
|
|
7509
7540
|
}), 128)),
|
|
7510
|
-
|
|
7541
|
+
hasFooter(_ctx.$slots) ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", {
|
|
7511
7542
|
key: 3,
|
|
7512
7543
|
class: (0, vue.normalizeClass)(["m-fields-group-list-footer", { "is-sticky-full": Boolean(__props.config.addButtonConfig?.sticky) }])
|
|
7513
|
-
}, [(0, vue.renderSlot)(_ctx.$slots, "toggle-button"), (0, vue.createElementVNode)("div",
|
|
7514
|
-
]);
|
|
7544
|
+
}, [(0, vue.renderSlot)(_ctx.$slots, "toggle-button"), (0, vue.createElementVNode)("div", _hoisted_4$2, [(0, vue.renderSlot)(_ctx.$slots, "add-button")])], 2)) : (0, vue.createCommentVNode)("v-if", true)
|
|
7545
|
+
], 6);
|
|
7515
7546
|
};
|
|
7516
7547
|
}
|
|
7517
7548
|
});
|
package/package.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "1.8.0-beta.
|
|
2
|
+
"version": "1.8.0-beta.28",
|
|
3
3
|
"name": "@tmagic/form",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"sideEffects": [
|
|
@@ -58,9 +58,9 @@
|
|
|
58
58
|
"peerDependencies": {
|
|
59
59
|
"typescript": "^6.0.3",
|
|
60
60
|
"vue": "^3.5.41",
|
|
61
|
-
"@tmagic/design": "1.8.0-beta.
|
|
62
|
-
"@tmagic/
|
|
63
|
-
"@tmagic/
|
|
61
|
+
"@tmagic/design": "1.8.0-beta.28",
|
|
62
|
+
"@tmagic/utils": "1.8.0-beta.28",
|
|
63
|
+
"@tmagic/form-schema": "1.8.0-beta.28"
|
|
64
64
|
},
|
|
65
65
|
"peerDependenciesMeta": {
|
|
66
66
|
"typescript": {
|
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div
|
|
2
|
+
<div
|
|
3
|
+
class="m-fields-group-list"
|
|
4
|
+
:class="{
|
|
5
|
+
'is-header-sticky': Boolean(config.header?.sticky),
|
|
6
|
+
'is-footer-sticky': isFooterSticky($slots),
|
|
7
|
+
}"
|
|
8
|
+
:style="headerVars"
|
|
9
|
+
>
|
|
3
10
|
<div v-if="config.extra" v-html="config.extra" style="color: rgba(0, 0, 0, 0.45)"></div>
|
|
4
11
|
<div v-if="!displayItems.length" class="el-table__empty-block">
|
|
5
12
|
<span class="el-table__empty-text t-table__empty">暂无{{ config.titlePrefix || '' }}数据</span>
|
|
@@ -34,7 +41,7 @@
|
|
|
34
41
|
<div
|
|
35
42
|
class="m-fields-group-list-footer"
|
|
36
43
|
:class="{ 'is-sticky-full': Boolean(config.addButtonConfig?.sticky) }"
|
|
37
|
-
v-if="
|
|
44
|
+
v-if="hasFooter($slots)"
|
|
38
45
|
>
|
|
39
46
|
<slot name="toggle-button"></slot>
|
|
40
47
|
<div style="display: flex; justify-content: flex-end; flex: 1">
|
|
@@ -49,6 +56,7 @@ import { computed } from 'vue';
|
|
|
49
56
|
import { cloneDeep } from 'lodash-es';
|
|
50
57
|
|
|
51
58
|
import type { ContainerChangeEventData, GroupListConfig } from '../schema';
|
|
59
|
+
import { getGroupListHeaderVars } from '../utils/tableGroupList';
|
|
52
60
|
|
|
53
61
|
import MFieldsGroupListItem from './GroupListItem.vue';
|
|
54
62
|
|
|
@@ -104,6 +112,19 @@ const onAddDiffCount = () => emit('addDiffCount');
|
|
|
104
112
|
|
|
105
113
|
const asList = (value: unknown): any[] => (Array.isArray(value) ? value : []);
|
|
106
114
|
|
|
115
|
+
const headerVars = computed(() => getGroupListHeaderVars(props.config.header));
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* 取 `$slots` 而不是 `useSlots()`:宿主切换 `addable` 时插槽会增删,
|
|
119
|
+
* computed 缓存不随插槽变化失效,只有在渲染期读才拿得到最新的。
|
|
120
|
+
*/
|
|
121
|
+
const hasFooter = (slots: Record<string, unknown>) =>
|
|
122
|
+
!props.isCompare && Boolean(slots['toggle-button'] || slots['add-button']);
|
|
123
|
+
|
|
124
|
+
/** 只有真的渲染出吸底 footer,内层列表才需要为它让位 */
|
|
125
|
+
const isFooterSticky = (slots: Record<string, unknown>) =>
|
|
126
|
+
hasFooter(slots) && Boolean(props.config.addButtonConfig?.sticky);
|
|
127
|
+
|
|
107
128
|
const currentList = computed(() => asList(props.model[props.name]));
|
|
108
129
|
|
|
109
130
|
/** 对比时按当前/历史较长一侧对齐,已删除的项也能渲染出来 */
|
|
@@ -70,27 +70,60 @@
|
|
|
70
70
|
flex-shrink: 0;
|
|
71
71
|
gap: 8px;
|
|
72
72
|
}
|
|
73
|
+
}
|
|
73
74
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
75
|
+
// 嵌套吸底按钮叠在外层 footer 之上(如「新增条件」叠在「新增条件组」上面)。
|
|
76
|
+
// 每穿过一层「自己渲染了吸底 footer」的列表才多让出一个 footer 高度,外层没有吸底按钮时
|
|
77
|
+
// 内层不能凭空抬高。自定义属性不能自增,所以用 item / list 两个变量交替接力。
|
|
78
|
+
> .m-fields-group-list-item {
|
|
79
|
+
--m-group-list-item-footer-bottom: var(
|
|
80
|
+
--m-group-list-nested-footer-bottom,
|
|
81
|
+
0px
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
&.is-footer-sticky > .m-fields-group-list-item {
|
|
86
|
+
--m-group-list-item-footer-bottom: calc(
|
|
87
|
+
var(--m-group-list-nested-footer-bottom, 0px) +
|
|
88
|
+
var(--m-group-list-footer-height)
|
|
89
|
+
);
|
|
83
90
|
}
|
|
84
91
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
+
.m-fields-group-list-item .m-fields-group-list {
|
|
93
|
+
--m-group-list-nested-footer-bottom: var(
|
|
94
|
+
--m-group-list-item-footer-bottom,
|
|
95
|
+
0px
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// 仅 header.sticky 时标题吸顶;直接子 item,避免外层吸顶带动未开启的内层
|
|
100
|
+
&.is-header-sticky {
|
|
101
|
+
// 从外层 item 接过已累加的偏移;最外层没有该变量时走 fallback
|
|
102
|
+
--m-group-list-nested-sticky-top: var(--m-group-list-child-list-sticky-top);
|
|
103
|
+
--m-group-list-nested-header-z: var(--m-group-list-child-list-header-z);
|
|
104
|
+
|
|
105
|
+
> .m-fields-group-list-item {
|
|
106
|
+
--m-group-list-item-sticky-top: var(
|
|
107
|
+
--m-group-list-nested-sticky-top,
|
|
108
|
+
var(--m-group-list-header-sticky-top, 0px)
|
|
92
109
|
);
|
|
93
|
-
z
|
|
110
|
+
--m-group-list-item-header-z: var(--m-group-list-nested-header-z, 7);
|
|
111
|
+
--m-group-list-child-list-sticky-top: calc(
|
|
112
|
+
var(--m-group-list-item-sticky-top) + var(--m-group-list-header-height)
|
|
113
|
+
);
|
|
114
|
+
--m-group-list-child-list-header-z: calc(
|
|
115
|
+
var(--m-group-list-item-header-z) - 1
|
|
116
|
+
);
|
|
117
|
+
|
|
118
|
+
// 卡片标题吸顶;补不透明背景,避免滚动时正文透出。
|
|
119
|
+
// z-index 必须低于吸底 footer,否则标题会盖住「新增」按钮。
|
|
120
|
+
> .el-card__header,
|
|
121
|
+
> .t-card__header {
|
|
122
|
+
position: sticky;
|
|
123
|
+
top: var(--m-group-list-item-sticky-top);
|
|
124
|
+
z-index: var(--m-group-list-item-header-z);
|
|
125
|
+
background-color: var(--m-group-list-header-bg, #fff);
|
|
126
|
+
}
|
|
94
127
|
}
|
|
95
128
|
}
|
|
96
129
|
|
|
@@ -113,10 +146,10 @@
|
|
|
113
146
|
}
|
|
114
147
|
|
|
115
148
|
// 吸底全宽主按钮(event-select / code-select / display-conds 外层列表)
|
|
116
|
-
// z-index 高于 item header
|
|
149
|
+
// z-index 高于 item header,避免吸顶标题挡住新增按钮;多层时 bottom 由内层 list 累加
|
|
117
150
|
> .m-fields-group-list-footer.is-sticky-full {
|
|
118
151
|
position: sticky;
|
|
119
|
-
bottom:
|
|
152
|
+
bottom: var(--m-group-list-nested-footer-bottom, 0px);
|
|
120
153
|
z-index: 7;
|
|
121
154
|
margin-bottom: 0;
|
|
122
155
|
padding: var(--m-group-list-footer-padding-top) 0
|
|
@@ -133,14 +166,6 @@
|
|
|
133
166
|
height: var(--m-group-list-footer-button-height);
|
|
134
167
|
}
|
|
135
168
|
}
|
|
136
|
-
|
|
137
|
-
// 嵌套吸底按钮叠在外层 footer 之上(如「新增条件」叠在「新增条件组」上面)
|
|
138
|
-
.m-fields-group-list-item
|
|
139
|
-
.m-fields-group-list
|
|
140
|
-
> .m-fields-group-list-footer.is-sticky-full {
|
|
141
|
-
bottom: var(--m-group-list-footer-height);
|
|
142
|
-
z-index: 7;
|
|
143
|
-
}
|
|
144
169
|
}
|
|
145
170
|
|
|
146
171
|
/** 最外层的groupList需要每个item需要增加空白区域界限时,增加outer-gorup_list可以实现 */
|
|
@@ -18,7 +18,9 @@
|
|
|
18
18
|
|
|
19
19
|
import { cloneDeep } from 'lodash-es';
|
|
20
20
|
|
|
21
|
-
import
|
|
21
|
+
import { isNumber } from '@tmagic/utils';
|
|
22
|
+
|
|
23
|
+
import type { GroupListConfig, GroupListHeaderConfig, TableColumnConfig, TableConfig } from '../schema';
|
|
22
24
|
|
|
23
25
|
/**
|
|
24
26
|
* table / group-list 是同一份配置的两种展示形态,可以互相切换(`TableGroupList.vue`)。
|
|
@@ -31,6 +33,31 @@ import type { GroupListConfig, TableColumnConfig, TableConfig } from '../schema'
|
|
|
31
33
|
/** group-list 形态的 type(兼容驼峰与中划线两种写法) */
|
|
32
34
|
export const isGroupListType = (type: unknown): boolean => type === 'groupList' || type === 'group-list';
|
|
33
35
|
|
|
36
|
+
/**
|
|
37
|
+
* 归一成带单位的 CSS 长度。
|
|
38
|
+
*
|
|
39
|
+
* 配置常常来自 JSON 或表单输入,`'48'` 这类无单位数字串很常见;直接写进 CSS 变量会让
|
|
40
|
+
* 嵌套层的 `calc()` 整体失效、吸顶静默失灵,所以纯数字一律补 `px`。
|
|
41
|
+
*/
|
|
42
|
+
const toCssLength = (height: number | string | undefined): string | undefined => {
|
|
43
|
+
const value = `${height ?? ''}`.trim();
|
|
44
|
+
if (!value) return undefined;
|
|
45
|
+
|
|
46
|
+
if (isNumber(value)) return `${value}px`;
|
|
47
|
+
// 走到这里还是 number 的只剩 NaN / Infinity,不写变量,交给样式默认值兜底
|
|
48
|
+
return typeof height === 'number' ? undefined : value;
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
/** header.sticky 开启时把 height 写成 CSS 变量,给嵌套吸顶偏移用 */
|
|
52
|
+
export const getGroupListHeaderVars = (
|
|
53
|
+
header: GroupListHeaderConfig | undefined,
|
|
54
|
+
): Record<string, string> | undefined => {
|
|
55
|
+
if (!header?.sticky) return undefined;
|
|
56
|
+
|
|
57
|
+
const height = toCssLength(header.height);
|
|
58
|
+
return height ? { '--m-group-list-header-height': height } : undefined;
|
|
59
|
+
};
|
|
60
|
+
|
|
34
61
|
/** 按 label 文案长度估算 label 宽度(中文按 20px、其他按 8px,最小 80px) */
|
|
35
62
|
export const calcLabelWidth = (label: string): string => {
|
|
36
63
|
if (!label) return '0px';
|