@veltra/desktop 1.7.17 → 1.7.18
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/batch-edit/batch-edit-form.js +6 -1
- package/dist/components/batch-edit/batch-edit-form.js.map +1 -1
- package/dist/components/batch-edit/batch-edit-list.js +37 -31
- package/dist/components/batch-edit/batch-edit-list.js.map +1 -1
- package/dist/components/batch-edit/batch-edit.js +2 -2
- package/dist/components/batch-edit/batch-edit.js.map +1 -1
- package/dist/components/batch-edit/di.js.map +1 -1
- package/dist/components/batch-edit/use-edit-state.js +14 -10
- package/dist/components/batch-edit/use-edit-state.js.map +1 -1
- package/dist/components/batch-edit/use-handlers.js +1 -0
- package/dist/components/batch-edit/use-handlers.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/types/batch-edit.d.ts +0 -3
- package/dist/types/index.d.ts +2 -2
- package/package.json +1 -1
- package/src/components/batch-edit/__test__/batch-edit.test.ts +164 -38
- package/src/components/batch-edit/batch-edit-form.vue +7 -1
- package/src/components/batch-edit/batch-edit-list.vue +38 -24
- package/src/components/batch-edit/batch-edit.vue +2 -1
- package/src/components/batch-edit/di.ts +2 -0
- package/src/components/batch-edit/use-edit-state.ts +25 -32
- package/src/components/batch-edit/use-handlers.ts +2 -0
- package/src/types/batch-edit.ts +0 -4
|
@@ -52,13 +52,18 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
52
52
|
return creatable.value || updatable.value || creatableChild.value;
|
|
53
53
|
});
|
|
54
54
|
const headerInfo = computed(() => FORM_ACTION_HEADER_MAP[state.formActionType]);
|
|
55
|
+
/** 头部图标色调修饰类:样式中 createChild 对应的修饰类为 is-child */
|
|
56
|
+
const iconToneCls = computed(() => {
|
|
57
|
+
const type = state.formActionType;
|
|
58
|
+
return bem.is(type === "createChild" ? "child" : type);
|
|
59
|
+
});
|
|
55
60
|
return (_ctx, _cache) => {
|
|
56
61
|
return openBlock(), createElementBlock(Fragment, null, [createCommentVNode(" 面板模式:表单常驻挂载(快照只在挂载时对传入的 model 拍一次),仅用 v-show 控制显隐;\n 弹框模式:表单随弹框挂载 / 卸载,model 初始快照由 use-edit-state 维护 "), !!unref(props).model ? withDirectives((openBlock(), createElementBlock("aside", {
|
|
57
62
|
key: 0,
|
|
58
63
|
class: normalizeClass([unref(cls).e("form"), unref(bem).is("dialog", unref(props).formMode === "dialog")])
|
|
59
64
|
}, [
|
|
60
65
|
createElementVNode("header", { class: normalizeClass(unref(cls).e("form-header")) }, [
|
|
61
|
-
createElementVNode("span", { class: normalizeClass([unref(cls).e("form-icon"),
|
|
66
|
+
createElementVNode("span", { class: normalizeClass([unref(cls).e("form-icon"), iconToneCls.value]) }, [createVNode(unref(_sfc_main$1), null, {
|
|
62
67
|
default: withCtx(() => [(openBlock(), createBlock(resolveDynamicComponent(headerInfo.value.icon)))]),
|
|
63
68
|
_: 1
|
|
64
69
|
})], 2),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"batch-edit-form.js","names":[],"sources":["../../../src/components/batch-edit/batch-edit-form.vue"],"sourcesContent":["<template>\n <!-- 面板模式:表单常驻挂载(快照只在挂载时对传入的 model 拍一次),仅用 v-show 控制显隐;\n 弹框模式:表单随弹框挂载 / 卸载,model 初始快照由 use-edit-state 维护 -->\n <aside\n :class=\"[cls.e('form'), bem.is('dialog', props.formMode === 'dialog')]\"\n v-if=\"!!props.model\"\n v-show=\"state.formVisible\"\n >\n <header :class=\"cls.e('form-header')\">\n <span :class=\"[cls.e('form-icon'),
|
|
1
|
+
{"version":3,"file":"batch-edit-form.js","names":[],"sources":["../../../src/components/batch-edit/batch-edit-form.vue"],"sourcesContent":["<template>\n <!-- 面板模式:表单常驻挂载(快照只在挂载时对传入的 model 拍一次),仅用 v-show 控制显隐;\n 弹框模式:表单随弹框挂载 / 卸载,model 初始快照由 use-edit-state 维护 -->\n <aside\n :class=\"[cls.e('form'), bem.is('dialog', props.formMode === 'dialog')]\"\n v-if=\"!!props.model\"\n v-show=\"state.formVisible\"\n >\n <header :class=\"cls.e('form-header')\">\n <span :class=\"[cls.e('form-icon'), iconToneCls]\">\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 </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')\">\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 @field:update=\"handleFieldUpdate\"\n >\n <slot\n v-bind=\"{\n row: state.row,\n parentRow: state.parentRow,\n formActionType: state.formActionType,\n depth: state.depth,\n indexes: state.indexPath,\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')\">\n <template v-if=\"props.readonly\"> 只读模式 </template>\n\n <span :class=\"{ [bem.is('concealed')]: !shortcutActive }\">\n <template v-if=\"!(state.formActionType === 'update' && props.quickEdit)\">\n <u-kbd>Ctrl + S</u-kbd> 保存 ·\n </template>\n <u-kbd>Esc</u-kbd> 关闭\n </span>\n </span>\n\n <div :class=\"cls.e('form-actions')\">\n <u-button size=\"small\" text :loading=\"state.loading\" @click=\"handleClose\"> 取消 </u-button>\n <u-button\n v-if=\"showSaveBtn\"\n type=\"primary\"\n size=\"small\"\n title=\"保存\"\n :icon=\"Save\"\n :loading=\"state.loading\"\n @click=\"handleSave\"\n />\n </div>\n </footer>\n </aside>\n</template>\n\n<script lang=\"ts\" setup>\nimport { o } from '@cat-kit/core'\nimport { Close, Save } from '@veltra/icons/normal'\nimport { bem } from '@veltra/utils'\nimport { computed, inject, shallowRef, toRef } 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'\nimport { FORM_ACTION_HEADER_MAP } from './form-action-header'\nimport { useDialogEffect } from './use-dialog-effect'\n\ndefineOptions({ name: 'UBatchEditForm' })\n\nconst batchEditCtx = inject(BatchEditDIKey)!\n\nconst { cls, props, state, handleClose, handleSave, staticFeatures, dynamicFeatures, syncing } =\n batchEditCtx\n\nconst focused = toRef(batchEditCtx, 'focused')\n\n// 弹框模式下,弹框自身关闭(遮罩点击 / 右上角关闭)时同步走 handleClose,不保存\nuseDialogEffect({ closeForm: handleClose })\n\n/** 快捷键提示是否可见:面板模式随聚焦显隐;弹框模式弹框打开期间快捷键始终可用 */\nconst shortcutActive = computed(() => {\n return props.formMode === 'dialog' ? state.formVisible : focused.value\n})\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\nfunction handleFieldUpdate(field: string, value: any) {\n // 编程方式重置/回显期间不写回行数据,避免默认值污染源数据\n if (syncing.value) return\n\n if (state.row && props.quickEdit) {\n o(state.row.data).set(field, value)\n }\n}\n\nconst creatable = computed(() => {\n if (state.formActionType !== 'create') return false\n return staticFeatures.value.has('create') || dynamicFeatures.value.create?.(state.row)\n})\n\nconst creatableChild = computed(() => {\n if (state.formActionType !== 'createChild') return false\n return (\n staticFeatures.value.has('createChild') || dynamicFeatures.value.createChild?.(state.parentRow)\n )\n})\n\nconst updatable = computed(() => {\n if (state.formActionType !== 'update') return false\n return staticFeatures.value.has('update') || dynamicFeatures.value.update?.(state.row)\n})\n\nconst showSaveBtn = computed(() => {\n if (props.readonly) return false\n if (props.quickEdit && state.formActionType === 'update') return false\n return creatable.value || updatable.value || creatableChild.value\n})\n\nconst headerInfo = computed(() => FORM_ACTION_HEADER_MAP[state.formActionType])\n\n/** 头部图标色调修饰类:样式中 createChild 对应的修饰类为 is-child */\nconst iconToneCls = computed(() => {\n const type = state.formActionType\n return bem.is(type === 'createChild' ? 'child' : type)\n})\n</script>\n"],"mappings":"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"}
|
|
@@ -4,7 +4,7 @@ import { BatchEditDIKey } from "./di.js";
|
|
|
4
4
|
import _sfc_main$3 from "../action/action.js";
|
|
5
5
|
import action_group_default from "../action/action-group.js";
|
|
6
6
|
import { computed, createBlock, createCommentVNode, createElementVNode, createSlots, createTextVNode, createVNode, defineComponent, inject, mergeProps, normalizeClass, openBlock, unref, withCtx, withModifiers } from "vue";
|
|
7
|
-
import { AddChild, Delete, InsertToNext, InsertToPrev, Plus } from "@veltra/icons/normal";
|
|
7
|
+
import { AddChild, Delete, EditPen, InsertToNext, InsertToPrev, Plus, View } from "@veltra/icons/normal";
|
|
8
8
|
import { o } from "@cat-kit/core";
|
|
9
9
|
//#region src/components/batch-edit/batch-edit-list.vue
|
|
10
10
|
const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
@@ -12,7 +12,7 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
12
12
|
__name: "batch-edit-list",
|
|
13
13
|
props: { slots: {} },
|
|
14
14
|
setup(__props) {
|
|
15
|
-
const { cls, state, props, emit, staticFeatures, dynamicFeatures, handleCreate, handleDelete, handleInsertToNext, handleInsertToPrev, handleInsertChild } = inject(BatchEditDIKey);
|
|
15
|
+
const { cls, state, props, emit, staticFeatures, dynamicFeatures, startEdit, handleCreate, handleDelete, handleInsertToNext, handleInsertToPrev, handleInsertChild } = inject(BatchEditDIKey);
|
|
16
16
|
const tableProps = computed(() => {
|
|
17
17
|
return o(props).omit([
|
|
18
18
|
"model",
|
|
@@ -22,9 +22,11 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
22
22
|
"deleteMethod",
|
|
23
23
|
"saveMethod",
|
|
24
24
|
"features",
|
|
25
|
-
"mode",
|
|
26
25
|
"beforeCreate",
|
|
27
|
-
"formMode"
|
|
26
|
+
"formMode",
|
|
27
|
+
"quickEdit",
|
|
28
|
+
"labelWidth",
|
|
29
|
+
"actionsProps"
|
|
28
30
|
]);
|
|
29
31
|
});
|
|
30
32
|
const hasNot = (value) => value.every((v) => !staticFeatures.value.has(v));
|
|
@@ -32,12 +34,13 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
32
34
|
return staticFeatures.value.has(feature) || !!dynamicFeatures.value[feature]?.(row);
|
|
33
35
|
};
|
|
34
36
|
const columns = computed(() => {
|
|
35
|
-
|
|
37
|
+
const related = props.readonly ? ["update"] : [
|
|
36
38
|
"create",
|
|
37
39
|
"delete",
|
|
38
40
|
"createChild",
|
|
39
41
|
"update"
|
|
40
|
-
]
|
|
42
|
+
];
|
|
43
|
+
if (hasNot(related)) return props.columns;
|
|
41
44
|
return (props.columns ?? []).concat({
|
|
42
45
|
name: "操作",
|
|
43
46
|
key: "__action__",
|
|
@@ -47,9 +50,6 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
47
50
|
resizable: false
|
|
48
51
|
});
|
|
49
52
|
});
|
|
50
|
-
function handleUpdateCurrentRow(row) {
|
|
51
|
-
if (allowed("update", row)) state.row = row;
|
|
52
|
-
}
|
|
53
53
|
function canDelete(row) {
|
|
54
54
|
return !props.readonly && allowed("delete", row);
|
|
55
55
|
}
|
|
@@ -64,47 +64,53 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
64
64
|
slots: __props.slots,
|
|
65
65
|
class: [unref(cls).e("table")],
|
|
66
66
|
columns: columns.value,
|
|
67
|
-
"highlight-current": "",
|
|
68
67
|
current: unref(state).row,
|
|
69
|
-
"onUpdate:
|
|
70
|
-
"onUpdate:
|
|
71
|
-
"onUpdate:selected": _cache[2] || (_cache[2] = ($event) => unref(emit)("update:selected", $event))
|
|
68
|
+
"onUpdate:checked": _cache[0] || (_cache[0] = ($event) => unref(emit)("update:checked", $event)),
|
|
69
|
+
"onUpdate:selected": _cache[1] || (_cache[1] = ($event) => unref(emit)("update:selected", $event))
|
|
72
70
|
}), createSlots({
|
|
73
71
|
"column:__action__": withCtx(({ row }) => [createVNode(unref(action_group_default), {
|
|
74
|
-
class: normalizeClass(unref(cls).e("row-actions")),
|
|
75
72
|
max: 5,
|
|
76
|
-
onClick: _cache[0] || (_cache[0] = withModifiers(() => {}, ["stop"])),
|
|
77
73
|
circle: ""
|
|
78
74
|
}, {
|
|
79
75
|
default: withCtx(() => [
|
|
80
|
-
allowed("
|
|
76
|
+
allowed("update", row) ? (openBlock(), createBlock(unref(_sfc_main$3), mergeProps({
|
|
81
77
|
key: 0,
|
|
82
|
-
icon: unref(
|
|
83
|
-
title: "
|
|
84
|
-
onRun: ($event) => unref(
|
|
85
|
-
}, null,
|
|
86
|
-
|
|
78
|
+
icon: unref(props).readonly ? unref(View) : unref(EditPen),
|
|
79
|
+
title: unref(props).readonly ? "查看" : "编辑",
|
|
80
|
+
onRun: ($event) => unref(startEdit)(row)
|
|
81
|
+
}, unref(props).actionsProps?.update), null, 16, [
|
|
82
|
+
"icon",
|
|
83
|
+
"title",
|
|
84
|
+
"onRun"
|
|
85
|
+
])) : createCommentVNode("v-if", true),
|
|
86
|
+
!unref(props).readonly && !!unref(props).tree && allowed("createChild", row) ? (openBlock(), createBlock(unref(_sfc_main$3), {
|
|
87
87
|
key: 1,
|
|
88
|
-
icon: unref(InsertToNext),
|
|
89
|
-
title: "在下方插入",
|
|
90
|
-
onRun: ($event) => unref(handleInsertToNext)(row)
|
|
91
|
-
}, null, 8, ["icon", "onRun"])) : createCommentVNode("v-if", true),
|
|
92
|
-
!!unref(props).tree && allowed("createChild", row) ? (openBlock(), createBlock(unref(_sfc_main$3), {
|
|
93
|
-
key: 2,
|
|
94
88
|
icon: unref(AddChild),
|
|
95
89
|
title: "添加子级",
|
|
96
90
|
onRun: ($event) => unref(handleInsertChild)(row)
|
|
97
91
|
}, null, 8, ["icon", "onRun"])) : createCommentVNode("v-if", true),
|
|
98
92
|
canDelete(row) ? (openBlock(), createBlock(unref(_sfc_main$3), mergeProps({
|
|
99
|
-
key:
|
|
93
|
+
key: 2,
|
|
100
94
|
icon: unref(Delete),
|
|
101
95
|
type: "danger",
|
|
102
96
|
title: "删除",
|
|
103
97
|
onRun: ($event) => unref(handleDelete)(row)
|
|
104
|
-
}, unref(props).actionsProps?.delete), null, 16, ["icon", "onRun"])) : createCommentVNode("v-if", true)
|
|
98
|
+
}, unref(props).actionsProps?.delete), null, 16, ["icon", "onRun"])) : createCommentVNode("v-if", true),
|
|
99
|
+
!unref(props).readonly && allowed("create", row) ? (openBlock(), createBlock(unref(_sfc_main$3), {
|
|
100
|
+
key: 3,
|
|
101
|
+
icon: unref(InsertToPrev),
|
|
102
|
+
title: "在上方插入",
|
|
103
|
+
onRun: ($event) => unref(handleInsertToPrev)(row)
|
|
104
|
+
}, null, 8, ["icon", "onRun"])) : createCommentVNode("v-if", true),
|
|
105
|
+
!unref(props).readonly && allowed("create", row) ? (openBlock(), createBlock(unref(_sfc_main$3), {
|
|
106
|
+
key: 4,
|
|
107
|
+
icon: unref(InsertToNext),
|
|
108
|
+
title: "在下方插入",
|
|
109
|
+
onRun: ($event) => unref(handleInsertToNext)(row)
|
|
110
|
+
}, null, 8, ["icon", "onRun"])) : createCommentVNode("v-if", true)
|
|
105
111
|
]),
|
|
106
112
|
_: 2
|
|
107
|
-
},
|
|
113
|
+
}, 1024)]),
|
|
108
114
|
_: 2
|
|
109
115
|
}, [showCreateBtn.value ? {
|
|
110
116
|
name: "append",
|
|
@@ -116,7 +122,7 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
116
122
|
plain: "",
|
|
117
123
|
onClick: withModifiers(unref(handleCreate), ["stop"])
|
|
118
124
|
}, {
|
|
119
|
-
default: withCtx(() => [..._cache[
|
|
125
|
+
default: withCtx(() => [..._cache[2] || (_cache[2] = [createTextVNode(" 新增一行 ", -1)])]),
|
|
120
126
|
_: 1
|
|
121
127
|
}, 8, [
|
|
122
128
|
"class",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"batch-edit-list.js","names":[],"sources":["../../../src/components/batch-edit/batch-edit-list.vue"],"sourcesContent":["<template>\n <u-table\n v-bind=\"tableProps\"\n :slots=\"slots\"\n :class=\"[cls.e('table')]\"\n :columns=\"columns\"\n
|
|
1
|
+
{"version":3,"file":"batch-edit-list.js","names":[],"sources":["../../../src/components/batch-edit/batch-edit-list.vue"],"sourcesContent":["<template>\n <u-table\n v-bind=\"tableProps\"\n :slots=\"slots\"\n :class=\"[cls.e('table')]\"\n :columns=\"columns\"\n :current=\"state.row\"\n @update:checked=\"emit('update:checked', $event)\"\n @update:selected=\"emit('update:selected', $event)\"\n >\n <template #column:__action__=\"{ row }\">\n <u-action-group :max=\"5\" circle>\n <u-action\n v-if=\"allowed('update', row)\"\n :icon=\"props.readonly ? View : EditPen\"\n :title=\"props.readonly ? '查看' : '编辑'\"\n @run=\"startEdit(row)\"\n v-bind=\"props.actionsProps?.update\"\n />\n <u-action\n v-if=\"!props.readonly && !!props.tree && allowed('createChild', row)\"\n :icon=\"AddChild\"\n title=\"添加子级\"\n @run=\"handleInsertChild(row)\"\n />\n <u-action\n v-if=\"canDelete(row)\"\n :icon=\"Delete\"\n type=\"danger\"\n title=\"删除\"\n @run=\"handleDelete(row)\"\n v-bind=\"props.actionsProps?.delete\"\n />\n <u-action\n v-if=\"!props.readonly && allowed('create', row)\"\n :icon=\"InsertToPrev\"\n title=\"在上方插入\"\n @run=\"handleInsertToPrev(row)\"\n />\n <u-action\n v-if=\"!props.readonly && allowed('create', row)\"\n :icon=\"InsertToNext\"\n title=\"在下方插入\"\n @run=\"handleInsertToNext(row)\"\n />\n </u-action-group>\n </template>\n\n <!-- 新增按钮 -->\n <template #append v-if=\"showCreateBtn\">\n <div :class=\"cls.e('add')\">\n <u-button\n :class=\"cls.e('add-btn')\"\n :icon=\"Plus\"\n :loading=\"state.loading\"\n type=\"primary\"\n plain\n @click.stop=\"handleCreate\"\n >\n 新增一行\n </u-button>\n </div>\n </template>\n </u-table>\n</template>\n\n<script setup lang=\"ts\">\nimport { o } from '@cat-kit/core'\nimport {\n AddChild,\n Delete,\n EditPen,\n InsertToNext,\n InsertToPrev,\n Plus,\n View\n} from '@veltra/icons/normal'\nimport { computed, inject, type Slots } from 'vue'\n\nimport type { BatchEditFeature, TableRow } from '../../types'\nimport { UAction, UActionGroup } from '../action'\nimport { UButton } from '../button'\nimport { UTable } from '../table'\nimport { BatchEditDIKey } from './di'\n\ndefineOptions({ name: 'UBatchEditList' })\n\ndefineProps<{ slots: Slots }>()\n\nconst {\n cls,\n state,\n props,\n emit,\n staticFeatures,\n dynamicFeatures,\n startEdit,\n handleCreate,\n handleDelete,\n handleInsertToNext,\n handleInsertToPrev,\n handleInsertChild\n} = inject(BatchEditDIKey)!\n\nconst tableProps = computed(() => {\n return o(props as Record<string, any>).omit([\n 'model',\n 'columns',\n 'cols',\n 'readonly',\n 'deleteMethod',\n 'saveMethod',\n 'features',\n 'beforeCreate',\n 'formMode',\n 'quickEdit',\n 'labelWidth',\n 'actionsProps'\n ])\n})\n\nconst hasNot = (value: BatchEditFeature[]) => value.every((v) => !staticFeatures.value.has(v))\n\nconst allowed = (feature: BatchEditFeature, row?: TableRow) => {\n return staticFeatures.value.has(feature) || !!dynamicFeatures.value[feature]?.(row)\n}\n\nconst columns = computed(() => {\n // 只读模式的操作列只保留「查看」入口\n const related: BatchEditFeature[] = props.readonly\n ? ['update']\n : ['create', 'delete', 'createChild', 'update']\n if (hasNot(related)) return props.columns\n\n return (props.columns ?? []).concat({\n name: '操作',\n key: '__action__',\n align: 'center',\n width: 180,\n fixed: 'right',\n resizable: false\n })\n})\n\nfunction canDelete(row: TableRow) {\n return !props.readonly && allowed('delete', row)\n}\n\nconst showCreateBtn = computed(() => {\n if (props.readonly) return false\n\n const hasFeature = staticFeatures.value.has('create') || dynamicFeatures.value.create?.()\n const createActionVisible = state.formActionType === 'create' && state.formVisible\n return hasFeature && !createActionVisible\n})\n</script>\n"],"mappings":"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"}
|
|
@@ -16,7 +16,6 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
16
16
|
__name: "batch-edit",
|
|
17
17
|
props: {
|
|
18
18
|
model: {},
|
|
19
|
-
title: {},
|
|
20
19
|
cols: { default: () => ["1fr", "420px"] },
|
|
21
20
|
readonly: { type: Boolean },
|
|
22
21
|
formMode: { default: "panel" },
|
|
@@ -68,7 +67,7 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
68
67
|
const slots = useSlots();
|
|
69
68
|
const cls = bem("batch-edit");
|
|
70
69
|
const formRef = useTemplateRef("form");
|
|
71
|
-
const { state, resetState, syncing } = useEditState({
|
|
70
|
+
const { state, resetState, startEdit, syncing } = useEditState({
|
|
72
71
|
props,
|
|
73
72
|
formRef
|
|
74
73
|
});
|
|
@@ -98,6 +97,7 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
98
97
|
dynamicFeatures,
|
|
99
98
|
focused,
|
|
100
99
|
syncing,
|
|
100
|
+
startEdit,
|
|
101
101
|
...handlers
|
|
102
102
|
});
|
|
103
103
|
return (_ctx, _cache) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"batch-edit.js","names":["$attrs"],"sources":["../../../src/components/batch-edit/batch-edit.vue"],"sourcesContent":["<template>\n <u-layout\n :class=\"cls.b\"\n :cols=\"cols\"\n rows=\"minmax(0, 1fr) \"\n gap=\"8px\"\n resizable\n tabindex=\"-1\"\n @focusin=\"handleFocusIn\"\n @focusout=\"handleFocusOut\"\n @keydown.capture=\"handleKeydown\"\n v-bind=\"$attrs\"\n >\n <!-- 编辑列表 -->\n <BatchEditList :slots=\"slots\" />\n\n <!-- 编辑表单 -->\n <BatchEditForm v-if=\"props.formMode === 'panel'\" ref=\"form\" v-slot=\"scoped\">\n <slot name=\"form\" v-bind=\"scoped\" />\n </BatchEditForm>\n </u-layout>\n\n <!-- 弹框模式:表单经 UDialog 呈现(teleport 到 body),快捷键监听落在弹框上,Esc 与弹框自带的 keyup.esc 去重 -->\n <u-dialog\n v-if=\"props.formMode === 'dialog'\"\n v-model=\"state.formVisible\"\n :class=\"cls.e('form-dialog')\"\n @keydown.capture=\"handleKeydown\"\n @keyup.esc.stop\n >\n <BatchEditForm ref=\"form\" v-slot=\"scoped\">\n <slot name=\"form\" v-bind=\"scoped\" />\n </BatchEditForm>\n </u-dialog>\n</template>\n\n<script lang=\"ts\" setup>\nimport { bem } from '@veltra/utils'\nimport { computed, provide, useTemplateRef } from 'vue'\n\nimport type { BatchEditEmits, BatchEditProps, BatchEditSlots, FormExposed } from '../../types'\nimport { UDialog } from '../dialog'\nimport { ULayout } from '../layout'\nimport BatchEditForm from './batch-edit-form.vue'\nimport BatchEditList from './batch-edit-list.vue'\nimport { BatchEditDIKey } from './di'\nimport { useEditState } from './use-edit-state'\nimport { useFeatures } from './use-features'\nimport { useHandlers } from './use-handlers'\nimport { useShortcutKey } from './use-shortcut-key'\n\ndefineOptions({ name: 'UBatchEdit', inheritAttrs: false })\n\nconst props = withDefaults(defineProps<BatchEditProps>(), {\n cols: () => ['1fr', '420px'],\n formMode: 'panel'\n})\n\nconst emit = defineEmits<BatchEditEmits>()\n\nconst slots = defineSlots<BatchEditSlots>()\n\nconst cls = bem('batch-edit')\n\nconst formRef = useTemplateRef<FormExposed>('form')\n\nconst { state, resetState, syncing } = useEditState({ props, formRef })\n\nconst { staticFeatures, dynamicFeatures } = useFeatures({ props })\n\nconst handlers = useHandlers({ props, emit, state, resetState, formRef })\n\n// 快捷键处理\nconst { handleFocusIn, handleFocusOut, handleKeydown, focused } = useShortcutKey({\n props,\n onSave: handlers.handleSave,\n onClose: handlers.handleClose,\n state\n})\n\nconst cols = computed(() => {\n return props.formMode === 'panel' && state.formVisible ? props.cols : undefined\n})\n\nprovide(BatchEditDIKey, {\n cls,\n props,\n emit,\n state,\n staticFeatures,\n dynamicFeatures,\n focused,\n syncing,\n ...handlers\n})\n</script>\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"batch-edit.js","names":["$attrs"],"sources":["../../../src/components/batch-edit/batch-edit.vue"],"sourcesContent":["<template>\n <u-layout\n :class=\"cls.b\"\n :cols=\"cols\"\n rows=\"minmax(0, 1fr) \"\n gap=\"8px\"\n resizable\n tabindex=\"-1\"\n @focusin=\"handleFocusIn\"\n @focusout=\"handleFocusOut\"\n @keydown.capture=\"handleKeydown\"\n v-bind=\"$attrs\"\n >\n <!-- 编辑列表 -->\n <BatchEditList :slots=\"slots\" />\n\n <!-- 编辑表单 -->\n <BatchEditForm v-if=\"props.formMode === 'panel'\" ref=\"form\" v-slot=\"scoped\">\n <slot name=\"form\" v-bind=\"scoped\" />\n </BatchEditForm>\n </u-layout>\n\n <!-- 弹框模式:表单经 UDialog 呈现(teleport 到 body),快捷键监听落在弹框上,Esc 与弹框自带的 keyup.esc 去重 -->\n <u-dialog\n v-if=\"props.formMode === 'dialog'\"\n v-model=\"state.formVisible\"\n :class=\"cls.e('form-dialog')\"\n @keydown.capture=\"handleKeydown\"\n @keyup.esc.stop\n >\n <BatchEditForm ref=\"form\" v-slot=\"scoped\">\n <slot name=\"form\" v-bind=\"scoped\" />\n </BatchEditForm>\n </u-dialog>\n</template>\n\n<script lang=\"ts\" setup>\nimport { bem } from '@veltra/utils'\nimport { computed, provide, useTemplateRef } from 'vue'\n\nimport type { BatchEditEmits, BatchEditProps, BatchEditSlots, FormExposed } from '../../types'\nimport { UDialog } from '../dialog'\nimport { ULayout } from '../layout'\nimport BatchEditForm from './batch-edit-form.vue'\nimport BatchEditList from './batch-edit-list.vue'\nimport { BatchEditDIKey } from './di'\nimport { useEditState } from './use-edit-state'\nimport { useFeatures } from './use-features'\nimport { useHandlers } from './use-handlers'\nimport { useShortcutKey } from './use-shortcut-key'\n\ndefineOptions({ name: 'UBatchEdit', inheritAttrs: false })\n\nconst props = withDefaults(defineProps<BatchEditProps>(), {\n cols: () => ['1fr', '420px'],\n formMode: 'panel'\n})\n\nconst emit = defineEmits<BatchEditEmits>()\n\nconst slots = defineSlots<BatchEditSlots>()\n\nconst cls = bem('batch-edit')\n\nconst formRef = useTemplateRef<FormExposed>('form')\n\nconst { state, resetState, startEdit, syncing } = useEditState({ props, formRef })\n\nconst { staticFeatures, dynamicFeatures } = useFeatures({ props })\n\nconst handlers = useHandlers({ props, emit, state, resetState, formRef })\n\n// 快捷键处理\nconst { handleFocusIn, handleFocusOut, handleKeydown, focused } = useShortcutKey({\n props,\n onSave: handlers.handleSave,\n onClose: handlers.handleClose,\n state\n})\n\nconst cols = computed(() => {\n return props.formMode === 'panel' && state.formVisible ? props.cols : undefined\n})\n\nprovide(BatchEditDIKey, {\n cls,\n props,\n emit,\n state,\n staticFeatures,\n dynamicFeatures,\n focused,\n syncing,\n startEdit,\n ...handlers\n})\n</script>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAqDA,MAAM,QAAQ;EAKd,MAAM,OAAO;EAEb,MAAM,QAAQ,SAAA;EAEd,MAAM,MAAM,IAAI,YAAY;EAE5B,MAAM,UAAU,eAA4B,MAAM;EAElD,MAAM,EAAE,OAAO,YAAY,WAAW,YAAY,aAAa;GAAE;GAAO;EAAQ,CAAC;EAEjF,MAAM,EAAE,gBAAgB,oBAAoB,YAAY,EAAE,MAAM,CAAC;EAEjE,MAAM,WAAW,YAAY;GAAE;GAAO;GAAM;GAAO;GAAY;EAAQ,CAAC;EAGxE,MAAM,EAAE,eAAe,gBAAgB,eAAe,YAAY,eAAe;GAC/E;GACA,QAAQ,SAAS;GACjB,SAAS,SAAS;GAClB;EACF,CAAC;EAED,MAAM,OAAO,eAAe;GAC1B,OAAO,MAAM,aAAa,WAAW,MAAM,cAAc,MAAM,OAAO,KAAA;EACxE,CAAC;EAED,QAAQ,gBAAgB;GACtB;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA,GAAG;EACL,CAAC;;;IA9FC,YAmBW,MAAA,WAAA,GAnBX,WAmBW;KAlBR,OAAO,MAAA,GAAA,CAAG,CAAC;KACX,MAAM,KAAA;KACP,MAAK;KACL,KAAI;KACJ,WAAA;KACA,UAAS;KACR,WAAS,MAAA,aAAA;KACT,YAAU,MAAA,cAAA;KACO,kBAAA,MAAA,aAAA;IACVA,GAAAA,KAAAA,MAAM,GAAA;KAEd,SAAA,cAAa;MAAb,mBAAA,QAAA;MACA,YAAgC,aAAA,EAAT,MAAK,CAAA;MAE5B,mBAAA,QAAA;MACqB,MAAM,aAAQ,WAAnC,UAAA,GAAA,YAEgB,aAAA;;OAFiC,KAAI;;OACnD,SAAA,SADkE,WAAM,CACxE,WAAoC,KAAA,QAAA,QAAA,eAAA,mBAAV,MAAM,CAAA,CAAA,CAAA,CAAA;;;;;;;;;;;;IAIpC,mBAAA,2EAAA;IAEQ,MAAM,aAAQ,YADtB,UAAA,GAAA,YAUW,MAAA,WAAA,GAAA;;KARA,YAAA,MAAA,KAAA,CAAK,CAAC;KAAN,uBAAA,OAAA,OAAA,OAAA,MAAA,WAAA,MAAA,KAAA,CAAK,CAAC,cAAW;KACzB,OAAK,eAAE,MAAA,GAAA,CAAG,CAAC,EAAC,aAAA,CAAA;KACK,kBAAA,MAAA,aAAA;KACjB,SAAK,OAAA,OAAA,OAAA,KAAA,SAAA,oBAAN,CAAA,GAAe,CAAA,MAAA,CAAA,GAAA,CAAA,KAAA,CAAA;;KAEf,SAAA,cAEgB,CAFhB,YAEgB,aAAA,EAFD,KAAI,OAAM,GAAA;MACvB,SAAA,SADgC,WAAM,CACtC,WAAoC,KAAA,QAAA,QAAA,eAAA,mBAAV,MAAM,CAAA,CAAA,CAAA,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"di.js","names":[],"sources":["../../../src/components/batch-edit/di.ts"],"sourcesContent":["import type { BEM } from '@veltra/utils'\nimport type { ComputedRef, InjectionKey, ShallowRef } from 'vue'\n\nimport type {\n BatchEditEmits,\n BatchEditFeature,\n BatchEditProps,\n BatchEditStates,\n TableRow\n} from '../../types'\nimport type { EditReturned } from './use-handlers'\n\nexport const BatchEditDIKey: InjectionKey<\n {\n cls: BEM<'batch-edit', 'u-'>\n props: BatchEditProps\n emit: BatchEditEmits\n state: BatchEditStates\n staticFeatures: ComputedRef<Set<BatchEditFeature>>\n dynamicFeatures: ComputedRef<\n Record<BatchEditFeature, ((row?: TableRow) => boolean) | undefined>\n >\n /** 组件或其子节点是否处于聚焦状态 */\n focused: ShallowRef<boolean>\n /** 是否正在以编程方式重置/回显表单,此期间禁止 quick-edit 回写行数据 */\n syncing: ShallowRef<boolean>\n } & EditReturned\n> = Symbol('BatchEditDIKey')\n"],"mappings":";AAYA,MAAa,
|
|
1
|
+
{"version":3,"file":"di.js","names":[],"sources":["../../../src/components/batch-edit/di.ts"],"sourcesContent":["import type { BEM } from '@veltra/utils'\nimport type { ComputedRef, InjectionKey, ShallowRef } from 'vue'\n\nimport type {\n BatchEditEmits,\n BatchEditFeature,\n BatchEditProps,\n BatchEditStates,\n TableRow\n} from '../../types'\nimport type { EditReturned } from './use-handlers'\n\nexport const BatchEditDIKey: InjectionKey<\n {\n cls: BEM<'batch-edit', 'u-'>\n props: BatchEditProps\n emit: BatchEditEmits\n state: BatchEditStates\n staticFeatures: ComputedRef<Set<BatchEditFeature>>\n dynamicFeatures: ComputedRef<\n Record<BatchEditFeature, ((row?: TableRow) => boolean) | undefined>\n >\n /** 组件或其子节点是否处于聚焦状态 */\n focused: ShallowRef<boolean>\n /** 是否正在以编程方式重置/回显表单,此期间禁止 quick-edit 回写行数据 */\n syncing: ShallowRef<boolean>\n /** 开始编辑/查看一行(操作列「编辑」按钮触发) */\n startEdit: (row: TableRow) => void\n } & EditReturned\n> = Symbol('BatchEditDIKey')\n"],"mappings":";AAYA,MAAa,iBAiBT,OAAO,gBAAgB"}
|
|
@@ -34,29 +34,33 @@ function useEditState(options) {
|
|
|
34
34
|
}
|
|
35
35
|
function resetState() {
|
|
36
36
|
resetModel();
|
|
37
|
-
if (state.row) state.row.isCurrent = false;
|
|
38
37
|
Object.keys(state).forEach((key) => {
|
|
39
38
|
delete state[key];
|
|
40
39
|
});
|
|
41
40
|
Object.assign(state, defaultState);
|
|
42
41
|
}
|
|
43
|
-
|
|
42
|
+
/**
|
|
43
|
+
* 开始编辑/查看一行:先重置回 model 初始快照,再回显行数据。
|
|
44
|
+
* 同一 tick 内的连续写入会被表单字段 watcher 合并,
|
|
45
|
+
* 重置产生的默认值不会触发 field:update 回写行数据
|
|
46
|
+
*/
|
|
47
|
+
function startEdit(row) {
|
|
44
48
|
syncing.value = true;
|
|
45
49
|
resetModel();
|
|
46
|
-
if (row)
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
} else resetState();
|
|
50
|
+
if (props.model) o(props.model).deepExtend(row.data);
|
|
51
|
+
state.row = row;
|
|
52
|
+
state.formActionType = props.readonly ? "view" : "update";
|
|
53
|
+
state.formVisible = true;
|
|
54
|
+
state.depth = row.depth;
|
|
55
|
+
state.indexPath = [...row.indexes];
|
|
53
56
|
nextTick(() => {
|
|
54
57
|
syncing.value = false;
|
|
55
58
|
});
|
|
56
|
-
}
|
|
59
|
+
}
|
|
57
60
|
return {
|
|
58
61
|
state,
|
|
59
62
|
resetState,
|
|
63
|
+
startEdit,
|
|
60
64
|
syncing
|
|
61
65
|
};
|
|
62
66
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-edit-state.js","names":[],"sources":["../../../src/components/batch-edit/use-edit-state.ts"],"sourcesContent":["import { copy, o } from '@cat-kit/core'\nimport { nextTick, shallowReactive, shallowRef, watch, type ShallowRef } from 'vue'\n\nimport type { BatchEditProps, BatchEditStates, FormExposed } from '../../types'\n\ninterface Options {\n props: BatchEditProps\n formRef: ShallowRef<FormExposed | null>\n}\n\nexport function useEditState(options: Options) {\n const { props, formRef } = options\n\n const defaultState: BatchEditStates = {\n depth: -1,\n formVisible: false,\n formActionType: 'create',\n loading: false,\n indexPath: []\n }\n\n const state = shallowReactive({ ...defaultState })\n\n /** 是否正在以编程方式重置/回显表单,此期间禁止 quick-edit 回写行数据 */\n const syncing = shallowRef(false)\n\n /**\n * model 初始快照。\n * 面板模式由常驻挂载的 UForm 自行维护快照;dialog 模式表单随弹框卸载,\n * UForm 快照会在每次打开时按已回显的 model 重拍,故这里单独保留一份供恢复\n */\n const initialModel = shallowRef<Record<string, any>>()\n\n watch(\n () => props.model,\n (model) => {\n initialModel.value = props.formMode === 'dialog' && model ? copy(model) : undefined\n },\n { immediate: true }\n )\n\n /** 重置表单数据到 model 初始快照 */\n function resetModel() {\n if (props.formMode !== 'dialog') {\n formRef.value?.reset()\n return\n }\n\n formRef.value?.clearValidate()\n if (!props.model || !initialModel.value) return\n for (const key of Object.keys(initialModel.value)) {\n o(props.model).set(key, copy(initialModel.value[key]))\n }\n }\n\n function resetState() {\n resetModel()\n\n
|
|
1
|
+
{"version":3,"file":"use-edit-state.js","names":[],"sources":["../../../src/components/batch-edit/use-edit-state.ts"],"sourcesContent":["import { copy, o } from '@cat-kit/core'\nimport { nextTick, shallowReactive, shallowRef, watch, type ShallowRef } from 'vue'\n\nimport type { BatchEditProps, BatchEditStates, FormExposed, TableRow } from '../../types'\n\ninterface Options {\n props: BatchEditProps\n formRef: ShallowRef<FormExposed | null>\n}\n\nexport function useEditState(options: Options) {\n const { props, formRef } = options\n\n const defaultState: BatchEditStates = {\n depth: -1,\n formVisible: false,\n formActionType: 'create',\n loading: false,\n indexPath: []\n }\n\n const state = shallowReactive({ ...defaultState })\n\n /** 是否正在以编程方式重置/回显表单,此期间禁止 quick-edit 回写行数据 */\n const syncing = shallowRef(false)\n\n /**\n * model 初始快照。\n * 面板模式由常驻挂载的 UForm 自行维护快照;dialog 模式表单随弹框卸载,\n * UForm 快照会在每次打开时按已回显的 model 重拍,故这里单独保留一份供恢复\n */\n const initialModel = shallowRef<Record<string, any>>()\n\n watch(\n () => props.model,\n (model) => {\n initialModel.value = props.formMode === 'dialog' && model ? copy(model) : undefined\n },\n { immediate: true }\n )\n\n /** 重置表单数据到 model 初始快照 */\n function resetModel() {\n if (props.formMode !== 'dialog') {\n formRef.value?.reset()\n return\n }\n\n formRef.value?.clearValidate()\n if (!props.model || !initialModel.value) return\n for (const key of Object.keys(initialModel.value)) {\n o(props.model).set(key, copy(initialModel.value[key]))\n }\n }\n\n function resetState() {\n resetModel()\n\n Object.keys(state).forEach((key) => {\n delete state[key]\n })\n\n Object.assign(state, defaultState)\n }\n\n /**\n * 开始编辑/查看一行:先重置回 model 初始快照,再回显行数据。\n * 同一 tick 内的连续写入会被表单字段 watcher 合并,\n * 重置产生的默认值不会触发 field:update 回写行数据\n */\n function startEdit(row: TableRow) {\n syncing.value = true\n\n resetModel()\n\n if (props.model) {\n o(props.model).deepExtend(row.data)\n }\n\n state.row = row\n state.formActionType = props.readonly ? 'view' : 'update'\n state.formVisible = true\n state.depth = row.depth\n state.indexPath = [...row.indexes]\n\n nextTick(() => {\n syncing.value = false\n })\n }\n\n return { state, resetState, startEdit, syncing }\n}\n"],"mappings":";;;AAUA,SAAgB,aAAa,SAAkB;CAC7C,MAAM,EAAE,OAAO,YAAY;CAE3B,MAAM,eAAgC;EACpC,OAAO;EACP,aAAa;EACb,gBAAgB;EAChB,SAAS;EACT,WAAW,CAAC;CACd;CAEA,MAAM,QAAQ,gBAAgB,EAAE,GAAG,aAAa,CAAC;;CAGjD,MAAM,UAAU,WAAW,KAAK;;;;;;CAOhC,MAAM,eAAe,WAAgC;CAErD,YACQ,MAAM,QACX,UAAU;EACT,aAAa,QAAQ,MAAM,aAAa,YAAY,QAAQ,KAAK,KAAK,IAAI,KAAA;CAC5E,GACA,EAAE,WAAW,KAAK,CACpB;;CAGA,SAAS,aAAa;EACpB,IAAI,MAAM,aAAa,UAAU;GAC/B,QAAQ,OAAO,MAAM;GACrB;EACF;EAEA,QAAQ,OAAO,cAAc;EAC7B,IAAI,CAAC,MAAM,SAAS,CAAC,aAAa,OAAO;EACzC,KAAK,MAAM,OAAO,OAAO,KAAK,aAAa,KAAK,GAC9C,EAAE,MAAM,KAAK,CAAC,CAAC,IAAI,KAAK,KAAK,aAAa,MAAM,IAAI,CAAC;CAEzD;CAEA,SAAS,aAAa;EACpB,WAAW;EAEX,OAAO,KAAK,KAAK,CAAC,CAAC,SAAS,QAAQ;GAClC,OAAO,MAAM;EACf,CAAC;EAED,OAAO,OAAO,OAAO,YAAY;CACnC;;;;;;CAOA,SAAS,UAAU,KAAe;EAChC,QAAQ,QAAQ;EAEhB,WAAW;EAEX,IAAI,MAAM,OACR,EAAE,MAAM,KAAK,CAAC,CAAC,WAAW,IAAI,IAAI;EAGpC,MAAM,MAAM;EACZ,MAAM,iBAAiB,MAAM,WAAW,SAAS;EACjD,MAAM,cAAc;EACpB,MAAM,QAAQ,IAAI;EAClB,MAAM,YAAY,CAAC,GAAG,IAAI,OAAO;EAEjC,eAAe;GACb,QAAQ,QAAQ;EAClB,CAAC;CACH;CAEA,OAAO;EAAE;EAAO;EAAY;EAAW;CAAQ;AACjD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-handlers.js","names":[],"sources":["../../../src/components/batch-edit/use-handlers.ts"],"sourcesContent":["import { copy, last, o } from '@cat-kit/core'\nimport { computed, nextTick, type ShallowRef } from 'vue'\n\nimport type {\n TableRow,\n BatchEditEmits,\n BatchEditProps,\n BatchEditStates,\n FormExposed\n} from '../../types'\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 state: BatchEditStates\n formRef: ShallowRef<FormExposed | null>\n resetState: () => void\n}\n\nexport interface EditReturned {\n handleSave: () => Promise<void>\n handleClose: () => void\n handleCreate: () => void\n handleDelete: (row: TableRow) => Promise<void>\n handleInsertToNext: (row: TableRow) => void\n handleInsertToPrev: (row: TableRow) => void\n handleInsertChild: (row: TableRow) => void\n}\n\nexport function useHandlers(options: Options): EditReturned {\n const { props, emit, state, resetState, formRef } = options\n\n const childrenKey = computed(() => {\n return typeof props.tree === 'string' ? props.tree : 'children'\n })\n\n function getInsertData(): Record<string, any> {\n return copy(props.model ?? {})\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(data ?? [], state.indexPath.slice(0, -1), childrenKey.value)\n\n if (parent) {\n const children = parent[childrenKey.value]\n if (!children) {\n parent[childrenKey.value] = [item]\n } else {\n children.splice(last(state.indexPath), 0, item)\n }\n } else {\n data.splice(last(state.indexPath), 0, item)\n }\n\n emit('update:data', data)\n\n return item\n }\n\n /**\n * 点击新增按钮\n */\n function handleCreate() {\n const { data } = props\n\n resetState()\n\n nextTick(() => {\n state.formActionType = 'create'\n state.formVisible = true\n state.depth = 1\n state.indexPath = [data?.length ?? 0]\n emit('create')\n })\n }\n\n function handleInsertToPrev(row: TableRow) {\n resetState()\n state.formActionType = 'create'\n state.formVisible = true\n state.parentRow = row.parent\n state.depth = row.depth\n state.indexPath = [...row.indexes]\n emit('create-prev', row)\n }\n\n function handleInsertToNext(row: TableRow) {\n resetState()\n state.formActionType = 'create'\n state.formVisible = true\n state.parentRow = row.parent\n state.depth = row.depth\n state.indexPath = [...row.indexes.slice(0, -1), row.index + 1]\n emit('create-next', row)\n }\n\n function handleInsertChild(row: TableRow) {\n resetState()\n state.formActionType = 'createChild'\n state.formVisible = true\n state.parentRow = row\n state.depth = row.depth + 1\n row.expanded = true\n state.indexPath = [...row.indexes, row.children?.length ?? 0]\n emit('create-child', row)\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 const valid = await formRef.value?.validate()\n if (!model || !valid) return\n\n let item = getInsertData()\n\n // 新增\n if (state.formActionType === 'create' || state.formActionType === 'createChild') {\n await props.beforeCreate?.(item, state.parentRow?.data)\n if (saveMethod) {\n const result = await saveMethod(item, state.formActionType, state.parentRow?.data)\n if (result) {\n item = result\n }\n }\n insert(item)\n\n // 弹框模式保存成功即关闭,不走面板的连续新增\n if (props.formMode === 'dialog') {\n resetState()\n return\n }\n\n // 推进插入点,便于连续新增;并重置表单到初始默认值\n const next = last(state.indexPath) + 1\n state.indexPath = [...state.indexPath.slice(0, -1), next]\n formRef.value?.reset()\n return\n }\n\n // 普通模式下的编辑\n if (saveMethod) {\n const result = await saveMethod(item, state.formActionType, 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 if (props.formMode === 'dialog') {\n resetState()\n }\n })\n\n const handleDelete = runWithLoading(async (row: TableRow) => {\n const { deleteMethod } = props\n\n if (deleteMethod) {\n const result = await deleteMethod([row.data])\n if (result === false) {\n return\n }\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 resetState()\n }\n\n emit('update:data', data)\n })\n\n function handleClose() {\n resetState()\n }\n\n return {\n handleDelete,\n handleInsertChild,\n handleInsertToNext,\n handleInsertToPrev,\n handleCreate,\n handleClose,\n handleSave\n }\n}\n"],"mappings":";;;;AAYA,SAAS,qBACP,OACA,WACA,aACe;CACf,IAAI,CAAC,UAAU,QAAQ,OAAO,KAAA;CAC9B,IAAI,cAA+B;CACnC,IAAI;CACJ,KAAK,IAAI,IAAI,GAAG,IAAI,UAAU,QAAQ,KAAK;EACzC,MAAM,MAAM,UAAU;EACtB,IAAI,CAAC,aAAa,OAAO,KAAA;EACzB,OAAO,YAAY;EACnB,IAAI,SAAS,KAAA,GAAW,OAAO,KAAA;EAC/B,IAAI,IAAI,UAAU,SAAS,GAAG;GAC5B,MAAM,OAAO,KAAK;GAClB,cAAc,MAAM,QAAQ,IAAI,IAAK,OAAe,KAAA;EACtD;CACF;CACA,OAAO;AACT;AAoBA,SAAgB,YAAY,SAAgC;CAC1D,MAAM,EAAE,OAAO,MAAM,OAAO,YAAY,YAAY;CAEpD,MAAM,cAAc,eAAe;EACjC,OAAO,OAAO,MAAM,SAAS,WAAW,MAAM,OAAO;CACvD,CAAC;CAED,SAAS,gBAAqC;EAC5C,OAAO,KAAK,MAAM,SAAS,CAAC,CAAC;CAC/B;;;;;CAMA,SAAS,OAAO,MAA2B;EACzC,MAAM,OAAO,CAAC,GAAI,MAAM,QAAQ,CAAC,CAAE;EAEnC,MAAM,SAAS,qBAAqB,QAAQ,CAAC,GAAG,MAAM,UAAU,MAAM,GAAG,EAAE,GAAG,YAAY,KAAK;EAE/F,IAAI,QAAQ;GACV,MAAM,WAAW,OAAO,YAAY;GACpC,IAAI,CAAC,UACH,OAAO,YAAY,SAAS,CAAC,IAAI;QAEjC,SAAS,OAAO,KAAK,MAAM,SAAS,GAAG,GAAG,IAAI;EAElD,OACE,KAAK,OAAO,KAAK,MAAM,SAAS,GAAG,GAAG,IAAI;EAG5C,KAAK,eAAe,IAAI;EAExB,OAAO;CACT;;;;CAKA,SAAS,eAAe;EACtB,MAAM,EAAE,SAAS;EAEjB,WAAW;EAEX,eAAe;GACb,MAAM,iBAAiB;GACvB,MAAM,cAAc;GACpB,MAAM,QAAQ;GACd,MAAM,YAAY,CAAC,MAAM,UAAU,CAAC;GACpC,KAAK,QAAQ;EACf,CAAC;CACH;CAEA,SAAS,mBAAmB,KAAe;EACzC,WAAW;EACX,MAAM,iBAAiB;EACvB,MAAM,cAAc;EACpB,MAAM,YAAY,IAAI;EACtB,MAAM,QAAQ,IAAI;EAClB,MAAM,YAAY,CAAC,GAAG,IAAI,OAAO;EACjC,KAAK,eAAe,GAAG;CACzB;CAEA,SAAS,mBAAmB,KAAe;EACzC,WAAW;EACX,MAAM,iBAAiB;EACvB,MAAM,cAAc;EACpB,MAAM,YAAY,IAAI;EACtB,MAAM,QAAQ,IAAI;EAClB,MAAM,YAAY,CAAC,GAAG,IAAI,QAAQ,MAAM,GAAG,EAAE,GAAG,IAAI,QAAQ,CAAC;EAC7D,KAAK,eAAe,GAAG;CACzB;CAEA,SAAS,kBAAkB,KAAe;EACxC,WAAW;EACX,MAAM,iBAAiB;EACvB,MAAM,cAAc;EACpB,MAAM,YAAY;EAClB,MAAM,QAAQ,IAAI,QAAQ;EAC1B,IAAI,WAAW;EACf,MAAM,YAAY,CAAC,GAAG,IAAI,SAAS,IAAI,UAAU,UAAU,CAAC;EAC5D,KAAK,gBAAgB,GAAG;CAC1B;CAEA,SAAS,eAAkC,IAA4C;EACrF,OAAO,OAAO,GAAG,SAAc;
|
|
1
|
+
{"version":3,"file":"use-handlers.js","names":[],"sources":["../../../src/components/batch-edit/use-handlers.ts"],"sourcesContent":["import { copy, last, o } from '@cat-kit/core'\nimport { computed, nextTick, type ShallowRef } from 'vue'\n\nimport type {\n TableRow,\n BatchEditEmits,\n BatchEditProps,\n BatchEditStates,\n FormExposed\n} from '../../types'\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 state: BatchEditStates\n formRef: ShallowRef<FormExposed | null>\n resetState: () => void\n}\n\nexport interface EditReturned {\n handleSave: () => Promise<void>\n handleClose: () => void\n handleCreate: () => void\n handleDelete: (row: TableRow) => Promise<void>\n handleInsertToNext: (row: TableRow) => void\n handleInsertToPrev: (row: TableRow) => void\n handleInsertChild: (row: TableRow) => void\n}\n\nexport function useHandlers(options: Options): EditReturned {\n const { props, emit, state, resetState, formRef } = options\n\n const childrenKey = computed(() => {\n return typeof props.tree === 'string' ? props.tree : 'children'\n })\n\n function getInsertData(): Record<string, any> {\n return copy(props.model ?? {})\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(data ?? [], state.indexPath.slice(0, -1), childrenKey.value)\n\n if (parent) {\n const children = parent[childrenKey.value]\n if (!children) {\n parent[childrenKey.value] = [item]\n } else {\n children.splice(last(state.indexPath), 0, item)\n }\n } else {\n data.splice(last(state.indexPath), 0, item)\n }\n\n emit('update:data', data)\n\n return item\n }\n\n /**\n * 点击新增按钮\n */\n function handleCreate() {\n const { data } = props\n\n resetState()\n\n nextTick(() => {\n state.formActionType = 'create'\n state.formVisible = true\n state.depth = 1\n state.indexPath = [data?.length ?? 0]\n emit('create')\n })\n }\n\n function handleInsertToPrev(row: TableRow) {\n resetState()\n state.formActionType = 'create'\n state.formVisible = true\n state.parentRow = row.parent\n state.depth = row.depth\n state.indexPath = [...row.indexes]\n emit('create-prev', row)\n }\n\n function handleInsertToNext(row: TableRow) {\n resetState()\n state.formActionType = 'create'\n state.formVisible = true\n state.parentRow = row.parent\n state.depth = row.depth\n state.indexPath = [...row.indexes.slice(0, -1), row.index + 1]\n emit('create-next', row)\n }\n\n function handleInsertChild(row: TableRow) {\n resetState()\n state.formActionType = 'createChild'\n state.formVisible = true\n state.parentRow = row\n state.depth = row.depth + 1\n row.expanded = true\n state.indexPath = [...row.indexes, row.children?.length ?? 0]\n emit('create-child', row)\n }\n\n function runWithLoading<Arg extends any[]>(fn: (...args: Arg) => Promise<void> | void) {\n return async (...args: Arg) => {\n // 重入保护:进行中(快捷键/按钮并发触发)直接忽略\n if (state.loading) return\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 const valid = await formRef.value?.validate()\n if (!model || !valid) return\n\n let item = getInsertData()\n\n // 新增\n if (state.formActionType === 'create' || state.formActionType === 'createChild') {\n await props.beforeCreate?.(item, state.parentRow?.data)\n if (saveMethod) {\n const result = await saveMethod(item, state.formActionType, state.parentRow?.data)\n if (result) {\n item = result\n }\n }\n insert(item)\n\n // 弹框模式保存成功即关闭,不走面板的连续新增\n if (props.formMode === 'dialog') {\n resetState()\n return\n }\n\n // 推进插入点,便于连续新增;并重置表单到初始默认值\n const next = last(state.indexPath) + 1\n state.indexPath = [...state.indexPath.slice(0, -1), next]\n formRef.value?.reset()\n return\n }\n\n // 普通模式下的编辑\n if (saveMethod) {\n const result = await saveMethod(item, state.formActionType, 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 if (props.formMode === 'dialog') {\n resetState()\n }\n })\n\n const handleDelete = runWithLoading(async (row: TableRow) => {\n const { deleteMethod } = props\n\n if (deleteMethod) {\n const result = await deleteMethod([row.data])\n if (result === false) {\n return\n }\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 resetState()\n }\n\n emit('update:data', data)\n })\n\n function handleClose() {\n resetState()\n }\n\n return {\n handleDelete,\n handleInsertChild,\n handleInsertToNext,\n handleInsertToPrev,\n handleCreate,\n handleClose,\n handleSave\n }\n}\n"],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -115,7 +115,7 @@ import { DatePanelEmits, DatePanelProps, PanelType } from "./types/date-panel.js
|
|
|
115
115
|
import { DialogEmits, DialogExposed, DialogProps, DialogTransition, _DialogExposed } from "./types/dialog.js";
|
|
116
116
|
import { ActionEmits, ActionExposed, ActionGroupExposed, ActionGroupProps, ActionProps, _ActionExposed, _ActionGroupExposed } from "./types/action.js";
|
|
117
117
|
import { TableColumn, TableColumnAlign, TableColumnNode, TableColumnRenderContext, TableColumnSlotsScope, TableColumnStyle, TableEmits, TableExposed, TableProps, TableRow, TableRowSlotsScope, TableSummaryContext, _TableExposed } from "./types/table.js";
|
|
118
|
-
import { BatchEditColumn, BatchEditEmits, BatchEditExposed, BatchEditFeature,
|
|
118
|
+
import { BatchEditColumn, BatchEditEmits, BatchEditExposed, BatchEditFeature, BatchEditProps, BatchEditSlots, BatchEditStates, _BatchEditExposed } from "./types/batch-edit.js";
|
|
119
119
|
import { BreadcrumbEmits, BreadcrumbExposed, BreadcrumbItem, BreadcrumbProps, BreadcrumbSlotScope, _BreadcrumbExposed } from "./types/breadcrumb.js";
|
|
120
120
|
import { ListEmits, ListExposed, ListProps, _ListExposed } from "./types/list.js";
|
|
121
121
|
import { EmptyEmits, EmptyExposed, EmptyProps, _EmptyExposed } from "./types/empty.js";
|
|
@@ -185,4 +185,4 @@ import { defineBatchEditColumns } from "./components/batch-edit/helper.js";
|
|
|
185
185
|
import { defineTableColumns } from "./components/table/use-columns.js";
|
|
186
186
|
import "./components/index.js";
|
|
187
187
|
export * from "@veltra/utils";
|
|
188
|
-
export { type ActionEmits, type ActionExposed, type ActionGroupExposed, type ActionGroupProps, type ActionProps, type AnimationEmits, type AnimationExposed, type AnimationProps, type AutoCompleteEmits, type AutoCompleteExposed, type AutoCompleteProps, type BadgeEmits, type BadgeExposed, type BadgeProps, type BarType, type BatchEditColumn, type BatchEditEmits, type BatchEditExposed, type BatchEditFeature, type BatchEditFormStatus, type BatchEditProps, type BatchEditSlots, type BatchEditStates, type BreadcrumbEmits, type BreadcrumbExposed, type BreadcrumbItem, type BreadcrumbProps, type BreadcrumbSlotScope, type BreakCols, type Breakpoint, type ButtonEmits, type ButtonExposed, type ButtonProps, type ButtonType, type CalendarDay, type CalendarEmits, type CalendarExposed, type CalendarMonth, type CalendarProps, type CalendarYear, type CardActionProps, type CardContentProps, type CardCoverProps, type CardEmits, type CardExposed, type CardProps, type CascadeEmits, type CascadeExposed, type CascadeNode, type CascadeProps, type CheckTagEmits, type CheckTagExposed, type CheckTagProps, type CheckboxButtonEmits, type CheckboxButtonProps, type CheckboxEmits, type CheckboxExposed, type CheckboxGroupEmits, type CheckboxGroupExposed, type CheckboxGroupProps, type CheckboxProps, type CodeEditorEmits, type CodeEditorExposed, type CodeEditorLang, type CodeEditorProps, type CollapseEmits, type CollapseItemEmits, type CollapseItemProps, type CollapseModelValue, type CollapseProps, type CollapseValue, type ConditionConnector, type ConditionEditorEmits, type ConditionEditorExposed, type ConditionEditorProps, type EvaluateOptions as ConditionEvaluateOptions, type ConditionExpression, type ConditionField, type ConditionGroup, type ConditionLeaf, type ConditionNode, type ConditionValue, type ContextmenuEmits, type ContextmenuExposed, type ContextmenuItem, ContextmenuPanelDIKey, type ContextmenuProps, ContextmenuRootDIKey, type CssTransitionEmits, type CssTransitionExposed, type CssTransitionProps, type DatePanelEmits, type DatePanelProps, type DatePickerDataType, type DatePickerEmits, type DatePickerExposed, type DatePickerProps, type DateRangePickerDataType, type DateRangePickerEmits, type DateRangePickerExposed, type DateRangePickerProps, type DateRangeValue, type DialogEmits, type DialogExposed, type DialogProps, type DialogTransition, type DrawerDirection, type DrawerEmits, type DrawerExposed, type DrawerMode, type DrawerProps, type DropdownEmits, type DropdownExposed, type DropdownProps, type DualNavEmits, type DualNavExposed, type DualNavProps, type DualNavRailVariant, type DualNavRootItem, type EmptyEmits, type EmptyExposed, type EmptyProps, type ExpressionEditorEmits, type ExpressionEditorExposed, type ExpressionEditorProps, type ExpressionSelectableLevels, type FileViewerEmits, type FileViewerExposed, type FileViewerItem, type FileViewerKind, type FileViewerProps, type FloatButtonEmits, type FloatButtonExposed, type FloatButtonItem, type FloatButtonProps, type FormEmits, type FormExposed, type FormItemEmits, type FormItemExposed, type FormItemProps, type FormProps, type GanttChartEmits, type GanttChartExposed, type GanttChartProps, type GridEmits, type GridExposed, type GridInputEmits, type GridInputExposed, type GridInputProps, type GridItemProps, type GridProps, type GroupInputEmits, type GroupInputExposed, type GroupInputProps, type GroupNavEmits, type GroupNavGroup, type GroupNavProps, type IconEmits, type IconExposed, type IconProps, type ImageCropperChangePayload, type ImageCropperCropTransform, type ImageCropperEmits, type ImageCropperExposed, type ImageCropperProps, type ImageCropperResult, type ImageCropperResultOptions, type ImageCropperSelection, type InputEmits, type InputExposed, type InputProps, type LayoutEmits, type LayoutExposed, type LayoutProps, type ListEmits, type ListExposed, type ListProps, type LoadingEmits, type LoadingExposed, type LoadingProps, type LoadingType, type Message, type MessageConfirm, type MessageConfirmAction, type MessageConfirmEmits, type MessageConfirmExposed, type MessageConfirmInstance, type MessageConfirmOptions, type MessageConfirmProps, type MessageEmits, type MessageExposed, type MessageInstance, type MessageOptions, type MessageProps, type MessageType, type MultiAutoCompleteEmits, type MultiAutoCompleteExposed, type MultiAutoCompleteProps, type MultiSelectEmits, type MultiSelectExposed, type MultiSelectProps, type MultiTreeSelectEmits, type MultiTreeSelectExposed, type MultiTreeSelectProps, type NavEmits, type NavExposed, type NavItem, type NavProps, type NodeRenderExposed, type NodeRenderProps, type Notification, type NotificationEmits, type NotificationExposed, type NotificationInstance, type NotificationOptions, type NotificationPosition, type NotificationProps, type NumberEmits, type NumberExposed, type NumberInputEmits, type NumberInputExposed, type NumberInputProps, type NumberProps, type NumberRangeInputEmits, type NumberRangeInputExposed, type NumberRangeInputProps, type NumberRangeTuple, type PaginatorEmits, type PaginatorExposed, type PaginatorProps, type PaletteColorType, type PaletteEmits, type PaletteExposed, type PaletteHSV, type PaletteProps, type PaletteRGB, type PanelItem, type PanelType, type PasswordInputEmits, type PasswordInputExposed, type PasswordInputProps, type PopConfirmEmits, type PopConfirmExposed, type PopConfirmProps, type PopEmits, type PopExposed, type PopProps, type ProgressEmits, type ProgressExposed, type ProgressNodesEmits, type ProgressNodesExposed, type ProgressNodesProps, type ProgressProps, type QuickBatchEditEmits, type QuickBatchEditExposed, type QuickBatchEditProps, type RadioEmits, type RadioExposed, type RadioGroupEmits, type RadioGroupExposed, type RadioGroupProps, type RadioProps, type RichTextEditorEmits, type RichTextEditorExposed, type RichTextEditorProps, type RichTextFormat, type ScrollEmits, type ScrollExposed, type ScrollPosition, type ScrollProps, type SegmentEmits, type SegmentExposed, type SegmentItem, type SegmentProps, type SelectEmits, type SelectExposed, type SelectProps, type SliderEmits, type SliderExposed, type SliderProps, type StepsEmits, type StepsExposed, type StepsProps, type StepsSlotScope, type SwitchEmits, type SwitchExposed, type SwitchProps, type TabItem, type TableColumn, type TableColumnAlign, type TableColumnNode, type TableColumnRenderContext, type TableColumnSlotsScope, type TableColumnStyle, type TableEditorColumn, type TableEditorEmits, type TableEditorExposed, type TableEditorProps, type TableEmits, type TableExposed, type TableProps, type TableRow, type TableRowSlotsScope, type TableSummaryContext, type TabsEmits, type TabsExposed, type TabsHorizontalEmits, type TabsHorizontalExposed, type TabsHorizontalProps, type TabsProps, type TabsVerticalEmits, type TabsVerticalExposed, type TabsVerticalProps, type TagEmits, type TagExposed, type TagProps, type TextEditorEmits, type TextEditorExposed, type TextEditorProps, type TextEmits, type TextExposed, type TextProps, type TextareaEmits, type TextareaExposed, type TextareaProps, type ThemeExposed, type ThemeProps, type TipAlign, type TipDirection, type TipEmits, type TipExposed, type TipProps, type TipType, type ToolbarItem, type TreeEmit, type TreeExposed, type TreeNode, type TreeNodeProps, type TreeProps, type TreeSelectEmits, type TreeSelectExposed, type TreeSelectProps, _sfc_main as UAction, action_group_default as UActionGroup, _sfc_main$1 as UAutoComplete, _sfc_main$2 as UBadge, _sfc_main$3 as UBatchEdit, _sfc_main$4 as UBreadcrumb, _sfc_main$5 as UButton, _sfc_main$6 as UButtonGroup, _sfc_main$7 as UCalendar, _sfc_main$8 as UCard, _sfc_main$9 as UCardAction, _sfc_main$10 as UCardContent, _sfc_main$11 as UCardCover, _sfc_main$12 as UCardHeader, _sfc_main$13 as UCascade, _sfc_main$14 as UCheckTag, _sfc_main$15 as UCheckbox, _sfc_main$16 as UCheckboxButton, _sfc_main$17 as UCheckboxGroup, _sfc_main$18 as UCodeEditor, _sfc_main$19 as UCollapse, _sfc_main$20 as UCollapseItem, _sfc_main$21 as UConditionEditor, _sfc_main$22 as UContextmenu, _sfc_main$23 as UDatePanel, _sfc_main$24 as UDatePicker, _sfc_main$25 as UDateRangePicker, _sfc_main$26 as UDialog, _sfc_main$27 as UDrawer, _sfc_main$28 as UDropdown, _sfc_main$29 as UDualNav, _sfc_main$30 as UEmpty, _sfc_main$31 as UExpressionEditor, _sfc_main$32 as UFilePicker, _sfc_main$33 as UFileViewer, _sfc_main$34 as UFloatButton, form_default as UForm, form_item_default as UFormItem, _sfc_main$35 as UGanttChart, _sfc_main$36 as UGrid, _sfc_main$37 as UGridInput, _sfc_main$38 as UGridItem, _sfc_main$39 as UGroupInput, _sfc_main$40 as UGroupNav, _sfc_main$41 as UIcon, _sfc_main$42 as UImageCropper, input_default as UInput, _sfc_main$43 as UKbd, _sfc_main$44 as ULayout, _sfc_main$45 as UList, _sfc_main$46 as UListItem, _sfc_main$47 as ULoading, _sfc_main$48 as UMessage, _sfc_main$49 as UMessageConfirm, _sfc_main$50 as UMultiSelect, _sfc_main$51 as UMultiTreeSelect, _sfc_main$52 as UNav, _sfc_main$53 as UNavItem, _sfc_main$54 as UNavSub, NodeRender as UNodeRender, _sfc_main$55 as UNotification, _sfc_main$56 as UNumber, _sfc_main$57 as UNumberInput, _sfc_main$58 as UNumberRangeInput, _sfc_main$59 as UPaginator, _sfc_main$60 as UPalette, _sfc_main$61 as UPasswordInput, _sfc_main$62 as UPopConfirm, _sfc_main$63 as UProgress, _sfc_main$64 as UProgressNodes, _sfc_main$65 as URadio, _sfc_main$66 as URadioGroup, _sfc_main$67 as URichTextEditor, _sfc_main$68 as UScroll, _sfc_main$69 as USegment, _sfc_main$70 as USelect, _sfc_main$71 as USlider, _sfc_main$72 as USteps, _sfc_main$73 as USwitch, _sfc_main$74 as UTable, _sfc_main$75 as UTableEditor, _sfc_main$76 as UTabs, _sfc_main$77 as UTabsHorizontal, _sfc_main$78 as UTabsVertical, _sfc_main$79 as UTag, _sfc_main$80 as UText, _sfc_main$81 as UTextarea, _sfc_main$82 as UTheme, _sfc_main$83 as UTip, _sfc_main$84 as UTree, _sfc_main$85 as UTreeSelect, _sfc_main$86 as UWatermark, type UploaderEmits, type UploaderExposed, type UploaderProps, type VariableItem, type WatermarkEmits, type WatermarkExposed, type WatermarkProps, type _ActionExposed, type _ActionGroupExposed, type _AnimationExposed, type _AutoCompleteExposed, type _BadgeExposed, type _BatchEditExposed, type _BreadcrumbExposed, type _ButtonExposed, type _CalendarExposed, type _CardExposed, type _CascadeExposed, type _CheckTagExposed, type _CodeEditorExposed, type _ConditionEditorExposed, type _ContextmenuExposed, type _CssTransitionExposed, type _DatePickerExposed, type _DateRangePickerExposed, type _DialogExposed, type _DrawerExposed, type _DropdownExposed, type _DualNavExposed, type _EmptyExposed, type _ExpressionEditorExposed, type _FileViewerExposed, type _FloatButtonExposed, type _FormExposed, type _GanttChartExposed, type _GridExposed, type _GridInputExposed, type _GroupInputExposed, type _ImageCropperExposed, type _InputExposed, type _LayoutExposed, type _ListExposed, type _LoadingExposed, type _MessageConfirmExposed, type _MessageExposed, type _MultiAutoCompleteExposed, type _MultiSelectExposed, type _MultiTreeSelectExposed, type _NavExposed, type _NotificationExposed, type _PaginatorExposed, type _PaletteExposed, type _PasswordInputExposed, type _PopConfirmExposed, type _PopExposed, type _ProgressExposed, type _ProgressNodesExposed, type _QuickBatchEditExposed, type _RadioExposed, type _RadioGroupExposed, type _RichTextEditorExposed, type _ScrollExposed, type _SegmentExposed, type _SelectExposed, type _SliderExposed, type _StepsExposed, type _SwitchExposed, type _TableEditorExposed, type _TableExposed, type _TabsExposed, type _TabsHorizontalExposed, type _TabsVerticalExposed, type _TextEditorExposed, type _TextExposed, type _TextareaExposed, type _ThemeExposed, type _TipExposed, type _TreeExposed, type _TreeSelectExposed, type _UploaderExposed, type _WatermarkExposed, contextmenu, createEmptyGroup, createEmptyLeaf, defineBatchEditColumns, defineTableColumns, evaluate as evaluateConditionExpression, message, messageConfirm, notification, vLoading };
|
|
188
|
+
export { type ActionEmits, type ActionExposed, type ActionGroupExposed, type ActionGroupProps, type ActionProps, type AnimationEmits, type AnimationExposed, type AnimationProps, type AutoCompleteEmits, type AutoCompleteExposed, type AutoCompleteProps, type BadgeEmits, type BadgeExposed, type BadgeProps, type BarType, type BatchEditColumn, type BatchEditEmits, type BatchEditExposed, type BatchEditFeature, type BatchEditProps, type BatchEditSlots, type BatchEditStates, type BreadcrumbEmits, type BreadcrumbExposed, type BreadcrumbItem, type BreadcrumbProps, type BreadcrumbSlotScope, type BreakCols, type Breakpoint, type ButtonEmits, type ButtonExposed, type ButtonProps, type ButtonType, type CalendarDay, type CalendarEmits, type CalendarExposed, type CalendarMonth, type CalendarProps, type CalendarYear, type CardActionProps, type CardContentProps, type CardCoverProps, type CardEmits, type CardExposed, type CardProps, type CascadeEmits, type CascadeExposed, type CascadeNode, type CascadeProps, type CheckTagEmits, type CheckTagExposed, type CheckTagProps, type CheckboxButtonEmits, type CheckboxButtonProps, type CheckboxEmits, type CheckboxExposed, type CheckboxGroupEmits, type CheckboxGroupExposed, type CheckboxGroupProps, type CheckboxProps, type CodeEditorEmits, type CodeEditorExposed, type CodeEditorLang, type CodeEditorProps, type CollapseEmits, type CollapseItemEmits, type CollapseItemProps, type CollapseModelValue, type CollapseProps, type CollapseValue, type ConditionConnector, type ConditionEditorEmits, type ConditionEditorExposed, type ConditionEditorProps, type EvaluateOptions as ConditionEvaluateOptions, type ConditionExpression, type ConditionField, type ConditionGroup, type ConditionLeaf, type ConditionNode, type ConditionValue, type ContextmenuEmits, type ContextmenuExposed, type ContextmenuItem, ContextmenuPanelDIKey, type ContextmenuProps, ContextmenuRootDIKey, type CssTransitionEmits, type CssTransitionExposed, type CssTransitionProps, type DatePanelEmits, type DatePanelProps, type DatePickerDataType, type DatePickerEmits, type DatePickerExposed, type DatePickerProps, type DateRangePickerDataType, type DateRangePickerEmits, type DateRangePickerExposed, type DateRangePickerProps, type DateRangeValue, type DialogEmits, type DialogExposed, type DialogProps, type DialogTransition, type DrawerDirection, type DrawerEmits, type DrawerExposed, type DrawerMode, type DrawerProps, type DropdownEmits, type DropdownExposed, type DropdownProps, type DualNavEmits, type DualNavExposed, type DualNavProps, type DualNavRailVariant, type DualNavRootItem, type EmptyEmits, type EmptyExposed, type EmptyProps, type ExpressionEditorEmits, type ExpressionEditorExposed, type ExpressionEditorProps, type ExpressionSelectableLevels, type FileViewerEmits, type FileViewerExposed, type FileViewerItem, type FileViewerKind, type FileViewerProps, type FloatButtonEmits, type FloatButtonExposed, type FloatButtonItem, type FloatButtonProps, type FormEmits, type FormExposed, type FormItemEmits, type FormItemExposed, type FormItemProps, type FormProps, type GanttChartEmits, type GanttChartExposed, type GanttChartProps, type GridEmits, type GridExposed, type GridInputEmits, type GridInputExposed, type GridInputProps, type GridItemProps, type GridProps, type GroupInputEmits, type GroupInputExposed, type GroupInputProps, type GroupNavEmits, type GroupNavGroup, type GroupNavProps, type IconEmits, type IconExposed, type IconProps, type ImageCropperChangePayload, type ImageCropperCropTransform, type ImageCropperEmits, type ImageCropperExposed, type ImageCropperProps, type ImageCropperResult, type ImageCropperResultOptions, type ImageCropperSelection, type InputEmits, type InputExposed, type InputProps, type LayoutEmits, type LayoutExposed, type LayoutProps, type ListEmits, type ListExposed, type ListProps, type LoadingEmits, type LoadingExposed, type LoadingProps, type LoadingType, type Message, type MessageConfirm, type MessageConfirmAction, type MessageConfirmEmits, type MessageConfirmExposed, type MessageConfirmInstance, type MessageConfirmOptions, type MessageConfirmProps, type MessageEmits, type MessageExposed, type MessageInstance, type MessageOptions, type MessageProps, type MessageType, type MultiAutoCompleteEmits, type MultiAutoCompleteExposed, type MultiAutoCompleteProps, type MultiSelectEmits, type MultiSelectExposed, type MultiSelectProps, type MultiTreeSelectEmits, type MultiTreeSelectExposed, type MultiTreeSelectProps, type NavEmits, type NavExposed, type NavItem, type NavProps, type NodeRenderExposed, type NodeRenderProps, type Notification, type NotificationEmits, type NotificationExposed, type NotificationInstance, type NotificationOptions, type NotificationPosition, type NotificationProps, type NumberEmits, type NumberExposed, type NumberInputEmits, type NumberInputExposed, type NumberInputProps, type NumberProps, type NumberRangeInputEmits, type NumberRangeInputExposed, type NumberRangeInputProps, type NumberRangeTuple, type PaginatorEmits, type PaginatorExposed, type PaginatorProps, type PaletteColorType, type PaletteEmits, type PaletteExposed, type PaletteHSV, type PaletteProps, type PaletteRGB, type PanelItem, type PanelType, type PasswordInputEmits, type PasswordInputExposed, type PasswordInputProps, type PopConfirmEmits, type PopConfirmExposed, type PopConfirmProps, type PopEmits, type PopExposed, type PopProps, type ProgressEmits, type ProgressExposed, type ProgressNodesEmits, type ProgressNodesExposed, type ProgressNodesProps, type ProgressProps, type QuickBatchEditEmits, type QuickBatchEditExposed, type QuickBatchEditProps, type RadioEmits, type RadioExposed, type RadioGroupEmits, type RadioGroupExposed, type RadioGroupProps, type RadioProps, type RichTextEditorEmits, type RichTextEditorExposed, type RichTextEditorProps, type RichTextFormat, type ScrollEmits, type ScrollExposed, type ScrollPosition, type ScrollProps, type SegmentEmits, type SegmentExposed, type SegmentItem, type SegmentProps, type SelectEmits, type SelectExposed, type SelectProps, type SliderEmits, type SliderExposed, type SliderProps, type StepsEmits, type StepsExposed, type StepsProps, type StepsSlotScope, type SwitchEmits, type SwitchExposed, type SwitchProps, type TabItem, type TableColumn, type TableColumnAlign, type TableColumnNode, type TableColumnRenderContext, type TableColumnSlotsScope, type TableColumnStyle, type TableEditorColumn, type TableEditorEmits, type TableEditorExposed, type TableEditorProps, type TableEmits, type TableExposed, type TableProps, type TableRow, type TableRowSlotsScope, type TableSummaryContext, type TabsEmits, type TabsExposed, type TabsHorizontalEmits, type TabsHorizontalExposed, type TabsHorizontalProps, type TabsProps, type TabsVerticalEmits, type TabsVerticalExposed, type TabsVerticalProps, type TagEmits, type TagExposed, type TagProps, type TextEditorEmits, type TextEditorExposed, type TextEditorProps, type TextEmits, type TextExposed, type TextProps, type TextareaEmits, type TextareaExposed, type TextareaProps, type ThemeExposed, type ThemeProps, type TipAlign, type TipDirection, type TipEmits, type TipExposed, type TipProps, type TipType, type ToolbarItem, type TreeEmit, type TreeExposed, type TreeNode, type TreeNodeProps, type TreeProps, type TreeSelectEmits, type TreeSelectExposed, type TreeSelectProps, _sfc_main as UAction, action_group_default as UActionGroup, _sfc_main$1 as UAutoComplete, _sfc_main$2 as UBadge, _sfc_main$3 as UBatchEdit, _sfc_main$4 as UBreadcrumb, _sfc_main$5 as UButton, _sfc_main$6 as UButtonGroup, _sfc_main$7 as UCalendar, _sfc_main$8 as UCard, _sfc_main$9 as UCardAction, _sfc_main$10 as UCardContent, _sfc_main$11 as UCardCover, _sfc_main$12 as UCardHeader, _sfc_main$13 as UCascade, _sfc_main$14 as UCheckTag, _sfc_main$15 as UCheckbox, _sfc_main$16 as UCheckboxButton, _sfc_main$17 as UCheckboxGroup, _sfc_main$18 as UCodeEditor, _sfc_main$19 as UCollapse, _sfc_main$20 as UCollapseItem, _sfc_main$21 as UConditionEditor, _sfc_main$22 as UContextmenu, _sfc_main$23 as UDatePanel, _sfc_main$24 as UDatePicker, _sfc_main$25 as UDateRangePicker, _sfc_main$26 as UDialog, _sfc_main$27 as UDrawer, _sfc_main$28 as UDropdown, _sfc_main$29 as UDualNav, _sfc_main$30 as UEmpty, _sfc_main$31 as UExpressionEditor, _sfc_main$32 as UFilePicker, _sfc_main$33 as UFileViewer, _sfc_main$34 as UFloatButton, form_default as UForm, form_item_default as UFormItem, _sfc_main$35 as UGanttChart, _sfc_main$36 as UGrid, _sfc_main$37 as UGridInput, _sfc_main$38 as UGridItem, _sfc_main$39 as UGroupInput, _sfc_main$40 as UGroupNav, _sfc_main$41 as UIcon, _sfc_main$42 as UImageCropper, input_default as UInput, _sfc_main$43 as UKbd, _sfc_main$44 as ULayout, _sfc_main$45 as UList, _sfc_main$46 as UListItem, _sfc_main$47 as ULoading, _sfc_main$48 as UMessage, _sfc_main$49 as UMessageConfirm, _sfc_main$50 as UMultiSelect, _sfc_main$51 as UMultiTreeSelect, _sfc_main$52 as UNav, _sfc_main$53 as UNavItem, _sfc_main$54 as UNavSub, NodeRender as UNodeRender, _sfc_main$55 as UNotification, _sfc_main$56 as UNumber, _sfc_main$57 as UNumberInput, _sfc_main$58 as UNumberRangeInput, _sfc_main$59 as UPaginator, _sfc_main$60 as UPalette, _sfc_main$61 as UPasswordInput, _sfc_main$62 as UPopConfirm, _sfc_main$63 as UProgress, _sfc_main$64 as UProgressNodes, _sfc_main$65 as URadio, _sfc_main$66 as URadioGroup, _sfc_main$67 as URichTextEditor, _sfc_main$68 as UScroll, _sfc_main$69 as USegment, _sfc_main$70 as USelect, _sfc_main$71 as USlider, _sfc_main$72 as USteps, _sfc_main$73 as USwitch, _sfc_main$74 as UTable, _sfc_main$75 as UTableEditor, _sfc_main$76 as UTabs, _sfc_main$77 as UTabsHorizontal, _sfc_main$78 as UTabsVertical, _sfc_main$79 as UTag, _sfc_main$80 as UText, _sfc_main$81 as UTextarea, _sfc_main$82 as UTheme, _sfc_main$83 as UTip, _sfc_main$84 as UTree, _sfc_main$85 as UTreeSelect, _sfc_main$86 as UWatermark, type UploaderEmits, type UploaderExposed, type UploaderProps, type VariableItem, type WatermarkEmits, type WatermarkExposed, type WatermarkProps, type _ActionExposed, type _ActionGroupExposed, type _AnimationExposed, type _AutoCompleteExposed, type _BadgeExposed, type _BatchEditExposed, type _BreadcrumbExposed, type _ButtonExposed, type _CalendarExposed, type _CardExposed, type _CascadeExposed, type _CheckTagExposed, type _CodeEditorExposed, type _ConditionEditorExposed, type _ContextmenuExposed, type _CssTransitionExposed, type _DatePickerExposed, type _DateRangePickerExposed, type _DialogExposed, type _DrawerExposed, type _DropdownExposed, type _DualNavExposed, type _EmptyExposed, type _ExpressionEditorExposed, type _FileViewerExposed, type _FloatButtonExposed, type _FormExposed, type _GanttChartExposed, type _GridExposed, type _GridInputExposed, type _GroupInputExposed, type _ImageCropperExposed, type _InputExposed, type _LayoutExposed, type _ListExposed, type _LoadingExposed, type _MessageConfirmExposed, type _MessageExposed, type _MultiAutoCompleteExposed, type _MultiSelectExposed, type _MultiTreeSelectExposed, type _NavExposed, type _NotificationExposed, type _PaginatorExposed, type _PaletteExposed, type _PasswordInputExposed, type _PopConfirmExposed, type _PopExposed, type _ProgressExposed, type _ProgressNodesExposed, type _QuickBatchEditExposed, type _RadioExposed, type _RadioGroupExposed, type _RichTextEditorExposed, type _ScrollExposed, type _SegmentExposed, type _SelectExposed, type _SliderExposed, type _StepsExposed, type _SwitchExposed, type _TableEditorExposed, type _TableExposed, type _TabsExposed, type _TabsHorizontalExposed, type _TabsVerticalExposed, type _TextEditorExposed, type _TextExposed, type _TextareaExposed, type _ThemeExposed, type _TipExposed, type _TreeExposed, type _TreeSelectExposed, type _UploaderExposed, type _WatermarkExposed, contextmenu, createEmptyGroup, createEmptyLeaf, defineBatchEditColumns, defineTableColumns, evaluate as evaluateConditionExpression, message, messageConfirm, notification, vLoading };
|
|
@@ -5,7 +5,6 @@ import { DeconstructValue } from "@veltra/utils";
|
|
|
5
5
|
/** 批量编辑列 */
|
|
6
6
|
export interface BatchEditColumn extends TableColumn {}
|
|
7
7
|
export type BatchEditFeature = 'create' | 'update' | 'delete' | 'view' | 'createChild';
|
|
8
|
-
export type BatchEditFormStatus = 'hidden';
|
|
9
8
|
/** 批量编辑状态 */
|
|
10
9
|
export interface BatchEditStates {
|
|
11
10
|
/** 层级 */
|
|
@@ -30,8 +29,6 @@ export interface BatchEditProps extends TableProps {
|
|
|
30
29
|
* @description 与右侧 UForm 绑定的 reactive 对象
|
|
31
30
|
*/
|
|
32
31
|
model?: Record<string, any>;
|
|
33
|
-
/** 表格标题 */
|
|
34
|
-
title?: string;
|
|
35
32
|
/**
|
|
36
33
|
* 列的宽度定义
|
|
37
34
|
*/
|
package/dist/types/index.d.ts
CHANGED
|
@@ -24,7 +24,7 @@ import { DatePanelEmits, DatePanelProps, PanelType } from "./date-panel.js";
|
|
|
24
24
|
import { DialogEmits, DialogExposed, DialogProps, DialogTransition, _DialogExposed } from "./dialog.js";
|
|
25
25
|
import { ActionEmits, ActionExposed, ActionGroupExposed, ActionGroupProps, ActionProps, _ActionExposed, _ActionGroupExposed } from "./action.js";
|
|
26
26
|
import { TableColumn, TableColumnAlign, TableColumnNode, TableColumnRenderContext, TableColumnSlotsScope, TableColumnStyle, TableEmits, TableExposed, TableProps, TableRow, TableRowSlotsScope, TableSummaryContext, _TableExposed } from "./table.js";
|
|
27
|
-
import { BatchEditColumn, BatchEditEmits, BatchEditExposed, BatchEditFeature,
|
|
27
|
+
import { BatchEditColumn, BatchEditEmits, BatchEditExposed, BatchEditFeature, BatchEditProps, BatchEditSlots, BatchEditStates, _BatchEditExposed } from "./batch-edit.js";
|
|
28
28
|
import { BreadcrumbEmits, BreadcrumbExposed, BreadcrumbItem, BreadcrumbProps, BreadcrumbSlotScope, _BreadcrumbExposed } from "./breadcrumb.js";
|
|
29
29
|
import { ListEmits, ListExposed, ListProps, _ListExposed } from "./list.js";
|
|
30
30
|
import { EmptyEmits, EmptyExposed, EmptyProps, _EmptyExposed } from "./empty.js";
|
|
@@ -82,4 +82,4 @@ import { CollapseEmits, CollapseItemEmits, CollapseItemProps, CollapseModelValue
|
|
|
82
82
|
import { SegmentEmits, SegmentExposed, SegmentItem, SegmentProps, _SegmentExposed } from "./segment.js";
|
|
83
83
|
import { ImageCropperChangePayload, ImageCropperCropTransform, ImageCropperEmits, ImageCropperExposed, ImageCropperProps, ImageCropperResult, ImageCropperResultOptions, ImageCropperSelection, _ImageCropperExposed } from "./image-cropper.js";
|
|
84
84
|
export type * from "@veltra/utils";
|
|
85
|
-
export { ActionEmits, ActionExposed, ActionGroupExposed, ActionGroupProps, ActionProps, AnimationEmits, AnimationExposed, AnimationProps, AutoCompleteEmits, AutoCompleteExposed, AutoCompleteProps, BadgeEmits, BadgeExposed, BadgeProps, BarType, BatchEditColumn, BatchEditEmits, BatchEditExposed, BatchEditFeature,
|
|
85
|
+
export { ActionEmits, ActionExposed, ActionGroupExposed, ActionGroupProps, ActionProps, AnimationEmits, AnimationExposed, AnimationProps, AutoCompleteEmits, AutoCompleteExposed, AutoCompleteProps, BadgeEmits, BadgeExposed, BadgeProps, BarType, BatchEditColumn, BatchEditEmits, BatchEditExposed, BatchEditFeature, BatchEditProps, BatchEditSlots, BatchEditStates, BreadcrumbEmits, BreadcrumbExposed, BreadcrumbItem, BreadcrumbProps, BreadcrumbSlotScope, BreakCols, Breakpoint, ButtonEmits, ButtonExposed, ButtonProps, ButtonType, CalendarDay, CalendarEmits, CalendarExposed, CalendarMonth, CalendarProps, CalendarYear, CardActionProps, CardContentProps, CardCoverProps, CardEmits, CardExposed, CardProps, CascadeEmits, CascadeExposed, CascadeNode, CascadeProps, CheckTagEmits, CheckTagExposed, CheckTagProps, CheckboxButtonEmits, CheckboxButtonProps, CheckboxEmits, CheckboxExposed, CheckboxGroupEmits, CheckboxGroupExposed, CheckboxGroupProps, CheckboxProps, CodeEditorEmits, CodeEditorExposed, CodeEditorLang, CodeEditorProps, CollapseEmits, CollapseItemEmits, CollapseItemProps, CollapseModelValue, CollapseProps, CollapseValue, ConditionConnector, ConditionEditorEmits, ConditionEditorExposed, ConditionEditorProps, ConditionExpression, ConditionField, ConditionGroup, ConditionLeaf, ConditionNode, ConditionValue, ContextmenuEmits, ContextmenuExposed, ContextmenuItem, ContextmenuProps, CssTransitionEmits, CssTransitionExposed, CssTransitionProps, DatePanelEmits, DatePanelProps, DatePickerDataType, DatePickerEmits, DatePickerExposed, DatePickerProps, DateRangePickerDataType, DateRangePickerEmits, DateRangePickerExposed, DateRangePickerProps, DateRangeValue, DialogEmits, DialogExposed, DialogProps, DialogTransition, DrawerDirection, DrawerEmits, DrawerExposed, DrawerMode, DrawerProps, DropdownEmits, DropdownExposed, DropdownProps, DualNavEmits, DualNavExposed, DualNavProps, DualNavRailVariant, DualNavRootItem, EmptyEmits, EmptyExposed, EmptyProps, ExpressionEditorEmits, ExpressionEditorExposed, ExpressionEditorProps, ExpressionSelectableLevels, FileViewerEmits, FileViewerExposed, FileViewerItem, FileViewerKind, FileViewerProps, FloatButtonEmits, FloatButtonExposed, FloatButtonItem, FloatButtonProps, FormEmits, FormExposed, FormItemEmits, FormItemExposed, FormItemProps, FormProps, GanttChartEmits, GanttChartExposed, GanttChartProps, GridEmits, GridExposed, GridInputEmits, GridInputExposed, GridInputProps, GridItemProps, GridProps, GroupInputEmits, GroupInputExposed, GroupInputProps, GroupNavEmits, GroupNavGroup, GroupNavProps, IconEmits, IconExposed, IconProps, ImageCropperChangePayload, ImageCropperCropTransform, ImageCropperEmits, ImageCropperExposed, ImageCropperProps, ImageCropperResult, ImageCropperResultOptions, ImageCropperSelection, InputEmits, InputExposed, InputProps, LayoutEmits, LayoutExposed, LayoutProps, ListEmits, ListExposed, ListProps, LoadingEmits, LoadingExposed, LoadingProps, LoadingType, Message, MessageConfirm, MessageConfirmAction, MessageConfirmEmits, MessageConfirmExposed, MessageConfirmInstance, MessageConfirmOptions, MessageConfirmProps, MessageEmits, MessageExposed, MessageInstance, MessageOptions, MessageProps, MessageType, MultiAutoCompleteEmits, MultiAutoCompleteExposed, MultiAutoCompleteProps, MultiSelectEmits, MultiSelectExposed, MultiSelectProps, MultiTreeSelectEmits, MultiTreeSelectExposed, MultiTreeSelectProps, NavEmits, NavExposed, NavItem, NavProps, NodeRenderExposed, NodeRenderProps, Notification, NotificationEmits, NotificationExposed, NotificationInstance, NotificationOptions, NotificationPosition, NotificationProps, NumberEmits, NumberExposed, NumberInputEmits, NumberInputExposed, NumberInputProps, NumberProps, NumberRangeInputEmits, NumberRangeInputExposed, NumberRangeInputProps, NumberRangeTuple, PaginatorEmits, PaginatorExposed, PaginatorProps, PaletteColorType, PaletteEmits, PaletteExposed, PaletteHSV, PaletteProps, PaletteRGB, PanelItem, PanelType, PasswordInputEmits, PasswordInputExposed, PasswordInputProps, PopConfirmEmits, PopConfirmExposed, PopConfirmProps, PopEmits, PopExposed, PopProps, ProgressEmits, ProgressExposed, ProgressNodesEmits, ProgressNodesExposed, ProgressNodesProps, ProgressProps, QuickBatchEditEmits, QuickBatchEditExposed, QuickBatchEditProps, RadioEmits, RadioExposed, RadioGroupEmits, RadioGroupExposed, RadioGroupProps, RadioProps, RichTextEditorEmits, RichTextEditorExposed, RichTextEditorProps, RichTextFormat, ScrollEmits, ScrollExposed, ScrollPosition, ScrollProps, SegmentEmits, SegmentExposed, SegmentItem, SegmentProps, SelectEmits, SelectExposed, SelectProps, SliderEmits, SliderExposed, SliderProps, StepsEmits, StepsExposed, StepsProps, StepsSlotScope, SwitchEmits, SwitchExposed, SwitchProps, TabItem, TableColumn, TableColumnAlign, TableColumnNode, TableColumnRenderContext, TableColumnSlotsScope, TableColumnStyle, TableEditorColumn, TableEditorEmits, TableEditorExposed, TableEditorProps, TableEmits, TableExposed, TableProps, TableRow, TableRowSlotsScope, TableSummaryContext, TabsEmits, TabsExposed, TabsHorizontalEmits, TabsHorizontalExposed, TabsHorizontalProps, TabsProps, TabsVerticalEmits, TabsVerticalExposed, TabsVerticalProps, TagEmits, TagExposed, TagProps, TextEditorEmits, TextEditorExposed, TextEditorProps, TextEmits, TextExposed, TextProps, TextareaEmits, TextareaExposed, TextareaProps, ThemeExposed, ThemeProps, TipAlign, TipDirection, TipEmits, TipExposed, TipProps, TipType, ToolbarItem, TreeEmit, TreeExposed, TreeNode, TreeNodeProps, TreeProps, TreeSelectEmits, TreeSelectExposed, TreeSelectProps, UploaderEmits, UploaderExposed, UploaderProps, VariableItem, WatermarkEmits, WatermarkExposed, WatermarkProps, _ActionExposed, _ActionGroupExposed, _AnimationExposed, _AutoCompleteExposed, _BadgeExposed, _BatchEditExposed, _BreadcrumbExposed, _ButtonExposed, _CalendarExposed, _CardExposed, _CascadeExposed, _CheckTagExposed, _CodeEditorExposed, _ConditionEditorExposed, _ContextmenuExposed, _CssTransitionExposed, _DatePickerExposed, _DateRangePickerExposed, _DialogExposed, _DrawerExposed, _DropdownExposed, _DualNavExposed, _EmptyExposed, _ExpressionEditorExposed, _FileViewerExposed, _FloatButtonExposed, _FormExposed, _GanttChartExposed, _GridExposed, _GridInputExposed, _GroupInputExposed, _ImageCropperExposed, _InputExposed, _LayoutExposed, _ListExposed, _LoadingExposed, _MessageConfirmExposed, _MessageExposed, _MultiAutoCompleteExposed, _MultiSelectExposed, _MultiTreeSelectExposed, _NavExposed, _NotificationExposed, _PaginatorExposed, _PaletteExposed, _PasswordInputExposed, _PopConfirmExposed, _PopExposed, _ProgressExposed, _ProgressNodesExposed, _QuickBatchEditExposed, _RadioExposed, _RadioGroupExposed, _RichTextEditorExposed, _ScrollExposed, _SegmentExposed, _SelectExposed, _SliderExposed, _StepsExposed, _SwitchExposed, _TableEditorExposed, _TableExposed, _TabsExposed, _TabsHorizontalExposed, _TabsVerticalExposed, _TextEditorExposed, _TextExposed, _TextareaExposed, _ThemeExposed, _TipExposed, _TreeExposed, _TreeSelectExposed, _UploaderExposed, _WatermarkExposed };
|
package/package.json
CHANGED
|
@@ -107,6 +107,10 @@ function queryRows(host: HTMLElement) {
|
|
|
107
107
|
return [...host.querySelectorAll<HTMLElement>('tr.u-table__row')]
|
|
108
108
|
}
|
|
109
109
|
|
|
110
|
+
function queryEditButton(host: HTMLElement, index: number) {
|
|
111
|
+
return queryRows(host)[index]?.querySelector<HTMLElement>('button[title="编辑"]')
|
|
112
|
+
}
|
|
113
|
+
|
|
110
114
|
async function clickRow(host: HTMLElement, index: number) {
|
|
111
115
|
const row = queryRows(host)[index]
|
|
112
116
|
expect(row, `第 ${index} 行应存在`).toBeTruthy()
|
|
@@ -115,19 +119,27 @@ async function clickRow(host: HTMLElement, index: number) {
|
|
|
115
119
|
await nextTick()
|
|
116
120
|
}
|
|
117
121
|
|
|
122
|
+
async function clickEditRow(host: HTMLElement, index: number) {
|
|
123
|
+
const btn = queryEditButton(host, index)
|
|
124
|
+
expect(btn, `第 ${index} 行的编辑按钮应存在`).toBeTruthy()
|
|
125
|
+
btn!.dispatchEvent(new MouseEvent('click', { bubbles: true, cancelable: true }))
|
|
126
|
+
await nextTick()
|
|
127
|
+
await nextTick()
|
|
128
|
+
}
|
|
129
|
+
|
|
118
130
|
describe('UBatchEdit quick-edit 切换编辑行', () => {
|
|
119
131
|
it('切换行时先重置表单再回显,不污染行数据', async () => {
|
|
120
132
|
const { host, data, model, unmount } = mountBatchEdit()
|
|
121
133
|
|
|
122
|
-
// 第一次点击第 1
|
|
123
|
-
await
|
|
134
|
+
// 第一次点击第 1 行的编辑按钮:正常回显
|
|
135
|
+
await clickEditRow(host, 0)
|
|
124
136
|
expect(model.label).toBe('存草稿')
|
|
125
137
|
expect(model.behavior).toBe('common-resource')
|
|
126
138
|
expect(model.submitType).toBe('DRAFT')
|
|
127
139
|
expect(model.apiMethod).toBeUndefined()
|
|
128
140
|
|
|
129
|
-
// 再点击第 2
|
|
130
|
-
await
|
|
141
|
+
// 再点击第 2 行的编辑按钮:先重置回 model 初始快照,再回显第 2 行数据
|
|
142
|
+
await clickEditRow(host, 1)
|
|
131
143
|
expect(model.label).toBe('调接口')
|
|
132
144
|
expect(model.behavior).toBe('api')
|
|
133
145
|
expect(model.submitType).toBe('SUBMIT')
|
|
@@ -142,14 +154,32 @@ describe('UBatchEdit quick-edit 切换编辑行', () => {
|
|
|
142
154
|
unmount()
|
|
143
155
|
})
|
|
144
156
|
|
|
145
|
-
it('
|
|
157
|
+
it('点击行不触发编辑,仅编辑按钮打开表单', async () => {
|
|
158
|
+
const { host, model, unmount } = mountBatchEdit()
|
|
159
|
+
|
|
160
|
+
await clickRow(host, 0)
|
|
161
|
+
|
|
162
|
+
const aside = host.querySelector<HTMLElement>('.u-batch-edit__form')!
|
|
163
|
+
expect(aside.style.display).toBe('none')
|
|
164
|
+
expect(model.label).toBe('')
|
|
165
|
+
|
|
166
|
+
await clickEditRow(host, 0)
|
|
167
|
+
expect(aside.style.display).not.toBe('none')
|
|
168
|
+
expect(model.label).toBe('存草稿')
|
|
169
|
+
|
|
170
|
+
unmount()
|
|
171
|
+
})
|
|
172
|
+
|
|
173
|
+
it('关闭表单后表单数据重置为 model 初始值', async () => {
|
|
146
174
|
const { host, data, model, unmount } = mountBatchEdit()
|
|
147
175
|
|
|
148
|
-
await
|
|
176
|
+
await clickEditRow(host, 1)
|
|
149
177
|
expect(model.label).toBe('调接口')
|
|
150
178
|
|
|
151
|
-
//
|
|
152
|
-
|
|
179
|
+
// 点击「取消」关闭表单,model 恢复到初始快照
|
|
180
|
+
clickEl(queryCancelButton(host)!)
|
|
181
|
+
await nextTick()
|
|
182
|
+
await nextTick()
|
|
153
183
|
expect(model.label).toBe('')
|
|
154
184
|
expect(model.behavior).toBe('event')
|
|
155
185
|
expect(model.submitType).toBeUndefined()
|
|
@@ -169,16 +199,16 @@ describe('UBatchEdit quick-edit 切换编辑行', () => {
|
|
|
169
199
|
it('表单常驻挂载(v-show 控制显隐),切换行不重建表单', async () => {
|
|
170
200
|
const { host, unmount } = mountBatchEdit()
|
|
171
201
|
|
|
172
|
-
// model
|
|
202
|
+
// model 存在即挂载表单,未编辑行时仅隐藏(快照只在首次挂载时拍一次)
|
|
173
203
|
const aside = host.querySelector<HTMLElement>('.u-batch-edit__form')
|
|
174
204
|
expect(aside).toBeTruthy()
|
|
175
205
|
expect(aside!.style.display).toBe('none')
|
|
176
206
|
|
|
177
|
-
await
|
|
207
|
+
await clickEditRow(host, 0)
|
|
178
208
|
const formBody = host.querySelector('.u-batch-edit__form-body')
|
|
179
209
|
expect(aside!.style.display).not.toBe('none')
|
|
180
210
|
|
|
181
|
-
await
|
|
211
|
+
await clickEditRow(host, 1)
|
|
182
212
|
// 同一 DOM 节点:表单未因切行销毁重建,初始快照不会被重新生成
|
|
183
213
|
expect(host.querySelector('.u-batch-edit__form-body')).toBe(formBody)
|
|
184
214
|
|
|
@@ -188,7 +218,7 @@ describe('UBatchEdit quick-edit 切换编辑行', () => {
|
|
|
188
218
|
it('quick-edit 下用户输入仍实时写回行数据', async () => {
|
|
189
219
|
const { host, data, unmount } = mountBatchEdit()
|
|
190
220
|
|
|
191
|
-
await
|
|
221
|
+
await clickEditRow(host, 0)
|
|
192
222
|
|
|
193
223
|
const input = host.querySelector<HTMLInputElement>('.u-input input')
|
|
194
224
|
expect(input).toBeTruthy()
|
|
@@ -205,18 +235,71 @@ describe('UBatchEdit quick-edit 切换编辑行', () => {
|
|
|
205
235
|
})
|
|
206
236
|
})
|
|
207
237
|
|
|
238
|
+
describe('UBatchEdit 操作列', () => {
|
|
239
|
+
it('按钮顺序:编辑在最前,上/下插入在最后', async () => {
|
|
240
|
+
const { host, unmount } = mountBatchEdit({ props: { tree: true } })
|
|
241
|
+
await nextTick()
|
|
242
|
+
|
|
243
|
+
const titles = [...queryRows(host)[0]!.querySelectorAll<HTMLElement>('button[title]')].map(
|
|
244
|
+
(btn) => btn.title
|
|
245
|
+
)
|
|
246
|
+
expect(titles).toEqual(['编辑', '添加子级', '删除', '在上方插入', '在下方插入'])
|
|
247
|
+
|
|
248
|
+
unmount()
|
|
249
|
+
})
|
|
250
|
+
|
|
251
|
+
it('readonly 模式操作列只保留「查看」按钮,点击打开只读表单', async () => {
|
|
252
|
+
const { host, unmount } = mountBatchEdit({ props: { readonly: true } })
|
|
253
|
+
await nextTick()
|
|
254
|
+
|
|
255
|
+
const row = queryRows(host)[0]!
|
|
256
|
+
const viewBtn = row.querySelector<HTMLElement>('button[title="查看"]')
|
|
257
|
+
expect(viewBtn).toBeTruthy()
|
|
258
|
+
expect(row.querySelector('button[title="删除"]')).toBeNull()
|
|
259
|
+
expect(row.querySelector('button[title="在上方插入"]')).toBeNull()
|
|
260
|
+
expect(host.querySelector('.u-batch-edit__add-btn')).toBeNull()
|
|
261
|
+
|
|
262
|
+
viewBtn!.dispatchEvent(new MouseEvent('click', { bubbles: true, cancelable: true }))
|
|
263
|
+
await nextTick()
|
|
264
|
+
await nextTick()
|
|
265
|
+
|
|
266
|
+
expect(host.querySelector('.u-batch-edit__form-title-text')!.textContent).toBe('查看详情')
|
|
267
|
+
|
|
268
|
+
unmount()
|
|
269
|
+
})
|
|
270
|
+
})
|
|
271
|
+
|
|
208
272
|
function queryDialog() {
|
|
209
273
|
return document.body.querySelector<HTMLElement>('.u-batch-edit__form-dialog')
|
|
210
274
|
}
|
|
211
275
|
|
|
212
|
-
/** 等弹框(teleport 到 body
|
|
213
|
-
async function
|
|
276
|
+
/** 等弹框(teleport 到 body)打开:进入过渡在 CI 高负载下可能超过固定时长,轮询等待 */
|
|
277
|
+
async function waitDialogOpen() {
|
|
278
|
+
await vi.waitFor(() => {
|
|
279
|
+
expect(queryDialog()).toBeTruthy()
|
|
280
|
+
})
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
/** 等弹框关闭卸载:离开过渡在 CI 高负载下可能超过固定时长,轮询等待 */
|
|
284
|
+
async function waitDialogClosed() {
|
|
285
|
+
await vi.waitFor(() => {
|
|
286
|
+
expect(queryDialog()).toBeNull()
|
|
287
|
+
})
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
/** 等一次校验 / 保存等异步处理落地(固定短等,避免两次点击的 handleSave 重叠) */
|
|
291
|
+
async function waitDialogSettled() {
|
|
214
292
|
await nextTick()
|
|
215
293
|
await nextTick()
|
|
216
294
|
await new Promise((resolve) => setTimeout(resolve, 20))
|
|
217
295
|
await nextTick()
|
|
218
296
|
}
|
|
219
297
|
|
|
298
|
+
/** 当前用例弹框的遮罩(body 上可能残留前序用例未卸载的弹框,必须按当前弹框定位) */
|
|
299
|
+
function currentOverlay() {
|
|
300
|
+
return queryDialog()!.closest<HTMLElement>('.u-dialog__overlay')!
|
|
301
|
+
}
|
|
302
|
+
|
|
220
303
|
function clickEl(el: HTMLElement) {
|
|
221
304
|
el.dispatchEvent(new MouseEvent('click', { bubbles: true, cancelable: true }))
|
|
222
305
|
}
|
|
@@ -232,8 +315,8 @@ function querySaveButton(dialog: HTMLElement) {
|
|
|
232
315
|
return dialog.querySelector<HTMLElement>('.u-batch-edit__form-actions button[title="保存"]')
|
|
233
316
|
}
|
|
234
317
|
|
|
235
|
-
function queryCancelButton(
|
|
236
|
-
return [...
|
|
318
|
+
function queryCancelButton(container: HTMLElement) {
|
|
319
|
+
return [...container.querySelectorAll<HTMLElement>('.u-batch-edit__form-actions button')].find(
|
|
237
320
|
(btn) => btn.textContent?.includes('取消')
|
|
238
321
|
)
|
|
239
322
|
}
|
|
@@ -242,7 +325,7 @@ describe('UBatchEdit formMode', () => {
|
|
|
242
325
|
it('默认(不传 formMode)仍渲染右侧面板,不出现弹框', async () => {
|
|
243
326
|
const { host, unmount } = mountBatchEdit()
|
|
244
327
|
|
|
245
|
-
await
|
|
328
|
+
await clickEditRow(host, 0)
|
|
246
329
|
const aside = host.querySelector<HTMLElement>('.u-batch-edit__form')
|
|
247
330
|
expect(aside).toBeTruthy()
|
|
248
331
|
expect(aside!.style.display).not.toBe('none')
|
|
@@ -259,8 +342,8 @@ describe('UBatchEdit formMode', () => {
|
|
|
259
342
|
expect(host.querySelector('.u-batch-edit__form')).toBeNull()
|
|
260
343
|
expect(queryDialog()).toBeNull()
|
|
261
344
|
|
|
262
|
-
await
|
|
263
|
-
await
|
|
345
|
+
await clickEditRow(host, 0)
|
|
346
|
+
await waitDialogOpen()
|
|
264
347
|
|
|
265
348
|
const dialog = queryDialog()
|
|
266
349
|
expect(dialog).toBeTruthy()
|
|
@@ -285,12 +368,11 @@ describe('UBatchEdit formMode', () => {
|
|
|
285
368
|
|
|
286
369
|
// 打开新增弹框
|
|
287
370
|
clickEl(host.querySelector<HTMLElement>('.u-batch-edit__add-btn')!)
|
|
288
|
-
await
|
|
289
|
-
expect(queryDialog()).toBeTruthy()
|
|
371
|
+
await waitDialogOpen()
|
|
290
372
|
|
|
291
373
|
// 必填校验失败:不调用 saveMethod,弹框保持打开
|
|
292
374
|
clickEl(querySaveButton(queryDialog()!)!)
|
|
293
|
-
await
|
|
375
|
+
await waitDialogSettled()
|
|
294
376
|
expect(saveMethod).not.toHaveBeenCalled()
|
|
295
377
|
expect(queryDialog()).toBeTruthy()
|
|
296
378
|
|
|
@@ -299,14 +381,13 @@ describe('UBatchEdit formMode', () => {
|
|
|
299
381
|
await nextTick()
|
|
300
382
|
await nextTick()
|
|
301
383
|
clickEl(querySaveButton(queryDialog()!)!)
|
|
302
|
-
await
|
|
384
|
+
await waitDialogClosed()
|
|
303
385
|
|
|
304
386
|
expect(saveMethod).toHaveBeenCalledTimes(1)
|
|
305
387
|
expect(saveMethod.mock.calls[0]![0]).toMatchObject({ label: '新名称' })
|
|
306
388
|
expect(saveMethod.mock.calls[0]![1]).toBe('create')
|
|
307
389
|
expect(data.value).toHaveLength(3)
|
|
308
390
|
expect(data.value[2]).toMatchObject({ label: '新名称' })
|
|
309
|
-
expect(queryDialog()).toBeNull()
|
|
310
391
|
|
|
311
392
|
unmount()
|
|
312
393
|
})
|
|
@@ -318,24 +399,23 @@ describe('UBatchEdit formMode', () => {
|
|
|
318
399
|
})
|
|
319
400
|
|
|
320
401
|
// 编辑第 1 行后取消
|
|
321
|
-
await
|
|
322
|
-
await
|
|
402
|
+
await clickEditRow(host, 0)
|
|
403
|
+
await waitDialogOpen()
|
|
323
404
|
setInputValue(queryDialog()!.querySelector<HTMLInputElement>('.u-input input')!, '改过的名称')
|
|
324
405
|
await nextTick()
|
|
325
406
|
await nextTick()
|
|
326
407
|
clickEl(queryCancelButton(queryDialog()!)!)
|
|
327
|
-
await
|
|
408
|
+
await waitDialogClosed()
|
|
328
409
|
|
|
329
410
|
expect(saveMethod).not.toHaveBeenCalled()
|
|
330
411
|
expect(data.value[0]).toMatchObject({ label: '存草稿' })
|
|
331
412
|
// model 恢复初始快照,而不是残留上一行数据
|
|
332
413
|
expect(model.label).toBe('')
|
|
333
414
|
expect(model.submitType).toBeUndefined()
|
|
334
|
-
expect(queryDialog()).toBeNull()
|
|
335
415
|
|
|
336
416
|
// 取消后再新增:表单应为初始值(快照不被上一行污染)
|
|
337
417
|
clickEl(host.querySelector<HTMLElement>('.u-batch-edit__add-btn')!)
|
|
338
|
-
await
|
|
418
|
+
await waitDialogOpen()
|
|
339
419
|
expect(queryDialog()!.querySelector<HTMLInputElement>('.u-input input')!.value).toBe('')
|
|
340
420
|
|
|
341
421
|
// 表单头部的关闭按钮同样不保存
|
|
@@ -343,27 +423,73 @@ describe('UBatchEdit formMode', () => {
|
|
|
343
423
|
await nextTick()
|
|
344
424
|
await nextTick()
|
|
345
425
|
clickEl(queryDialog()!.querySelector<HTMLElement>('.u-batch-edit__form-close')!)
|
|
346
|
-
await
|
|
426
|
+
await waitDialogClosed()
|
|
347
427
|
expect(saveMethod).not.toHaveBeenCalled()
|
|
348
428
|
expect(model.label).toBe('')
|
|
349
429
|
expect(data.value).toHaveLength(2)
|
|
350
|
-
expect(queryDialog()).toBeNull()
|
|
351
430
|
|
|
352
431
|
// 弹框自身关闭交互(点击遮罩)也不保存
|
|
353
|
-
await
|
|
354
|
-
await
|
|
432
|
+
await clickEditRow(host, 1)
|
|
433
|
+
await waitDialogOpen()
|
|
355
434
|
setInputValue(queryDialog()!.querySelector<HTMLInputElement>('.u-input input')!, '改过的名称')
|
|
356
435
|
await nextTick()
|
|
357
436
|
await nextTick()
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
.dispatchEvent(new MouseEvent('mousedown', { bubbles: true, cancelable: true }))
|
|
361
|
-
await flushDialog()
|
|
437
|
+
currentOverlay().dispatchEvent(new MouseEvent('mousedown', { bubbles: true, cancelable: true }))
|
|
438
|
+
await waitDialogClosed()
|
|
362
439
|
|
|
363
440
|
expect(saveMethod).not.toHaveBeenCalled()
|
|
364
441
|
expect(data.value[1]).toMatchObject({ label: '调接口' })
|
|
365
442
|
expect(model.label).toBe('')
|
|
366
|
-
|
|
443
|
+
|
|
444
|
+
unmount()
|
|
445
|
+
})
|
|
446
|
+
})
|
|
447
|
+
|
|
448
|
+
describe('UBatchEdit 重入保护', () => {
|
|
449
|
+
it('保存进行中重复触发(快捷键/连点)被忽略:saveMethod 只调一次、只插一行、弹框正常关闭', async () => {
|
|
450
|
+
const saveMethod = vi.fn()
|
|
451
|
+
const { host, data, unmount } = mountBatchEdit({
|
|
452
|
+
props: { formMode: 'dialog', quickEdit: false, saveMethod },
|
|
453
|
+
labelRules: { required: true }
|
|
454
|
+
})
|
|
455
|
+
|
|
456
|
+
clickEl(host.querySelector<HTMLElement>('.u-batch-edit__add-btn')!)
|
|
457
|
+
await waitDialogOpen()
|
|
458
|
+
|
|
459
|
+
setInputValue(queryDialog()!.querySelector<HTMLInputElement>('.u-input input')!, '新名称')
|
|
460
|
+
await nextTick()
|
|
461
|
+
await nextTick()
|
|
462
|
+
|
|
463
|
+
// 同一 tick 内连续两次触发保存(模拟保存进行中再按 Ctrl/Cmd+S),中间故意不等待
|
|
464
|
+
const saveBtn = querySaveButton(queryDialog()!)!
|
|
465
|
+
clickEl(saveBtn)
|
|
466
|
+
clickEl(saveBtn)
|
|
467
|
+
|
|
468
|
+
await waitDialogClosed()
|
|
469
|
+
|
|
470
|
+
expect(saveMethod).toHaveBeenCalledTimes(1)
|
|
471
|
+
expect(data.value).toHaveLength(3)
|
|
472
|
+
expect(data.value[2]).toMatchObject({ label: '新名称' })
|
|
473
|
+
|
|
474
|
+
unmount()
|
|
475
|
+
})
|
|
476
|
+
|
|
477
|
+
it('删除进行中重复触发被忽略:deleteMethod 只调一次、只删一行', async () => {
|
|
478
|
+
const deleteMethod = vi.fn()
|
|
479
|
+
const { host, data, unmount } = mountBatchEdit({ props: { deleteMethod } })
|
|
480
|
+
await nextTick()
|
|
481
|
+
|
|
482
|
+
// 同一 tick 内连续两次点击删除,中间故意不等待
|
|
483
|
+
const deleteBtn = queryRows(host)[0]!.querySelector<HTMLElement>('button[title="删除"]')!
|
|
484
|
+
clickEl(deleteBtn)
|
|
485
|
+
clickEl(deleteBtn)
|
|
486
|
+
|
|
487
|
+
await waitDialogSettled()
|
|
488
|
+
|
|
489
|
+
expect(deleteMethod).toHaveBeenCalledTimes(1)
|
|
490
|
+
expect(deleteMethod.mock.calls[0]![0]).toHaveLength(1)
|
|
491
|
+
expect(data.value).toHaveLength(1)
|
|
492
|
+
expect(data.value[0]).toMatchObject({ id: '2' })
|
|
367
493
|
|
|
368
494
|
unmount()
|
|
369
495
|
})
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
v-show="state.formVisible"
|
|
8
8
|
>
|
|
9
9
|
<header :class="cls.e('form-header')">
|
|
10
|
-
<span :class="[cls.e('form-icon'),
|
|
10
|
+
<span :class="[cls.e('form-icon'), iconToneCls]">
|
|
11
11
|
<u-icon>
|
|
12
12
|
<component :is="headerInfo.icon" />
|
|
13
13
|
</u-icon>
|
|
@@ -152,4 +152,10 @@ const showSaveBtn = computed(() => {
|
|
|
152
152
|
})
|
|
153
153
|
|
|
154
154
|
const headerInfo = computed(() => FORM_ACTION_HEADER_MAP[state.formActionType])
|
|
155
|
+
|
|
156
|
+
/** 头部图标色调修饰类:样式中 createChild 对应的修饰类为 is-child */
|
|
157
|
+
const iconToneCls = computed(() => {
|
|
158
|
+
const type = state.formActionType
|
|
159
|
+
return bem.is(type === 'createChild' ? 'child' : type)
|
|
160
|
+
})
|
|
155
161
|
</script>
|
|
@@ -4,28 +4,21 @@
|
|
|
4
4
|
:slots="slots"
|
|
5
5
|
:class="[cls.e('table')]"
|
|
6
6
|
:columns="columns"
|
|
7
|
-
highlight-current
|
|
8
7
|
:current="state.row"
|
|
9
|
-
@update:current="handleUpdateCurrentRow"
|
|
10
8
|
@update:checked="emit('update:checked', $event)"
|
|
11
9
|
@update:selected="emit('update:selected', $event)"
|
|
12
10
|
>
|
|
13
11
|
<template #column:__action__="{ row }">
|
|
14
|
-
<u-action-group :
|
|
12
|
+
<u-action-group :max="5" circle>
|
|
15
13
|
<u-action
|
|
16
|
-
v-if="allowed('
|
|
17
|
-
:icon="
|
|
18
|
-
title="
|
|
19
|
-
@run="
|
|
20
|
-
|
|
21
|
-
<u-action
|
|
22
|
-
v-if="allowed('create', row)"
|
|
23
|
-
:icon="InsertToNext"
|
|
24
|
-
title="在下方插入"
|
|
25
|
-
@run="handleInsertToNext(row)"
|
|
14
|
+
v-if="allowed('update', row)"
|
|
15
|
+
:icon="props.readonly ? View : EditPen"
|
|
16
|
+
:title="props.readonly ? '查看' : '编辑'"
|
|
17
|
+
@run="startEdit(row)"
|
|
18
|
+
v-bind="props.actionsProps?.update"
|
|
26
19
|
/>
|
|
27
20
|
<u-action
|
|
28
|
-
v-if="!!props.tree && allowed('createChild', row)"
|
|
21
|
+
v-if="!props.readonly && !!props.tree && allowed('createChild', row)"
|
|
29
22
|
:icon="AddChild"
|
|
30
23
|
title="添加子级"
|
|
31
24
|
@run="handleInsertChild(row)"
|
|
@@ -38,6 +31,18 @@
|
|
|
38
31
|
@run="handleDelete(row)"
|
|
39
32
|
v-bind="props.actionsProps?.delete"
|
|
40
33
|
/>
|
|
34
|
+
<u-action
|
|
35
|
+
v-if="!props.readonly && allowed('create', row)"
|
|
36
|
+
:icon="InsertToPrev"
|
|
37
|
+
title="在上方插入"
|
|
38
|
+
@run="handleInsertToPrev(row)"
|
|
39
|
+
/>
|
|
40
|
+
<u-action
|
|
41
|
+
v-if="!props.readonly && allowed('create', row)"
|
|
42
|
+
:icon="InsertToNext"
|
|
43
|
+
title="在下方插入"
|
|
44
|
+
@run="handleInsertToNext(row)"
|
|
45
|
+
/>
|
|
41
46
|
</u-action-group>
|
|
42
47
|
</template>
|
|
43
48
|
|
|
@@ -61,7 +66,15 @@
|
|
|
61
66
|
|
|
62
67
|
<script setup lang="ts">
|
|
63
68
|
import { o } from '@cat-kit/core'
|
|
64
|
-
import {
|
|
69
|
+
import {
|
|
70
|
+
AddChild,
|
|
71
|
+
Delete,
|
|
72
|
+
EditPen,
|
|
73
|
+
InsertToNext,
|
|
74
|
+
InsertToPrev,
|
|
75
|
+
Plus,
|
|
76
|
+
View
|
|
77
|
+
} from '@veltra/icons/normal'
|
|
65
78
|
import { computed, inject, type Slots } from 'vue'
|
|
66
79
|
|
|
67
80
|
import type { BatchEditFeature, TableRow } from '../../types'
|
|
@@ -81,6 +94,7 @@ const {
|
|
|
81
94
|
emit,
|
|
82
95
|
staticFeatures,
|
|
83
96
|
dynamicFeatures,
|
|
97
|
+
startEdit,
|
|
84
98
|
handleCreate,
|
|
85
99
|
handleDelete,
|
|
86
100
|
handleInsertToNext,
|
|
@@ -97,9 +111,11 @@ const tableProps = computed(() => {
|
|
|
97
111
|
'deleteMethod',
|
|
98
112
|
'saveMethod',
|
|
99
113
|
'features',
|
|
100
|
-
'mode',
|
|
101
114
|
'beforeCreate',
|
|
102
|
-
'formMode'
|
|
115
|
+
'formMode',
|
|
116
|
+
'quickEdit',
|
|
117
|
+
'labelWidth',
|
|
118
|
+
'actionsProps'
|
|
103
119
|
])
|
|
104
120
|
})
|
|
105
121
|
|
|
@@ -110,7 +126,11 @@ const allowed = (feature: BatchEditFeature, row?: TableRow) => {
|
|
|
110
126
|
}
|
|
111
127
|
|
|
112
128
|
const columns = computed(() => {
|
|
113
|
-
|
|
129
|
+
// 只读模式的操作列只保留「查看」入口
|
|
130
|
+
const related: BatchEditFeature[] = props.readonly
|
|
131
|
+
? ['update']
|
|
132
|
+
: ['create', 'delete', 'createChild', 'update']
|
|
133
|
+
if (hasNot(related)) return props.columns
|
|
114
134
|
|
|
115
135
|
return (props.columns ?? []).concat({
|
|
116
136
|
name: '操作',
|
|
@@ -122,12 +142,6 @@ const columns = computed(() => {
|
|
|
122
142
|
})
|
|
123
143
|
})
|
|
124
144
|
|
|
125
|
-
function handleUpdateCurrentRow(row?: TableRow) {
|
|
126
|
-
if (allowed('update', row)) {
|
|
127
|
-
state.row = row
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
|
|
131
145
|
function canDelete(row: TableRow) {
|
|
132
146
|
return !props.readonly && allowed('delete', row)
|
|
133
147
|
}
|
|
@@ -64,7 +64,7 @@ const cls = bem('batch-edit')
|
|
|
64
64
|
|
|
65
65
|
const formRef = useTemplateRef<FormExposed>('form')
|
|
66
66
|
|
|
67
|
-
const { state, resetState, syncing } = useEditState({ props, formRef })
|
|
67
|
+
const { state, resetState, startEdit, syncing } = useEditState({ props, formRef })
|
|
68
68
|
|
|
69
69
|
const { staticFeatures, dynamicFeatures } = useFeatures({ props })
|
|
70
70
|
|
|
@@ -91,6 +91,7 @@ provide(BatchEditDIKey, {
|
|
|
91
91
|
dynamicFeatures,
|
|
92
92
|
focused,
|
|
93
93
|
syncing,
|
|
94
|
+
startEdit,
|
|
94
95
|
...handlers
|
|
95
96
|
})
|
|
96
97
|
</script>
|
|
@@ -24,5 +24,7 @@ export const BatchEditDIKey: InjectionKey<
|
|
|
24
24
|
focused: ShallowRef<boolean>
|
|
25
25
|
/** 是否正在以编程方式重置/回显表单,此期间禁止 quick-edit 回写行数据 */
|
|
26
26
|
syncing: ShallowRef<boolean>
|
|
27
|
+
/** 开始编辑/查看一行(操作列「编辑」按钮触发) */
|
|
28
|
+
startEdit: (row: TableRow) => void
|
|
27
29
|
} & EditReturned
|
|
28
30
|
> = Symbol('BatchEditDIKey')
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { copy, o } from '@cat-kit/core'
|
|
2
2
|
import { nextTick, shallowReactive, shallowRef, watch, type ShallowRef } from 'vue'
|
|
3
3
|
|
|
4
|
-
import type { BatchEditProps, BatchEditStates, FormExposed } from '../../types'
|
|
4
|
+
import type { BatchEditProps, BatchEditStates, FormExposed, TableRow } from '../../types'
|
|
5
5
|
|
|
6
6
|
interface Options {
|
|
7
7
|
props: BatchEditProps
|
|
@@ -56,10 +56,6 @@ export function useEditState(options: Options) {
|
|
|
56
56
|
function resetState() {
|
|
57
57
|
resetModel()
|
|
58
58
|
|
|
59
|
-
if (state.row) {
|
|
60
|
-
state.row.isCurrent = false
|
|
61
|
-
}
|
|
62
|
-
|
|
63
59
|
Object.keys(state).forEach((key) => {
|
|
64
60
|
delete state[key]
|
|
65
61
|
})
|
|
@@ -67,33 +63,30 @@ export function useEditState(options: Options) {
|
|
|
67
63
|
Object.assign(state, defaultState)
|
|
68
64
|
}
|
|
69
65
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
o(props.model).deepExtend(row.data)
|
|
83
|
-
}
|
|
84
|
-
state.formActionType = props.readonly ? 'view' : 'update'
|
|
85
|
-
state.formVisible = true
|
|
86
|
-
state.depth = row.depth
|
|
87
|
-
state.indexPath = [...row.indexes]
|
|
88
|
-
} else {
|
|
89
|
-
resetState()
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
nextTick(() => {
|
|
93
|
-
syncing.value = false
|
|
94
|
-
})
|
|
66
|
+
/**
|
|
67
|
+
* 开始编辑/查看一行:先重置回 model 初始快照,再回显行数据。
|
|
68
|
+
* 同一 tick 内的连续写入会被表单字段 watcher 合并,
|
|
69
|
+
* 重置产生的默认值不会触发 field:update 回写行数据
|
|
70
|
+
*/
|
|
71
|
+
function startEdit(row: TableRow) {
|
|
72
|
+
syncing.value = true
|
|
73
|
+
|
|
74
|
+
resetModel()
|
|
75
|
+
|
|
76
|
+
if (props.model) {
|
|
77
|
+
o(props.model).deepExtend(row.data)
|
|
95
78
|
}
|
|
96
|
-
)
|
|
97
79
|
|
|
98
|
-
|
|
80
|
+
state.row = row
|
|
81
|
+
state.formActionType = props.readonly ? 'view' : 'update'
|
|
82
|
+
state.formVisible = true
|
|
83
|
+
state.depth = row.depth
|
|
84
|
+
state.indexPath = [...row.indexes]
|
|
85
|
+
|
|
86
|
+
nextTick(() => {
|
|
87
|
+
syncing.value = false
|
|
88
|
+
})
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return { state, resetState, startEdit, syncing }
|
|
99
92
|
}
|
|
@@ -135,6 +135,8 @@ export function useHandlers(options: Options): EditReturned {
|
|
|
135
135
|
|
|
136
136
|
function runWithLoading<Arg extends any[]>(fn: (...args: Arg) => Promise<void> | void) {
|
|
137
137
|
return async (...args: Arg) => {
|
|
138
|
+
// 重入保护:进行中(快捷键/按钮并发触发)直接忽略
|
|
139
|
+
if (state.loading) return
|
|
138
140
|
state.loading = true
|
|
139
141
|
if (state.row) {
|
|
140
142
|
state.row.operating = true
|
package/src/types/batch-edit.ts
CHANGED
|
@@ -8,8 +8,6 @@ export interface BatchEditColumn extends TableColumn {}
|
|
|
8
8
|
|
|
9
9
|
export type BatchEditFeature = 'create' | 'update' | 'delete' | 'view' | 'createChild'
|
|
10
10
|
|
|
11
|
-
export type BatchEditFormStatus = 'hidden'
|
|
12
|
-
|
|
13
11
|
/** 批量编辑状态 */
|
|
14
12
|
export interface BatchEditStates {
|
|
15
13
|
/** 层级 */
|
|
@@ -35,8 +33,6 @@ export interface BatchEditProps extends TableProps {
|
|
|
35
33
|
* @description 与右侧 UForm 绑定的 reactive 对象
|
|
36
34
|
*/
|
|
37
35
|
model?: Record<string, any>
|
|
38
|
-
/** 表格标题 */
|
|
39
|
-
title?: string
|
|
40
36
|
/**
|
|
41
37
|
* 列的宽度定义
|
|
42
38
|
*/
|