@tmagic/editor 1.8.0-beta.1 → 1.8.0-beta.2
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/Editor.vue_vue_type_script_setup_true_lang.js +11 -2
- package/dist/es/components/CodeBlockEditor.vue_vue_type_script_setup_true_lang.js +18 -110
- package/dist/es/components/CodeParams.vue_vue_type_script_setup_true_lang.js +6 -0
- package/dist/es/components/CompareForm.js +5 -0
- package/dist/es/components/CompareForm.vue_vue_type_script_setup_true_lang.js +167 -0
- package/dist/es/fields/Code.vue_vue_type_script_setup_true_lang.js +19 -3
- package/dist/es/fields/CodeSelect.vue_vue_type_script_setup_true_lang.js +18 -2
- package/dist/es/fields/CodeSelectCol.vue_vue_type_script_setup_true_lang.js +37 -6
- package/dist/es/fields/DataSourceFieldSelect/FieldSelect.vue_vue_type_script_setup_true_lang.js +3 -1
- package/dist/es/fields/DataSourceFieldSelect/Index.vue_vue_type_script_setup_true_lang.js +2 -2
- package/dist/es/fields/DataSourceFields.vue_vue_type_script_setup_true_lang.js +14 -6
- package/dist/es/fields/DataSourceMethodSelect.vue_vue_type_script_setup_true_name_true_lang.js +3 -1
- package/dist/es/fields/DataSourceMethods.vue_vue_type_script_setup_true_lang.js +15 -7
- package/dist/es/fields/DataSourceMocks.vue_vue_type_script_setup_true_lang.js +14 -6
- package/dist/es/fields/DataSourceSelect.vue_vue_type_script_setup_true_lang.js +3 -1
- package/dist/es/fields/EventSelect.vue_vue_type_script_setup_true_lang.js +58 -11
- package/dist/es/fields/KeyValue.vue_vue_type_script_setup_true_lang.js +11 -6
- package/dist/es/fields/UISelect.vue_vue_type_script_setup_true_lang.js +8 -5
- package/dist/es/hooks/use-code-block-edit.js +2 -2
- package/dist/es/hooks/use-stage.js +15 -7
- package/dist/es/index.js +3 -1
- package/dist/es/initService.js +6 -6
- package/dist/es/layouts/CodeEditor.vue_vue_type_script_setup_true_lang.js +4 -0
- package/dist/es/layouts/Framework.vue_vue_type_script_setup_true_lang.js +12 -7
- package/dist/es/layouts/NavMenu.vue_vue_type_script_setup_true_lang.js +8 -0
- package/dist/es/layouts/history-list/Bucket.js +5 -0
- package/dist/es/layouts/history-list/Bucket.vue_vue_type_script_setup_true_lang.js +84 -0
- package/dist/es/layouts/history-list/CodeBlockTab.js +5 -0
- package/dist/es/layouts/history-list/CodeBlockTab.vue_vue_type_script_setup_true_lang.js +62 -0
- package/dist/es/layouts/history-list/DataSourceTab.js +5 -0
- package/dist/es/layouts/history-list/DataSourceTab.vue_vue_type_script_setup_true_lang.js +62 -0
- package/dist/es/layouts/history-list/GroupRow.js +5 -0
- package/dist/es/layouts/history-list/GroupRow.vue_vue_type_script_setup_true_lang.js +180 -0
- package/dist/es/layouts/history-list/HistoryDiffDialog.js +5 -0
- package/dist/es/layouts/history-list/HistoryDiffDialog.vue_vue_type_script_setup_true_lang.js +195 -0
- package/dist/es/layouts/history-list/HistoryListPanel.js +5 -0
- package/dist/es/layouts/history-list/HistoryListPanel.vue_vue_type_script_setup_true_lang.js +270 -0
- package/dist/es/layouts/history-list/InitialRow.js +5 -0
- package/dist/es/layouts/history-list/InitialRow.vue_vue_type_script_setup_true_lang.js +48 -0
- package/dist/es/layouts/history-list/PageTab.js +5 -0
- package/dist/es/layouts/history-list/PageTab.vue_vue_type_script_setup_true_lang.js +99 -0
- package/dist/es/layouts/history-list/composables.js +154 -0
- package/dist/es/layouts/sidebar/layer/use-node-status.js +1 -1
- package/dist/es/services/BaseService.js +31 -68
- package/dist/es/services/codeBlock.js +205 -8
- package/dist/es/services/componentList.js +2 -2
- package/dist/es/services/dataSource.js +217 -8
- package/dist/es/services/dep.js +21 -9
- package/dist/es/services/editor.js +350 -160
- package/dist/es/services/events.js +2 -2
- package/dist/es/services/history.js +407 -12
- package/dist/es/services/keybinding.js +2 -2
- package/dist/es/services/props.js +8 -8
- package/dist/es/services/stageOverlay.js +2 -2
- package/dist/es/services/storage.js +2 -2
- package/dist/es/services/ui.js +2 -2
- package/dist/es/style.css +347 -1
- package/dist/es/utils/code-block.js +122 -0
- package/dist/es/utils/content-menu.js +4 -5
- package/dist/es/utils/dep/worker.js +1 -1
- package/dist/es/utils/editor.js +2 -2
- package/dist/es/utils/undo-redo.js +20 -0
- package/dist/style.css +347 -1
- package/dist/tmagic-editor.umd.cjs +3165 -774
- package/package.json +7 -7
- package/src/Editor.vue +7 -0
- package/src/components/CodeBlockEditor.vue +20 -109
- package/src/components/CodeParams.vue +6 -0
- package/src/components/CompareForm.vue +225 -0
- package/src/editorProps.ts +2 -0
- package/src/fields/Code.vue +19 -3
- package/src/fields/CodeSelect.vue +17 -1
- package/src/fields/CodeSelectCol.vue +30 -2
- package/src/fields/DataSourceFieldSelect/FieldSelect.vue +7 -1
- package/src/fields/DataSourceFieldSelect/Index.vue +2 -2
- package/src/fields/DataSourceFields.vue +12 -3
- package/src/fields/DataSourceMethodSelect.vue +4 -1
- package/src/fields/DataSourceMethods.vue +14 -4
- package/src/fields/DataSourceMocks.vue +13 -3
- package/src/fields/DataSourceSelect.vue +4 -1
- package/src/fields/EventSelect.vue +57 -8
- package/src/fields/KeyValue.vue +17 -4
- package/src/fields/UISelect.vue +5 -2
- package/src/hooks/use-code-block-edit.ts +5 -2
- package/src/hooks/use-stage.ts +23 -7
- package/src/index.ts +1 -0
- package/src/layouts/CodeEditor.vue +15 -0
- package/src/layouts/Framework.vue +10 -5
- package/src/layouts/NavMenu.vue +9 -0
- package/src/layouts/history-list/Bucket.vue +99 -0
- package/src/layouts/history-list/CodeBlockTab.vue +61 -0
- package/src/layouts/history-list/DataSourceTab.vue +61 -0
- package/src/layouts/history-list/GroupRow.vue +207 -0
- package/src/layouts/history-list/HistoryDiffDialog.vue +212 -0
- package/src/layouts/history-list/HistoryListPanel.vue +271 -0
- package/src/layouts/history-list/InitialRow.vue +41 -0
- package/src/layouts/history-list/PageTab.vue +94 -0
- package/src/layouts/history-list/composables.ts +195 -0
- package/src/layouts/sidebar/layer/use-node-status.ts +9 -6
- package/src/services/BaseService.ts +35 -86
- package/src/services/codeBlock.ts +256 -5
- package/src/services/dataSource.ts +257 -6
- package/src/services/dep.ts +32 -9
- package/src/services/editor.ts +454 -171
- package/src/services/history.ts +452 -8
- package/src/services/props.ts +2 -2
- package/src/theme/history-list-panel.scss +423 -0
- package/src/theme/theme.scss +1 -0
- package/src/type.ts +179 -6
- package/src/utils/code-block.ts +150 -0
- package/src/utils/content-menu.ts +8 -5
- package/src/utils/dep/worker.ts +5 -3
- package/src/utils/index.ts +1 -0
- package/src/utils/undo-redo.ts +23 -0
- package/types/index.d.ts +2105 -810
- package/dist/es/utils/compose.js +0 -44
- package/dist/es/utils/editor-history.js +0 -100
- package/src/utils/compose.ts +0 -52
- package/src/utils/editor-history.ts +0 -138
|
@@ -4,12 +4,19 @@ import type { Writable } from 'type-fest';
|
|
|
4
4
|
|
|
5
5
|
import type { DataSourceSchema, EventOption, Id, MNode, TargetOptions } from '@tmagic/core';
|
|
6
6
|
import { Target, Watcher } from '@tmagic/core';
|
|
7
|
-
import type {
|
|
8
|
-
import { guid, toLine } from '@tmagic/utils';
|
|
7
|
+
import type { FormConfig } from '@tmagic/form';
|
|
8
|
+
import { getValueByKeyPath, guid, setValueByKeyPath, toLine } from '@tmagic/utils';
|
|
9
9
|
|
|
10
10
|
import editorService from '@editor/services/editor';
|
|
11
|
+
import historyService from '@editor/services/history';
|
|
11
12
|
import storageService, { Protocol } from '@editor/services/storage';
|
|
12
|
-
import type {
|
|
13
|
+
import type {
|
|
14
|
+
DataSourceStepValue,
|
|
15
|
+
DatasourceTypeOption,
|
|
16
|
+
HistoryOpOptions,
|
|
17
|
+
HistoryOpOptionsWithChangeRecords,
|
|
18
|
+
SyncHookPlugin,
|
|
19
|
+
} from '@editor/type';
|
|
13
20
|
import { getFormConfig, getFormValue } from '@editor/utils/data-source';
|
|
14
21
|
import { COPY_DS_STORAGE_KEY } from '@editor/utils/editor';
|
|
15
22
|
|
|
@@ -47,6 +54,19 @@ const canUsePluginMethods = {
|
|
|
47
54
|
|
|
48
55
|
type SyncMethodName = Writable<(typeof canUsePluginMethods)['sync']>;
|
|
49
56
|
|
|
57
|
+
/**
|
|
58
|
+
* 「回滚」生成的新 step 简短描述。
|
|
59
|
+
* 仅在 service 层使用,避免依赖 UI 层 composables。
|
|
60
|
+
*/
|
|
61
|
+
const describeRevertDataSourceStep = (step: DataSourceStepValue): string => {
|
|
62
|
+
const { oldSchema, newSchema, changeRecords, id } = step;
|
|
63
|
+
if (oldSchema === null && newSchema) return `撤回新增 ${newSchema.title || newSchema.id || id}`;
|
|
64
|
+
if (oldSchema && newSchema === null) return `还原已删除的 ${oldSchema.title || oldSchema.id || id}`;
|
|
65
|
+
const title = newSchema?.title || oldSchema?.title || `${id}`;
|
|
66
|
+
const propPath = changeRecords?.[0]?.propPath;
|
|
67
|
+
return propPath ? `还原 ${title} · ${propPath}` : `还原 ${title}`;
|
|
68
|
+
};
|
|
69
|
+
|
|
50
70
|
class DataSource extends BaseService {
|
|
51
71
|
private state = reactive<State>({
|
|
52
72
|
datasourceTypeList: [],
|
|
@@ -102,7 +122,14 @@ class DataSource extends BaseService {
|
|
|
102
122
|
this.get('methods')[toLine(type)] = value;
|
|
103
123
|
}
|
|
104
124
|
|
|
105
|
-
|
|
125
|
+
/**
|
|
126
|
+
* 新增数据源
|
|
127
|
+
* @param config 数据源配置
|
|
128
|
+
* @param options 可选配置
|
|
129
|
+
* @param options.doNotPushHistory 是否不写入历史记录(默认 false)
|
|
130
|
+
* @param options.historyDescription 入栈时附带的人类可读描述,用于历史面板展示
|
|
131
|
+
*/
|
|
132
|
+
public add(config: DataSourceSchema, { doNotPushHistory = false, historyDescription }: HistoryOpOptions = {}) {
|
|
106
133
|
const newConfig = {
|
|
107
134
|
...config,
|
|
108
135
|
id: config.id && !this.getDataSourceById(config.id) ? config.id : this.createId(),
|
|
@@ -110,12 +137,27 @@ class DataSource extends BaseService {
|
|
|
110
137
|
|
|
111
138
|
this.get('dataSources').push(newConfig);
|
|
112
139
|
|
|
140
|
+
if (!doNotPushHistory) {
|
|
141
|
+
historyService.pushDataSource(newConfig.id, { oldSchema: null, newSchema: newConfig, historyDescription });
|
|
142
|
+
}
|
|
143
|
+
|
|
113
144
|
this.emit('add', newConfig);
|
|
114
145
|
|
|
115
146
|
return newConfig;
|
|
116
147
|
}
|
|
117
148
|
|
|
118
|
-
|
|
149
|
+
/**
|
|
150
|
+
* 更新数据源
|
|
151
|
+
* @param config 数据源配置
|
|
152
|
+
* @param data 额外数据
|
|
153
|
+
* @param data.changeRecords form 端变更记录
|
|
154
|
+
* @param data.doNotPushHistory 是否不写入历史记录(默认 false)
|
|
155
|
+
* @param data.historyDescription 入栈时附带的人类可读描述,用于历史面板展示
|
|
156
|
+
*/
|
|
157
|
+
public update(
|
|
158
|
+
config: DataSourceSchema,
|
|
159
|
+
{ changeRecords = [], doNotPushHistory = false, historyDescription }: HistoryOpOptionsWithChangeRecords = {},
|
|
160
|
+
) {
|
|
119
161
|
const dataSources = this.get('dataSources');
|
|
120
162
|
|
|
121
163
|
const index = dataSources.findIndex((ds) => ds.id === config.id);
|
|
@@ -125,6 +167,15 @@ class DataSource extends BaseService {
|
|
|
125
167
|
|
|
126
168
|
dataSources[index] = newConfig;
|
|
127
169
|
|
|
170
|
+
if (!doNotPushHistory) {
|
|
171
|
+
historyService.pushDataSource(newConfig.id, {
|
|
172
|
+
oldSchema: oldConfig ? cloneDeep(oldConfig) : null,
|
|
173
|
+
newSchema: newConfig,
|
|
174
|
+
changeRecords,
|
|
175
|
+
historyDescription,
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
|
|
128
179
|
this.emit('update', newConfig, {
|
|
129
180
|
oldConfig,
|
|
130
181
|
changeRecords,
|
|
@@ -133,14 +184,104 @@ class DataSource extends BaseService {
|
|
|
133
184
|
return newConfig;
|
|
134
185
|
}
|
|
135
186
|
|
|
136
|
-
|
|
187
|
+
/**
|
|
188
|
+
* 删除数据源
|
|
189
|
+
* @param id 数据源 id
|
|
190
|
+
* @param options 可选配置
|
|
191
|
+
* @param options.doNotPushHistory 是否不写入历史记录(默认 false)
|
|
192
|
+
* @param options.historyDescription 入栈时附带的人类可读描述,用于历史面板展示
|
|
193
|
+
*/
|
|
194
|
+
public remove(id: string, { doNotPushHistory = false, historyDescription }: HistoryOpOptions = {}) {
|
|
137
195
|
const dataSources = this.get('dataSources');
|
|
138
196
|
const index = dataSources.findIndex((ds) => ds.id === id);
|
|
197
|
+
const oldConfig = index !== -1 ? dataSources[index] : null;
|
|
139
198
|
dataSources.splice(index, 1);
|
|
140
199
|
|
|
200
|
+
if (oldConfig && !doNotPushHistory) {
|
|
201
|
+
historyService.pushDataSource(id, { oldSchema: cloneDeep(oldConfig), newSchema: null, historyDescription });
|
|
202
|
+
}
|
|
203
|
+
|
|
141
204
|
this.emit('remove', id);
|
|
142
205
|
}
|
|
143
206
|
|
|
207
|
+
/**
|
|
208
|
+
* 撤销指定数据源的最近一次变更。
|
|
209
|
+
*
|
|
210
|
+
* 内部走 add / update / remove,因此会自动触发 dataSourceService 的事件,
|
|
211
|
+
* 由 initService 中的对应 handler 重新收集 dep(DATA_SOURCE / DATA_SOURCE_COND / DATA_SOURCE_METHOD)。
|
|
212
|
+
* 所有写回都带 `doNotPushHistory: true`,避免在历史栈里产生新的记录。
|
|
213
|
+
*
|
|
214
|
+
* @param id 数据源 id
|
|
215
|
+
* @returns 撤销的 step;栈不存在或已无可撤销时返回 null
|
|
216
|
+
*/
|
|
217
|
+
public undo(id: Id) {
|
|
218
|
+
const step = historyService.undoDataSource(id);
|
|
219
|
+
if (!step) return null;
|
|
220
|
+
this.applyHistoryStep(step, true);
|
|
221
|
+
return step;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* 重做指定数据源的下一次变更。
|
|
226
|
+
* @param id 数据源 id
|
|
227
|
+
* @returns 重做的 step;栈不存在或已无可重做时返回 null
|
|
228
|
+
*/
|
|
229
|
+
public redo(id: Id) {
|
|
230
|
+
const step = historyService.redoDataSource(id);
|
|
231
|
+
if (!step) return null;
|
|
232
|
+
this.applyHistoryStep(step, false);
|
|
233
|
+
return step;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/** 是否可对指定数据源撤销。 */
|
|
237
|
+
public canUndo(id: Id): boolean {
|
|
238
|
+
return historyService.canUndoDataSource(id);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/** 是否可对指定数据源重做。 */
|
|
242
|
+
public canRedo(id: Id): boolean {
|
|
243
|
+
return historyService.canRedoDataSource(id);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* 跳转指定数据源的历史栈到目标游标。语义同 editor.gotoPageStep。
|
|
248
|
+
*
|
|
249
|
+
* @param id 数据源 id
|
|
250
|
+
* @param targetCursor 目标游标位置(已应用步骤数量)
|
|
251
|
+
* @returns 实际移动到的最终游标位置
|
|
252
|
+
*/
|
|
253
|
+
public goto(id: Id, targetCursor: number): number {
|
|
254
|
+
let cursor = historyService.getDataSourceCursor(id);
|
|
255
|
+
const target = Math.max(0, targetCursor);
|
|
256
|
+
while (cursor > target) {
|
|
257
|
+
if (!this.undo(id)) break;
|
|
258
|
+
cursor -= 1;
|
|
259
|
+
}
|
|
260
|
+
while (cursor < target) {
|
|
261
|
+
if (!this.redo(id)) break;
|
|
262
|
+
cursor += 1;
|
|
263
|
+
}
|
|
264
|
+
return cursor;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* 「回滚」指定数据源历史步骤(类 git revert 语义):
|
|
269
|
+
* - 不动原始栈结构(不移动 cursor、不丢弃任何步骤);
|
|
270
|
+
* - 把目标 step 的修改**反向应用**一次,并作为**新步骤**追加到栈顶;
|
|
271
|
+
* - 仅对已应用的步骤生效——未应用步骤本身就不存在于当前 schema 中,反向无意义。
|
|
272
|
+
*
|
|
273
|
+
* @param id 数据源 id
|
|
274
|
+
* @param index 目标 step 在该栈中的索引(0 为最早),通常由历史面板传入
|
|
275
|
+
* @returns 反向后产生的新 step;目标不存在 / 未应用时返回 null
|
|
276
|
+
*/
|
|
277
|
+
public revert(id: Id, index: number): DataSourceStepValue | null {
|
|
278
|
+
const list = historyService.getDataSourceStepList(id);
|
|
279
|
+
const entry = list[index];
|
|
280
|
+
if (!entry?.applied) return null;
|
|
281
|
+
const description = `回滚 #${index + 1}: ${describeRevertDataSourceStep(entry.step)}`;
|
|
282
|
+
return this.applyRevertStep(entry.step, description);
|
|
283
|
+
}
|
|
284
|
+
|
|
144
285
|
public createId(): string {
|
|
145
286
|
return `ds_${guid()}`;
|
|
146
287
|
}
|
|
@@ -215,6 +356,116 @@ class DataSource extends BaseService {
|
|
|
215
356
|
}
|
|
216
357
|
});
|
|
217
358
|
}
|
|
359
|
+
|
|
360
|
+
/**
|
|
361
|
+
* 反向应用一个 step 并以新 step 入栈(不带 doNotPushHistory)。逻辑与 applyHistoryStep(reverse=true)
|
|
362
|
+
* 同构,差异仅在于走对应的公共 add / update / remove 而不是带 doNotPushHistory 的版本。
|
|
363
|
+
*/
|
|
364
|
+
private applyRevertStep(step: DataSourceStepValue, historyDescription: string): DataSourceStepValue | null {
|
|
365
|
+
const { id, oldSchema, newSchema, changeRecords } = step;
|
|
366
|
+
|
|
367
|
+
// 原本是新增 → revert 即删除
|
|
368
|
+
if (oldSchema === null && newSchema) {
|
|
369
|
+
this.remove(`${id}`, { historyDescription });
|
|
370
|
+
return historyService.getDataSourceStepList(id).slice(-1)[0]?.step ?? null;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
// 原本是删除 → revert 即重新加回
|
|
374
|
+
if (oldSchema && newSchema === null) {
|
|
375
|
+
this.add(cloneDeep(oldSchema), { historyDescription });
|
|
376
|
+
return historyService.getDataSourceStepList(id).slice(-1)[0]?.step ?? null;
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
if (!oldSchema || !newSchema) return null;
|
|
380
|
+
|
|
381
|
+
// 原本是更新 → 把 oldSchema 写回;优先按 changeRecords 局部 patch
|
|
382
|
+
if (changeRecords?.length) {
|
|
383
|
+
const current = this.getDataSourceById(`${id}`);
|
|
384
|
+
if (!current) return null;
|
|
385
|
+
const patched = cloneDeep(current) as DataSourceSchema;
|
|
386
|
+
let fallbackToFullReplace = false;
|
|
387
|
+
for (const record of changeRecords) {
|
|
388
|
+
if (!record.propPath) {
|
|
389
|
+
fallbackToFullReplace = true;
|
|
390
|
+
break;
|
|
391
|
+
}
|
|
392
|
+
const value = cloneDeep(getValueByKeyPath(record.propPath, oldSchema));
|
|
393
|
+
setValueByKeyPath(record.propPath, value, patched);
|
|
394
|
+
}
|
|
395
|
+
this.update(fallbackToFullReplace ? cloneDeep(oldSchema) : patched, {
|
|
396
|
+
changeRecords,
|
|
397
|
+
historyDescription,
|
|
398
|
+
});
|
|
399
|
+
return historyService.getDataSourceStepList(id).slice(-1)[0]?.step ?? null;
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
this.update(cloneDeep(oldSchema), { historyDescription });
|
|
403
|
+
return historyService.getDataSourceStepList(id).slice(-1)[0]?.step ?? null;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
/**
|
|
407
|
+
* 把一条历史 step 应用到当前数据源服务上。
|
|
408
|
+
*
|
|
409
|
+
* 复用现有的 add / update / remove,目的是借助它们发出的事件触发 initService 中
|
|
410
|
+
* 的依赖收集逻辑(DATA_SOURCE / DATA_SOURCE_COND / DATA_SOURCE_METHOD)。
|
|
411
|
+
* 所有写回都带 `doNotPushHistory: true`,确保不会在历史栈里产生新的记录。
|
|
412
|
+
*
|
|
413
|
+
* - oldSchema=null, newSchema≠null:原始为新增 → undo 删除;redo 再次 add
|
|
414
|
+
* - oldSchema≠null, newSchema=null:原始为删除 → undo 还原 add;redo 再次删除
|
|
415
|
+
* - 两侧都有:原始为更新 → 按 changeRecords 局部 patch;缺省退化为整 schema 替换
|
|
416
|
+
*
|
|
417
|
+
* @param step 历史 step
|
|
418
|
+
* @param reverse true=撤销,false=重做
|
|
419
|
+
*/
|
|
420
|
+
private applyHistoryStep(step: DataSourceStepValue, reverse: boolean): void {
|
|
421
|
+
const { id, oldSchema, newSchema, changeRecords } = step;
|
|
422
|
+
|
|
423
|
+
// 新增 / 删除:直接 add 或 remove,不走 patch 逻辑
|
|
424
|
+
if (oldSchema === null && newSchema) {
|
|
425
|
+
if (reverse) {
|
|
426
|
+
this.remove(`${id}`, { doNotPushHistory: true });
|
|
427
|
+
} else {
|
|
428
|
+
this.add(cloneDeep(newSchema), { doNotPushHistory: true });
|
|
429
|
+
}
|
|
430
|
+
return;
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
if (oldSchema && newSchema === null) {
|
|
434
|
+
if (reverse) {
|
|
435
|
+
this.add(cloneDeep(oldSchema), { doNotPushHistory: true });
|
|
436
|
+
} else {
|
|
437
|
+
this.remove(`${id}`, { doNotPushHistory: true });
|
|
438
|
+
}
|
|
439
|
+
return;
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
if (!oldSchema || !newSchema) return;
|
|
443
|
+
|
|
444
|
+
// 更新场景:优先按 changeRecords 局部 patch;缺省退化为整 schema 替换
|
|
445
|
+
const sourceForValues = reverse ? oldSchema : newSchema;
|
|
446
|
+
|
|
447
|
+
if (changeRecords?.length) {
|
|
448
|
+
const current = this.getDataSourceById(`${id}`);
|
|
449
|
+
if (!current) return;
|
|
450
|
+
const patched = cloneDeep(current) as DataSourceSchema;
|
|
451
|
+
let fallbackToFullReplace = false;
|
|
452
|
+
for (const record of changeRecords) {
|
|
453
|
+
if (!record.propPath) {
|
|
454
|
+
fallbackToFullReplace = true;
|
|
455
|
+
break;
|
|
456
|
+
}
|
|
457
|
+
const value = cloneDeep(getValueByKeyPath(record.propPath, sourceForValues));
|
|
458
|
+
setValueByKeyPath(record.propPath, value, patched);
|
|
459
|
+
}
|
|
460
|
+
this.update(fallbackToFullReplace ? cloneDeep(sourceForValues) : patched, {
|
|
461
|
+
changeRecords,
|
|
462
|
+
doNotPushHistory: true,
|
|
463
|
+
});
|
|
464
|
+
return;
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
this.update(cloneDeep(sourceForValues), { doNotPushHistory: true });
|
|
468
|
+
}
|
|
218
469
|
}
|
|
219
470
|
|
|
220
471
|
export type DataSourceService = DataSource;
|
package/src/services/dep.ts
CHANGED
|
@@ -109,9 +109,23 @@ class Dep extends BaseService {
|
|
|
109
109
|
|
|
110
110
|
public collect(nodes: MNode[], depExtendedData: DepExtendedData = {}, deep = false, type?: DepTargetType) {
|
|
111
111
|
this.set('collecting', true);
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
112
|
+
|
|
113
|
+
const targets = this.watcher.getCollectableTargets(type);
|
|
114
|
+
|
|
115
|
+
if (targets.length) {
|
|
116
|
+
for (const node of nodes) {
|
|
117
|
+
// 先删除原有依赖,再批量收集
|
|
118
|
+
if (isPage(node)) {
|
|
119
|
+
for (const target of targets) {
|
|
120
|
+
this.removePageDep(target, depExtendedData);
|
|
121
|
+
}
|
|
122
|
+
} else {
|
|
123
|
+
this.watcher.removeTargetsDep(targets, node);
|
|
124
|
+
}
|
|
125
|
+
this.watcher.collectItems(node, targets, depExtendedData, deep);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
115
129
|
this.set('collecting', false);
|
|
116
130
|
|
|
117
131
|
this.emit('collected', nodes, deep);
|
|
@@ -176,7 +190,7 @@ class Dep extends BaseService {
|
|
|
176
190
|
dsl.dataSourceDeps[target.id] = target.deps;
|
|
177
191
|
} else if (target.type === DepTargetType.DATA_SOURCE_COND && dsl.dataSourceCondDeps) {
|
|
178
192
|
dsl.dataSourceCondDeps[target.id] = target.deps;
|
|
179
|
-
} else if (target.type === DepTargetType.DATA_SOURCE_METHOD) {
|
|
193
|
+
} else if (target.type === DepTargetType.DATA_SOURCE_METHOD && dsl.dataSourceMethodDeps) {
|
|
180
194
|
dsl.dataSourceMethodDeps[target.id] = target.deps;
|
|
181
195
|
}
|
|
182
196
|
}
|
|
@@ -194,11 +208,7 @@ class Dep extends BaseService {
|
|
|
194
208
|
public collectNode(node: MNode, target: Target, depExtendedData: DepExtendedData = {}, deep = false) {
|
|
195
209
|
// 先删除原有依赖,重新收集
|
|
196
210
|
if (isPage(node)) {
|
|
197
|
-
|
|
198
|
-
if (dep.data?.pageId && dep.data.pageId === depExtendedData.pageId) {
|
|
199
|
-
delete target.deps[depKey];
|
|
200
|
-
}
|
|
201
|
-
}
|
|
211
|
+
this.removePageDep(target, depExtendedData);
|
|
202
212
|
} else {
|
|
203
213
|
this.watcher.removeTargetDep(target, node);
|
|
204
214
|
}
|
|
@@ -263,6 +273,19 @@ class Dep extends BaseService {
|
|
|
263
273
|
return super.emit(eventName, ...args);
|
|
264
274
|
}
|
|
265
275
|
|
|
276
|
+
/**
|
|
277
|
+
* 删除指定 page 在该 target 下的旧依赖:
|
|
278
|
+
* 按 pageId 匹配,可清掉页面内已被删除节点的残留依赖
|
|
279
|
+
*/
|
|
280
|
+
private removePageDep(target: Target, depExtendedData: DepExtendedData = {}) {
|
|
281
|
+
for (const depKey of Object.keys(target.deps)) {
|
|
282
|
+
const dep = target.deps[depKey];
|
|
283
|
+
if (dep.data?.pageId && dep.data.pageId === depExtendedData.pageId) {
|
|
284
|
+
delete target.deps[depKey];
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
266
289
|
private enqueueTask(node: MNode, target: Target, depExtendedData: DepExtendedData, deep: boolean) {
|
|
267
290
|
this.idleTask.enqueueTask(
|
|
268
291
|
({ node, deep, target }) => {
|