@tmagic/editor 1.8.0-beta.5 → 1.8.0-beta.6
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/es/fields/CodeSelectCol.vue_vue_type_script_setup_true_lang.js +4 -1
- package/dist/es/fields/DataSourceFieldSelect/FieldSelect.vue_vue_type_script_setup_true_lang.js +8 -2
- package/dist/es/fields/DataSourceFields.vue_vue_type_script_setup_true_lang.js +25 -8
- package/dist/es/fields/DataSourceMethodSelect.vue_vue_type_script_setup_true_name_true_lang.js +6 -4
- package/dist/es/fields/DataSourceMethods.vue_vue_type_script_setup_true_lang.js +25 -12
- package/dist/es/fields/StyleSetter/components/Border.vue_vue_type_script_setup_true_lang.js +27 -5
- package/dist/es/index.js +2 -2
- package/dist/es/layouts/history-list/HistoryListPanel.vue_vue_type_script_setup_true_lang.js +2 -2
- package/dist/es/layouts/history-list/InitialRow.vue_vue_type_script_setup_true_lang.js +12 -4
- package/dist/es/layouts/sidebar/data-source/DataSourceConfigPanel.vue_vue_type_script_setup_true_lang.js +16 -3
- package/dist/es/layouts/sidebar/data-source/DataSourceListPanel.vue_vue_type_script_setup_true_lang.js +23 -1
- package/dist/es/services/codeBlock.js +30 -19
- package/dist/es/services/dataSource.js +29 -21
- package/dist/es/services/editor.js +52 -33
- package/dist/es/services/history.js +10 -15
- package/dist/es/style.css +4 -1
- package/dist/es/utils/data-source/index.js +2 -0
- package/dist/es/utils/editor.js +68 -48
- package/dist/es/utils/history.js +42 -33
- package/dist/style.css +4 -1
- package/dist/tmagic-editor.umd.cjs +376 -206
- package/package.json +7 -7
- package/src/fields/CodeSelectCol.vue +7 -1
- package/src/fields/DataSourceFieldSelect/FieldSelect.vue +16 -2
- package/src/fields/DataSourceFields.vue +37 -8
- package/src/fields/DataSourceMethodSelect.vue +9 -4
- package/src/fields/DataSourceMethods.vue +42 -21
- package/src/fields/StyleSetter/components/Border.vue +15 -6
- package/src/layouts/history-list/HistoryListPanel.vue +2 -2
- package/src/layouts/history-list/InitialRow.vue +3 -0
- package/src/layouts/sidebar/data-source/DataSourceConfigPanel.vue +30 -2
- package/src/layouts/sidebar/data-source/DataSourceListPanel.vue +26 -1
- package/src/services/codeBlock.ts +28 -22
- package/src/services/dataSource.ts +29 -24
- package/src/services/editor.ts +41 -37
- package/src/services/history.ts +14 -19
- package/src/theme/style-setter/border.scss +4 -1
- package/src/type.ts +16 -1
- package/src/utils/data-source/index.ts +2 -0
- package/src/utils/editor.ts +125 -59
- package/src/utils/history.ts +46 -36
- package/types/index.d.ts +87 -68
package/package.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "1.8.0-beta.
|
|
2
|
+
"version": "1.8.0-beta.6",
|
|
3
3
|
"name": "@tmagic/editor",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"sideEffects": [
|
|
@@ -58,11 +58,11 @@
|
|
|
58
58
|
"moveable": "^0.53.0",
|
|
59
59
|
"serialize-javascript": "^7.0.0",
|
|
60
60
|
"sortablejs": "^1.15.6",
|
|
61
|
-
"@tmagic/
|
|
62
|
-
"@tmagic/
|
|
63
|
-
"@tmagic/
|
|
64
|
-
"@tmagic/
|
|
65
|
-
"@tmagic/
|
|
61
|
+
"@tmagic/design": "1.8.0-beta.6",
|
|
62
|
+
"@tmagic/stage": "1.8.0-beta.6",
|
|
63
|
+
"@tmagic/form": "1.8.0-beta.6",
|
|
64
|
+
"@tmagic/table": "1.8.0-beta.6",
|
|
65
|
+
"@tmagic/utils": "1.8.0-beta.6"
|
|
66
66
|
},
|
|
67
67
|
"devDependencies": {
|
|
68
68
|
"@types/events": "^3.0.3",
|
|
@@ -76,7 +76,7 @@
|
|
|
76
76
|
"type-fest": "^5.2.0",
|
|
77
77
|
"typescript": "^6.0.3",
|
|
78
78
|
"vue": "^3.5.34",
|
|
79
|
-
"@tmagic/core": "1.8.0-beta.
|
|
79
|
+
"@tmagic/core": "1.8.0-beta.6"
|
|
80
80
|
},
|
|
81
81
|
"peerDependenciesMeta": {
|
|
82
82
|
"typescript": {
|
|
@@ -107,10 +107,12 @@ const isCompareMode = computed(() => Boolean(props.isCompare && props.lastValues
|
|
|
107
107
|
|
|
108
108
|
const notEditable = computed(() => filterFunction(mForm, props.config.notEditable, props));
|
|
109
109
|
|
|
110
|
-
const
|
|
110
|
+
const codeBlockSidePanel = computed(() =>
|
|
111
111
|
(uiService.get('sideBarItems') || []).find((item) => item.$key === SideItemKey.CODE_BLOCK),
|
|
112
112
|
);
|
|
113
113
|
|
|
114
|
+
const hasCodeBlockSidePanel = computed(() => codeBlockSidePanel.value);
|
|
115
|
+
|
|
114
116
|
/**
|
|
115
117
|
* 根据代码块id获取代码块参数配置
|
|
116
118
|
* @param codeId 代码块ID
|
|
@@ -191,6 +193,10 @@ const onParamsChangeHandler = (value: any, eventData: ContainerChangeEventData)
|
|
|
191
193
|
};
|
|
192
194
|
|
|
193
195
|
const editCode = (id: string) => {
|
|
196
|
+
const sideBarItem = codeBlockSidePanel.value;
|
|
197
|
+
if (sideBarItem) {
|
|
198
|
+
uiService.set('sideBarActiveTabName', sideBarItem.text || sideBarItem.$key || SideItemKey.CODE_BLOCK);
|
|
199
|
+
}
|
|
194
200
|
eventBus?.emit('edit-code', id);
|
|
195
201
|
};
|
|
196
202
|
</script>
|
|
@@ -211,11 +211,25 @@ const onChangeHandler = (v: string[] = []) => {
|
|
|
211
211
|
emit('change', v);
|
|
212
212
|
};
|
|
213
213
|
|
|
214
|
-
const
|
|
214
|
+
const dataSourceSidePanel = computed(() =>
|
|
215
215
|
uiService.get('sideBarItems').find((item) => item.$key === SideItemKey.DATA_SOURCE),
|
|
216
216
|
);
|
|
217
217
|
|
|
218
|
+
const hasDataSourceSidePanel = computed(() => dataSourceSidePanel.value);
|
|
219
|
+
|
|
218
220
|
const editHandler = (id: string) => {
|
|
219
|
-
|
|
221
|
+
const sideBarItem = dataSourceSidePanel.value;
|
|
222
|
+
if (sideBarItem) {
|
|
223
|
+
uiService.set('sideBarActiveTabName', sideBarItem.text || sideBarItem.$key || SideItemKey.DATA_SOURCE);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
const dataSourceId = removeDataSourceFieldPrefix(id);
|
|
227
|
+
const fieldPath = selectFieldsId.value;
|
|
228
|
+
|
|
229
|
+
if (fieldPath.length) {
|
|
230
|
+
eventBus?.emit('edit-data-source-field', dataSourceId, [...fieldPath]);
|
|
231
|
+
} else {
|
|
232
|
+
eventBus?.emit('edit-data-source', dataSourceId);
|
|
233
|
+
}
|
|
220
234
|
};
|
|
221
235
|
</script>
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
</template>
|
|
48
48
|
|
|
49
49
|
<script setup lang="ts">
|
|
50
|
-
import { computed, inject, Ref, ref } from 'vue';
|
|
50
|
+
import { computed, type ComputedRef, inject, onMounted, provide, Ref, ref } from 'vue';
|
|
51
51
|
|
|
52
52
|
import type { DataSchema } from '@tmagic/core';
|
|
53
53
|
import { TMagicButton, tMagicMessage, tMagicMessageBox } from '@tmagic/design';
|
|
@@ -101,6 +101,16 @@ const newHandler = () => {
|
|
|
101
101
|
addDialogVisible.value = true;
|
|
102
102
|
};
|
|
103
103
|
|
|
104
|
+
const editField = (row: Record<string, any>, index: number) => {
|
|
105
|
+
fieldValues.value = {
|
|
106
|
+
...row,
|
|
107
|
+
index,
|
|
108
|
+
};
|
|
109
|
+
fieldTitle.value = `编辑${row.title}`;
|
|
110
|
+
calcBoxPosition();
|
|
111
|
+
addDialogVisible.value = true;
|
|
112
|
+
};
|
|
113
|
+
|
|
104
114
|
const fieldChange = ({ index, ...value }: Record<string, any>, data: ContainerChangeEventData) => {
|
|
105
115
|
addDialogVisible.value = false;
|
|
106
116
|
|
|
@@ -158,13 +168,7 @@ const fieldColumns: ColumnConfig[] = [
|
|
|
158
168
|
{
|
|
159
169
|
text: '编辑',
|
|
160
170
|
handler: (row: Record<string, any>, index: number) => {
|
|
161
|
-
|
|
162
|
-
...row,
|
|
163
|
-
index,
|
|
164
|
-
};
|
|
165
|
-
fieldTitle.value = `编辑${row.title}`;
|
|
166
|
-
calcBoxPosition();
|
|
167
|
-
addDialogVisible.value = true;
|
|
171
|
+
editField(row, index);
|
|
168
172
|
},
|
|
169
173
|
},
|
|
170
174
|
{
|
|
@@ -354,4 +358,29 @@ const { height: editorHeight } = useEditorContentHeight();
|
|
|
354
358
|
|
|
355
359
|
const parentFloating = inject<Ref<HTMLDivElement | null>>('parentFloating', ref(null));
|
|
356
360
|
const { boxPosition, calcBoxPosition } = useNextFloatBoxPosition(uiService, parentFloating);
|
|
361
|
+
|
|
362
|
+
/**
|
|
363
|
+
* 由 DataSourceConfigPanel 注入:打开数据源详情后需要直接打开的字段路径(字段名数组)。
|
|
364
|
+
* 当前层消费 path[0],并把剩余路径下发给嵌套字段,实现逐层打开。
|
|
365
|
+
*/
|
|
366
|
+
const editingFieldPath = inject<ComputedRef<string[]>>(
|
|
367
|
+
'editingDataSourceFieldPath',
|
|
368
|
+
computed(() => []),
|
|
369
|
+
);
|
|
370
|
+
|
|
371
|
+
provide(
|
|
372
|
+
'editingDataSourceFieldPath',
|
|
373
|
+
computed(() => editingFieldPath.value.slice(1)),
|
|
374
|
+
);
|
|
375
|
+
|
|
376
|
+
onMounted(() => {
|
|
377
|
+
const path = editingFieldPath.value;
|
|
378
|
+
if (!path.length) return;
|
|
379
|
+
|
|
380
|
+
const fields: Record<string, any>[] = props.model[props.name] || [];
|
|
381
|
+
const index = fields.findIndex((field) => field.name === path[0]);
|
|
382
|
+
if (index === -1) return;
|
|
383
|
+
|
|
384
|
+
editField(fields[index], index);
|
|
385
|
+
});
|
|
357
386
|
</script>
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
></MCascader>
|
|
14
14
|
|
|
15
15
|
<TMagicTooltip
|
|
16
|
-
v-if="model[name] && isCustomMethod &&
|
|
16
|
+
v-if="model[name] && isCustomMethod && dataSourceSidePanel && !isCompare"
|
|
17
17
|
:content="notEditable ? '查看' : '编辑'"
|
|
18
18
|
>
|
|
19
19
|
<TMagicButton class="m-fields-select-action-button" :size="size" @click="editCodeHandler">
|
|
@@ -75,7 +75,7 @@ const props = withDefaults(defineProps<FieldProps<DataSourceMethodSelectConfig>>
|
|
|
75
75
|
disabled: false,
|
|
76
76
|
});
|
|
77
77
|
|
|
78
|
-
const
|
|
78
|
+
const dataSourceSidePanel = computed(() =>
|
|
79
79
|
(uiService.get('sideBarItems') || []).find((item) => item.$key === SideItemKey.DATA_SOURCE),
|
|
80
80
|
);
|
|
81
81
|
|
|
@@ -208,12 +208,17 @@ const onParamsChangeHandler = (value: any, eventData: ContainerChangeEventData)
|
|
|
208
208
|
};
|
|
209
209
|
|
|
210
210
|
const editCodeHandler = () => {
|
|
211
|
-
const [id] = props.model[props.name];
|
|
211
|
+
const [id, methodName] = props.model[props.name];
|
|
212
212
|
|
|
213
213
|
const dataSource = dataSourceService.getDataSourceById(id);
|
|
214
214
|
|
|
215
215
|
if (!dataSource) return;
|
|
216
216
|
|
|
217
|
-
|
|
217
|
+
const sideBarItem = dataSourceSidePanel.value;
|
|
218
|
+
if (sideBarItem) {
|
|
219
|
+
uiService.set('sideBarActiveTabName', sideBarItem.text || sideBarItem.$key || SideItemKey.DATA_SOURCE);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
eventBus?.emit('edit-data-source-method', id, methodName);
|
|
218
223
|
};
|
|
219
224
|
</script>
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
</template>
|
|
22
22
|
|
|
23
23
|
<script setup lang="ts">
|
|
24
|
-
import { computed, inject, nextTick, ref, useTemplateRef } from 'vue';
|
|
24
|
+
import { computed, type ComputedRef, inject, nextTick, onMounted, ref, useTemplateRef } from 'vue';
|
|
25
25
|
import { cloneDeep } from 'lodash-es';
|
|
26
26
|
|
|
27
27
|
import type { CodeBlockContent } from '@tmagic/core';
|
|
@@ -52,6 +52,29 @@ const codeBlockEditorRef = useTemplateRef<InstanceType<typeof CodeBlockEditor>>(
|
|
|
52
52
|
|
|
53
53
|
let editIndex = -1;
|
|
54
54
|
|
|
55
|
+
const editMethod = (method: CodeBlockContent, index: number) => {
|
|
56
|
+
let codeContent: string = '({ params, dataSource, app }) => {\n // place your code here\n}';
|
|
57
|
+
|
|
58
|
+
if (method.content) {
|
|
59
|
+
if (typeof method.content !== 'string') {
|
|
60
|
+
codeContent = method.content.toString();
|
|
61
|
+
} else {
|
|
62
|
+
codeContent = method.content;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
codeConfig.value = {
|
|
67
|
+
...cloneDeep(method),
|
|
68
|
+
content: codeContent,
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
editIndex = index;
|
|
72
|
+
|
|
73
|
+
nextTick(() => {
|
|
74
|
+
codeBlockEditorRef.value?.show();
|
|
75
|
+
});
|
|
76
|
+
};
|
|
77
|
+
|
|
55
78
|
const methodColumns: ColumnConfig[] = [
|
|
56
79
|
{
|
|
57
80
|
label: '名称',
|
|
@@ -77,26 +100,7 @@ const methodColumns: ColumnConfig[] = [
|
|
|
77
100
|
{
|
|
78
101
|
text: '编辑',
|
|
79
102
|
handler: (method: CodeBlockContent, index: number) => {
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
if (method.content) {
|
|
83
|
-
if (typeof method.content !== 'string') {
|
|
84
|
-
codeContent = method.content.toString();
|
|
85
|
-
} else {
|
|
86
|
-
codeContent = method.content;
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
codeConfig.value = {
|
|
91
|
-
...cloneDeep(method),
|
|
92
|
-
content: codeContent,
|
|
93
|
-
};
|
|
94
|
-
|
|
95
|
-
editIndex = index;
|
|
96
|
-
|
|
97
|
-
nextTick(() => {
|
|
98
|
-
codeBlockEditorRef.value?.show();
|
|
99
|
-
});
|
|
103
|
+
editMethod(method, index);
|
|
100
104
|
},
|
|
101
105
|
},
|
|
102
106
|
{
|
|
@@ -158,4 +162,21 @@ const submitCodeHandler = (value: CodeBlockContent, data: ContainerChangeEventDa
|
|
|
158
162
|
|
|
159
163
|
codeBlockEditorRef.value?.hide();
|
|
160
164
|
};
|
|
165
|
+
|
|
166
|
+
/** 由 DataSourceConfigPanel 注入:打开数据源详情后需要直接打开的方法名 */
|
|
167
|
+
const editingMethodName = inject<ComputedRef<string | undefined>>(
|
|
168
|
+
'editingDataSourceMethodName',
|
|
169
|
+
computed(() => ''),
|
|
170
|
+
);
|
|
171
|
+
|
|
172
|
+
onMounted(() => {
|
|
173
|
+
const methodName = editingMethodName.value;
|
|
174
|
+
if (!methodName) return;
|
|
175
|
+
|
|
176
|
+
const methods: CodeBlockContent[] = props.model[props.name] || [];
|
|
177
|
+
const index = methods.findIndex((method) => method.name === methodName);
|
|
178
|
+
if (index === -1) return;
|
|
179
|
+
|
|
180
|
+
editMethod(methods[index], index);
|
|
181
|
+
});
|
|
161
182
|
</script>
|
|
@@ -4,27 +4,31 @@
|
|
|
4
4
|
<div class="border-icon-container-row">
|
|
5
5
|
<div
|
|
6
6
|
class="border-icon border-icon-top"
|
|
7
|
-
:class="{ active: direction === 'Top' }"
|
|
7
|
+
:class="{ active: direction === 'Top', configured: isConfigured('Top') }"
|
|
8
8
|
@click="selectDirection('Top')"
|
|
9
9
|
></div>
|
|
10
10
|
</div>
|
|
11
11
|
<div class="border-icon-container-row">
|
|
12
12
|
<div
|
|
13
13
|
class="border-icon border-icon-left"
|
|
14
|
-
:class="{ active: direction === 'Left' }"
|
|
14
|
+
:class="{ active: direction === 'Left', configured: isConfigured('Left') }"
|
|
15
15
|
@click="selectDirection('Left')"
|
|
16
16
|
></div>
|
|
17
|
-
<div
|
|
17
|
+
<div
|
|
18
|
+
class="border-icon"
|
|
19
|
+
:class="{ active: direction === '', configured: isConfigured('') }"
|
|
20
|
+
@click="selectDirection()"
|
|
21
|
+
></div>
|
|
18
22
|
<div
|
|
19
23
|
class="border-icon border-icon-right"
|
|
20
|
-
:class="{ active: direction === 'Right' }"
|
|
24
|
+
:class="{ active: direction === 'Right', configured: isConfigured('Right') }"
|
|
21
25
|
@click="selectDirection('Right')"
|
|
22
26
|
></div>
|
|
23
27
|
</div>
|
|
24
28
|
<div class="border-icon-container-row">
|
|
25
29
|
<div
|
|
26
30
|
class="border-icon border-icon-bottom"
|
|
27
|
-
:class="{ active: direction === 'Bottom' }"
|
|
31
|
+
:class="{ active: direction === 'Bottom', configured: isConfigured('Bottom') }"
|
|
28
32
|
@click="selectDirection('Bottom')"
|
|
29
33
|
></div>
|
|
30
34
|
</div>
|
|
@@ -98,7 +102,7 @@ const emit = defineEmits<{
|
|
|
98
102
|
addDiffCount: [];
|
|
99
103
|
}>();
|
|
100
104
|
|
|
101
|
-
withDefaults(
|
|
105
|
+
const props = withDefaults(
|
|
102
106
|
defineProps<{
|
|
103
107
|
model: FormValue;
|
|
104
108
|
lastValues?: FormValue;
|
|
@@ -109,6 +113,11 @@ withDefaults(
|
|
|
109
113
|
{},
|
|
110
114
|
);
|
|
111
115
|
|
|
116
|
+
const hasValue = (value: unknown) => value !== undefined && value !== null && value !== '';
|
|
117
|
+
|
|
118
|
+
const isConfigured = (d: string) =>
|
|
119
|
+
['Width', 'Color', 'Style'].some((key) => hasValue(props.model?.[`border${d}${key}`]));
|
|
120
|
+
|
|
112
121
|
const change = (value: StyleSchema, eventData: ContainerChangeEventData) => {
|
|
113
122
|
eventData.changeRecords?.forEach((record) => {
|
|
114
123
|
emit('change', record.value, {
|
|
@@ -100,8 +100,8 @@
|
|
|
100
100
|
/**
|
|
101
101
|
* 历史记录面板:在顶部 NavMenu 上点击图标打开 popover,分三个 tab:
|
|
102
102
|
* - 页面:当前活动页面的历史栈,连续修改同一节点的多步会被合并成一组
|
|
103
|
-
* - 数据源:以 dataSource.id
|
|
104
|
-
* - 代码块:同上,按 codeBlock.id
|
|
103
|
+
* - 数据源:以 dataSource.id 分桶,每条操作记录独立展示
|
|
104
|
+
* - 代码块:同上,按 codeBlock.id 分桶,每条操作记录独立展示
|
|
105
105
|
*
|
|
106
106
|
* 数据通过 historyService 暴露的聚合 API 读取,UI 仅用于只读展示,
|
|
107
107
|
* 同时支持点击任意一条记录跳转至该状态:
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
<span class="m-editor-history-list-item-index" title="历史步骤编号 #0(未修改的初始状态)">#0</span>
|
|
8
8
|
<span class="m-editor-history-list-item-op op-initial">初始</span>
|
|
9
9
|
<span class="m-editor-history-list-item-desc">{{ desc }}</span>
|
|
10
|
+
<span v-if="saved" class="m-editor-history-list-item-saved" title="该记录为最近一次保存的状态">已保存</span>
|
|
10
11
|
<span v-if="gotoEnabled && !isCurrent" class="m-editor-history-list-item-actions">
|
|
11
12
|
<span class="m-editor-history-list-item-goto" title="回到该记录" @click.stop="onClick">回到</span>
|
|
12
13
|
</span>
|
|
@@ -49,6 +50,8 @@ const props = withDefaults(
|
|
|
49
50
|
);
|
|
50
51
|
|
|
51
52
|
const desc = computed(() => props.marker?.historyDescription || '未修改的初始状态');
|
|
53
|
+
/** 基线(初始状态)是否为最近一次保存点:仅页面栈的 `initial` 基线 step 会被 markSaved 标记。 */
|
|
54
|
+
const saved = computed(() => Boolean(props.marker?.saved));
|
|
52
55
|
const time = computed(() => formatHistoryTime(props.marker?.timestamp));
|
|
53
56
|
const timeTitle = computed(() => formatHistoryFullTime(props.marker?.timestamp));
|
|
54
57
|
const rowTitle = computed(() => {
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
</template>
|
|
23
23
|
|
|
24
24
|
<script setup lang="ts">
|
|
25
|
-
import { inject, nextTick, Ref, ref, watch, watchEffect } from 'vue';
|
|
25
|
+
import { computed, inject, nextTick, provide, Ref, ref, watch, watchEffect } from 'vue';
|
|
26
26
|
|
|
27
27
|
import type { DataSourceSchema } from '@tmagic/core';
|
|
28
28
|
import { tMagicMessage } from '@tmagic/design';
|
|
@@ -41,6 +41,10 @@ const props = defineProps<{
|
|
|
41
41
|
title?: string;
|
|
42
42
|
values: any;
|
|
43
43
|
disabled: boolean;
|
|
44
|
+
/** 打开后需要直接定位并打开的方法名,传入时默认激活「方法定义」tab */
|
|
45
|
+
editMethodName?: string;
|
|
46
|
+
/** 打开后需要直接定位并打开的字段路径,传入时默认激活「数据定义」tab */
|
|
47
|
+
editFieldPath?: string[];
|
|
44
48
|
}>();
|
|
45
49
|
|
|
46
50
|
const boxVisible = defineModel<boolean>('visible', { default: false });
|
|
@@ -62,9 +66,33 @@ const { height: editorHeight } = useEditorContentHeight();
|
|
|
62
66
|
const parentFloating = inject<Ref<HTMLDivElement | null>>('parentFloating', ref(null));
|
|
63
67
|
const { boxPosition, calcBoxPosition } = useNextFloatBoxPosition(uiService, parentFloating);
|
|
64
68
|
|
|
69
|
+
/** 供「方法定义」tab 内的字段消费,用于打开数据源详情后自动打开指定方法 */
|
|
70
|
+
provide(
|
|
71
|
+
'editingDataSourceMethodName',
|
|
72
|
+
computed(() => props.editMethodName),
|
|
73
|
+
);
|
|
74
|
+
|
|
75
|
+
/** 供「数据定义」tab 内的字段消费,用于打开数据源详情后自动打开指定字段 */
|
|
76
|
+
provide(
|
|
77
|
+
'editingDataSourceFieldPath',
|
|
78
|
+
computed(() => props.editFieldPath || []),
|
|
79
|
+
);
|
|
80
|
+
|
|
65
81
|
watchEffect(() => {
|
|
66
82
|
initValues.value = props.values;
|
|
67
|
-
|
|
83
|
+
const config = dataSourceService.getFormConfig(initValues.value.type);
|
|
84
|
+
|
|
85
|
+
// 传入方法名/字段路径时,将外层 tab 容器默认激活到对应 tab(status: methods / fields)
|
|
86
|
+
let activeTab = '';
|
|
87
|
+
if (props.editMethodName) {
|
|
88
|
+
activeTab = 'methods';
|
|
89
|
+
} else if (props.editFieldPath?.length) {
|
|
90
|
+
activeTab = 'fields';
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
dataSourceConfig.value = activeTab
|
|
94
|
+
? config.map((item) => ((item as { type?: string }).type === 'tab' ? { ...item, active: activeTab } : item))
|
|
95
|
+
: config;
|
|
68
96
|
});
|
|
69
97
|
|
|
70
98
|
const submitHandler = (values: any, data: ContainerChangeEventData) => {
|
|
@@ -29,6 +29,8 @@
|
|
|
29
29
|
:disabled="!editable"
|
|
30
30
|
:values="dataSourceValues"
|
|
31
31
|
:title="dialogTitle"
|
|
32
|
+
:edit-method-name="editMethodName"
|
|
33
|
+
:edit-field-path="editFieldPath"
|
|
32
34
|
@submit="submitDataSourceHandler"
|
|
33
35
|
@close="editDialogCloseHandler"
|
|
34
36
|
></DataSourceConfigPanel>
|
|
@@ -45,7 +47,7 @@
|
|
|
45
47
|
</template>
|
|
46
48
|
|
|
47
49
|
<script setup lang="ts">
|
|
48
|
-
import { computed, inject, useTemplateRef, watch } from 'vue';
|
|
50
|
+
import { computed, inject, ref, useTemplateRef, watch } from 'vue';
|
|
49
51
|
import { mergeWith } from 'lodash-es';
|
|
50
52
|
|
|
51
53
|
import { tMagicMessageBox, TMagicScrollbar } from '@tmagic/design';
|
|
@@ -79,7 +81,16 @@ const { dataSourceService } = useServices();
|
|
|
79
81
|
const { editDialog, dataSourceValues, dialogTitle, editable, editHandler, submitDataSourceHandler } =
|
|
80
82
|
useDataSourceEdit(dataSourceService);
|
|
81
83
|
|
|
84
|
+
/** 打开数据源详情时需要直接定位并打开的方法名,为空则正常展示「数据定义」tab */
|
|
85
|
+
const editMethodName = ref('');
|
|
86
|
+
|
|
87
|
+
/** 打开数据源详情时需要直接定位并打开的字段路径,为空则不自动打开字段配置 */
|
|
88
|
+
const editFieldPath = ref<string[]>([]);
|
|
89
|
+
|
|
82
90
|
const editDialogCloseHandler = () => {
|
|
91
|
+
editMethodName.value = '';
|
|
92
|
+
editFieldPath.value = [];
|
|
93
|
+
|
|
83
94
|
if (dataSourceListRef.value) {
|
|
84
95
|
for (const [, status] of dataSourceListRef.value.nodeStatusMap.entries()) {
|
|
85
96
|
status.selected = false;
|
|
@@ -139,6 +150,20 @@ const filterTextChangeHandler = (val: string) => {
|
|
|
139
150
|
};
|
|
140
151
|
|
|
141
152
|
eventBus?.on('edit-data-source', (id: string) => {
|
|
153
|
+
editMethodName.value = '';
|
|
154
|
+
editFieldPath.value = [];
|
|
155
|
+
editHandler(id);
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
eventBus?.on('edit-data-source-method', (id: string, methodName: string) => {
|
|
159
|
+
editMethodName.value = methodName;
|
|
160
|
+
editFieldPath.value = [];
|
|
161
|
+
editHandler(id);
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
eventBus?.on('edit-data-source-field', (id: string, fieldPath: string[]) => {
|
|
165
|
+
editMethodName.value = '';
|
|
166
|
+
editFieldPath.value = fieldPath;
|
|
142
167
|
editHandler(id);
|
|
143
168
|
});
|
|
144
169
|
|
|
@@ -32,13 +32,14 @@ import type {
|
|
|
32
32
|
AsyncHookPlugin,
|
|
33
33
|
CodeBlockStepValue,
|
|
34
34
|
CodeState,
|
|
35
|
+
DslOpWithHistoryIdsResult,
|
|
35
36
|
HistoryOpOptions,
|
|
36
37
|
HistoryOpOptionsWithChangeRecords,
|
|
37
38
|
} from '@editor/type';
|
|
38
39
|
import { CODE_DRAFT_STORAGE_KEY } from '@editor/type';
|
|
39
40
|
import { getEditorConfig } from '@editor/utils/config';
|
|
40
41
|
import { COPY_CODE_STORAGE_KEY } from '@editor/utils/editor';
|
|
41
|
-
import { describeRevertStep } from '@editor/utils/history';
|
|
42
|
+
import { describeRevertStep, getLastPushedHistoryIds } from '@editor/utils/history';
|
|
42
43
|
|
|
43
44
|
import BaseService from './BaseService';
|
|
44
45
|
|
|
@@ -321,43 +322,46 @@ class CodeBlock extends BaseService {
|
|
|
321
322
|
// #region AndGetHistoryId
|
|
322
323
|
/**
|
|
323
324
|
* 下列 *AndGetHistoryId 方法与对应的写入方法行为完全一致,
|
|
324
|
-
*
|
|
325
|
+
* 返回值在 {@link DslOpWithHistoryIdsResult} 中同时包含原操作结果与本次写入的历史 uuid 列表,
|
|
325
326
|
* 可用于精确引用 / 定位该条历史记录(埋点、revert、跨端同步等)。
|
|
326
327
|
*
|
|
327
|
-
* 当本次操作未写入历史(doNotPushHistory 为 true
|
|
328
|
+
* 当本次操作未写入历史(doNotPushHistory 为 true、或无对应记录)时 historyIds 为 `[]`。
|
|
328
329
|
*/
|
|
329
330
|
|
|
330
|
-
/** 等价于 {@link setCodeDslById}
|
|
331
|
+
/** 等价于 {@link setCodeDslById},并额外返回本次写入历史记录的 uuid 列表(未入栈时 historyIds 为 `[]`)。 */
|
|
331
332
|
public async setCodeDslByIdAndGetHistoryId(
|
|
332
333
|
id: Id,
|
|
333
334
|
codeConfig: Partial<CodeBlockContent>,
|
|
334
335
|
options: HistoryOpOptionsWithChangeRecords = {},
|
|
335
|
-
): Promise<
|
|
336
|
+
): Promise<DslOpWithHistoryIdsResult<void>> {
|
|
336
337
|
this.lastPushedHistoryId = null;
|
|
337
338
|
await this.setCodeDslById(id, codeConfig, options);
|
|
338
|
-
return this.lastPushedHistoryId;
|
|
339
|
+
return { result: undefined, historyIds: getLastPushedHistoryIds(this.lastPushedHistoryId) };
|
|
339
340
|
}
|
|
340
341
|
|
|
341
|
-
/** 等价于 {@link setCodeDslByIdSync}
|
|
342
|
+
/** 等价于 {@link setCodeDslByIdSync},并额外返回本次写入历史记录的 uuid 列表(未入栈时 historyIds 为 `[]`)。 */
|
|
342
343
|
public setCodeDslByIdSyncAndGetHistoryId(
|
|
343
344
|
id: Id,
|
|
344
345
|
codeConfig: Partial<CodeBlockContent>,
|
|
345
346
|
force = true,
|
|
346
347
|
options: HistoryOpOptionsWithChangeRecords = {},
|
|
347
|
-
):
|
|
348
|
+
): DslOpWithHistoryIdsResult<void> {
|
|
348
349
|
this.lastPushedHistoryId = null;
|
|
349
350
|
this.setCodeDslByIdSync(id, codeConfig, force, options);
|
|
350
|
-
return this.lastPushedHistoryId;
|
|
351
|
+
return { result: undefined, historyIds: getLastPushedHistoryIds(this.lastPushedHistoryId) };
|
|
351
352
|
}
|
|
352
353
|
|
|
353
354
|
/**
|
|
354
|
-
* 等价于 {@link deleteCodeDslByIds}
|
|
355
|
-
*
|
|
355
|
+
* 等价于 {@link deleteCodeDslByIds},并额外返回本次写入的全部历史记录 uuid(按删除顺序)。
|
|
356
|
+
* 一次删除多个代码块会产生多条历史记录;未写入任何历史时 historyIds 为 `[]`。
|
|
356
357
|
*/
|
|
357
|
-
public async deleteCodeDslByIdsAndGetHistoryId(
|
|
358
|
+
public async deleteCodeDslByIdsAndGetHistoryId(
|
|
359
|
+
codeIds: Id[],
|
|
360
|
+
options: HistoryOpOptions = {},
|
|
361
|
+
): Promise<DslOpWithHistoryIdsResult<void>> {
|
|
358
362
|
this.lastDeletedHistoryIds = [];
|
|
359
363
|
await this.deleteCodeDslByIds(codeIds, options);
|
|
360
|
-
return [...this.lastDeletedHistoryIds];
|
|
364
|
+
return { result: undefined, historyIds: [...this.lastDeletedHistoryIds] };
|
|
361
365
|
}
|
|
362
366
|
// #endregion AndGetHistoryId
|
|
363
367
|
|
|
@@ -455,17 +459,19 @@ class CodeBlock extends BaseService {
|
|
|
455
459
|
}
|
|
456
460
|
|
|
457
461
|
/**
|
|
458
|
-
* 通过历史记录 uuid
|
|
459
|
-
* 仅无需调用方再传 codeBlockId 与 index:内部会按 uuid
|
|
460
|
-
*
|
|
462
|
+
* 通过历史记录 uuid 回滚代码块历史步骤,语义同 {@link revert},
|
|
463
|
+
* 仅无需调用方再传 codeBlockId 与 index:内部会按 uuid 在全部代码块栈中定位对应步骤后再回滚。
|
|
464
|
+
* 按数组顺序依次回滚,返回与入参同序的结果列表(某项失败时为 `null`)。
|
|
461
465
|
*
|
|
462
|
-
* @param
|
|
463
|
-
* @returns 反向后产生的新 step;找不到对应 uuid / 未应用时返回 null
|
|
466
|
+
* @param uuids 目标历史记录的 uuid 列表,通常由 {@link setCodeDslByIdAndGetHistoryId} 等方法返回的 `historyIds`
|
|
464
467
|
*/
|
|
465
|
-
public async revertById(
|
|
466
|
-
const
|
|
467
|
-
|
|
468
|
-
|
|
468
|
+
public async revertById(uuids: string[]): Promise<(CodeBlockStepValue | null)[]> {
|
|
469
|
+
const results: (CodeBlockStepValue | null)[] = [];
|
|
470
|
+
for (const uuid of uuids) {
|
|
471
|
+
const location = historyService.findCodeBlockStepLocationByUuid(uuid);
|
|
472
|
+
results.push(location ? await this.revert(location.id, location.index) : null);
|
|
473
|
+
}
|
|
474
|
+
return results;
|
|
469
475
|
}
|
|
470
476
|
|
|
471
477
|
/**
|