@veltra/desktop 1.2.6 → 1.2.8
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/components/action/action-group.vue.d.ts +3 -3
- package/dist/components/action/action.vue.d.ts +2 -2
- package/dist/components/batch-edit/batch-edit-form.js +2 -6
- package/dist/components/batch-edit/batch-edit-form.js.map +1 -1
- package/dist/components/batch-edit/use-edit.js +17 -1
- package/dist/components/batch-edit/use-edit.js.map +1 -1
- package/dist/components/checkbox/checkbox-button.vue.d.ts +1 -1
- package/dist/components/date-panel/date-panel.vue.d.ts +1 -1
- package/dist/components/date-picker/date-picker.vue.d.ts +1 -1
- package/dist/components/date-range-picker/date-range-picker.vue.d.ts +1 -1
- package/dist/components/dual-nav/dual-nav.js +2 -2
- package/dist/components/dual-nav/dual-nav.js.map +1 -1
- package/dist/components/dual-nav/helper.js +6 -1
- package/dist/components/dual-nav/helper.js.map +1 -1
- package/dist/components/dual-nav/style2.css +0 -2
- package/dist/components/empty/empty.vue.d.ts +1 -1
- package/dist/components/number/number.vue.d.ts +1 -1
- package/dist/components/steps/steps.vue.d.ts +2 -2
- package/dist/components/tabs/tabs-horizontal.vue.d.ts +2 -2
- package/dist/components/tabs/tabs-vertical.vue.d.ts +2 -2
- package/dist/components/tabs/tabs.vue.d.ts +2 -2
- package/dist/types/batch-edit.d.ts +1 -1
- package/package.json +6 -6
- package/src/components/batch-edit/batch-edit-form.vue +2 -9
- package/src/components/batch-edit/use-edit.ts +25 -3
- package/src/components/dual-nav/dual-nav.vue +2 -4
- package/src/components/dual-nav/helper.ts +7 -1
- package/src/components/dual-nav/style.scss +0 -2
- package/src/types/batch-edit.ts +1 -1
|
@@ -6,11 +6,11 @@ type __VLS_Slots = {
|
|
|
6
6
|
default?: () => VNode[];
|
|
7
7
|
};
|
|
8
8
|
declare const __VLS_base: import("vue").DefineComponent<ActionGroupProps, _ActionGroupExposed, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<ActionGroupProps> & Readonly<{}>, {
|
|
9
|
-
text: boolean;
|
|
10
|
-
size: "small" | "default" | "large";
|
|
11
9
|
type: import("@veltra/utils").ColorType;
|
|
12
|
-
circle: boolean;
|
|
13
10
|
max: number;
|
|
11
|
+
size: "small" | "default" | "large";
|
|
12
|
+
text: boolean;
|
|
13
|
+
circle: boolean;
|
|
14
14
|
loading: boolean;
|
|
15
15
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
16
16
|
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
@@ -12,9 +12,9 @@ declare const __VLS_base: import("vue").DefineComponent<ActionProps, {}, {}, {},
|
|
|
12
12
|
}, string, import("vue").PublicProps, Readonly<ActionProps> & Readonly<{
|
|
13
13
|
onRun?: (() => any) | undefined;
|
|
14
14
|
}>, {
|
|
15
|
-
text: boolean;
|
|
16
|
-
size: import("@veltra/utils").ComponentSize;
|
|
17
15
|
type: ButtonType;
|
|
16
|
+
size: import("@veltra/utils").ComponentSize;
|
|
17
|
+
text: boolean;
|
|
18
18
|
circle: boolean;
|
|
19
19
|
loading: boolean;
|
|
20
20
|
inDropdown: boolean;
|
|
@@ -31,10 +31,6 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
31
31
|
const isQuick = computed(() => props.mode === "quick");
|
|
32
32
|
const isNormal = computed(() => props.mode !== "quick");
|
|
33
33
|
const isQuickUpdate = computed(() => isQuick.value && state.type === "update");
|
|
34
|
-
const formModel = computed(() => {
|
|
35
|
-
if (isQuick.value && state.type === "update" && state.row) return state.row.data;
|
|
36
|
-
return props.model;
|
|
37
|
-
});
|
|
38
34
|
const headerInfo = computed(() => {
|
|
39
35
|
if (props.readonly) return {
|
|
40
36
|
icon: View,
|
|
@@ -65,7 +61,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
65
61
|
return `${state.type}-${state.row?.uid ?? "create"}-${state.parentRow?.uid ?? "root"}`;
|
|
66
62
|
});
|
|
67
63
|
return (_ctx, _cache) => {
|
|
68
|
-
return unref(state).visible &&
|
|
64
|
+
return unref(state).visible && unref(props).model ? (openBlock(), createElementBlock("aside", {
|
|
69
65
|
key: 0,
|
|
70
66
|
class: normalizeClass(unref(cls).e("form"))
|
|
71
67
|
}, [
|
|
@@ -105,7 +101,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
105
101
|
default: withCtx(() => [createVNode(unref(form_default), {
|
|
106
102
|
ref_key: "formComponentRef",
|
|
107
103
|
ref: formComponentRef,
|
|
108
|
-
model:
|
|
104
|
+
model: unref(props).model,
|
|
109
105
|
readonly: unref(props).readonly,
|
|
110
106
|
"label-width": unref(props).labelWidth
|
|
111
107
|
}, {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"batch-edit-form.js","names":[],"sources":["../../../src/components/batch-edit/batch-edit-form.vue"],"sourcesContent":["<template>\n <aside :class=\"cls.e('form')\" v-if=\"state.visible &&
|
|
1
|
+
{"version":3,"file":"batch-edit-form.js","names":[],"sources":["../../../src/components/batch-edit/batch-edit-form.vue"],"sourcesContent":["<template>\n <aside :class=\"cls.e('form')\" v-if=\"state.visible && props.model\">\n <header :class=\"cls.e('form-header')\">\n <span :class=\"[cls.e('form-icon'), bem.is(headerInfo.tone)]\">\n <u-icon>\n <component :is=\"headerInfo.icon\" />\n </u-icon>\n </span>\n <div :class=\"cls.e('form-title')\">\n <h3 :class=\"cls.e('form-title-text')\">{{ headerInfo.title }}</h3>\n <span v-if=\"headerInfo.chip\" :class=\"cls.e('form-chip')\">\n {{ headerInfo.chip }}\n </span>\n </div>\n <u-button\n :class=\"cls.e('form-close')\"\n :icon=\"Close\"\n text\n circle\n size=\"small\"\n title=\"关闭\"\n @click=\"handleClose\"\n />\n </header>\n\n <u-scroll always :class=\"cls.e('form-body')\" :key=\"bodyKey\">\n <transition name=\"fade\" appear mode=\"out-in\">\n <u-form\n ref=\"formComponentRef\"\n :model=\"props.model\"\n :readonly=\"props.readonly\"\n :label-width=\"props.labelWidth\"\n >\n <slot\n v-bind=\"{\n row: state.row,\n depth: state.depth,\n indexes: insertIndexes,\n index: state.row?.index\n }\"\n />\n </u-form>\n </transition>\n </u-scroll>\n\n <footer :class=\"cls.e('form-footer')\">\n <span :class=\"cls.e('form-hint')\" v-if=\"props.readonly\">只读模式</span>\n <span :class=\"cls.e('form-hint')\" v-else-if=\"isQuickUpdate\">\n 实时编辑\n <span :class=\"{ [bem.is('concealed')]: !focused }\"> · <u-kbd>Esc</u-kbd> 关闭</span>\n </span>\n <span :class=\"cls.e('form-hint')\" v-else>\n <span :class=\"{ [bem.is('concealed')]: !focused }\">\n <u-kbd>Ctrl + S</u-kbd> 保存 · <u-kbd>Esc</u-kbd> 关闭\n </span>\n </span>\n\n <div :class=\"cls.e('form-actions')\">\n <u-button text :loading=\"state.loading\" @click=\"handleClose\"> 取消 </u-button>\n <u-button\n v-if=\"\n !props.readonly && ((isNormal && (creatable || updatable)) || (isQuick && creatable))\n \"\n :type=\"state.type === 'create' ? 'success' : 'primary'\"\n :loading=\"state.loading\"\n @click=\"handleSave\"\n >\n 保存\n </u-button>\n </div>\n </footer>\n </aside>\n</template>\n\n<script lang=\"ts\" setup>\nimport { AddChild, Close, EditPen, Plus, View } from '@veltra/icons/normal'\nimport { bem } from '@veltra/utils'\nimport { computed, inject, shallowRef, toRef, type Component } from 'vue'\n\nimport type { _FormExposed, FormExposed } from '../../types/form'\nimport { UButton } from '../button'\nimport { UForm } from '../form'\nimport { UIcon } from '../icon'\nimport { UKbd } from '../kbd'\nimport { UScroll } from '../scroll'\nimport { BatchEditDIKey } from './di'\n\ndefineOptions({ name: 'BatchEditForm' })\n\nconst batchEditCtx = inject(BatchEditDIKey)!\n\nconst {\n cls,\n props,\n state,\n insertIndexes,\n handleSave,\n handleClose,\n staticFeatures,\n dynamicFeatures\n} = batchEditCtx\n\nconst focused = toRef(batchEditCtx, 'focused')\n\nconst formComponentRef = shallowRef<FormExposed>()\n\ndefineExpose<_FormExposed>({\n el: toRef(() => formComponentRef.value?.el),\n validate: () => formComponentRef.value?.validate() ?? Promise.resolve(true),\n clearValidate: () => formComponentRef.value?.clearValidate(),\n reset: () => formComponentRef.value?.reset()\n})\n\nconst creatable = computed(() => {\n return (\n state.type === 'create' &&\n (staticFeatures.value.has('create') || dynamicFeatures.value.create?.(state.row))\n )\n})\n\nconst updatable = computed(() => {\n return (\n state.type === 'update' &&\n (staticFeatures.value.has('update') || dynamicFeatures.value.update?.(state.row))\n )\n})\n\nconst isQuick = computed(() => props.mode === 'quick')\nconst isNormal = computed(() => props.mode !== 'quick')\nconst isQuickUpdate = computed(() => isQuick.value && state.type === 'update')\n\ninterface HeaderInfo {\n icon: Component\n title: string\n chip?: string\n tone: 'create' | 'update' | 'view' | 'child'\n}\n\nconst headerInfo = computed<HeaderInfo>(() => {\n if (props.readonly) {\n return {\n icon: View,\n title: '查看详情',\n chip: state.row ? `第 ${state.row.index + 1} 行` : undefined,\n tone: 'view'\n }\n }\n if (state.parentRow) {\n return {\n icon: AddChild,\n title: '新增子级',\n chip: `归属于第 ${state.parentRow.index + 1} 行`,\n tone: 'child'\n }\n }\n if (state.type === 'create') {\n return { icon: Plus, title: '新增', tone: 'create' }\n }\n return {\n icon: EditPen,\n title: '编辑',\n chip: state.row ? `第 ${state.row.index + 1} 行` : undefined,\n tone: 'update'\n }\n})\n\n/** 通过 row 切换 / 类型切换驱动表单内容淡出淡入 */\nconst bodyKey = computed(() => {\n return `${state.type}-${state.row?.uid ?? 'create'}-${state.parentRow?.uid ?? 'root'}`\n})\n</script>\n"],"mappings":";;;;;;;;;;;;;;EAyFA,MAAM,eAAe,OAAO,cAAc;EAE1C,MAAM,EACJ,KACA,OACA,OACA,eACA,YACA,aACA,gBACA,oBACE;EAEJ,MAAM,UAAU,MAAM,cAAc,SAAS;EAE7C,MAAM,mBAAmB,WAAwB;EAEjD,SAA2B;GACzB,IAAI,YAAY,iBAAiB,OAAO,EAAE;GAC1C,gBAAgB,iBAAiB,OAAO,SAAS,KAAK,QAAQ,QAAQ,IAAI;GAC1E,qBAAqB,iBAAiB,OAAO,cAAc;GAC3D,aAAa,iBAAiB,OAAO,MAAM;EAC7C,CAAC;EAED,MAAM,YAAY,eAAe;GAC/B,OACE,MAAM,SAAS,aACd,eAAe,MAAM,IAAI,QAAQ,KAAK,gBAAgB,MAAM,SAAS,MAAM,GAAG;EAEnF,CAAC;EAED,MAAM,YAAY,eAAe;GAC/B,OACE,MAAM,SAAS,aACd,eAAe,MAAM,IAAI,QAAQ,KAAK,gBAAgB,MAAM,SAAS,MAAM,GAAG;EAEnF,CAAC;EAED,MAAM,UAAU,eAAe,MAAM,SAAS,OAAO;EACrD,MAAM,WAAW,eAAe,MAAM,SAAS,OAAO;EACtD,MAAM,gBAAgB,eAAe,QAAQ,SAAS,MAAM,SAAS,QAAQ;EAS7E,MAAM,aAAa,eAA2B;GAC5C,IAAI,MAAM,UACR,OAAO;IACL,MAAM;IACN,OAAO;IACP,MAAM,MAAM,MAAM,KAAK,MAAM,IAAI,QAAQ,EAAE,MAAM,KAAA;IACjD,MAAM;GACR;GAEF,IAAI,MAAM,WACR,OAAO;IACL,MAAM;IACN,OAAO;IACP,MAAM,QAAQ,MAAM,UAAU,QAAQ,EAAE;IACxC,MAAM;GACR;GAEF,IAAI,MAAM,SAAS,UACjB,OAAO;IAAE,MAAM;IAAM,OAAO;IAAM,MAAM;GAAS;GAEnD,OAAO;IACL,MAAM;IACN,OAAO;IACP,MAAM,MAAM,MAAM,KAAK,MAAM,IAAI,QAAQ,EAAE,MAAM,KAAA;IACjD,MAAM;GACR;EACF,CAAC;;EAGD,MAAM,UAAU,eAAe;GAC7B,OAAO,GAAG,MAAM,KAAK,GAAG,MAAM,KAAK,OAAO,SAAS,GAAG,MAAM,WAAW,OAAO;EAChF,CAAC;;UAxKqC,MAAA,KAAA,EAAM,WAAW,MAAA,KAAA,EAAM,SAAA,UAAA,GAA3D,mBAsEQ,SAAA;;IAtEA,OAAK,eAAE,MAAA,GAAA,EAAI,EAAC,MAAA,CAAA;;IAClB,mBAqBS,UAAA,EArBA,OAAK,eAAE,MAAA,GAAA,EAAI,EAAC,aAAA,CAAA,EAAA,GAAA;KACnB,mBAIO,QAAA,EAJA,OAAK,eAAA,CAAG,MAAA,GAAA,EAAI,EAAC,WAAA,GAAe,MAAA,GAAA,EAAI,GAAG,WAAA,MAAW,IAAI,CAAA,CAAA,EAAA,GAAA,CACvD,YAES,MAAA,WAAA,GAAA,MAAA;6BAD4B,EAAA,UAAA,GAAnC,YAAmC,wBAAnB,WAAA,MAAW,IAAI,CAAA,EAAA,CAAA;;;KAGnC,mBAKM,OAAA,EALA,OAAK,eAAE,MAAA,GAAA,EAAI,EAAC,YAAA,CAAA,EAAA,GAAA,CAChB,mBAAiE,MAAA,EAA5D,OAAK,eAAE,MAAA,GAAA,EAAI,EAAC,iBAAA,CAAA,EAAA,GAAA,gBAAwB,WAAA,MAAW,KAAK,GAAA,CAAA,GAC7C,WAAA,MAAW,QAAA,UAAA,GAAvB,mBAEO,QAAA;;MAFuB,OAAK,eAAE,MAAA,GAAA,EAAI,EAAC,WAAA,CAAA;wBACrC,WAAA,MAAW,IAAI,GAAA,CAAA,KAAA,mBAAA,QAAA,IAAA,CAAA,GAAA,CAAA;KAGtB,YAQE,MAAA,WAAA,GAAA;MAPC,OAAK,eAAE,MAAA,GAAA,EAAI,EAAC,YAAA,CAAA;MACZ,MAAM,MAAA,KAAA;MACP,MAAA;MACA,QAAA;MACA,MAAK;MACL,OAAM;MACL,SAAO,MAAA,WAAA;;;;;;;kBAIZ,YAkBW,MAAA,WAAA,GAAA;KAlBD,QAAA;KAAQ,OAAK,eAAE,MAAA,GAAA,EAAI,EAAC,WAAA,CAAA;KAAgB,KAAK,QAAA;;4BAiBpC,CAhBb,YAgBa,YAAA;MAhBD,MAAK;MAAO,QAAA;MAAO,MAAK;;6BAezB,CAdT,YAcS,MAAA,YAAA,GAAA;gBAbH;OAAJ,KAAI;OACH,OAAO,MAAA,KAAA,EAAM;OACb,UAAU,MAAA,KAAA,EAAM;OAChB,eAAa,MAAA,KAAA,EAAM;;8BASlB,CAPF,WAOE,KAAA,QAAA,WAAA,eAAA,mBAAA;aAN6B,MAAA,KAAA,EAAM;eAA0B,MAAA,KAAA,EAAM;iBAA8B,MAAA,aAAA;eAAoC,MAAA,KAAA,EAAM,KAAK;;;;;;;;;;;;IAWxJ,mBAyBS,UAAA,EAzBA,OAAK,eAAE,MAAA,GAAA,EAAI,EAAC,aAAA,CAAA,EAAA,GAAA,CACqB,MAAA,KAAA,EAAM,YAAA,UAAA,GAA9C,mBAAmE,QAAA;;KAA5D,OAAK,eAAE,MAAA,GAAA,EAAI,EAAC,WAAA,CAAA;OAAqC,QAAI,CAAA,KACf,cAAA,SAAA,UAAA,GAA7C,mBAGO,QAAA;;KAHA,OAAK,eAAE,MAAA,GAAA,EAAI,EAAC,WAAA,CAAA;kDAAyC,UAE1D,EAAA,IAAA,mBAAkF,QAAA,EAA3E,OAAK,eAAA,GAAK,MAAA,GAAA,EAAI,GAAE,WAAA,IAAA,CAAiB,QAAA,MAAO,CAAA,EAAA,GAAA;+CAAI,OAAG,EAAA;KAAA,YAAkB,MAAA,WAAA,GAAA,MAAA;6BAAR,CAAA,GAAA,OAAA,OAAA,OAAA,KAAA,CAAA,gBAAH,OAAG,EAAA,CAAA,EAAA,CAAA;;;+CAAQ,OAAG,EAAA;gCAE7E,mBAIO,QAAA;;KAJA,OAAK,eAAE,MAAA,GAAA,EAAI,EAAC,WAAA,CAAA;QACjB,mBAEO,QAAA,EAFA,OAAK,eAAA,GAAK,MAAA,GAAA,EAAI,GAAE,WAAA,IAAA,CAAiB,QAAA,MAAO,CAAA,EAAA,GAAA;KAC7C,YAAuB,MAAA,WAAA,GAAA,MAAA;6BAAR,CAAA,GAAA,OAAA,OAAA,OAAA,KAAA,CAAA,gBAAR,YAAQ,EAAA,CAAA,EAAA,CAAA;;;+CAAQ,UAAM,EAAA;KAAA,YAAkB,MAAA,WAAA,GAAA,MAAA;6BAAR,CAAA,GAAA,OAAA,OAAA,OAAA,KAAA,CAAA,gBAAH,OAAG,EAAA,CAAA,EAAA,CAAA;;;+CAAQ,QACjD,EAAA;iBAGF,mBAYM,OAAA,EAZA,OAAK,eAAE,MAAA,GAAA,EAAI,EAAC,cAAA,CAAA,EAAA,GAAA,CAChB,YAA4E,MAAA,WAAA,GAAA;KAAlE,MAAA;KAAM,SAAS,MAAA,KAAA,EAAM;KAAU,SAAO,MAAA,WAAA;;4BAAiB,CAAA,GAAA,OAAA,OAAA,OAAA,KAAA,CAAA,gBAAJ,QAAI,EAAA,CAAA,EAAA,CAAA;;oCAE3C,MAAA,KAAA,EAAM,aAAc,SAAA,UAAa,UAAA,SAAa,UAAA,UAAgB,QAAA,SAAW,UAAA,UAAA,UAAA,GAD/F,YASW,MAAA,WAAA,GAAA;;KALR,MAAM,MAAA,KAAA,EAAM,SAAI,WAAA,YAAA;KAChB,SAAS,MAAA,KAAA,EAAM;KACf,SAAO,MAAA,UAAA;;4BAGV,CAAA,GAAA,OAAA,OAAA,OAAA,KAAA,CAAA,gBAFC,QAED,EAAA,CAAA,EAAA,CAAA"}
|
|
@@ -50,9 +50,25 @@ function useEdit(options) {
|
|
|
50
50
|
if (row) {
|
|
51
51
|
state.type = "update";
|
|
52
52
|
state.visible = true;
|
|
53
|
-
|
|
53
|
+
setFormData(row.data);
|
|
54
54
|
} else state.visible = false;
|
|
55
55
|
}, { flush: "sync" });
|
|
56
|
+
/**
|
|
57
|
+
* quick + update:model 实时写回 row.data,让表格显示同步更新。
|
|
58
|
+
* normal 模式不写回,需等待保存。
|
|
59
|
+
*
|
|
60
|
+
* 监听源仅限 props.model(deep 遍历仅作用于 model,不触及 row 树);
|
|
61
|
+
* mode/type/row 在回调中读取但不作为依赖,避免行切换等场景误触发。
|
|
62
|
+
*/
|
|
63
|
+
watch(() => props.model, (model) => {
|
|
64
|
+
const { row, type } = state;
|
|
65
|
+
if (props.mode !== "quick" || type !== "update" || !row || !model) return;
|
|
66
|
+
const data = row.data;
|
|
67
|
+
Object.keys(model).forEach((key) => {
|
|
68
|
+
const next = o(model).get(key);
|
|
69
|
+
if (o(data).get(key) !== next) o(data).set(key, next);
|
|
70
|
+
});
|
|
71
|
+
}, { deep: true });
|
|
56
72
|
const childrenKey = computed(() => {
|
|
57
73
|
return typeof props.tree === "string" ? props.tree : "children";
|
|
58
74
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-edit.js","names":[],"sources":["../../../src/components/batch-edit/use-edit.ts"],"sourcesContent":["import { last, o, safeRun } from '@cat-kit/core'\nimport { computed, nextTick, shallowReactive, shallowRef, watch, type ShallowRef } from 'vue'\n\nimport type { TableRow, BatchEditEmits, BatchEditProps } from '../../types'\nimport type { FormExposed } from '../../types/form'\n\n/** 按索引路径在原始数据树中定位节点(等价于历史 Forest.visit 路径访问) */\nfunction visitDataByIndexPath<T extends Record<string, unknown>>(\n roots: T[],\n indexPath: number[],\n childrenKey: string\n): T | undefined {\n if (!indexPath.length) return undefined\n let currentList: T[] | undefined = roots\n let node: T | undefined\n for (let i = 0; i < indexPath.length; i++) {\n const idx = indexPath[i]!\n if (!currentList) return undefined\n node = currentList[idx]\n if (node === undefined) return undefined\n if (i < indexPath.length - 1) {\n const next = node[childrenKey]\n currentList = Array.isArray(next) ? (next as T[]) : undefined\n }\n }\n return node\n}\n\ninterface Options {\n props: BatchEditProps\n emit: BatchEditEmits\n formRef: ShallowRef<FormExposed | undefined>\n}\n\nexport interface BatchEditStates {\n /** 层级 */\n depth?: number\n visible: boolean\n type: 'create' | 'update'\n loading: boolean\n row?: TableRow\n /** 父级,只在添加子级时会有值 */\n parentRow?: TableRow\n}\n\nexport interface EditReturned {\n state: BatchEditStates\n insertIndexes: ShallowRef<number[]>\n handleSave: () => Promise<void>\n handleClose: () => void\n handleCreate: () => Promise<void>\n handleEdit: (row: TableRow) => void\n handleCopy: (row: TableRow) => Promise<void>\n handleDelete: (row: TableRow) => Promise<void>\n handleInsertToNext: (row: TableRow) => Promise<void>\n handleInsertToPrev: (row: TableRow) => Promise<void>\n handleInsertChild: (row: TableRow) => Promise<void>\n}\n\nfunction snapshotData(data?: Record<string, any>) {\n return safeRun(() => JSON.parse(JSON.stringify(data ?? {})), {})\n}\n\nfunction replaceModelData(model: Record<string, any>, data: Record<string, any>) {\n for (const key of Object.keys(model)) {\n delete model[key]\n }\n Object.assign(model, data)\n}\n\nexport function useEdit(options: Options): EditReturned {\n const { props, emit, formRef } = options\n\n /** 组件状态 */\n const state = shallowReactive<BatchEditStates>({\n depth: undefined,\n visible: false,\n type: 'create',\n loading: false\n })\n\n const insertIndexes = shallowRef<number[]>([])\n\n function snapshotModelData() {\n return snapshotData(props.model)\n }\n\n function setFormData(formData?: Record<string, any>) {\n if (!props.model) return\n replaceModelData(props.model, snapshotData(formData))\n }\n\n const isQuickMode = () => props.mode === 'quick'\n\n async function runBeforeCreate(data: Record<string, any>) {\n await props.beforeCreate?.(data, state.parentRow?.data)\n }\n\n watch(\n () => state.row,\n (row) => {\n if (row) {\n state.type = 'update'\n state.visible = true\n if (!isQuickMode()) {\n setFormData(row.data)\n }\n } else {\n state.visible = false\n }\n },\n { flush: 'sync' }\n )\n\n const childrenKey = computed(() => {\n return typeof props.tree === 'string' ? props.tree : 'children'\n })\n\n /**\n * 插入数据\n * @param item 数据\n */\n function insert(item: Record<string, any>) {\n const data = [...(props.data ?? [])]\n\n const parent = visitDataByIndexPath(\n data ?? [],\n insertIndexes.value.slice(0, -1),\n childrenKey.value\n )\n\n if (parent) {\n const children = parent[childrenKey.value]\n if (!children) {\n parent[childrenKey.value] = [item]\n } else {\n children.splice(last(insertIndexes.value), 0, item)\n }\n } else {\n data.splice(last(insertIndexes.value), 0, item)\n }\n\n emit('update:data', data)\n\n return item\n }\n\n function getInsertData(): Record<string, any> {\n return snapshotModelData()\n }\n\n async function runCreate(cb: () => void, initialData?: Record<string, any>) {\n state.parentRow = undefined\n if (state.row) {\n state.row.isCurrent = false\n }\n state.row = undefined\n state.type = 'create'\n cb()\n\n await nextTick()\n\n setFormData(initialData)\n\n if (isQuickMode() && props.model) {\n await runBeforeCreate(props.model)\n }\n\n state.visible = true\n }\n\n /**\n * 点击新增按钮\n */\n async function handleCreate() {\n const { data } = props\n await runCreate(() => {\n state.depth = 1\n insertIndexes.value = [data?.length ?? 0]\n })\n }\n\n async function handleInsertToPrev(row: TableRow) {\n await runCreate(() => {\n state.depth = row.depth\n insertIndexes.value = [...row.indexes]\n })\n }\n\n async function handleInsertToNext(row: TableRow) {\n await runCreate(() => {\n state.depth = row.depth\n insertIndexes.value = [...row.indexes.slice(0, -1), row.index + 1]\n })\n }\n\n async function handleInsertChild(row: TableRow) {\n await runCreate(() => {\n state.parentRow = row\n state.depth = row.depth + 1\n row.expanded = true\n\n insertIndexes.value = [...row.indexes, row.children?.length ?? 0]\n })\n }\n\n /** 编辑指定行(等同于点击行) */\n function handleEdit(row: TableRow) {\n state.type = 'update'\n state.row = row\n state.depth = row.depth\n }\n\n /** 复制指定行:在其下方以 create 模式打开表单,并预填副本数据 */\n async function handleCopy(row: TableRow) {\n await runCreate(() => {\n state.depth = row.depth\n insertIndexes.value = [...row.indexes.slice(0, -1), row.index + 1]\n }, row.data)\n }\n\n function runWithLoading<Arg extends any[]>(fn: (...args: Arg) => Promise<void> | void) {\n return async (...args: Arg) => {\n state.loading = true\n if (state.row) {\n state.row.operating = true\n }\n try {\n await fn.apply(null, args)\n } catch (error) {\n console.error(error)\n }\n state.loading = false\n if (state.row) {\n state.row.operating = false\n }\n }\n }\n\n /** 保存 */\n const handleSave = runWithLoading(async () => {\n const { model, saveMethod } = props\n\n if (!model) return\n\n if (isQuickMode() && state.type === 'update') return\n\n formRef.value?.clearValidate()\n const valid = await formRef.value?.validate()\n\n if (!valid) return\n\n // quick + create:仅校验 + insert\n if (isQuickMode() && state.type === 'create') {\n insert(getInsertData())\n return\n }\n\n let item = getInsertData()\n\n // normal + create:beforeCreate → saveMethod → insert\n if (state.type === 'create') {\n await runBeforeCreate(item)\n if (saveMethod) {\n const result = await saveMethod(item, state.type, state.parentRow?.data)\n if (result) {\n item = result\n }\n }\n insert(item)\n return\n }\n\n // normal + update\n if (saveMethod) {\n const result = await saveMethod(item, state.type, state.parentRow?.data)\n if (result) {\n item = result\n }\n }\n\n const { row } = state\n row &&\n Object.keys(item).forEach((key) => {\n o(row.data).set(key, o(item).get(key))\n })\n })\n\n const handleDelete = runWithLoading(async (row: TableRow) => {\n const { deleteMethod } = props\n\n if (deleteMethod) {\n await deleteMethod([row.data])\n }\n\n const data = [...(props.data ?? [])]\n\n const parent = visitDataByIndexPath(data, row.indexes.slice(0, -1), childrenKey.value)\n\n if (parent) {\n const children = parent[childrenKey.value]\n if (children) {\n children.splice(row.index, 1)\n } else {\n console.error('行路径不正确')\n }\n } else {\n data.splice(row.index, 1)\n }\n\n if (state.row === row) {\n state.row = undefined\n state.depth = undefined\n }\n\n emit('update:data', data)\n })\n\n function handleClose() {\n state.visible = false\n if (state.row) {\n state.row.isCurrent = false\n }\n state.row = undefined\n state.parentRow = undefined\n state.depth = undefined\n insertIndexes.value = []\n }\n\n return {\n state,\n insertIndexes,\n handleDelete,\n handleInsertChild,\n handleInsertToNext,\n handleInsertToPrev,\n handleCreate,\n handleEdit,\n handleCopy,\n handleClose,\n handleSave\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"use-edit.js","names":[],"sources":["../../../src/components/batch-edit/use-edit.ts"],"sourcesContent":["import { last, o, safeRun } from '@cat-kit/core'\nimport { computed, nextTick, shallowReactive, shallowRef, watch, type ShallowRef } from 'vue'\n\nimport type { TableRow, BatchEditEmits, BatchEditProps } from '../../types'\nimport type { FormExposed } from '../../types/form'\n\n/** 按索引路径在原始数据树中定位节点(等价于历史 Forest.visit 路径访问) */\nfunction visitDataByIndexPath<T extends Record<string, unknown>>(\n roots: T[],\n indexPath: number[],\n childrenKey: string\n): T | undefined {\n if (!indexPath.length) return undefined\n let currentList: T[] | undefined = roots\n let node: T | undefined\n for (let i = 0; i < indexPath.length; i++) {\n const idx = indexPath[i]!\n if (!currentList) return undefined\n node = currentList[idx]\n if (node === undefined) return undefined\n if (i < indexPath.length - 1) {\n const next = node[childrenKey]\n currentList = Array.isArray(next) ? (next as T[]) : undefined\n }\n }\n return node\n}\n\ninterface Options {\n props: BatchEditProps\n emit: BatchEditEmits\n formRef: ShallowRef<FormExposed | undefined>\n}\n\nexport interface BatchEditStates {\n /** 层级 */\n depth?: number\n visible: boolean\n type: 'create' | 'update'\n loading: boolean\n row?: TableRow\n /** 父级,只在添加子级时会有值 */\n parentRow?: TableRow\n}\n\nexport interface EditReturned {\n state: BatchEditStates\n insertIndexes: ShallowRef<number[]>\n handleSave: () => Promise<void>\n handleClose: () => void\n handleCreate: () => Promise<void>\n handleEdit: (row: TableRow) => void\n handleCopy: (row: TableRow) => Promise<void>\n handleDelete: (row: TableRow) => Promise<void>\n handleInsertToNext: (row: TableRow) => Promise<void>\n handleInsertToPrev: (row: TableRow) => Promise<void>\n handleInsertChild: (row: TableRow) => Promise<void>\n}\n\nfunction snapshotData(data?: Record<string, any>) {\n return safeRun(() => JSON.parse(JSON.stringify(data ?? {})), {})\n}\n\nfunction replaceModelData(model: Record<string, any>, data: Record<string, any>) {\n for (const key of Object.keys(model)) {\n delete model[key]\n }\n Object.assign(model, data)\n}\n\nexport function useEdit(options: Options): EditReturned {\n const { props, emit, formRef } = options\n\n /** 组件状态 */\n const state = shallowReactive<BatchEditStates>({\n depth: undefined,\n visible: false,\n type: 'create',\n loading: false\n })\n\n const insertIndexes = shallowRef<number[]>([])\n\n function snapshotModelData() {\n return snapshotData(props.model)\n }\n\n function setFormData(formData?: Record<string, any>) {\n if (!props.model) return\n replaceModelData(props.model, snapshotData(formData))\n }\n\n const isQuickMode = () => props.mode === 'quick'\n\n async function runBeforeCreate(data: Record<string, any>) {\n await props.beforeCreate?.(data, state.parentRow?.data)\n }\n\n watch(\n () => state.row,\n (row) => {\n if (row) {\n state.type = 'update'\n state.visible = true\n // 所有模式下都回填 model,保证表单内条件字段(依赖 model)能响应当前编辑行\n setFormData(row.data)\n } else {\n state.visible = false\n }\n },\n { flush: 'sync' }\n )\n\n /**\n * quick + update:model 实时写回 row.data,让表格显示同步更新。\n * normal 模式不写回,需等待保存。\n *\n * 监听源仅限 props.model(deep 遍历仅作用于 model,不触及 row 树);\n * mode/type/row 在回调中读取但不作为依赖,避免行切换等场景误触发。\n */\n watch(\n () => props.model,\n (model) => {\n const { row, type } = state\n if (props.mode !== 'quick' || type !== 'update' || !row || !model) return\n const data = row.data\n Object.keys(model).forEach((key) => {\n const next = o(model).get(key)\n if (o(data).get(key) !== next) {\n o(data).set(key, next)\n }\n })\n },\n { deep: true }\n )\n\n const childrenKey = computed(() => {\n return typeof props.tree === 'string' ? props.tree : 'children'\n })\n\n /**\n * 插入数据\n * @param item 数据\n */\n function insert(item: Record<string, any>) {\n const data = [...(props.data ?? [])]\n\n const parent = visitDataByIndexPath(\n data ?? [],\n insertIndexes.value.slice(0, -1),\n childrenKey.value\n )\n\n if (parent) {\n const children = parent[childrenKey.value]\n if (!children) {\n parent[childrenKey.value] = [item]\n } else {\n children.splice(last(insertIndexes.value), 0, item)\n }\n } else {\n data.splice(last(insertIndexes.value), 0, item)\n }\n\n emit('update:data', data)\n\n return item\n }\n\n function getInsertData(): Record<string, any> {\n return snapshotModelData()\n }\n\n async function runCreate(cb: () => void, initialData?: Record<string, any>) {\n state.parentRow = undefined\n if (state.row) {\n state.row.isCurrent = false\n }\n state.row = undefined\n state.type = 'create'\n cb()\n\n await nextTick()\n\n setFormData(initialData)\n\n if (isQuickMode() && props.model) {\n await runBeforeCreate(props.model)\n }\n\n state.visible = true\n }\n\n /**\n * 点击新增按钮\n */\n async function handleCreate() {\n const { data } = props\n await runCreate(() => {\n state.depth = 1\n insertIndexes.value = [data?.length ?? 0]\n })\n }\n\n async function handleInsertToPrev(row: TableRow) {\n await runCreate(() => {\n state.depth = row.depth\n insertIndexes.value = [...row.indexes]\n })\n }\n\n async function handleInsertToNext(row: TableRow) {\n await runCreate(() => {\n state.depth = row.depth\n insertIndexes.value = [...row.indexes.slice(0, -1), row.index + 1]\n })\n }\n\n async function handleInsertChild(row: TableRow) {\n await runCreate(() => {\n state.parentRow = row\n state.depth = row.depth + 1\n row.expanded = true\n\n insertIndexes.value = [...row.indexes, row.children?.length ?? 0]\n })\n }\n\n /** 编辑指定行(等同于点击行) */\n function handleEdit(row: TableRow) {\n state.type = 'update'\n state.row = row\n state.depth = row.depth\n }\n\n /** 复制指定行:在其下方以 create 模式打开表单,并预填副本数据 */\n async function handleCopy(row: TableRow) {\n await runCreate(() => {\n state.depth = row.depth\n insertIndexes.value = [...row.indexes.slice(0, -1), row.index + 1]\n }, row.data)\n }\n\n function runWithLoading<Arg extends any[]>(fn: (...args: Arg) => Promise<void> | void) {\n return async (...args: Arg) => {\n state.loading = true\n if (state.row) {\n state.row.operating = true\n }\n try {\n await fn.apply(null, args)\n } catch (error) {\n console.error(error)\n }\n state.loading = false\n if (state.row) {\n state.row.operating = false\n }\n }\n }\n\n /** 保存 */\n const handleSave = runWithLoading(async () => {\n const { model, saveMethod } = props\n\n if (!model) return\n\n if (isQuickMode() && state.type === 'update') return\n\n formRef.value?.clearValidate()\n const valid = await formRef.value?.validate()\n\n if (!valid) return\n\n // quick + create:仅校验 + insert\n if (isQuickMode() && state.type === 'create') {\n insert(getInsertData())\n return\n }\n\n let item = getInsertData()\n\n // normal + create:beforeCreate → saveMethod → insert\n if (state.type === 'create') {\n await runBeforeCreate(item)\n if (saveMethod) {\n const result = await saveMethod(item, state.type, state.parentRow?.data)\n if (result) {\n item = result\n }\n }\n insert(item)\n return\n }\n\n // normal + update\n if (saveMethod) {\n const result = await saveMethod(item, state.type, state.parentRow?.data)\n if (result) {\n item = result\n }\n }\n\n const { row } = state\n row &&\n Object.keys(item).forEach((key) => {\n o(row.data).set(key, o(item).get(key))\n })\n })\n\n const handleDelete = runWithLoading(async (row: TableRow) => {\n const { deleteMethod } = props\n\n if (deleteMethod) {\n await deleteMethod([row.data])\n }\n\n const data = [...(props.data ?? [])]\n\n const parent = visitDataByIndexPath(data, row.indexes.slice(0, -1), childrenKey.value)\n\n if (parent) {\n const children = parent[childrenKey.value]\n if (children) {\n children.splice(row.index, 1)\n } else {\n console.error('行路径不正确')\n }\n } else {\n data.splice(row.index, 1)\n }\n\n if (state.row === row) {\n state.row = undefined\n state.depth = undefined\n }\n\n emit('update:data', data)\n })\n\n function handleClose() {\n state.visible = false\n if (state.row) {\n state.row.isCurrent = false\n }\n state.row = undefined\n state.parentRow = undefined\n state.depth = undefined\n insertIndexes.value = []\n }\n\n return {\n state,\n insertIndexes,\n handleDelete,\n handleInsertChild,\n handleInsertToNext,\n handleInsertToPrev,\n handleCreate,\n handleEdit,\n handleCopy,\n handleClose,\n handleSave\n }\n}\n"],"mappings":"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"}
|
|
@@ -17,9 +17,9 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_PublicProps, {}, {
|
|
|
17
17
|
"onUpdate:modelValue"?: ((checked: boolean) => any) | undefined;
|
|
18
18
|
onChange?: ((checked: boolean) => any) | undefined;
|
|
19
19
|
}>, {
|
|
20
|
+
type: import("@veltra/utils").ColorType;
|
|
20
21
|
disabled: boolean;
|
|
21
22
|
readonly: boolean;
|
|
22
|
-
type: import("@veltra/utils").ColorType;
|
|
23
23
|
round: boolean;
|
|
24
24
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
25
25
|
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
@@ -7,8 +7,8 @@ declare const __VLS_export: import("vue").DefineComponent<DatePanelProps, {}, {}
|
|
|
7
7
|
"onSelect:range-date"?: ((rangeDate?: [import("@cat-kit/core").Dater, import("@cat-kit/core").Dater] | undefined) => any) | undefined;
|
|
8
8
|
"onSelect:date"?: ((date: import("@cat-kit/core").Dater) => any) | undefined;
|
|
9
9
|
}>, {
|
|
10
|
-
size: import("@veltra/utils").ComponentSize;
|
|
11
10
|
type: "date" | "month" | "year";
|
|
11
|
+
size: import("@veltra/utils").ComponentSize;
|
|
12
12
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
13
13
|
declare const _default: typeof __VLS_export;
|
|
14
14
|
//#endregion
|
|
@@ -5,11 +5,11 @@ declare const __VLS_export: import("vue").DefineComponent<DatePickerProps, {}, {
|
|
|
5
5
|
}, string, import("vue").PublicProps, Readonly<DatePickerProps> & Readonly<{
|
|
6
6
|
"onUpdate:modelValue"?: ((value?: string | number | Date | undefined) => any) | undefined;
|
|
7
7
|
}>, {
|
|
8
|
+
type: "date" | "month" | "year";
|
|
8
9
|
placeholder: string;
|
|
9
10
|
clearable: boolean;
|
|
10
11
|
disabled: boolean;
|
|
11
12
|
readonly: boolean;
|
|
12
|
-
type: "date" | "month" | "year";
|
|
13
13
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
14
14
|
declare const _default: typeof __VLS_export;
|
|
15
15
|
//#endregion
|
|
@@ -5,11 +5,11 @@ declare const __VLS_export: import("vue").DefineComponent<DateRangePickerProps,
|
|
|
5
5
|
}, string, import("vue").PublicProps, Readonly<DateRangePickerProps> & Readonly<{
|
|
6
6
|
"onUpdate:modelValue"?: ((value?: [string, string] | undefined) => any) | undefined;
|
|
7
7
|
}>, {
|
|
8
|
+
type: "date" | "month" | "year";
|
|
8
9
|
placeholder: [string, string];
|
|
9
10
|
clearable: boolean;
|
|
10
11
|
disabled: boolean;
|
|
11
12
|
readonly: boolean;
|
|
12
|
-
type: "date" | "month" | "year";
|
|
13
13
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
14
14
|
declare const _default: typeof __VLS_export;
|
|
15
15
|
//#endregion
|
|
@@ -3,7 +3,7 @@ import _sfc_main$2 from "../tip/tip.js";
|
|
|
3
3
|
import { collectNavBranchPaths } from "../nav/helper.js";
|
|
4
4
|
import _sfc_main$3 from "../nav/nav.js";
|
|
5
5
|
import _sfc_main$4 from "./dual-nav-app.js";
|
|
6
|
-
import { findRootApp } from "./helper.js";
|
|
6
|
+
import { findFirstLeaf, findRootApp } from "./helper.js";
|
|
7
7
|
import { Fragment, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createVNode, defineComponent, normalizeClass, openBlock, ref, renderList, toDisplayString, unref, useTemplateRef, watch, withCtx } from "vue";
|
|
8
8
|
import { bem } from "@veltra/utils";
|
|
9
9
|
import { Folder, FolderOpened } from "@veltra/icons/normal";
|
|
@@ -64,7 +64,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
64
64
|
function handleAppClick(app) {
|
|
65
65
|
if (app.disabled) return;
|
|
66
66
|
panelAppPath.value = app.path;
|
|
67
|
-
|
|
67
|
+
emit("item-click", findFirstLeaf(app));
|
|
68
68
|
}
|
|
69
69
|
function handleToggleExpandAll() {
|
|
70
70
|
if (allExpanded.value) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dual-nav.js","names":[],"sources":["../../../src/components/dual-nav/dual-nav.vue"],"sourcesContent":["<template>\n <div :class=\"cls.b\">\n <div :class=\"cls.e('rail')\">\n <DualNavApp\n v-for=\"app in menus\"\n :key=\"app.path\"\n :app=\"app\"\n :active=\"isAppActive(app)\"\n :selected=\"isAppSelected(app)\"\n @click=\"handleAppClick(app)\"\n />\n </div>\n\n <!-- <div :class=\"cls.e('divider')\" aria-hidden=\"true\" /> -->\n\n <div :class=\"cls.e('panel')\">\n <template v-if=\"panelApp\">\n <div :class=\"cls.e('panel-header')\">\n <div :class=\"cls.e('panel-header-main')\">\n <h3 :class=\"cls.e('panel-title')\">{{ panelApp.title }}</h3>\n <p v-if=\"panelApp.description\" :class=\"cls.e('description')\">\n {{ panelApp.description }}\n </p>\n </div>\n\n <u-tip\n v-if=\"hasExpandableMenus\"\n :content=\"allExpanded ? '折叠全部' : '展开全部'\"\n hide-arrow\n >\n <button\n type=\"button\"\n :class=\"cls.e('toggle-expand')\"\n :aria-label=\"allExpanded ? '折叠全部' : '展开全部'\"\n @click=\"handleToggleExpandAll\"\n >\n <u-icon>\n <FolderOpened v-if=\"!allExpanded\" />\n <Folder v-else />\n </u-icon>\n </button>\n </u-tip>\n </div>\n\n <div :class=\"cls.e('panel-body')\">\n <UNav\n ref=\"navRef\"\n :menus=\"panelMenus\"\n :current-path=\"currentPath\"\n :collapsed=\"false\"\n @item-click=\"emit('item-click', $event)\"\n />\n </div>\n </template>\n </div>\n </div>\n</template>\n\n<script lang=\"ts\" setup>\nimport { Folder, FolderOpened } from '@veltra/icons/normal'\nimport { bem } from '@veltra/utils'\nimport { computed, ref, useTemplateRef, watch } from 'vue'\n\nimport type { DualNavEmits, DualNavProps, DualNavRootItem } from '../../types/dual-nav'\nimport type { NavExposed, NavItem } from '../../types/nav'\nimport { UIcon } from '../icon'\nimport { UNav } from '../nav'\nimport { collectNavBranchPaths } from '../nav/helper'\nimport { UTip } from '../tip'\nimport DualNavApp from './dual-nav-app.vue'\nimport { findRootApp } from './helper'\n\ndefineOptions({ name: 'DualNav' })\n\nconst props = defineProps<DualNavProps>()\nconst emit = defineEmits<DualNavEmits>()\n\nconst cls = bem('dual-nav')\nconst navRef = useTemplateRef<NavExposed>('navRef')\n\n/** 右栏当前展示的应用(点击左轨或 currentPath 同步) */\nconst panelAppPath = ref<string>()\nconst allExpanded = ref(false)\n\nfunction syncPanelAppFromCurrentPath(currentPath?: string) {\n const rootApp = findRootApp(props.menus, currentPath)\n if (rootApp) {\n panelAppPath.value = rootApp.path\n return\n }\n\n if (!panelAppPath.value && props.menus?.length) {\n panelAppPath.value = props.menus[0]!.path\n }\n}\n\nwatch(\n () => [props.currentPath, props.menus] as const,\n ([currentPath]) => {\n syncPanelAppFromCurrentPath(currentPath)\n },\n { immediate: true }\n)\n\nconst panelApp = computed<DualNavRootItem | undefined>(() => {\n if (!panelAppPath.value || !props.menus?.length) return undefined\n return props.menus.find((app) => app.path === panelAppPath.value)\n})\n\n/** 右栏菜单:有子级时展示子级,单层时展示根项自身 */\nconst panelMenus = computed<NavItem[] | undefined>(() => {\n const app = panelApp.value\n if (!app) return undefined\n if (app.children?.length) return app.children\n return [app]\n})\n\nconst hasExpandableMenus = computed(() => {\n return collectNavBranchPaths(panelMenus.value).length > 0\n})\n\nwatch(panelAppPath, () => {\n allExpanded.value = false\n})\n\n/** 左轨高亮:currentPath 落在该应用下时为激活态 */\nfunction isAppActive(app: NavItem): boolean {\n return findRootApp(props.menus, props.currentPath)?.path === app.path\n}\n\n/** 左轨选中:已切换右栏但尚未导航到该应用下任一菜单时,使用 hover 风格 */\nfunction isAppSelected(app: NavItem): boolean {\n return panelAppPath.value === app.path && !isAppActive(app)\n}\n\nfunction handleAppClick(app: NavItem) {\n if (app.disabled) return\n\n panelAppPath.value = app.path\n\n
|
|
1
|
+
{"version":3,"file":"dual-nav.js","names":[],"sources":["../../../src/components/dual-nav/dual-nav.vue"],"sourcesContent":["<template>\n <div :class=\"cls.b\">\n <div :class=\"cls.e('rail')\">\n <DualNavApp\n v-for=\"app in menus\"\n :key=\"app.path\"\n :app=\"app\"\n :active=\"isAppActive(app)\"\n :selected=\"isAppSelected(app)\"\n @click=\"handleAppClick(app)\"\n />\n </div>\n\n <!-- <div :class=\"cls.e('divider')\" aria-hidden=\"true\" /> -->\n\n <div :class=\"cls.e('panel')\">\n <template v-if=\"panelApp\">\n <div :class=\"cls.e('panel-header')\">\n <div :class=\"cls.e('panel-header-main')\">\n <h3 :class=\"cls.e('panel-title')\">{{ panelApp.title }}</h3>\n <p v-if=\"panelApp.description\" :class=\"cls.e('description')\">\n {{ panelApp.description }}\n </p>\n </div>\n\n <u-tip\n v-if=\"hasExpandableMenus\"\n :content=\"allExpanded ? '折叠全部' : '展开全部'\"\n hide-arrow\n >\n <button\n type=\"button\"\n :class=\"cls.e('toggle-expand')\"\n :aria-label=\"allExpanded ? '折叠全部' : '展开全部'\"\n @click=\"handleToggleExpandAll\"\n >\n <u-icon>\n <FolderOpened v-if=\"!allExpanded\" />\n <Folder v-else />\n </u-icon>\n </button>\n </u-tip>\n </div>\n\n <div :class=\"cls.e('panel-body')\">\n <UNav\n ref=\"navRef\"\n :menus=\"panelMenus\"\n :current-path=\"currentPath\"\n :collapsed=\"false\"\n @item-click=\"emit('item-click', $event)\"\n />\n </div>\n </template>\n </div>\n </div>\n</template>\n\n<script lang=\"ts\" setup>\nimport { Folder, FolderOpened } from '@veltra/icons/normal'\nimport { bem } from '@veltra/utils'\nimport { computed, ref, useTemplateRef, watch } from 'vue'\n\nimport type { DualNavEmits, DualNavProps, DualNavRootItem } from '../../types/dual-nav'\nimport type { NavExposed, NavItem } from '../../types/nav'\nimport { UIcon } from '../icon'\nimport { UNav } from '../nav'\nimport { collectNavBranchPaths } from '../nav/helper'\nimport { UTip } from '../tip'\nimport DualNavApp from './dual-nav-app.vue'\nimport { findFirstLeaf, findRootApp } from './helper'\n\ndefineOptions({ name: 'DualNav' })\n\nconst props = defineProps<DualNavProps>()\nconst emit = defineEmits<DualNavEmits>()\n\nconst cls = bem('dual-nav')\nconst navRef = useTemplateRef<NavExposed>('navRef')\n\n/** 右栏当前展示的应用(点击左轨或 currentPath 同步) */\nconst panelAppPath = ref<string>()\nconst allExpanded = ref(false)\n\nfunction syncPanelAppFromCurrentPath(currentPath?: string) {\n const rootApp = findRootApp(props.menus, currentPath)\n if (rootApp) {\n panelAppPath.value = rootApp.path\n return\n }\n\n if (!panelAppPath.value && props.menus?.length) {\n panelAppPath.value = props.menus[0]!.path\n }\n}\n\nwatch(\n () => [props.currentPath, props.menus] as const,\n ([currentPath]) => {\n syncPanelAppFromCurrentPath(currentPath)\n },\n { immediate: true }\n)\n\nconst panelApp = computed<DualNavRootItem | undefined>(() => {\n if (!panelAppPath.value || !props.menus?.length) return undefined\n return props.menus.find((app) => app.path === panelAppPath.value)\n})\n\n/** 右栏菜单:有子级时展示子级,单层时展示根项自身 */\nconst panelMenus = computed<NavItem[] | undefined>(() => {\n const app = panelApp.value\n if (!app) return undefined\n if (app.children?.length) return app.children\n return [app]\n})\n\nconst hasExpandableMenus = computed(() => {\n return collectNavBranchPaths(panelMenus.value).length > 0\n})\n\nwatch(panelAppPath, () => {\n allExpanded.value = false\n})\n\n/** 左轨高亮:currentPath 落在该应用下时为激活态 */\nfunction isAppActive(app: NavItem): boolean {\n return findRootApp(props.menus, props.currentPath)?.path === app.path\n}\n\n/** 左轨选中:已切换右栏但尚未导航到该应用下任一菜单时,使用 hover 风格 */\nfunction isAppSelected(app: NavItem): boolean {\n return panelAppPath.value === app.path && !isAppActive(app)\n}\n\nfunction handleAppClick(app: NavItem) {\n if (app.disabled) return\n\n panelAppPath.value = app.path\n\n emit('item-click', findFirstLeaf(app))\n}\n\nfunction handleToggleExpandAll() {\n if (allExpanded.value) {\n navRef.value?.collapseAll()\n allExpanded.value = false\n return\n }\n\n navRef.value?.expandAll()\n allExpanded.value = true\n}\n</script>\n"],"mappings":"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"}
|
|
@@ -15,7 +15,12 @@ function findRootApp(menus, currentPath) {
|
|
|
15
15
|
if (matched) return app;
|
|
16
16
|
}
|
|
17
17
|
}
|
|
18
|
+
/** 深度优先查找首个叶子节点(无子级或子级为空) */
|
|
19
|
+
function findFirstLeaf(node) {
|
|
20
|
+
if (!node.children?.length) return node;
|
|
21
|
+
return findFirstLeaf(node.children[0]);
|
|
22
|
+
}
|
|
18
23
|
//#endregion
|
|
19
|
-
export { findRootApp };
|
|
24
|
+
export { findFirstLeaf, findRootApp };
|
|
20
25
|
|
|
21
26
|
//# sourceMappingURL=helper.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"helper.js","names":[],"sources":["../../../src/components/dual-nav/helper.ts"],"sourcesContent":["import type { DualNavRootItem } from '../../types'\nimport { walkNavWithPath } from '../nav/walk-nav-path'\n\n/** 根据当前路径反查所属顶层应用 */\nexport function findRootApp(\n menus: DualNavRootItem[] | undefined,\n currentPath?: string\n): DualNavRootItem | undefined {\n if (!currentPath || !menus?.length) return undefined\n\n for (const app of menus) {\n if (app.path === currentPath) return app\n\n let matched = false\n walkNavWithPath(app, (node) => {\n if (node.path === currentPath) {\n matched = true\n return false\n }\n })\n if (matched) return app\n }\n\n return undefined\n}\n"],"mappings":";;;AAIA,SAAgB,YACd,OACA,aAC6B;CAC7B,IAAI,CAAC,eAAe,CAAC,OAAO,QAAQ,OAAO,KAAA;CAE3C,KAAK,MAAM,OAAO,OAAO;EACvB,IAAI,IAAI,SAAS,aAAa,OAAO;EAErC,IAAI,UAAU;EACd,gBAAgB,MAAM,SAAS;GAC7B,IAAI,KAAK,SAAS,aAAa;IAC7B,UAAU;IACV,OAAO;GACT;EACF,CAAC;EACD,IAAI,SAAS,OAAO;CACtB;AAGF"}
|
|
1
|
+
{"version":3,"file":"helper.js","names":[],"sources":["../../../src/components/dual-nav/helper.ts"],"sourcesContent":["import type { DualNavRootItem, NavItem } from '../../types'\nimport { walkNavWithPath } from '../nav/walk-nav-path'\n\n/** 根据当前路径反查所属顶层应用 */\nexport function findRootApp(\n menus: DualNavRootItem[] | undefined,\n currentPath?: string\n): DualNavRootItem | undefined {\n if (!currentPath || !menus?.length) return undefined\n\n for (const app of menus) {\n if (app.path === currentPath) return app\n\n let matched = false\n walkNavWithPath(app, (node) => {\n if (node.path === currentPath) {\n matched = true\n return false\n }\n })\n if (matched) return app\n }\n\n return undefined\n}\n\n/** 深度优先查找首个叶子节点(无子级或子级为空) */\nexport function findFirstLeaf(node: NavItem): NavItem {\n if (!node.children?.length) return node\n return findFirstLeaf(node.children[0]!)\n}\n"],"mappings":";;;AAIA,SAAgB,YACd,OACA,aAC6B;CAC7B,IAAI,CAAC,eAAe,CAAC,OAAO,QAAQ,OAAO,KAAA;CAE3C,KAAK,MAAM,OAAO,OAAO;EACvB,IAAI,IAAI,SAAS,aAAa,OAAO;EAErC,IAAI,UAAU;EACd,gBAAgB,MAAM,SAAS;GAC7B,IAAI,KAAK,SAAS,aAAa;IAC7B,UAAU;IACV,OAAO;GACT;EACF,CAAC;EACD,IAAI,SAAS,OAAO;CACtB;AAGF;;AAGA,SAAgB,cAAc,MAAwB;CACpD,IAAI,CAAC,KAAK,UAAU,QAAQ,OAAO;CACnC,OAAO,cAAc,KAAK,SAAS,EAAG;AACxC"}
|
|
@@ -20,7 +20,6 @@
|
|
|
20
20
|
height: 100%;
|
|
21
21
|
min-height: 0;
|
|
22
22
|
background-color: var(--u-nav-bg-color);
|
|
23
|
-
border: 1px solid var(--u-border-color);
|
|
24
23
|
border-radius: calc(var(--u-radius-large) + 6px);
|
|
25
24
|
overflow: hidden;
|
|
26
25
|
}
|
|
@@ -53,7 +52,6 @@
|
|
|
53
52
|
justify-content: space-between;
|
|
54
53
|
gap: 8px;
|
|
55
54
|
padding: 12px 12px 10px;
|
|
56
|
-
border-bottom: 1px solid var(--u-border-color);
|
|
57
55
|
}
|
|
58
56
|
.u-dual-nav__panel-header-main {
|
|
59
57
|
flex: 1;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { EmptyProps } from "../../types/empty.js";
|
|
2
2
|
//#region src/components/empty/empty.vue.d.ts
|
|
3
3
|
declare const __VLS_export: import("vue").DefineComponent<EmptyProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<EmptyProps> & Readonly<{}>, {
|
|
4
|
-
text: string;
|
|
5
4
|
size: number;
|
|
5
|
+
text: string;
|
|
6
6
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
7
7
|
declare const _default: typeof __VLS_export;
|
|
8
8
|
//#endregion
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { NumberProps } from "../../types/number.js";
|
|
2
2
|
//#region src/components/number/number.vue.d.ts
|
|
3
3
|
declare const __VLS_export: import("vue").DefineComponent<NumberProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<NumberProps> & Readonly<{}>, {
|
|
4
|
-
duration: number;
|
|
5
4
|
format: "currency" | "percent" | "decimal";
|
|
5
|
+
duration: number;
|
|
6
6
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
7
7
|
declare const _default: typeof __VLS_export;
|
|
8
8
|
//#endregion
|
|
@@ -6,11 +6,11 @@ type __VLS_Slots = {
|
|
|
6
6
|
tip?: (scope: StepsSlotScope) => any;
|
|
7
7
|
};
|
|
8
8
|
declare const __VLS_base: import("vue").DefineComponent<StepsProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
|
|
9
|
-
"item-click": (item: Record<string, any>, index: number) => any;
|
|
10
9
|
"update:current": (value?: string | number | undefined) => any;
|
|
10
|
+
"item-click": (item: Record<string, any>, index: number) => any;
|
|
11
11
|
}, string, import("vue").PublicProps, Readonly<StepsProps> & Readonly<{
|
|
12
|
-
"onItem-click"?: ((item: Record<string, any>, index: number) => any) | undefined;
|
|
13
12
|
"onUpdate:current"?: ((value?: string | number | undefined) => any) | undefined;
|
|
13
|
+
"onItem-click"?: ((item: Record<string, any>, index: number) => any) | undefined;
|
|
14
14
|
}>, {
|
|
15
15
|
labelKey: string;
|
|
16
16
|
direction: "horizontal" | "vertical";
|
|
@@ -15,12 +15,12 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_PublicProps, {}, {
|
|
|
15
15
|
"update:modelValue": (value: string | undefined) => any;
|
|
16
16
|
} & {
|
|
17
17
|
"update:modelValue": (value: string) => any;
|
|
18
|
-
click: (item: TabItem, index: number) => any;
|
|
19
18
|
close: (item: TabItem, index: number) => any;
|
|
19
|
+
click: (item: TabItem, index: number) => any;
|
|
20
20
|
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
21
21
|
"onUpdate:modelValue"?: ((value: string) => any) | undefined;
|
|
22
|
-
onClick?: ((item: TabItem, index: number) => any) | undefined;
|
|
23
22
|
onClose?: ((item: TabItem, index: number) => any) | undefined;
|
|
23
|
+
onClick?: ((item: TabItem, index: number) => any) | undefined;
|
|
24
24
|
}>, {
|
|
25
25
|
closable: boolean;
|
|
26
26
|
position: "top" | "bottom";
|
|
@@ -15,12 +15,12 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_PublicProps, {}, {
|
|
|
15
15
|
"update:modelValue": (value: string | undefined) => any;
|
|
16
16
|
} & {
|
|
17
17
|
"update:modelValue": (value: string) => any;
|
|
18
|
-
click: (item: TabItem, index: number) => any;
|
|
19
18
|
close: (item: TabItem, index: number) => any;
|
|
19
|
+
click: (item: TabItem, index: number) => any;
|
|
20
20
|
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
21
21
|
"onUpdate:modelValue"?: ((value: string) => any) | undefined;
|
|
22
|
-
onClick?: ((item: TabItem, index: number) => any) | undefined;
|
|
23
22
|
onClose?: ((item: TabItem, index: number) => any) | undefined;
|
|
23
|
+
onClick?: ((item: TabItem, index: number) => any) | undefined;
|
|
24
24
|
}>, {
|
|
25
25
|
closable: boolean;
|
|
26
26
|
position: "left" | "right";
|
|
@@ -10,12 +10,12 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_PublicProps, {}, {
|
|
|
10
10
|
"update:modelValue": (value: string | undefined) => any;
|
|
11
11
|
} & {
|
|
12
12
|
"update:modelValue": (value: string) => any;
|
|
13
|
-
click: (item: TabItem, index: number) => any;
|
|
14
13
|
close: (item: TabItem, index: number) => any;
|
|
14
|
+
click: (item: TabItem, index: number) => any;
|
|
15
15
|
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
16
16
|
"onUpdate:modelValue"?: ((value: string) => any) | undefined;
|
|
17
|
-
onClick?: ((item: TabItem, index: number) => any) | undefined;
|
|
18
17
|
onClose?: ((item: TabItem, index: number) => any) | undefined;
|
|
18
|
+
onClick?: ((item: TabItem, index: number) => any) | undefined;
|
|
19
19
|
}>, {
|
|
20
20
|
closable: boolean;
|
|
21
21
|
position: "left" | "right" | "top" | "bottom";
|
|
@@ -26,7 +26,7 @@ interface BatchEditProps extends TableProps {
|
|
|
26
26
|
/**
|
|
27
27
|
* 编辑模式
|
|
28
28
|
* @default 'normal'
|
|
29
|
-
* @description `quick`
|
|
29
|
+
* @description `quick` 模式下编辑行时表单实时写回 `row.data`(经 `model` 中转),且不调用 `saveMethod`
|
|
30
30
|
*/
|
|
31
31
|
mode?: BatchEditMode;
|
|
32
32
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@veltra/desktop",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.8",
|
|
4
4
|
"files": [
|
|
5
5
|
"dist",
|
|
6
6
|
"src"
|
|
@@ -68,11 +68,11 @@
|
|
|
68
68
|
"@cat-kit/core": ">=1.1.6",
|
|
69
69
|
"@cat-kit/excel": ">=1.0.0",
|
|
70
70
|
"@cat-kit/fe": "^1.1.6",
|
|
71
|
-
"@veltra/compositions": "1.2.
|
|
72
|
-
"@veltra/directives": "1.2.
|
|
73
|
-
"@veltra/icons": "1.2.
|
|
74
|
-
"@veltra/styles": "1.2.
|
|
75
|
-
"@veltra/utils": "1.2.
|
|
71
|
+
"@veltra/compositions": "1.2.8",
|
|
72
|
+
"@veltra/directives": "1.2.8",
|
|
73
|
+
"@veltra/icons": "1.2.8",
|
|
74
|
+
"@veltra/styles": "1.2.8",
|
|
75
|
+
"@veltra/utils": "1.2.8",
|
|
76
76
|
"vue": ">=3.5.0"
|
|
77
77
|
}
|
|
78
78
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<aside :class="cls.e('form')" v-if="state.visible &&
|
|
2
|
+
<aside :class="cls.e('form')" v-if="state.visible && props.model">
|
|
3
3
|
<header :class="cls.e('form-header')">
|
|
4
4
|
<span :class="[cls.e('form-icon'), bem.is(headerInfo.tone)]">
|
|
5
5
|
<u-icon>
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
<transition name="fade" appear mode="out-in">
|
|
28
28
|
<u-form
|
|
29
29
|
ref="formComponentRef"
|
|
30
|
-
:model="
|
|
30
|
+
:model="props.model"
|
|
31
31
|
:readonly="props.readonly"
|
|
32
32
|
:label-width="props.labelWidth"
|
|
33
33
|
>
|
|
@@ -129,13 +129,6 @@ const isQuick = computed(() => props.mode === 'quick')
|
|
|
129
129
|
const isNormal = computed(() => props.mode !== 'quick')
|
|
130
130
|
const isQuickUpdate = computed(() => isQuick.value && state.type === 'update')
|
|
131
131
|
|
|
132
|
-
const formModel = computed(() => {
|
|
133
|
-
if (isQuick.value && state.type === 'update' && state.row) {
|
|
134
|
-
return state.row.data
|
|
135
|
-
}
|
|
136
|
-
return props.model
|
|
137
|
-
})
|
|
138
|
-
|
|
139
132
|
interface HeaderInfo {
|
|
140
133
|
icon: Component
|
|
141
134
|
title: string
|
|
@@ -102,9 +102,8 @@ export function useEdit(options: Options): EditReturned {
|
|
|
102
102
|
if (row) {
|
|
103
103
|
state.type = 'update'
|
|
104
104
|
state.visible = true
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
}
|
|
105
|
+
// 所有模式下都回填 model,保证表单内条件字段(依赖 model)能响应当前编辑行
|
|
106
|
+
setFormData(row.data)
|
|
108
107
|
} else {
|
|
109
108
|
state.visible = false
|
|
110
109
|
}
|
|
@@ -112,6 +111,29 @@ export function useEdit(options: Options): EditReturned {
|
|
|
112
111
|
{ flush: 'sync' }
|
|
113
112
|
)
|
|
114
113
|
|
|
114
|
+
/**
|
|
115
|
+
* quick + update:model 实时写回 row.data,让表格显示同步更新。
|
|
116
|
+
* normal 模式不写回,需等待保存。
|
|
117
|
+
*
|
|
118
|
+
* 监听源仅限 props.model(deep 遍历仅作用于 model,不触及 row 树);
|
|
119
|
+
* mode/type/row 在回调中读取但不作为依赖,避免行切换等场景误触发。
|
|
120
|
+
*/
|
|
121
|
+
watch(
|
|
122
|
+
() => props.model,
|
|
123
|
+
(model) => {
|
|
124
|
+
const { row, type } = state
|
|
125
|
+
if (props.mode !== 'quick' || type !== 'update' || !row || !model) return
|
|
126
|
+
const data = row.data
|
|
127
|
+
Object.keys(model).forEach((key) => {
|
|
128
|
+
const next = o(model).get(key)
|
|
129
|
+
if (o(data).get(key) !== next) {
|
|
130
|
+
o(data).set(key, next)
|
|
131
|
+
}
|
|
132
|
+
})
|
|
133
|
+
},
|
|
134
|
+
{ deep: true }
|
|
135
|
+
)
|
|
136
|
+
|
|
115
137
|
const childrenKey = computed(() => {
|
|
116
138
|
return typeof props.tree === 'string' ? props.tree : 'children'
|
|
117
139
|
})
|
|
@@ -68,7 +68,7 @@ import { UNav } from '../nav'
|
|
|
68
68
|
import { collectNavBranchPaths } from '../nav/helper'
|
|
69
69
|
import { UTip } from '../tip'
|
|
70
70
|
import DualNavApp from './dual-nav-app.vue'
|
|
71
|
-
import { findRootApp } from './helper'
|
|
71
|
+
import { findFirstLeaf, findRootApp } from './helper'
|
|
72
72
|
|
|
73
73
|
defineOptions({ name: 'DualNav' })
|
|
74
74
|
|
|
@@ -138,9 +138,7 @@ function handleAppClick(app: NavItem) {
|
|
|
138
138
|
|
|
139
139
|
panelAppPath.value = app.path
|
|
140
140
|
|
|
141
|
-
|
|
142
|
-
emit('item-click', app)
|
|
143
|
-
}
|
|
141
|
+
emit('item-click', findFirstLeaf(app))
|
|
144
142
|
}
|
|
145
143
|
|
|
146
144
|
function handleToggleExpandAll() {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { DualNavRootItem } from '../../types'
|
|
1
|
+
import type { DualNavRootItem, NavItem } from '../../types'
|
|
2
2
|
import { walkNavWithPath } from '../nav/walk-nav-path'
|
|
3
3
|
|
|
4
4
|
/** 根据当前路径反查所属顶层应用 */
|
|
@@ -23,3 +23,9 @@ export function findRootApp(
|
|
|
23
23
|
|
|
24
24
|
return undefined
|
|
25
25
|
}
|
|
26
|
+
|
|
27
|
+
/** 深度优先查找首个叶子节点(无子级或子级为空) */
|
|
28
|
+
export function findFirstLeaf(node: NavItem): NavItem {
|
|
29
|
+
if (!node.children?.length) return node
|
|
30
|
+
return findFirstLeaf(node.children[0]!)
|
|
31
|
+
}
|
|
@@ -7,7 +7,6 @@
|
|
|
7
7
|
height: 100%;
|
|
8
8
|
min-height: 0;
|
|
9
9
|
background-color: var(--u-nav-bg-color);
|
|
10
|
-
border: 1px solid fn.use-var(border, color);
|
|
11
10
|
border-radius: calc(fn.use-var(radius, large) + 6px);
|
|
12
11
|
overflow: hidden;
|
|
13
12
|
|
|
@@ -43,7 +42,6 @@
|
|
|
43
42
|
justify-content: space-between;
|
|
44
43
|
gap: 8px;
|
|
45
44
|
padding: 12px 12px 10px;
|
|
46
|
-
border-bottom: 1px solid fn.use-var(border, color);
|
|
47
45
|
}
|
|
48
46
|
|
|
49
47
|
@include m.e(panel-header-main) {
|
package/src/types/batch-edit.ts
CHANGED
|
@@ -39,7 +39,7 @@ export interface BatchEditProps extends TableProps {
|
|
|
39
39
|
/**
|
|
40
40
|
* 编辑模式
|
|
41
41
|
* @default 'normal'
|
|
42
|
-
* @description `quick`
|
|
42
|
+
* @description `quick` 模式下编辑行时表单实时写回 `row.data`(经 `model` 中转),且不调用 `saveMethod`
|
|
43
43
|
*/
|
|
44
44
|
mode?: BatchEditMode
|
|
45
45
|
/**
|