@tmagic/editor 1.5.0-beta.13 → 1.5.0-beta.15
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/style.css +61 -6
- package/dist/tmagic-editor.js +521 -242
- package/dist/tmagic-editor.umd.cjs +522 -243
- package/package.json +12 -10
- package/src/components/CodeBlockEditor.vue +11 -5
- package/src/components/CodeParams.vue +3 -3
- package/src/fields/Code.vue +1 -2
- package/src/fields/CodeSelect.vue +13 -11
- package/src/fields/CodeSelectCol.vue +32 -5
- package/src/fields/CondOpSelect.vue +5 -2
- package/src/fields/DataSourceFields.vue +31 -12
- package/src/fields/DataSourceMethods.vue +72 -14
- package/src/fields/DisplayConds.vue +8 -3
- package/src/fields/EventSelect.vue +25 -8
- package/src/fields/KeyValue.vue +15 -10
- package/src/hooks/index.ts +0 -1
- package/src/hooks/use-code-block-edit.ts +1 -1
- package/src/hooks/use-data-source-edit.ts +3 -2
- package/src/initService.ts +103 -24
- package/src/layouts/Framework.vue +0 -3
- package/src/layouts/PropsPanel.vue +3 -3
- package/src/layouts/page-bar/PageBar.vue +46 -3
- package/src/layouts/page-bar/PageBarScrollContainer.vue +49 -24
- package/src/layouts/page-bar/PageList.vue +4 -2
- package/src/layouts/sidebar/Sidebar.vue +3 -0
- package/src/layouts/sidebar/code-block/CodeBlockList.vue +6 -1
- package/src/layouts/sidebar/data-source/DataSourceConfigPanel.vue +7 -5
- package/src/layouts/sidebar/data-source/DataSourceList.vue +6 -1
- package/src/layouts/workspace/Workspace.vue +5 -2
- package/src/layouts/workspace/viewer/Stage.vue +12 -5
- package/src/services/dataSource.ts +12 -5
- package/src/services/dep.ts +49 -11
- package/src/services/editor.ts +26 -11
- package/src/theme/page-bar.scss +24 -9
- package/src/theme/search-input.scss +1 -0
- package/src/utils/data-source/formConfigs/http.ts +2 -0
- package/src/utils/data-source/index.ts +2 -2
- package/src/utils/editor.ts +94 -2
- package/src/utils/idle-task.ts +34 -3
- package/src/utils/props.ts +3 -3
- package/types/index.d.ts +803 -1169
- package/src/hooks/use-data-source-method.ts +0 -100
|
@@ -21,7 +21,7 @@ export const useCodeBlockEdit = (codeBlockService?: CodeBlockService) => {
|
|
|
21
21
|
|
|
22
22
|
codeConfig.value = {
|
|
23
23
|
name: '',
|
|
24
|
-
content: `({app, params}) => {\n // place your code here\n}`,
|
|
24
|
+
content: `({app, params, flowState}) => {\n // place your code here\n}`,
|
|
25
25
|
params: [],
|
|
26
26
|
};
|
|
27
27
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { computed, ref } from 'vue';
|
|
2
2
|
|
|
3
3
|
import type { DataSourceSchema } from '@tmagic/core';
|
|
4
|
+
import type { ContainerChangeEventData } from '@tmagic/form';
|
|
4
5
|
|
|
5
6
|
import DataSourceConfigPanel from '@editor/layouts/sidebar/data-source/DataSourceConfigPanel.vue';
|
|
6
7
|
import type { DataSourceService } from '@editor/services/dataSource';
|
|
@@ -24,9 +25,9 @@ export const useDataSourceEdit = (dataSourceService?: DataSourceService) => {
|
|
|
24
25
|
editDialog.value.show();
|
|
25
26
|
};
|
|
26
27
|
|
|
27
|
-
const submitDataSourceHandler = (value: DataSourceSchema) => {
|
|
28
|
+
const submitDataSourceHandler = (value: DataSourceSchema, eventData: ContainerChangeEventData) => {
|
|
28
29
|
if (value.id) {
|
|
29
|
-
dataSourceService?.update(value);
|
|
30
|
+
dataSourceService?.update(value, { changeRecords: eventData.changeRecords });
|
|
30
31
|
} else {
|
|
31
32
|
dataSourceService?.add(value);
|
|
32
33
|
}
|
package/src/initService.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { onBeforeUnmount, reactive, toRaw, watch } from 'vue';
|
|
1
|
+
import { computed, onBeforeUnmount, reactive, toRaw, watch } from 'vue';
|
|
2
2
|
import { cloneDeep } from 'lodash-es';
|
|
3
3
|
|
|
4
4
|
import type {
|
|
@@ -17,11 +17,14 @@ import {
|
|
|
17
17
|
createDataSourceMethodTarget,
|
|
18
18
|
createDataSourceTarget,
|
|
19
19
|
DepTargetType,
|
|
20
|
+
NODE_CONDS_KEY,
|
|
20
21
|
Target,
|
|
21
22
|
} from '@tmagic/core';
|
|
23
|
+
import { ChangeRecord } from '@tmagic/form';
|
|
22
24
|
import { getNodes, isPage, traverseNode } from '@tmagic/utils';
|
|
23
25
|
|
|
24
26
|
import PropsPanel from './layouts/PropsPanel.vue';
|
|
27
|
+
import { isIncludeDataSource, isValueIncludeDataSource } from './utils/editor';
|
|
25
28
|
import { EditorProps } from './editorProps';
|
|
26
29
|
import { Services } from './type';
|
|
27
30
|
|
|
@@ -219,6 +222,7 @@ export const initServiceEvents = (
|
|
|
219
222
|
});
|
|
220
223
|
|
|
221
224
|
if (Array.isArray(value.items)) {
|
|
225
|
+
depService.clearIdleTasks();
|
|
222
226
|
collectIdle(value.items, true);
|
|
223
227
|
} else {
|
|
224
228
|
depService.clear();
|
|
@@ -247,10 +251,25 @@ export const initServiceEvents = (
|
|
|
247
251
|
}
|
|
248
252
|
};
|
|
249
253
|
|
|
250
|
-
const
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
+
const stage = computed(() => editorService.get('stage'));
|
|
255
|
+
|
|
256
|
+
watch(stage, (stage) => {
|
|
257
|
+
if (!stage) {
|
|
258
|
+
return;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
stage.on('rerender', () => {
|
|
262
|
+
const node = editorService.get('node');
|
|
263
|
+
|
|
264
|
+
if (!node) return;
|
|
265
|
+
|
|
266
|
+
collectIdle([node], true).then(() => {
|
|
267
|
+
afterUpdateNodes([node]);
|
|
268
|
+
});
|
|
269
|
+
});
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
const getApp = () => stage.value?.renderer?.runtime?.getApp?.();
|
|
254
273
|
|
|
255
274
|
const updateDataSourceSchema = (nodes: MNode[], deep: boolean) => {
|
|
256
275
|
const root = editorService.get('root');
|
|
@@ -266,9 +285,7 @@ export const initServiceEvents = (
|
|
|
266
285
|
getApp()?.dataSourceManager?.updateSchema(root.dataSources);
|
|
267
286
|
}
|
|
268
287
|
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
if (!root || !stage) return;
|
|
288
|
+
if (!root || !stage.value) return;
|
|
272
289
|
|
|
273
290
|
const allNodes: MNode[] = [];
|
|
274
291
|
|
|
@@ -289,7 +306,7 @@ export const initServiceEvents = (
|
|
|
289
306
|
Object.keys(dep).forEach((id) => {
|
|
290
307
|
const node = allNodes.find((node) => node.id === id);
|
|
291
308
|
node &&
|
|
292
|
-
stage.update({
|
|
309
|
+
stage.value?.update({
|
|
293
310
|
config: cloneDeep(node),
|
|
294
311
|
parentId: editorService.getParentById(node.id)?.id,
|
|
295
312
|
root: cloneDeep(root),
|
|
@@ -301,13 +318,8 @@ export const initServiceEvents = (
|
|
|
301
318
|
const afterUpdateNodes = (nodes: MNode[]) => {
|
|
302
319
|
const root = editorService.get('root');
|
|
303
320
|
if (!root) return;
|
|
304
|
-
const stage = editorService.get('stage');
|
|
305
|
-
const app = getApp();
|
|
306
|
-
if (app?.dsl) {
|
|
307
|
-
app.dsl.dataSourceDeps = root.dataSourceDeps;
|
|
308
|
-
}
|
|
309
321
|
for (const node of nodes) {
|
|
310
|
-
stage?.update({
|
|
322
|
+
stage.value?.update({
|
|
311
323
|
config: cloneDeep(node),
|
|
312
324
|
parentId: editorService.getParentById(node.id)?.id,
|
|
313
325
|
root: cloneDeep(root),
|
|
@@ -348,8 +360,18 @@ export const initServiceEvents = (
|
|
|
348
360
|
}
|
|
349
361
|
};
|
|
350
362
|
|
|
363
|
+
const depCollectedHandler = () => {
|
|
364
|
+
const root = editorService.get('root');
|
|
365
|
+
if (!root) return;
|
|
366
|
+
const app = getApp();
|
|
367
|
+
if (app?.dsl) {
|
|
368
|
+
app.dsl.dataSourceDeps = root.dataSourceDeps;
|
|
369
|
+
}
|
|
370
|
+
};
|
|
371
|
+
|
|
351
372
|
depService.on('add-target', targetAddHandler);
|
|
352
373
|
depService.on('remove-target', targetRemoveHandler);
|
|
374
|
+
depService.on('collected', depCollectedHandler);
|
|
353
375
|
|
|
354
376
|
const initDataSourceDepTarget = (ds: DataSourceSchema) => {
|
|
355
377
|
depService.addTarget(createDataSourceTarget(ds, reactive({})));
|
|
@@ -380,10 +402,39 @@ export const initServiceEvents = (
|
|
|
380
402
|
};
|
|
381
403
|
|
|
382
404
|
// 节点更新,收集依赖
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
405
|
+
// 仅当修改到数据源相关的才收集
|
|
406
|
+
const nodeUpdateHandler = (data: { newNode: MNode; oldNode: MNode; changeRecords?: ChangeRecord[] }[]) => {
|
|
407
|
+
const needRecollectNodes: MNode[] = [];
|
|
408
|
+
const normalNodes: MNode[] = [];
|
|
409
|
+
data.forEach(({ newNode, oldNode, changeRecords }) => {
|
|
410
|
+
if (changeRecords?.length) {
|
|
411
|
+
for (const record of changeRecords) {
|
|
412
|
+
// NODE_CONDS_KEY为显示条件key
|
|
413
|
+
if (
|
|
414
|
+
!record.propPath ||
|
|
415
|
+
new RegExp(`${NODE_CONDS_KEY}.(\\d)+.cond`).test(record.propPath) ||
|
|
416
|
+
new RegExp(`${NODE_CONDS_KEY}.(\\d)+.cond.(\\d)+.value`).test(record.propPath) ||
|
|
417
|
+
record.propPath === NODE_CONDS_KEY ||
|
|
418
|
+
isValueIncludeDataSource(record.value)
|
|
419
|
+
) {
|
|
420
|
+
needRecollectNodes.push(newNode);
|
|
421
|
+
break;
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
} else if (isIncludeDataSource(newNode, oldNode)) {
|
|
425
|
+
needRecollectNodes.push(newNode);
|
|
426
|
+
} else {
|
|
427
|
+
normalNodes.push(newNode);
|
|
428
|
+
}
|
|
386
429
|
});
|
|
430
|
+
|
|
431
|
+
if (needRecollectNodes.length) {
|
|
432
|
+
collectIdle(needRecollectNodes, true).then(() => {
|
|
433
|
+
afterUpdateNodes(needRecollectNodes);
|
|
434
|
+
});
|
|
435
|
+
} else if (normalNodes.length) {
|
|
436
|
+
afterUpdateNodes(normalNodes);
|
|
437
|
+
}
|
|
387
438
|
};
|
|
388
439
|
|
|
389
440
|
// 节点删除,清除对齐的依赖收集
|
|
@@ -425,14 +476,41 @@ export const initServiceEvents = (
|
|
|
425
476
|
getApp()?.dataSourceManager?.addDataSource(config);
|
|
426
477
|
};
|
|
427
478
|
|
|
428
|
-
const dataSourceUpdateHandler = (config: DataSourceSchema) => {
|
|
479
|
+
const dataSourceUpdateHandler = (config: DataSourceSchema, { changeRecords }: { changeRecords: ChangeRecord[] }) => {
|
|
480
|
+
let needRecollectDep = false;
|
|
481
|
+
for (const changeRecord of changeRecords) {
|
|
482
|
+
if (!changeRecord.propPath) {
|
|
483
|
+
continue;
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
needRecollectDep =
|
|
487
|
+
changeRecord.propPath === 'fields' ||
|
|
488
|
+
changeRecord.propPath === 'methods' ||
|
|
489
|
+
/fields.(\d)+.name/.test(changeRecord.propPath) ||
|
|
490
|
+
/fields.(\d)+$/.test(changeRecord.propPath) ||
|
|
491
|
+
/methods.(\d)+.name/.test(changeRecord.propPath) ||
|
|
492
|
+
/methods.(\d)+$/.test(changeRecord.propPath);
|
|
493
|
+
|
|
494
|
+
if (needRecollectDep) {
|
|
495
|
+
break;
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
|
|
429
499
|
const root = editorService.get('root');
|
|
430
|
-
|
|
431
|
-
|
|
500
|
+
if (needRecollectDep) {
|
|
501
|
+
if (Array.isArray(root?.items)) {
|
|
502
|
+
depService.clearIdleTasks();
|
|
432
503
|
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
504
|
+
removeDataSourceTarget(config.id);
|
|
505
|
+
initDataSourceDepTarget(config);
|
|
506
|
+
|
|
507
|
+
collectIdle(root.items, true).then(() => {
|
|
508
|
+
updateDataSourceSchema(root?.items || [], true);
|
|
509
|
+
});
|
|
510
|
+
}
|
|
511
|
+
} else if (root?.dataSources) {
|
|
512
|
+
getApp()?.dataSourceManager?.updateSchema(root.dataSources);
|
|
513
|
+
}
|
|
436
514
|
};
|
|
437
515
|
|
|
438
516
|
const removeDataSourceTarget = (id: string) => {
|
|
@@ -459,6 +537,7 @@ export const initServiceEvents = (
|
|
|
459
537
|
onBeforeUnmount(() => {
|
|
460
538
|
depService.off('add-target', targetAddHandler);
|
|
461
539
|
depService.off('remove-target', targetRemoveHandler);
|
|
540
|
+
depService.off('collected', depCollectedHandler);
|
|
462
541
|
|
|
463
542
|
editorService.off('history-change', historyChangeHandler);
|
|
464
543
|
editorService.off('root-change', rootChangeHandler);
|
|
@@ -11,8 +11,6 @@
|
|
|
11
11
|
</slot>
|
|
12
12
|
|
|
13
13
|
<SplitView
|
|
14
|
-
v-loading="stageLoading"
|
|
15
|
-
element-loading-text="Runtime 加载中..."
|
|
16
14
|
v-else
|
|
17
15
|
ref="splitView"
|
|
18
16
|
class="m-editor-content"
|
|
@@ -102,7 +100,6 @@ const root = computed(() => editorService?.get('root'));
|
|
|
102
100
|
const page = computed(() => editorService?.get('page'));
|
|
103
101
|
|
|
104
102
|
const pageLength = computed(() => editorService?.get('pageLength') || 0);
|
|
105
|
-
const stageLoading = computed(() => editorService?.get('stageLoading') || false);
|
|
106
103
|
const showSrc = computed(() => uiService?.get('showSrc'));
|
|
107
104
|
|
|
108
105
|
const LEFT_COLUMN_WIDTH_STORAGE_KEY = '$MagicEditorLeftColumnWidthData';
|
|
@@ -43,7 +43,7 @@ import { Document as DocumentIcon } from '@element-plus/icons-vue';
|
|
|
43
43
|
|
|
44
44
|
import type { MNode } from '@tmagic/core';
|
|
45
45
|
import { TMagicButton } from '@tmagic/design';
|
|
46
|
-
import type { FormState, FormValue } from '@tmagic/form';
|
|
46
|
+
import type { ContainerChangeEventData, FormState, FormValue } from '@tmagic/form';
|
|
47
47
|
import { MForm } from '@tmagic/form';
|
|
48
48
|
|
|
49
49
|
import MIcon from '@editor/components/Icon.vue';
|
|
@@ -110,10 +110,10 @@ watchEffect(() => {
|
|
|
110
110
|
}
|
|
111
111
|
});
|
|
112
112
|
|
|
113
|
-
const submit = async () => {
|
|
113
|
+
const submit = async (v: FormValue, eventData: ContainerChangeEventData) => {
|
|
114
114
|
try {
|
|
115
115
|
const values = await configForm.value?.submitForm();
|
|
116
|
-
services?.editorService.update(values);
|
|
116
|
+
services?.editorService.update(values, { changeRecords: eventData.changeRecords });
|
|
117
117
|
} catch (e: any) {
|
|
118
118
|
emit('submit-error', e);
|
|
119
119
|
}
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div class="m-editor-page-bar-tabs">
|
|
3
|
-
<PageBarScrollContainer
|
|
3
|
+
<PageBarScrollContainer
|
|
4
|
+
ref="pageBarScrollContainer"
|
|
5
|
+
:page-bar-sort-options="pageBarSortOptions"
|
|
6
|
+
:length="list.length"
|
|
7
|
+
>
|
|
4
8
|
<template #prepend>
|
|
5
9
|
<slot name="page-bar-add-button"><AddButton></AddButton></slot>
|
|
6
10
|
|
|
@@ -13,8 +17,9 @@
|
|
|
13
17
|
<div
|
|
14
18
|
v-for="item in list"
|
|
15
19
|
class="m-editor-page-bar-item"
|
|
20
|
+
ref="pageBarItems"
|
|
16
21
|
:key="item.id"
|
|
17
|
-
:page-id="item.id"
|
|
22
|
+
:data-page-id="item.id"
|
|
18
23
|
:class="{ active: page?.id === item.id }"
|
|
19
24
|
@click="switchPage(item.id)"
|
|
20
25
|
>
|
|
@@ -63,7 +68,7 @@
|
|
|
63
68
|
</template>
|
|
64
69
|
|
|
65
70
|
<script lang="ts" setup>
|
|
66
|
-
import { computed, inject, ref } from 'vue';
|
|
71
|
+
import { computed, inject, ref, watch } from 'vue';
|
|
67
72
|
import { CaretBottom, Delete, DocumentCopy } from '@element-plus/icons-vue';
|
|
68
73
|
|
|
69
74
|
import { type Id, type MPage, type MPageFragment, NodeType } from '@tmagic/core';
|
|
@@ -138,4 +143,42 @@ const copy = (node: MPage | MPageFragment) => {
|
|
|
138
143
|
const remove = (node: MPage | MPageFragment) => {
|
|
139
144
|
editorService?.remove(node);
|
|
140
145
|
};
|
|
146
|
+
|
|
147
|
+
const pageBarScrollContainer = ref<InstanceType<typeof PageBarScrollContainer>>();
|
|
148
|
+
const pageBarItems = ref<HTMLDivElement[]>();
|
|
149
|
+
watch(page, (page) => {
|
|
150
|
+
if (
|
|
151
|
+
!page ||
|
|
152
|
+
!pageBarScrollContainer.value?.itemsContainerWidth ||
|
|
153
|
+
!pageBarItems.value ||
|
|
154
|
+
pageBarItems.value.length < 2
|
|
155
|
+
) {
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
const firstItem = pageBarItems.value[0];
|
|
160
|
+
const lastItem = pageBarItems.value[pageBarItems.value.length - 1];
|
|
161
|
+
|
|
162
|
+
if (page.id === firstItem.dataset.pageId) {
|
|
163
|
+
pageBarScrollContainer.value.scroll('start');
|
|
164
|
+
} else if (page.id === lastItem.dataset.pageId) {
|
|
165
|
+
pageBarScrollContainer.value.scroll('end');
|
|
166
|
+
} else {
|
|
167
|
+
const pageItem = pageBarItems.value.find((item) => item.dataset.pageId === page.id);
|
|
168
|
+
if (!pageItem) {
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
const pageItemRect = pageItem.getBoundingClientRect();
|
|
173
|
+
const offsetLeft = pageItemRect.left - firstItem.getBoundingClientRect().left;
|
|
174
|
+
const { itemsContainerWidth } = pageBarScrollContainer.value;
|
|
175
|
+
|
|
176
|
+
const left = itemsContainerWidth - offsetLeft - pageItemRect.width;
|
|
177
|
+
|
|
178
|
+
const translateLeft = pageBarScrollContainer.value.getTranslateLeft();
|
|
179
|
+
if (offsetLeft + translateLeft < 0 || offsetLeft + pageItemRect.width > itemsContainerWidth - translateLeft) {
|
|
180
|
+
pageBarScrollContainer.value.scrollTo(left);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
});
|
|
141
184
|
</script>
|
|
@@ -1,16 +1,23 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div class="m-editor-page-bar" ref="pageBar">
|
|
3
3
|
<slot name="prepend"></slot>
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
<Icon :icon="ArrowLeftBold"></Icon>
|
|
4
|
+
<div v-if="length" class="m-editor-page-bar-items" ref="itemsContainer">
|
|
5
|
+
<slot></slot>
|
|
7
6
|
</div>
|
|
8
7
|
|
|
9
|
-
<div
|
|
10
|
-
|
|
8
|
+
<div
|
|
9
|
+
v-if="canScroll"
|
|
10
|
+
class="m-editor-page-bar-item m-editor-page-bar-item-icon m-editor-page-bar-item-left-icon"
|
|
11
|
+
@click="scroll('left')"
|
|
12
|
+
>
|
|
13
|
+
<Icon :icon="ArrowLeftBold"></Icon>
|
|
11
14
|
</div>
|
|
12
15
|
|
|
13
|
-
<div
|
|
16
|
+
<div
|
|
17
|
+
v-if="canScroll"
|
|
18
|
+
class="m-editor-page-bar-item m-editor-page-bar-item-icon m-editor-page-bar-item-right-icon"
|
|
19
|
+
@click="scroll('right')"
|
|
20
|
+
>
|
|
14
21
|
<Icon :icon="ArrowRightBold"></Icon>
|
|
15
22
|
</div>
|
|
16
23
|
</div>
|
|
@@ -80,27 +87,34 @@ onBeforeUnmount(() => {
|
|
|
80
87
|
let translateLeft = 0;
|
|
81
88
|
|
|
82
89
|
const scroll = (type: 'left' | 'right' | 'start' | 'end') => {
|
|
83
|
-
if (!itemsContainer.value) return;
|
|
90
|
+
if (!itemsContainer.value || !canScroll.value) return;
|
|
84
91
|
|
|
85
92
|
const maxScrollLeft = itemsContainer.value.scrollWidth - itemsContainerWidth.value;
|
|
86
93
|
|
|
87
94
|
if (type === 'left') {
|
|
88
|
-
translateLeft
|
|
89
|
-
|
|
90
|
-
if (translateLeft > 0) {
|
|
91
|
-
translateLeft = 0;
|
|
92
|
-
}
|
|
95
|
+
scrollTo(translateLeft + 200);
|
|
93
96
|
} else if (type === 'right') {
|
|
94
|
-
translateLeft
|
|
95
|
-
|
|
96
|
-
if (-translateLeft > maxScrollLeft) {
|
|
97
|
-
translateLeft = -maxScrollLeft;
|
|
98
|
-
}
|
|
97
|
+
scrollTo(translateLeft - 200);
|
|
99
98
|
} else if (type === 'start') {
|
|
100
|
-
|
|
99
|
+
scrollTo(0);
|
|
101
100
|
} else if (type === 'end') {
|
|
102
|
-
|
|
101
|
+
scrollTo(-maxScrollLeft);
|
|
103
102
|
}
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
const scrollTo = (value: number) => {
|
|
106
|
+
if (!itemsContainer.value || !canScroll.value) return;
|
|
107
|
+
const maxScrollLeft = itemsContainer.value.scrollWidth - itemsContainerWidth.value;
|
|
108
|
+
|
|
109
|
+
if (value >= 0) {
|
|
110
|
+
value = 0;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (-value > maxScrollLeft) {
|
|
114
|
+
value = -maxScrollLeft;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
translateLeft = value;
|
|
104
118
|
|
|
105
119
|
itemsContainer.value.style.transform = `translate(${translateLeft}px, 0px)`;
|
|
106
120
|
};
|
|
@@ -110,11 +124,13 @@ watch(
|
|
|
110
124
|
(length = 0, preLength = 0) => {
|
|
111
125
|
setTimeout(() => {
|
|
112
126
|
setCanScroll();
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
127
|
+
nextTick(() => {
|
|
128
|
+
if (length < preLength || preLength === 0) {
|
|
129
|
+
scroll('start');
|
|
130
|
+
} else {
|
|
131
|
+
scroll('end');
|
|
132
|
+
}
|
|
133
|
+
});
|
|
118
134
|
if (length > 1) {
|
|
119
135
|
const el = document.querySelector('.m-editor-page-bar-items') as HTMLElement;
|
|
120
136
|
let beforeDragList: Id[] = [];
|
|
@@ -150,4 +166,13 @@ watch(
|
|
|
150
166
|
immediate: true,
|
|
151
167
|
},
|
|
152
168
|
);
|
|
169
|
+
|
|
170
|
+
defineExpose({
|
|
171
|
+
itemsContainerWidth,
|
|
172
|
+
scroll,
|
|
173
|
+
scrollTo,
|
|
174
|
+
getTranslateLeft() {
|
|
175
|
+
return translateLeft;
|
|
176
|
+
},
|
|
177
|
+
});
|
|
153
178
|
</script>
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
:data="{
|
|
19
19
|
type: 'button',
|
|
20
20
|
text: item.devconfig?.tabName || item.name || item.id,
|
|
21
|
+
className: item.id === page?.id ? 'active' : '',
|
|
21
22
|
handler: () => switchPage(item.id),
|
|
22
23
|
}"
|
|
23
24
|
:key="index"
|
|
@@ -55,7 +56,8 @@ const uiService = services?.uiService;
|
|
|
55
56
|
const editorService = services?.editorService;
|
|
56
57
|
|
|
57
58
|
const showPageListButton = computed(() => uiService?.get('showPageListButton'));
|
|
58
|
-
const
|
|
59
|
-
|
|
59
|
+
const page = computed(() => editorService?.get('page'));
|
|
60
|
+
const switchPage = async (id: Id) => {
|
|
61
|
+
await editorService?.select(id);
|
|
60
62
|
};
|
|
61
63
|
</script>
|
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
</div>
|
|
20
20
|
<div
|
|
21
21
|
class="m-editor-sidebar-content"
|
|
22
|
+
:class="{ 'm-editor-dep-collecting': collecting }"
|
|
22
23
|
v-for="(config, index) in sideBarItems"
|
|
23
24
|
:key="config.$key ?? index"
|
|
24
25
|
v-show="[config.text, config.$key, `${index}`].includes(activeTabName)"
|
|
@@ -197,6 +198,8 @@ const props = withDefaults(
|
|
|
197
198
|
|
|
198
199
|
const services = inject<Services>('services');
|
|
199
200
|
|
|
201
|
+
const collecting = computed(() => services?.depService.get('collecting'));
|
|
202
|
+
|
|
200
203
|
const columnLeftWidth = computed(() => services?.uiService.get('columnWidth')[ColumnLayout.LEFT] || 0);
|
|
201
204
|
const { height: editorContentHeight } = useEditorContentHeight();
|
|
202
205
|
const columnLeftHeight = ref(0);
|
|
@@ -19,6 +19,9 @@
|
|
|
19
19
|
</template>
|
|
20
20
|
|
|
21
21
|
<template #tree-node-tool="{ data }">
|
|
22
|
+
<TMagicTag v-if="collecting && data.type === 'code'" type="info" size="small" style="margin-right: 5px"
|
|
23
|
+
>依赖收集中</TMagicTag
|
|
24
|
+
>
|
|
22
25
|
<TMagicTooltip v-if="data.type === 'code'" effect="dark" :content="editable ? '编辑' : '查看'" placement="bottom">
|
|
23
26
|
<Icon :icon="editable ? Edit : View" class="edit-icon" @click.stop="editCode(`${data.key}`)"></Icon>
|
|
24
27
|
</TMagicTooltip>
|
|
@@ -36,7 +39,7 @@ import { Close, Edit, View } from '@element-plus/icons-vue';
|
|
|
36
39
|
|
|
37
40
|
import type { Id, MNode } from '@tmagic/core';
|
|
38
41
|
import { DepTargetType } from '@tmagic/core';
|
|
39
|
-
import { tMagicMessage, tMagicMessageBox, TMagicTooltip } from '@tmagic/design';
|
|
42
|
+
import { tMagicMessage, tMagicMessageBox, TMagicTag, TMagicTooltip } from '@tmagic/design';
|
|
40
43
|
|
|
41
44
|
import Icon from '@editor/components/Icon.vue';
|
|
42
45
|
import Tree from '@editor/components/Tree.vue';
|
|
@@ -64,6 +67,8 @@ const emit = defineEmits<{
|
|
|
64
67
|
const services = inject<Services>('services');
|
|
65
68
|
const { codeBlockService, depService, editorService } = services || {};
|
|
66
69
|
|
|
70
|
+
const collecting = computed(() => depService?.get('collecting'));
|
|
71
|
+
|
|
67
72
|
// 代码块列表
|
|
68
73
|
const codeList = computed<TreeNodeData[]>(() =>
|
|
69
74
|
Object.entries(codeBlockService?.getCodeDsl() || {}).map(([codeId, code]) => {
|
|
@@ -24,9 +24,9 @@
|
|
|
24
24
|
<script setup lang="ts">
|
|
25
25
|
import { inject, Ref, ref, watchEffect } from 'vue';
|
|
26
26
|
|
|
27
|
-
import { DataSourceSchema } from '@tmagic/core';
|
|
27
|
+
import type { DataSourceSchema } from '@tmagic/core';
|
|
28
28
|
import { tMagicMessage } from '@tmagic/design';
|
|
29
|
-
import { FormConfig, MFormBox } from '@tmagic/form';
|
|
29
|
+
import { type ContainerChangeEventData, type FormConfig, MFormBox } from '@tmagic/form';
|
|
30
30
|
|
|
31
31
|
import FloatingBox from '@editor/components/FloatingBox.vue';
|
|
32
32
|
import { useEditorContentHeight } from '@editor/hooks';
|
|
@@ -46,7 +46,9 @@ const props = defineProps<{
|
|
|
46
46
|
const boxVisible = defineModel<boolean>('visible', { default: false });
|
|
47
47
|
const width = defineModel<number>('width', { default: 670 });
|
|
48
48
|
|
|
49
|
-
const emit = defineEmits
|
|
49
|
+
const emit = defineEmits<{
|
|
50
|
+
submit: [v: any, eventData: ContainerChangeEventData];
|
|
51
|
+
}>();
|
|
50
52
|
|
|
51
53
|
const services = inject<Services>('services');
|
|
52
54
|
|
|
@@ -63,8 +65,8 @@ watchEffect(() => {
|
|
|
63
65
|
dataSourceConfig.value = services?.dataSourceService.getFormConfig(initValues.value.type) || [];
|
|
64
66
|
});
|
|
65
67
|
|
|
66
|
-
const submitHandler = (values: any) => {
|
|
67
|
-
emit('submit', values);
|
|
68
|
+
const submitHandler = (values: any, data: ContainerChangeEventData) => {
|
|
69
|
+
emit('submit', values, data);
|
|
68
70
|
};
|
|
69
71
|
|
|
70
72
|
const errorHandler = (error: any) => {
|
|
@@ -18,6 +18,9 @@
|
|
|
18
18
|
</div>
|
|
19
19
|
</template>
|
|
20
20
|
<template #tree-node-tool="{ data }">
|
|
21
|
+
<TMagicTag v-if="collecting && data.type === 'ds'" type="info" size="small" style="margin-right: 5px"
|
|
22
|
+
>依赖收集中</TMagicTag
|
|
23
|
+
>
|
|
21
24
|
<TMagicTooltip v-if="data.type === 'ds'" effect="dark" :content="editable ? '编辑' : '查看'" placement="bottom">
|
|
22
25
|
<Icon :icon="editable ? Edit : View" class="edit-icon" @click.stop="editHandler(`${data.key}`)"></Icon>
|
|
23
26
|
</TMagicTooltip>
|
|
@@ -34,7 +37,7 @@ import { computed, inject } from 'vue';
|
|
|
34
37
|
import { Close, Edit, View } from '@element-plus/icons-vue';
|
|
35
38
|
|
|
36
39
|
import { DepData, DepTargetType, Id, MNode } from '@tmagic/core';
|
|
37
|
-
import { tMagicMessageBox, TMagicTooltip } from '@tmagic/design';
|
|
40
|
+
import { tMagicMessageBox, TMagicTag, TMagicTooltip } from '@tmagic/design';
|
|
38
41
|
|
|
39
42
|
import Icon from '@editor/components/Icon.vue';
|
|
40
43
|
import Tree from '@editor/components/Tree.vue';
|
|
@@ -60,6 +63,8 @@ const emit = defineEmits<{
|
|
|
60
63
|
|
|
61
64
|
const { depService, editorService, dataSourceService } = inject<Services>('services') || {};
|
|
62
65
|
|
|
66
|
+
const collecting = computed(() => depService?.get('collecting'));
|
|
67
|
+
|
|
63
68
|
const editable = computed(() => dataSourceService?.get('editable') ?? true);
|
|
64
69
|
|
|
65
70
|
const dataSources = computed(() => dataSourceService?.get('dataSources') || []);
|
|
@@ -4,7 +4,8 @@
|
|
|
4
4
|
|
|
5
5
|
<slot name="stage">
|
|
6
6
|
<MagicStage
|
|
7
|
-
v-if="page"
|
|
7
|
+
v-if="page && (stageOptions?.render || stageOptions?.runtimeUrl)"
|
|
8
|
+
:stage-options="stageOptions"
|
|
8
9
|
:disabled-stage-overlay="disabledStageOverlay"
|
|
9
10
|
:stage-content-menu="stageContentMenu"
|
|
10
11
|
:custom-content-menu="customContentMenu"
|
|
@@ -18,7 +19,7 @@
|
|
|
18
19
|
<script lang="ts" setup>
|
|
19
20
|
import { computed, inject } from 'vue';
|
|
20
21
|
|
|
21
|
-
import type { MenuButton, MenuComponent, Services, WorkspaceSlots } from '@editor/type';
|
|
22
|
+
import type { MenuButton, MenuComponent, Services, StageOptions, WorkspaceSlots } from '@editor/type';
|
|
22
23
|
|
|
23
24
|
import MagicStage from './viewer/Stage.vue';
|
|
24
25
|
import Breadcrumb from './Breadcrumb.vue';
|
|
@@ -40,6 +41,8 @@ withDefaults(
|
|
|
40
41
|
},
|
|
41
42
|
);
|
|
42
43
|
|
|
44
|
+
const stageOptions = inject<StageOptions>('stageOptions');
|
|
45
|
+
|
|
43
46
|
const services = inject<Services>('services');
|
|
44
47
|
|
|
45
48
|
const page = computed(() => services?.editorService.get('page'));
|
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
class="m-editor-stage"
|
|
4
4
|
ref="stageWrap"
|
|
5
5
|
tabindex="-1"
|
|
6
|
+
v-loading="stageLoading"
|
|
7
|
+
element-loading-text="Runtime 加载中..."
|
|
6
8
|
:width="stageRect?.width"
|
|
7
9
|
:height="stageRect?.height"
|
|
8
10
|
:wrap-width="stageContainerRect?.width"
|
|
@@ -62,8 +64,9 @@ defineOptions({
|
|
|
62
64
|
name: 'MEditorStage',
|
|
63
65
|
});
|
|
64
66
|
|
|
65
|
-
withDefaults(
|
|
67
|
+
const props = withDefaults(
|
|
66
68
|
defineProps<{
|
|
69
|
+
stageOptions: StageOptions;
|
|
67
70
|
stageContentMenu: (MenuButton | MenuComponent)[];
|
|
68
71
|
disabledStageOverlay?: boolean;
|
|
69
72
|
customContentMenu?: (menus: (MenuButton | MenuComponent)[], type: string) => (MenuButton | MenuComponent)[];
|
|
@@ -77,7 +80,8 @@ let stage: StageCore | null = null;
|
|
|
77
80
|
let runtime: Runtime | null = null;
|
|
78
81
|
|
|
79
82
|
const services = inject<Services>('services');
|
|
80
|
-
|
|
83
|
+
|
|
84
|
+
const stageLoading = computed(() => services?.editorService.get('stageLoading') || false);
|
|
81
85
|
|
|
82
86
|
const stageWrap = ref<InstanceType<typeof ScrollViewer>>();
|
|
83
87
|
const stageContainer = ref<HTMLDivElement>();
|
|
@@ -96,9 +100,9 @@ watchEffect(() => {
|
|
|
96
100
|
if (stage || !page.value) return;
|
|
97
101
|
|
|
98
102
|
if (!stageContainer.value) return;
|
|
99
|
-
if (!(stageOptions?.runtimeUrl || stageOptions?.render) || !root.value) return;
|
|
103
|
+
if (!(props.stageOptions?.runtimeUrl || props.stageOptions?.render) || !root.value) return;
|
|
100
104
|
|
|
101
|
-
stage = useStage(stageOptions);
|
|
105
|
+
stage = useStage(props.stageOptions);
|
|
102
106
|
|
|
103
107
|
stage.on('select', () => {
|
|
104
108
|
stageWrap.value?.container?.focus();
|
|
@@ -125,6 +129,7 @@ watchEffect(() => {
|
|
|
125
129
|
|
|
126
130
|
onBeforeUnmount(() => {
|
|
127
131
|
stage?.destroy();
|
|
132
|
+
services?.editorService.set('stage', null);
|
|
128
133
|
});
|
|
129
134
|
|
|
130
135
|
watch(zoom, (zoom) => {
|
|
@@ -212,7 +217,9 @@ const dropHandler = async (e: DragEvent) => {
|
|
|
212
217
|
e.preventDefault();
|
|
213
218
|
|
|
214
219
|
const doc = stage?.renderer?.contentWindow?.document;
|
|
215
|
-
const parentEl: HTMLElement | null | undefined = doc?.querySelector(
|
|
220
|
+
const parentEl: HTMLElement | null | undefined = doc?.querySelector(
|
|
221
|
+
`.${props.stageOptions?.containerHighlightClassName}`,
|
|
222
|
+
);
|
|
216
223
|
|
|
217
224
|
let parent: MContainer | undefined | null = page.value;
|
|
218
225
|
const parentId = getIdFromEl()(parentEl);
|