@done-coding/admin-core 0.29.0 → 0.29.1-alpha.0

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.
Files changed (86) hide show
  1. package/es/bridge/layout.mjs +31 -2
  2. package/es/components/app-layout/AppAside.vue.mjs +1 -1
  3. package/es/components/app-layout/AppCollapseToggle.vue.mjs +1 -1
  4. package/es/components/app-layout/AppFooter.vue.mjs +1 -1
  5. package/es/components/app-layout/AppHeader.vue.mjs +1 -1
  6. package/es/components/app-layout/AppHeader.vue2.mjs +1 -1
  7. package/es/components/app-layout/AppSidebar.vue.mjs +1 -1
  8. package/es/components/app-layout/AppSidebar.vue2.mjs +60 -34
  9. package/es/components/data-view/DataGridView.vue.mjs +1 -1
  10. package/es/components/data-view/DataGridView.vue2.mjs +30 -6
  11. package/es/components/data-view/DataListView.vue.mjs +1 -1
  12. package/es/components/data-view/DataListView.vue2.mjs +38 -14
  13. package/es/components/data-view/DataListViewItem.vue.mjs +1 -1
  14. package/es/components/data-view/DataListViewItem.vue2.mjs +23 -4
  15. package/es/components/data-view/InfiniteListView.vue.mjs +1 -1
  16. package/es/components/data-view/InfiniteListView.vue2.mjs +9 -3
  17. package/es/components/data-view/use-grid-layout.mjs +46 -0
  18. package/es/components/data-view/use-masonry.mjs +65 -0
  19. package/es/components/display/BadgeMark.vue.mjs +1 -1
  20. package/es/components/display/BadgeMark.vue2.mjs +11 -3
  21. package/es/components/display/HeightProvider.vue.mjs +17 -3
  22. package/es/components/display/use-badge.mjs +22 -13
  23. package/es/components/form/use-upload-state.mjs +33 -11
  24. package/es/components/page-layout/AppPageDetail.vue.mjs +1 -1
  25. package/es/components/page-layout/AppPageDetail.vue2.mjs +12 -2
  26. package/es/components/page-layout/AppPageListDetailLayout.vue.mjs +11 -4
  27. package/es/components/page-layout/AppPageListDetailSheet.vue.mjs +8 -1
  28. package/es/components/page-layout/AppPageListDetailSplit.vue.mjs +1 -1
  29. package/es/components/page-layout/AppPageListDetailSplit.vue2.mjs +8 -1
  30. package/es/components/table/TableMain.vue.mjs +1 -1
  31. package/es/components/table/TableMain.vue2.mjs +8 -5
  32. package/es/components/view-layout/ViewLayout.vue.mjs +1 -1
  33. package/es/components/view-layout/ViewLayout.vue2.mjs +68 -20
  34. package/es/hooks/use-surface.mjs +4 -1
  35. package/es/hooks/use-theme-apply.mjs +78 -0
  36. package/es/index.mjs +118 -120
  37. package/es/store/app.mjs +25 -0
  38. package/es/style.css +120 -95
  39. package/package.json +2 -2
  40. package/src/bridge/docs/README.md +31 -0
  41. package/src/components/app-layout/docs/README-AppAside.md +11 -0
  42. package/src/components/app-layout/docs/README-AppFooter.md +11 -1
  43. package/src/components/app-layout/docs/README-AppHeader.md +16 -0
  44. package/src/components/app-layout/docs/README-AppSidebar.md +18 -0
  45. package/src/components/data-view/README.md +2 -1
  46. package/src/components/data-view/docs/README-DataGridView.md +21 -1
  47. package/src/components/data-view/docs/README-DataListView.md +65 -3
  48. package/src/components/data-view/docs/README-InfiniteListView.md +17 -0
  49. package/src/components/display/README.md +1 -1
  50. package/src/components/display/docs/README-BadgeMark.md +52 -10
  51. package/src/components/display/docs/README-HeightProvider.md +14 -8
  52. package/src/components/form/docs/README-FormUpload.md +79 -0
  53. package/src/components/form/docs/README-FormUploadImage.md +19 -0
  54. package/src/components/form/docs/README-FormUploadVideo.md +19 -0
  55. package/src/components/page-layout/README.md +15 -0
  56. package/src/components/page-layout/docs/README-AppPageDetail.md +3 -0
  57. package/src/components/page-layout/docs/README-AppPageListDetailLayout.md +33 -0
  58. package/src/components/table/docs/README-TableMain.md +17 -0
  59. package/src/components/view-layout/README.md +2 -2
  60. package/src/components/view-layout/docs/README-ViewLayout.md +97 -6
  61. package/types/bridge/badge.d.ts +3 -1
  62. package/types/bridge/layout.d.ts +42 -5
  63. package/types/components/app-layout/AppSidebar.vue.d.ts +286 -2
  64. package/types/components/app-layout/types.d.ts +1 -1
  65. package/types/components/data-view/DataListViewItem.vue.d.ts +12 -7
  66. package/types/components/data-view/types.d.ts +76 -0
  67. package/types/components/data-view/use-grid-layout.d.ts +42 -0
  68. package/types/components/data-view/use-masonry.d.ts +44 -0
  69. package/types/components/display/BadgeMark.vue.d.ts +5 -5
  70. package/types/components/display/HeightProvider.vue.d.ts +1 -0
  71. package/types/components/display/use-badge.d.ts +6 -0
  72. package/types/components/page-layout/AppPageDetail.vue.d.ts +18 -0
  73. package/types/components/page-layout/AppPageListDetailLayout.vue.d.ts +20 -0
  74. package/types/components/page-layout/AppPageListDetailSheet.vue.d.ts +4 -0
  75. package/types/components/page-layout/AppPageListDetailSplit.vue.d.ts +4 -0
  76. package/types/components/table/types.d.ts +8 -0
  77. package/types/components/view-layout/ViewLayout.vue.d.ts +30 -0
  78. package/types/components/view-layout/types.d.ts +12 -0
  79. package/types/hooks/use-surface.d.ts +11 -0
  80. package/types/index.d.ts +0 -1
  81. package/types/injectInfo.json.d.ts +1 -1
  82. package/es/components/icon/IconHammer.vue.mjs +0 -26
  83. package/es/components/icon/IconHammer.vue2.mjs +0 -4
  84. package/src/components/icon/README.md +0 -38
  85. package/types/components/icon/IconHammer.vue.d.ts +0 -2
  86. package/types/components/icon/index.d.ts +0 -7
@@ -0,0 +1,65 @@
1
+ import { ref, watch, nextTick, onScopeDispose } from "vue";
2
+ const MASONRY_ROW_UNIT = 4;
3
+ const useDataViewMasonry = (options) => {
4
+ const masonrySpans = ref([]);
5
+ const masonryContainerStyle = ref(void 0);
6
+ const hasRO = typeof ResizeObserver !== "undefined";
7
+ let observer;
8
+ const measureAll = () => {
9
+ if (!options.enabled()) return;
10
+ const el = options.container();
11
+ if (!el) return;
12
+ const gap = options.gap();
13
+ const items = Array.from(el.children);
14
+ const next = items.map((item) => {
15
+ if (item.dataset.masonrySkip !== void 0) return void 0;
16
+ const h = item.getBoundingClientRect().height;
17
+ if (!h) return void 0;
18
+ return Math.ceil((h + gap) / MASONRY_ROW_UNIT);
19
+ });
20
+ const same = next.length === masonrySpans.value.length && next.every((v, i) => v === masonrySpans.value[i]);
21
+ if (!same) masonrySpans.value = next;
22
+ if (observer) items.forEach((item) => observer == null ? void 0 : observer.observe(item));
23
+ };
24
+ const start = () => {
25
+ masonryContainerStyle.value = {
26
+ gridAutoRows: `${MASONRY_ROW_UNIT}px`,
27
+ // 行距由跨度里的 gap 分量承担,[MUST NOT] 再叠 row-gap(会双倍)
28
+ rowGap: "0px"
29
+ };
30
+ if (hasRO && !observer) {
31
+ observer = new ResizeObserver(() => measureAll());
32
+ }
33
+ nextTick(measureAll);
34
+ };
35
+ const stop = () => {
36
+ observer == null ? void 0 : observer.disconnect();
37
+ observer = void 0;
38
+ masonryContainerStyle.value = void 0;
39
+ masonrySpans.value = [];
40
+ };
41
+ watch(
42
+ () => options.enabled(),
43
+ (on) => on ? start() : stop(),
44
+ { immediate: true }
45
+ );
46
+ watch(
47
+ () => options.data(),
48
+ () => {
49
+ if (options.enabled()) nextTick(measureAll);
50
+ }
51
+ );
52
+ watch(
53
+ () => options.container(),
54
+ (el) => {
55
+ if (el && observer) observer.observe(el);
56
+ if (el) nextTick(measureAll);
57
+ },
58
+ { immediate: true }
59
+ );
60
+ onScopeDispose(stop);
61
+ return { masonrySpans, masonryContainerStyle };
62
+ };
63
+ export {
64
+ useDataViewMasonry
65
+ };
@@ -1,7 +1,7 @@
1
1
  import _sfc_main from "./BadgeMark.vue2.mjs";
2
2
  /* empty css */
3
3
  import _export_sfc from "../../_virtual/_plugin-vue_export-helper.mjs";
4
- const BadgeMark = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-18853ddc"]]);
4
+ const BadgeMark = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-9eb89306"]]);
5
5
  export {
6
6
  BadgeMark as default
7
7
  };
@@ -1,4 +1,4 @@
1
- import { defineComponent, computed, useTemplateRef, openBlock, createBlock, unref, normalizeProps, createSlots, withCtx, renderSlot, createVNode, resolveDynamicComponent } from "vue";
1
+ import { defineComponent, computed, useTemplateRef, openBlock, createBlock, unref, normalizeProps, createSlots, withCtx, renderSlot, createVNode, normalizeStyle, resolveDynamicComponent } from "vue";
2
2
  import { ElBadge, ElTooltip, ElIcon } from "element-plus";
3
3
  import { useBadgeHit, badgeResolveDisplay } from "./use-badge.mjs";
4
4
  import { useBadgeMask } from "./use-badge-mask.mjs";
@@ -16,6 +16,11 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
16
16
  var _a;
17
17
  return badgeResolveDisplay((_a = hit.value) == null ? void 0 : _a.entry);
18
18
  });
19
+ const iconStyle = computed(() => {
20
+ var _a;
21
+ const scale = (_a = resolved.value) == null ? void 0 : _a.iconScale;
22
+ return scale === void 0 ? void 0 : { fontSize: `${scale}em` };
23
+ });
19
24
  const badgeRef = useTemplateRef("badgeRef");
20
25
  useBadgeMask(
21
26
  () => {
@@ -53,12 +58,15 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
53
58
  placement: "top"
54
59
  }, {
55
60
  default: withCtx(() => [
56
- createVNode(unref(ElIcon), { class: "badge-mark__icon" }, {
61
+ createVNode(unref(ElIcon), {
62
+ class: "badge-mark__icon",
63
+ style: normalizeStyle(iconStyle.value)
64
+ }, {
57
65
  default: withCtx(() => [
58
66
  (openBlock(), createBlock(resolveDynamicComponent(resolved.value.icon)))
59
67
  ]),
60
68
  _: 1
61
- })
69
+ }, 8, ["style"])
62
70
  ]),
63
71
  _: 1
64
72
  }, 8, ["content"])
@@ -10,12 +10,17 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
10
10
  setup(__props, { emit: __emit }) {
11
11
  const props = __props;
12
12
  const emits = __emit;
13
- const reserve = ref(0);
13
+ const headerReserve = ref(0);
14
+ const footerReserve = ref(0);
15
+ const reserve = computed(() => headerReserve.value + footerReserve.value);
14
16
  const available = computed(
15
17
  () => Math.max(props.viewportHeight - reserve.value, props.minHeight)
16
18
  );
17
19
  const onHeaderHeightChange = (height) => {
18
- reserve.value = height;
20
+ headerReserve.value = height;
21
+ };
22
+ const onFooterHeightChange = (height) => {
23
+ footerReserve.value = height;
19
24
  };
20
25
  const defaultSlotProps = computed(
21
26
  () => {
@@ -38,7 +43,16 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
38
43
  ]),
39
44
  _: 3
40
45
  })) : createCommentVNode("", true),
41
- renderSlot(_ctx.$slots, "default", normalizeProps(guardReactiveProps(defaultSlotProps.value)))
46
+ renderSlot(_ctx.$slots, "default", normalizeProps(guardReactiveProps(defaultSlotProps.value))),
47
+ _ctx.$slots.footer ? (openBlock(), createBlock(_sfc_main$1, {
48
+ key: 1,
49
+ onHeightChange: onFooterHeightChange
50
+ }, {
51
+ default: withCtx(() => [
52
+ renderSlot(_ctx.$slots, "footer")
53
+ ]),
54
+ _: 3
55
+ })) : createCommentVNode("", true)
42
56
  ], 64);
43
57
  };
44
58
  }
@@ -1,19 +1,27 @@
1
1
  import { inject, computed, onScopeDispose, markRaw, ref } from "vue";
2
- import { Lock, Warning } from "@element-plus/icons-vue";
3
- import _sfc_main from "../icon/IconHammer.vue.mjs";
2
+ import { Lock, Warning, Calendar, MoonNight, Opportunity, RefreshRight, Sunny } from "@element-plus/icons-vue";
4
3
  import { CORE_BRIDGE_KEY } from "../../inject/key.mjs";
5
4
  const BADGE_BUILTIN_PRESET = {
6
- new: { text: "新", type: "success" },
7
- updated: { text: "更新", type: "primary" },
8
- beta: { text: "内测", type: "warning" },
9
- // 锤子走 core 自带(EP 无锤子,其 Tools 是扳手+齿轮、被读成「设置」)
10
- wip: { text: "开发中", type: "info", icon: markRaw(_sfc_main) },
11
- // 待下线:danger(红)——「要迁走」是需要用户采取行动的信号,强度高于 beta
12
- // 「谨慎用」。与 count 的红撞色顾虑较弱:一个 key 只能挂一条 entry,同一位置不会
13
- // 同时出现数字标与文字标,且形态(数字 vs 三字)扫视即可分。
5
+ // 上新:整圆 + 放射(团)。[MUST NOT] 改回 `Star` —— wip 的 MoonNight 自带小星星,
6
+ // 两者在 12px 下会互相干扰;`Sunny` 是「团」、`MoonNight` 是「钩」,小尺寸才拉得开。
7
+ new: { text: "新上线", type: "success", icon: markRaw(Sunny) },
8
+ // 更新:闭合环 + 箭头(七档里唯一的环)
9
+ updated: { text: "已更新", type: "primary", icon: markRaw(RefreshRight) },
10
+ // 内测:钟形灯泡(还在试)。[MUST NOT] 改回 `Aim` —— 靶心是同心圆,会与 `Sunny` 撞成两个团。
11
+ beta: { text: "内测中", type: "warning", icon: markRaw(Opportunity) },
12
+ // 开发中:月牙(甲方 2026-09-18 指定 MoonNight,替下自绘的 IconHammer)。
13
+ // 视觉重量比其余几档满 ⇒ 逐档缩到 0.8。
14
+ wip: {
15
+ text: "开发中",
16
+ type: "info",
17
+ icon: markRaw(MoonNight),
18
+ iconScale: 0.8
19
+ },
20
+ // 规划中:方框 + 顶部两耳(排期表)。与 wip 同为 info 档,靠形状区分(实测可辨)。
21
+ planned: { text: "规划中", type: "info", icon: markRaw(Calendar) },
22
+ // 待下线:三角
14
23
  deprecated: { text: "待下线", type: "danger", icon: markRaw(Warning) },
15
- // 未开通:warning(橙)——与 beta 同档。EP 只有五档语义色而内置标已六个,必然有撞;
16
- // 选 warning 因语义最近(都是「有条件可用」),文案完全不同足以区分。
24
+ // 未开通:拱 + 方体
17
25
  locked: { text: "未开通", type: "warning", icon: markRaw(Lock) }
18
26
  };
19
27
  const BADGE_TICK_INTERVAL = 6e4;
@@ -77,7 +85,8 @@ function badgeResolveDisplay(entry) {
77
85
  value: preset.text,
78
86
  type: preset.type,
79
87
  icon: preset.icon,
80
- label: preset.text
88
+ label: preset.text,
89
+ iconScale: preset.iconScale
81
90
  };
82
91
  }
83
92
  export {
@@ -10,6 +10,10 @@ const uploadFileFromUrl = (url) => {
10
10
  }
11
11
  return { uid: ++uploadUidSeed, name: name || url, url, status: "success" };
12
12
  };
13
+ const uploadFinalUrlOf = (file) => {
14
+ const url = file.response ?? file.url ?? void 0;
15
+ return url && !url.startsWith("blob:") ? url : void 0;
16
+ };
13
17
  function useUploadState(modelValue, options) {
14
18
  const {
15
19
  maxCount,
@@ -39,17 +43,34 @@ function useUploadState(modelValue, options) {
39
43
  uploadingCount.value -= 1;
40
44
  if (uploadingCount.value === 0) applyLoading();
41
45
  };
46
+ const alignFileList = (value) => {
47
+ const urls = urlsOf(value);
48
+ const current = fileList.value;
49
+ const pending = current.filter((file) => !uploadFinalUrlOf(file));
50
+ const settled = /* @__PURE__ */ new Map();
51
+ current.forEach((file) => {
52
+ const url = uploadFinalUrlOf(file);
53
+ if (!url) return;
54
+ const queue = settled.get(url);
55
+ if (queue) queue.push(file);
56
+ else settled.set(url, [file]);
57
+ });
58
+ const next = [
59
+ ...urls.map((url) => {
60
+ var _a;
61
+ return ((_a = settled.get(url)) == null ? void 0 : _a.shift()) ?? uploadFileFromUrl(url);
62
+ }),
63
+ ...pending
64
+ ];
65
+ if (next.length === current.length && next.every((file, index) => file === current[index])) {
66
+ return;
67
+ }
68
+ fileList.value = next;
69
+ };
42
70
  watch(
43
- modelValue,
44
- (value) => {
45
- const urls = urlsOf(value);
46
- if (urls.length === 0) {
47
- fileList.value = [];
48
- } else if (fileList.value.length === 0) {
49
- fileList.value = urls.map(uploadFileFromUrl);
50
- }
51
- },
52
- { immediate: true }
71
+ [modelValue, fileList, uploadingCount],
72
+ () => alignFileList(modelValue.value),
73
+ { immediate: true, flush: "post" }
53
74
  );
54
75
  const handleUpload = async (options2) => {
55
76
  beginUpload();
@@ -84,7 +105,8 @@ function useUploadState(modelValue, options) {
84
105
  }
85
106
  };
86
107
  const handleRemove = (file) => {
87
- const url = file.response ?? file.url;
108
+ fileList.value = fileList.value.filter((item) => item !== file);
109
+ const url = uploadFinalUrlOf(file);
88
110
  if (url) {
89
111
  modelValue.value = urlsOf(modelValue.value).filter(
90
112
  (item) => item !== url
@@ -1,7 +1,7 @@
1
1
  import _sfc_main from "./AppPageDetail.vue2.mjs";
2
2
  /* empty css */
3
3
  import _export_sfc from "../../_virtual/_plugin-vue_export-helper.mjs";
4
- const AppPageDetail = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-4426d26a"]]);
4
+ const AppPageDetail = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-1b784d3a"]]);
5
5
  export {
6
6
  AppPageDetail as default
7
7
  };
@@ -59,7 +59,10 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
59
59
  }, {
60
60
  default: withCtx(() => [
61
61
  ctxFinal.value.id !== void 0 && !__props.detailApi && titleOf() ? (openBlock(), createElementBlock("div", _hoisted_1, toDisplayString(titleOf()), 1)) : createCommentVNode("", true),
62
- ctxFinal.value.id !== void 0 && __props.detailApi ? (openBlock(), createBlock(unref(ViewLayout), mergeProps({ key: 1 }, __props.viewLayoutProps, {
62
+ ctxFinal.value.id !== void 0 && __props.detailApi ? (openBlock(), createBlock(unref(ViewLayout), mergeProps({
63
+ key: 1,
64
+ fillHeight: !!_ctx.$slots.detailBottom
65
+ }, __props.viewLayoutProps, {
63
66
  api: __props.detailApi,
64
67
  params: detailParams.value,
65
68
  refreshToken: ctxFinal.value.id
@@ -75,8 +78,15 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
75
78
  createTextVNode(toDisplayString(titleOf(data)), 1)
76
79
  ]),
77
80
  key: "0"
81
+ } : void 0,
82
+ _ctx.$slots.detailBottom ? {
83
+ name: "bottom",
84
+ fn: withCtx(({ data, loading, fetchSeq }) => [
85
+ renderSlot(_ctx.$slots, "detailBottom", normalizeProps(guardReactiveProps(detailScope(data, loading, fetchSeq))), void 0, true)
86
+ ]),
87
+ key: "1"
78
88
  } : void 0
79
- ]), 1040, ["api", "params", "refreshToken"])) : ctxFinal.value.id !== void 0 ? renderSlot(_ctx.$slots, "detail", normalizeProps(mergeProps({ key: 2 }, detailScope())), void 0, true) : renderSlot(_ctx.$slots, "empty", {
89
+ ]), 1040, ["fillHeight", "api", "params", "refreshToken"])) : ctxFinal.value.id !== void 0 ? renderSlot(_ctx.$slots, "detail", normalizeProps(mergeProps({ key: 2 }, detailScope())), void 0, true) : renderSlot(_ctx.$slots, "empty", {
80
90
  key: 3,
81
91
  listEmpty: __props.listEmpty
82
92
  }, () => [
@@ -121,33 +121,40 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
121
121
  ]),
122
122
  key: "1"
123
123
  } : void 0,
124
+ _ctx.$slots.detailBottom ? {
125
+ name: "detailBottom",
126
+ fn: withCtx((scope) => [
127
+ renderSlot(_ctx.$slots, "detailBottom", mergeProps(scope, { resolvedMode: resolvedMode.value }))
128
+ ]),
129
+ key: "2"
130
+ } : void 0,
124
131
  _ctx.$slots.empty ? {
125
132
  name: "empty",
126
133
  fn: withCtx((scope) => [
127
134
  renderSlot(_ctx.$slots, "empty", mergeProps(scope, { resolvedMode: resolvedMode.value }))
128
135
  ]),
129
- key: "2"
136
+ key: "3"
130
137
  } : void 0,
131
138
  _ctx.$slots.right ? {
132
139
  name: "right",
133
140
  fn: withCtx(() => [
134
141
  renderSlot(_ctx.$slots, "right")
135
142
  ]),
136
- key: "3"
143
+ key: "4"
137
144
  } : void 0,
138
145
  _ctx.$slots.top ? {
139
146
  name: "top",
140
147
  fn: withCtx(() => [
141
148
  renderSlot(_ctx.$slots, "top")
142
149
  ]),
143
- key: "4"
150
+ key: "5"
144
151
  } : void 0,
145
152
  _ctx.$slots.bottom ? {
146
153
  name: "bottom",
147
154
  fn: withCtx(() => [
148
155
  renderSlot(_ctx.$slots, "bottom")
149
156
  ]),
150
- key: "5"
157
+ key: "6"
151
158
  } : void 0
152
159
  ]), 1064, ["listProps", "ctx", "listEmpty", "listWidth", "sheetLayerType", "sheetSize", "detailApi", "detailTitle", "viewLayoutProps"]);
153
160
  };
@@ -62,12 +62,19 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
62
62
  ]),
63
63
  key: "0"
64
64
  } : void 0,
65
+ _ctx.$slots.detailBottom ? {
66
+ name: "detailBottom",
67
+ fn: withCtx((scope) => [
68
+ renderSlot(_ctx.$slots, "detailBottom", normalizeProps(guardReactiveProps(scope)))
69
+ ]),
70
+ key: "1"
71
+ } : void 0,
65
72
  _ctx.$slots.empty ? {
66
73
  name: "empty",
67
74
  fn: withCtx((scope) => [
68
75
  renderSlot(_ctx.$slots, "empty", normalizeProps(guardReactiveProps(scope)))
69
76
  ]),
70
- key: "1"
77
+ key: "2"
71
78
  } : void 0
72
79
  ]), 1032, ["ctx", "listEmpty", "detailApi", "viewLayoutProps"])
73
80
  ]),
@@ -1,7 +1,7 @@
1
1
  import _sfc_main from "./AppPageListDetailSplit.vue2.mjs";
2
2
  /* empty css */
3
3
  import _export_sfc from "../../_virtual/_plugin-vue_export-helper.mjs";
4
- const AppPageListDetailSplit = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-e97ba16e"]]);
4
+ const AppPageListDetailSplit = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-7aa91bcb"]]);
5
5
  export {
6
6
  AppPageListDetailSplit as default
7
7
  };
@@ -51,12 +51,19 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
51
51
  ]),
52
52
  key: "0"
53
53
  } : void 0,
54
+ _ctx.$slots.detailBottom ? {
55
+ name: "detailBottom",
56
+ fn: withCtx((scope) => [
57
+ renderSlot(_ctx.$slots, "detailBottom", normalizeProps(guardReactiveProps(scope)), void 0, true)
58
+ ]),
59
+ key: "1"
60
+ } : void 0,
54
61
  _ctx.$slots.empty ? {
55
62
  name: "empty",
56
63
  fn: withCtx((scope) => [
57
64
  renderSlot(_ctx.$slots, "empty", normalizeProps(guardReactiveProps(scope)), void 0, true)
58
65
  ]),
59
- key: "1"
66
+ key: "2"
60
67
  } : void 0
61
68
  ]), 1032, ["ctx", "listEmpty", "detailApi", "detailTitle", "viewLayoutProps"])
62
69
  ]),
@@ -1,7 +1,7 @@
1
1
  import _sfc_main from "./TableMain.vue2.mjs";
2
2
  /* empty css */
3
3
  import _export_sfc from "../../_virtual/_plugin-vue_export-helper.mjs";
4
- const TableMain = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-431aac71"]]);
4
+ const TableMain = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-f5764fe4"]]);
5
5
  export {
6
6
  TableMain as default
7
7
  };
@@ -1,4 +1,4 @@
1
- import { defineComponent, useCssVars, unref, useModel, useAttrs, ref, computed, markRaw, shallowRef, watch, onMounted, onActivated, openBlock, createElementBlock, normalizeClass, createBlock, withCtx, createVNode, mergeProps, createCommentVNode, resolveDynamicComponent, Fragment, renderList, createSlots, renderSlot, createTextVNode, toDisplayString, normalizeProps, guardReactiveProps, withDirectives, vShow, mergeModels } from "vue";
1
+ import { defineComponent, useCssVars, unref, useModel, computed, useAttrs, ref, markRaw, shallowRef, watch, onMounted, onActivated, openBlock, createElementBlock, normalizeClass, createBlock, withCtx, createVNode, mergeProps, createCommentVNode, resolveDynamicComponent, Fragment, renderList, createSlots, renderSlot, createTextVNode, toDisplayString, normalizeProps, guardReactiveProps, withDirectives, vShow, mergeModels } from "vue";
2
2
  import { useActiveRecord, activeRecordValueOf } from "../../hooks/use-active-record.mjs";
3
3
  import _cloneDeep from "lodash/cloneDeep";
4
4
  import _omit from "lodash/omit";
@@ -21,6 +21,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
21
21
  __name: "TableMain",
22
22
  props: /* @__PURE__ */ mergeModels({
23
23
  surface: { type: Boolean, default: void 0 },
24
+ itemCard: { type: Boolean, default: void 0 },
24
25
  showPager: { type: Boolean, default: true },
25
26
  initialSearch: { type: Boolean, default: true },
26
27
  showSwitchView: { type: Boolean },
@@ -61,14 +62,15 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
61
62
  emits: /* @__PURE__ */ mergeModels(["pageChange", "pageSizeChange", "dataChange", "loadingChange", "pageInfoChange"], ["update:activeId", "update:activeData", "update:isAutoRefresh", "update:refreshInterval", "update:customView"]),
62
63
  setup(__props, { expose: __expose, emit: __emit }) {
63
64
  useCssVars((_ctx) => ({
64
- "v02eff1c8": unref(surfacePadCss),
65
- "v75a7164e": unref(fillMinHeightCss)
65
+ "v5308fe58": unref(surfacePadCss),
66
+ "v418a0592": unref(fillMinHeightCss)
66
67
  }));
67
68
  const props = __props;
68
69
  const emits = __emit;
69
70
  const activeId = useModel(__props, "activeId");
70
71
  const activeData = useModel(__props, "activeData");
71
- const { surfaceActive, surfacePad, surfacePadCss } = useSurface(() => props);
72
+ const itemCardFinal = computed(() => props.itemCard ?? customView.value);
73
+ const { surfaceActive, surfaceBgActive, surfacePad, surfacePadCss } = useSurface(() => ({ ...props, itemCard: itemCardFinal.value }));
72
74
  const isAutoRefresh = useModel(__props, "isAutoRefresh");
73
75
  const refreshInterval = useModel(__props, "refreshInterval");
74
76
  const customView = useModel(__props, "customView");
@@ -371,7 +373,8 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
371
373
  return openBlock(), createElementBlock("div", {
372
374
  class: normalizeClass(["dc-table-main table-main", {
373
375
  "table-main_fill": unref(fillActive),
374
- "table-main_surface": unref(surfaceActive)
376
+ "table-main_surface": unref(surfaceActive),
377
+ "table-main_surface-bg": unref(surfaceBgActive)
375
378
  }])
376
379
  }, [
377
380
  __props.showToolbar ? (openBlock(), createBlock(unref(_sfc_main$1), {
@@ -1,7 +1,7 @@
1
1
  import _sfc_main from "./ViewLayout.vue2.mjs";
2
2
  /* empty css */
3
3
  import _export_sfc from "../../_virtual/_plugin-vue_export-helper.mjs";
4
- const ViewLayout = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-e7dc3f12"]]);
4
+ const ViewLayout = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-3c6fd3fe"]]);
5
5
  export {
6
6
  ViewLayout as default
7
7
  };
@@ -1,4 +1,4 @@
1
- import { defineComponent, shallowRef, ref, useModel, computed, inject, watch, provide, useSlots, withDirectives, openBlock, createElementBlock, unref, createBlock, withCtx, createElementVNode, normalizeStyle, renderSlot, createTextVNode, toDisplayString, createCommentVNode, createVNode, vShow, Fragment, mergeModels } from "vue";
1
+ import { defineComponent, useCssVars, shallowRef, ref, useModel, computed, inject, watch, provide, useSlots, withDirectives, openBlock, createElementBlock, unref, createBlock, createSlots, withCtx, createElementVNode, normalizeStyle, renderSlot, createTextVNode, toDisplayString, createCommentVNode, createVNode, vShow, Fragment, mergeModels } from "vue";
2
2
  import { vLoading } from "element-plus";
3
3
  import AutoRefreshGroup from "../misc/AutoRefreshGroup.vue.mjs";
4
4
  import _sfc_main$1 from "../display/HeightProvider.vue.mjs";
@@ -6,8 +6,9 @@ import _sfc_main$2 from "../display/ActionBtnGroup.vue.mjs";
6
6
  import { useContextDefaults } from "../../hooks/use-context-defaults.mjs";
7
7
  import ViewLayoutNavigation from "./ViewLayoutNavigation.vue.mjs";
8
8
  import { useChannelViewportHeight } from "../../hooks/use-channel-viewport-height.mjs";
9
- import { APP_PAGE_LIST_DETAIL_CONTEXT, SCOPE_VIEWPORT_MAX_HEIGHT } from "../../inject/key.mjs";
9
+ import { APP_PAGE_LIST_DETAIL_CONTEXT, APP_LAYOUT_BRIDGE_KEY, SCOPE_VIEWPORT_MAX_HEIGHT } from "../../inject/key.mjs";
10
10
  import { useActivated } from "../../hooks/activated.mjs";
11
+ import { gapScaleValue } from "../../utils/gap-scale.mjs";
11
12
  import { SlotRegion } from "../../config/slot-region.mjs";
12
13
  const _hoisted_1 = { class: "dc-view-layout view-layout" };
13
14
  const _hoisted_2 = { class: "view-layout-toolbar" };
@@ -17,14 +18,20 @@ const _hoisted_4 = {
17
18
  class: "dc-view-layout__header view-layout-header"
18
19
  };
19
20
  const _hoisted_5 = { class: "view-layout-toolbar__right" };
20
- const _hoisted_6 = { class: "view-layout-toolbar" };
21
- const _hoisted_7 = { class: "view-layout-toolbar__left" };
22
- const _hoisted_8 = {
21
+ const _hoisted_6 = { class: "dc-view-layout__bottom" };
22
+ const _hoisted_7 = { class: "view-layout-toolbar" };
23
+ const _hoisted_8 = { class: "view-layout-toolbar__left" };
24
+ const _hoisted_9 = {
23
25
  key: 0,
24
26
  class: "dc-view-layout__header view-layout-header"
25
27
  };
26
- const _hoisted_9 = { class: "view-layout-toolbar__right" };
27
- const _hoisted_10 = { class: "view-layout-content" };
28
+ const _hoisted_10 = { class: "view-layout-toolbar__right" };
29
+ const _hoisted_11 = { class: "view-layout-content" };
30
+ const _hoisted_12 = {
31
+ key: 0,
32
+ class: "dc-view-layout__bottom"
33
+ };
34
+ const DEFAULT_GAP_BASE = 8;
28
35
  const _sfc_main = /* @__PURE__ */ defineComponent({
29
36
  __name: "ViewLayout",
30
37
  props: /* @__PURE__ */ mergeModels({
@@ -36,6 +43,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
36
43
  channel: {},
37
44
  parentChannel: {},
38
45
  minHeight: { default: 100 },
46
+ fillHeight: { type: Boolean },
39
47
  showAutoRefresh: { type: Boolean, default: true },
40
48
  showRefresh: { type: Boolean, default: true },
41
49
  title: {},
@@ -48,6 +56,10 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
48
56
  }),
49
57
  emits: ["update:isAutoRefresh"],
50
58
  setup(__props) {
59
+ useCssVars((_ctx) => ({
60
+ "v72fb5e44": gapUnitPx.value,
61
+ "v7243a29e": padLeftPx.value
62
+ }));
51
63
  const props = __props;
52
64
  const { ctxRefine } = useContextDefaults({
53
65
  getProps: () => props,
@@ -88,6 +100,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
88
100
  refreshList: listDetailCtx == null ? void 0 : listDetailCtx.refreshList
89
101
  }));
90
102
  const hasHeader = computed(() => !!slots.header || !!props.title);
103
+ const hasBottom = computed(() => !!slots.bottom);
91
104
  const hasToolbarContent = computed(
92
105
  () => {
93
106
  var _a, _b;
@@ -104,10 +117,24 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
104
117
  if (token !== void 0) fetch();
105
118
  }
106
119
  );
107
- const heightProviderViewportHeight = computed(() => viewportHeightFinal.value);
108
- const contentStyle = (available) => ({
109
- maxHeight: `${available}px`
110
- });
120
+ const layoutBridge = inject(APP_LAYOUT_BRIDGE_KEY, void 0);
121
+ const gapUnit = computed(
122
+ () => gapScaleValue(
123
+ (layoutBridge == null ? void 0 : layoutBridge.APP_LAYOUT_GAP_CONFIG.size) ?? DEFAULT_GAP_BASE,
124
+ "module",
125
+ layoutBridge == null ? void 0 : layoutBridge.themeDensity.value
126
+ )
127
+ );
128
+ const gapUnitPx = computed(() => `${gapUnit.value}px`);
129
+ const padLeftPx = computed(() => `${gapUnit.value * 2}px`);
130
+ const contentPaddingVertical = computed(() => gapUnit.value * 2);
131
+ const heightProviderViewportHeight = computed(
132
+ () => Math.max(viewportHeightFinal.value - contentPaddingVertical.value, 0)
133
+ );
134
+ const contentStyle = (available) => {
135
+ const box = `${available + contentPaddingVertical.value}px`;
136
+ return props.fillHeight ? { maxHeight: box, minHeight: box } : { maxHeight: box };
137
+ };
111
138
  const childViewportHeightChange = ref(0);
112
139
  const onChildViewportHeightChange = (value) => {
113
140
  childViewportHeightChange.value = value;
@@ -132,7 +159,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
132
159
  viewportHeight: heightProviderViewportHeight.value,
133
160
  minHeight: __props.minHeight,
134
161
  onChildViewportHeightChange
135
- }, {
162
+ }, createSlots({
136
163
  header: withCtx(() => [
137
164
  withDirectives(createElementVNode("div", _hoisted_2, [
138
165
  createElementVNode("div", _hoisted_3, [
@@ -187,11 +214,25 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
187
214
  }, void 0, true)
188
215
  ], 4)
189
216
  ]),
190
- _: 3
191
- }, 8, ["viewportHeight", "minHeight"])) : (openBlock(), createElementBlock(Fragment, { key: 1 }, [
192
- withDirectives(createElementVNode("div", _hoisted_6, [
193
- createElementVNode("div", _hoisted_7, [
194
- hasHeader.value ? (openBlock(), createElementBlock("div", _hoisted_8, [
217
+ _: 2
218
+ }, [
219
+ hasBottom.value ? {
220
+ name: "footer",
221
+ fn: withCtx(() => [
222
+ createElementVNode("div", _hoisted_6, [
223
+ renderSlot(_ctx.$slots, "bottom", {
224
+ data: data.value,
225
+ loading: loading.value,
226
+ fetchSeq: fetchSeq.value
227
+ }, void 0, true)
228
+ ])
229
+ ]),
230
+ key: "0"
231
+ } : void 0
232
+ ]), 1032, ["viewportHeight", "minHeight"])) : (openBlock(), createElementBlock(Fragment, { key: 1 }, [
233
+ withDirectives(createElementVNode("div", _hoisted_7, [
234
+ createElementVNode("div", _hoisted_8, [
235
+ hasHeader.value ? (openBlock(), createElementBlock("div", _hoisted_9, [
195
236
  renderSlot(_ctx.$slots, "header", {
196
237
  data: data.value,
197
238
  loading: loading.value
@@ -205,7 +246,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
205
246
  "default-size": "small"
206
247
  }, null, 8, ["configs", "ctx"])
207
248
  ]),
208
- createElementVNode("div", _hoisted_9, [
249
+ createElementVNode("div", _hoisted_10, [
209
250
  showNavigationFinal.value ? (openBlock(), createBlock(ViewLayoutNavigation, {
210
251
  key: 0,
211
252
  ctx: unref(listDetailCtx)
@@ -227,7 +268,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
227
268
  ], 512), [
228
269
  [vShow, hasToolbarContent.value || hasHeader.value]
229
270
  ]),
230
- createElementVNode("div", _hoisted_10, [
271
+ createElementVNode("div", _hoisted_11, [
231
272
  renderSlot(_ctx.$slots, "default", {
232
273
  data: data.value,
233
274
  loading: loading.value,
@@ -235,7 +276,14 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
235
276
  viewportHeight: void 0,
236
277
  fetchSeq: fetchSeq.value
237
278
  }, void 0, true)
238
- ])
279
+ ]),
280
+ hasBottom.value ? (openBlock(), createElementBlock("div", _hoisted_12, [
281
+ renderSlot(_ctx.$slots, "bottom", {
282
+ data: data.value,
283
+ loading: loading.value,
284
+ fetchSeq: fetchSeq.value
285
+ }, void 0, true)
286
+ ])) : createCommentVNode("", true)
239
287
  ], 64))
240
288
  ])), [
241
289
  [unref(vLoading), showLoadingMask.value]
@@ -20,7 +20,10 @@ const useSurface = (getProps) => {
20
20
  ) : 0
21
21
  );
22
22
  const surfacePadCss = computed(() => `${surfacePad.value}px`);
23
- return { surfaceActive, surfacePad, surfacePadCss };
23
+ const surfaceBgActive = computed(
24
+ () => surfaceActive.value && !getProps().itemCard
25
+ );
26
+ return { surfaceActive, surfaceBgActive, surfacePad, surfacePadCss };
24
27
  };
25
28
  export {
26
29
  useSurface