@done-coding/admin-core 0.22.2 → 0.23.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 (30) hide show
  1. package/es/components/data-view/DataGridView.vue.mjs +7 -0
  2. package/es/components/data-view/DataGridView.vue2.mjs +448 -0
  3. package/es/components/data-view/DataListView.vue.mjs +1 -1
  4. package/es/components/data-view/DataListView.vue2.mjs +6 -62
  5. package/es/components/data-view/InfiniteListView.vue.mjs +7 -0
  6. package/es/components/data-view/InfiniteListView.vue2.mjs +205 -0
  7. package/es/components/data-view/use-data-view-field-map.mjs +70 -0
  8. package/es/components/data-view/use-pull-refresh.mjs +38 -0
  9. package/es/components/data-view/utils.mjs +21 -1
  10. package/es/components/list-layout/ListLayout.vue.mjs +1 -1
  11. package/es/components/list-layout/ListLayout.vue2.mjs +48 -8
  12. package/es/index.mjs +92 -82
  13. package/es/style.css +199 -97
  14. package/package.json +5 -2
  15. package/src/components/data-view/README.md +34 -8
  16. package/src/components/data-view/docs/README-DataGridView.md +139 -0
  17. package/src/components/data-view/docs/README-InfiniteListView.md +105 -0
  18. package/types/components/data-view/DataGridView.vue.d.ts +40 -0
  19. package/types/components/data-view/DataListView.vue.d.ts +1 -2
  20. package/types/components/data-view/InfiniteListView.vue.d.ts +30 -0
  21. package/types/components/data-view/index.d.ts +9 -3
  22. package/types/components/data-view/types.d.ts +125 -1
  23. package/types/components/data-view/use-data-view-field-map.d.ts +24 -0
  24. package/types/components/data-view/use-pull-refresh.d.ts +20 -0
  25. package/types/components/data-view/utils.d.ts +13 -1
  26. package/types/components/list-layout/ListLayout.vue.d.ts +4 -0
  27. package/types/components/list-layout/types.d.ts +16 -0
  28. package/types/components/table/index.d.ts +11 -1
  29. package/types/index.d.ts +2 -0
  30. package/types/injectInfo.json.d.ts +1 -1
@@ -0,0 +1,205 @@
1
+ import { defineComponent, ref, computed, watch, nextTick, openBlock, createElementBlock, unref, normalizeStyle, createElementVNode, toDisplayString, createCommentVNode, Fragment, renderList, renderSlot, createVNode } from "vue";
2
+ import { ElEmpty } from "element-plus";
3
+ import { useVirtualizer } from "@tanstack/vue-virtual";
4
+ import { usePullRefresh } from "./use-pull-refresh.mjs";
5
+ import { useActivated } from "../../hooks/activated.mjs";
6
+ const _hoisted_1 = ["data-index"];
7
+ const _hoisted_2 = { class: "infinite-list-view__json" };
8
+ const _hoisted_3 = { class: "infinite-list-view__footer" };
9
+ const _hoisted_4 = { class: "infinite-list-view__tip" };
10
+ const _hoisted_5 = {
11
+ key: 2,
12
+ class: "infinite-list-view__empty"
13
+ };
14
+ const _hoisted_6 = {
15
+ key: 3,
16
+ class: "infinite-list-view__empty"
17
+ };
18
+ const _sfc_main = /* @__PURE__ */ defineComponent({
19
+ __name: "InfiniteListView",
20
+ props: {
21
+ data: {},
22
+ itemKey: {},
23
+ loading: { type: Boolean, default: false },
24
+ loadingMore: { type: Boolean, default: false },
25
+ error: { default: null },
26
+ finished: { type: Boolean, default: false },
27
+ loadMoreDistance: { default: 100 },
28
+ endText: { default: "我是有底线的" },
29
+ errorText: { default: "加载失败,点击重试" },
30
+ estimateSize: { default: 200 },
31
+ overscan: { default: 5 },
32
+ maxHeight: { default: void 0 },
33
+ pullRefresh: { type: Boolean, default: false }
34
+ },
35
+ emits: ["loadMore", "retry", "refresh"],
36
+ setup(__props, { expose: __expose, emit: __emit }) {
37
+ const props = __props;
38
+ const emits = __emit;
39
+ const scrollContainer = ref();
40
+ const sentinel = ref();
41
+ const containerStyle = computed(
42
+ () => props.maxHeight ? {
43
+ maxHeight: typeof props.maxHeight === "number" ? `${props.maxHeight}px` : props.maxHeight,
44
+ overflowY: "auto"
45
+ } : void 0
46
+ );
47
+ const virtualizer = useVirtualizer(
48
+ computed(() => ({
49
+ count: props.data.length,
50
+ getScrollElement: () => scrollContainer.value ?? null,
51
+ estimateSize: () => props.estimateSize,
52
+ overscan: props.overscan
53
+ }))
54
+ );
55
+ const virtualItems = computed(() => virtualizer.value.getVirtualItems());
56
+ const totalSize = computed(() => virtualizer.value.getTotalSize());
57
+ const measureElementRef = (el) => {
58
+ var _a;
59
+ if (el) (_a = virtualizer.value) == null ? void 0 : _a.measureElement(el);
60
+ };
61
+ const { pullDistance, pullThreshold, onTouchStart, onTouchMove, onTouchEnd } = usePullRefresh({
62
+ enabled: () => props.pullRefresh,
63
+ getScrollContainer: () => scrollContainer.value ?? null,
64
+ onRefresh: () => emits("refresh")
65
+ });
66
+ const emitRetry = () => emits("retry");
67
+ const tryEmitLoadMore = () => {
68
+ if (props.loading || props.loadingMore || props.error || props.finished) {
69
+ return;
70
+ }
71
+ emits("loadMore");
72
+ };
73
+ const isSentinelVisible = () => {
74
+ const container = scrollContainer.value;
75
+ const s = sentinel.value;
76
+ if (!container || !s) return false;
77
+ const c = container.getBoundingClientRect();
78
+ const r = s.getBoundingClientRect();
79
+ return r.top <= c.bottom + props.loadMoreDistance;
80
+ };
81
+ let observer;
82
+ const observeSentinel = () => {
83
+ observer == null ? void 0 : observer.disconnect();
84
+ const container = scrollContainer.value;
85
+ const s = sentinel.value;
86
+ if (!container || !s) return;
87
+ observer = new IntersectionObserver(
88
+ (entries) => {
89
+ if (entries.some((e) => e.isIntersecting)) tryEmitLoadMore();
90
+ },
91
+ { root: container, rootMargin: `0px 0px ${props.loadMoreDistance}px 0px` }
92
+ );
93
+ observer.observe(s);
94
+ };
95
+ useActivated((info) => {
96
+ if (info.isActivated) {
97
+ observeSentinel();
98
+ } else {
99
+ observer == null ? void 0 : observer.disconnect();
100
+ }
101
+ });
102
+ watch(
103
+ () => props.data.length,
104
+ () => {
105
+ nextTick(observeSentinel);
106
+ }
107
+ );
108
+ watch(
109
+ () => [props.loading, props.loadingMore, props.error, props.finished],
110
+ () => {
111
+ if (isSentinelVisible()) tryEmitLoadMore();
112
+ }
113
+ );
114
+ __expose({
115
+ scrollTo: (index) => {
116
+ var _a;
117
+ return (_a = virtualizer.value) == null ? void 0 : _a.scrollToIndex(index);
118
+ },
119
+ reset: () => {
120
+ var _a;
121
+ return (_a = virtualizer.value) == null ? void 0 : _a.scrollToIndex(0, { align: "start" });
122
+ }
123
+ });
124
+ return (_ctx, _cache) => {
125
+ return openBlock(), createElementBlock("div", {
126
+ ref_key: "scrollContainer",
127
+ ref: scrollContainer,
128
+ class: "dc-infinite-list-view infinite-list-view",
129
+ style: normalizeStyle(containerStyle.value),
130
+ onTouchstartPassive: _cache[0] || (_cache[0] = //@ts-ignore
131
+ (...args) => unref(onTouchStart) && unref(onTouchStart)(...args)),
132
+ onTouchmovePassive: _cache[1] || (_cache[1] = //@ts-ignore
133
+ (...args) => unref(onTouchMove) && unref(onTouchMove)(...args)),
134
+ onTouchend: _cache[2] || (_cache[2] = //@ts-ignore
135
+ (...args) => unref(onTouchEnd) && unref(onTouchEnd)(...args))
136
+ }, [
137
+ unref(pullDistance) > 0 ? (openBlock(), createElementBlock("div", {
138
+ key: 0,
139
+ class: "infinite-list-view__pull-indicator",
140
+ style: normalizeStyle({ height: `${unref(pullDistance)}px` })
141
+ }, [
142
+ createElementVNode("span", null, toDisplayString(unref(pullDistance) >= unref(pullThreshold) ? "释放刷新" : "下拉刷新"), 1)
143
+ ], 4)) : createCommentVNode("", true),
144
+ __props.data.length ? (openBlock(), createElementBlock(Fragment, { key: 1 }, [
145
+ createElementVNode("div", {
146
+ class: "infinite-list-view__viewport",
147
+ style: normalizeStyle({ height: `${totalSize.value}px`, position: "relative" })
148
+ }, [
149
+ (openBlock(true), createElementBlock(Fragment, null, renderList(virtualItems.value, (item) => {
150
+ return openBlock(), createElementBlock("div", {
151
+ key: String(item.key),
152
+ ref_for: true,
153
+ ref: measureElementRef,
154
+ class: "infinite-list-view__row",
155
+ "data-index": item.index,
156
+ style: normalizeStyle({
157
+ position: "absolute",
158
+ top: 0,
159
+ left: 0,
160
+ width: "100%",
161
+ transform: `translateY(${item.start}px)`
162
+ })
163
+ }, [
164
+ renderSlot(_ctx.$slots, "item", {
165
+ item: __props.data[item.index],
166
+ index: item.index
167
+ }, () => [
168
+ createElementVNode("pre", _hoisted_2, toDisplayString(JSON.stringify(__props.data[item.index], null, 2)), 1)
169
+ ], true)
170
+ ], 12, _hoisted_1);
171
+ }), 128))
172
+ ], 4),
173
+ createElementVNode("div", {
174
+ ref_key: "sentinel",
175
+ ref: sentinel,
176
+ class: "infinite-list-view__sentinel"
177
+ }, null, 512),
178
+ createElementVNode("div", _hoisted_3, [
179
+ __props.loadingMore ? renderSlot(_ctx.$slots, "loading-more", { key: 0 }, () => [
180
+ _cache[3] || (_cache[3] = createElementVNode("span", { class: "infinite-list-view__tip" }, "加载中…", -1))
181
+ ], true) : __props.error ? renderSlot(_ctx.$slots, "error", {
182
+ key: 1,
183
+ error: __props.error,
184
+ retry: emitRetry
185
+ }, () => [
186
+ createElementVNode("button", {
187
+ class: "infinite-list-view__retry",
188
+ onClick: emitRetry
189
+ }, toDisplayString(__props.errorText), 1)
190
+ ], true) : __props.finished ? renderSlot(_ctx.$slots, "end", { key: 2 }, () => [
191
+ createElementVNode("span", _hoisted_4, toDisplayString(__props.endText), 1)
192
+ ], true) : createCommentVNode("", true)
193
+ ])
194
+ ], 64)) : __props.loading ? (openBlock(), createElementBlock("div", _hoisted_5, "加载中…")) : (openBlock(), createElementBlock("div", _hoisted_6, [
195
+ renderSlot(_ctx.$slots, "empty", {}, () => [
196
+ createVNode(unref(ElEmpty))
197
+ ], true)
198
+ ]))
199
+ ], 36);
200
+ };
201
+ }
202
+ });
203
+ export {
204
+ _sfc_main as default
205
+ };
@@ -0,0 +1,70 @@
1
+ import { computed, markRaw, defineComponent, h } from "vue";
2
+ function makeFieldComp(column, getRenderCtxParams) {
3
+ return markRaw(
4
+ defineComponent({
5
+ name: "DataViewField",
6
+ props: {
7
+ row: { type: Object, required: true },
8
+ index: { type: Number, required: true },
9
+ selected: { type: Boolean, default: false },
10
+ toggleSelect: { type: Function, default: void 0 }
11
+ },
12
+ setup(p) {
13
+ return () => {
14
+ const { type, render, prop } = column;
15
+ if (type === "index") {
16
+ return h("span", String(p.index + 1));
17
+ }
18
+ if (type === "selection") {
19
+ return h("input", {
20
+ type: "checkbox",
21
+ checked: p.selected,
22
+ onChange: () => {
23
+ var _a;
24
+ return (_a = p.toggleSelect) == null ? void 0 : _a.call(p);
25
+ }
26
+ });
27
+ }
28
+ if (typeof render === "function") {
29
+ return render({
30
+ ...getRenderCtxParams(),
31
+ row: p.row,
32
+ column,
33
+ _index: p.index
34
+ });
35
+ }
36
+ if (render) {
37
+ return h(render);
38
+ }
39
+ const v = prop ? p.row[prop] : void 0;
40
+ return h("span", v === void 0 || v === null ? "" : String(v));
41
+ };
42
+ }
43
+ })
44
+ );
45
+ }
46
+ function useDataViewFieldMap(options) {
47
+ const fieldComponentMap = computed(() => {
48
+ const map = {};
49
+ for (const column of options.columns()) {
50
+ if (column.type === "expand") continue;
51
+ const key = column.type === "index" ? "$type_index" : column.type === "selection" ? "$type_selection" : column.prop;
52
+ if (!key) {
53
+ console.warn(
54
+ "[DataViewFieldMap] 列缺少 prop 且非 index/selection,跳过",
55
+ column
56
+ );
57
+ continue;
58
+ }
59
+ if (map[key]) {
60
+ console.warn(`[DataViewFieldMap] 列 key 重复 "${key}",后者覆盖前者`);
61
+ }
62
+ map[key] = makeFieldComp(column, options.getRenderCtxParams);
63
+ }
64
+ return map;
65
+ });
66
+ return { fieldComponentMap };
67
+ }
68
+ export {
69
+ useDataViewFieldMap
70
+ };
@@ -0,0 +1,38 @@
1
+ import { ref } from "vue";
2
+ const PULL_MAX = 80;
3
+ const PULL_THRESHOLD = 60;
4
+ function usePullRefresh(options) {
5
+ const pullDistance = ref(0);
6
+ const startY = ref(0);
7
+ const pulling = ref(false);
8
+ const onTouchStart = (e) => {
9
+ if (!options.enabled()) return;
10
+ const container = options.getScrollContainer();
11
+ if (!container || container.scrollTop > 0) return;
12
+ startY.value = e.touches[0].clientY;
13
+ pulling.value = true;
14
+ };
15
+ const onTouchMove = (e) => {
16
+ if (!pulling.value) return;
17
+ const delta = e.touches[0].clientY - startY.value;
18
+ pullDistance.value = Math.min(Math.max(delta, 0), PULL_MAX);
19
+ };
20
+ const onTouchEnd = () => {
21
+ if (!pulling.value) return;
22
+ if (pullDistance.value >= PULL_THRESHOLD) {
23
+ options.onRefresh();
24
+ }
25
+ pullDistance.value = 0;
26
+ pulling.value = false;
27
+ };
28
+ return {
29
+ pullDistance,
30
+ pullThreshold: PULL_THRESHOLD,
31
+ onTouchStart,
32
+ onTouchMove,
33
+ onTouchEnd
34
+ };
35
+ }
36
+ export {
37
+ usePullRefresh
38
+ };
@@ -1,3 +1,22 @@
1
+ const BREAKPOINTS_DESC = ["xl", "lg", "md", "sm", "xs"];
2
+ const spanToColumns = (span) => Math.min(24, Math.max(1, Math.round(24 / span)));
3
+ const resolveGridColumnsByBreakpoint = (gridColumns, breakpoint) => {
4
+ if (typeof gridColumns === "number") {
5
+ return Math.max(1, Math.round(gridColumns));
6
+ }
7
+ if (!gridColumns || typeof gridColumns !== "object") return 1;
8
+ const bpIndex = BREAKPOINTS_DESC.indexOf(breakpoint);
9
+ let span = 24;
10
+ for (let i = bpIndex; i < BREAKPOINTS_DESC.length; i += 1) {
11
+ const v = gridColumns[BREAKPOINTS_DESC[i]];
12
+ if (typeof v === "number") {
13
+ span = v;
14
+ break;
15
+ }
16
+ }
17
+ if (!Number.isFinite(span) || span <= 0) return 1;
18
+ return spanToColumns(span);
19
+ };
1
20
  const createDataListViewInstance = (mainMethods) => {
2
21
  return {
3
22
  toggleRowExpansion: () => {
@@ -34,5 +53,6 @@ const createDataListViewInstance = (mainMethods) => {
34
53
  };
35
54
  };
36
55
  export {
37
- createDataListViewInstance
56
+ createDataListViewInstance,
57
+ resolveGridColumnsByBreakpoint
38
58
  };
@@ -1,7 +1,7 @@
1
1
  import _sfc_main from "./ListLayout.vue2.mjs";
2
2
  /* empty css */
3
3
  import _export_sfc from "../../_virtual/_plugin-vue_export-helper.mjs";
4
- const ListLayout = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-ce5a651b"]]);
4
+ const ListLayout = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-a47ec619"]]);
5
5
  export {
6
6
  ListLayout as default
7
7
  };
@@ -1,4 +1,4 @@
1
- import { defineComponent, useCssVars, unref, useSlots, computed, useModel, ref, shallowRef, watch, withDirectives, openBlock, createBlock, normalizeClass, withCtx, createVNode, mergeProps, createSlots, renderSlot, normalizeProps, guardReactiveProps, renderList, createCommentVNode, mergeModels } from "vue";
1
+ import { defineComponent, useCssVars, unref, useSlots, computed, useModel, ref, shallowRef, watch, withDirectives, openBlock, createBlock, normalizeClass, withCtx, mergeProps, createSlots, renderSlot, normalizeProps, guardReactiveProps, renderList, createCommentVNode, createVNode, mergeModels } from "vue";
2
2
  import { vLoading } from "element-plus";
3
3
  import FormActiveFilter from "../form/FormActiveFilter.vue.mjs";
4
4
  import FormSearch from "../form/FormSearch.vue.mjs";
@@ -8,10 +8,13 @@ import { useListLayoutSticky } from "./use-list-layout-sticky.mjs";
8
8
  import { useActiveFilter } from "./use-active-filter.mjs";
9
9
  import _sfc_main$1 from "../display/WatchSize.vue.mjs";
10
10
  import TableMain from "../table/TableMain.vue.mjs";
11
+ import DataGridView from "../data-view/DataGridView.vue.mjs";
12
+ import { resolveGridColumnsByBreakpoint } from "../data-view/utils.mjs";
11
13
  import SlotLayoutFlowAside from "../slot-layout/SlotLayoutFlowAside.vue.mjs";
12
14
  import _pick from "lodash/pick";
13
15
  import _cloneDeep from "lodash/cloneDeep";
14
16
  import { useChannelViewportHeight } from "../../hooks/use-channel-viewport-height.mjs";
17
+ import { useBreakpoint } from "../../hooks/use-breakpoint.mjs";
15
18
  import { SlotRegion } from "../../config/slot-region.mjs";
16
19
  const _sfc_main = /* @__PURE__ */ defineComponent({
17
20
  __name: "ListLayout",
@@ -42,7 +45,11 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
42
45
  allowClear: { type: Boolean, default: false },
43
46
  pagerSticky: { type: Boolean, default: false },
44
47
  headerObserveResize: { type: Boolean, default: false },
45
- operationObserveResize: { type: Boolean, default: false }
48
+ operationObserveResize: { type: Boolean, default: false },
49
+ viewMode: { default: "table" },
50
+ gridColumns: { default: 4 },
51
+ infiniteListProps: {},
52
+ gridProps: {}
46
53
  }, {
47
54
  "isAutoRefresh": { type: Boolean },
48
55
  "isAutoRefreshModifiers": {},
@@ -54,10 +61,10 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
54
61
  emits: /* @__PURE__ */ mergeModels(["dataChange", "pageInfoChange"], ["update:isAutoRefresh", "update:refreshInterval", "update:customView"]),
55
62
  setup(__props, { expose: __expose, emit: __emit }) {
56
63
  useCssVars((_ctx) => ({
57
- "bbc8b4b6": minHeight.value,
58
- "v2ce52870": unref(searchStickyTop),
59
- "ca6d5736": unref(toolbarStickyTop),
60
- "v0af15863": unref(pagerStickyBottom)
64
+ "v37fdcdf2": minHeight.value,
65
+ "v5bcb0a52": unref(searchStickyTop),
66
+ "v489faec3": unref(toolbarStickyTop),
67
+ "v17e649c5": unref(pagerStickyBottom)
61
68
  }));
62
69
  const props = __props;
63
70
  const listLayoutEmits = __emit;
@@ -91,6 +98,10 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
91
98
  ...props.staticQuery
92
99
  };
93
100
  });
101
+ const { activeBreakpoint } = useBreakpoint();
102
+ const gridColumnsFinal = computed(
103
+ () => resolveGridColumnsByBreakpoint(props.gridColumns, activeBreakpoint.value)
104
+ );
94
105
  const showSearch = ref(false);
95
106
  const searchHeightAdjust = computed(() => {
96
107
  if (!showSearch.value) {
@@ -362,7 +373,8 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
362
373
  }, 8, ["observe-resize"])) : createCommentVNode("", true)
363
374
  ]),
364
375
  default: withCtx(() => [
365
- createVNode(unref(TableMain), mergeProps({
376
+ __props.viewMode === "table" ? (openBlock(), createBlock(unref(TableMain), mergeProps({
377
+ key: 0,
366
378
  ref_key: "tableMain",
367
379
  ref: tableMain,
368
380
  "is-auto-refresh": isAutoRefresh.value,
@@ -413,7 +425,35 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
413
425
  })
414
426
  };
415
427
  })
416
- ]), 1040, ["is-auto-refresh", "refresh-interval", "custom-view", "api", "columns", "query", "maxHeight", "rowKey", "toolbar", "showSwitchView", "initial-search", "injectInfo"])
428
+ ]), 1040, ["is-auto-refresh", "refresh-interval", "custom-view", "api", "columns", "query", "maxHeight", "rowKey", "toolbar", "showSwitchView", "initial-search", "injectInfo"])) : (openBlock(), createBlock(unref(DataGridView), mergeProps({
429
+ key: 1,
430
+ ref_key: "tableMain",
431
+ ref: tableMain,
432
+ "is-auto-refresh": isAutoRefresh.value,
433
+ "onUpdate:isAutoRefresh": _cache[3] || (_cache[3] = ($event) => isAutoRefresh.value = $event),
434
+ "refresh-interval": refreshInterval.value,
435
+ "onUpdate:refreshInterval": _cache[4] || (_cache[4] = ($event) => refreshInterval.value = $event),
436
+ api: __props.api,
437
+ columns: __props.columns,
438
+ query: queryMerge.value,
439
+ maxHeight: tableMaxHeight.value,
440
+ rowKey: assertRowKey.value,
441
+ toolbar: __props.toolbar,
442
+ "initial-search": __props.initialSearch
443
+ }, __props.gridProps, {
444
+ refine: false,
445
+ injectInfo: injectInfoAdjust.value,
446
+ gridColumns: gridColumnsFinal.value,
447
+ "infinite-list-props": __props.infiniteListProps,
448
+ onLoadingChange,
449
+ onDataChange,
450
+ onPageInfoChange
451
+ }), {
452
+ "custom-view-item": withCtx((scope) => [
453
+ renderSlot(_ctx.$slots, "custom-view-item", normalizeProps(guardReactiveProps(assertDataViewItemScope(scope))), void 0, true)
454
+ ]),
455
+ _: 3
456
+ }, 16, ["is-auto-refresh", "refresh-interval", "api", "columns", "query", "maxHeight", "rowKey", "toolbar", "initial-search", "injectInfo", "gridColumns", "infinite-list-props"]))
417
457
  ]),
418
458
  _: 3
419
459
  }, 8, ["class", "separate", "type", "gap", "aside-width", "aside-max-height"])), [