@veltra/desktop 1.2.7 → 1.2.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. package/dist/components/action/action-group.vue.d.ts +2 -2
  2. package/dist/components/action/action.vue.d.ts +1 -1
  3. package/dist/components/auto-complete/auto-complete.vue.d.ts +2 -2
  4. package/dist/components/batch-edit/batch-edit-form.js +41 -79
  5. package/dist/components/batch-edit/batch-edit-form.js.map +1 -1
  6. package/dist/components/batch-edit/batch-edit-list.js +17 -29
  7. package/dist/components/batch-edit/batch-edit-list.js.map +1 -1
  8. package/dist/components/batch-edit/batch-edit.js +34 -60
  9. package/dist/components/batch-edit/batch-edit.js.map +1 -1
  10. package/dist/components/batch-edit/batch-edit.vue.d.ts +3 -14
  11. package/dist/components/batch-edit/di.js.map +1 -1
  12. package/dist/components/batch-edit/form-action-header.js +25 -0
  13. package/dist/components/batch-edit/form-action-header.js.map +1 -0
  14. package/dist/components/batch-edit/style2.css +0 -13
  15. package/dist/components/batch-edit/use-edit-state.js +40 -0
  16. package/dist/components/batch-edit/use-edit-state.js.map +1 -0
  17. package/dist/components/batch-edit/use-handlers.js +146 -0
  18. package/dist/components/batch-edit/use-handlers.js.map +1 -0
  19. package/dist/components/batch-edit/use-shortcut-key.js +44 -0
  20. package/dist/components/batch-edit/use-shortcut-key.js.map +1 -0
  21. package/dist/components/cascade/cascade.vue.d.ts +4 -4
  22. package/dist/components/checkbox/checkbox-button.vue.d.ts +2 -2
  23. package/dist/components/checkbox/checkbox.vue.d.ts +1 -1
  24. package/dist/components/checkbox-group/checkbox-group.vue.d.ts +2 -2
  25. package/dist/components/code-editor/code-editor.vue.d.ts +1 -1
  26. package/dist/components/date-panel/date-panel.vue.d.ts +1 -1
  27. package/dist/components/date-picker/date-picker.vue.d.ts +2 -2
  28. package/dist/components/date-range-picker/date-range-picker.vue.d.ts +2 -2
  29. package/dist/components/empty/empty.vue.d.ts +1 -1
  30. package/dist/components/file-picker/file-picker.vue.d.ts +1 -1
  31. package/dist/components/form/form.js.map +1 -1
  32. package/dist/components/form/form.vue.d.ts +5 -1
  33. package/dist/components/form/form.vue_vue_type_script_setup_true_lang.js +8 -2
  34. package/dist/components/form/form.vue_vue_type_script_setup_true_lang.js.map +1 -1
  35. package/dist/components/form-item/form-item.js.map +1 -1
  36. package/dist/components/form-item/form-item.vue_vue_type_script_setup_true_lang.js +3 -2
  37. package/dist/components/form-item/form-item.vue_vue_type_script_setup_true_lang.js.map +1 -1
  38. package/dist/components/input/input.vue.d.ts +8 -8
  39. package/dist/components/multi-select/multi-select.vue.d.ts +3 -3
  40. package/dist/components/multi-tree-select/multi-tree-select.vue.d.ts +6 -6
  41. package/dist/components/number-input/number-input.vue.d.ts +4 -4
  42. package/dist/components/number-range-input/number-range-input.vue.d.ts +2 -2
  43. package/dist/components/palette/palette.vue.d.ts +1 -1
  44. package/dist/components/password-input/password-input.vue.d.ts +2 -2
  45. package/dist/components/pop-confirm/pop-confirm.vue.d.ts +1 -1
  46. package/dist/components/progress-nodes/progress-nodes.vue.d.ts +1 -1
  47. package/dist/components/radio-group/radio-group.vue.d.ts +2 -2
  48. package/dist/components/rich-text-editor/rich-text-editor.vue.d.ts +2 -2
  49. package/dist/components/scroll/scroll.vue.d.ts +2 -2
  50. package/dist/components/select/select.vue.d.ts +2 -2
  51. package/dist/components/steps/steps.vue.d.ts +3 -3
  52. package/dist/components/switch/switch.vue.d.ts +1 -1
  53. package/dist/components/tabs/tabs-horizontal.vue.d.ts +2 -2
  54. package/dist/components/tabs/tabs-vertical.vue.d.ts +2 -2
  55. package/dist/components/tabs/tabs.vue.d.ts +2 -2
  56. package/dist/components/textarea/textarea.vue.d.ts +4 -4
  57. package/dist/components/tip/tip.vue.d.ts +1 -1
  58. package/dist/components/tree/tree.vue.d.ts +1 -1
  59. package/dist/components/tree-select/tree-select.vue.d.ts +6 -6
  60. package/dist/index.d.ts +4 -4
  61. package/dist/types/batch-edit.d.ts +38 -12
  62. package/dist/types/form.d.ts +4 -1
  63. package/dist/types/index.d.ts +3 -3
  64. package/package.json +6 -6
  65. package/src/components/batch-edit/batch-edit-form.vue +40 -86
  66. package/src/components/batch-edit/batch-edit-list.vue +13 -29
  67. package/src/components/batch-edit/batch-edit.vue +27 -92
  68. package/src/components/batch-edit/di.ts +6 -5
  69. package/src/components/batch-edit/form-action-header.ts +21 -0
  70. package/src/components/batch-edit/style.scss +0 -14
  71. package/src/components/batch-edit/use-dialog-effect.ts +21 -0
  72. package/src/components/batch-edit/use-edit-state.ts +55 -0
  73. package/src/components/batch-edit/use-handlers.ts +226 -0
  74. package/src/components/batch-edit/use-shortcut-key.ts +58 -0
  75. package/src/components/form/form.vue +10 -3
  76. package/src/components/form-item/form-item.vue +4 -2
  77. package/src/types/batch-edit.ts +43 -22
  78. package/src/types/form.ts +4 -0
  79. package/dist/components/batch-edit/use-edit.js +0 -215
  80. package/dist/components/batch-edit/use-edit.js.map +0 -1
  81. package/src/components/batch-edit/use-edit.ts +0 -343
@@ -1,215 +0,0 @@
1
- import { computed, nextTick, shallowReactive, shallowRef, watch } from "vue";
2
- import { last, o, safeRun } from "@cat-kit/core";
3
- //#region src/components/batch-edit/use-edit.ts
4
- /** 按索引路径在原始数据树中定位节点(等价于历史 Forest.visit 路径访问) */
5
- function visitDataByIndexPath(roots, indexPath, childrenKey) {
6
- if (!indexPath.length) return void 0;
7
- let currentList = roots;
8
- let node;
9
- for (let i = 0; i < indexPath.length; i++) {
10
- const idx = indexPath[i];
11
- if (!currentList) return void 0;
12
- node = currentList[idx];
13
- if (node === void 0) return void 0;
14
- if (i < indexPath.length - 1) {
15
- const next = node[childrenKey];
16
- currentList = Array.isArray(next) ? next : void 0;
17
- }
18
- }
19
- return node;
20
- }
21
- function snapshotData(data) {
22
- return safeRun(() => JSON.parse(JSON.stringify(data ?? {})), {});
23
- }
24
- function replaceModelData(model, data) {
25
- for (const key of Object.keys(model)) delete model[key];
26
- Object.assign(model, data);
27
- }
28
- function useEdit(options) {
29
- const { props, emit, formRef } = options;
30
- /** 组件状态 */
31
- const state = shallowReactive({
32
- depth: void 0,
33
- visible: false,
34
- type: "create",
35
- loading: false
36
- });
37
- const insertIndexes = shallowRef([]);
38
- function snapshotModelData() {
39
- return snapshotData(props.model);
40
- }
41
- function setFormData(formData) {
42
- if (!props.model) return;
43
- replaceModelData(props.model, snapshotData(formData));
44
- }
45
- const isQuickMode = () => props.mode === "quick";
46
- async function runBeforeCreate(data) {
47
- await props.beforeCreate?.(data, state.parentRow?.data);
48
- }
49
- watch(() => state.row, (row) => {
50
- if (row) {
51
- state.type = "update";
52
- state.visible = true;
53
- if (!isQuickMode()) setFormData(row.data);
54
- } else state.visible = false;
55
- }, { flush: "sync" });
56
- const childrenKey = computed(() => {
57
- return typeof props.tree === "string" ? props.tree : "children";
58
- });
59
- /**
60
- * 插入数据
61
- * @param item 数据
62
- */
63
- function insert(item) {
64
- const data = [...props.data ?? []];
65
- const parent = visitDataByIndexPath(data ?? [], insertIndexes.value.slice(0, -1), childrenKey.value);
66
- if (parent) {
67
- const children = parent[childrenKey.value];
68
- if (!children) parent[childrenKey.value] = [item];
69
- else children.splice(last(insertIndexes.value), 0, item);
70
- } else data.splice(last(insertIndexes.value), 0, item);
71
- emit("update:data", data);
72
- return item;
73
- }
74
- function getInsertData() {
75
- return snapshotModelData();
76
- }
77
- async function runCreate(cb, initialData) {
78
- state.parentRow = void 0;
79
- if (state.row) state.row.isCurrent = false;
80
- state.row = void 0;
81
- state.type = "create";
82
- cb();
83
- await nextTick();
84
- setFormData(initialData);
85
- if (isQuickMode() && props.model) await runBeforeCreate(props.model);
86
- state.visible = true;
87
- }
88
- /**
89
- * 点击新增按钮
90
- */
91
- async function handleCreate() {
92
- const { data } = props;
93
- await runCreate(() => {
94
- state.depth = 1;
95
- insertIndexes.value = [data?.length ?? 0];
96
- });
97
- }
98
- async function handleInsertToPrev(row) {
99
- await runCreate(() => {
100
- state.depth = row.depth;
101
- insertIndexes.value = [...row.indexes];
102
- });
103
- }
104
- async function handleInsertToNext(row) {
105
- await runCreate(() => {
106
- state.depth = row.depth;
107
- insertIndexes.value = [...row.indexes.slice(0, -1), row.index + 1];
108
- });
109
- }
110
- async function handleInsertChild(row) {
111
- await runCreate(() => {
112
- state.parentRow = row;
113
- state.depth = row.depth + 1;
114
- row.expanded = true;
115
- insertIndexes.value = [...row.indexes, row.children?.length ?? 0];
116
- });
117
- }
118
- /** 编辑指定行(等同于点击行) */
119
- function handleEdit(row) {
120
- state.type = "update";
121
- state.row = row;
122
- state.depth = row.depth;
123
- }
124
- /** 复制指定行:在其下方以 create 模式打开表单,并预填副本数据 */
125
- async function handleCopy(row) {
126
- await runCreate(() => {
127
- state.depth = row.depth;
128
- insertIndexes.value = [...row.indexes.slice(0, -1), row.index + 1];
129
- }, row.data);
130
- }
131
- function runWithLoading(fn) {
132
- return async (...args) => {
133
- state.loading = true;
134
- if (state.row) state.row.operating = true;
135
- try {
136
- await fn.apply(null, args);
137
- } catch (error) {
138
- console.error(error);
139
- }
140
- state.loading = false;
141
- if (state.row) state.row.operating = false;
142
- };
143
- }
144
- /** 保存 */
145
- const handleSave = runWithLoading(async () => {
146
- const { model, saveMethod } = props;
147
- if (!model) return;
148
- if (isQuickMode() && state.type === "update") return;
149
- formRef.value?.clearValidate();
150
- if (!await formRef.value?.validate()) return;
151
- if (isQuickMode() && state.type === "create") {
152
- insert(getInsertData());
153
- return;
154
- }
155
- let item = getInsertData();
156
- if (state.type === "create") {
157
- await runBeforeCreate(item);
158
- if (saveMethod) {
159
- const result = await saveMethod(item, state.type, state.parentRow?.data);
160
- if (result) item = result;
161
- }
162
- insert(item);
163
- return;
164
- }
165
- if (saveMethod) {
166
- const result = await saveMethod(item, state.type, state.parentRow?.data);
167
- if (result) item = result;
168
- }
169
- const { row } = state;
170
- row && Object.keys(item).forEach((key) => {
171
- o(row.data).set(key, o(item).get(key));
172
- });
173
- });
174
- const handleDelete = runWithLoading(async (row) => {
175
- const { deleteMethod } = props;
176
- if (deleteMethod) await deleteMethod([row.data]);
177
- const data = [...props.data ?? []];
178
- const parent = visitDataByIndexPath(data, row.indexes.slice(0, -1), childrenKey.value);
179
- if (parent) {
180
- const children = parent[childrenKey.value];
181
- if (children) children.splice(row.index, 1);
182
- else console.error("行路径不正确");
183
- } else data.splice(row.index, 1);
184
- if (state.row === row) {
185
- state.row = void 0;
186
- state.depth = void 0;
187
- }
188
- emit("update:data", data);
189
- });
190
- function handleClose() {
191
- state.visible = false;
192
- if (state.row) state.row.isCurrent = false;
193
- state.row = void 0;
194
- state.parentRow = void 0;
195
- state.depth = void 0;
196
- insertIndexes.value = [];
197
- }
198
- return {
199
- state,
200
- insertIndexes,
201
- handleDelete,
202
- handleInsertChild,
203
- handleInsertToNext,
204
- handleInsertToPrev,
205
- handleCreate,
206
- handleEdit,
207
- handleCopy,
208
- handleClose,
209
- handleSave
210
- };
211
- }
212
- //#endregion
213
- export { useEdit };
214
-
215
- //# sourceMappingURL=use-edit.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"use-edit.js","names":[],"sources":["../../../src/components/batch-edit/use-edit.ts"],"sourcesContent":["import { last, o, safeRun } from '@cat-kit/core'\nimport { computed, nextTick, shallowReactive, shallowRef, watch, type ShallowRef } from 'vue'\n\nimport type { TableRow, BatchEditEmits, BatchEditProps } from '../../types'\nimport type { FormExposed } from '../../types/form'\n\n/** 按索引路径在原始数据树中定位节点(等价于历史 Forest.visit 路径访问) */\nfunction visitDataByIndexPath<T extends Record<string, unknown>>(\n roots: T[],\n indexPath: number[],\n childrenKey: string\n): T | undefined {\n if (!indexPath.length) return undefined\n let currentList: T[] | undefined = roots\n let node: T | undefined\n for (let i = 0; i < indexPath.length; i++) {\n const idx = indexPath[i]!\n if (!currentList) return undefined\n node = currentList[idx]\n if (node === undefined) return undefined\n if (i < indexPath.length - 1) {\n const next = node[childrenKey]\n currentList = Array.isArray(next) ? (next as T[]) : undefined\n }\n }\n return node\n}\n\ninterface Options {\n props: BatchEditProps\n emit: BatchEditEmits\n formRef: ShallowRef<FormExposed | undefined>\n}\n\nexport interface BatchEditStates {\n /** 层级 */\n depth?: number\n visible: boolean\n type: 'create' | 'update'\n loading: boolean\n row?: TableRow\n /** 父级,只在添加子级时会有值 */\n parentRow?: TableRow\n}\n\nexport interface EditReturned {\n state: BatchEditStates\n insertIndexes: ShallowRef<number[]>\n handleSave: () => Promise<void>\n handleClose: () => void\n handleCreate: () => Promise<void>\n handleEdit: (row: TableRow) => void\n handleCopy: (row: TableRow) => Promise<void>\n handleDelete: (row: TableRow) => Promise<void>\n handleInsertToNext: (row: TableRow) => Promise<void>\n handleInsertToPrev: (row: TableRow) => Promise<void>\n handleInsertChild: (row: TableRow) => Promise<void>\n}\n\nfunction snapshotData(data?: Record<string, any>) {\n return safeRun(() => JSON.parse(JSON.stringify(data ?? {})), {})\n}\n\nfunction replaceModelData(model: Record<string, any>, data: Record<string, any>) {\n for (const key of Object.keys(model)) {\n delete model[key]\n }\n Object.assign(model, data)\n}\n\nexport function useEdit(options: Options): EditReturned {\n const { props, emit, formRef } = options\n\n /** 组件状态 */\n const state = shallowReactive<BatchEditStates>({\n depth: undefined,\n visible: false,\n type: 'create',\n loading: false\n })\n\n const insertIndexes = shallowRef<number[]>([])\n\n function snapshotModelData() {\n return snapshotData(props.model)\n }\n\n function setFormData(formData?: Record<string, any>) {\n if (!props.model) return\n replaceModelData(props.model, snapshotData(formData))\n }\n\n const isQuickMode = () => props.mode === 'quick'\n\n async function runBeforeCreate(data: Record<string, any>) {\n await props.beforeCreate?.(data, state.parentRow?.data)\n }\n\n watch(\n () => state.row,\n (row) => {\n if (row) {\n state.type = 'update'\n state.visible = true\n if (!isQuickMode()) {\n setFormData(row.data)\n }\n } else {\n state.visible = false\n }\n },\n { flush: 'sync' }\n )\n\n const childrenKey = computed(() => {\n return typeof props.tree === 'string' ? props.tree : 'children'\n })\n\n /**\n * 插入数据\n * @param item 数据\n */\n function insert(item: Record<string, any>) {\n const data = [...(props.data ?? [])]\n\n const parent = visitDataByIndexPath(\n data ?? [],\n insertIndexes.value.slice(0, -1),\n childrenKey.value\n )\n\n if (parent) {\n const children = parent[childrenKey.value]\n if (!children) {\n parent[childrenKey.value] = [item]\n } else {\n children.splice(last(insertIndexes.value), 0, item)\n }\n } else {\n data.splice(last(insertIndexes.value), 0, item)\n }\n\n emit('update:data', data)\n\n return item\n }\n\n function getInsertData(): Record<string, any> {\n return snapshotModelData()\n }\n\n async function runCreate(cb: () => void, initialData?: Record<string, any>) {\n state.parentRow = undefined\n if (state.row) {\n state.row.isCurrent = false\n }\n state.row = undefined\n state.type = 'create'\n cb()\n\n await nextTick()\n\n setFormData(initialData)\n\n if (isQuickMode() && props.model) {\n await runBeforeCreate(props.model)\n }\n\n state.visible = true\n }\n\n /**\n * 点击新增按钮\n */\n async function handleCreate() {\n const { data } = props\n await runCreate(() => {\n state.depth = 1\n insertIndexes.value = [data?.length ?? 0]\n })\n }\n\n async function handleInsertToPrev(row: TableRow) {\n await runCreate(() => {\n state.depth = row.depth\n insertIndexes.value = [...row.indexes]\n })\n }\n\n async function handleInsertToNext(row: TableRow) {\n await runCreate(() => {\n state.depth = row.depth\n insertIndexes.value = [...row.indexes.slice(0, -1), row.index + 1]\n })\n }\n\n async function handleInsertChild(row: TableRow) {\n await runCreate(() => {\n state.parentRow = row\n state.depth = row.depth + 1\n row.expanded = true\n\n insertIndexes.value = [...row.indexes, row.children?.length ?? 0]\n })\n }\n\n /** 编辑指定行(等同于点击行) */\n function handleEdit(row: TableRow) {\n state.type = 'update'\n state.row = row\n state.depth = row.depth\n }\n\n /** 复制指定行:在其下方以 create 模式打开表单,并预填副本数据 */\n async function handleCopy(row: TableRow) {\n await runCreate(() => {\n state.depth = row.depth\n insertIndexes.value = [...row.indexes.slice(0, -1), row.index + 1]\n }, row.data)\n }\n\n function runWithLoading<Arg extends any[]>(fn: (...args: Arg) => Promise<void> | void) {\n return async (...args: Arg) => {\n state.loading = true\n if (state.row) {\n state.row.operating = true\n }\n try {\n await fn.apply(null, args)\n } catch (error) {\n console.error(error)\n }\n state.loading = false\n if (state.row) {\n state.row.operating = false\n }\n }\n }\n\n /** 保存 */\n const handleSave = runWithLoading(async () => {\n const { model, saveMethod } = props\n\n if (!model) return\n\n if (isQuickMode() && state.type === 'update') return\n\n formRef.value?.clearValidate()\n const valid = await formRef.value?.validate()\n\n if (!valid) return\n\n // quick + create:仅校验 + insert\n if (isQuickMode() && state.type === 'create') {\n insert(getInsertData())\n return\n }\n\n let item = getInsertData()\n\n // normal + create:beforeCreate → saveMethod → insert\n if (state.type === 'create') {\n await runBeforeCreate(item)\n if (saveMethod) {\n const result = await saveMethod(item, state.type, state.parentRow?.data)\n if (result) {\n item = result\n }\n }\n insert(item)\n return\n }\n\n // normal + update\n if (saveMethod) {\n const result = await saveMethod(item, state.type, state.parentRow?.data)\n if (result) {\n item = result\n }\n }\n\n const { row } = state\n row &&\n Object.keys(item).forEach((key) => {\n o(row.data).set(key, o(item).get(key))\n })\n })\n\n const handleDelete = runWithLoading(async (row: TableRow) => {\n const { deleteMethod } = props\n\n if (deleteMethod) {\n await deleteMethod([row.data])\n }\n\n const data = [...(props.data ?? [])]\n\n const parent = visitDataByIndexPath(data, row.indexes.slice(0, -1), childrenKey.value)\n\n if (parent) {\n const children = parent[childrenKey.value]\n if (children) {\n children.splice(row.index, 1)\n } else {\n console.error('行路径不正确')\n }\n } else {\n data.splice(row.index, 1)\n }\n\n if (state.row === row) {\n state.row = undefined\n state.depth = undefined\n }\n\n emit('update:data', data)\n })\n\n function handleClose() {\n state.visible = false\n if (state.row) {\n state.row.isCurrent = false\n }\n state.row = undefined\n state.parentRow = undefined\n state.depth = undefined\n insertIndexes.value = []\n }\n\n return {\n state,\n insertIndexes,\n handleDelete,\n handleInsertChild,\n handleInsertToNext,\n handleInsertToPrev,\n handleCreate,\n handleEdit,\n handleCopy,\n handleClose,\n handleSave\n }\n}\n"],"mappings":"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"}
@@ -1,343 +0,0 @@
1
- import { last, o, safeRun } from '@cat-kit/core'
2
- import { computed, nextTick, shallowReactive, shallowRef, watch, type ShallowRef } from 'vue'
3
-
4
- import type { TableRow, BatchEditEmits, BatchEditProps } from '../../types'
5
- import type { FormExposed } from '../../types/form'
6
-
7
- /** 按索引路径在原始数据树中定位节点(等价于历史 Forest.visit 路径访问) */
8
- function visitDataByIndexPath<T extends Record<string, unknown>>(
9
- roots: T[],
10
- indexPath: number[],
11
- childrenKey: string
12
- ): T | undefined {
13
- if (!indexPath.length) return undefined
14
- let currentList: T[] | undefined = roots
15
- let node: T | undefined
16
- for (let i = 0; i < indexPath.length; i++) {
17
- const idx = indexPath[i]!
18
- if (!currentList) return undefined
19
- node = currentList[idx]
20
- if (node === undefined) return undefined
21
- if (i < indexPath.length - 1) {
22
- const next = node[childrenKey]
23
- currentList = Array.isArray(next) ? (next as T[]) : undefined
24
- }
25
- }
26
- return node
27
- }
28
-
29
- interface Options {
30
- props: BatchEditProps
31
- emit: BatchEditEmits
32
- formRef: ShallowRef<FormExposed | undefined>
33
- }
34
-
35
- export interface BatchEditStates {
36
- /** 层级 */
37
- depth?: number
38
- visible: boolean
39
- type: 'create' | 'update'
40
- loading: boolean
41
- row?: TableRow
42
- /** 父级,只在添加子级时会有值 */
43
- parentRow?: TableRow
44
- }
45
-
46
- export interface EditReturned {
47
- state: BatchEditStates
48
- insertIndexes: ShallowRef<number[]>
49
- handleSave: () => Promise<void>
50
- handleClose: () => void
51
- handleCreate: () => Promise<void>
52
- handleEdit: (row: TableRow) => void
53
- handleCopy: (row: TableRow) => Promise<void>
54
- handleDelete: (row: TableRow) => Promise<void>
55
- handleInsertToNext: (row: TableRow) => Promise<void>
56
- handleInsertToPrev: (row: TableRow) => Promise<void>
57
- handleInsertChild: (row: TableRow) => Promise<void>
58
- }
59
-
60
- function snapshotData(data?: Record<string, any>) {
61
- return safeRun(() => JSON.parse(JSON.stringify(data ?? {})), {})
62
- }
63
-
64
- function replaceModelData(model: Record<string, any>, data: Record<string, any>) {
65
- for (const key of Object.keys(model)) {
66
- delete model[key]
67
- }
68
- Object.assign(model, data)
69
- }
70
-
71
- export function useEdit(options: Options): EditReturned {
72
- const { props, emit, formRef } = options
73
-
74
- /** 组件状态 */
75
- const state = shallowReactive<BatchEditStates>({
76
- depth: undefined,
77
- visible: false,
78
- type: 'create',
79
- loading: false
80
- })
81
-
82
- const insertIndexes = shallowRef<number[]>([])
83
-
84
- function snapshotModelData() {
85
- return snapshotData(props.model)
86
- }
87
-
88
- function setFormData(formData?: Record<string, any>) {
89
- if (!props.model) return
90
- replaceModelData(props.model, snapshotData(formData))
91
- }
92
-
93
- const isQuickMode = () => props.mode === 'quick'
94
-
95
- async function runBeforeCreate(data: Record<string, any>) {
96
- await props.beforeCreate?.(data, state.parentRow?.data)
97
- }
98
-
99
- watch(
100
- () => state.row,
101
- (row) => {
102
- if (row) {
103
- state.type = 'update'
104
- state.visible = true
105
- if (!isQuickMode()) {
106
- setFormData(row.data)
107
- }
108
- } else {
109
- state.visible = false
110
- }
111
- },
112
- { flush: 'sync' }
113
- )
114
-
115
- const childrenKey = computed(() => {
116
- return typeof props.tree === 'string' ? props.tree : 'children'
117
- })
118
-
119
- /**
120
- * 插入数据
121
- * @param item 数据
122
- */
123
- function insert(item: Record<string, any>) {
124
- const data = [...(props.data ?? [])]
125
-
126
- const parent = visitDataByIndexPath(
127
- data ?? [],
128
- insertIndexes.value.slice(0, -1),
129
- childrenKey.value
130
- )
131
-
132
- if (parent) {
133
- const children = parent[childrenKey.value]
134
- if (!children) {
135
- parent[childrenKey.value] = [item]
136
- } else {
137
- children.splice(last(insertIndexes.value), 0, item)
138
- }
139
- } else {
140
- data.splice(last(insertIndexes.value), 0, item)
141
- }
142
-
143
- emit('update:data', data)
144
-
145
- return item
146
- }
147
-
148
- function getInsertData(): Record<string, any> {
149
- return snapshotModelData()
150
- }
151
-
152
- async function runCreate(cb: () => void, initialData?: Record<string, any>) {
153
- state.parentRow = undefined
154
- if (state.row) {
155
- state.row.isCurrent = false
156
- }
157
- state.row = undefined
158
- state.type = 'create'
159
- cb()
160
-
161
- await nextTick()
162
-
163
- setFormData(initialData)
164
-
165
- if (isQuickMode() && props.model) {
166
- await runBeforeCreate(props.model)
167
- }
168
-
169
- state.visible = true
170
- }
171
-
172
- /**
173
- * 点击新增按钮
174
- */
175
- async function handleCreate() {
176
- const { data } = props
177
- await runCreate(() => {
178
- state.depth = 1
179
- insertIndexes.value = [data?.length ?? 0]
180
- })
181
- }
182
-
183
- async function handleInsertToPrev(row: TableRow) {
184
- await runCreate(() => {
185
- state.depth = row.depth
186
- insertIndexes.value = [...row.indexes]
187
- })
188
- }
189
-
190
- async function handleInsertToNext(row: TableRow) {
191
- await runCreate(() => {
192
- state.depth = row.depth
193
- insertIndexes.value = [...row.indexes.slice(0, -1), row.index + 1]
194
- })
195
- }
196
-
197
- async function handleInsertChild(row: TableRow) {
198
- await runCreate(() => {
199
- state.parentRow = row
200
- state.depth = row.depth + 1
201
- row.expanded = true
202
-
203
- insertIndexes.value = [...row.indexes, row.children?.length ?? 0]
204
- })
205
- }
206
-
207
- /** 编辑指定行(等同于点击行) */
208
- function handleEdit(row: TableRow) {
209
- state.type = 'update'
210
- state.row = row
211
- state.depth = row.depth
212
- }
213
-
214
- /** 复制指定行:在其下方以 create 模式打开表单,并预填副本数据 */
215
- async function handleCopy(row: TableRow) {
216
- await runCreate(() => {
217
- state.depth = row.depth
218
- insertIndexes.value = [...row.indexes.slice(0, -1), row.index + 1]
219
- }, row.data)
220
- }
221
-
222
- function runWithLoading<Arg extends any[]>(fn: (...args: Arg) => Promise<void> | void) {
223
- return async (...args: Arg) => {
224
- state.loading = true
225
- if (state.row) {
226
- state.row.operating = true
227
- }
228
- try {
229
- await fn.apply(null, args)
230
- } catch (error) {
231
- console.error(error)
232
- }
233
- state.loading = false
234
- if (state.row) {
235
- state.row.operating = false
236
- }
237
- }
238
- }
239
-
240
- /** 保存 */
241
- const handleSave = runWithLoading(async () => {
242
- const { model, saveMethod } = props
243
-
244
- if (!model) return
245
-
246
- if (isQuickMode() && state.type === 'update') return
247
-
248
- formRef.value?.clearValidate()
249
- const valid = await formRef.value?.validate()
250
-
251
- if (!valid) return
252
-
253
- // quick + create:仅校验 + insert
254
- if (isQuickMode() && state.type === 'create') {
255
- insert(getInsertData())
256
- return
257
- }
258
-
259
- let item = getInsertData()
260
-
261
- // normal + create:beforeCreate → saveMethod → insert
262
- if (state.type === 'create') {
263
- await runBeforeCreate(item)
264
- if (saveMethod) {
265
- const result = await saveMethod(item, state.type, state.parentRow?.data)
266
- if (result) {
267
- item = result
268
- }
269
- }
270
- insert(item)
271
- return
272
- }
273
-
274
- // normal + update
275
- if (saveMethod) {
276
- const result = await saveMethod(item, state.type, state.parentRow?.data)
277
- if (result) {
278
- item = result
279
- }
280
- }
281
-
282
- const { row } = state
283
- row &&
284
- Object.keys(item).forEach((key) => {
285
- o(row.data).set(key, o(item).get(key))
286
- })
287
- })
288
-
289
- const handleDelete = runWithLoading(async (row: TableRow) => {
290
- const { deleteMethod } = props
291
-
292
- if (deleteMethod) {
293
- await deleteMethod([row.data])
294
- }
295
-
296
- const data = [...(props.data ?? [])]
297
-
298
- const parent = visitDataByIndexPath(data, row.indexes.slice(0, -1), childrenKey.value)
299
-
300
- if (parent) {
301
- const children = parent[childrenKey.value]
302
- if (children) {
303
- children.splice(row.index, 1)
304
- } else {
305
- console.error('行路径不正确')
306
- }
307
- } else {
308
- data.splice(row.index, 1)
309
- }
310
-
311
- if (state.row === row) {
312
- state.row = undefined
313
- state.depth = undefined
314
- }
315
-
316
- emit('update:data', data)
317
- })
318
-
319
- function handleClose() {
320
- state.visible = false
321
- if (state.row) {
322
- state.row.isCurrent = false
323
- }
324
- state.row = undefined
325
- state.parentRow = undefined
326
- state.depth = undefined
327
- insertIndexes.value = []
328
- }
329
-
330
- return {
331
- state,
332
- insertIndexes,
333
- handleDelete,
334
- handleInsertChild,
335
- handleInsertToNext,
336
- handleInsertToPrev,
337
- handleCreate,
338
- handleEdit,
339
- handleCopy,
340
- handleClose,
341
- handleSave
342
- }
343
- }