@veltra/desktop 1.0.13 → 1.0.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/action/action-group.js +110 -3
- package/dist/components/action/action-group.js.map +1 -1
- package/dist/components/action/action-group.vue.d.ts +16 -3
- package/dist/components/action/action.js +26 -13
- package/dist/components/action/action.js.map +1 -1
- package/dist/components/action/action.vue.d.ts +2 -2
- package/dist/components/action/style.js +2 -1
- package/dist/components/action/style2.css +35 -7
- package/dist/components/auto-complete/auto-complete.vue.d.ts +2 -2
- package/dist/components/batch-edit/batch-edit-form.js +106 -42
- package/dist/components/batch-edit/batch-edit-form.js.map +1 -1
- package/dist/components/batch-edit/batch-edit-list.js +84 -47
- package/dist/components/batch-edit/batch-edit-list.js.map +1 -1
- package/dist/components/batch-edit/batch-edit.js +42 -10
- package/dist/components/batch-edit/batch-edit.js.map +1 -1
- package/dist/components/batch-edit/style.js +2 -4
- package/dist/components/batch-edit/style2.css +202 -30
- package/dist/components/batch-edit/use-edit.js +45 -9
- package/dist/components/batch-edit/use-edit.js.map +1 -1
- package/dist/components/cascade/cascade.js +3 -1
- package/dist/components/cascade/cascade.js.map +1 -1
- package/dist/components/cascade/cascade.vue.d.ts +2 -2
- package/dist/components/checkbox/checkbox-button.vue.d.ts +1 -1
- package/dist/components/checkbox-group/checkbox-group.vue.d.ts +2 -2
- package/dist/components/code-editor/code-editor.js +145 -49
- package/dist/components/code-editor/code-editor.js.map +1 -1
- package/dist/components/code-editor/code-editor.vue.d.ts +2 -0
- package/dist/components/code-editor/style2.css +87 -19
- package/dist/components/date-panel/date-panel.vue.d.ts +1 -1
- package/dist/components/date-picker/date-picker.vue.d.ts +2 -2
- package/dist/components/date-range-picker/date-range-picker.vue.d.ts +2 -2
- package/dist/components/dialog/dialog.js +6 -2
- package/dist/components/dialog/dialog.js.map +1 -1
- package/dist/components/dialog/style2.css +2 -3
- package/dist/components/expression-editor/components/path-preview.js +27 -0
- package/dist/components/expression-editor/components/path-preview.js.map +1 -0
- package/dist/components/expression-editor/components/variable-picker.js +199 -153
- package/dist/components/expression-editor/components/variable-picker.js.map +1 -1
- package/dist/components/expression-editor/core/chip.js +54 -0
- package/dist/components/expression-editor/core/chip.js.map +1 -0
- package/dist/components/expression-editor/core/editor.js +424 -0
- package/dist/components/expression-editor/core/editor.js.map +1 -0
- package/dist/components/expression-editor/core/mention.js +91 -0
- package/dist/components/expression-editor/core/mention.js.map +1 -0
- package/dist/components/expression-editor/core/model.js +64 -0
- package/dist/components/expression-editor/core/model.js.map +1 -0
- package/dist/components/expression-editor/di.js +4 -10
- package/dist/components/expression-editor/di.js.map +1 -1
- package/dist/components/expression-editor/expression-editor.js +168 -114
- package/dist/components/expression-editor/expression-editor.js.map +1 -1
- package/dist/components/expression-editor/expression-editor.vue.d.ts +2 -1
- package/dist/components/expression-editor/style.js +0 -2
- package/dist/components/expression-editor/style2.css +145 -219
- package/dist/components/index.js +54 -54
- package/dist/components/input/input.vue.d.ts +2 -2
- package/dist/components/layout/layout.js +12 -11
- package/dist/components/layout/layout.js.map +1 -1
- package/dist/components/multi-select/multi-select.vue.d.ts +3 -3
- package/dist/components/multi-tree-select/multi-tree-select.vue.d.ts +3 -3
- package/dist/components/notification/notification.vue.d.ts +1 -1
- package/dist/components/number/number.vue.d.ts +1 -1
- package/dist/components/number-input/number-input.js +4 -4
- package/dist/components/number-input/number-input.js.map +1 -1
- package/dist/components/number-input/number-input.vue.d.ts +2 -2
- package/dist/components/number-range-input/number-range-input.vue.d.ts +1 -1
- package/dist/components/password-input/password-input.vue.d.ts +1 -1
- package/dist/components/pop-confirm/pop-confirm.vue.d.ts +1 -1
- package/dist/components/radio-group/radio-group.vue.d.ts +2 -2
- package/dist/components/rich-text-editor/rich-text-editor.js +1 -1
- package/dist/components/rich-text-editor/rich-text-editor.vue.d.ts +1 -1
- package/dist/components/rich-text-editor/toolbar.js +2 -2
- package/dist/components/select/select.vue.d.ts +2 -2
- package/dist/components/steps/steps.vue.d.ts +1 -1
- package/dist/components/table/use-table.js +16 -0
- package/dist/components/table/use-table.js.map +1 -1
- package/dist/components/tabs/tabs-horizontal.vue.d.ts +1 -1
- package/dist/components/tabs/tabs-vertical.vue.d.ts +1 -1
- package/dist/components/tabs/tabs.vue.d.ts +1 -1
- package/dist/components/textarea/textarea.vue.d.ts +2 -2
- package/dist/components/tip/tip.vue.d.ts +1 -1
- package/dist/components/tree/style2.css +18 -12
- package/dist/components/tree/tree-node.js +7 -4
- package/dist/components/tree/tree-node.js.map +1 -1
- package/dist/components/tree-select/tree-select.vue.d.ts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +83 -83
- package/dist/style.js +3 -3
- package/dist/types/action.d.ts +38 -4
- package/dist/types/cascade.d.ts +2 -3
- package/dist/types/code-editor.d.ts +9 -2
- package/dist/types/expression-editor.d.ts +9 -1
- package/dist/types/index.d.ts +2 -2
- package/package.json +11 -12
- package/src/components/action/action-group.vue +126 -56
- package/src/components/action/action.vue +35 -12
- package/src/components/action/style.scss +46 -10
- package/src/components/action/style.ts +2 -1
- package/src/components/batch-edit/batch-edit-form.vue +121 -45
- package/src/components/batch-edit/batch-edit-list.vue +56 -39
- package/src/components/batch-edit/batch-edit.vue +57 -6
- package/src/components/batch-edit/style.scss +251 -37
- package/src/components/batch-edit/style.ts +5 -8
- package/src/components/batch-edit/use-edit.ts +58 -11
- package/src/components/cascade/cascade.vue +3 -1
- package/src/components/code-editor/code-editor.vue +198 -63
- package/src/components/code-editor/style.scss +110 -12
- package/src/components/dialog/dialog.vue +6 -2
- package/src/components/dialog/style.scss +4 -4
- package/src/components/expression-editor/__test__/chip.test.ts +86 -0
- package/src/components/expression-editor/__test__/mention.test.ts +122 -0
- package/src/components/expression-editor/__test__/model.test.ts +127 -0
- package/src/components/expression-editor/components/path-preview.vue +32 -0
- package/src/components/expression-editor/components/variable-picker.vue +224 -219
- package/src/components/expression-editor/core/chip.ts +101 -0
- package/src/components/expression-editor/core/editor.ts +513 -0
- package/src/components/expression-editor/core/mention.ts +121 -0
- package/src/components/expression-editor/core/model.ts +109 -0
- package/src/components/expression-editor/di.ts +4 -32
- package/src/components/expression-editor/expression-editor.vue +184 -151
- package/src/components/expression-editor/style.scss +148 -220
- package/src/components/expression-editor/style.ts +0 -2
- package/src/components/layout/layout.vue +17 -19
- package/src/components/number-input/number-input.vue +4 -4
- package/src/components/table/use-table.ts +16 -0
- package/src/components/tree/style.scss +30 -33
- package/src/components/tree/tree-node.vue +4 -2
- package/src/types/action.ts +42 -4
- package/src/types/cascade.ts +4 -3
- package/src/types/code-editor.ts +9 -2
- package/src/types/expression-editor.ts +9 -0
- package/dist/components/action/action-group.vue_vue_type_script_setup_true_lang.js +0 -65
- package/dist/components/action/action-group.vue_vue_type_script_setup_true_lang.js.map +0 -1
- package/dist/components/expression-editor/constants.js +0 -9
- package/dist/components/expression-editor/constants.js.map +0 -1
- package/dist/components/expression-editor/internal/editor-runtime/create-runtime.js +0 -47
- package/dist/components/expression-editor/internal/editor-runtime/create-runtime.js.map +0 -1
- package/dist/components/expression-editor/internal/editor-runtime/model-sync.js +0 -49
- package/dist/components/expression-editor/internal/editor-runtime/model-sync.js.map +0 -1
- package/dist/components/expression-editor/internal/features/commands/register-command-packs.js +0 -215
- package/dist/components/expression-editor/internal/features/commands/register-command-packs.js.map +0 -1
- package/dist/components/expression-editor/internal/features/drag-drop/drag-drop-service.js +0 -33
- package/dist/components/expression-editor/internal/features/drag-drop/drag-drop-service.js.map +0 -1
- package/dist/components/expression-editor/internal/features/insertion/insertion-service.js +0 -33
- package/dist/components/expression-editor/internal/features/insertion/insertion-service.js.map +0 -1
- package/dist/components/expression-editor/nodes/variable-node.js +0 -94
- package/dist/components/expression-editor/nodes/variable-node.js.map +0 -1
- package/dist/components/expression-editor/parser.js +0 -32
- package/dist/components/expression-editor/parser.js.map +0 -1
- package/dist/components/expression-editor/plain-text.js +0 -19
- package/dist/components/expression-editor/plain-text.js.map +0 -1
- package/dist/components/expression-editor/use-context.js +0 -69
- package/dist/components/expression-editor/use-context.js.map +0 -1
- package/dist/components/expression-editor/use-decorators.js +0 -27
- package/dist/components/expression-editor/use-decorators.js.map +0 -1
- package/dist/components/expression-editor/use-expression-drag-drop.js +0 -275
- package/dist/components/expression-editor/use-expression-drag-drop.js.map +0 -1
- package/src/components/batch-edit/batch-edit-new.vue +0 -168
- package/src/components/batch-edit/style-new.scss +0 -35
- package/src/components/batch-edit/use-edit-new.ts +0 -68
- package/src/components/batch-edit/use-tip.ts +0 -47
- package/src/components/expression-editor/__test__/architecture-boundaries.test.ts +0 -103
- package/src/components/expression-editor/__test__/architecture-compatibility.test.ts +0 -52
- package/src/components/expression-editor/__test__/drag-drop.test.ts +0 -171
- package/src/components/expression-editor/__test__/parser.test.ts +0 -62
- package/src/components/expression-editor/constants.ts +0 -6
- package/src/components/expression-editor/internal/contracts/editor-runtime.ts +0 -11
- package/src/components/expression-editor/internal/editor-runtime/create-runtime.ts +0 -64
- package/src/components/expression-editor/internal/editor-runtime/index.ts +0 -1
- package/src/components/expression-editor/internal/editor-runtime/model-sync.ts +0 -68
- package/src/components/expression-editor/internal/features/commands/register-command-packs.ts +0 -517
- package/src/components/expression-editor/internal/features/drag-drop/drag-drop-service.ts +0 -51
- package/src/components/expression-editor/internal/features/insertion/insertion-service.ts +0 -56
- package/src/components/expression-editor/nodes/variable-node.tsx +0 -118
- package/src/components/expression-editor/parser.ts +0 -46
- package/src/components/expression-editor/plain-text.ts +0 -25
- package/src/components/expression-editor/plan.md +0 -22
- package/src/components/expression-editor/use-context.ts +0 -134
- package/src/components/expression-editor/use-decorators.tsx +0 -29
- package/src/components/expression-editor/use-editor.ts +0 -12
- package/src/components/expression-editor/use-expression-drag-drop.ts +0 -396
|
@@ -1,275 +0,0 @@
|
|
|
1
|
-
import { EXPRESSION_DROP_SCOPE_ATTR, EXPRESSION_VARIABLE_DRAG_KEY_ATTR, EXPRESSION_VARIABLE_DRAG_MARKER_ATTR, EXPRESSION_VARIABLE_DRAG_TYPE } from "./constants.js";
|
|
2
|
-
import { VariableNode } from "./nodes/variable-node.js";
|
|
3
|
-
import { $getNodeByKey, $getRoot } from "lexical";
|
|
4
|
-
//#region src/components/expression-editor/use-expression-drag-drop.ts
|
|
5
|
-
const DROP_INDICATOR_CLASS = "expression-editor__drop-indicator";
|
|
6
|
-
const DRAG_SOURCE_CLASS = "is-dragging";
|
|
7
|
-
const dragVisualStateMap = /* @__PURE__ */ new WeakMap();
|
|
8
|
-
function getDragVisualState(editor) {
|
|
9
|
-
const existing = dragVisualStateMap.get(editor);
|
|
10
|
-
if (existing) return existing;
|
|
11
|
-
const created = {
|
|
12
|
-
indicatorEl: null,
|
|
13
|
-
sourceEl: null,
|
|
14
|
-
cleanupDragEnd: null,
|
|
15
|
-
activePayload: null
|
|
16
|
-
};
|
|
17
|
-
dragVisualStateMap.set(editor, created);
|
|
18
|
-
return created;
|
|
19
|
-
}
|
|
20
|
-
function isHTMLElement(target) {
|
|
21
|
-
return target instanceof HTMLElement;
|
|
22
|
-
}
|
|
23
|
-
function hasChildren(node) {
|
|
24
|
-
return typeof node.getChildren === "function";
|
|
25
|
-
}
|
|
26
|
-
function traverseVariableNodes(node, collector) {
|
|
27
|
-
if (node instanceof VariableNode) {
|
|
28
|
-
collector.push({
|
|
29
|
-
key: node.getKey(),
|
|
30
|
-
variable: node.getVariable(),
|
|
31
|
-
label: node.getLabel()
|
|
32
|
-
});
|
|
33
|
-
return;
|
|
34
|
-
}
|
|
35
|
-
if (!hasChildren(node)) return;
|
|
36
|
-
node.getChildren().forEach((child) => traverseVariableNodes(child, collector));
|
|
37
|
-
}
|
|
38
|
-
function $collectVariableNodeDescriptors() {
|
|
39
|
-
const collector = [];
|
|
40
|
-
traverseVariableNodes($getRoot(), collector);
|
|
41
|
-
return collector;
|
|
42
|
-
}
|
|
43
|
-
function getDropIndicator(rootElement) {
|
|
44
|
-
const existing = rootElement.querySelector(`.${DROP_INDICATOR_CLASS}`);
|
|
45
|
-
if (existing) return existing;
|
|
46
|
-
const indicator = document.createElement("div");
|
|
47
|
-
indicator.className = DROP_INDICATOR_CLASS;
|
|
48
|
-
indicator.style.opacity = "0";
|
|
49
|
-
rootElement.appendChild(indicator);
|
|
50
|
-
return indicator;
|
|
51
|
-
}
|
|
52
|
-
function getDropAnchors(editor) {
|
|
53
|
-
const descriptors = collectVariableNodeDescriptors(editor);
|
|
54
|
-
if (descriptors.length === 0) return [];
|
|
55
|
-
const rects = descriptors.map((descriptor) => editor.getElementByKey(descriptor.key)).filter((element) => element instanceof HTMLElement).map((element) => element.getBoundingClientRect());
|
|
56
|
-
if (rects.length === 0) return [];
|
|
57
|
-
const anchors = [];
|
|
58
|
-
const first = rects[0];
|
|
59
|
-
anchors.push({
|
|
60
|
-
x: first.left,
|
|
61
|
-
y: first.top,
|
|
62
|
-
height: first.height
|
|
63
|
-
});
|
|
64
|
-
for (let index = 0; index < rects.length - 1; index++) {
|
|
65
|
-
const currentRect = rects[index];
|
|
66
|
-
const nextRect = rects[index + 1];
|
|
67
|
-
anchors.push({
|
|
68
|
-
x: (currentRect.right + nextRect.left) / 2,
|
|
69
|
-
y: (currentRect.top + nextRect.top) / 2,
|
|
70
|
-
height: Math.max(currentRect.height, nextRect.height)
|
|
71
|
-
});
|
|
72
|
-
}
|
|
73
|
-
const last = rects[rects.length - 1];
|
|
74
|
-
anchors.push({
|
|
75
|
-
x: last.right,
|
|
76
|
-
y: last.top,
|
|
77
|
-
height: last.height
|
|
78
|
-
});
|
|
79
|
-
return anchors;
|
|
80
|
-
}
|
|
81
|
-
function getDistance(pointerX, pointerY, anchor) {
|
|
82
|
-
const dx = pointerX - anchor.x;
|
|
83
|
-
const dy = pointerY - (anchor.y + anchor.height / 2);
|
|
84
|
-
return dx * dx + dy * dy;
|
|
85
|
-
}
|
|
86
|
-
function supportsNativeDnD() {
|
|
87
|
-
if (typeof window === "undefined") return false;
|
|
88
|
-
const hasDragApi = "draggable" in document.createElement("span") && typeof DataTransfer !== "undefined";
|
|
89
|
-
const coarsePointer = window.matchMedia?.("(pointer: coarse)").matches ?? false;
|
|
90
|
-
return hasDragApi && !coarsePointer;
|
|
91
|
-
}
|
|
92
|
-
function collectVariableNodeDescriptors(editor) {
|
|
93
|
-
let descriptors = [];
|
|
94
|
-
editor.getEditorState().read(() => {
|
|
95
|
-
descriptors = $collectVariableNodeDescriptors();
|
|
96
|
-
});
|
|
97
|
-
return descriptors;
|
|
98
|
-
}
|
|
99
|
-
function ensureDropScopeId(editor) {
|
|
100
|
-
const rootElement = editor.getRootElement();
|
|
101
|
-
if (!rootElement) return "";
|
|
102
|
-
const existing = rootElement.getAttribute(EXPRESSION_DROP_SCOPE_ATTR);
|
|
103
|
-
if (existing) return existing;
|
|
104
|
-
const generated = `scope-${Math.random().toString(36).slice(2)}`;
|
|
105
|
-
rootElement.setAttribute(EXPRESSION_DROP_SCOPE_ATTR, generated);
|
|
106
|
-
return generated;
|
|
107
|
-
}
|
|
108
|
-
function findVariableDragSource(target) {
|
|
109
|
-
if (!isHTMLElement(target)) return null;
|
|
110
|
-
return target.closest(`[${EXPRESSION_VARIABLE_DRAG_MARKER_ATTR}="true"]`);
|
|
111
|
-
}
|
|
112
|
-
function readDragSourceKey(target) {
|
|
113
|
-
const source = findVariableDragSource(target);
|
|
114
|
-
if (!source) return null;
|
|
115
|
-
return source.getAttribute(EXPRESSION_VARIABLE_DRAG_KEY_ATTR);
|
|
116
|
-
}
|
|
117
|
-
function createInternalDragPayload(payload) {
|
|
118
|
-
return JSON.stringify(payload);
|
|
119
|
-
}
|
|
120
|
-
function writeInternalDragPayload(dataTransfer, payload) {
|
|
121
|
-
if (!dataTransfer) return;
|
|
122
|
-
dataTransfer.setData(EXPRESSION_VARIABLE_DRAG_TYPE, createInternalDragPayload(payload));
|
|
123
|
-
}
|
|
124
|
-
function parseInternalDragPayload(payloadText) {
|
|
125
|
-
if (!payloadText) return null;
|
|
126
|
-
try {
|
|
127
|
-
const parsed = JSON.parse(payloadText);
|
|
128
|
-
if (parsed.action !== "move-variable" || typeof parsed.scopeId !== "string" || parsed.scopeId.length === 0 || typeof parsed.sourceKey !== "string" || parsed.sourceKey.length === 0) return null;
|
|
129
|
-
return {
|
|
130
|
-
action: parsed.action,
|
|
131
|
-
scopeId: parsed.scopeId,
|
|
132
|
-
sourceKey: parsed.sourceKey
|
|
133
|
-
};
|
|
134
|
-
} catch {
|
|
135
|
-
return null;
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
function readInternalDragPayload(dataTransfer) {
|
|
139
|
-
if (!dataTransfer) return null;
|
|
140
|
-
return parseInternalDragPayload(dataTransfer.getData(EXPRESSION_VARIABLE_DRAG_TYPE));
|
|
141
|
-
}
|
|
142
|
-
function beginDragVisualState(editor, sourceEl, payload) {
|
|
143
|
-
const state = getDragVisualState(editor);
|
|
144
|
-
clearDragVisualState(editor);
|
|
145
|
-
state.activePayload = payload ?? null;
|
|
146
|
-
if (!sourceEl) return;
|
|
147
|
-
sourceEl.classList.add(DRAG_SOURCE_CLASS);
|
|
148
|
-
state.sourceEl = sourceEl;
|
|
149
|
-
const onDragEnd = () => {
|
|
150
|
-
clearDragVisualState(editor);
|
|
151
|
-
};
|
|
152
|
-
window.addEventListener("dragend", onDragEnd, true);
|
|
153
|
-
state.cleanupDragEnd = () => {
|
|
154
|
-
window.removeEventListener("dragend", onDragEnd, true);
|
|
155
|
-
};
|
|
156
|
-
}
|
|
157
|
-
function getActiveInternalDragPayload(editor) {
|
|
158
|
-
return getDragVisualState(editor).activePayload;
|
|
159
|
-
}
|
|
160
|
-
function showDropIndicator(editor, slot) {
|
|
161
|
-
const rootElement = editor.getRootElement();
|
|
162
|
-
if (!rootElement) return;
|
|
163
|
-
const anchors = getDropAnchors(editor);
|
|
164
|
-
if (slot < 0 || slot >= anchors.length) {
|
|
165
|
-
clearDropIndicator(editor);
|
|
166
|
-
return;
|
|
167
|
-
}
|
|
168
|
-
const anchor = anchors[slot];
|
|
169
|
-
const indicator = getDropIndicator(rootElement);
|
|
170
|
-
const rootRect = rootElement.getBoundingClientRect();
|
|
171
|
-
indicator.style.left = `${anchor.x - rootRect.left}px`;
|
|
172
|
-
indicator.style.top = `${anchor.y - rootRect.top}px`;
|
|
173
|
-
indicator.style.height = `${anchor.height}px`;
|
|
174
|
-
indicator.style.opacity = "1";
|
|
175
|
-
const state = getDragVisualState(editor);
|
|
176
|
-
state.indicatorEl = indicator;
|
|
177
|
-
}
|
|
178
|
-
function clearDropIndicator(editor) {
|
|
179
|
-
const state = getDragVisualState(editor);
|
|
180
|
-
if (!state.indicatorEl) return;
|
|
181
|
-
state.indicatorEl.style.opacity = "0";
|
|
182
|
-
}
|
|
183
|
-
function clearDragVisualState(editor) {
|
|
184
|
-
const state = getDragVisualState(editor);
|
|
185
|
-
if (state.sourceEl) {
|
|
186
|
-
state.sourceEl.classList.remove(DRAG_SOURCE_CLASS);
|
|
187
|
-
state.sourceEl = null;
|
|
188
|
-
}
|
|
189
|
-
if (state.indicatorEl) {
|
|
190
|
-
state.indicatorEl.style.opacity = "0";
|
|
191
|
-
state.indicatorEl = null;
|
|
192
|
-
}
|
|
193
|
-
if (state.cleanupDragEnd) {
|
|
194
|
-
state.cleanupDragEnd();
|
|
195
|
-
state.cleanupDragEnd = null;
|
|
196
|
-
}
|
|
197
|
-
state.activePayload = null;
|
|
198
|
-
}
|
|
199
|
-
function autoScrollWhenNearEdge(container, pointerY) {
|
|
200
|
-
const rect = container.getBoundingClientRect();
|
|
201
|
-
const threshold = 24;
|
|
202
|
-
const step = 10;
|
|
203
|
-
if (pointerY < rect.top + threshold) {
|
|
204
|
-
container.scrollBy({
|
|
205
|
-
top: -step,
|
|
206
|
-
behavior: "auto"
|
|
207
|
-
});
|
|
208
|
-
return;
|
|
209
|
-
}
|
|
210
|
-
if (pointerY > rect.bottom - threshold) container.scrollBy({
|
|
211
|
-
top: step,
|
|
212
|
-
behavior: "auto"
|
|
213
|
-
});
|
|
214
|
-
}
|
|
215
|
-
function resolveDropSlot(editor, event) {
|
|
216
|
-
const rootElement = editor.getRootElement();
|
|
217
|
-
if (!rootElement || !isHTMLElement(event.target)) return null;
|
|
218
|
-
if (!rootElement.contains(event.target)) return null;
|
|
219
|
-
const anchors = getDropAnchors(editor);
|
|
220
|
-
if (anchors.length === 0) return null;
|
|
221
|
-
let nearestSlot = 0;
|
|
222
|
-
let nearestDistance = Number.POSITIVE_INFINITY;
|
|
223
|
-
for (let slot = 0; slot < anchors.length; slot++) {
|
|
224
|
-
const anchor = anchors[slot];
|
|
225
|
-
const distance = getDistance(event.clientX, event.clientY, anchor);
|
|
226
|
-
if (distance < nearestDistance) {
|
|
227
|
-
nearestDistance = distance;
|
|
228
|
-
nearestSlot = slot;
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
return nearestSlot;
|
|
232
|
-
}
|
|
233
|
-
function reorderVariableNode(sourceKey, targetSlot, focusMovedNode = true) {
|
|
234
|
-
const nodes = $collectVariableNodeDescriptors();
|
|
235
|
-
if (nodes.length <= 1) return false;
|
|
236
|
-
const sourceIndex = nodes.findIndex((item) => item.key === sourceKey);
|
|
237
|
-
if (sourceIndex < 0) return false;
|
|
238
|
-
if (targetSlot < 0 || targetSlot > nodes.length) return false;
|
|
239
|
-
if (targetSlot === sourceIndex || targetSlot === sourceIndex + 1) return false;
|
|
240
|
-
const sourceNode = $getNodeByKey(sourceKey);
|
|
241
|
-
if (!(sourceNode instanceof VariableNode)) return false;
|
|
242
|
-
const remaining = nodes.filter((item) => item.key !== sourceKey);
|
|
243
|
-
const reference = remaining[targetSlot > sourceIndex ? targetSlot - 1 : targetSlot];
|
|
244
|
-
if (reference) {
|
|
245
|
-
const referenceNode = $getNodeByKey(reference.key);
|
|
246
|
-
if (!(referenceNode instanceof VariableNode)) return false;
|
|
247
|
-
referenceNode.insertBefore(sourceNode);
|
|
248
|
-
} else {
|
|
249
|
-
const last = remaining[remaining.length - 1];
|
|
250
|
-
if (!last) return false;
|
|
251
|
-
const lastNode = $getNodeByKey(last.key);
|
|
252
|
-
if (!(lastNode instanceof VariableNode)) return false;
|
|
253
|
-
lastNode.insertAfter(sourceNode);
|
|
254
|
-
}
|
|
255
|
-
if (focusMovedNode) sourceNode.selectEnd();
|
|
256
|
-
return true;
|
|
257
|
-
}
|
|
258
|
-
function moveVariableByDirection(sourceKey, direction, focusMovedNode = true) {
|
|
259
|
-
const nodes = $collectVariableNodeDescriptors();
|
|
260
|
-
const sourceIndex = nodes.findIndex((item) => item.key === sourceKey);
|
|
261
|
-
if (sourceIndex < 0) return false;
|
|
262
|
-
const targetIndex = sourceIndex + direction;
|
|
263
|
-
if (targetIndex < 0 || targetIndex >= nodes.length) return false;
|
|
264
|
-
return reorderVariableNode(sourceKey, direction === -1 ? targetIndex : targetIndex + 1, focusMovedNode);
|
|
265
|
-
}
|
|
266
|
-
function applyDropReorder(options) {
|
|
267
|
-
const payload = parseInternalDragPayload(options.payloadText);
|
|
268
|
-
if (!payload) return false;
|
|
269
|
-
if (payload.scopeId !== options.scopeId) return false;
|
|
270
|
-
return reorderVariableNode(payload.sourceKey, options.targetSlot, options.focusMovedNode ?? true);
|
|
271
|
-
}
|
|
272
|
-
//#endregion
|
|
273
|
-
export { applyDropReorder, autoScrollWhenNearEdge, beginDragVisualState, clearDragVisualState, clearDropIndicator, collectVariableNodeDescriptors, ensureDropScopeId, getActiveInternalDragPayload, moveVariableByDirection, readDragSourceKey, readInternalDragPayload, resolveDropSlot, showDropIndicator, supportsNativeDnD, writeInternalDragPayload };
|
|
274
|
-
|
|
275
|
-
//# sourceMappingURL=use-expression-drag-drop.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"use-expression-drag-drop.js","names":[],"sources":["../../../src/components/expression-editor/use-expression-drag-drop.ts"],"sourcesContent":["import { $getNodeByKey, $getRoot, type LexicalEditor, type LexicalNode } from 'lexical'\n\nimport {\n EXPRESSION_DROP_SCOPE_ATTR,\n EXPRESSION_VARIABLE_DRAG_KEY_ATTR,\n EXPRESSION_VARIABLE_DRAG_MARKER_ATTR,\n EXPRESSION_VARIABLE_DRAG_TYPE\n} from './constants'\nimport { VariableNode } from './nodes/variable-node'\n\ntype Direction = -1 | 1\n\ninterface DragVisualState {\n indicatorEl: HTMLDivElement | null\n sourceEl: HTMLElement | null\n cleanupDragEnd: (() => void) | null\n activePayload: InternalDragPayload | null\n}\n\ninterface DropAnchor {\n x: number\n y: number\n height: number\n}\n\nexport interface VariableNodeDescriptor {\n key: string\n variable: string\n label: string\n}\n\nexport interface InternalDragPayload {\n sourceKey: string\n scopeId: string\n action: 'move-variable'\n}\n\nexport interface ApplyDropReorderOptions {\n payloadText: string | null\n scopeId: string\n targetSlot: number\n focusMovedNode?: boolean\n}\n\nconst DROP_INDICATOR_CLASS = 'expression-editor__drop-indicator'\nconst DRAG_SOURCE_CLASS = 'is-dragging'\n\nconst dragVisualStateMap = new WeakMap<LexicalEditor, DragVisualState>()\n\nfunction getDragVisualState(editor: LexicalEditor): DragVisualState {\n const existing = dragVisualStateMap.get(editor)\n if (existing) return existing\n\n const created: DragVisualState = {\n indicatorEl: null,\n sourceEl: null,\n cleanupDragEnd: null,\n activePayload: null\n }\n dragVisualStateMap.set(editor, created)\n return created\n}\n\nfunction isHTMLElement(target: EventTarget | null): target is HTMLElement {\n return target instanceof HTMLElement\n}\n\nfunction hasChildren(\n node: LexicalNode\n): node is LexicalNode & { getChildren: () => LexicalNode[] } {\n return typeof (node as { getChildren?: unknown }).getChildren === 'function'\n}\n\nfunction traverseVariableNodes(node: LexicalNode, collector: VariableNodeDescriptor[]): void {\n if (node instanceof VariableNode) {\n collector.push({ key: node.getKey(), variable: node.getVariable(), label: node.getLabel() })\n return\n }\n\n if (!hasChildren(node)) return\n node.getChildren().forEach((child) => traverseVariableNodes(child, collector))\n}\n\nfunction $collectVariableNodeDescriptors(): VariableNodeDescriptor[] {\n const collector: VariableNodeDescriptor[] = []\n const root = $getRoot()\n traverseVariableNodes(root, collector)\n return collector\n}\n\nfunction getDropIndicator(rootElement: HTMLElement): HTMLDivElement {\n const existing = rootElement.querySelector<HTMLDivElement>(`.${DROP_INDICATOR_CLASS}`)\n if (existing) return existing\n\n const indicator = document.createElement('div')\n indicator.className = DROP_INDICATOR_CLASS\n indicator.style.opacity = '0'\n rootElement.appendChild(indicator)\n return indicator\n}\n\nfunction getDropAnchors(editor: LexicalEditor): DropAnchor[] {\n const descriptors = collectVariableNodeDescriptors(editor)\n if (descriptors.length === 0) return []\n\n const rects = descriptors\n .map((descriptor) => editor.getElementByKey(descriptor.key))\n .filter((element): element is HTMLElement => element instanceof HTMLElement)\n .map((element) => element.getBoundingClientRect())\n\n if (rects.length === 0) return []\n\n const anchors: DropAnchor[] = []\n const first = rects[0]!\n anchors.push({ x: first.left, y: first.top, height: first.height })\n\n for (let index = 0; index < rects.length - 1; index++) {\n const currentRect = rects[index]!\n const nextRect = rects[index + 1]!\n anchors.push({\n x: (currentRect.right + nextRect.left) / 2,\n y: (currentRect.top + nextRect.top) / 2,\n height: Math.max(currentRect.height, nextRect.height)\n })\n }\n\n const last = rects[rects.length - 1]!\n anchors.push({ x: last.right, y: last.top, height: last.height })\n\n return anchors\n}\n\nfunction getDistance(pointerX: number, pointerY: number, anchor: DropAnchor): number {\n const dx = pointerX - anchor.x\n const dy = pointerY - (anchor.y + anchor.height / 2)\n return dx * dx + dy * dy\n}\n\nexport function supportsNativeDnD(): boolean {\n if (typeof window === 'undefined') return false\n\n const probe = document.createElement('span')\n const hasDragApi = 'draggable' in probe && typeof DataTransfer !== 'undefined'\n const coarsePointer = window.matchMedia?.('(pointer: coarse)').matches ?? false\n\n return hasDragApi && !coarsePointer\n}\n\nexport function collectVariableNodeDescriptors(editor: LexicalEditor): VariableNodeDescriptor[] {\n let descriptors: VariableNodeDescriptor[] = []\n editor.getEditorState().read(() => {\n descriptors = $collectVariableNodeDescriptors()\n })\n return descriptors\n}\n\nexport function ensureDropScopeId(editor: LexicalEditor): string {\n const rootElement = editor.getRootElement()\n if (!rootElement) return ''\n\n const existing = rootElement.getAttribute(EXPRESSION_DROP_SCOPE_ATTR)\n if (existing) return existing\n\n const generated = `scope-${Math.random().toString(36).slice(2)}`\n rootElement.setAttribute(EXPRESSION_DROP_SCOPE_ATTR, generated)\n return generated\n}\n\nexport function findVariableDragSource(target: EventTarget | null): HTMLElement | null {\n if (!isHTMLElement(target)) return null\n\n return target.closest<HTMLElement>(`[${EXPRESSION_VARIABLE_DRAG_MARKER_ATTR}=\"true\"]`)\n}\n\nexport function readDragSourceKey(target: EventTarget | null): string | null {\n const source = findVariableDragSource(target)\n if (!source) return null\n\n return source.getAttribute(EXPRESSION_VARIABLE_DRAG_KEY_ATTR)\n}\n\nexport function createInternalDragPayload(payload: InternalDragPayload): string {\n return JSON.stringify(payload)\n}\n\nexport function writeInternalDragPayload(\n dataTransfer: DataTransfer | null,\n payload: InternalDragPayload\n): void {\n if (!dataTransfer) return\n dataTransfer.setData(EXPRESSION_VARIABLE_DRAG_TYPE, createInternalDragPayload(payload))\n}\n\nexport function parseInternalDragPayload(payloadText: string | null): InternalDragPayload | null {\n if (!payloadText) return null\n\n try {\n const parsed = JSON.parse(payloadText) as Partial<InternalDragPayload>\n if (\n parsed.action !== 'move-variable' ||\n typeof parsed.scopeId !== 'string' ||\n parsed.scopeId.length === 0 ||\n typeof parsed.sourceKey !== 'string' ||\n parsed.sourceKey.length === 0\n ) {\n return null\n }\n\n return { action: parsed.action, scopeId: parsed.scopeId, sourceKey: parsed.sourceKey }\n } catch {\n return null\n }\n}\n\nexport function readInternalDragPayload(\n dataTransfer: DataTransfer | null\n): InternalDragPayload | null {\n if (!dataTransfer) return null\n return parseInternalDragPayload(dataTransfer.getData(EXPRESSION_VARIABLE_DRAG_TYPE))\n}\n\nexport function beginDragVisualState(\n editor: LexicalEditor,\n sourceEl: HTMLElement | null,\n payload?: InternalDragPayload\n): void {\n const state = getDragVisualState(editor)\n clearDragVisualState(editor)\n state.activePayload = payload ?? null\n\n if (!sourceEl) return\n sourceEl.classList.add(DRAG_SOURCE_CLASS)\n state.sourceEl = sourceEl\n\n const onDragEnd = () => {\n clearDragVisualState(editor)\n }\n window.addEventListener('dragend', onDragEnd, true)\n state.cleanupDragEnd = () => {\n window.removeEventListener('dragend', onDragEnd, true)\n }\n}\n\nexport function getActiveInternalDragPayload(editor: LexicalEditor): InternalDragPayload | null {\n return getDragVisualState(editor).activePayload\n}\n\nexport function showDropIndicator(editor: LexicalEditor, slot: number): void {\n const rootElement = editor.getRootElement()\n if (!rootElement) return\n\n const anchors = getDropAnchors(editor)\n if (slot < 0 || slot >= anchors.length) {\n clearDropIndicator(editor)\n return\n }\n\n const anchor = anchors[slot]!\n const indicator = getDropIndicator(rootElement)\n const rootRect = rootElement.getBoundingClientRect()\n\n indicator.style.left = `${anchor.x - rootRect.left}px`\n indicator.style.top = `${anchor.y - rootRect.top}px`\n indicator.style.height = `${anchor.height}px`\n indicator.style.opacity = '1'\n\n const state = getDragVisualState(editor)\n state.indicatorEl = indicator\n}\n\nexport function clearDropIndicator(editor: LexicalEditor): void {\n const state = getDragVisualState(editor)\n if (!state.indicatorEl) return\n state.indicatorEl.style.opacity = '0'\n}\n\nexport function clearDragVisualState(editor: LexicalEditor): void {\n const state = getDragVisualState(editor)\n\n if (state.sourceEl) {\n state.sourceEl.classList.remove(DRAG_SOURCE_CLASS)\n state.sourceEl = null\n }\n\n if (state.indicatorEl) {\n state.indicatorEl.style.opacity = '0'\n state.indicatorEl = null\n }\n\n if (state.cleanupDragEnd) {\n state.cleanupDragEnd()\n state.cleanupDragEnd = null\n }\n\n state.activePayload = null\n}\n\nexport function autoScrollWhenNearEdge(container: HTMLElement, pointerY: number): void {\n const rect = container.getBoundingClientRect()\n const threshold = 24\n const step = 10\n\n if (pointerY < rect.top + threshold) {\n container.scrollBy({ top: -step, behavior: 'auto' })\n return\n }\n\n if (pointerY > rect.bottom - threshold) {\n container.scrollBy({ top: step, behavior: 'auto' })\n }\n}\n\nexport function resolveDropSlot(editor: LexicalEditor, event: DragEvent): number | null {\n const rootElement = editor.getRootElement()\n if (!rootElement || !isHTMLElement(event.target)) return null\n if (!rootElement.contains(event.target)) return null\n\n const anchors = getDropAnchors(editor)\n if (anchors.length === 0) return null\n\n let nearestSlot = 0\n let nearestDistance = Number.POSITIVE_INFINITY\n for (let slot = 0; slot < anchors.length; slot++) {\n const anchor = anchors[slot]!\n const distance = getDistance(event.clientX, event.clientY, anchor)\n if (distance < nearestDistance) {\n nearestDistance = distance\n nearestSlot = slot\n }\n }\n\n return nearestSlot\n}\n\nexport function reorderVariableNode(\n sourceKey: string,\n targetSlot: number,\n focusMovedNode = true\n): boolean {\n const nodes = $collectVariableNodeDescriptors()\n if (nodes.length <= 1) return false\n\n const sourceIndex = nodes.findIndex((item) => item.key === sourceKey)\n if (sourceIndex < 0) return false\n if (targetSlot < 0 || targetSlot > nodes.length) return false\n if (targetSlot === sourceIndex || targetSlot === sourceIndex + 1) return false\n\n const sourceNode = $getNodeByKey(sourceKey)\n if (!(sourceNode instanceof VariableNode)) return false\n\n const remaining = nodes.filter((item) => item.key !== sourceKey)\n const insertionIndex = targetSlot > sourceIndex ? targetSlot - 1 : targetSlot\n const reference = remaining[insertionIndex]\n\n if (reference) {\n const referenceNode = $getNodeByKey(reference.key)\n if (!(referenceNode instanceof VariableNode)) return false\n referenceNode.insertBefore(sourceNode)\n } else {\n const last = remaining[remaining.length - 1]\n if (!last) return false\n const lastNode = $getNodeByKey(last.key)\n if (!(lastNode instanceof VariableNode)) return false\n lastNode.insertAfter(sourceNode)\n }\n\n if (focusMovedNode) {\n sourceNode.selectEnd()\n }\n\n return true\n}\n\nexport function moveVariableByDirection(\n sourceKey: string,\n direction: Direction,\n focusMovedNode = true\n): boolean {\n const nodes = $collectVariableNodeDescriptors()\n const sourceIndex = nodes.findIndex((item) => item.key === sourceKey)\n if (sourceIndex < 0) return false\n\n const targetIndex = sourceIndex + direction\n if (targetIndex < 0 || targetIndex >= nodes.length) return false\n\n const targetSlot = direction === -1 ? targetIndex : targetIndex + 1\n return reorderVariableNode(sourceKey, targetSlot, focusMovedNode)\n}\n\nexport function applyDropReorder(options: ApplyDropReorderOptions): boolean {\n const payload = parseInternalDragPayload(options.payloadText)\n if (!payload) return false\n if (payload.scopeId !== options.scopeId) return false\n\n return reorderVariableNode(payload.sourceKey, options.targetSlot, options.focusMovedNode ?? true)\n}\n"],"mappings":"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"}
|
|
@@ -1,168 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<u-table v-bind="tableProps" :columns="columnsWithOperation" :current="currentRow" :class="cls.b">
|
|
3
|
-
<template #column:__action__="{ row }">
|
|
4
|
-
<ButtonWrap tag="div" @click.stop>
|
|
5
|
-
<u-button
|
|
6
|
-
:icon="View"
|
|
7
|
-
title="查看"
|
|
8
|
-
v-if="featureSets.has('view')"
|
|
9
|
-
@click="handleView(row, $event)"
|
|
10
|
-
/>
|
|
11
|
-
<u-button
|
|
12
|
-
:icon="Edit"
|
|
13
|
-
title="编辑"
|
|
14
|
-
v-if="featureSets.has('update')"
|
|
15
|
-
@click="handleEdit(row, $event)"
|
|
16
|
-
/>
|
|
17
|
-
<u-button
|
|
18
|
-
:icon="Plus"
|
|
19
|
-
title="下方新增"
|
|
20
|
-
v-if="featureSets.has('create')"
|
|
21
|
-
@click="handleAdd(row, $event)"
|
|
22
|
-
/>
|
|
23
|
-
<u-button
|
|
24
|
-
:icon="AddChild"
|
|
25
|
-
title="新增子项"
|
|
26
|
-
v-if="featureSets.has('create') && !!tree"
|
|
27
|
-
@click="handleAdd(row, $event)"
|
|
28
|
-
/>
|
|
29
|
-
<u-button
|
|
30
|
-
:icon="Copy"
|
|
31
|
-
title="复制"
|
|
32
|
-
v-if="featureSets.has('copy')"
|
|
33
|
-
@click="handleCopy(row, $event)"
|
|
34
|
-
/>
|
|
35
|
-
<u-button
|
|
36
|
-
:icon="Delete"
|
|
37
|
-
type="danger"
|
|
38
|
-
title="删除"
|
|
39
|
-
v-if="featureSets.has('delete')"
|
|
40
|
-
@click="handleDelete(row)"
|
|
41
|
-
/>
|
|
42
|
-
</ButtonWrap>
|
|
43
|
-
</template>
|
|
44
|
-
|
|
45
|
-
<template #append>
|
|
46
|
-
<u-tip
|
|
47
|
-
:visible="visible && !!model"
|
|
48
|
-
:trigger-dom="triggerDom"
|
|
49
|
-
trigger="click"
|
|
50
|
-
alignment="center"
|
|
51
|
-
direction="left"
|
|
52
|
-
:class="cls.e('tip')"
|
|
53
|
-
>
|
|
54
|
-
<template #content>
|
|
55
|
-
<div :class="cls.e('form-title')" v-if="tipType">
|
|
56
|
-
{{ titleDict[tipType] }}
|
|
57
|
-
</div>
|
|
58
|
-
<u-scroll :class="cls.e('form-scroll')" :content-class="cls.e('form-scroll-content')">
|
|
59
|
-
<u-form :model="model!" :readonly="readonly" :label-width="labelWidth">
|
|
60
|
-
<template #default="{ data, model }">
|
|
61
|
-
<slot name="form" v-bind="{ data, model }" />
|
|
62
|
-
</template>
|
|
63
|
-
</u-form>
|
|
64
|
-
</u-scroll>
|
|
65
|
-
|
|
66
|
-
<div :class="cls.e('form-action')">
|
|
67
|
-
<u-button @click="handleClose" type="primary" text> 关闭 </u-button>
|
|
68
|
-
<u-button type="primary" @click="handleSubmit" v-if="!readonly"> 提交 </u-button>
|
|
69
|
-
</div>
|
|
70
|
-
</template>
|
|
71
|
-
</u-tip>
|
|
72
|
-
</template>
|
|
73
|
-
</u-table>
|
|
74
|
-
</template>
|
|
75
|
-
|
|
76
|
-
<script lang="ts" setup>
|
|
77
|
-
import { o } from '@cat-kit/core'
|
|
78
|
-
import { useComponentProps } from '@veltra/compositions'
|
|
79
|
-
import { AddChild, Copy, Delete, Edit, Plus, View } from '@veltra/icons'
|
|
80
|
-
import { bem } from '@veltra/utils'
|
|
81
|
-
import { computed, watch } from 'vue'
|
|
82
|
-
|
|
83
|
-
import type { BatchEditEmits, BatchEditProps, ButtonProps, TableColumn } from '../../types'
|
|
84
|
-
import { UButton } from '../button'
|
|
85
|
-
import { type FormModel, UForm } from '../form'
|
|
86
|
-
import { UScroll } from '../scroll'
|
|
87
|
-
import { UTable } from '../table'
|
|
88
|
-
import { UTip } from '../tip'
|
|
89
|
-
import { useEdit } from './use-edit-new'
|
|
90
|
-
import { useTip } from './use-tip'
|
|
91
|
-
|
|
92
|
-
defineOptions({
|
|
93
|
-
name: 'BatchEdit'
|
|
94
|
-
})
|
|
95
|
-
|
|
96
|
-
const props = defineProps<BatchEditProps<FormModel>>()
|
|
97
|
-
const emit = defineEmits<BatchEditEmits>()
|
|
98
|
-
|
|
99
|
-
const tableProps = computed(() => {
|
|
100
|
-
return o(props as Record<string, any>).omit([
|
|
101
|
-
'model',
|
|
102
|
-
'columns',
|
|
103
|
-
'cols',
|
|
104
|
-
'readonly',
|
|
105
|
-
'deleteMethod',
|
|
106
|
-
'saveMethod',
|
|
107
|
-
'features',
|
|
108
|
-
'current'
|
|
109
|
-
])
|
|
110
|
-
})
|
|
111
|
-
|
|
112
|
-
const featureSets = computed(() => {
|
|
113
|
-
return new Set(
|
|
114
|
-
['create', 'delete', 'update', 'copy', 'view']
|
|
115
|
-
// props.features ?? ['create', 'delete', 'update', 'copy', 'view']
|
|
116
|
-
)
|
|
117
|
-
})
|
|
118
|
-
|
|
119
|
-
const cls = bem('batch-edit')
|
|
120
|
-
|
|
121
|
-
const columnsWithOperation = computed<TableColumn[]>(() => {
|
|
122
|
-
return [
|
|
123
|
-
...(props.columns ?? []),
|
|
124
|
-
{
|
|
125
|
-
name: '操作',
|
|
126
|
-
key: '__action__',
|
|
127
|
-
align: 'center',
|
|
128
|
-
fixed: 'right',
|
|
129
|
-
width: 196,
|
|
130
|
-
resizable: false
|
|
131
|
-
}
|
|
132
|
-
]
|
|
133
|
-
})
|
|
134
|
-
|
|
135
|
-
const ButtonWrap = useComponentProps<ButtonProps>({
|
|
136
|
-
size: 'small',
|
|
137
|
-
circle: true,
|
|
138
|
-
text: true,
|
|
139
|
-
type: 'primary',
|
|
140
|
-
style: { fontSize: '16px', marginRight: '6px' },
|
|
141
|
-
loading: false
|
|
142
|
-
})
|
|
143
|
-
|
|
144
|
-
const { visible, triggerDom, tipType, open, handleSubmit } = useTip({
|
|
145
|
-
props
|
|
146
|
-
})
|
|
147
|
-
|
|
148
|
-
const titleDict = {
|
|
149
|
-
create: '新增',
|
|
150
|
-
update: '编辑',
|
|
151
|
-
copy: '复制',
|
|
152
|
-
view: '查看'
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
const { currentRow, handleEdit, handleAdd, handleCopy, handleDelete, handleView } = useEdit({
|
|
156
|
-
emit,
|
|
157
|
-
props,
|
|
158
|
-
open
|
|
159
|
-
})
|
|
160
|
-
|
|
161
|
-
watch(currentRow, (r) => {
|
|
162
|
-
visible.value = Boolean(r)
|
|
163
|
-
})
|
|
164
|
-
|
|
165
|
-
function handleClose() {
|
|
166
|
-
currentRow.value = undefined
|
|
167
|
-
}
|
|
168
|
-
</script>
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
@use 'pkg:@veltra/styles/mixins' as m;
|
|
2
|
-
@use 'pkg:@veltra/styles/functions' as fn;
|
|
3
|
-
@use 'pkg:@veltra/styles/vars';
|
|
4
|
-
|
|
5
|
-
$root-name: batch-edit;
|
|
6
|
-
|
|
7
|
-
@include m.b($root-name) {
|
|
8
|
-
@include m.e(tip) {
|
|
9
|
-
padding: 0;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
@include m.e(form-title) {
|
|
13
|
-
font-size: fn.use-var(font-size, title, default);
|
|
14
|
-
color: fn.use-var(text-color, title);
|
|
15
|
-
padding: fn.use-var(gap, small);
|
|
16
|
-
border-bottom: 1px solid fn.use-var(border-color);
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
@include m.e(form-scroll) {
|
|
20
|
-
max-height: 500px;
|
|
21
|
-
width: 900px;
|
|
22
|
-
|
|
23
|
-
&-content {
|
|
24
|
-
padding: fn.use-var(gap, large);
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
@include m.e(form-action) {
|
|
29
|
-
display: flex;
|
|
30
|
-
justify-content: flex-end;
|
|
31
|
-
gap: fn.use-var(gap, small);
|
|
32
|
-
padding: fn.use-var(gap, small);
|
|
33
|
-
border-top: 1px solid fn.use-var(border-color);
|
|
34
|
-
}
|
|
35
|
-
}
|
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
import { nextTick, type ShallowRef, shallowRef } from 'vue'
|
|
2
|
-
|
|
3
|
-
import type { BatchEditEmits, BatchEditProps, TableRow } from '../../types'
|
|
4
|
-
import type { TipReturned } from './use-tip'
|
|
5
|
-
|
|
6
|
-
interface EditReturned {
|
|
7
|
-
currentRow: ShallowRef<TableRow | undefined>
|
|
8
|
-
handleEdit: (row: TableRow, e: MouseEvent) => Promise<void>
|
|
9
|
-
handleAdd: (row: TableRow, e: MouseEvent) => Promise<void>
|
|
10
|
-
handleCopy: (row: TableRow, e: MouseEvent) => Promise<void>
|
|
11
|
-
handleDelete: (row: TableRow) => Promise<void>
|
|
12
|
-
handleView: (row: TableRow, e: MouseEvent) => void
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export function useEdit(options: {
|
|
16
|
-
props: BatchEditProps
|
|
17
|
-
emit: BatchEditEmits
|
|
18
|
-
open: TipReturned['open']
|
|
19
|
-
}): EditReturned {
|
|
20
|
-
const { props, emit, open } = options
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* 当前操作行
|
|
24
|
-
*/
|
|
25
|
-
const currentRow = shallowRef<TableRow>()
|
|
26
|
-
|
|
27
|
-
async function setCurrentRow(row: TableRow): Promise<TableRow | undefined> {
|
|
28
|
-
// 重复点击,则清空
|
|
29
|
-
if (row === currentRow.value) {
|
|
30
|
-
currentRow.value = undefined
|
|
31
|
-
return
|
|
32
|
-
}
|
|
33
|
-
if (!currentRow.value) {
|
|
34
|
-
currentRow.value = row
|
|
35
|
-
return
|
|
36
|
-
}
|
|
37
|
-
currentRow.value = undefined
|
|
38
|
-
await nextTick()
|
|
39
|
-
currentRow.value = row
|
|
40
|
-
return row
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
async function handleAdd(row: TableRow, e: MouseEvent) {
|
|
44
|
-
open('create', e.currentTarget as HTMLElement)
|
|
45
|
-
setCurrentRow(row)
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
async function handleEdit(row: TableRow, e: MouseEvent) {
|
|
49
|
-
open('update', e.currentTarget as HTMLElement)
|
|
50
|
-
setCurrentRow(row)
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
async function handleCopy(row: TableRow, e: MouseEvent) {
|
|
54
|
-
open('copy', e.currentTarget as HTMLElement)
|
|
55
|
-
setCurrentRow(row)
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
async function handleDelete(row: TableRow) {
|
|
59
|
-
emit('update:data', props.data?.filter((_, i) => i !== row.index) ?? [])
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
function handleView(row: TableRow, e: MouseEvent) {
|
|
63
|
-
open('view', e.currentTarget as HTMLElement)
|
|
64
|
-
setCurrentRow(row)
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
return { currentRow, handleEdit, handleAdd, handleCopy, handleDelete, handleView }
|
|
68
|
-
}
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
import { type ShallowRef, shallowRef, watch } from 'vue'
|
|
2
|
-
|
|
3
|
-
import type { BatchEditProps, BatchEditFeature } from '../../types'
|
|
4
|
-
|
|
5
|
-
export interface TipReturned {
|
|
6
|
-
visible: ShallowRef<boolean>
|
|
7
|
-
triggerDom: ShallowRef<HTMLElement | undefined>
|
|
8
|
-
tipType: ShallowRef<BatchEditFeature | undefined>
|
|
9
|
-
open: (type: BatchEditFeature, triggerDom: HTMLElement) => void
|
|
10
|
-
|
|
11
|
-
handleSubmit: () => Promise<void>
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export function useTip(options: { props: BatchEditProps }): TipReturned {
|
|
15
|
-
const { props } = options
|
|
16
|
-
|
|
17
|
-
const visible = shallowRef(false)
|
|
18
|
-
const triggerDom = shallowRef<HTMLElement>()
|
|
19
|
-
const tipType = shallowRef<BatchEditFeature>()
|
|
20
|
-
|
|
21
|
-
function open(type: BatchEditFeature, dom: HTMLElement) {
|
|
22
|
-
tipType.value = type
|
|
23
|
-
triggerDom.value = dom
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
watch(visible, (v) => {
|
|
27
|
-
if (!v) {
|
|
28
|
-
const { model } = props
|
|
29
|
-
model?.clearValidate()
|
|
30
|
-
model?.resetData()
|
|
31
|
-
}
|
|
32
|
-
})
|
|
33
|
-
|
|
34
|
-
async function handleSubmit() {
|
|
35
|
-
await props.model?.validate()
|
|
36
|
-
visible.value = false
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
return {
|
|
40
|
-
visible,
|
|
41
|
-
triggerDom,
|
|
42
|
-
tipType,
|
|
43
|
-
open,
|
|
44
|
-
|
|
45
|
-
handleSubmit
|
|
46
|
-
}
|
|
47
|
-
}
|