@tmagic/editor 1.8.0-beta.4 → 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/components/CompareForm.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/es/components/ToolButton.vue_vue_type_script_setup_true_lang.js +6 -6
- 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 +6 -3
- package/dist/es/initService.js +1 -1
- package/dist/es/layouts/Framework.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/es/layouts/history-list/Bucket.vue_vue_type_script_setup_true_lang.js +19 -55
- package/dist/es/layouts/history-list/BucketTab.vue_vue_type_script_setup_true_lang.js +22 -39
- package/dist/es/layouts/history-list/GroupRow.vue_vue_type_script_setup_true_lang.js +149 -103
- package/dist/es/layouts/history-list/HistoryDiffDialog.vue_vue_type_script_setup_true_lang.js +32 -8
- package/dist/es/layouts/history-list/HistoryListPanel.vue_vue_type_script_setup_true_lang.js +335 -213
- package/dist/es/layouts/history-list/InitialRow.vue_vue_type_script_setup_true_lang.js +36 -7
- package/dist/es/layouts/history-list/PageTab.vue_vue_type_script_setup_true_lang.js +47 -60
- package/dist/es/layouts/history-list/composables.js +73 -32
- package/dist/es/layouts/page-bar/PageBar.vue_vue_type_script_setup_true_lang.js +4 -2
- package/dist/es/layouts/sidebar/Sidebar.vue_vue_type_script_setup_true_lang.js +5 -1
- 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 +96 -37
- package/dist/es/services/dataSource.js +70 -26
- package/dist/es/services/editor.js +266 -104
- package/dist/es/services/history.js +271 -212
- package/dist/es/services/ui.js +3 -0
- package/dist/es/style.css +53 -7
- package/dist/es/utils/data-source/index.js +2 -0
- package/dist/es/utils/editor.js +103 -49
- package/dist/es/utils/history.js +232 -0
- package/dist/es/utils/indexed-db.js +86 -0
- package/dist/es/utils/undo-redo.js +60 -1
- package/dist/style.css +53 -7
- package/dist/tmagic-editor.umd.cjs +2064 -1000
- package/package.json +7 -7
- package/src/components/CompareForm.vue +3 -1
- package/src/components/ToolButton.vue +2 -2
- 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/index.ts +1 -0
- package/src/initService.ts +1 -1
- package/src/layouts/Framework.vue +1 -1
- package/src/layouts/history-list/Bucket.vue +34 -71
- package/src/layouts/history-list/BucketTab.vue +46 -54
- package/src/layouts/history-list/GroupRow.vue +146 -111
- package/src/layouts/history-list/HistoryDiffDialog.vue +94 -68
- package/src/layouts/history-list/HistoryListPanel.vue +298 -115
- package/src/layouts/history-list/InitialRow.vue +28 -9
- package/src/layouts/history-list/PageTab.vue +57 -51
- package/src/layouts/history-list/composables.ts +157 -36
- package/src/layouts/page-bar/PageBar.vue +4 -2
- package/src/layouts/sidebar/Sidebar.vue +6 -1
- 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 +113 -37
- package/src/services/dataSource.ts +94 -40
- package/src/services/editor.ts +376 -136
- package/src/services/history.ts +306 -209
- package/src/services/ui.ts +7 -0
- package/src/theme/history-list-panel.scss +72 -5
- package/src/theme/page-bar.scss +0 -4
- package/src/theme/style-setter/border.scss +4 -1
- package/src/type.ts +183 -64
- package/src/utils/data-source/index.ts +2 -0
- package/src/utils/editor.ts +166 -60
- package/src/utils/history.ts +308 -0
- package/src/utils/index.ts +2 -0
- package/src/utils/indexed-db.ts +122 -0
- package/src/utils/undo-redo.ts +88 -0
- package/types/index.d.ts +813 -302
|
@@ -4917,8 +4917,41 @@
|
|
|
4917
4917
|
};
|
|
4918
4918
|
var props_default = new Props();
|
|
4919
4919
|
//#endregion
|
|
4920
|
+
//#region packages/editor/src/utils/config.ts
|
|
4921
|
+
var $TMAGIC_EDITOR = {};
|
|
4922
|
+
var setEditorConfig = (option) => {
|
|
4923
|
+
$TMAGIC_EDITOR = option;
|
|
4924
|
+
};
|
|
4925
|
+
var getEditorConfig = (key) => $TMAGIC_EDITOR[key];
|
|
4926
|
+
//#endregion
|
|
4920
4927
|
//#region packages/editor/src/utils/undo-redo.ts
|
|
4921
|
-
var UndoRedo = class {
|
|
4928
|
+
var UndoRedo = class UndoRedo {
|
|
4929
|
+
/**
|
|
4930
|
+
* 由 {@link UndoRedo.serialize} 产出的快照重建一个 UndoRedo 实例。
|
|
4931
|
+
* 游标会被夹紧到 [0, length] 区间,避免脏数据导致越界。
|
|
4932
|
+
*
|
|
4933
|
+
* @param options.isSavedStep 可选谓词:若提供,则把游标定位到「最近一条满足该谓词的记录」之后
|
|
4934
|
+
* (即恢复到最近一个已保存点);找不到匹配记录时退回快照中的原游标。
|
|
4935
|
+
*/
|
|
4936
|
+
static fromSerialized(data, options = {}) {
|
|
4937
|
+
const undoRedo = new UndoRedo(data.listMaxSize);
|
|
4938
|
+
const list = Array.isArray(data.elementList) ? data.elementList.map((item) => cloneDeep$1(item)) : [];
|
|
4939
|
+
let cursor = Number.isFinite(data.listCursor) ? data.listCursor : list.length;
|
|
4940
|
+
const overflow = list.length - undoRedo.listMaxSize;
|
|
4941
|
+
if (overflow > 0) {
|
|
4942
|
+
list.splice(0, overflow);
|
|
4943
|
+
cursor -= overflow;
|
|
4944
|
+
}
|
|
4945
|
+
if (options.isSavedStep) {
|
|
4946
|
+
for (let i = list.length - 1; i >= 0; i--) if (options.isSavedStep(list[i])) {
|
|
4947
|
+
cursor = i + 1;
|
|
4948
|
+
break;
|
|
4949
|
+
}
|
|
4950
|
+
}
|
|
4951
|
+
undoRedo.elementList = list;
|
|
4952
|
+
undoRedo.listCursor = Math.max(0, Math.min(cursor, list.length));
|
|
4953
|
+
return undoRedo;
|
|
4954
|
+
}
|
|
4922
4955
|
elementList;
|
|
4923
4956
|
listCursor;
|
|
4924
4957
|
listMaxSize;
|
|
@@ -4928,6 +4961,17 @@
|
|
|
4928
4961
|
this.listCursor = 0;
|
|
4929
4962
|
this.listMaxSize = listMaxSize > minListMaxSize ? listMaxSize : minListMaxSize;
|
|
4930
4963
|
}
|
|
4964
|
+
/**
|
|
4965
|
+
* 导出当前栈的可序列化快照(深克隆,避免外部改动污染内部状态)。
|
|
4966
|
+
* 配合 {@link UndoRedo.fromSerialized} 可在持久化后完整还原撤销/重做栈。
|
|
4967
|
+
*/
|
|
4968
|
+
serialize() {
|
|
4969
|
+
return {
|
|
4970
|
+
elementList: this.elementList.map((item) => cloneDeep$1(item)),
|
|
4971
|
+
listCursor: this.listCursor,
|
|
4972
|
+
listMaxSize: this.listMaxSize
|
|
4973
|
+
};
|
|
4974
|
+
}
|
|
4931
4975
|
pushElement(element) {
|
|
4932
4976
|
this.elementList.splice(this.listCursor, this.elementList.length - this.listCursor, cloneDeep$1(element));
|
|
4933
4977
|
this.listCursor += 1;
|
|
@@ -4960,6 +5004,28 @@
|
|
|
4960
5004
|
return cloneDeep$1(this.elementList[this.listCursor - 1]);
|
|
4961
5005
|
}
|
|
4962
5006
|
/**
|
|
5007
|
+
* 用 `element` 替换当前游标所在元素(cursor - 1),并丢弃其后的重做尾部(与 {@link pushElement} 的丢尾一致),
|
|
5008
|
+
* 游标位置保持不变(元素数量不增)。cursor 为 0(无已应用元素)时不做任何操作并返回 false。
|
|
5009
|
+
* 用于「连续同类记录合并」等就地替换最新一条的场景。
|
|
5010
|
+
*/
|
|
5011
|
+
replaceCurrentElement(element) {
|
|
5012
|
+
if (this.listCursor < 1) return false;
|
|
5013
|
+
this.elementList.splice(this.listCursor - 1, this.elementList.length - (this.listCursor - 1), cloneDeep$1(element));
|
|
5014
|
+
return true;
|
|
5015
|
+
}
|
|
5016
|
+
/**
|
|
5017
|
+
* 对当前游标所在元素(cursor - 1)做就地更新;cursor 为 0(全部已撤销)时不做任何操作。
|
|
5018
|
+
* 用于给「当前步骤」打标记(如标记为已保存)等元数据写入场景。
|
|
5019
|
+
*/
|
|
5020
|
+
updateCurrentElement(updater) {
|
|
5021
|
+
if (this.listCursor < 1) return;
|
|
5022
|
+
updater(this.elementList[this.listCursor - 1]);
|
|
5023
|
+
}
|
|
5024
|
+
/** 对栈内全部元素做就地更新。用于批量清理元数据(如清空所有元素的已保存标记)。 */
|
|
5025
|
+
updateElements(updater) {
|
|
5026
|
+
this.elementList.forEach(updater);
|
|
5027
|
+
}
|
|
5028
|
+
/**
|
|
4963
5029
|
* 返回栈内全部元素的浅克隆数组(按时间顺序,索引 0 为最早一步)。
|
|
4964
5030
|
* 仅用于历史面板等只读展示场景,不应直接修改返回值。
|
|
4965
5031
|
*/
|
|
@@ -4981,172 +5047,325 @@
|
|
|
4981
5047
|
}
|
|
4982
5048
|
};
|
|
4983
5049
|
//#endregion
|
|
4984
|
-
//#region packages/editor/src/
|
|
4985
|
-
|
|
4986
|
-
|
|
4987
|
-
|
|
4988
|
-
|
|
4989
|
-
|
|
4990
|
-
|
|
4991
|
-
|
|
4992
|
-
|
|
4993
|
-
|
|
4994
|
-
|
|
4995
|
-
|
|
4996
|
-
|
|
4997
|
-
|
|
4998
|
-
|
|
4999
|
-
|
|
5000
|
-
|
|
5001
|
-
|
|
5002
|
-
|
|
5003
|
-
|
|
5004
|
-
|
|
5005
|
-
|
|
5006
|
-
|
|
5007
|
-
|
|
5008
|
-
|
|
5009
|
-
|
|
5010
|
-
|
|
5011
|
-
|
|
5012
|
-
|
|
5013
|
-
|
|
5014
|
-
|
|
5015
|
-
|
|
5016
|
-
|
|
5017
|
-
|
|
5018
|
-
|
|
5019
|
-
|
|
5020
|
-
|
|
5021
|
-
|
|
5022
|
-
|
|
5023
|
-
|
|
5024
|
-
|
|
5025
|
-
|
|
5026
|
-
|
|
5027
|
-
|
|
5028
|
-
|
|
5029
|
-
|
|
5030
|
-
|
|
5031
|
-
|
|
5032
|
-
|
|
5033
|
-
|
|
5034
|
-
|
|
5035
|
-
|
|
5036
|
-
|
|
5037
|
-
|
|
5038
|
-
|
|
5039
|
-
|
|
5040
|
-
|
|
5041
|
-
|
|
5042
|
-
|
|
5043
|
-
|
|
5044
|
-
|
|
5045
|
-
|
|
5046
|
-
|
|
5047
|
-
|
|
5048
|
-
|
|
5049
|
-
|
|
5050
|
-
|
|
5051
|
-
|
|
5052
|
-
|
|
5053
|
-
|
|
5054
|
-
|
|
5055
|
-
|
|
5056
|
-
|
|
5057
|
-
|
|
5058
|
-
|
|
5059
|
-
|
|
5060
|
-
|
|
5061
|
-
|
|
5062
|
-
|
|
5063
|
-
/**
|
|
5064
|
-
* 根据 old/new 是否为 null 推断 opType(与 push 时的约定一致)。
|
|
5065
|
-
*/
|
|
5066
|
-
static detectOpType(oldVal, newVal) {
|
|
5067
|
-
if (oldVal === null && newVal !== null) return "add";
|
|
5068
|
-
if (oldVal !== null && newVal === null) return "remove";
|
|
5069
|
-
return "update";
|
|
5070
|
-
}
|
|
5071
|
-
/**
|
|
5072
|
-
* 把页面栈拆成若干 group:
|
|
5073
|
-
* - 单节点的 'update' 按 targetId 与相邻同 targetId 的 update 合并到一个 group;
|
|
5074
|
-
* - 'add' / 'remove' 始终独立成组(语义上是结构变更,不应被收纳进单节点修改组);
|
|
5075
|
-
* - 多节点 'update'(如批量改属性)也独立成组(无明确单一目标,避免误合并)。
|
|
5076
|
-
*/
|
|
5077
|
-
static mergePageSteps(pageId, list, cursor) {
|
|
5078
|
-
const groups = [];
|
|
5079
|
-
let current = null;
|
|
5080
|
-
const currentIndex = cursor - 1;
|
|
5081
|
-
list.forEach((step, index) => {
|
|
5082
|
-
const applied = index < cursor;
|
|
5083
|
-
const isCurrent = index === currentIndex;
|
|
5084
|
-
const targetId = History.detectPageTargetId(step);
|
|
5085
|
-
const targetName = History.detectPageTargetName(step);
|
|
5086
|
-
const entry = {
|
|
5050
|
+
//#region packages/editor/src/utils/history.ts
|
|
5051
|
+
/**
|
|
5052
|
+
* 「回滚」生成的新 step 简短描述。代码块 / 数据源共用。
|
|
5053
|
+
* 二者逻辑一致,仅展示名取值字段不同(代码块取 `name`,数据源取 `title`),
|
|
5054
|
+
* 因此通过 `getLabel` 注入取值方式。
|
|
5055
|
+
*
|
|
5056
|
+
* @param id 关联的代码块 / 数据源 id
|
|
5057
|
+
* @param diff 单条变更 diff(缺省视为空)
|
|
5058
|
+
* @param getLabel 从快照取展示名
|
|
5059
|
+
*/
|
|
5060
|
+
var describeRevertStep = (id, { oldSchema, newSchema, changeRecords } = {}, getLabel) => {
|
|
5061
|
+
const labelOf = (schema) => getLabel(schema) || schema.id;
|
|
5062
|
+
if (!oldSchema && newSchema) return `撤回新增 ${labelOf(newSchema) || id}`;
|
|
5063
|
+
if (oldSchema && !newSchema) return `还原已删除的 ${labelOf(oldSchema) || id}`;
|
|
5064
|
+
const label = newSchema && getLabel(newSchema) || oldSchema && getLabel(oldSchema) || `${id}`;
|
|
5065
|
+
const propPath = changeRecords?.[0]?.propPath;
|
|
5066
|
+
return propPath ? `还原 ${label} · ${propPath}` : `还原 ${label}`;
|
|
5067
|
+
};
|
|
5068
|
+
/**
|
|
5069
|
+
* 根据 old/new 是否为 null 推断 opType(与 push 时的约定一致)。
|
|
5070
|
+
*/
|
|
5071
|
+
var detectStackOpType = (oldVal, newVal) => {
|
|
5072
|
+
if (oldVal === null && newVal !== null) return "add";
|
|
5073
|
+
if (oldVal !== null && newVal === null) return "remove";
|
|
5074
|
+
return "update";
|
|
5075
|
+
};
|
|
5076
|
+
/**
|
|
5077
|
+
* 构造一条代码块 / 数据源「按 id 分栈」的历史记录:两者除 payload 字段命名外完全一致。
|
|
5078
|
+
*
|
|
5079
|
+
* - `add`:oldValue = null;`remove`:newValue = null;`update`:两者都有,可带 changeRecords 做局部更新。
|
|
5080
|
+
* - 内容会做 cloneDeep 防止后续被外部引用篡改;opType 依据 old/new 是否为 null 推断。
|
|
5081
|
+
* - 仅负责构造 step 并返回,入栈与事件 emit 由各公共方法(pushCodeBlock / pushDataSource)自行处理。
|
|
5082
|
+
* - 不直接驱动业务 service,调用方负责实际写回。
|
|
5083
|
+
*/
|
|
5084
|
+
var createStackStep = (id, payload) => {
|
|
5085
|
+
if (!id) return null;
|
|
5086
|
+
const oldSchema = payload.oldValue ? cloneDeep$1(payload.oldValue) : null;
|
|
5087
|
+
const newSchema = payload.newValue ? cloneDeep$1(payload.newValue) : null;
|
|
5088
|
+
const changeRecords = payload.changeRecords?.length ? cloneDeep$1(payload.changeRecords) : void 0;
|
|
5089
|
+
const opType = detectStackOpType(payload.oldValue, payload.newValue);
|
|
5090
|
+
return {
|
|
5091
|
+
uuid: (0, _tmagic_utils.guid)(),
|
|
5092
|
+
id,
|
|
5093
|
+
opType,
|
|
5094
|
+
diff: [{
|
|
5095
|
+
...newSchema !== null ? { newSchema } : {},
|
|
5096
|
+
...oldSchema !== null ? { oldSchema } : {},
|
|
5097
|
+
...opType === "update" && changeRecords ? { changeRecords } : {}
|
|
5098
|
+
}],
|
|
5099
|
+
historyDescription: payload.historyDescription,
|
|
5100
|
+
source: payload.source,
|
|
5101
|
+
timestamp: Date.now()
|
|
5102
|
+
};
|
|
5103
|
+
};
|
|
5104
|
+
var markStackSaved = (undoRedo) => {
|
|
5105
|
+
if (!undoRedo) return;
|
|
5106
|
+
undoRedo.updateElements((element) => {
|
|
5107
|
+
element.saved = false;
|
|
5108
|
+
});
|
|
5109
|
+
undoRedo.updateCurrentElement((element) => {
|
|
5110
|
+
element.saved = true;
|
|
5111
|
+
});
|
|
5112
|
+
};
|
|
5113
|
+
/**
|
|
5114
|
+
* 把单个「按 id 分栈」的历史栈(代码块 / 数据源)拆成若干 group:
|
|
5115
|
+
* 每条操作记录独立成组,不做相邻 update 合并(与页面历史的合并策略不同)。
|
|
5116
|
+
*
|
|
5117
|
+
* 代码块与数据源除 `kind` 外结构完全一致,统一由本方法处理;`kind` 决定返回的具体分组类型。
|
|
5118
|
+
*/
|
|
5119
|
+
var mergeStackSteps = (kind, id, list, cursor) => {
|
|
5120
|
+
const currentIndex = cursor - 1;
|
|
5121
|
+
return list.map((step, index) => {
|
|
5122
|
+
const applied = index < cursor;
|
|
5123
|
+
const isCurrent = index === currentIndex;
|
|
5124
|
+
return {
|
|
5125
|
+
kind,
|
|
5126
|
+
id,
|
|
5127
|
+
opType: step.opType,
|
|
5128
|
+
steps: [{
|
|
5087
5129
|
step,
|
|
5088
5130
|
index,
|
|
5089
5131
|
applied,
|
|
5090
5132
|
isCurrent
|
|
5133
|
+
}],
|
|
5134
|
+
applied,
|
|
5135
|
+
isCurrent
|
|
5136
|
+
};
|
|
5137
|
+
});
|
|
5138
|
+
};
|
|
5139
|
+
/**
|
|
5140
|
+
* 把页面栈拆成若干 group:
|
|
5141
|
+
* - 单节点的 'update' 按 targetId 与相邻同 targetId 的 update 合并到一个 group;
|
|
5142
|
+
* - 'add' / 'remove' 始终独立成组(语义上是结构变更,不应被收纳进单节点修改组);
|
|
5143
|
+
* - 多节点 'update'(如批量改属性)也独立成组(无明确单一目标,避免误合并)。
|
|
5144
|
+
*/
|
|
5145
|
+
var mergePageSteps = (pageId, list, cursor) => {
|
|
5146
|
+
const groups = [];
|
|
5147
|
+
let current = null;
|
|
5148
|
+
const currentIndex = cursor - 1;
|
|
5149
|
+
list.forEach((step, index) => {
|
|
5150
|
+
const applied = index < cursor;
|
|
5151
|
+
const isCurrent = index === currentIndex;
|
|
5152
|
+
const targetId = detectPageTargetId(step);
|
|
5153
|
+
const targetName = detectPageTargetName(step);
|
|
5154
|
+
const entry = {
|
|
5155
|
+
step,
|
|
5156
|
+
index,
|
|
5157
|
+
applied,
|
|
5158
|
+
isCurrent
|
|
5159
|
+
};
|
|
5160
|
+
const mergeable = step.opType === "update" && targetId !== void 0;
|
|
5161
|
+
if (mergeable && current?.opType === "update" && current.targetId === targetId) {
|
|
5162
|
+
current.steps.push(entry);
|
|
5163
|
+
current.applied = applied;
|
|
5164
|
+
if (isCurrent) current.isCurrent = true;
|
|
5165
|
+
if (targetName) current.targetName = targetName;
|
|
5166
|
+
} else {
|
|
5167
|
+
current = {
|
|
5168
|
+
kind: "page",
|
|
5169
|
+
pageId,
|
|
5170
|
+
opType: step.opType,
|
|
5171
|
+
targetId: mergeable ? targetId : void 0,
|
|
5172
|
+
targetName,
|
|
5173
|
+
steps: [entry],
|
|
5174
|
+
applied,
|
|
5175
|
+
isCurrent
|
|
5091
5176
|
};
|
|
5092
|
-
|
|
5093
|
-
|
|
5094
|
-
|
|
5095
|
-
|
|
5096
|
-
|
|
5097
|
-
|
|
5098
|
-
|
|
5099
|
-
|
|
5100
|
-
|
|
5101
|
-
|
|
5102
|
-
|
|
5103
|
-
|
|
5104
|
-
|
|
5105
|
-
|
|
5106
|
-
|
|
5107
|
-
|
|
5108
|
-
|
|
5109
|
-
|
|
5110
|
-
|
|
5111
|
-
|
|
5112
|
-
|
|
5177
|
+
groups.push(current);
|
|
5178
|
+
}
|
|
5179
|
+
});
|
|
5180
|
+
return groups;
|
|
5181
|
+
};
|
|
5182
|
+
/**
|
|
5183
|
+
* 解析 StepValue 中的"目标节点 id"用于合并:
|
|
5184
|
+
* - 单节点 update:取唯一一项 updatedItems 的节点 id;
|
|
5185
|
+
* - 其它情形(多节点 update / add / remove):返回 undefined,表示不参与合并。
|
|
5186
|
+
*/
|
|
5187
|
+
var detectPageTargetId = (step) => {
|
|
5188
|
+
if (step.opType !== "update") return void 0;
|
|
5189
|
+
const items = step.diff;
|
|
5190
|
+
if (items?.length !== 1) return void 0;
|
|
5191
|
+
return items[0].newSchema?.id ?? items[0].oldSchema?.id;
|
|
5192
|
+
};
|
|
5193
|
+
/** 解析 StepValue 中的目标节点可读名(用于 UI 展示)。 */
|
|
5194
|
+
var detectPageTargetName = (step) => {
|
|
5195
|
+
const items = step.diff;
|
|
5196
|
+
if (step.opType === "update") {
|
|
5197
|
+
if (items?.length === 1) {
|
|
5198
|
+
const node = items[0].newSchema || items[0].oldSchema;
|
|
5199
|
+
return node?.name || node?.type || (node?.id !== void 0 ? `${node.id}` : void 0);
|
|
5200
|
+
}
|
|
5201
|
+
return items?.length ? `${items.length} 个节点` : void 0;
|
|
5113
5202
|
}
|
|
5114
|
-
|
|
5115
|
-
|
|
5116
|
-
|
|
5117
|
-
|
|
5118
|
-
*/
|
|
5119
|
-
static detectPageTargetId(step) {
|
|
5120
|
-
if (step.opType !== "update") return void 0;
|
|
5121
|
-
const items = step.updatedItems;
|
|
5122
|
-
if (items?.length !== 1) return void 0;
|
|
5123
|
-
return items[0].newNode?.id ?? items[0].oldNode?.id;
|
|
5124
|
-
}
|
|
5125
|
-
/** 解析 StepValue 中的目标节点可读名(用于 UI 展示)。 */
|
|
5126
|
-
static detectPageTargetName(step) {
|
|
5127
|
-
if (step.opType === "update") {
|
|
5128
|
-
const items = step.updatedItems;
|
|
5129
|
-
if (items?.length === 1) {
|
|
5130
|
-
const node = items[0].newNode || items[0].oldNode;
|
|
5131
|
-
return node?.name || node?.type || (node?.id !== void 0 ? `${node.id}` : void 0);
|
|
5132
|
-
}
|
|
5133
|
-
return items?.length ? `${items.length} 个节点` : void 0;
|
|
5203
|
+
if (step.opType === "add") {
|
|
5204
|
+
if (items?.length === 1) {
|
|
5205
|
+
const n = items[0].newSchema;
|
|
5206
|
+
return n?.name || n?.type || `${n?.id}`;
|
|
5134
5207
|
}
|
|
5135
|
-
|
|
5136
|
-
|
|
5137
|
-
|
|
5138
|
-
|
|
5139
|
-
|
|
5140
|
-
return
|
|
5208
|
+
return items?.length ? `${items.length} 个节点` : void 0;
|
|
5209
|
+
}
|
|
5210
|
+
if (step.opType === "remove") {
|
|
5211
|
+
if (items?.length === 1) {
|
|
5212
|
+
const n = items[0].oldSchema;
|
|
5213
|
+
return n?.name || n?.type || `${n?.id}`;
|
|
5141
5214
|
}
|
|
5142
|
-
|
|
5143
|
-
|
|
5144
|
-
|
|
5145
|
-
|
|
5146
|
-
|
|
5147
|
-
|
|
5215
|
+
return items?.length ? `${items.length} 个节点` : void 0;
|
|
5216
|
+
}
|
|
5217
|
+
};
|
|
5218
|
+
/**
|
|
5219
|
+
* 把 `Record<Id, UndoRedo>` 整体序列化为 `Record<Id, SerializedUndoRedo>`。
|
|
5220
|
+
*
|
|
5221
|
+
* 序列化(深克隆)的同一趟里,只把每条 step 中可能含函数的 `diff` 用 serialize-javascript 序列化成字符串,
|
|
5222
|
+
* 其余字段(uuid / opType / timestamp / `modifiedNodeIds` Map 等)原样保留,交给 IndexedDB 结构化克隆。
|
|
5223
|
+
* 这样既能写入函数,又避免序列化整份快照的开销;读取时再由 {@link parseStacksStepDiff} 还原 diff。
|
|
5224
|
+
* 不含 `diff` 的元素(如通用栈)原样透传。
|
|
5225
|
+
*/
|
|
5226
|
+
var serializeStacks = (stacks) => {
|
|
5227
|
+
const result = {};
|
|
5228
|
+
Object.entries(stacks).forEach(([id, undoRedo]) => {
|
|
5229
|
+
if (!undoRedo) return;
|
|
5230
|
+
const serialized = undoRedo.serialize();
|
|
5231
|
+
result[id] = {
|
|
5232
|
+
...serialized,
|
|
5233
|
+
elementList: serialized.elementList.map((step) => step.diff === void 0 ? step : Object.assign({}, step, { diff: (0, serialize_javascript.default)(step.diff) }))
|
|
5234
|
+
};
|
|
5235
|
+
});
|
|
5236
|
+
return result;
|
|
5237
|
+
};
|
|
5238
|
+
/**
|
|
5239
|
+
* 把 `Record<Id, SerializedUndoRedo>` 整体还原为 `Record<Id, UndoRedo>`。
|
|
5240
|
+
* 还原时把每个栈的游标定位到最近一条已保存(`saved === true`)记录之后。
|
|
5241
|
+
*
|
|
5242
|
+
* 与 {@link serializeStacks} 相反:当传入 `parse`(parseDSL)时,把每条 step 中以字符串形式存储的 `diff`
|
|
5243
|
+
* 解析回真实对象(含函数);不含 `diff` 的元素(如通用栈)原样透传。
|
|
5244
|
+
*/
|
|
5245
|
+
var deserializeStacks = (stacks = {}, parse) => {
|
|
5246
|
+
const result = {};
|
|
5247
|
+
Object.entries(stacks).forEach(([id, serialized]) => {
|
|
5248
|
+
if (!serialized) return;
|
|
5249
|
+
const elementList = parse ? serialized.elementList.map((step) => {
|
|
5250
|
+
const { diff } = step;
|
|
5251
|
+
return typeof diff === "string" ? Object.assign({}, step, { diff: parse(`(${diff})`) }) : step;
|
|
5252
|
+
}) : serialized.elementList;
|
|
5253
|
+
result[id] = UndoRedo.fromSerialized({
|
|
5254
|
+
...serialized,
|
|
5255
|
+
elementList
|
|
5256
|
+
}, { isSavedStep: (element) => element.saved === true });
|
|
5257
|
+
});
|
|
5258
|
+
return result;
|
|
5259
|
+
};
|
|
5260
|
+
/**
|
|
5261
|
+
* 按 id 从「按 id 分栈」的记录表(代码块 / 数据源)中获取(或创建)对应的 UndoRedo 栈。
|
|
5262
|
+
*/
|
|
5263
|
+
var getOrCreateStack = (stacks, id) => {
|
|
5264
|
+
if (!stacks[id]) stacks[id] = new UndoRedo();
|
|
5265
|
+
return stacks[id];
|
|
5266
|
+
};
|
|
5267
|
+
/**
|
|
5268
|
+
* 撤销下限:当页面栈 index 0 是 `opType: 'initial'` 的基线 step 时为 1(基线不可被撤销),否则为 0。
|
|
5269
|
+
* 用于把 cursor 钉在基线之上,保证 undo / canUndo / goto 都不会越过初始基线。
|
|
5270
|
+
*/
|
|
5271
|
+
var undoFloor = (undoRedo) => {
|
|
5272
|
+
return undoRedo.getElementList()[0]?.opType === "initial" ? 1 : 0;
|
|
5273
|
+
};
|
|
5274
|
+
/** 将单次 push 产生的 history uuid(或 null)转为 *AndGetHistoryId 返回用的 uuid 列表。 */
|
|
5275
|
+
var getLastPushedHistoryIds = (historyId) => historyId ? [historyId] : [];
|
|
5276
|
+
//#endregion
|
|
5277
|
+
//#region packages/editor/src/utils/indexed-db.ts
|
|
5278
|
+
/**
|
|
5279
|
+
* 一组极简的、基于原生 IndexedDB 的 Promise KV 工具,避免引入额外依赖。
|
|
5280
|
+
* 仅用于浏览器环境;在不支持 IndexedDB 的环境(如 SSR / 部分测试环境)下会 reject。
|
|
5281
|
+
*/
|
|
5282
|
+
/** 是否处于支持 IndexedDB 的环境。 */
|
|
5283
|
+
var isIndexedDBSupported = () => typeof indexedDB !== "undefined" && indexedDB !== null;
|
|
5284
|
+
/**
|
|
5285
|
+
* 打开(必要时升级)数据库,确保目标 objectStore 存在后返回连接。
|
|
5286
|
+
*
|
|
5287
|
+
* 由于 objectStore 只能在 `onupgradeneeded` 内创建,这里先以当前版本打开,
|
|
5288
|
+
* 若发现 store 不存在则关闭连接、以更高版本重开来按需创建,兼容动态 storeName。
|
|
5289
|
+
*/
|
|
5290
|
+
var openIndexedDB = (dbName, storeName) => new Promise((resolve, reject) => {
|
|
5291
|
+
if (!isIndexedDBSupported()) {
|
|
5292
|
+
reject(/* @__PURE__ */ new Error("当前环境不支持 IndexedDB"));
|
|
5293
|
+
return;
|
|
5294
|
+
}
|
|
5295
|
+
const request = indexedDB.open(dbName);
|
|
5296
|
+
request.onupgradeneeded = () => {
|
|
5297
|
+
const db = request.result;
|
|
5298
|
+
if (!db.objectStoreNames.contains(storeName)) db.createObjectStore(storeName);
|
|
5299
|
+
};
|
|
5300
|
+
request.onerror = () => reject(request.error);
|
|
5301
|
+
request.onsuccess = () => {
|
|
5302
|
+
const db = request.result;
|
|
5303
|
+
if (db.objectStoreNames.contains(storeName)) {
|
|
5304
|
+
resolve(db);
|
|
5305
|
+
return;
|
|
5148
5306
|
}
|
|
5307
|
+
const nextVersion = db.version + 1;
|
|
5308
|
+
db.close();
|
|
5309
|
+
const upgradeRequest = indexedDB.open(dbName, nextVersion);
|
|
5310
|
+
upgradeRequest.onupgradeneeded = () => {
|
|
5311
|
+
const upgradeDb = upgradeRequest.result;
|
|
5312
|
+
if (!upgradeDb.objectStoreNames.contains(storeName)) upgradeDb.createObjectStore(storeName);
|
|
5313
|
+
};
|
|
5314
|
+
upgradeRequest.onerror = () => reject(upgradeRequest.error);
|
|
5315
|
+
upgradeRequest.onsuccess = () => resolve(upgradeRequest.result);
|
|
5316
|
+
};
|
|
5317
|
+
});
|
|
5318
|
+
/** 写入(覆盖)一条记录。value 通过结构化克隆存储,支持 Map / Set 等结构。 */
|
|
5319
|
+
var idbSet = async (dbName, storeName, key, value) => {
|
|
5320
|
+
const db = await openIndexedDB(dbName, storeName);
|
|
5321
|
+
try {
|
|
5322
|
+
await new Promise((resolve, reject) => {
|
|
5323
|
+
const tx = db.transaction(storeName, "readwrite");
|
|
5324
|
+
tx.objectStore(storeName).put(value, key);
|
|
5325
|
+
tx.oncomplete = () => resolve();
|
|
5326
|
+
tx.onabort = () => reject(tx.error);
|
|
5327
|
+
tx.onerror = () => reject(tx.error);
|
|
5328
|
+
});
|
|
5329
|
+
} finally {
|
|
5330
|
+
db.close();
|
|
5331
|
+
}
|
|
5332
|
+
};
|
|
5333
|
+
/** 读取一条记录,不存在时返回 undefined。 */
|
|
5334
|
+
var idbGet = async (dbName, storeName, key) => {
|
|
5335
|
+
const db = await openIndexedDB(dbName, storeName);
|
|
5336
|
+
try {
|
|
5337
|
+
return await new Promise((resolve, reject) => {
|
|
5338
|
+
const request = db.transaction(storeName, "readonly").objectStore(storeName).get(key);
|
|
5339
|
+
request.onsuccess = () => resolve(request.result);
|
|
5340
|
+
request.onerror = () => reject(request.error);
|
|
5341
|
+
});
|
|
5342
|
+
} finally {
|
|
5343
|
+
db.close();
|
|
5344
|
+
}
|
|
5345
|
+
};
|
|
5346
|
+
/** 删除一条记录。 */
|
|
5347
|
+
var idbDelete = async (dbName, storeName, key) => {
|
|
5348
|
+
const db = await openIndexedDB(dbName, storeName);
|
|
5349
|
+
try {
|
|
5350
|
+
await new Promise((resolve, reject) => {
|
|
5351
|
+
const tx = db.transaction(storeName, "readwrite");
|
|
5352
|
+
tx.objectStore(storeName).delete(key);
|
|
5353
|
+
tx.oncomplete = () => resolve();
|
|
5354
|
+
tx.onabort = () => reject(tx.error);
|
|
5355
|
+
tx.onerror = () => reject(tx.error);
|
|
5356
|
+
});
|
|
5357
|
+
} finally {
|
|
5358
|
+
db.close();
|
|
5149
5359
|
}
|
|
5360
|
+
};
|
|
5361
|
+
//#endregion
|
|
5362
|
+
//#region packages/editor/src/services/history.ts
|
|
5363
|
+
/** 历史记录持久化快照的默认存储位置与结构版本。 */
|
|
5364
|
+
var DEFAULT_DB_NAME = "tmagic-editor";
|
|
5365
|
+
var DEFAULT_STORE_NAME = "history";
|
|
5366
|
+
var DEFAULT_KEY = "default";
|
|
5367
|
+
var PERSIST_VERSION = 2;
|
|
5368
|
+
var History = class extends BaseService {
|
|
5150
5369
|
state = (0, vue.reactive)({
|
|
5151
5370
|
pageSteps: {},
|
|
5152
5371
|
pageId: void 0,
|
|
@@ -5186,6 +5405,53 @@
|
|
|
5186
5405
|
this.state.dataSourceState = {};
|
|
5187
5406
|
}
|
|
5188
5407
|
/**
|
|
5408
|
+
* 为指定页面 / 页面片种入一条「初始基线」记录(如加载 DSL 时的「初始 / 加载」基线)。
|
|
5409
|
+
*
|
|
5410
|
+
* 该记录是一条 `opType: 'initial'` 的 {@link StepValue},作为页面历史栈 **index 0 的固定底线**:
|
|
5411
|
+
* - 它是一条真实入栈的 step(随栈一起持久化),但被钉为撤销/回滚的下限——cursor 永不低于它,
|
|
5412
|
+
* 因此不会被 undo / goto / revert 触达(详见 {@link undo} / {@link setCanUndoRedo});
|
|
5413
|
+
* - 历史面板把它过滤出分组列表(见 {@link getPageHistoryGroups}),改由底部「初始」行展示。
|
|
5414
|
+
*
|
|
5415
|
+
* 仅当目标页面栈为空时种入(保证 initial 一定位于 index 0);已存在 initial 底线时默认不重复种入,
|
|
5416
|
+
* 传 `force=true` 且栈为空时按新基线种入。
|
|
5417
|
+
*/
|
|
5418
|
+
setPageMarker(pageId, options = {}) {
|
|
5419
|
+
if (pageId === void 0 || pageId === null || `${pageId}` === "") return null;
|
|
5420
|
+
const existing = this.getPageMarker(pageId);
|
|
5421
|
+
if (existing) return existing;
|
|
5422
|
+
const stack = getOrCreateStack(this.state.pageSteps, pageId);
|
|
5423
|
+
if (stack.getLength() > 0) return null;
|
|
5424
|
+
const marker = {
|
|
5425
|
+
uuid: (0, _tmagic_utils.guid)(),
|
|
5426
|
+
opType: "initial",
|
|
5427
|
+
diff: [],
|
|
5428
|
+
data: {
|
|
5429
|
+
name: options.name || "",
|
|
5430
|
+
id: pageId
|
|
5431
|
+
},
|
|
5432
|
+
selectedBefore: [],
|
|
5433
|
+
selectedAfter: [],
|
|
5434
|
+
modifiedNodeIds: /* @__PURE__ */ new Map(),
|
|
5435
|
+
historyDescription: options.description || "未修改的初始状态",
|
|
5436
|
+
timestamp: Date.now(),
|
|
5437
|
+
...options.source ? { source: options.source } : {}
|
|
5438
|
+
};
|
|
5439
|
+
stack.pushElement(marker);
|
|
5440
|
+
if (`${pageId}` === `${this.state.pageId}`) this.setCanUndoRedo();
|
|
5441
|
+
this.emit("page-marker-change", marker);
|
|
5442
|
+
return marker;
|
|
5443
|
+
}
|
|
5444
|
+
/**
|
|
5445
|
+
* 读取指定页面(缺省当前活动页)的初始基线 step(页面栈 index 0 且 `opType: 'initial'`);
|
|
5446
|
+
* 不存在时返回 undefined。
|
|
5447
|
+
*/
|
|
5448
|
+
getPageMarker(pageId) {
|
|
5449
|
+
const targetPageId = pageId ?? this.state.pageId;
|
|
5450
|
+
if (!targetPageId) return void 0;
|
|
5451
|
+
const first = this.state.pageSteps[targetPageId]?.getElementList()[0];
|
|
5452
|
+
return first?.opType === "initial" ? first : void 0;
|
|
5453
|
+
}
|
|
5454
|
+
/**
|
|
5189
5455
|
* 把一条步骤推入指定页面的栈;不指定 pageId 时落到当前活动页。
|
|
5190
5456
|
*
|
|
5191
5457
|
* 跨页操作(例如 `moveToContainer` 把节点搬到其它页)必须显式传入 `pageId`,
|
|
@@ -5194,11 +5460,31 @@
|
|
|
5194
5460
|
push(state, pageId) {
|
|
5195
5461
|
const undoRedo = this.getUndoRedo(pageId);
|
|
5196
5462
|
if (!undoRedo) return null;
|
|
5463
|
+
if (state.uuid === void 0) state.uuid = (0, _tmagic_utils.guid)();
|
|
5197
5464
|
if (state.timestamp === void 0) state.timestamp = Date.now();
|
|
5198
5465
|
undoRedo.pushElement(state);
|
|
5199
5466
|
if (pageId === void 0 || `${pageId}` === `${this.state.pageId}`) this.emit("change", state);
|
|
5200
5467
|
return state;
|
|
5201
5468
|
}
|
|
5469
|
+
/** 读取指定页面(缺省当前活动页)历史栈当前游标所在的 step(cursor - 1);无则返回 null。 */
|
|
5470
|
+
getCurrentPageStep(pageId) {
|
|
5471
|
+
const targetPageId = pageId ?? this.state.pageId;
|
|
5472
|
+
if (!targetPageId) return null;
|
|
5473
|
+
return this.state.pageSteps[targetPageId]?.getCurrentElement() ?? null;
|
|
5474
|
+
}
|
|
5475
|
+
/**
|
|
5476
|
+
* 用 `state` 替换指定页面栈当前游标所在的 step(并丢弃其后的重做尾部),游标不变。
|
|
5477
|
+
* 用于「连续 set root 记录合并」等就地替换最新一条的场景;替换成功后按需刷新 / 通知。
|
|
5478
|
+
*/
|
|
5479
|
+
replaceCurrentPageStep(state, pageId) {
|
|
5480
|
+
const undoRedo = this.getUndoRedo(pageId);
|
|
5481
|
+
if (!undoRedo) return null;
|
|
5482
|
+
if (state.uuid === void 0) state.uuid = (0, _tmagic_utils.guid)();
|
|
5483
|
+
if (state.timestamp === void 0) state.timestamp = Date.now();
|
|
5484
|
+
if (!undoRedo.replaceCurrentElement(state)) return null;
|
|
5485
|
+
this.emit("change", state);
|
|
5486
|
+
return state;
|
|
5487
|
+
}
|
|
5202
5488
|
/**
|
|
5203
5489
|
* 推入一条代码块变更记录(与页面/节点完全无关),按 `codeBlockId` 维度独立一份 UndoRedo 栈。
|
|
5204
5490
|
*
|
|
@@ -5209,17 +5495,15 @@
|
|
|
5209
5495
|
* - 不直接驱动 codeBlockService,调用方负责实际写回。
|
|
5210
5496
|
*/
|
|
5211
5497
|
pushCodeBlock(codeBlockId, payload) {
|
|
5212
|
-
|
|
5213
|
-
|
|
5214
|
-
|
|
5215
|
-
|
|
5216
|
-
newContent: payload.newContent ? cloneDeep$1(payload.newContent) : null,
|
|
5217
|
-
changeRecords: payload.changeRecords?.length ? cloneDeep$1(payload.changeRecords) : void 0,
|
|
5498
|
+
const step = createStackStep(codeBlockId, {
|
|
5499
|
+
oldValue: payload.oldContent,
|
|
5500
|
+
newValue: payload.newContent,
|
|
5501
|
+
changeRecords: payload.changeRecords,
|
|
5218
5502
|
historyDescription: payload.historyDescription,
|
|
5219
|
-
source: payload.source
|
|
5220
|
-
|
|
5221
|
-
|
|
5222
|
-
this.
|
|
5503
|
+
source: payload.source
|
|
5504
|
+
});
|
|
5505
|
+
if (!step) return null;
|
|
5506
|
+
getOrCreateStack(this.state.codeBlockState, codeBlockId).pushElement(step);
|
|
5223
5507
|
this.emit("code-block-history-change", codeBlockId, step);
|
|
5224
5508
|
return step;
|
|
5225
5509
|
}
|
|
@@ -5228,17 +5512,15 @@
|
|
|
5228
5512
|
* 行为同 pushCodeBlock(新增 oldSchema=null;删除 newSchema=null)。
|
|
5229
5513
|
*/
|
|
5230
5514
|
pushDataSource(dataSourceId, payload) {
|
|
5231
|
-
|
|
5232
|
-
|
|
5233
|
-
|
|
5234
|
-
|
|
5235
|
-
newSchema: payload.newSchema ? cloneDeep$1(payload.newSchema) : null,
|
|
5236
|
-
changeRecords: payload.changeRecords?.length ? cloneDeep$1(payload.changeRecords) : void 0,
|
|
5515
|
+
const step = createStackStep(dataSourceId, {
|
|
5516
|
+
oldValue: payload.oldSchema,
|
|
5517
|
+
newValue: payload.newSchema,
|
|
5518
|
+
changeRecords: payload.changeRecords,
|
|
5237
5519
|
historyDescription: payload.historyDescription,
|
|
5238
|
-
source: payload.source
|
|
5239
|
-
|
|
5240
|
-
|
|
5241
|
-
this.
|
|
5520
|
+
source: payload.source
|
|
5521
|
+
});
|
|
5522
|
+
if (!step) return null;
|
|
5523
|
+
getOrCreateStack(this.state.dataSourceState, dataSourceId).pushElement(step);
|
|
5242
5524
|
this.emit("data-source-history-change", dataSourceId, step);
|
|
5243
5525
|
return step;
|
|
5244
5526
|
}
|
|
@@ -5293,6 +5575,7 @@
|
|
|
5293
5575
|
undo() {
|
|
5294
5576
|
const undoRedo = this.getUndoRedo();
|
|
5295
5577
|
if (!undoRedo) return null;
|
|
5578
|
+
if (undoRedo.getCursor() <= undoFloor(undoRedo)) return null;
|
|
5296
5579
|
const state = undoRedo.undo();
|
|
5297
5580
|
this.emit("change", state);
|
|
5298
5581
|
return state;
|
|
@@ -5310,6 +5593,126 @@
|
|
|
5310
5593
|
this.removeAllPlugins();
|
|
5311
5594
|
}
|
|
5312
5595
|
/**
|
|
5596
|
+
* 清空指定页面(缺省当前活动页)的历史记录栈。
|
|
5597
|
+
* 仅删除撤销/重做记录,不会改动当前 DSL;清空后该页将无法再撤销/重做之前的操作。
|
|
5598
|
+
*/
|
|
5599
|
+
clearPage(pageId) {
|
|
5600
|
+
const targetPageId = pageId ?? this.state.pageId;
|
|
5601
|
+
if (!targetPageId) return;
|
|
5602
|
+
const marker = this.getPageMarker(targetPageId);
|
|
5603
|
+
this.state.pageSteps[targetPageId] = new UndoRedo();
|
|
5604
|
+
if (marker) this.setPageMarker(targetPageId, {
|
|
5605
|
+
name: marker.data?.name,
|
|
5606
|
+
description: marker.historyDescription,
|
|
5607
|
+
source: marker.source
|
|
5608
|
+
});
|
|
5609
|
+
if (`${targetPageId}` === `${this.state.pageId}`) {
|
|
5610
|
+
this.setCanUndoRedo();
|
|
5611
|
+
this.emit("clear-page", null);
|
|
5612
|
+
}
|
|
5613
|
+
}
|
|
5614
|
+
/**
|
|
5615
|
+
* 清空数据源历史记录栈:传入 `dataSourceId` 仅清空该数据源,缺省清空全部数据源。
|
|
5616
|
+
* 仅删除撤销/重做记录,不会改动数据源本身。
|
|
5617
|
+
*/
|
|
5618
|
+
clearDataSource(dataSourceId) {
|
|
5619
|
+
if (dataSourceId !== void 0) delete this.state.dataSourceState[dataSourceId];
|
|
5620
|
+
else this.state.dataSourceState = {};
|
|
5621
|
+
}
|
|
5622
|
+
/**
|
|
5623
|
+
* 清空代码块历史记录栈:传入 `codeBlockId` 仅清空该代码块,缺省清空全部代码块。
|
|
5624
|
+
* 仅删除撤销/重做记录,不会改动代码块本身。
|
|
5625
|
+
*/
|
|
5626
|
+
clearCodeBlock(codeBlockId) {
|
|
5627
|
+
if (codeBlockId !== void 0) delete this.state.codeBlockState[codeBlockId];
|
|
5628
|
+
else this.state.codeBlockState = {};
|
|
5629
|
+
}
|
|
5630
|
+
/**
|
|
5631
|
+
* 标记「整份 DSL 已保存」:把页面 / 代码块 / 数据源所有栈当前游标所在的记录都标为 `saved`。
|
|
5632
|
+
* 适用于「整体落库」场景;若只保存了其中一类,请改用更细粒度的
|
|
5633
|
+
* {@link markPageSaved} / {@link markCodeBlockSaved} / {@link markDataSourceSaved}。
|
|
5634
|
+
*/
|
|
5635
|
+
markSaved() {
|
|
5636
|
+
Object.values(this.state.pageSteps).forEach(markStackSaved);
|
|
5637
|
+
Object.values(this.state.codeBlockState).forEach(markStackSaved);
|
|
5638
|
+
Object.values(this.state.dataSourceState).forEach(markStackSaved);
|
|
5639
|
+
this.emit("mark-saved", { kind: "all" });
|
|
5640
|
+
}
|
|
5641
|
+
/**
|
|
5642
|
+
* 标记指定页面(缺省为当前活动页)的历史栈当前记录为已保存。
|
|
5643
|
+
* 仅影响该页面自己的栈,不波及代码块 / 数据源 / 其它页面。
|
|
5644
|
+
*/
|
|
5645
|
+
markPageSaved(pageId) {
|
|
5646
|
+
const targetPageId = pageId ?? this.state.pageId;
|
|
5647
|
+
if (!targetPageId) return;
|
|
5648
|
+
markStackSaved(this.state.pageSteps[targetPageId]);
|
|
5649
|
+
this.emit("mark-saved", {
|
|
5650
|
+
kind: "page",
|
|
5651
|
+
id: targetPageId
|
|
5652
|
+
});
|
|
5653
|
+
}
|
|
5654
|
+
/** 标记指定代码块的历史栈当前记录为已保存,仅影响该代码块自己的栈。 */
|
|
5655
|
+
markCodeBlockSaved(codeBlockId) {
|
|
5656
|
+
if (!codeBlockId) return;
|
|
5657
|
+
markStackSaved(this.state.codeBlockState[codeBlockId]);
|
|
5658
|
+
this.emit("mark-saved", {
|
|
5659
|
+
kind: "code-block",
|
|
5660
|
+
id: codeBlockId
|
|
5661
|
+
});
|
|
5662
|
+
}
|
|
5663
|
+
/** 标记指定数据源的历史栈当前记录为已保存,仅影响该数据源自己的栈。 */
|
|
5664
|
+
markDataSourceSaved(dataSourceId) {
|
|
5665
|
+
if (!dataSourceId) return;
|
|
5666
|
+
markStackSaved(this.state.dataSourceState[dataSourceId]);
|
|
5667
|
+
this.emit("mark-saved", {
|
|
5668
|
+
kind: "data-source",
|
|
5669
|
+
id: dataSourceId
|
|
5670
|
+
});
|
|
5671
|
+
}
|
|
5672
|
+
/**
|
|
5673
|
+
* 把当前内存中的全部历史栈(页面 / 代码块 / 数据源)序列化后写入本地 IndexedDB。
|
|
5674
|
+
*
|
|
5675
|
+
* - 每个 UndoRedo 栈连同其游标、容量一并保存,恢复后可继续 undo/redo;
|
|
5676
|
+
* - `key` 用于区分不同活动页 / 项目(同一 store 下可保存多份快照),缺省为 `default`;
|
|
5677
|
+
* - 返回写入成功的快照对象,便于调用方记录 savedAt 等信息;
|
|
5678
|
+
* - 不支持 IndexedDB 的环境(如 SSR)会 reject。
|
|
5679
|
+
*/
|
|
5680
|
+
async saveToIndexedDB(options = {}) {
|
|
5681
|
+
const { dbName = DEFAULT_DB_NAME, storeName = DEFAULT_STORE_NAME, key = DEFAULT_KEY, appId } = options;
|
|
5682
|
+
const snapshot = {
|
|
5683
|
+
version: PERSIST_VERSION,
|
|
5684
|
+
pageId: this.state.pageId,
|
|
5685
|
+
pageSteps: serializeStacks(this.state.pageSteps),
|
|
5686
|
+
codeBlockState: serializeStacks(this.state.codeBlockState),
|
|
5687
|
+
dataSourceState: serializeStacks(this.state.dataSourceState),
|
|
5688
|
+
savedAt: Date.now()
|
|
5689
|
+
};
|
|
5690
|
+
await idbSet(this.resolveDbName(dbName, appId), storeName, key, snapshot);
|
|
5691
|
+
this.emit("save-to-indexed-db", snapshot);
|
|
5692
|
+
return snapshot;
|
|
5693
|
+
}
|
|
5694
|
+
/**
|
|
5695
|
+
* 从本地 IndexedDB 读取此前保存的历史快照并重建全部撤销/重做栈。
|
|
5696
|
+
*
|
|
5697
|
+
* - 读取到的每个栈都会经 {@link UndoRedo.fromSerialized} 还原(含游标),随后可直接 undo/redo;
|
|
5698
|
+
* - 会整体覆盖当前内存中的历史状态,并把活动页恢复为快照中的 pageId;
|
|
5699
|
+
* - 找不到对应记录时返回 null,且不改动当前状态;
|
|
5700
|
+
* - 不支持 IndexedDB 的环境(如 SSR)会 reject。
|
|
5701
|
+
*/
|
|
5702
|
+
async restoreFromIndexedDB(options = {}) {
|
|
5703
|
+
const { dbName = DEFAULT_DB_NAME, storeName = DEFAULT_STORE_NAME, key = DEFAULT_KEY, appId } = options;
|
|
5704
|
+
const snapshot = await idbGet(this.resolveDbName(dbName, appId), storeName, key);
|
|
5705
|
+
if (!snapshot) return null;
|
|
5706
|
+
const parseDSL = getEditorConfig("parseDSL");
|
|
5707
|
+
this.state.pageSteps = deserializeStacks(snapshot.pageSteps, parseDSL);
|
|
5708
|
+
this.state.codeBlockState = deserializeStacks(snapshot.codeBlockState, parseDSL);
|
|
5709
|
+
this.state.dataSourceState = deserializeStacks(snapshot.dataSourceState, parseDSL);
|
|
5710
|
+
this.state.pageId = snapshot.pageId;
|
|
5711
|
+
this.setCanUndoRedo();
|
|
5712
|
+
this.emit("restore-from-indexed-db", snapshot);
|
|
5713
|
+
return snapshot;
|
|
5714
|
+
}
|
|
5715
|
+
/**
|
|
5313
5716
|
* 取出当前活动页的历史步骤平铺列表(包含已应用 + 已撤销)。
|
|
5314
5717
|
* 列表按时间正序,最早一步在最前面。
|
|
5315
5718
|
* 通常 UI 应使用 `getPageHistoryGroups` 取已合并分组的版本;本方法仅为兼容/调试保留。
|
|
@@ -5340,15 +5743,11 @@
|
|
|
5340
5743
|
if (!undoRedo) return [];
|
|
5341
5744
|
const list = undoRedo.getElementList();
|
|
5342
5745
|
if (!list.length) return [];
|
|
5343
|
-
|
|
5344
|
-
return History.mergePageSteps(targetPageId, list, cursor);
|
|
5746
|
+
return mergePageSteps(targetPageId, list, undoRedo.getCursor()).filter((group) => group.opType !== "initial");
|
|
5345
5747
|
}
|
|
5346
5748
|
/**
|
|
5347
|
-
* 取出全部代码块的历史栈,按 codeBlockId
|
|
5348
|
-
*
|
|
5349
|
-
* - 这正是"代码块/数据源各自按 id 分栈"的天然表现,再叠加"连续修改同目标的相邻步骤合并展示"。
|
|
5350
|
-
* - 合并后 group 暴露子步骤数组,UI 可展开查看每一步的 changeRecords。
|
|
5351
|
-
* - applied 字段:组内最后一步是否处于已应用段。
|
|
5749
|
+
* 取出全部代码块的历史栈,按 codeBlockId 分桶展示。
|
|
5750
|
+
* 同一栈内每条操作记录独立成组,不做相邻 update 合并。
|
|
5352
5751
|
*/
|
|
5353
5752
|
getCodeBlockHistoryGroups() {
|
|
5354
5753
|
const groups = [];
|
|
@@ -5357,7 +5756,7 @@
|
|
|
5357
5756
|
const list = undoRedo.getElementList();
|
|
5358
5757
|
if (!list.length) return;
|
|
5359
5758
|
const cursor = undoRedo.getCursor();
|
|
5360
|
-
groups.push(...
|
|
5759
|
+
groups.push(...mergeStackSteps("code-block", id, list, cursor));
|
|
5361
5760
|
});
|
|
5362
5761
|
return groups;
|
|
5363
5762
|
}
|
|
@@ -5407,7 +5806,45 @@
|
|
|
5407
5806
|
}));
|
|
5408
5807
|
}
|
|
5409
5808
|
/**
|
|
5410
|
-
*
|
|
5809
|
+
* 按历史记录 uuid 在指定页面(默认当前活动页)的栈中查找其索引。
|
|
5810
|
+
* 找不到时返回 -1。供「按 uuid 回滚」等需要把 uuid 映射回 index 的场景使用。
|
|
5811
|
+
*/
|
|
5812
|
+
getPageStepIndexByUuid(uuid, pageId) {
|
|
5813
|
+
if (!uuid) return -1;
|
|
5814
|
+
return this.getPageStepList(pageId).findIndex((entry) => entry.step.uuid === uuid);
|
|
5815
|
+
}
|
|
5816
|
+
/**
|
|
5817
|
+
* 按历史记录 uuid 在全部代码块栈中查找其所属 codeBlockId 与索引。
|
|
5818
|
+
* 找不到时返回 null。
|
|
5819
|
+
*/
|
|
5820
|
+
findCodeBlockStepLocationByUuid(uuid) {
|
|
5821
|
+
if (!uuid) return null;
|
|
5822
|
+
for (const id of Object.keys(this.state.codeBlockState)) {
|
|
5823
|
+
const index = this.getCodeBlockStepList(id).findIndex((entry) => entry.step.uuid === uuid);
|
|
5824
|
+
if (index >= 0) return {
|
|
5825
|
+
id,
|
|
5826
|
+
index
|
|
5827
|
+
};
|
|
5828
|
+
}
|
|
5829
|
+
return null;
|
|
5830
|
+
}
|
|
5831
|
+
/**
|
|
5832
|
+
* 按历史记录 uuid 在全部数据源栈中查找其所属 dataSourceId 与索引。
|
|
5833
|
+
* 找不到时返回 null。
|
|
5834
|
+
*/
|
|
5835
|
+
findDataSourceStepLocationByUuid(uuid) {
|
|
5836
|
+
if (!uuid) return null;
|
|
5837
|
+
for (const id of Object.keys(this.state.dataSourceState)) {
|
|
5838
|
+
const index = this.getDataSourceStepList(id).findIndex((entry) => entry.step.uuid === uuid);
|
|
5839
|
+
if (index >= 0) return {
|
|
5840
|
+
id,
|
|
5841
|
+
index
|
|
5842
|
+
};
|
|
5843
|
+
}
|
|
5844
|
+
return null;
|
|
5845
|
+
}
|
|
5846
|
+
/**
|
|
5847
|
+
* 取出全部数据源的历史栈,按 dataSourceId 分桶展示。同上,每条操作独立成组。
|
|
5411
5848
|
*/
|
|
5412
5849
|
getDataSourceHistoryGroups() {
|
|
5413
5850
|
const groups = [];
|
|
@@ -5416,7 +5853,7 @@
|
|
|
5416
5853
|
const list = undoRedo.getElementList();
|
|
5417
5854
|
if (!list.length) return;
|
|
5418
5855
|
const cursor = undoRedo.getCursor();
|
|
5419
|
-
groups.push(...
|
|
5856
|
+
groups.push(...mergeStackSteps("data-source", id, list, cursor));
|
|
5420
5857
|
});
|
|
5421
5858
|
return groups;
|
|
5422
5859
|
}
|
|
@@ -5432,35 +5869,22 @@
|
|
|
5432
5869
|
if (!this.state.pageSteps[targetPageId]) this.state.pageSteps[targetPageId] = new UndoRedo();
|
|
5433
5870
|
return this.state.pageSteps[targetPageId];
|
|
5434
5871
|
}
|
|
5435
|
-
setCanUndoRedo() {
|
|
5436
|
-
const undoRedo = this.getUndoRedo();
|
|
5437
|
-
this.state.canRedo = undoRedo?.canRedo() || false;
|
|
5438
|
-
this.state.canUndo = undoRedo?.canUndo() || false;
|
|
5439
|
-
}
|
|
5440
5872
|
/**
|
|
5441
|
-
*
|
|
5873
|
+
* 把基础 dbName 与当前 DSL(root app)的 id 拼成最终库名,实现不同应用历史隔离。
|
|
5874
|
+
* 取不到 app id(如尚未加载 DSL)时退回基础 dbName。
|
|
5442
5875
|
*/
|
|
5443
|
-
|
|
5444
|
-
|
|
5445
|
-
return
|
|
5876
|
+
resolveDbName(dbName, appId) {
|
|
5877
|
+
const resolvedAppId = appId ?? editor_default.get("root")?.id;
|
|
5878
|
+
return resolvedAppId ? `${dbName}-${resolvedAppId}` : dbName;
|
|
5446
5879
|
}
|
|
5447
|
-
|
|
5448
|
-
|
|
5449
|
-
|
|
5450
|
-
|
|
5451
|
-
if (!this.state.dataSourceState[dataSourceId]) this.state.dataSourceState[dataSourceId] = new UndoRedo();
|
|
5452
|
-
return this.state.dataSourceState[dataSourceId];
|
|
5880
|
+
setCanUndoRedo() {
|
|
5881
|
+
const undoRedo = this.getUndoRedo();
|
|
5882
|
+
this.state.canRedo = undoRedo?.canRedo() || false;
|
|
5883
|
+
this.state.canUndo = undoRedo ? undoRedo.getCursor() > undoFloor(undoRedo) : false;
|
|
5453
5884
|
}
|
|
5454
5885
|
};
|
|
5455
5886
|
var history_default = new History();
|
|
5456
5887
|
//#endregion
|
|
5457
|
-
//#region packages/editor/src/utils/config.ts
|
|
5458
|
-
var $TMAGIC_EDITOR = {};
|
|
5459
|
-
var setEditorConfig = (option) => {
|
|
5460
|
-
$TMAGIC_EDITOR = option;
|
|
5461
|
-
};
|
|
5462
|
-
var getEditorConfig = (key) => $TMAGIC_EDITOR[key];
|
|
5463
|
-
//#endregion
|
|
5464
5888
|
//#region packages/editor/src/services/storage.ts
|
|
5465
5889
|
var Protocol = /* @__PURE__ */ function(Protocol) {
|
|
5466
5890
|
Protocol["OBJECT"] = "object";
|
|
@@ -5653,12 +6077,26 @@
|
|
|
5653
6077
|
}
|
|
5654
6078
|
return (Math.min(parentHeight, wrapperHeightDeal) - height) / 2;
|
|
5655
6079
|
};
|
|
6080
|
+
var removeConflictPosition = (style, primary, secondary) => {
|
|
6081
|
+
const isInvalid = (value) => value === "" || value === 0 || value === void 0 || value === null;
|
|
6082
|
+
if (!(primary in style) || !(secondary in style)) return;
|
|
6083
|
+
const primaryValue = style[primary];
|
|
6084
|
+
const secondaryValue = style[secondary];
|
|
6085
|
+
const primaryInvalid = isInvalid(primaryValue);
|
|
6086
|
+
const secondaryInvalid = isInvalid(secondaryValue);
|
|
6087
|
+
if (primaryInvalid && !secondaryInvalid) delete style[primary];
|
|
6088
|
+
else if (secondaryInvalid && !primaryInvalid) delete style[secondary];
|
|
6089
|
+
else if (primaryInvalid && secondaryInvalid) if (secondaryValue === 0 && primaryValue !== 0) delete style[primary];
|
|
6090
|
+
else delete style[secondary];
|
|
6091
|
+
};
|
|
5656
6092
|
var getInitPositionStyle = (style = {}, layout) => {
|
|
5657
6093
|
if (layout === Layout.ABSOLUTE) {
|
|
5658
6094
|
const newStyle = {
|
|
5659
6095
|
...style,
|
|
5660
6096
|
position: "absolute"
|
|
5661
6097
|
};
|
|
6098
|
+
removeConflictPosition(newStyle, "left", "right");
|
|
6099
|
+
removeConflictPosition(newStyle, "top", "bottom");
|
|
5662
6100
|
if (typeof newStyle.left === "undefined" && typeof newStyle.right === "undefined") newStyle.left = 0;
|
|
5663
6101
|
return newStyle;
|
|
5664
6102
|
}
|
|
@@ -5683,58 +6121,63 @@
|
|
|
5683
6121
|
}
|
|
5684
6122
|
return node;
|
|
5685
6123
|
};
|
|
5686
|
-
var
|
|
5687
|
-
|
|
5688
|
-
|
|
5689
|
-
|
|
5690
|
-
|
|
5691
|
-
|
|
5692
|
-
|
|
5693
|
-
|
|
5694
|
-
|
|
5695
|
-
|
|
5696
|
-
|
|
5697
|
-
|
|
5698
|
-
|
|
6124
|
+
var hasPositionValue = (style, key) => typeof style?.[key] !== "undefined" && style?.[key] !== "";
|
|
6125
|
+
/**
|
|
6126
|
+
* 沿节点路径累加(或抵消)某一方向上的定位偏移量
|
|
6127
|
+
* 当路径上的祖先使用了反方向定位(例如计算 left 时祖先用了 right)或非数值定位时,
|
|
6128
|
+
* 无法简单地通过求和换算坐标,此时返回 0 表示放弃补偿、保持原值
|
|
6129
|
+
* @param path 从根到目标节点的路径(含节点自身)
|
|
6130
|
+
* @param dir 需要累加的定位方向
|
|
6131
|
+
* @param opposite 反方向定位属性
|
|
6132
|
+
* @param sign change2Fixed 取 1(累加祖先偏移),Fixed2Other 取 -1(抵消祖先偏移)
|
|
6133
|
+
* @param init 偏移量初始值
|
|
6134
|
+
*/
|
|
6135
|
+
var accumulatePositionOffset = (path, dir, opposite, sign, init = 0) => {
|
|
6136
|
+
let offset = init;
|
|
6137
|
+
for (const value of path) {
|
|
6138
|
+
if (hasPositionValue(value.style, opposite) || !(0, _tmagic_utils.isNumber)(value.style?.[dir] || 0)) return 0;
|
|
6139
|
+
offset = offset + sign * Number(value.style?.[dir] || 0);
|
|
5699
6140
|
}
|
|
5700
|
-
|
|
5701
|
-
|
|
5702
|
-
|
|
5703
|
-
|
|
5704
|
-
|
|
5705
|
-
|
|
6141
|
+
return offset;
|
|
6142
|
+
};
|
|
6143
|
+
var change2Fixed = (node, path) => {
|
|
6144
|
+
const style = { ...node.style || {} };
|
|
6145
|
+
if (!hasPositionValue(node.style, "right") && (0, _tmagic_utils.isNumber)(node.style?.left || 0)) {
|
|
6146
|
+
const left = accumulatePositionOffset(path, "left", "right", 1);
|
|
6147
|
+
if (left) style.left = left;
|
|
6148
|
+
} else if (hasPositionValue(node.style, "right") && (0, _tmagic_utils.isNumber)(node.style?.right || 0)) {
|
|
6149
|
+
const right = accumulatePositionOffset(path, "right", "left", 1);
|
|
6150
|
+
if (right) style.right = right;
|
|
6151
|
+
}
|
|
6152
|
+
if (!hasPositionValue(node.style, "bottom") && (0, _tmagic_utils.isNumber)(node.style?.top || 0)) {
|
|
6153
|
+
const top = accumulatePositionOffset(path, "top", "bottom", 1);
|
|
6154
|
+
if (top) style.top = top;
|
|
6155
|
+
} else if (hasPositionValue(node.style, "bottom") && (0, _tmagic_utils.isNumber)(node.style?.bottom || 0)) {
|
|
6156
|
+
const bottom = accumulatePositionOffset(path, "bottom", "top", 1);
|
|
6157
|
+
if (bottom) style.bottom = bottom;
|
|
5706
6158
|
}
|
|
5707
|
-
if (offset.left) style.left = offset.left;
|
|
5708
|
-
if (offset.top) style.top = offset.top;
|
|
5709
6159
|
return style;
|
|
5710
6160
|
};
|
|
5711
|
-
var Fixed2Other = async (node,
|
|
5712
|
-
const path = (0, _tmagic_utils.getNodePath)(node.id, root.items);
|
|
6161
|
+
var Fixed2Other = async (node, path, getLayout) => {
|
|
5713
6162
|
const cur = path.pop();
|
|
5714
6163
|
const offset = {
|
|
5715
|
-
left:
|
|
5716
|
-
top:
|
|
6164
|
+
left: 0,
|
|
6165
|
+
top: 0,
|
|
6166
|
+
right: 0,
|
|
6167
|
+
bottom: 0
|
|
5717
6168
|
};
|
|
5718
|
-
if (!node.style
|
|
5719
|
-
|
|
5720
|
-
|
|
5721
|
-
|
|
5722
|
-
}
|
|
5723
|
-
offset.left = offset.left - Number(value.style?.left || 0);
|
|
5724
|
-
}
|
|
5725
|
-
if (!node.style?.bottom && (0, _tmagic_utils.isNumber)(node.style?.top || 0)) for (const value of path) {
|
|
5726
|
-
if (value.style?.bottom || !(0, _tmagic_utils.isNumber)(value.style?.top || 0)) {
|
|
5727
|
-
offset.top = 0;
|
|
5728
|
-
break;
|
|
5729
|
-
}
|
|
5730
|
-
offset.top = offset.top - Number(value.style?.top || 0);
|
|
5731
|
-
}
|
|
6169
|
+
if (!hasPositionValue(node.style, "right") && (0, _tmagic_utils.isNumber)(node.style?.left || 0)) offset.left = accumulatePositionOffset(path, "left", "right", -1, Number(cur?.style?.left || 0));
|
|
6170
|
+
else if (hasPositionValue(node.style, "right") && (0, _tmagic_utils.isNumber)(node.style?.right || 0)) offset.right = accumulatePositionOffset(path, "right", "left", -1, Number(cur?.style?.right || 0));
|
|
6171
|
+
if (!hasPositionValue(node.style, "bottom") && (0, _tmagic_utils.isNumber)(node.style?.top || 0)) offset.top = accumulatePositionOffset(path, "top", "bottom", -1, Number(cur?.style?.top || 0));
|
|
6172
|
+
else if (hasPositionValue(node.style, "bottom") && (0, _tmagic_utils.isNumber)(node.style?.bottom || 0)) offset.bottom = accumulatePositionOffset(path, "bottom", "top", -1, Number(cur?.style?.bottom || 0));
|
|
5732
6173
|
const style = node.style || {};
|
|
5733
6174
|
const parent = path.pop();
|
|
5734
6175
|
if (!parent) return getRelativeStyle(style);
|
|
5735
6176
|
if (await getLayout(parent) !== Layout.RELATIVE) {
|
|
5736
6177
|
if (offset.left) style.left = offset.left;
|
|
5737
6178
|
if (offset.top) style.top = offset.top;
|
|
6179
|
+
if (offset.right) style.right = offset.right;
|
|
6180
|
+
if (offset.bottom) style.bottom = offset.bottom;
|
|
5738
6181
|
return {
|
|
5739
6182
|
...style,
|
|
5740
6183
|
position: "absolute"
|
|
@@ -5766,11 +6209,11 @@
|
|
|
5766
6209
|
};
|
|
5767
6210
|
var fixNodePosition = (config, parent, stage) => {
|
|
5768
6211
|
if (config.style?.position !== "absolute") return config.style;
|
|
5769
|
-
|
|
5770
|
-
|
|
5771
|
-
|
|
5772
|
-
|
|
5773
|
-
|
|
6212
|
+
const style = { ...config.style || {} };
|
|
6213
|
+
const baseStyle = config.style || {};
|
|
6214
|
+
if ("left" in baseStyle && !("right" in baseStyle)) style.left = fixNodeLeft(config, parent, stage?.renderer?.contentWindow?.document);
|
|
6215
|
+
if ("top" in baseStyle && !("bottom" in baseStyle)) style.top = getMiddleTop(config, parent, stage);
|
|
6216
|
+
return style;
|
|
5774
6217
|
};
|
|
5775
6218
|
var serializeConfig = (config) => (0, serialize_javascript.default)(config, {
|
|
5776
6219
|
space: 2,
|
|
@@ -5847,13 +6290,14 @@
|
|
|
5847
6290
|
var resolveSelectedNode = (config, getNodeInfoFn, rootId) => {
|
|
5848
6291
|
const id = typeof config === "string" || typeof config === "number" ? config : config.id;
|
|
5849
6292
|
if (!id) throw new Error("没有ID,无法选中");
|
|
5850
|
-
const { node, parent, page } = getNodeInfoFn(id);
|
|
6293
|
+
const { node, parent, page, path } = getNodeInfoFn(id);
|
|
5851
6294
|
if (!node) throw new Error("获取不到组件信息");
|
|
5852
6295
|
if (node.id === rootId) throw new Error("不能选根节点");
|
|
5853
6296
|
return {
|
|
5854
6297
|
node,
|
|
5855
6298
|
parent,
|
|
5856
|
-
page
|
|
6299
|
+
page,
|
|
6300
|
+
path
|
|
5857
6301
|
};
|
|
5858
6302
|
};
|
|
5859
6303
|
/**
|
|
@@ -5865,11 +6309,11 @@
|
|
|
5865
6309
|
* @param getLayoutFn 获取父节点布局方式的回调函数
|
|
5866
6310
|
* @returns 处理后的节点配置(深拷贝)
|
|
5867
6311
|
*/
|
|
5868
|
-
var toggleFixedPosition = async (dist, src,
|
|
6312
|
+
var toggleFixedPosition = async (dist, src, path, getLayoutFn) => {
|
|
5869
6313
|
const newConfig = cloneDeep$1(dist);
|
|
5870
6314
|
if (!(0, _tmagic_utils.isPop)(src) && newConfig.style?.position) {
|
|
5871
|
-
if ((0, _tmagic_stage.isFixed)(newConfig.style) && !(0, _tmagic_stage.isFixed)(src.style || {})) newConfig.style = change2Fixed(newConfig,
|
|
5872
|
-
else if (!(0, _tmagic_stage.isFixed)(newConfig.style) && (0, _tmagic_stage.isFixed)(src.style || {})) newConfig.style = await Fixed2Other(newConfig,
|
|
6315
|
+
if ((0, _tmagic_stage.isFixed)(newConfig.style) && !(0, _tmagic_stage.isFixed)(src.style || {})) newConfig.style = change2Fixed(newConfig, path);
|
|
6316
|
+
else if (!(0, _tmagic_stage.isFixed)(newConfig.style) && (0, _tmagic_stage.isFixed)(src.style || {})) newConfig.style = await Fixed2Other(newConfig, path, getLayoutFn);
|
|
5873
6317
|
}
|
|
5874
6318
|
return newConfig;
|
|
5875
6319
|
};
|
|
@@ -6010,6 +6454,40 @@
|
|
|
6010
6454
|
aborted: false
|
|
6011
6455
|
};
|
|
6012
6456
|
};
|
|
6457
|
+
/**
|
|
6458
|
+
* 给「回滚」生成的新 step 用的简短描述生成器。
|
|
6459
|
+
* 与 UI 层 `describePageStep` 同义,但避免 service 反向依赖 layouts/,故放在此工具函数中。
|
|
6460
|
+
*/
|
|
6461
|
+
var describeStepForRevert = (step) => {
|
|
6462
|
+
const items = step.diff ?? [];
|
|
6463
|
+
const withId = (node, label) => {
|
|
6464
|
+
const id = node?.id;
|
|
6465
|
+
if (id === void 0 || id === null || `${id}` === "") return label;
|
|
6466
|
+
return label ? `${label}(id: ${id})` : `id: ${id}`;
|
|
6467
|
+
};
|
|
6468
|
+
switch (step.opType) {
|
|
6469
|
+
case "add": {
|
|
6470
|
+
const count = items.length;
|
|
6471
|
+
const node = items[0]?.newSchema;
|
|
6472
|
+
const label = node?.name || node?.type || "";
|
|
6473
|
+
return `撤回新增 ${count} 个节点${count === 1 ? `(${withId(node, label)})` : ""}`;
|
|
6474
|
+
}
|
|
6475
|
+
case "remove": {
|
|
6476
|
+
const count = items.length;
|
|
6477
|
+
const node = items[0]?.oldSchema;
|
|
6478
|
+
const label = node?.name || node?.type || "";
|
|
6479
|
+
return `还原已删除的 ${count} 个节点${count === 1 ? `(${withId(node, label)})` : ""}`;
|
|
6480
|
+
}
|
|
6481
|
+
default:
|
|
6482
|
+
if (items.length === 1) {
|
|
6483
|
+
const { newSchema, oldSchema, changeRecords } = items[0];
|
|
6484
|
+
const target = withId(newSchema || oldSchema, newSchema?.name || newSchema?.type || oldSchema?.name || oldSchema?.type || "");
|
|
6485
|
+
const propPath = changeRecords?.[0]?.propPath;
|
|
6486
|
+
return propPath ? `还原 ${target} · ${propPath}` : `还原 ${target}`;
|
|
6487
|
+
}
|
|
6488
|
+
return `还原 ${items.length} 个节点的修改`;
|
|
6489
|
+
}
|
|
6490
|
+
};
|
|
6013
6491
|
//#endregion
|
|
6014
6492
|
//#region packages/editor/src/utils/operator.ts
|
|
6015
6493
|
/**
|
|
@@ -6078,35 +6556,15 @@
|
|
|
6078
6556
|
//#endregion
|
|
6079
6557
|
//#region packages/editor/src/services/editor.ts
|
|
6080
6558
|
/**
|
|
6081
|
-
*
|
|
6082
|
-
*
|
|
6559
|
+
* 把「变更前后节点快照」列表归一成 update 类型的 {@link StepDiffItem} 列表,供 {@link StepValue.diff} 使用。
|
|
6560
|
+
* `changeRecords` 来自 form 端的 propPath/value 列表,撤销/重做时只对这些 propPath 做局部更新;
|
|
6561
|
+
* 缺省(未传 / 空数组)才退化为整节点替换。
|
|
6083
6562
|
*/
|
|
6084
|
-
var
|
|
6085
|
-
|
|
6086
|
-
|
|
6087
|
-
|
|
6088
|
-
|
|
6089
|
-
const label = node?.name || node?.type || (node?.id !== void 0 ? `${node.id}` : "");
|
|
6090
|
-
return `撤回新增 ${count} 个节点${count === 1 && label ? `(${label})` : ""}`;
|
|
6091
|
-
}
|
|
6092
|
-
case "remove": {
|
|
6093
|
-
const count = step.removedItems?.length ?? 0;
|
|
6094
|
-
const node = step.removedItems?.[0]?.node;
|
|
6095
|
-
const label = node?.name || node?.type || (node?.id !== void 0 ? `${node.id}` : "");
|
|
6096
|
-
return `还原已删除的 ${count} 个节点${count === 1 && label ? `(${label})` : ""}`;
|
|
6097
|
-
}
|
|
6098
|
-
default: {
|
|
6099
|
-
const items = step.updatedItems ?? [];
|
|
6100
|
-
if (items.length === 1) {
|
|
6101
|
-
const { newNode, oldNode, changeRecords } = items[0];
|
|
6102
|
-
const target = newNode?.name || newNode?.type || oldNode?.name || oldNode?.type || `${newNode?.id ?? ""}`;
|
|
6103
|
-
const propPath = changeRecords?.[0]?.propPath;
|
|
6104
|
-
return propPath ? `还原 ${target} · ${propPath}` : `还原 ${target}`;
|
|
6105
|
-
}
|
|
6106
|
-
return `还原 ${items.length} 个节点的修改`;
|
|
6107
|
-
}
|
|
6108
|
-
}
|
|
6109
|
-
};
|
|
6563
|
+
var buildUpdateDiff = (items) => items.map(({ oldNode, newNode, changeRecords }) => ({
|
|
6564
|
+
oldSchema: oldNode,
|
|
6565
|
+
newSchema: newNode,
|
|
6566
|
+
...changeRecords?.length ? { changeRecords } : {}
|
|
6567
|
+
}));
|
|
6110
6568
|
var Editor = class extends BaseService {
|
|
6111
6569
|
state = (0, vue.reactive)({
|
|
6112
6570
|
root: null,
|
|
@@ -6124,6 +6582,12 @@
|
|
|
6124
6582
|
alwaysMultiSelect: false
|
|
6125
6583
|
});
|
|
6126
6584
|
selectionBeforeOp = null;
|
|
6585
|
+
/**
|
|
6586
|
+
* 最近一次 pushOpHistory 写入的历史记录 uuid。
|
|
6587
|
+
* 供 *AndGetHistoryId 系列方法在调用普通操作后取回本次产生的历史记录 id;
|
|
6588
|
+
* 普通操作不会读取它,调用前由 *AndGetHistoryId 重置为 null。
|
|
6589
|
+
*/
|
|
6590
|
+
lastPushedHistoryId = null;
|
|
6127
6591
|
constructor() {
|
|
6128
6592
|
super(canUsePluginMethods.async.map((methodName) => ({
|
|
6129
6593
|
name: methodName,
|
|
@@ -6138,8 +6602,9 @@
|
|
|
6138
6602
|
* 设置当前指点节点配置
|
|
6139
6603
|
* @param name 'root' | 'page' | 'parent' | 'node' | 'highlightNode' | 'nodes' | 'stage' | 'modifiedNodeIds' | 'pageLength' | 'pageFragmentLength
|
|
6140
6604
|
* @param value MNode
|
|
6605
|
+
* @param options.historySource 设置 root 时,本次变更写入历史记录的「操作来源」(仅 name === 'root' 时生效)
|
|
6141
6606
|
*/
|
|
6142
|
-
set(name, value) {
|
|
6607
|
+
set(name, value, options = {}) {
|
|
6143
6608
|
const preValue = this.state[name];
|
|
6144
6609
|
this.state[name] = value;
|
|
6145
6610
|
if (name === "nodes" && Array.isArray(value)) this.set("node", value[0]);
|
|
@@ -6150,12 +6615,19 @@
|
|
|
6150
6615
|
this.state.pageLength = getPageList(app).length || 0;
|
|
6151
6616
|
this.state.pageFragmentLength = getPageFragmentList(app).length || 0;
|
|
6152
6617
|
this.state.stageLoading = this.state.pageLength !== 0;
|
|
6618
|
+
if (preValue && !isEmpty(preValue)) this.pushRootDiffHistory(preValue, app, options.historySource);
|
|
6619
|
+
else app.items?.forEach((pageNode) => {
|
|
6620
|
+
if (pageNode?.id !== void 0 && !history_default.getPageMarker(pageNode.id)) history_default.setPageMarker(pageNode.id, {
|
|
6621
|
+
name: pageNode.name,
|
|
6622
|
+
source: options.historySource
|
|
6623
|
+
});
|
|
6624
|
+
});
|
|
6153
6625
|
} else {
|
|
6154
6626
|
this.state.pageLength = 0;
|
|
6155
6627
|
this.state.pageFragmentLength = 0;
|
|
6156
6628
|
this.state.stageLoading = false;
|
|
6157
6629
|
}
|
|
6158
|
-
this.emit("root-change", value, preValue);
|
|
6630
|
+
this.emit("root-change", value, preValue, options);
|
|
6159
6631
|
}
|
|
6160
6632
|
}
|
|
6161
6633
|
/**
|
|
@@ -6175,7 +6647,25 @@
|
|
|
6175
6647
|
getNodeInfo(id, raw = true) {
|
|
6176
6648
|
let root = this.get("root");
|
|
6177
6649
|
if (raw) root = (0, vue.toRaw)(root);
|
|
6178
|
-
|
|
6650
|
+
if (!root) return {
|
|
6651
|
+
node: null,
|
|
6652
|
+
parent: null,
|
|
6653
|
+
page: null,
|
|
6654
|
+
path: []
|
|
6655
|
+
};
|
|
6656
|
+
if (id === root.id) return {
|
|
6657
|
+
node: root,
|
|
6658
|
+
parent: null,
|
|
6659
|
+
page: null,
|
|
6660
|
+
path: []
|
|
6661
|
+
};
|
|
6662
|
+
const pageIdStr = `${this.get("page")?.id || ""}`;
|
|
6663
|
+
const currentPageNode = root.items?.find((item) => `${item.id}` === pageIdStr);
|
|
6664
|
+
if (currentPageNode && `${id}` !== pageIdStr) {
|
|
6665
|
+
const info = (0, _tmagic_utils.getNodeInfo)(id, currentPageNode);
|
|
6666
|
+
if (info.node) return info;
|
|
6667
|
+
}
|
|
6668
|
+
return (0, _tmagic_utils.getNodeInfo)(id, root, currentPageNode);
|
|
6179
6669
|
}
|
|
6180
6670
|
/**
|
|
6181
6671
|
* 根据ID获取指点节点配置
|
|
@@ -6368,23 +6858,26 @@
|
|
|
6368
6858
|
}
|
|
6369
6859
|
if (!((0, _tmagic_utils.isPage)(newNodes[0]) || (0, _tmagic_utils.isPageFragment)(newNodes[0]))) {
|
|
6370
6860
|
const pageForOp = this.getNodeInfo(newNodes[0].id, false).page;
|
|
6371
|
-
if (!doNotPushHistory)
|
|
6372
|
-
|
|
6373
|
-
|
|
6374
|
-
|
|
6375
|
-
indexMap: Object.fromEntries(newNodes.map((n) => {
|
|
6861
|
+
if (!doNotPushHistory) {
|
|
6862
|
+
const parentId = (this.getParentById(newNodes[0].id, false) ?? this.get("root")).id;
|
|
6863
|
+
this.pushOpHistory("add", {
|
|
6864
|
+
diff: newNodes.map((n) => {
|
|
6376
6865
|
const p = this.getParentById(n.id, false);
|
|
6377
|
-
|
|
6378
|
-
|
|
6379
|
-
|
|
6380
|
-
|
|
6381
|
-
|
|
6382
|
-
|
|
6383
|
-
|
|
6384
|
-
|
|
6385
|
-
|
|
6386
|
-
|
|
6387
|
-
|
|
6866
|
+
const idx = p ? getNodeIndex(n.id, p) : -1;
|
|
6867
|
+
return {
|
|
6868
|
+
newSchema: cloneDeep$1((0, vue.toRaw)(n)),
|
|
6869
|
+
parentId,
|
|
6870
|
+
index: typeof idx === "number" ? idx : -1
|
|
6871
|
+
};
|
|
6872
|
+
}),
|
|
6873
|
+
pageData: {
|
|
6874
|
+
name: pageForOp?.name || "",
|
|
6875
|
+
id: pageForOp.id
|
|
6876
|
+
},
|
|
6877
|
+
historyDescription,
|
|
6878
|
+
source: historySource
|
|
6879
|
+
});
|
|
6880
|
+
} else this.selectionBeforeOp = null;
|
|
6388
6881
|
}
|
|
6389
6882
|
this.emit("add", newNodes);
|
|
6390
6883
|
return Array.isArray(addNode) ? newNodes : newNodes[0];
|
|
@@ -6464,7 +6957,7 @@
|
|
|
6464
6957
|
};
|
|
6465
6958
|
const idx = getNodeIndex(curNode.id, parent);
|
|
6466
6959
|
removedItems.push({
|
|
6467
|
-
|
|
6960
|
+
oldSchema: cloneDeep$1((0, vue.toRaw)(curNode)),
|
|
6468
6961
|
parentId: parent.id,
|
|
6469
6962
|
index: typeof idx === "number" ? idx : -1
|
|
6470
6963
|
});
|
|
@@ -6475,7 +6968,7 @@
|
|
|
6475
6968
|
doNotSwitchPage
|
|
6476
6969
|
})));
|
|
6477
6970
|
if (removedItems.length > 0 && pageForOp) if (!doNotPushHistory) this.pushOpHistory("remove", {
|
|
6478
|
-
|
|
6971
|
+
diff: removedItems,
|
|
6479
6972
|
pageData: pageForOp,
|
|
6480
6973
|
historyDescription,
|
|
6481
6974
|
source: historySource
|
|
@@ -6483,18 +6976,17 @@
|
|
|
6483
6976
|
else this.selectionBeforeOp = null;
|
|
6484
6977
|
this.emit("remove", nodes);
|
|
6485
6978
|
}
|
|
6486
|
-
async doUpdate(config, { changeRecords = [] } = {}) {
|
|
6487
|
-
|
|
6488
|
-
if (!root) throw new Error("root为空");
|
|
6979
|
+
async doUpdate(config, { changeRecords = [], historySource } = {}) {
|
|
6980
|
+
if (!this.get("root")) throw new Error("root为空");
|
|
6489
6981
|
if (!config?.id) throw new Error("没有配置或者配置缺少id值");
|
|
6490
6982
|
const info = this.getNodeInfo(config.id, false);
|
|
6491
6983
|
if (!info.node) throw new Error(`获取不到id为${config.id}的节点`);
|
|
6492
6984
|
const node = (0, vue.toRaw)(info.node);
|
|
6493
|
-
let newConfig = await toggleFixedPosition((0, vue.toRaw)(config), node,
|
|
6985
|
+
let newConfig = await toggleFixedPosition((0, vue.toRaw)(config), node, info.path, this.getLayout);
|
|
6494
6986
|
newConfig = mergeWith(cloneDeep$1(node), newConfig, editorNodeMergeCustomizer);
|
|
6495
6987
|
if (!newConfig.type) throw new Error("配置缺少type值");
|
|
6496
6988
|
if (newConfig.type === _tmagic_core.NodeType.ROOT) {
|
|
6497
|
-
this.set("root", newConfig);
|
|
6989
|
+
this.set("root", newConfig, { historySource });
|
|
6498
6990
|
return {
|
|
6499
6991
|
oldNode: node,
|
|
6500
6992
|
newNode: newConfig,
|
|
@@ -6544,17 +7036,20 @@
|
|
|
6544
7036
|
const nodes = Array.isArray(config) ? config : [config];
|
|
6545
7037
|
const updateData = await Promise.all(nodes.map((node, index) => {
|
|
6546
7038
|
const recordsForNode = changeRecordList ? changeRecordList[index] ?? [] : changeRecords ?? [];
|
|
6547
|
-
return this.doUpdate(node, {
|
|
7039
|
+
return this.doUpdate(node, {
|
|
7040
|
+
changeRecords: recordsForNode,
|
|
7041
|
+
historySource
|
|
7042
|
+
});
|
|
6548
7043
|
}));
|
|
6549
7044
|
if (updateData[0].oldNode?.type !== _tmagic_core.NodeType.ROOT) {
|
|
6550
7045
|
if (this.get("nodes").length) if (!doNotPushHistory) {
|
|
6551
7046
|
const pageForOp = this.getNodeInfo(nodes[0].id, false).page;
|
|
6552
7047
|
this.pushOpHistory("update", {
|
|
6553
|
-
|
|
7048
|
+
diff: buildUpdateDiff(updateData.map((d) => ({
|
|
6554
7049
|
oldNode: cloneDeep$1(d.oldNode),
|
|
6555
|
-
newNode: cloneDeep$1(
|
|
7050
|
+
newNode: cloneDeep$1(d.newNode),
|
|
6556
7051
|
changeRecords: d.changeRecords?.length ? cloneDeep$1(d.changeRecords) : void 0
|
|
6557
|
-
}))
|
|
7052
|
+
}))),
|
|
6558
7053
|
pageData: {
|
|
6559
7054
|
name: pageForOp?.name || "",
|
|
6560
7055
|
id: pageForOp.id
|
|
@@ -6717,10 +7212,10 @@
|
|
|
6717
7212
|
if (!doNotPushHistory) {
|
|
6718
7213
|
const pageForOp = this.getNodeInfo(node.id, false).page;
|
|
6719
7214
|
this.pushOpHistory("update", {
|
|
6720
|
-
|
|
7215
|
+
diff: buildUpdateDiff([{
|
|
6721
7216
|
oldNode: oldParent,
|
|
6722
7217
|
newNode: cloneDeep$1((0, vue.toRaw)(parent))
|
|
6723
|
-
}]
|
|
7218
|
+
}]),
|
|
6724
7219
|
pageData: {
|
|
6725
7220
|
name: pageForOp?.name || "",
|
|
6726
7221
|
id: pageForOp.id
|
|
@@ -6794,7 +7289,7 @@
|
|
|
6794
7289
|
id: target.id
|
|
6795
7290
|
};
|
|
6796
7291
|
this.pushOpHistory("update", {
|
|
6797
|
-
|
|
7292
|
+
diff: buildUpdateDiff(updatedItems),
|
|
6798
7293
|
pageData: historyPage,
|
|
6799
7294
|
historyDescription,
|
|
6800
7295
|
source: historySource
|
|
@@ -6845,7 +7340,7 @@
|
|
|
6845
7340
|
if (!doNotPushHistory) {
|
|
6846
7341
|
const pageForOp = this.getNodeInfo(configs[0].id, false).page;
|
|
6847
7342
|
this.pushOpHistory("update", {
|
|
6848
|
-
|
|
7343
|
+
diff: buildUpdateDiff(updatedItems),
|
|
6849
7344
|
pageData: {
|
|
6850
7345
|
name: pageForOp?.name || "",
|
|
6851
7346
|
id: pageForOp.id
|
|
@@ -6861,6 +7356,64 @@
|
|
|
6861
7356
|
});
|
|
6862
7357
|
}
|
|
6863
7358
|
/**
|
|
7359
|
+
* 下列 *AndGetHistoryId 方法与对应的普通操作(add / remove / update ...)行为完全一致,
|
|
7360
|
+
* 返回值在 {@link DslOpWithHistoryIdsResult} 中同时包含原操作结果与本次写入历史栈的 uuid 列表({@link StepValue.uuid}),
|
|
7361
|
+
* 可用于精确引用 / 定位该条历史记录(埋点、revert、跨端同步等)。
|
|
7362
|
+
*
|
|
7363
|
+
* 当本次操作未写入历史(doNotPushHistory 为 true、或操作无实际变更 / 提前返回)时 historyIds 为 `[]`。
|
|
7364
|
+
*/
|
|
7365
|
+
/** 等价于 {@link add},并额外返回本次写入历史记录的 uuid 列表(未入栈时 historyIds 为 `[]`)。 */
|
|
7366
|
+
async addAndGetHistoryId(addNode, parent, options = {}) {
|
|
7367
|
+
this.lastPushedHistoryId = null;
|
|
7368
|
+
return {
|
|
7369
|
+
result: await this.add(addNode, parent, options),
|
|
7370
|
+
historyIds: getLastPushedHistoryIds(this.lastPushedHistoryId)
|
|
7371
|
+
};
|
|
7372
|
+
}
|
|
7373
|
+
/** 等价于 {@link remove},并额外返回本次写入历史记录的 uuid 列表(未入栈时 historyIds 为 `[]`)。 */
|
|
7374
|
+
async removeAndGetHistoryId(nodeOrNodeList, options = {}) {
|
|
7375
|
+
this.lastPushedHistoryId = null;
|
|
7376
|
+
await this.remove(nodeOrNodeList, options);
|
|
7377
|
+
return {
|
|
7378
|
+
result: void 0,
|
|
7379
|
+
historyIds: getLastPushedHistoryIds(this.lastPushedHistoryId)
|
|
7380
|
+
};
|
|
7381
|
+
}
|
|
7382
|
+
/** 等价于 {@link update},并额外返回本次写入历史记录的 uuid 列表(未入栈时 historyIds 为 `[]`)。 */
|
|
7383
|
+
async updateAndGetHistoryId(config, data = {}) {
|
|
7384
|
+
this.lastPushedHistoryId = null;
|
|
7385
|
+
return {
|
|
7386
|
+
result: await this.update(config, data),
|
|
7387
|
+
historyIds: getLastPushedHistoryIds(this.lastPushedHistoryId)
|
|
7388
|
+
};
|
|
7389
|
+
}
|
|
7390
|
+
/** 等价于 {@link moveLayer},并额外返回本次写入历史记录的 uuid 列表(未入栈时 historyIds 为 `[]`)。 */
|
|
7391
|
+
async moveLayerAndGetHistoryId(offset, options = {}) {
|
|
7392
|
+
this.lastPushedHistoryId = null;
|
|
7393
|
+
await this.moveLayer(offset, options);
|
|
7394
|
+
return {
|
|
7395
|
+
result: void 0,
|
|
7396
|
+
historyIds: getLastPushedHistoryIds(this.lastPushedHistoryId)
|
|
7397
|
+
};
|
|
7398
|
+
}
|
|
7399
|
+
/** 等价于 {@link moveToContainer},并额外返回本次写入历史记录的 uuid 列表(未入栈时 historyIds 为 `[]`)。 */
|
|
7400
|
+
async moveToContainerAndGetHistoryId(config, targetId, options = {}) {
|
|
7401
|
+
this.lastPushedHistoryId = null;
|
|
7402
|
+
return {
|
|
7403
|
+
result: await this.moveToContainer(config, targetId, options),
|
|
7404
|
+
historyIds: getLastPushedHistoryIds(this.lastPushedHistoryId)
|
|
7405
|
+
};
|
|
7406
|
+
}
|
|
7407
|
+
/** 等价于 {@link dragTo},并额外返回本次写入历史记录的 uuid 列表(未入栈时 historyIds 为 `[]`)。 */
|
|
7408
|
+
async dragToAndGetHistoryId(config, targetParent, targetIndex, options = {}) {
|
|
7409
|
+
this.lastPushedHistoryId = null;
|
|
7410
|
+
await this.dragTo(config, targetParent, targetIndex, options);
|
|
7411
|
+
return {
|
|
7412
|
+
result: void 0,
|
|
7413
|
+
historyIds: getLastPushedHistoryIds(this.lastPushedHistoryId)
|
|
7414
|
+
};
|
|
7415
|
+
}
|
|
7416
|
+
/**
|
|
6864
7417
|
* 撤销当前操作
|
|
6865
7418
|
* @returns 被撤销的操作
|
|
6866
7419
|
*/
|
|
@@ -6898,9 +7451,10 @@
|
|
|
6898
7451
|
const entry = history_default.getPageStepList()[index];
|
|
6899
7452
|
if (!entry?.applied) return null;
|
|
6900
7453
|
const { step } = entry;
|
|
7454
|
+
if (step.opType === "initial") return null;
|
|
6901
7455
|
if (!this.get("root")) return null;
|
|
6902
7456
|
if (step.opType === "update") {
|
|
6903
|
-
const items = step.
|
|
7457
|
+
const items = step.diff ?? [];
|
|
6904
7458
|
if (!items.length || !items.every((item) => item.changeRecords?.length)) return null;
|
|
6905
7459
|
}
|
|
6906
7460
|
let revertedStep = null;
|
|
@@ -6917,24 +7471,26 @@
|
|
|
6917
7471
|
};
|
|
6918
7472
|
try {
|
|
6919
7473
|
switch (step.opType) {
|
|
6920
|
-
case "add":
|
|
6921
|
-
const
|
|
6922
|
-
|
|
6923
|
-
const existing = this.getNodeById(
|
|
7474
|
+
case "add":
|
|
7475
|
+
for (const { newSchema } of step.diff ?? []) {
|
|
7476
|
+
if (!newSchema) continue;
|
|
7477
|
+
const existing = this.getNodeById(newSchema.id, false);
|
|
6924
7478
|
if (existing) await this.remove(existing, opts);
|
|
6925
7479
|
}
|
|
6926
7480
|
break;
|
|
6927
|
-
}
|
|
6928
7481
|
case "remove": {
|
|
6929
|
-
const sorted = [...step.
|
|
6930
|
-
for (const {
|
|
7482
|
+
const sorted = [...step.diff ?? []].sort((a, b) => (a.index ?? 0) - (b.index ?? 0));
|
|
7483
|
+
for (const { oldSchema, parentId } of sorted) {
|
|
7484
|
+
if (!oldSchema || parentId === void 0) continue;
|
|
6931
7485
|
const parent = this.getNodeById(parentId, false);
|
|
6932
|
-
if (parent) await this.add([cloneDeep$1(
|
|
7486
|
+
if (parent) await this.add([cloneDeep$1(oldSchema)], parent, opts);
|
|
6933
7487
|
}
|
|
6934
7488
|
break;
|
|
6935
7489
|
}
|
|
6936
7490
|
case "update": {
|
|
6937
|
-
const configs = (step.
|
|
7491
|
+
const configs = (step.diff ?? []).filter((item) => item.oldSchema && item.newSchema).map(({ oldSchema, newSchema, changeRecords }) => {
|
|
7492
|
+
const oldNode = oldSchema;
|
|
7493
|
+
const newNode = newSchema;
|
|
6938
7494
|
if (changeRecords?.length) {
|
|
6939
7495
|
const patch = {
|
|
6940
7496
|
id: newNode.id,
|
|
@@ -6964,6 +7520,21 @@
|
|
|
6964
7520
|
return revertedStep;
|
|
6965
7521
|
}
|
|
6966
7522
|
/**
|
|
7523
|
+
* 通过历史记录 uuid 回滚当前页面的历史步骤,语义与 {@link revertPageStep} 完全一致,
|
|
7524
|
+
* 仅入参从 index 改为 uuid 列表({@link StepValue.uuid})。按数组顺序依次回滚,
|
|
7525
|
+
* 返回与入参同序的结果列表(某项失败时为 `null`)。
|
|
7526
|
+
*
|
|
7527
|
+
* @param uuids 目标历史记录的 uuid 列表,通常由 *AndGetHistoryId 方法返回的 `historyIds`
|
|
7528
|
+
*/
|
|
7529
|
+
async revertPageStepById(uuids) {
|
|
7530
|
+
const results = [];
|
|
7531
|
+
for (const uuid of uuids) {
|
|
7532
|
+
const index = history_default.getPageStepIndexByUuid(uuid);
|
|
7533
|
+
results.push(index < 0 ? null : await this.revertPageStep(index));
|
|
7534
|
+
}
|
|
7535
|
+
return results;
|
|
7536
|
+
}
|
|
7537
|
+
/**
|
|
6967
7538
|
* 跳转当前页面历史栈到指定游标位置。
|
|
6968
7539
|
*
|
|
6969
7540
|
* `targetCursor` 与 `UndoRedo.getCursor()` 同义:表示"已应用步骤数量",
|
|
@@ -7039,19 +7610,83 @@
|
|
|
7039
7610
|
if (this.selectionBeforeOp) return;
|
|
7040
7611
|
this.selectionBeforeOp = this.get("nodes").map((n) => n.id);
|
|
7041
7612
|
}
|
|
7042
|
-
|
|
7613
|
+
/**
|
|
7614
|
+
* 比较「上一次 root」与「新 root」的页面 / 页面片,按页面粒度把整体替换拆成历史记录:
|
|
7615
|
+
* - 新旧都存在且内容变化的页面 → 一条 `update`(整页快照替换,无 changeRecords);
|
|
7616
|
+
* - 仅新 root 存在的页面 → 一条 `add`;
|
|
7617
|
+
* - 仅旧 root 存在的页面 → 一条 `remove`。
|
|
7618
|
+
*
|
|
7619
|
+
* 每条记录落到对应页面自己的历史栈(与普通节点操作一致),并标记来源 `source`。
|
|
7620
|
+
* 内容未变化的页面不产生记录,避免重复设置相同 DSL 时产生噪声。
|
|
7621
|
+
*/
|
|
7622
|
+
pushRootDiffHistory(preRoot, nextRoot, source) {
|
|
7623
|
+
const prevPages = preRoot?.items || [];
|
|
7624
|
+
const nextPages = nextRoot?.items || [];
|
|
7625
|
+
const prevMap = new Map(prevPages.map((p) => [`${p.id}`, p]));
|
|
7626
|
+
const nextMap = new Map(nextPages.map((p) => [`${p.id}`, p]));
|
|
7627
|
+
const indexInItems = (root, id) => (root.items ?? []).findIndex((item) => `${item.id}` === `${id}`);
|
|
7628
|
+
nextPages.forEach((nextPage) => {
|
|
7629
|
+
const prevPage = prevMap.get(`${nextPage.id}`);
|
|
7630
|
+
if (!prevPage) this.pushPageDiffStep("add", nextPage, {
|
|
7631
|
+
newSchema: cloneDeep$1((0, vue.toRaw)(nextPage)),
|
|
7632
|
+
parentId: nextRoot.id,
|
|
7633
|
+
index: indexInItems(nextRoot, nextPage.id)
|
|
7634
|
+
}, source);
|
|
7635
|
+
else if (!isEqual((0, vue.toRaw)(prevPage), (0, vue.toRaw)(nextPage))) this.pushPageDiffStep("update", nextPage, {
|
|
7636
|
+
oldSchema: cloneDeep$1((0, vue.toRaw)(prevPage)),
|
|
7637
|
+
newSchema: cloneDeep$1((0, vue.toRaw)(nextPage))
|
|
7638
|
+
}, source);
|
|
7639
|
+
});
|
|
7640
|
+
prevPages.forEach((prevPage) => {
|
|
7641
|
+
if (!nextMap.has(`${prevPage.id}`)) this.pushPageDiffStep("remove", prevPage, {
|
|
7642
|
+
oldSchema: cloneDeep$1((0, vue.toRaw)(prevPage)),
|
|
7643
|
+
parentId: preRoot.id,
|
|
7644
|
+
index: indexInItems(preRoot, prevPage.id)
|
|
7645
|
+
}, source);
|
|
7646
|
+
});
|
|
7647
|
+
}
|
|
7648
|
+
/**
|
|
7649
|
+
* 构造一条页面级「set root」历史记录(不携带选区 / modifiedNodeIds 上下文)并落到该页面自己的栈。
|
|
7650
|
+
*
|
|
7651
|
+
* 连续 set root 替换:若该页栈最新一条已是**同来源**的 set root 记录({@link StepValue.rootStep} 且 `source` 相同),
|
|
7652
|
+
* 则用本次记录**替换**它而非新增,避免源码反复保存 / 外部重设 DSL 时堆积多条 root 记录;
|
|
7653
|
+
* 来源不同则照常新增(initial 基线不是 rootStep,不在此列)。
|
|
7654
|
+
*/
|
|
7655
|
+
pushPageDiffStep(opType, page, diffItem, source) {
|
|
7656
|
+
const step = {
|
|
7657
|
+
uuid: (0, _tmagic_utils.guid)(),
|
|
7658
|
+
data: {
|
|
7659
|
+
name: page.name || "",
|
|
7660
|
+
id: page.id
|
|
7661
|
+
},
|
|
7662
|
+
opType,
|
|
7663
|
+
selectedBefore: [],
|
|
7664
|
+
selectedAfter: [],
|
|
7665
|
+
modifiedNodeIds: /* @__PURE__ */ new Map(),
|
|
7666
|
+
diff: [diffItem],
|
|
7667
|
+
rootStep: true
|
|
7668
|
+
};
|
|
7669
|
+
if (source) step.source = source;
|
|
7670
|
+
const top = history_default.getCurrentPageStep(page.id);
|
|
7671
|
+
if (top?.rootStep && top.source === source) history_default.replaceCurrentPageStep(step, page.id);
|
|
7672
|
+
else history_default.push(step, page.id);
|
|
7673
|
+
}
|
|
7674
|
+
pushOpHistory(opType, { diff, pageData, historyDescription, source }) {
|
|
7043
7675
|
const step = {
|
|
7676
|
+
uuid: (0, _tmagic_utils.guid)(),
|
|
7044
7677
|
data: pageData,
|
|
7045
7678
|
opType,
|
|
7046
7679
|
selectedBefore: this.selectionBeforeOp ?? [],
|
|
7047
7680
|
selectedAfter: this.get("nodes").map((n) => n.id),
|
|
7048
7681
|
modifiedNodeIds: new Map(this.get("modifiedNodeIds")),
|
|
7049
|
-
|
|
7682
|
+
diff
|
|
7050
7683
|
};
|
|
7051
7684
|
if (historyDescription) step.historyDescription = historyDescription;
|
|
7052
7685
|
if (source) step.source = source;
|
|
7053
|
-
history_default.push(step, pageData.id);
|
|
7686
|
+
const historyId = history_default.push(step, pageData.id) ? step.uuid : null;
|
|
7687
|
+
this.lastPushedHistoryId = historyId;
|
|
7054
7688
|
this.selectionBeforeOp = null;
|
|
7689
|
+
return historyId;
|
|
7055
7690
|
}
|
|
7056
7691
|
/**
|
|
7057
7692
|
* 应用历史操作(撤销 / 重做)
|
|
@@ -7066,6 +7701,7 @@
|
|
|
7066
7701
|
* @param reverse true = 撤销,false = 重做
|
|
7067
7702
|
*/
|
|
7068
7703
|
async applyHistoryOp(step, reverse) {
|
|
7704
|
+
if (step.opType === "initial") return;
|
|
7069
7705
|
const root = this.get("root");
|
|
7070
7706
|
const stage = this.get("stage");
|
|
7071
7707
|
if (!root) return;
|
|
@@ -7076,56 +7712,59 @@
|
|
|
7076
7712
|
};
|
|
7077
7713
|
switch (step.opType) {
|
|
7078
7714
|
case "add": {
|
|
7079
|
-
const
|
|
7080
|
-
if (reverse) for (const
|
|
7081
|
-
|
|
7715
|
+
const items = step.diff ?? [];
|
|
7716
|
+
if (reverse) for (const { newSchema } of items) {
|
|
7717
|
+
if (!newSchema) continue;
|
|
7718
|
+
const existing = this.getNodeById(newSchema.id, false);
|
|
7082
7719
|
if (existing) await this.remove(existing, commonOpts);
|
|
7083
7720
|
}
|
|
7084
7721
|
else {
|
|
7085
|
-
const
|
|
7086
|
-
|
|
7087
|
-
|
|
7088
|
-
|
|
7089
|
-
|
|
7090
|
-
if (parent.items)
|
|
7091
|
-
|
|
7092
|
-
|
|
7093
|
-
|
|
7094
|
-
|
|
7095
|
-
|
|
7096
|
-
|
|
7097
|
-
|
|
7098
|
-
});
|
|
7099
|
-
}
|
|
7722
|
+
const sorted = [...items].sort((a, b) => (a.index ?? 0) - (b.index ?? 0));
|
|
7723
|
+
for (const { newSchema, parentId, index } of sorted) {
|
|
7724
|
+
if (!newSchema || parentId === void 0) continue;
|
|
7725
|
+
const parent = this.getNodeById(parentId, false);
|
|
7726
|
+
if (parent?.items) {
|
|
7727
|
+
if (typeof index === "number" && index >= 0 && index < parent.items.length) parent.items.splice(index, 0, cloneDeep$1(newSchema));
|
|
7728
|
+
else parent.items.push(cloneDeep$1(newSchema));
|
|
7729
|
+
await stage?.add({
|
|
7730
|
+
config: cloneDeep$1(newSchema),
|
|
7731
|
+
parent: cloneDeep$1(parent),
|
|
7732
|
+
parentId: parent.id,
|
|
7733
|
+
root: cloneDeep$1(root)
|
|
7734
|
+
});
|
|
7100
7735
|
}
|
|
7101
7736
|
}
|
|
7102
7737
|
}
|
|
7103
7738
|
break;
|
|
7104
7739
|
}
|
|
7105
7740
|
case "remove": {
|
|
7106
|
-
const items = step.
|
|
7741
|
+
const items = step.diff ?? [];
|
|
7107
7742
|
if (reverse) {
|
|
7108
|
-
const sorted = [...items].sort((a, b) => a.index - b.index);
|
|
7109
|
-
for (const {
|
|
7743
|
+
const sorted = [...items].sort((a, b) => (a.index ?? 0) - (b.index ?? 0));
|
|
7744
|
+
for (const { oldSchema, parentId, index } of sorted) {
|
|
7745
|
+
if (!oldSchema || parentId === void 0) continue;
|
|
7110
7746
|
const parent = this.getNodeById(parentId, false);
|
|
7111
7747
|
if (parent?.items) {
|
|
7112
|
-
parent.items.splice(index, 0, cloneDeep$1(
|
|
7748
|
+
parent.items.splice(index ?? parent.items.length, 0, cloneDeep$1(oldSchema));
|
|
7113
7749
|
await stage?.add({
|
|
7114
|
-
config: cloneDeep$1(
|
|
7750
|
+
config: cloneDeep$1(oldSchema),
|
|
7115
7751
|
parent: cloneDeep$1(parent),
|
|
7116
7752
|
parentId,
|
|
7117
7753
|
root: cloneDeep$1(root)
|
|
7118
7754
|
});
|
|
7119
7755
|
}
|
|
7120
7756
|
}
|
|
7121
|
-
} else for (const {
|
|
7122
|
-
|
|
7757
|
+
} else for (const { oldSchema } of items) {
|
|
7758
|
+
if (!oldSchema) continue;
|
|
7759
|
+
const existing = this.getNodeById(oldSchema.id, false);
|
|
7123
7760
|
if (existing) await this.remove(existing, commonOpts);
|
|
7124
7761
|
}
|
|
7125
7762
|
break;
|
|
7126
7763
|
}
|
|
7127
7764
|
case "update": {
|
|
7128
|
-
const configs = (step.
|
|
7765
|
+
const configs = (step.diff ?? []).filter((item) => item.oldSchema && item.newSchema).map(({ oldSchema, newSchema, changeRecords }) => {
|
|
7766
|
+
const oldNode = oldSchema;
|
|
7767
|
+
const newNode = newSchema;
|
|
7129
7768
|
if (changeRecords?.length) {
|
|
7130
7769
|
const sourceForValues = reverse ? oldNode : newNode;
|
|
7131
7770
|
const patch = {
|
|
@@ -7206,6 +7845,7 @@
|
|
|
7206
7845
|
showPageListButton: true,
|
|
7207
7846
|
hideSlideBar: false,
|
|
7208
7847
|
sideBarItems: [],
|
|
7848
|
+
sideBarActiveTabName: "",
|
|
7209
7849
|
navMenuRect: {
|
|
7210
7850
|
left: 0,
|
|
7211
7851
|
top: 0,
|
|
@@ -7238,7 +7878,9 @@
|
|
|
7238
7878
|
}
|
|
7239
7879
|
if (name === "showGuides") mask?.showGuides(value);
|
|
7240
7880
|
if (name === "showRule") mask?.showRule(value);
|
|
7881
|
+
const preValue = state[name];
|
|
7241
7882
|
state[name] = value;
|
|
7883
|
+
if (preValue !== value) this.emit("state-change", name, value, preValue);
|
|
7242
7884
|
}
|
|
7243
7885
|
get(name) {
|
|
7244
7886
|
return state[name];
|
|
@@ -7872,6 +8514,7 @@
|
|
|
7872
8514
|
items: [
|
|
7873
8515
|
{
|
|
7874
8516
|
title: "数据定义",
|
|
8517
|
+
status: "fields",
|
|
7875
8518
|
items: [{
|
|
7876
8519
|
name: "fields",
|
|
7877
8520
|
type: "data-source-fields",
|
|
@@ -7880,6 +8523,7 @@
|
|
|
7880
8523
|
},
|
|
7881
8524
|
{
|
|
7882
8525
|
title: "方法定义",
|
|
8526
|
+
status: "methods",
|
|
7883
8527
|
items: [{
|
|
7884
8528
|
name: "methods",
|
|
7885
8529
|
type: "data-source-methods",
|
|
@@ -8461,7 +9105,7 @@
|
|
|
8461
9105
|
key: 1,
|
|
8462
9106
|
class: "menu-item-text"
|
|
8463
9107
|
};
|
|
8464
|
-
var _hoisted_2$
|
|
9108
|
+
var _hoisted_2$30 = { class: "el-dropdown-link menubar-menu-button" };
|
|
8465
9109
|
var ToolButton_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
8466
9110
|
name: "MEditorToolButton",
|
|
8467
9111
|
__name: "ToolButton",
|
|
@@ -8526,11 +9170,11 @@
|
|
|
8526
9170
|
placement: "bottom-start",
|
|
8527
9171
|
content: __props.data.tooltip
|
|
8528
9172
|
}, {
|
|
8529
|
-
default: (0, vue.withCtx)(() => [(0, vue.createVNode)((0, vue.unref)(_tmagic_design.TMagicButton), {
|
|
9173
|
+
default: (0, vue.withCtx)(() => [(0, vue.createVNode)((0, vue.unref)(_tmagic_design.TMagicButton), (0, vue.mergeProps)({
|
|
8530
9174
|
size: "small",
|
|
8531
9175
|
link: "",
|
|
8532
9176
|
disabled: disabled.value
|
|
8533
|
-
}, (0, vue.createSlots)({ _: 2 }, [__props.data.icon ? {
|
|
9177
|
+
}, __props.data.buttonProps || {}), (0, vue.createSlots)({ _: 2 }, [__props.data.icon ? {
|
|
8534
9178
|
name: "icon",
|
|
8535
9179
|
fn: (0, vue.withCtx)(() => [(0, vue.createVNode)(Icon_default, { icon: __props.data.icon }, null, 8, ["icon"])]),
|
|
8536
9180
|
key: "0"
|
|
@@ -8538,15 +9182,15 @@
|
|
|
8538
9182
|
name: "default",
|
|
8539
9183
|
fn: (0, vue.withCtx)(() => [(0, vue.createTextVNode)((0, vue.toDisplayString)(__props.data.text), 1)]),
|
|
8540
9184
|
key: "1"
|
|
8541
|
-
} : void 0]),
|
|
9185
|
+
} : void 0]), 1040, ["disabled"])]),
|
|
8542
9186
|
_: 1
|
|
8543
|
-
}, 8, ["content"])) : ((0, vue.openBlock)(), (0, vue.createBlock)((0, vue.unref)(_tmagic_design.TMagicButton), {
|
|
9187
|
+
}, 8, ["content"])) : ((0, vue.openBlock)(), (0, vue.createBlock)((0, vue.unref)(_tmagic_design.TMagicButton), (0, vue.mergeProps)({
|
|
8544
9188
|
key: 1,
|
|
8545
9189
|
size: "small",
|
|
8546
9190
|
link: "",
|
|
8547
9191
|
disabled: disabled.value,
|
|
8548
9192
|
title: __props.data.text
|
|
8549
|
-
}, (0, vue.createSlots)({ _: 2 }, [__props.data.icon ? {
|
|
9193
|
+
}, __props.data.buttonProps || {}), (0, vue.createSlots)({ _: 2 }, [__props.data.icon ? {
|
|
8550
9194
|
name: "icon",
|
|
8551
9195
|
fn: (0, vue.withCtx)(() => [(0, vue.createVNode)(Icon_default, { icon: __props.data.icon }, null, 8, ["icon"])]),
|
|
8552
9196
|
key: "0"
|
|
@@ -8554,7 +9198,7 @@
|
|
|
8554
9198
|
name: "default",
|
|
8555
9199
|
fn: (0, vue.withCtx)(() => [(0, vue.createTextVNode)((0, vue.toDisplayString)(__props.data.text), 1)]),
|
|
8556
9200
|
key: "1"
|
|
8557
|
-
} : void 0]),
|
|
9201
|
+
} : void 0]), 1040, ["disabled", "title"]))], 64)) : __props.data.type === "dropdown" ? ((0, vue.openBlock)(), (0, vue.createBlock)((0, vue.unref)(_tmagic_design.TMagicDropdown), {
|
|
8558
9202
|
key: 3,
|
|
8559
9203
|
trigger: "click",
|
|
8560
9204
|
disabled: disabled.value,
|
|
@@ -8575,7 +9219,7 @@
|
|
|
8575
9219
|
}), 128))]),
|
|
8576
9220
|
_: 1
|
|
8577
9221
|
})) : (0, vue.createCommentVNode)("v-if", true)]),
|
|
8578
|
-
default: (0, vue.withCtx)(() => [(0, vue.createElementVNode)("span", _hoisted_2$
|
|
9222
|
+
default: (0, vue.withCtx)(() => [(0, vue.createElementVNode)("span", _hoisted_2$30, [(0, vue.createTextVNode)((0, vue.toDisplayString)(__props.data.text), 1), (0, vue.createVNode)((0, vue.unref)(_tmagic_design.TMagicIcon), { class: "el-icon--right" }, {
|
|
8579
9223
|
default: (0, vue.withCtx)(() => [(0, vue.createVNode)((0, vue.unref)(_element_plus_icons_vue.ArrowDown))]),
|
|
8580
9224
|
_: 1
|
|
8581
9225
|
})])]),
|
|
@@ -8594,7 +9238,7 @@
|
|
|
8594
9238
|
id: "m-editor-page-bar-add-icon",
|
|
8595
9239
|
class: "m-editor-page-bar-item m-editor-page-bar-item-icon"
|
|
8596
9240
|
};
|
|
8597
|
-
var _hoisted_2$
|
|
9241
|
+
var _hoisted_2$29 = {
|
|
8598
9242
|
key: 1,
|
|
8599
9243
|
style: { "width": "21px" }
|
|
8600
9244
|
};
|
|
@@ -8631,7 +9275,7 @@
|
|
|
8631
9275
|
}
|
|
8632
9276
|
} }, null, 8, ["data"])]),
|
|
8633
9277
|
_: 1
|
|
8634
|
-
})])) : ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_2$
|
|
9278
|
+
})])) : ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_2$29));
|
|
8635
9279
|
};
|
|
8636
9280
|
}
|
|
8637
9281
|
});
|
|
@@ -8644,7 +9288,7 @@
|
|
|
8644
9288
|
class: "m-editor-page-bar",
|
|
8645
9289
|
ref: "pageBar"
|
|
8646
9290
|
};
|
|
8647
|
-
var _hoisted_2$
|
|
9291
|
+
var _hoisted_2$28 = {
|
|
8648
9292
|
key: 0,
|
|
8649
9293
|
class: "m-editor-page-bar-items",
|
|
8650
9294
|
ref: "itemsContainer"
|
|
@@ -8736,7 +9380,7 @@
|
|
|
8736
9380
|
return (_ctx, _cache) => {
|
|
8737
9381
|
return (0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_1$68, [
|
|
8738
9382
|
(0, vue.renderSlot)(_ctx.$slots, "prepend"),
|
|
8739
|
-
__props.length ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_2$
|
|
9383
|
+
__props.length ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_2$28, [(0, vue.renderSlot)(_ctx.$slots, "default")], 512)) : (0, vue.createCommentVNode)("v-if", true),
|
|
8740
9384
|
canScroll.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", {
|
|
8741
9385
|
key: 1,
|
|
8742
9386
|
class: "m-editor-page-bar-item m-editor-page-bar-item-icon m-editor-page-bar-item-left-icon",
|
|
@@ -8761,8 +9405,8 @@
|
|
|
8761
9405
|
id: "m-editor-page-bar-list-icon",
|
|
8762
9406
|
class: "m-editor-page-bar-item m-editor-page-bar-item-icon"
|
|
8763
9407
|
};
|
|
8764
|
-
var _hoisted_2$
|
|
8765
|
-
var _hoisted_3$
|
|
9408
|
+
var _hoisted_2$27 = { class: "page-bar-popover-wrapper" };
|
|
9409
|
+
var _hoisted_3$13 = { class: "page-bar-popover-inner" };
|
|
8766
9410
|
var PageList_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
8767
9411
|
name: "MEditorPageList",
|
|
8768
9412
|
__name: "PageList",
|
|
@@ -8786,7 +9430,7 @@
|
|
|
8786
9430
|
default: (0, vue.withCtx)(() => [(0, vue.createVNode)((0, vue.unref)(_element_plus_icons_vue.Files))]),
|
|
8787
9431
|
_: 1
|
|
8788
9432
|
})]),
|
|
8789
|
-
default: (0, vue.withCtx)(() => [(0, vue.createElementVNode)("div", _hoisted_2$
|
|
9433
|
+
default: (0, vue.withCtx)(() => [(0, vue.createElementVNode)("div", _hoisted_2$27, [(0, vue.createElementVNode)("div", _hoisted_3$13, [(0, vue.renderSlot)(_ctx.$slots, "page-list-popover", { list: __props.list }, () => [((0, vue.openBlock)(true), (0, vue.createElementBlock)(vue.Fragment, null, (0, vue.renderList)(__props.list, (item, index) => {
|
|
8790
9434
|
return (0, vue.openBlock)(), (0, vue.createBlock)(ToolButton_default, {
|
|
8791
9435
|
data: {
|
|
8792
9436
|
type: "button",
|
|
@@ -8865,9 +9509,9 @@
|
|
|
8865
9509
|
//#endregion
|
|
8866
9510
|
//#region packages/editor/src/layouts/page-bar/PageBar.vue?vue&type=script&setup=true&lang.ts
|
|
8867
9511
|
var _hoisted_1$65 = { class: "m-editor-page-bar-tabs" };
|
|
8868
|
-
var _hoisted_2$
|
|
8869
|
-
var _hoisted_3$
|
|
8870
|
-
var _hoisted_4$
|
|
9512
|
+
var _hoisted_2$26 = ["data-page-id", "onClick"];
|
|
9513
|
+
var _hoisted_3$12 = { class: "m-editor-page-bar-title" };
|
|
9514
|
+
var _hoisted_4$9 = ["title"];
|
|
8871
9515
|
var PageBar_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
8872
9516
|
name: "MEditorPageBar",
|
|
8873
9517
|
__name: "PageBar",
|
|
@@ -8909,7 +9553,8 @@
|
|
|
8909
9553
|
top: 0
|
|
8910
9554
|
});
|
|
8911
9555
|
};
|
|
8912
|
-
const remove = (node) => {
|
|
9556
|
+
const remove = async (node) => {
|
|
9557
|
+
await _tmagic_design.tMagicMessageBox.confirm("确定删除该页面吗?");
|
|
8913
9558
|
editorService.remove(node);
|
|
8914
9559
|
};
|
|
8915
9560
|
const pageBarScrollContainerRef = (0, vue.useTemplateRef)("pageBarScrollContainer");
|
|
@@ -8956,7 +9601,7 @@
|
|
|
8956
9601
|
key: item.id,
|
|
8957
9602
|
"data-page-id": item.id,
|
|
8958
9603
|
onClick: ($event) => switchPage(item.id)
|
|
8959
|
-
}, [(0, vue.createElementVNode)("div", _hoisted_3$
|
|
9604
|
+
}, [(0, vue.createElementVNode)("div", _hoisted_3$12, [(0, vue.renderSlot)(_ctx.$slots, "page-bar-title", { page: item }, () => [(0, vue.createElementVNode)("span", { title: item.name }, (0, vue.toDisplayString)(item.name || item.id), 9, _hoisted_4$9)])]), (0, vue.createVNode)((0, vue.unref)(_tmagic_design.TMagicPopover), {
|
|
8960
9605
|
"popper-class": "page-bar-popover",
|
|
8961
9606
|
placement: "top",
|
|
8962
9607
|
trigger: "hover",
|
|
@@ -8976,10 +9621,11 @@
|
|
|
8976
9621
|
type: "button",
|
|
8977
9622
|
text: "删除",
|
|
8978
9623
|
icon: (0, vue.unref)(_element_plus_icons_vue.Delete),
|
|
9624
|
+
buttonProps: { type: "danger" },
|
|
8979
9625
|
handler: () => remove(item)
|
|
8980
9626
|
} }, null, 8, ["data"])])])]),
|
|
8981
9627
|
_: 2
|
|
8982
|
-
}, 1024)], 10, _hoisted_2$
|
|
9628
|
+
}, 1024)], 10, _hoisted_2$26);
|
|
8983
9629
|
}), 128))]),
|
|
8984
9630
|
_: 3
|
|
8985
9631
|
}, 8, ["page-bar-sort-options", "length"])]);
|
|
@@ -8992,7 +9638,7 @@
|
|
|
8992
9638
|
//#endregion
|
|
8993
9639
|
//#region packages/editor/src/layouts/AddPageBox.vue?vue&type=script&setup=true&lang.ts
|
|
8994
9640
|
var _hoisted_1$64 = { class: "m-editor-empty-panel" };
|
|
8995
|
-
var _hoisted_2$
|
|
9641
|
+
var _hoisted_2$25 = { class: "m-editor-empty-content" };
|
|
8996
9642
|
var AddPageBox_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
8997
9643
|
name: "MEditorAddPageBox",
|
|
8998
9644
|
__name: "AddPageBox",
|
|
@@ -9009,7 +9655,7 @@
|
|
|
9009
9655
|
});
|
|
9010
9656
|
};
|
|
9011
9657
|
return (_ctx, _cache) => {
|
|
9012
|
-
return (0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_1$64, [(0, vue.createElementVNode)("div", _hoisted_2$
|
|
9658
|
+
return (0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_1$64, [(0, vue.createElementVNode)("div", _hoisted_2$25, [(0, vue.createElementVNode)("div", {
|
|
9013
9659
|
class: "m-editor-empty-button",
|
|
9014
9660
|
onClick: _cache[0] || (_cache[0] = ($event) => clickHandler((0, vue.unref)(_tmagic_core.NodeType).PAGE))
|
|
9015
9661
|
}, [(0, vue.createElementVNode)("div", null, [(0, vue.createVNode)(Icon_default, { icon: (0, vue.unref)(_element_plus_icons_vue.Plus) }, null, 8, ["icon"])]), _cache[2] || (_cache[2] = (0, vue.createElementVNode)("p", null, "新增页面", -1))]), !__props.disabledPageFragment ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", {
|
|
@@ -9026,7 +9672,7 @@
|
|
|
9026
9672
|
//#endregion
|
|
9027
9673
|
//#region packages/editor/src/layouts/CodeEditor.vue?vue&type=script&setup=true&lang.ts
|
|
9028
9674
|
var _hoisted_1$63 = { class: "magic-code-editor" };
|
|
9029
|
-
var _hoisted_2$
|
|
9675
|
+
var _hoisted_2$24 = {
|
|
9030
9676
|
ref: "codeEditor",
|
|
9031
9677
|
class: "magic-code-editor-content"
|
|
9032
9678
|
};
|
|
@@ -9281,7 +9927,7 @@
|
|
|
9281
9927
|
}, {
|
|
9282
9928
|
default: (0, vue.withCtx)(() => [(0, vue.createVNode)(Icon_default, { icon: (0, vue.unref)(_element_plus_icons_vue.FullScreen) }, null, 8, ["icon"])]),
|
|
9283
9929
|
_: 1
|
|
9284
|
-
})) : (0, vue.createCommentVNode)("v-if", true), (0, vue.createElementVNode)("div", _hoisted_2$
|
|
9930
|
+
})) : (0, vue.createCommentVNode)("v-if", true), (0, vue.createElementVNode)("div", _hoisted_2$24, null, 512)], 6)], 8, ["disabled"]))]);
|
|
9285
9931
|
};
|
|
9286
9932
|
}
|
|
9287
9933
|
});
|
|
@@ -9348,7 +9994,7 @@
|
|
|
9348
9994
|
const saveCode = (value) => {
|
|
9349
9995
|
try {
|
|
9350
9996
|
const parseDSL = getEditorConfig("parseDSL");
|
|
9351
|
-
editorService.set("root", parseDSL(value));
|
|
9997
|
+
editorService.set("root", parseDSL(value), { historySource: "root-code" });
|
|
9352
9998
|
} catch (e) {
|
|
9353
9999
|
console.error(e);
|
|
9354
10000
|
}
|
|
@@ -9422,6 +10068,8 @@
|
|
|
9422
10068
|
var Framework_default = Framework_vue_vue_type_script_setup_true_lang_default;
|
|
9423
10069
|
//#endregion
|
|
9424
10070
|
//#region packages/editor/src/layouts/history-list/composables.ts
|
|
10071
|
+
/** 合并组默认展开;仅当 expanded[key] === false 时为收起。 */
|
|
10072
|
+
var isHistoryGroupExpanded = (expanded, key) => expanded[key] !== false;
|
|
9425
10073
|
/**
|
|
9426
10074
|
* 历史记录面板共享逻辑:
|
|
9427
10075
|
* - 暴露三类历史的聚合数据(页面 / 数据源 / 代码块);
|
|
@@ -9435,10 +10083,11 @@
|
|
|
9435
10083
|
/**
|
|
9436
10084
|
* 折叠状态:key 形如 `pg-${组内首步 index}` / `ds-${id}-${组内首步 index}` / `cb-${id}-${组内首步 index}`。
|
|
9437
10085
|
* 用组内首步的稳定 index(而非展示位置)作为 key,确保历史数据更新后已展开的分组状态保持不变。
|
|
10086
|
+
* 合并组默认展开;仅当值为 `false` 时表示收起。
|
|
9438
10087
|
*/
|
|
9439
10088
|
const expanded = (0, vue.reactive)({});
|
|
9440
10089
|
const toggleGroup = (key) => {
|
|
9441
|
-
expanded[key] =
|
|
10090
|
+
expanded[key] = expanded[key] === false;
|
|
9442
10091
|
};
|
|
9443
10092
|
const pageGroups = (0, vue.computed)(() => historyService.getPageHistoryGroups());
|
|
9444
10093
|
const dataSourceGroups = (0, vue.computed)(() => historyService.getDataSourceHistoryGroups());
|
|
@@ -9500,6 +10149,7 @@
|
|
|
9500
10149
|
"component-panel": "组件面板",
|
|
9501
10150
|
props: "配置面板",
|
|
9502
10151
|
code: "源码",
|
|
10152
|
+
"root-code": "DSL源码",
|
|
9503
10153
|
"stage-contextmenu": "画布菜单",
|
|
9504
10154
|
"tree-contextmenu": "树菜单",
|
|
9505
10155
|
toolbar: "工具栏",
|
|
@@ -9507,6 +10157,8 @@
|
|
|
9507
10157
|
rollback: "回滚",
|
|
9508
10158
|
api: "接口",
|
|
9509
10159
|
ai: "AI",
|
|
10160
|
+
initial: "初始值",
|
|
10161
|
+
sync: "同步",
|
|
9510
10162
|
unknown: "未知"
|
|
9511
10163
|
};
|
|
9512
10164
|
/** 操作途径文案:用于历史面板展示「画布 / 树面板 / 配置面板…」标签。 */
|
|
@@ -9515,6 +10167,37 @@
|
|
|
9515
10167
|
};
|
|
9516
10168
|
/** 取一组历史步骤里最后一步(最近一次)的操作途径,用于组头部展示。 */
|
|
9517
10169
|
var groupSource = (group) => group.steps[group.steps.length - 1]?.step.source;
|
|
10170
|
+
/**
|
|
10171
|
+
* 把一个历史分组(页面 / bucket)派生为 GroupRow 直接消费的视图模型 {@link HistoryRowGroup}。
|
|
10172
|
+
* 统一了原先 PageTab / Bucket 各自内联的 sub-steps 映射逻辑:描述、可差异、可回滚、时间、途径
|
|
10173
|
+
* 全部在此一次性算好,组件层只负责渲染。
|
|
10174
|
+
*/
|
|
10175
|
+
var toRowGroup = (group, key, descriptor) => {
|
|
10176
|
+
const { describeGroup, describeStep, isStepDiffable, isStepRevertable } = descriptor;
|
|
10177
|
+
const timestamp = groupTimestamp(group);
|
|
10178
|
+
return {
|
|
10179
|
+
key,
|
|
10180
|
+
applied: group.applied,
|
|
10181
|
+
isCurrent: Boolean(group.isCurrent),
|
|
10182
|
+
opType: group.opType,
|
|
10183
|
+
desc: describeGroup(group),
|
|
10184
|
+
source: groupSource(group),
|
|
10185
|
+
time: formatHistoryTime(timestamp),
|
|
10186
|
+
timeTitle: formatHistoryFullTime(timestamp),
|
|
10187
|
+
subSteps: group.steps.map((s) => ({
|
|
10188
|
+
index: s.index,
|
|
10189
|
+
applied: s.applied,
|
|
10190
|
+
isCurrent: s.isCurrent,
|
|
10191
|
+
saved: s.step.saved,
|
|
10192
|
+
desc: describeStep(s.step),
|
|
10193
|
+
diffable: isStepDiffable ? isStepDiffable(s.step) : false,
|
|
10194
|
+
revertable: s.applied && (isStepRevertable ? isStepRevertable(s.step) : true),
|
|
10195
|
+
source: s.step.source,
|
|
10196
|
+
time: formatHistoryTime(s.step.timestamp),
|
|
10197
|
+
timeTitle: formatHistoryFullTime(s.step.timestamp)
|
|
10198
|
+
}))
|
|
10199
|
+
};
|
|
10200
|
+
};
|
|
9518
10201
|
var nameOf = (node) => node?.name || node?.type || `${node?.id ?? ""}`;
|
|
9519
10202
|
/**
|
|
9520
10203
|
* 默认描述里展示「名称 (id: xxx)」,便于区分同名实体。
|
|
@@ -9533,24 +10216,24 @@
|
|
|
9533
10216
|
var describePageStep = (step) => {
|
|
9534
10217
|
if (step.historyDescription) return step.historyDescription;
|
|
9535
10218
|
const { opType } = step;
|
|
10219
|
+
const items = step.diff ?? [];
|
|
9536
10220
|
if (opType === "add") {
|
|
9537
|
-
const count =
|
|
9538
|
-
const node =
|
|
10221
|
+
const count = items.length;
|
|
10222
|
+
const node = items[0]?.newSchema;
|
|
9539
10223
|
return `新增 ${count} 个节点${count === 1 && node ? `(${labelWithId(nameOf(node), node.id)})` : ""}`;
|
|
9540
10224
|
}
|
|
9541
10225
|
if (opType === "remove") {
|
|
9542
|
-
const count =
|
|
9543
|
-
const node =
|
|
10226
|
+
const count = items.length;
|
|
10227
|
+
const node = items[0]?.oldSchema;
|
|
9544
10228
|
return `删除 ${count} 个节点${count === 1 && node ? `(${labelWithId(nameOf(node), node.id)})` : ""}`;
|
|
9545
10229
|
}
|
|
9546
|
-
|
|
9547
|
-
if (
|
|
9548
|
-
|
|
9549
|
-
const { newNode, changeRecords } = updated[0];
|
|
10230
|
+
if (!items.length) return "修改节点";
|
|
10231
|
+
if (items.length === 1) {
|
|
10232
|
+
const { newSchema, changeRecords } = items[0];
|
|
9550
10233
|
const propPath = changeRecords?.[0]?.propPath;
|
|
9551
|
-
return `修改 ${labelWithId(nameOf(
|
|
10234
|
+
return `修改 ${labelWithId(nameOf(newSchema), newSchema?.id)}${propPath ? ` · ${propPath}` : ""}`;
|
|
9552
10235
|
}
|
|
9553
|
-
return `修改 ${
|
|
10236
|
+
return `修改 ${items.length} 个节点`;
|
|
9554
10237
|
};
|
|
9555
10238
|
/**
|
|
9556
10239
|
* 合并组的展示文案:
|
|
@@ -9564,7 +10247,7 @@
|
|
|
9564
10247
|
if (group.steps.length === 1) return describePageStep(group.steps[0].step);
|
|
9565
10248
|
const paths = /* @__PURE__ */ new Set();
|
|
9566
10249
|
group.steps.forEach((s) => {
|
|
9567
|
-
s.step.
|
|
10250
|
+
s.step.diff?.[0]?.changeRecords?.forEach((r) => r.propPath && paths.add(r.propPath));
|
|
9568
10251
|
});
|
|
9569
10252
|
const pathList = Array.from(paths).slice(0, 3).join(", ");
|
|
9570
10253
|
const target = labelWithId(group.targetName ?? (group.targetId !== void 0 ? `${group.targetId}` : "节点"), group.targetId);
|
|
@@ -9572,10 +10255,11 @@
|
|
|
9572
10255
|
};
|
|
9573
10256
|
var describeDataSourceStep = (step) => {
|
|
9574
10257
|
if (step.historyDescription) return step.historyDescription;
|
|
9575
|
-
|
|
9576
|
-
if (
|
|
9577
|
-
|
|
9578
|
-
const
|
|
10258
|
+
const { oldSchema, newSchema, changeRecords } = step.diff?.[0] ?? {};
|
|
10259
|
+
if (!oldSchema && newSchema) return `创建 ${labelWithId(newSchema.title, newSchema.id ?? step.id)}`;
|
|
10260
|
+
if (!newSchema && oldSchema) return `删除 ${labelWithId(oldSchema.title, oldSchema.id ?? step.id)}`;
|
|
10261
|
+
const propPath = changeRecords?.[0]?.propPath;
|
|
10262
|
+
const title = labelWithId(newSchema?.title || oldSchema?.title, step.id);
|
|
9579
10263
|
return propPath ? `修改 ${title} · ${propPath}` : `修改 ${title}`;
|
|
9580
10264
|
};
|
|
9581
10265
|
var describeDataSourceGroup = (group) => {
|
|
@@ -9584,18 +10268,19 @@
|
|
|
9584
10268
|
if (group.steps.length === 1) return describeDataSourceStep(group.steps[0].step);
|
|
9585
10269
|
const paths = /* @__PURE__ */ new Set();
|
|
9586
10270
|
group.steps.forEach((s) => {
|
|
9587
|
-
s.step.changeRecords?.forEach((r) => r.propPath && paths.add(r.propPath));
|
|
10271
|
+
s.step.diff?.[0]?.changeRecords?.forEach((r) => r.propPath && paths.add(r.propPath));
|
|
9588
10272
|
});
|
|
9589
10273
|
const pathList = Array.from(paths).slice(0, 3).join(", ");
|
|
9590
|
-
const target = labelWithId(group.steps[group.steps.length - 1].step.newSchema?.title || group.steps[0].step.oldSchema?.title, group.id);
|
|
10274
|
+
const target = labelWithId(group.steps[group.steps.length - 1].step.diff?.[0]?.newSchema?.title || group.steps[0].step.diff?.[0]?.oldSchema?.title, group.id);
|
|
9591
10275
|
return pathList ? `修改 ${target} · ${pathList}${paths.size > 3 ? "…" : ""}` : `修改 ${target}`;
|
|
9592
10276
|
};
|
|
9593
10277
|
var describeCodeBlockStep = (step) => {
|
|
9594
10278
|
if (step.historyDescription) return step.historyDescription;
|
|
9595
|
-
|
|
9596
|
-
if (
|
|
9597
|
-
|
|
9598
|
-
const
|
|
10279
|
+
const { oldSchema: oldContent, newSchema: newContent, changeRecords } = step.diff?.[0] ?? {};
|
|
10280
|
+
if (!oldContent && newContent) return `创建 ${labelWithId(newContent.name, newContent.id ?? step.id)}`;
|
|
10281
|
+
if (!newContent && oldContent) return `删除 ${labelWithId(oldContent.name, oldContent.id ?? step.id)}`;
|
|
10282
|
+
const propPath = changeRecords?.[0]?.propPath;
|
|
10283
|
+
const title = labelWithId(newContent?.name || oldContent?.name, step.id);
|
|
9599
10284
|
return propPath ? `修改 ${title} · ${propPath}` : `修改 ${title}`;
|
|
9600
10285
|
};
|
|
9601
10286
|
var describeCodeBlockGroup = (group) => {
|
|
@@ -9604,10 +10289,10 @@
|
|
|
9604
10289
|
if (group.steps.length === 1) return describeCodeBlockStep(group.steps[0].step);
|
|
9605
10290
|
const paths = /* @__PURE__ */ new Set();
|
|
9606
10291
|
group.steps.forEach((s) => {
|
|
9607
|
-
s.step.changeRecords?.forEach((r) => r.propPath && paths.add(r.propPath));
|
|
10292
|
+
s.step.diff?.[0]?.changeRecords?.forEach((r) => r.propPath && paths.add(r.propPath));
|
|
9608
10293
|
});
|
|
9609
10294
|
const pathList = Array.from(paths).slice(0, 3).join(", ");
|
|
9610
|
-
const target = labelWithId(group.steps[group.steps.length - 1].step.
|
|
10295
|
+
const target = labelWithId(group.steps[group.steps.length - 1].step.diff?.[0]?.newSchema?.name || group.steps[0].step.diff?.[0]?.oldSchema?.name, group.id);
|
|
9611
10296
|
return pathList ? `修改 ${target} · ${pathList}${paths.size > 3 ? "…" : ""}` : `修改 ${target}`;
|
|
9612
10297
|
};
|
|
9613
10298
|
/**
|
|
@@ -9618,136 +10303,176 @@
|
|
|
9618
10303
|
*/
|
|
9619
10304
|
var isPageStepRevertable = (step) => {
|
|
9620
10305
|
if (step.opType !== "update") return true;
|
|
9621
|
-
const items = step.
|
|
10306
|
+
const items = step.diff ?? [];
|
|
9622
10307
|
if (!items.length) return false;
|
|
9623
10308
|
return items.every((item) => Boolean(item.changeRecords?.length));
|
|
9624
10309
|
};
|
|
9625
10310
|
/**
|
|
9626
10311
|
* 数据源 step 是否支持「回滚」:
|
|
9627
|
-
* -
|
|
10312
|
+
* - 新增(无 oldSchema)/ 删除(无 newSchema):不依赖 changeRecords,始终可回滚;
|
|
9628
10313
|
* - 更新(前后 schema 都存在):必须有 changeRecords 才支持局部反向 patch,否则不支持回滚。
|
|
9629
10314
|
*/
|
|
9630
10315
|
var isDataSourceStepRevertable = (step) => {
|
|
9631
|
-
|
|
9632
|
-
|
|
10316
|
+
const item = step.diff?.[0];
|
|
10317
|
+
if (!item?.oldSchema || !item?.newSchema) return true;
|
|
10318
|
+
return Boolean(item.changeRecords?.length);
|
|
9633
10319
|
};
|
|
9634
10320
|
/**
|
|
9635
10321
|
* 代码块 step 是否支持「回滚」:
|
|
9636
|
-
* -
|
|
10322
|
+
* - 新增(无 oldSchema)/ 删除(无 newSchema):不依赖 changeRecords,始终可回滚;
|
|
9637
10323
|
* - 更新(前后 content 都存在):必须有 changeRecords 才支持局部反向 patch,否则不支持回滚。
|
|
9638
10324
|
*/
|
|
9639
10325
|
var isCodeBlockStepRevertable = (step) => {
|
|
9640
|
-
|
|
9641
|
-
|
|
10326
|
+
const item = step.diff?.[0];
|
|
10327
|
+
if (!item?.oldSchema || !item?.newSchema) return true;
|
|
10328
|
+
return Boolean(item.changeRecords?.length);
|
|
9642
10329
|
};
|
|
9643
10330
|
//#endregion
|
|
9644
10331
|
//#region packages/editor/src/layouts/history-list/GroupRow.vue?vue&type=script&setup=true&lang.ts
|
|
9645
10332
|
var _hoisted_1$61 = ["title"];
|
|
9646
|
-
var _hoisted_2$
|
|
9647
|
-
var _hoisted_3$
|
|
9648
|
-
var _hoisted_4$
|
|
9649
|
-
|
|
9650
|
-
|
|
9651
|
-
|
|
10333
|
+
var _hoisted_2$23 = ["title"];
|
|
10334
|
+
var _hoisted_3$11 = { class: "m-editor-history-list-item-desc" };
|
|
10335
|
+
var _hoisted_4$8 = {
|
|
10336
|
+
key: 0,
|
|
10337
|
+
class: "m-editor-history-list-item-saved",
|
|
10338
|
+
title: "该记录为最近一次保存的状态"
|
|
10339
|
+
};
|
|
10340
|
+
var _hoisted_5$4 = {
|
|
10341
|
+
key: 1,
|
|
10342
|
+
class: "m-editor-history-list-item-actions"
|
|
10343
|
+
};
|
|
10344
|
+
var _hoisted_6$3 = ["title"];
|
|
10345
|
+
var _hoisted_7$1 = ["title"];
|
|
10346
|
+
var _hoisted_8 = {
|
|
10347
|
+
key: 4,
|
|
9652
10348
|
class: "m-editor-history-list-item-merge"
|
|
9653
10349
|
};
|
|
9654
|
-
var
|
|
10350
|
+
var _hoisted_9 = {
|
|
9655
10351
|
key: 0,
|
|
9656
10352
|
class: "m-editor-history-list-substeps"
|
|
9657
10353
|
};
|
|
9658
|
-
var
|
|
9659
|
-
var
|
|
9660
|
-
var
|
|
9661
|
-
var
|
|
9662
|
-
|
|
9663
|
-
|
|
9664
|
-
|
|
10354
|
+
var _hoisted_10 = ["title", "onClick"];
|
|
10355
|
+
var _hoisted_11 = { class: "m-editor-history-list-item-index" };
|
|
10356
|
+
var _hoisted_12 = { class: "m-editor-history-list-substep-desc" };
|
|
10357
|
+
var _hoisted_13 = {
|
|
10358
|
+
key: 0,
|
|
10359
|
+
class: "m-editor-history-list-item-saved",
|
|
10360
|
+
title: "该记录为最近一次保存的状态"
|
|
10361
|
+
};
|
|
10362
|
+
var _hoisted_14 = {
|
|
10363
|
+
key: 1,
|
|
10364
|
+
class: "m-editor-history-list-item-actions"
|
|
10365
|
+
};
|
|
9665
10366
|
var _hoisted_15 = ["onClick"];
|
|
10367
|
+
var _hoisted_16 = ["onClick"];
|
|
10368
|
+
var _hoisted_17 = ["onClick"];
|
|
10369
|
+
var _hoisted_18 = ["title"];
|
|
10370
|
+
var _hoisted_19 = ["title"];
|
|
9666
10371
|
var GroupRow_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
9667
10372
|
name: "MEditorHistoryListGroupRow",
|
|
9668
10373
|
__name: "GroupRow",
|
|
9669
10374
|
props: {
|
|
9670
|
-
|
|
9671
|
-
applied: { type: Boolean },
|
|
9672
|
-
merged: { type: Boolean },
|
|
9673
|
-
opType: {},
|
|
9674
|
-
desc: {},
|
|
9675
|
-
source: {},
|
|
9676
|
-
time: {},
|
|
9677
|
-
timeTitle: {},
|
|
9678
|
-
stepCount: {},
|
|
9679
|
-
subSteps: {},
|
|
10375
|
+
group: {},
|
|
9680
10376
|
expanded: { type: Boolean },
|
|
9681
|
-
isCurrent: {
|
|
9682
|
-
type: Boolean,
|
|
9683
|
-
default: false
|
|
9684
|
-
},
|
|
9685
10377
|
gotoEnabled: {
|
|
9686
10378
|
type: Boolean,
|
|
9687
10379
|
default: true
|
|
10380
|
+
},
|
|
10381
|
+
selectEnabled: {
|
|
10382
|
+
type: Boolean,
|
|
10383
|
+
default: false
|
|
9688
10384
|
}
|
|
9689
10385
|
},
|
|
9690
10386
|
emits: [
|
|
9691
10387
|
"toggle",
|
|
9692
10388
|
"goto",
|
|
9693
10389
|
"diff-step",
|
|
9694
|
-
"revert-step"
|
|
10390
|
+
"revert-step",
|
|
10391
|
+
"select"
|
|
9695
10392
|
],
|
|
9696
10393
|
setup(__props, { emit: __emit }) {
|
|
9697
10394
|
const props = __props;
|
|
9698
10395
|
const emit = __emit;
|
|
10396
|
+
/** 子步数大于 1 即为合并组:决定是否展示合并标记与可展开的子步列表。 */
|
|
10397
|
+
const merged = (0, vue.computed)(() => props.group.subSteps.length > 1);
|
|
10398
|
+
/** 组内 step 总数,仅在合并组时显示为 "合并 N 步"。 */
|
|
10399
|
+
const stepCount = (0, vue.computed)(() => props.group.subSteps.length);
|
|
9699
10400
|
/**
|
|
9700
|
-
*
|
|
9701
|
-
*
|
|
10401
|
+
* 头部可点击的场景:
|
|
10402
|
+
* - 合并组:点击切换展开 / 收起;
|
|
10403
|
+
* - 开启 `selectEnabled`(页面 tab):点击选中对应节点。
|
|
10404
|
+
* 单步组的跳转仍由头部的「回到」按钮触发。
|
|
9702
10405
|
*/
|
|
9703
|
-
const isHeadClickable = (0, vue.computed)(() => props.
|
|
10406
|
+
const isHeadClickable = (0, vue.computed)(() => merged.value || props.selectEnabled);
|
|
9704
10407
|
const headTitle = (0, vue.computed)(() => {
|
|
9705
|
-
if (
|
|
9706
|
-
|
|
10408
|
+
if (merged.value) {
|
|
10409
|
+
const expandHint = props.expanded ? "点击收起子步" : "点击展开子步";
|
|
10410
|
+
return props.selectEnabled ? `${expandHint}(并选中该节点)` : expandHint;
|
|
10411
|
+
}
|
|
10412
|
+
if (props.selectEnabled) return "点击选中该节点";
|
|
10413
|
+
if (props.group.isCurrent) return "当前所在记录";
|
|
9707
10414
|
return "";
|
|
9708
10415
|
});
|
|
9709
10416
|
/**
|
|
9710
|
-
*
|
|
10417
|
+
* 头部点击行为:
|
|
10418
|
+
* - 开启 selectEnabled 时,发出 select(携带组内首步 index,上层据此选中节点);
|
|
10419
|
+
* - 合并组同时切换展开 / 收起。
|
|
9711
10420
|
*/
|
|
9712
10421
|
const onHeadClick = () => {
|
|
9713
|
-
if (props.
|
|
10422
|
+
if (props.selectEnabled && props.group.subSteps.length) emit("select", props.group.subSteps[0].index);
|
|
10423
|
+
if (merged.value) emit("toggle", props.group.key);
|
|
9714
10424
|
};
|
|
9715
10425
|
const onGotoClick = (index) => {
|
|
9716
10426
|
if (!props.gotoEnabled) return;
|
|
9717
10427
|
emit("goto", index);
|
|
9718
10428
|
};
|
|
10429
|
+
/** 点击子步行:开启 selectEnabled 时选中该子步对应的节点。 */
|
|
10430
|
+
const onSubStepClick = (index) => {
|
|
10431
|
+
if (!props.selectEnabled) return;
|
|
10432
|
+
emit("select", index);
|
|
10433
|
+
};
|
|
9719
10434
|
const subStepTitle = (s) => {
|
|
10435
|
+
if (props.selectEnabled) return "点击选中该节点";
|
|
9720
10436
|
if (s.isCurrent) return "当前所在记录";
|
|
9721
10437
|
return "";
|
|
9722
10438
|
};
|
|
10439
|
+
/**
|
|
10440
|
+
* 头部是否展示「已保存」标记:
|
|
10441
|
+
* - 单步组:取该唯一子步的 saved;
|
|
10442
|
+
* - 合并组:组内任一子步为已保存即在头部提示(具体落在哪一步可展开查看)。
|
|
10443
|
+
*/
|
|
10444
|
+
const headSaved = (0, vue.computed)(() => merged.value ? props.group.subSteps.some((s) => s.saved) : Boolean(props.group.subSteps[0]?.saved));
|
|
9723
10445
|
/** 单步组头部是否展示"查看差异"入口:要求该唯一子步本身可对比。 */
|
|
9724
|
-
const headDiffable = (0, vue.computed)(() => !
|
|
10446
|
+
const headDiffable = (0, vue.computed)(() => !merged.value && Boolean(props.group.subSteps[0]?.diffable));
|
|
9725
10447
|
/** 单步组头部是否展示"回滚"入口:要求该唯一子步本身可回滚(已应用)。 */
|
|
9726
|
-
const headRevertable = (0, vue.computed)(() => !
|
|
10448
|
+
const headRevertable = (0, vue.computed)(() => !merged.value && Boolean(props.group.subSteps[0]?.revertable));
|
|
10449
|
+
/** 单步组头部是否展示"回到"入口:可跳转、非当前、且存在唯一子步。 */
|
|
10450
|
+
const canHeadGoto = (0, vue.computed)(() => !merged.value && props.gotoEnabled && !props.group.isCurrent && props.group.subSteps.length > 0);
|
|
9727
10451
|
/**
|
|
9728
10452
|
* 合并组展开后的子步渲染顺序:与外层分组列表保持一致——倒序展示(最新的子步在最上方)。
|
|
9729
10453
|
* 外层 page tab / bucket 都已对 groups 做了 reverse,子步沿用同样的视觉规则更直观。
|
|
9730
10454
|
* 注意:仅用于渲染,原 `subSteps` 保持时间正序,`headIndexLabel` 等基于首尾索引的展示语义不变。
|
|
9731
10455
|
*/
|
|
9732
|
-
const subStepsDisplay = (0, vue.computed)(() => props.subSteps.slice().reverse());
|
|
10456
|
+
const subStepsDisplay = (0, vue.computed)(() => props.group.subSteps.slice().reverse());
|
|
9733
10457
|
/**
|
|
9734
10458
|
* 头部索引展示:
|
|
9735
|
-
* -
|
|
10459
|
+
* - 单步组(非合并):显示该唯一 step 的编号,如 `#5`;
|
|
9736
10460
|
* - 合并组:显示组内 step 的编号范围,如 `#3-#7`(首尾相同则退化为 `#5`)。
|
|
9737
10461
|
*
|
|
9738
10462
|
* 这里展示的是 step.index + 1(与子步列表 `#{{ s.index + 1 }}` 保持一致),从 1 起编号更符合直觉。
|
|
9739
10463
|
*/
|
|
9740
10464
|
const headIndexLabel = (0, vue.computed)(() => {
|
|
9741
|
-
const list = props.subSteps;
|
|
10465
|
+
const list = props.group.subSteps;
|
|
9742
10466
|
if (!list.length) return "";
|
|
9743
10467
|
const first = list[0].index + 1;
|
|
9744
10468
|
const last = list[list.length - 1].index + 1;
|
|
9745
|
-
if (!
|
|
10469
|
+
if (!merged.value || first === last) return `#${first}`;
|
|
9746
10470
|
return `#${first}-#${last}`;
|
|
9747
10471
|
});
|
|
9748
10472
|
const headIndexTitle = (0, vue.computed)(() => {
|
|
9749
|
-
|
|
9750
|
-
|
|
10473
|
+
const list = props.group.subSteps;
|
|
10474
|
+
if (!merged.value) return `历史步骤编号 #${list[0]?.index + 1}`;
|
|
10475
|
+
return `合并了第 ${list[0]?.index + 1} 至第 ${list[list.length - 1]?.index + 1} 共 ${list.length} 条历史步骤`;
|
|
9751
10476
|
});
|
|
9752
10477
|
const onDiffClick = (index) => {
|
|
9753
10478
|
emit("diff-step", index);
|
|
@@ -9757,9 +10482,9 @@
|
|
|
9757
10482
|
};
|
|
9758
10483
|
return (_ctx, _cache) => {
|
|
9759
10484
|
return (0, vue.openBlock)(), (0, vue.createElementBlock)("li", { class: (0, vue.normalizeClass)(["m-editor-history-list-item m-editor-history-list-group", {
|
|
9760
|
-
"is-undone": !__props.applied,
|
|
9761
|
-
"is-merged":
|
|
9762
|
-
"is-current": __props.isCurrent
|
|
10485
|
+
"is-undone": !__props.group.applied,
|
|
10486
|
+
"is-merged": merged.value,
|
|
10487
|
+
"is-current": __props.group.isCurrent
|
|
9763
10488
|
}]) }, [(0, vue.createElementVNode)("div", {
|
|
9764
10489
|
class: (0, vue.normalizeClass)(["m-editor-history-list-group-head", { "is-clickable": isHeadClickable.value }]),
|
|
9765
10490
|
title: headTitle.value,
|
|
@@ -9768,82 +10493,90 @@
|
|
|
9768
10493
|
(0, vue.createElementVNode)("span", {
|
|
9769
10494
|
class: "m-editor-history-list-item-index",
|
|
9770
10495
|
title: headIndexTitle.value
|
|
9771
|
-
}, (0, vue.toDisplayString)(headIndexLabel.value), 9, _hoisted_2$
|
|
9772
|
-
(0, vue.createElementVNode)("span", { class: (0, vue.normalizeClass)(["m-editor-history-list-item-op", `op-${__props.opType}`]) }, (0, vue.toDisplayString)((0, vue.unref)(opLabel)(__props.opType)), 3),
|
|
9773
|
-
(0, vue.createElementVNode)("span", _hoisted_3$
|
|
9774
|
-
|
|
9775
|
-
|
|
10496
|
+
}, (0, vue.toDisplayString)(headIndexLabel.value), 9, _hoisted_2$23),
|
|
10497
|
+
(0, vue.createElementVNode)("span", { class: (0, vue.normalizeClass)(["m-editor-history-list-item-op", `op-${__props.group.opType}`]) }, (0, vue.toDisplayString)((0, vue.unref)(opLabel)(__props.group.opType)), 3),
|
|
10498
|
+
(0, vue.createElementVNode)("span", _hoisted_3$11, (0, vue.toDisplayString)(__props.group.desc), 1),
|
|
10499
|
+
headSaved.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", _hoisted_4$8, "已保存")) : (0, vue.createCommentVNode)("v-if", true),
|
|
10500
|
+
!merged.value && (headRevertable.value || headDiffable.value || canHeadGoto.value) ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", _hoisted_5$4, [
|
|
10501
|
+
headRevertable.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", {
|
|
10502
|
+
key: 0,
|
|
10503
|
+
class: "m-editor-history-list-item-revert",
|
|
10504
|
+
title: "将该步骤的修改作为一次新操作反向应用(不影响后续历史)",
|
|
10505
|
+
onClick: _cache[0] || (_cache[0] = (0, vue.withModifiers)(($event) => onRevertClick(__props.group.subSteps[0].index), ["stop"]))
|
|
10506
|
+
}, "回滚")) : (0, vue.createCommentVNode)("v-if", true),
|
|
10507
|
+
canHeadGoto.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", {
|
|
10508
|
+
key: 1,
|
|
10509
|
+
class: "m-editor-history-list-item-goto",
|
|
10510
|
+
title: "回到该记录",
|
|
10511
|
+
onClick: _cache[1] || (_cache[1] = (0, vue.withModifiers)(($event) => onGotoClick(__props.group.subSteps[0].index), ["stop"]))
|
|
10512
|
+
}, "回到")) : (0, vue.createCommentVNode)("v-if", true),
|
|
10513
|
+
headDiffable.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", {
|
|
10514
|
+
key: 2,
|
|
10515
|
+
class: "m-editor-history-list-item-diff",
|
|
10516
|
+
title: "查看修改差异",
|
|
10517
|
+
onClick: _cache[2] || (_cache[2] = (0, vue.withModifiers)(($event) => onDiffClick(__props.group.subSteps[0].index), ["stop"]))
|
|
10518
|
+
}, "查看差异")) : (0, vue.createCommentVNode)("v-if", true)
|
|
10519
|
+
])) : (0, vue.createCommentVNode)("v-if", true),
|
|
10520
|
+
!merged.value && (0, vue.unref)(sourceLabel)(__props.group.source) ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", {
|
|
10521
|
+
key: 2,
|
|
9776
10522
|
class: "m-editor-history-list-item-source",
|
|
9777
|
-
title: `操作途径:${(0, vue.unref)(sourceLabel)(__props.source)}`
|
|
9778
|
-
}, (0, vue.toDisplayString)((0, vue.unref)(sourceLabel)(__props.source)), 9,
|
|
9779
|
-
!
|
|
9780
|
-
key: 1,
|
|
9781
|
-
class: "m-editor-history-list-item-time",
|
|
9782
|
-
title: __props.timeTitle || __props.time
|
|
9783
|
-
}, (0, vue.toDisplayString)(__props.time), 9, _hoisted_5$3)) : (0, vue.createCommentVNode)("v-if", true),
|
|
9784
|
-
__props.merged ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", _hoisted_6$3, "合并 " + (0, vue.toDisplayString)(__props.stepCount) + " 步", 1)) : (0, vue.createCommentVNode)("v-if", true),
|
|
9785
|
-
!__props.merged && headRevertable.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", {
|
|
10523
|
+
title: `操作途径:${(0, vue.unref)(sourceLabel)(__props.group.source)}`
|
|
10524
|
+
}, (0, vue.toDisplayString)((0, vue.unref)(sourceLabel)(__props.group.source)), 9, _hoisted_6$3)) : (0, vue.createCommentVNode)("v-if", true),
|
|
10525
|
+
!merged.value && __props.group.time ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", {
|
|
9786
10526
|
key: 3,
|
|
9787
|
-
class: "m-editor-history-list-item-
|
|
9788
|
-
title:
|
|
9789
|
-
|
|
9790
|
-
|
|
9791
|
-
|
|
9792
|
-
key: 4,
|
|
9793
|
-
class: "m-editor-history-list-item-goto",
|
|
9794
|
-
title: "回到该记录",
|
|
9795
|
-
onClick: _cache[1] || (_cache[1] = (0, vue.withModifiers)(($event) => onGotoClick(__props.subSteps[0].index), ["stop"]))
|
|
9796
|
-
}, "回到")) : (0, vue.createCommentVNode)("v-if", true),
|
|
9797
|
-
!__props.merged && headDiffable.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", {
|
|
10527
|
+
class: "m-editor-history-list-item-time",
|
|
10528
|
+
title: __props.group.timeTitle || __props.group.time
|
|
10529
|
+
}, (0, vue.toDisplayString)(__props.group.time), 9, _hoisted_7$1)) : (0, vue.createCommentVNode)("v-if", true),
|
|
10530
|
+
merged.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", _hoisted_8, "合并 " + (0, vue.toDisplayString)(stepCount.value) + " 步", 1)) : (0, vue.createCommentVNode)("v-if", true),
|
|
10531
|
+
merged.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", {
|
|
9798
10532
|
key: 5,
|
|
9799
|
-
class: "m-editor-history-list-item-diff",
|
|
9800
|
-
title: "查看修改差异",
|
|
9801
|
-
onClick: _cache[2] || (_cache[2] = (0, vue.withModifiers)(($event) => onDiffClick(__props.subSteps[0].index), ["stop"]))
|
|
9802
|
-
}, "查看差异")) : (0, vue.createCommentVNode)("v-if", true),
|
|
9803
|
-
__props.merged ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", {
|
|
9804
|
-
key: 6,
|
|
9805
10533
|
class: (0, vue.normalizeClass)(["m-editor-history-list-group-toggle", { "is-expanded": __props.expanded }])
|
|
9806
10534
|
}, "▾", 2)) : (0, vue.createCommentVNode)("v-if", true)
|
|
9807
|
-
], 10, _hoisted_1$61),
|
|
10535
|
+
], 10, _hoisted_1$61), merged.value && __props.expanded ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("ul", _hoisted_9, [((0, vue.openBlock)(true), (0, vue.createElementBlock)(vue.Fragment, null, (0, vue.renderList)(subStepsDisplay.value, (s) => {
|
|
9808
10536
|
return (0, vue.openBlock)(), (0, vue.createElementBlock)("li", {
|
|
9809
10537
|
key: s.index,
|
|
9810
10538
|
class: (0, vue.normalizeClass)({
|
|
9811
10539
|
"is-undone": !s.applied,
|
|
9812
|
-
"is-current": s.isCurrent
|
|
10540
|
+
"is-current": s.isCurrent,
|
|
10541
|
+
"is-clickable": __props.selectEnabled
|
|
9813
10542
|
}),
|
|
9814
|
-
title: subStepTitle(s)
|
|
10543
|
+
title: subStepTitle(s),
|
|
10544
|
+
onClick: ($event) => onSubStepClick(s.index)
|
|
9815
10545
|
}, [
|
|
9816
|
-
(0, vue.createElementVNode)("span",
|
|
9817
|
-
(0, vue.createElementVNode)("span",
|
|
10546
|
+
(0, vue.createElementVNode)("span", _hoisted_11, "#" + (0, vue.toDisplayString)(s.index + 1), 1),
|
|
10547
|
+
(0, vue.createElementVNode)("span", _hoisted_12, (0, vue.toDisplayString)(s.desc), 1),
|
|
10548
|
+
s.saved ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", _hoisted_13, "已保存")) : (0, vue.createCommentVNode)("v-if", true),
|
|
10549
|
+
s.revertable || s.diffable || __props.gotoEnabled && !s.isCurrent ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", _hoisted_14, [
|
|
10550
|
+
s.revertable ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", {
|
|
10551
|
+
key: 0,
|
|
10552
|
+
class: "m-editor-history-list-item-revert",
|
|
10553
|
+
title: "将该步骤的修改作为一次新操作反向应用(不影响后续历史)",
|
|
10554
|
+
onClick: (0, vue.withModifiers)(($event) => onRevertClick(s.index), ["stop"])
|
|
10555
|
+
}, "回滚", 8, _hoisted_15)) : (0, vue.createCommentVNode)("v-if", true),
|
|
10556
|
+
__props.gotoEnabled && !s.isCurrent ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", {
|
|
10557
|
+
key: 1,
|
|
10558
|
+
class: "m-editor-history-list-item-goto",
|
|
10559
|
+
title: "回到该记录",
|
|
10560
|
+
onClick: (0, vue.withModifiers)(($event) => onGotoClick(s.index), ["stop"])
|
|
10561
|
+
}, "回到", 8, _hoisted_16)) : (0, vue.createCommentVNode)("v-if", true),
|
|
10562
|
+
s.diffable ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", {
|
|
10563
|
+
key: 2,
|
|
10564
|
+
class: "m-editor-history-list-item-diff",
|
|
10565
|
+
title: "查看修改差异",
|
|
10566
|
+
onClick: (0, vue.withModifiers)(($event) => onDiffClick(s.index), ["stop"])
|
|
10567
|
+
}, "查看差异", 8, _hoisted_17)) : (0, vue.createCommentVNode)("v-if", true)
|
|
10568
|
+
])) : (0, vue.createCommentVNode)("v-if", true),
|
|
9818
10569
|
(0, vue.unref)(sourceLabel)(s.source) ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", {
|
|
9819
|
-
key:
|
|
10570
|
+
key: 2,
|
|
9820
10571
|
class: "m-editor-history-list-item-source",
|
|
9821
10572
|
title: `操作途径:${(0, vue.unref)(sourceLabel)(s.source)}`
|
|
9822
|
-
}, (0, vue.toDisplayString)((0, vue.unref)(sourceLabel)(s.source)), 9,
|
|
10573
|
+
}, (0, vue.toDisplayString)((0, vue.unref)(sourceLabel)(s.source)), 9, _hoisted_18)) : (0, vue.createCommentVNode)("v-if", true),
|
|
9823
10574
|
s.time ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", {
|
|
9824
|
-
key:
|
|
10575
|
+
key: 3,
|
|
9825
10576
|
class: "m-editor-history-list-item-time",
|
|
9826
10577
|
title: s.timeTitle || s.time
|
|
9827
|
-
}, (0, vue.toDisplayString)(s.time), 9,
|
|
9828
|
-
|
|
9829
|
-
key: 2,
|
|
9830
|
-
class: "m-editor-history-list-item-revert",
|
|
9831
|
-
title: "将该步骤的修改作为一次新操作反向应用(不影响后续历史)",
|
|
9832
|
-
onClick: (0, vue.withModifiers)(($event) => onRevertClick(s.index), ["stop"])
|
|
9833
|
-
}, "回滚", 8, _hoisted_13)) : (0, vue.createCommentVNode)("v-if", true),
|
|
9834
|
-
__props.gotoEnabled && !s.isCurrent ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", {
|
|
9835
|
-
key: 3,
|
|
9836
|
-
class: "m-editor-history-list-item-goto",
|
|
9837
|
-
title: "回到该记录",
|
|
9838
|
-
onClick: (0, vue.withModifiers)(($event) => onGotoClick(s.index), ["stop"])
|
|
9839
|
-
}, "回到", 8, _hoisted_14)) : (0, vue.createCommentVNode)("v-if", true),
|
|
9840
|
-
s.diffable ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", {
|
|
9841
|
-
key: 4,
|
|
9842
|
-
class: "m-editor-history-list-item-diff",
|
|
9843
|
-
title: "查看修改差异",
|
|
9844
|
-
onClick: (0, vue.withModifiers)(($event) => onDiffClick(s.index), ["stop"])
|
|
9845
|
-
}, "查看差异", 8, _hoisted_15)) : (0, vue.createCommentVNode)("v-if", true)
|
|
9846
|
-
], 10, _hoisted_8);
|
|
10578
|
+
}, (0, vue.toDisplayString)(s.time), 9, _hoisted_19)) : (0, vue.createCommentVNode)("v-if", true)
|
|
10579
|
+
], 10, _hoisted_10);
|
|
9847
10580
|
}), 128))])) : (0, vue.createCommentVNode)("v-if", true)], 2);
|
|
9848
10581
|
};
|
|
9849
10582
|
}
|
|
@@ -9854,6 +10587,17 @@
|
|
|
9854
10587
|
//#endregion
|
|
9855
10588
|
//#region packages/editor/src/layouts/history-list/InitialRow.vue?vue&type=script&setup=true&lang.ts
|
|
9856
10589
|
var _hoisted_1$60 = ["title"];
|
|
10590
|
+
var _hoisted_2$22 = { class: "m-editor-history-list-item-desc" };
|
|
10591
|
+
var _hoisted_3$10 = {
|
|
10592
|
+
key: 0,
|
|
10593
|
+
class: "m-editor-history-list-item-saved",
|
|
10594
|
+
title: "该记录为最近一次保存的状态"
|
|
10595
|
+
};
|
|
10596
|
+
var _hoisted_4$7 = {
|
|
10597
|
+
key: 1,
|
|
10598
|
+
class: "m-editor-history-list-item-actions"
|
|
10599
|
+
};
|
|
10600
|
+
var _hoisted_5$3 = ["title"];
|
|
9857
10601
|
var InitialRow_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
9858
10602
|
name: "MEditorHistoryListInitialRow",
|
|
9859
10603
|
__name: "InitialRow",
|
|
@@ -9862,7 +10606,8 @@
|
|
|
9862
10606
|
gotoEnabled: {
|
|
9863
10607
|
type: Boolean,
|
|
9864
10608
|
default: true
|
|
9865
|
-
}
|
|
10609
|
+
},
|
|
10610
|
+
marker: { default: void 0 }
|
|
9866
10611
|
},
|
|
9867
10612
|
emits: ["goto-initial"],
|
|
9868
10613
|
setup(__props, { emit: __emit }) {
|
|
@@ -9870,10 +10615,21 @@
|
|
|
9870
10615
|
* 「初始状态」记录行:渲染于历史列表底部,作为整个栈的"零点"。
|
|
9871
10616
|
* - 点击该行会把对应栈撤销到 cursor === 0(即没有任何已应用步骤),等同于回到所有修改之前。
|
|
9872
10617
|
* - 当对应栈本身已处于 cursor === 0 时(isCurrent=true),用户已在初始状态,点击不再触发动作。
|
|
10618
|
+
* - 当上层传入 `marker`(设置 root 时为该页生成的「未修改的初始状态」标记)时,
|
|
10619
|
+
* 用标记的文案与时间渲染本行;标记不进入撤销/重做栈,仅作为该页基线展示。
|
|
9873
10620
|
*
|
|
9874
10621
|
* 该行不是真实 step,仅作为 UI 入口;上层负责把"点击"翻译为 `service.goto*(0)`。
|
|
9875
10622
|
*/
|
|
9876
10623
|
const props = __props;
|
|
10624
|
+
const desc = (0, vue.computed)(() => props.marker?.historyDescription || "未修改的初始状态");
|
|
10625
|
+
/** 基线(初始状态)是否为最近一次保存点:仅页面栈的 `initial` 基线 step 会被 markSaved 标记。 */
|
|
10626
|
+
const saved = (0, vue.computed)(() => Boolean(props.marker?.saved));
|
|
10627
|
+
const time = (0, vue.computed)(() => formatHistoryTime(props.marker?.timestamp));
|
|
10628
|
+
const timeTitle = (0, vue.computed)(() => formatHistoryFullTime(props.marker?.timestamp));
|
|
10629
|
+
const rowTitle = (0, vue.computed)(() => {
|
|
10630
|
+
const base = props.marker?.historyDescription || "未修改的初始状态";
|
|
10631
|
+
return props.isCurrent ? `当前已回到${base}` : `点击回到${base}`;
|
|
10632
|
+
});
|
|
9877
10633
|
const emit = __emit;
|
|
9878
10634
|
const onClick = () => {
|
|
9879
10635
|
if (props.isCurrent) return;
|
|
@@ -9885,20 +10641,25 @@
|
|
|
9885
10641
|
"is-current": __props.isCurrent,
|
|
9886
10642
|
"is-clickable": !__props.isCurrent
|
|
9887
10643
|
}]),
|
|
9888
|
-
title:
|
|
10644
|
+
title: rowTitle.value
|
|
9889
10645
|
}, [
|
|
9890
10646
|
_cache[0] || (_cache[0] = (0, vue.createElementVNode)("span", {
|
|
9891
10647
|
class: "m-editor-history-list-item-index",
|
|
9892
10648
|
title: "历史步骤编号 #0(未修改的初始状态)"
|
|
9893
10649
|
}, "#0", -1)),
|
|
9894
10650
|
_cache[1] || (_cache[1] = (0, vue.createElementVNode)("span", { class: "m-editor-history-list-item-op op-initial" }, "初始", -1)),
|
|
9895
|
-
|
|
9896
|
-
|
|
9897
|
-
|
|
10651
|
+
(0, vue.createElementVNode)("span", _hoisted_2$22, (0, vue.toDisplayString)(desc.value), 1),
|
|
10652
|
+
saved.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", _hoisted_3$10, "已保存")) : (0, vue.createCommentVNode)("v-if", true),
|
|
10653
|
+
__props.gotoEnabled && !__props.isCurrent ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", _hoisted_4$7, [(0, vue.createElementVNode)("span", {
|
|
9898
10654
|
class: "m-editor-history-list-item-goto",
|
|
9899
10655
|
title: "回到该记录",
|
|
9900
10656
|
onClick: (0, vue.withModifiers)(onClick, ["stop"])
|
|
9901
|
-
}, "回到")) : (0, vue.createCommentVNode)("v-if", true)
|
|
10657
|
+
}, "回到")])) : (0, vue.createCommentVNode)("v-if", true),
|
|
10658
|
+
time.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", {
|
|
10659
|
+
key: 2,
|
|
10660
|
+
class: "m-editor-history-list-item-time",
|
|
10661
|
+
title: timeTitle.value
|
|
10662
|
+
}, (0, vue.toDisplayString)(time.value), 9, _hoisted_5$3)) : (0, vue.createCommentVNode)("v-if", true)
|
|
9902
10663
|
], 10, _hoisted_1$60);
|
|
9903
10664
|
};
|
|
9904
10665
|
}
|
|
@@ -9909,30 +10670,17 @@
|
|
|
9909
10670
|
//#endregion
|
|
9910
10671
|
//#region packages/editor/src/layouts/history-list/Bucket.vue?vue&type=script&setup=true&lang.ts
|
|
9911
10672
|
var _hoisted_1$59 = { class: "m-editor-history-list-bucket" };
|
|
9912
|
-
var _hoisted_2$
|
|
9913
|
-
var _hoisted_3$
|
|
10673
|
+
var _hoisted_2$21 = { class: "m-editor-history-list-bucket-title" };
|
|
10674
|
+
var _hoisted_3$9 = { class: "m-editor-history-list-bucket-count" };
|
|
9914
10675
|
var _hoisted_4$6 = { class: "m-editor-history-list-ul" };
|
|
9915
10676
|
var Bucket_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
9916
10677
|
name: "MEditorHistoryListBucket",
|
|
9917
10678
|
__name: "Bucket",
|
|
9918
10679
|
props: {
|
|
9919
|
-
|
|
10680
|
+
config: {},
|
|
9920
10681
|
bucketId: {},
|
|
9921
|
-
prefix: {},
|
|
9922
|
-
showInitial: {
|
|
9923
|
-
type: Boolean,
|
|
9924
|
-
default: true
|
|
9925
|
-
},
|
|
9926
10682
|
groups: {},
|
|
9927
|
-
|
|
9928
|
-
describeStep: {},
|
|
9929
|
-
isStepDiffable: {},
|
|
9930
|
-
isStepRevertable: {},
|
|
9931
|
-
expanded: {},
|
|
9932
|
-
gotoEnabled: {
|
|
9933
|
-
type: Boolean,
|
|
9934
|
-
default: true
|
|
9935
|
-
}
|
|
10683
|
+
expanded: {}
|
|
9936
10684
|
},
|
|
9937
10685
|
emits: [
|
|
9938
10686
|
"toggle",
|
|
@@ -9943,65 +10691,42 @@
|
|
|
9943
10691
|
],
|
|
9944
10692
|
setup(__props) {
|
|
9945
10693
|
const props = __props;
|
|
10694
|
+
/**
|
|
10695
|
+
* 子项 / 折叠状态 key:`${prefix}-${bucketId}-${组内首步 index}`。
|
|
10696
|
+
* 以稳定的 step 索引(而非展示位置)标识分组,历史数据更新后已展开的分组状态仍能正确保持。
|
|
10697
|
+
*/
|
|
10698
|
+
const rowKey = (group) => `${props.config.prefix}-${props.bucketId}-${group.steps[0]?.index}`;
|
|
10699
|
+
/** 把原始分组派生为 GroupRow 直接消费的视图模型。 */
|
|
10700
|
+
const toRow = (group) => toRowGroup(group, rowKey(group), props.config);
|
|
9946
10701
|
/** 该 bucket 是否处于初始状态(栈 cursor=0),等价于全部 group 都未 applied。 */
|
|
9947
10702
|
const isInitial = (0, vue.computed)(() => props.groups.length > 0 && props.groups.every((g) => !g.applied));
|
|
9948
10703
|
return (_ctx, _cache) => {
|
|
9949
|
-
return (0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_1$59, [(0, vue.createElementVNode)("div", _hoisted_2$
|
|
9950
|
-
(0, vue.createElementVNode)("span", null, (0, vue.toDisplayString)(__props.title), 1),
|
|
10704
|
+
return (0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_1$59, [(0, vue.createElementVNode)("div", _hoisted_2$21, [
|
|
10705
|
+
(0, vue.createElementVNode)("span", null, (0, vue.toDisplayString)(__props.config.title), 1),
|
|
9951
10706
|
(0, vue.createElementVNode)("code", null, (0, vue.toDisplayString)(String(__props.bucketId)), 1),
|
|
9952
|
-
(0, vue.createElementVNode)("span", _hoisted_3$
|
|
10707
|
+
(0, vue.createElementVNode)("span", _hoisted_3$9, (0, vue.toDisplayString)(__props.groups.length) + " 组", 1)
|
|
9953
10708
|
]), (0, vue.createElementVNode)("ul", _hoisted_4$6, [
|
|
9954
10709
|
((0, vue.openBlock)(true), (0, vue.createElementBlock)(vue.Fragment, null, (0, vue.renderList)(__props.groups, (group) => {
|
|
9955
10710
|
return (0, vue.openBlock)(), (0, vue.createBlock)(GroupRow_default, {
|
|
9956
|
-
key:
|
|
9957
|
-
|
|
9958
|
-
|
|
9959
|
-
|
|
9960
|
-
"op-type": group.opType,
|
|
9961
|
-
desc: __props.describeGroup(group),
|
|
9962
|
-
source: (0, vue.unref)(groupSource)(group),
|
|
9963
|
-
time: (0, vue.unref)(formatHistoryTime)((0, vue.unref)(groupTimestamp)(group)),
|
|
9964
|
-
"time-title": (0, vue.unref)(formatHistoryFullTime)((0, vue.unref)(groupTimestamp)(group)),
|
|
9965
|
-
"step-count": group.steps.length,
|
|
9966
|
-
"sub-steps": group.steps.map((s) => ({
|
|
9967
|
-
index: s.index,
|
|
9968
|
-
applied: s.applied,
|
|
9969
|
-
isCurrent: s.isCurrent,
|
|
9970
|
-
desc: __props.describeStep(s.step),
|
|
9971
|
-
diffable: __props.isStepDiffable ? __props.isStepDiffable(s.step) : false,
|
|
9972
|
-
revertable: s.applied && (__props.isStepRevertable ? __props.isStepRevertable(s.step) : true),
|
|
9973
|
-
source: s.step.source,
|
|
9974
|
-
time: (0, vue.unref)(formatHistoryTime)(s.step.timestamp),
|
|
9975
|
-
timeTitle: (0, vue.unref)(formatHistoryFullTime)(s.step.timestamp)
|
|
9976
|
-
})),
|
|
9977
|
-
"is-current": group.isCurrent,
|
|
9978
|
-
expanded: !!__props.expanded[`${__props.prefix}-${__props.bucketId}-${group.steps[0]?.index}`],
|
|
9979
|
-
"goto-enabled": __props.gotoEnabled,
|
|
10711
|
+
key: rowKey(group),
|
|
10712
|
+
group: toRow(group),
|
|
10713
|
+
expanded: (0, vue.unref)(isHistoryGroupExpanded)(__props.expanded, rowKey(group)),
|
|
10714
|
+
"goto-enabled": __props.config.gotoEnabled,
|
|
9980
10715
|
onToggle: _cache[0] || (_cache[0] = (key) => _ctx.$emit("toggle", key)),
|
|
9981
10716
|
onGoto: _cache[1] || (_cache[1] = (index) => _ctx.$emit("goto", __props.bucketId, index)),
|
|
9982
10717
|
onDiffStep: _cache[2] || (_cache[2] = (index) => _ctx.$emit("diff-step", __props.bucketId, index)),
|
|
9983
10718
|
onRevertStep: _cache[3] || (_cache[3] = (index) => _ctx.$emit("revert-step", __props.bucketId, index))
|
|
9984
10719
|
}, null, 8, [
|
|
9985
|
-
"group
|
|
9986
|
-
"applied",
|
|
9987
|
-
"merged",
|
|
9988
|
-
"op-type",
|
|
9989
|
-
"desc",
|
|
9990
|
-
"source",
|
|
9991
|
-
"time",
|
|
9992
|
-
"time-title",
|
|
9993
|
-
"step-count",
|
|
9994
|
-
"sub-steps",
|
|
9995
|
-
"is-current",
|
|
10720
|
+
"group",
|
|
9996
10721
|
"expanded",
|
|
9997
10722
|
"goto-enabled"
|
|
9998
10723
|
]);
|
|
9999
10724
|
}), 128)),
|
|
10000
|
-
(0, vue.createCommentVNode)("\n 初始状态项:永远位于该 bucket 列表底部(同样按倒序展示,最底部 = 最早状态)。\n 当 bucket 内所有 group 都未 applied 时即为当前位置。\n showInitial=false 时不展示(用于没有\"撤销到初始状态\"语义的自定义历史,如业务模块历史)。\n "),
|
|
10001
|
-
__props.showInitial !== false ? ((0, vue.openBlock)(), (0, vue.createBlock)(InitialRow_default, {
|
|
10725
|
+
(0, vue.createCommentVNode)("\n 初始状态项:永远位于该 bucket 列表底部(同样按倒序展示,最底部 = 最早状态)。\n 当 bucket 内所有 group 都未 applied 时即为当前位置。\n config.showInitial=false 时不展示(用于没有\"撤销到初始状态\"语义的自定义历史,如业务模块历史)。\n "),
|
|
10726
|
+
__props.config.showInitial !== false ? ((0, vue.openBlock)(), (0, vue.createBlock)(InitialRow_default, {
|
|
10002
10727
|
key: 0,
|
|
10003
10728
|
"is-current": isInitial.value,
|
|
10004
|
-
"goto-enabled": __props.gotoEnabled,
|
|
10729
|
+
"goto-enabled": __props.config.gotoEnabled,
|
|
10005
10730
|
onGotoInitial: _cache[4] || (_cache[4] = ($event) => _ctx.$emit("goto-initial", __props.bucketId))
|
|
10006
10731
|
}, null, 8, ["is-current", "goto-enabled"])) : (0, vue.createCommentVNode)("v-if", true)
|
|
10007
10732
|
])]);
|
|
@@ -10017,69 +10742,52 @@
|
|
|
10017
10742
|
key: 0,
|
|
10018
10743
|
class: "m-editor-history-list-empty"
|
|
10019
10744
|
};
|
|
10745
|
+
var _hoisted_2$20 = { class: "m-editor-history-list-toolbar" };
|
|
10746
|
+
var _hoisted_3$8 = ["title"];
|
|
10020
10747
|
var BucketTab_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
10021
10748
|
name: "MEditorHistoryListBucketTab",
|
|
10022
10749
|
__name: "BucketTab",
|
|
10023
10750
|
props: {
|
|
10024
|
-
|
|
10025
|
-
prefix: {},
|
|
10751
|
+
config: {},
|
|
10026
10752
|
buckets: {},
|
|
10027
|
-
|
|
10028
|
-
describeStep: {},
|
|
10029
|
-
isStepDiffable: {},
|
|
10030
|
-
isStepRevertable: {},
|
|
10031
|
-
expanded: {},
|
|
10032
|
-
gotoEnabled: {
|
|
10033
|
-
type: Boolean,
|
|
10034
|
-
default: true
|
|
10035
|
-
}
|
|
10753
|
+
expanded: {}
|
|
10036
10754
|
},
|
|
10037
10755
|
emits: [
|
|
10038
10756
|
"toggle",
|
|
10039
10757
|
"goto",
|
|
10040
10758
|
"goto-initial",
|
|
10041
10759
|
"diff-step",
|
|
10042
|
-
"revert-step"
|
|
10760
|
+
"revert-step",
|
|
10761
|
+
"clear"
|
|
10043
10762
|
],
|
|
10044
10763
|
setup(__props) {
|
|
10045
10764
|
return (_ctx, _cache) => {
|
|
10046
|
-
return !__props.buckets.length ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_1$58, "暂无操作记录")) : ((0, vue.openBlock)(), (0, vue.
|
|
10047
|
-
|
|
10048
|
-
|
|
10049
|
-
|
|
10765
|
+
return !__props.buckets.length ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_1$58, "暂无操作记录")) : ((0, vue.openBlock)(), (0, vue.createElementBlock)(vue.Fragment, { key: 1 }, [(0, vue.createElementVNode)("div", _hoisted_2$20, [(0, vue.createElementVNode)("span", {
|
|
10766
|
+
class: "m-editor-history-list-clear",
|
|
10767
|
+
title: `清空${__props.config.title}的历史记录`,
|
|
10768
|
+
onClick: _cache[0] || (_cache[0] = ($event) => _ctx.$emit("clear"))
|
|
10769
|
+
}, "清空", 8, _hoisted_3$8)]), (0, vue.createVNode)((0, vue.unref)(_tmagic_design.TMagicScrollbar), { "max-height": "360px" }, {
|
|
10050
10770
|
default: (0, vue.withCtx)(() => [((0, vue.openBlock)(true), (0, vue.createElementBlock)(vue.Fragment, null, (0, vue.renderList)(__props.buckets, (bucket) => {
|
|
10051
10771
|
return (0, vue.openBlock)(), (0, vue.createBlock)(Bucket_default, {
|
|
10052
|
-
key: `${__props.prefix}-${bucket.id}`,
|
|
10053
|
-
|
|
10772
|
+
key: `${__props.config.prefix}-${bucket.id}`,
|
|
10773
|
+
config: __props.config,
|
|
10054
10774
|
"bucket-id": bucket.id,
|
|
10055
|
-
prefix: __props.prefix,
|
|
10056
10775
|
groups: bucket.groups,
|
|
10057
|
-
"describe-group": __props.describeGroup,
|
|
10058
|
-
"describe-step": __props.describeStep,
|
|
10059
|
-
"is-step-diffable": __props.isStepDiffable,
|
|
10060
|
-
"is-step-revertable": __props.isStepRevertable,
|
|
10061
10776
|
expanded: __props.expanded,
|
|
10062
|
-
"
|
|
10063
|
-
|
|
10064
|
-
|
|
10065
|
-
|
|
10066
|
-
|
|
10067
|
-
onRevertStep: _cache[4] || (_cache[4] = (id, index) => _ctx.$emit("revert-step", id, index))
|
|
10777
|
+
onToggle: _cache[1] || (_cache[1] = (key) => _ctx.$emit("toggle", key)),
|
|
10778
|
+
onGoto: _cache[2] || (_cache[2] = (id, index) => _ctx.$emit("goto", id, index)),
|
|
10779
|
+
onGotoInitial: _cache[3] || (_cache[3] = (id) => _ctx.$emit("goto-initial", id)),
|
|
10780
|
+
onDiffStep: _cache[4] || (_cache[4] = (id, index) => _ctx.$emit("diff-step", id, index)),
|
|
10781
|
+
onRevertStep: _cache[5] || (_cache[5] = (id, index) => _ctx.$emit("revert-step", id, index))
|
|
10068
10782
|
}, null, 8, [
|
|
10069
|
-
"
|
|
10783
|
+
"config",
|
|
10070
10784
|
"bucket-id",
|
|
10071
|
-
"prefix",
|
|
10072
10785
|
"groups",
|
|
10073
|
-
"
|
|
10074
|
-
"describe-step",
|
|
10075
|
-
"is-step-diffable",
|
|
10076
|
-
"is-step-revertable",
|
|
10077
|
-
"expanded",
|
|
10078
|
-
"goto-enabled"
|
|
10786
|
+
"expanded"
|
|
10079
10787
|
]);
|
|
10080
10788
|
}), 128))]),
|
|
10081
10789
|
_: 1
|
|
10082
|
-
}));
|
|
10790
|
+
})], 64));
|
|
10083
10791
|
};
|
|
10084
10792
|
}
|
|
10085
10793
|
});
|
|
@@ -10184,7 +10892,7 @@
|
|
|
10184
10892
|
switch (props.category) {
|
|
10185
10893
|
case "node":
|
|
10186
10894
|
if (!props.type) return [];
|
|
10187
|
-
return removeStyleDisplayConfig(await propsService.getPropsConfig(props.type));
|
|
10895
|
+
return removeStyleDisplayConfig(await propsService.getPropsConfig(props.type, { node: props.value }));
|
|
10188
10896
|
case "data-source": return dataSourceService.getFormConfig(props.type || "base");
|
|
10189
10897
|
case "code-block": return getCodeBlockFormConfig({
|
|
10190
10898
|
paramColConfig: codeBlockService.getParamsColConfig(),
|
|
@@ -10277,7 +10985,7 @@
|
|
|
10277
10985
|
key: 0,
|
|
10278
10986
|
class: "m-editor-history-diff-dialog-notice"
|
|
10279
10987
|
};
|
|
10280
|
-
var _hoisted_3$
|
|
10988
|
+
var _hoisted_3$7 = { class: "m-editor-history-diff-dialog-header" };
|
|
10281
10989
|
var _hoisted_4$5 = { class: "m-editor-history-diff-dialog-target" };
|
|
10282
10990
|
var _hoisted_5$2 = { class: "m-editor-history-diff-dialog-controls" };
|
|
10283
10991
|
var _hoisted_6$2 = { class: "m-editor-history-diff-dialog-legend" };
|
|
@@ -10292,6 +11000,7 @@
|
|
|
10292
11000
|
extendState: {},
|
|
10293
11001
|
loadConfig: {},
|
|
10294
11002
|
width: { default: "900px" },
|
|
11003
|
+
isConfirm: { type: Boolean },
|
|
10295
11004
|
onConfirm: {},
|
|
10296
11005
|
selfDiffFieldTypes: {}
|
|
10297
11006
|
},
|
|
@@ -10346,9 +11055,12 @@
|
|
|
10346
11055
|
if (mode.value !== "current" || !payload.value) return false;
|
|
10347
11056
|
return isEqual(payload.value.value, payload.value.currentValue);
|
|
10348
11057
|
});
|
|
11058
|
+
/** confirm() 的 resolve,仅在「等待用户确认回滚」期间存在 */
|
|
11059
|
+
let confirmResolve = null;
|
|
10349
11060
|
const onConfirmClick = () => {
|
|
10350
|
-
|
|
10351
|
-
|
|
11061
|
+
props.onConfirm?.();
|
|
11062
|
+
confirmResolve?.(true);
|
|
11063
|
+
confirmResolve = null;
|
|
10352
11064
|
visible.value = false;
|
|
10353
11065
|
};
|
|
10354
11066
|
const targetText = (0, vue.computed)(() => {
|
|
@@ -10370,21 +11082,41 @@
|
|
|
10370
11082
|
viewMode.value = "form";
|
|
10371
11083
|
visible.value = true;
|
|
10372
11084
|
};
|
|
11085
|
+
/**
|
|
11086
|
+
* 以 Promise 形式打开确认回滚弹窗:
|
|
11087
|
+
* - 用户点击「确定回滚」时 resolve(true);
|
|
11088
|
+
* - 取消 / 关闭 / 按 Esc 等其他方式关闭弹窗时 resolve(false)。
|
|
11089
|
+
*
|
|
11090
|
+
* 同一时刻只允许一个待确认流程,重复调用会先 resolve(false) 掉上一个。
|
|
11091
|
+
*/
|
|
11092
|
+
const confirm = (p) => {
|
|
11093
|
+
confirmResolve?.(false);
|
|
11094
|
+
confirmResolve = null;
|
|
11095
|
+
return new Promise((resolve) => {
|
|
11096
|
+
confirmResolve = resolve;
|
|
11097
|
+
open(p);
|
|
11098
|
+
});
|
|
11099
|
+
};
|
|
10373
11100
|
const close = () => {
|
|
10374
11101
|
visible.value = false;
|
|
10375
11102
|
};
|
|
10376
11103
|
(0, vue.watch)(visible, (v) => {
|
|
10377
|
-
if (!v)
|
|
11104
|
+
if (!v) {
|
|
11105
|
+
payload.value = null;
|
|
11106
|
+
confirmResolve?.(false);
|
|
11107
|
+
confirmResolve = null;
|
|
11108
|
+
}
|
|
10378
11109
|
});
|
|
10379
11110
|
const onClose = () => {
|
|
10380
11111
|
emit("close");
|
|
10381
11112
|
};
|
|
10382
11113
|
__expose({
|
|
10383
11114
|
open,
|
|
11115
|
+
confirm,
|
|
10384
11116
|
close
|
|
10385
11117
|
});
|
|
10386
11118
|
return (_ctx, _cache) => {
|
|
10387
|
-
return (0, vue.openBlock)(), (0, vue.createBlock)(
|
|
11119
|
+
return (0, vue.openBlock)(), (0, vue.createBlock)((0, vue.unref)(_tmagic_design.TMagicDialog), {
|
|
10388
11120
|
modelValue: visible.value,
|
|
10389
11121
|
"onUpdate:modelValue": _cache[4] || (_cache[4] = ($event) => visible.value = $event),
|
|
10390
11122
|
class: "m-editor-history-diff-dialog",
|
|
@@ -10395,7 +11127,7 @@
|
|
|
10395
11127
|
width: __props.width,
|
|
10396
11128
|
onClose
|
|
10397
11129
|
}, {
|
|
10398
|
-
footer: (0, vue.withCtx)(() => [__props.
|
|
11130
|
+
footer: (0, vue.withCtx)(() => [__props.isConfirm ? ((0, vue.openBlock)(), (0, vue.createElementBlock)(vue.Fragment, { key: 0 }, [(0, vue.createVNode)((0, vue.unref)(_tmagic_design.TMagicButton), {
|
|
10399
11131
|
size: "small",
|
|
10400
11132
|
onClick: _cache[2] || (_cache[2] = ($event) => visible.value = false)
|
|
10401
11133
|
}, {
|
|
@@ -10416,9 +11148,9 @@
|
|
|
10416
11148
|
default: (0, vue.withCtx)(() => [..._cache[12] || (_cache[12] = [(0, vue.createTextVNode)("关闭", -1)])]),
|
|
10417
11149
|
_: 1
|
|
10418
11150
|
}))]),
|
|
10419
|
-
default: (0, vue.withCtx)(() => [payload.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_1$57, [
|
|
11151
|
+
default: (0, vue.withCtx)(() => [payload.value && visible.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_1$57, [
|
|
10420
11152
|
__props.onConfirm ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_2$19, "仅回滚有差异的字段")) : (0, vue.createCommentVNode)("v-if", true),
|
|
10421
|
-
(0, vue.createElementVNode)("div", _hoisted_3$
|
|
11153
|
+
(0, vue.createElementVNode)("div", _hoisted_3$7, [(0, vue.createElementVNode)("span", _hoisted_4$5, (0, vue.toDisplayString)(targetText.value), 1), (0, vue.createElementVNode)("div", _hoisted_5$2, [(0, vue.createVNode)((0, vue.unref)(_tmagic_design.TMagicRadioGroup), {
|
|
10422
11154
|
modelValue: viewMode.value,
|
|
10423
11155
|
"onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => viewMode.value = $event),
|
|
10424
11156
|
size: "small",
|
|
@@ -10504,7 +11236,7 @@
|
|
|
10504
11236
|
"modelValue",
|
|
10505
11237
|
"title",
|
|
10506
11238
|
"width"
|
|
10507
|
-
])
|
|
11239
|
+
]);
|
|
10508
11240
|
};
|
|
10509
11241
|
}
|
|
10510
11242
|
});
|
|
@@ -10517,99 +11249,86 @@
|
|
|
10517
11249
|
key: 0,
|
|
10518
11250
|
class: "m-editor-history-list-empty"
|
|
10519
11251
|
};
|
|
10520
|
-
var _hoisted_2$18 = {
|
|
11252
|
+
var _hoisted_2$18 = {
|
|
11253
|
+
key: 0,
|
|
11254
|
+
class: "m-editor-history-list-toolbar"
|
|
11255
|
+
};
|
|
11256
|
+
var _hoisted_3$6 = { class: "m-editor-history-list-ul" };
|
|
10521
11257
|
var PageTab_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
10522
11258
|
name: "MEditorHistoryListPageTab",
|
|
10523
11259
|
__name: "PageTab",
|
|
10524
11260
|
props: {
|
|
10525
11261
|
list: {},
|
|
10526
|
-
expanded: {}
|
|
11262
|
+
expanded: {},
|
|
11263
|
+
marker: {}
|
|
10527
11264
|
},
|
|
10528
11265
|
emits: [
|
|
10529
11266
|
"toggle",
|
|
10530
11267
|
"goto",
|
|
10531
11268
|
"goto-initial",
|
|
10532
11269
|
"diff-step",
|
|
10533
|
-
"revert-step"
|
|
11270
|
+
"revert-step",
|
|
11271
|
+
"select",
|
|
11272
|
+
"clear"
|
|
10534
11273
|
],
|
|
10535
11274
|
setup(__props) {
|
|
10536
11275
|
const props = __props;
|
|
10537
11276
|
/**
|
|
10538
11277
|
* 当前 step 是否可查看差异:
|
|
10539
11278
|
* - 仅 update 操作;
|
|
10540
|
-
* - 单节点更新(
|
|
11279
|
+
* - 单节点更新(diff.length === 1),且 oldSchema / newSchema 都存在。
|
|
10541
11280
|
* 多节点更新难以选定单一对比目标,统一不展示差异入口。
|
|
10542
11281
|
*/
|
|
10543
11282
|
const isPageStepDiffable = (step) => {
|
|
10544
11283
|
if (step.opType !== "update") return false;
|
|
10545
|
-
const items = step.
|
|
11284
|
+
const items = step.diff ?? [];
|
|
10546
11285
|
if (items.length !== 1) return false;
|
|
10547
|
-
return Boolean(items[0]?.
|
|
11286
|
+
return Boolean(items[0]?.oldSchema && items[0]?.newSchema);
|
|
10548
11287
|
};
|
|
11288
|
+
/** 页面历史的描述 / 可操作性判定集合,注入给统一的 `toRowGroup`。 */
|
|
11289
|
+
const descriptor = {
|
|
11290
|
+
describeGroup: describePageGroup,
|
|
11291
|
+
describeStep: describePageStep,
|
|
11292
|
+
isStepDiffable: isPageStepDiffable,
|
|
11293
|
+
isStepRevertable: isPageStepRevertable
|
|
11294
|
+
};
|
|
11295
|
+
const rowKey = (group) => `pg-${group.steps[0]?.index}`;
|
|
11296
|
+
const toRow = (group) => toRowGroup(group, rowKey(group), descriptor);
|
|
10549
11297
|
/**
|
|
10550
11298
|
* 是否处于"初始状态"——即对应页面历史栈 cursor===0:
|
|
10551
|
-
* 当 list 中所有 group 的 applied 都为 false
|
|
10552
|
-
*
|
|
11299
|
+
* 当 list 中所有 group 的 applied 都为 false 时即为该状态(空列表 `every` 返回 true,
|
|
11300
|
+
* 即仅有 marker、无任何操作记录时也视为处于初始状态)。
|
|
10553
11301
|
*/
|
|
10554
|
-
const isInitial = (0, vue.computed)(() => props.list.
|
|
11302
|
+
const isInitial = (0, vue.computed)(() => props.list.every((g) => !g.applied));
|
|
10555
11303
|
return (_ctx, _cache) => {
|
|
10556
|
-
return !__props.list.length ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_1$56, "暂无操作记录")) : ((0, vue.openBlock)(), (0, vue.
|
|
10557
|
-
|
|
10558
|
-
|
|
10559
|
-
|
|
10560
|
-
|
|
11304
|
+
return !__props.list.length && !__props.marker ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_1$56, "暂无操作记录")) : ((0, vue.openBlock)(), (0, vue.createElementBlock)(vue.Fragment, { key: 1 }, [__props.list.length ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_2$18, [(0, vue.createElementVNode)("span", {
|
|
11305
|
+
class: "m-editor-history-list-clear",
|
|
11306
|
+
title: "清空当前页面的历史记录",
|
|
11307
|
+
onClick: _cache[0] || (_cache[0] = ($event) => _ctx.$emit("clear"))
|
|
11308
|
+
}, "清空")])) : (0, vue.createCommentVNode)("v-if", true), (0, vue.createVNode)((0, vue.unref)(_tmagic_design.TMagicScrollbar), { "max-height": "360px" }, {
|
|
11309
|
+
default: (0, vue.withCtx)(() => [(0, vue.createElementVNode)("ul", _hoisted_3$6, [
|
|
10561
11310
|
((0, vue.openBlock)(true), (0, vue.createElementBlock)(vue.Fragment, null, (0, vue.renderList)(__props.list, (group) => {
|
|
10562
11311
|
return (0, vue.openBlock)(), (0, vue.createBlock)(GroupRow_default, {
|
|
10563
|
-
key:
|
|
10564
|
-
|
|
10565
|
-
|
|
10566
|
-
|
|
10567
|
-
"
|
|
10568
|
-
|
|
10569
|
-
|
|
10570
|
-
|
|
10571
|
-
|
|
10572
|
-
|
|
10573
|
-
"sub-steps": group.steps.map((s) => ({
|
|
10574
|
-
index: s.index,
|
|
10575
|
-
applied: s.applied,
|
|
10576
|
-
isCurrent: s.isCurrent,
|
|
10577
|
-
desc: (0, vue.unref)(describePageStep)(s.step),
|
|
10578
|
-
diffable: isPageStepDiffable(s.step),
|
|
10579
|
-
revertable: s.applied && (0, vue.unref)(isPageStepRevertable)(s.step),
|
|
10580
|
-
source: s.step.source,
|
|
10581
|
-
time: (0, vue.unref)(formatHistoryTime)(s.step.timestamp),
|
|
10582
|
-
timeTitle: (0, vue.unref)(formatHistoryFullTime)(s.step.timestamp)
|
|
10583
|
-
})),
|
|
10584
|
-
"is-current": group.isCurrent,
|
|
10585
|
-
expanded: !!__props.expanded[`pg-${group.steps[0]?.index}`],
|
|
10586
|
-
onToggle: _cache[0] || (_cache[0] = (key) => _ctx.$emit("toggle", key)),
|
|
10587
|
-
onGoto: _cache[1] || (_cache[1] = (index) => _ctx.$emit("goto", index)),
|
|
10588
|
-
onDiffStep: _cache[2] || (_cache[2] = (index) => _ctx.$emit("diff-step", index)),
|
|
10589
|
-
onRevertStep: _cache[3] || (_cache[3] = (index) => _ctx.$emit("revert-step", index))
|
|
10590
|
-
}, null, 8, [
|
|
10591
|
-
"group-key",
|
|
10592
|
-
"applied",
|
|
10593
|
-
"merged",
|
|
10594
|
-
"op-type",
|
|
10595
|
-
"desc",
|
|
10596
|
-
"source",
|
|
10597
|
-
"time",
|
|
10598
|
-
"time-title",
|
|
10599
|
-
"step-count",
|
|
10600
|
-
"sub-steps",
|
|
10601
|
-
"is-current",
|
|
10602
|
-
"expanded"
|
|
10603
|
-
]);
|
|
11312
|
+
key: rowKey(group),
|
|
11313
|
+
group: toRow(group),
|
|
11314
|
+
expanded: (0, vue.unref)(isHistoryGroupExpanded)(__props.expanded, rowKey(group)),
|
|
11315
|
+
"select-enabled": true,
|
|
11316
|
+
onToggle: _cache[1] || (_cache[1] = (key) => _ctx.$emit("toggle", key)),
|
|
11317
|
+
onGoto: _cache[2] || (_cache[2] = (index) => _ctx.$emit("goto", index)),
|
|
11318
|
+
onDiffStep: _cache[3] || (_cache[3] = (index) => _ctx.$emit("diff-step", index)),
|
|
11319
|
+
onRevertStep: _cache[4] || (_cache[4] = (index) => _ctx.$emit("revert-step", index)),
|
|
11320
|
+
onSelect: _cache[5] || (_cache[5] = (index) => _ctx.$emit("select", index))
|
|
11321
|
+
}, null, 8, ["group", "expanded"]);
|
|
10604
11322
|
}), 128)),
|
|
10605
|
-
(0, vue.createCommentVNode)("\n 初始状态项:永远位于列表底部(页面 tab 倒序展示,最底部=最早),\n 作为\"未修改\"零点。当所有 group 都未 applied 时它即为当前位置。\n "),
|
|
11323
|
+
(0, vue.createCommentVNode)("\n 初始状态项:永远位于列表底部(页面 tab 倒序展示,最底部=最早),\n 作为\"未修改\"零点。当所有 group 都未 applied 时它即为当前位置。\n 设置 root 时生成的「未修改的初始状态」标记(marker)会作为该行的文案与时间来源。\n "),
|
|
10606
11324
|
(0, vue.createVNode)(InitialRow_default, {
|
|
10607
11325
|
"is-current": isInitial.value,
|
|
10608
|
-
|
|
10609
|
-
|
|
11326
|
+
marker: __props.marker,
|
|
11327
|
+
onGotoInitial: _cache[6] || (_cache[6] = ($event) => _ctx.$emit("goto-initial"))
|
|
11328
|
+
}, null, 8, ["is-current", "marker"])
|
|
10610
11329
|
])]),
|
|
10611
11330
|
_: 1
|
|
10612
|
-
}));
|
|
11331
|
+
})], 64));
|
|
10613
11332
|
};
|
|
10614
11333
|
}
|
|
10615
11334
|
});
|
|
@@ -10619,6 +11338,12 @@
|
|
|
10619
11338
|
//#endregion
|
|
10620
11339
|
//#region packages/editor/src/layouts/history-list/HistoryListPanel.vue?vue&type=script&setup=true&lang.ts
|
|
10621
11340
|
var _hoisted_1$55 = { class: "m-editor-history-list" };
|
|
11341
|
+
/**
|
|
11342
|
+
* 构造差异弹窗入参:仅 update(前后值都存在)可对比。
|
|
11343
|
+
* - 页面(无 id):在全部分组中按 index 定位 step,目标 id 取自快照;
|
|
11344
|
+
* - 数据源 / 代码块(带 id):先匹配分组 id 再按 index 定位。
|
|
11345
|
+
* 无可对比内容(多节点 / add / remove)或定位不到时返回 null。
|
|
11346
|
+
*/
|
|
10622
11347
|
var HistoryListPanel_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
10623
11348
|
name: "MEditorHistoryListPanel",
|
|
10624
11349
|
__name: "HistoryListPanel",
|
|
@@ -10626,8 +11351,8 @@
|
|
|
10626
11351
|
/**
|
|
10627
11352
|
* 历史记录面板:在顶部 NavMenu 上点击图标打开 popover,分三个 tab:
|
|
10628
11353
|
* - 页面:当前活动页面的历史栈,连续修改同一节点的多步会被合并成一组
|
|
10629
|
-
* - 数据源:以 dataSource.id
|
|
10630
|
-
* - 代码块:同上,按 codeBlock.id
|
|
11354
|
+
* - 数据源:以 dataSource.id 分桶,每条操作记录独立展示
|
|
11355
|
+
* - 代码块:同上,按 codeBlock.id 分桶,每条操作记录独立展示
|
|
10631
11356
|
*
|
|
10632
11357
|
* 数据通过 historyService 暴露的聚合 API 读取,UI 仅用于只读展示,
|
|
10633
11358
|
* 同时支持点击任意一条记录跳转至该状态:
|
|
@@ -10647,7 +11372,10 @@
|
|
|
10647
11372
|
const ClockIcon = (0, vue.markRaw)(_element_plus_icons_vue.Clock);
|
|
10648
11373
|
const CloseIcon = (0, vue.markRaw)(_element_plus_icons_vue.Close);
|
|
10649
11374
|
const activeTab = (0, vue.ref)("page");
|
|
10650
|
-
/**
|
|
11375
|
+
/**
|
|
11376
|
+
* 面板显隐受控:reference 图标点击切换,右上角关闭按钮置为 false。
|
|
11377
|
+
* 点击面板以外区域的自动收起由 TMagicPopover 通过 v-model:visible 回写完成。
|
|
11378
|
+
*/
|
|
10651
11379
|
const visible = (0, vue.ref)(false);
|
|
10652
11380
|
const tabPaneComponent = (0, _tmagic_design.getDesignConfig)("components")?.tabPane;
|
|
10653
11381
|
/**
|
|
@@ -10657,7 +11385,7 @@
|
|
|
10657
11385
|
const extraTabs = (0, vue.inject)("historyListExtraTabs", []);
|
|
10658
11386
|
/** label 支持字符串或函数,函数形式便于展示动态数量等内容。 */
|
|
10659
11387
|
const resolveTabLabel = (tab) => typeof tab.label === "function" ? tab.label() : tab.label;
|
|
10660
|
-
const { editorService, dataSourceService, codeBlockService, historyService, propsService } = useServices();
|
|
11388
|
+
const { editorService, dataSourceService, codeBlockService, historyService, propsService, stageOverlayService } = useServices();
|
|
10661
11389
|
/**
|
|
10662
11390
|
* 数据源 / 代码块功能可被业务方通过 `disabledDataSource` / `disabledCodeBlock` 禁用,
|
|
10663
11391
|
* 禁用后对应的历史记录 tab 不再展示。若当前激活的 tab 恰好被禁用,则回退到「页面」tab。
|
|
@@ -10674,15 +11402,60 @@
|
|
|
10674
11402
|
*/
|
|
10675
11403
|
const extendFormState = (0, vue.inject)("extendFormState", void 0);
|
|
10676
11404
|
const { expanded, toggleGroup, pageGroups, dataSourceGroups, codeBlockGroups, pageGroupsDisplay, dataSourceGroupsByTarget, codeBlockGroupsByTarget } = useHistoryList();
|
|
11405
|
+
/**
|
|
11406
|
+
* 当前活动页的「加载/初始」标记记录(设置 root 时生成),透传给 PageTab 的底部初始行展示。
|
|
11407
|
+
* 基于 historyService 的 reactive state 派生,活动页切换或标记写入后自动刷新。
|
|
11408
|
+
*/
|
|
11409
|
+
const pageMarker = (0, vue.computed)(() => historyService.getPageMarker());
|
|
10677
11410
|
/** 数据源 step 仅 update(前后 schema 都存在)时可查看差异。 */
|
|
10678
|
-
const isDataSourceStepDiffable = (step) => Boolean(step.oldSchema && step.newSchema);
|
|
11411
|
+
const isDataSourceStepDiffable = (step) => Boolean(step.diff?.[0]?.oldSchema && step.diff?.[0]?.newSchema);
|
|
10679
11412
|
/** 代码块 step 仅 update(前后 content 都存在)时可查看差异。 */
|
|
10680
|
-
const isCodeBlockStepDiffable = (step) => Boolean(step.
|
|
11413
|
+
const isCodeBlockStepDiffable = (step) => Boolean(step.diff?.[0]?.oldSchema && step.diff?.[0]?.newSchema);
|
|
11414
|
+
/**
|
|
11415
|
+
* 数据源 / 代码块两类 bucket 历史的整体渲染配置:把 title / prefix 与各自的描述、
|
|
11416
|
+
* 可差异、可回滚判定收敛为单一对象整体注入 BucketTab,组件内部按需读取。
|
|
11417
|
+
*/
|
|
11418
|
+
const dataSourceConfig = {
|
|
11419
|
+
title: "数据源",
|
|
11420
|
+
prefix: "ds",
|
|
11421
|
+
describeGroup: describeDataSourceGroup,
|
|
11422
|
+
describeStep: describeDataSourceStep,
|
|
11423
|
+
isStepDiffable: isDataSourceStepDiffable,
|
|
11424
|
+
isStepRevertable: isDataSourceStepRevertable
|
|
11425
|
+
};
|
|
11426
|
+
const codeBlockConfig = {
|
|
11427
|
+
title: "代码块",
|
|
11428
|
+
prefix: "cb",
|
|
11429
|
+
describeGroup: describeCodeBlockGroup,
|
|
11430
|
+
describeStep: describeCodeBlockStep,
|
|
11431
|
+
isStepDiffable: isCodeBlockStepDiffable,
|
|
11432
|
+
isStepRevertable: isCodeBlockStepRevertable
|
|
11433
|
+
};
|
|
10681
11434
|
/** 把"目标 step 索引"翻译成"目标 cursor"(已应用步骤数量)。 */
|
|
10682
11435
|
const indexToCursor = (index) => index + 1;
|
|
10683
11436
|
const onPageGoto = (index) => {
|
|
10684
11437
|
editorService.gotoPageStep(indexToCursor(index));
|
|
10685
11438
|
};
|
|
11439
|
+
/**
|
|
11440
|
+
* 点击页面历史记录行:选中该记录对应的画布节点。
|
|
11441
|
+
* - 从目标 step 的 diff 中取节点 id(优先 newSchema,回退 oldSchema),按出现顺序找到第一个当前仍存在的节点;
|
|
11442
|
+
* - 与图层树点击选中一致:editorService.select + 画布 / overlay 画布 select 三者联动;
|
|
11443
|
+
* - 该 step 涉及的节点都已不存在(如删除记录、被撤销的新增)时给出提示,不做选中。
|
|
11444
|
+
*/
|
|
11445
|
+
const onPageSelect = async (index) => {
|
|
11446
|
+
const step = historyService.getPageStepList()[index]?.step;
|
|
11447
|
+
if (!step) return;
|
|
11448
|
+
const targetId = (step.diff ?? []).map((item) => item.newSchema?.id ?? item.oldSchema?.id).find((id) => id !== void 0 && id !== null && editorService.getNodeById(id, false));
|
|
11449
|
+
if (targetId === void 0 || targetId === null) {
|
|
11450
|
+
_tmagic_design.tMagicMessage.warning("该记录对应的节点已不存在,无法选中");
|
|
11451
|
+
return;
|
|
11452
|
+
}
|
|
11453
|
+
const node = editorService.getNodeById(targetId, false);
|
|
11454
|
+
if (!node) return;
|
|
11455
|
+
await editorService.select(node);
|
|
11456
|
+
editorService.get("stage")?.select(targetId);
|
|
11457
|
+
stageOverlayService.get("stage")?.select(targetId);
|
|
11458
|
+
};
|
|
10686
11459
|
const onDataSourceGoto = (id, index) => {
|
|
10687
11460
|
dataSourceService.goto(id, indexToCursor(index));
|
|
10688
11461
|
};
|
|
@@ -10703,71 +11476,53 @@
|
|
|
10703
11476
|
codeBlockService.goto(id, 0);
|
|
10704
11477
|
};
|
|
10705
11478
|
const diffDialogRef = (0, vue.useTemplateRef)("diffDialog");
|
|
11479
|
+
const confirmDialogRef = (0, vue.useTemplateRef)("confirmDialog");
|
|
10706
11480
|
/**
|
|
10707
|
-
*
|
|
10708
|
-
*
|
|
10709
|
-
* `currentValue` 取自 editorService 中该节点当前实际值,用于支持「与当前对比」。
|
|
10710
|
-
* 无可对比内容(如多节点 / add / remove)时返回 null。
|
|
11481
|
+
* 三类历史(页面 / 数据源 / 代码块)差异弹窗入参的构造差异,收敛为一份配置:
|
|
11482
|
+
* 仅「分组来源、当前值读取、类型 / 展示名提取」不同,定位 step、校验前后值、组装 payload 的流程共用。
|
|
10711
11483
|
*/
|
|
10712
|
-
const
|
|
10713
|
-
const
|
|
10714
|
-
|
|
10715
|
-
const
|
|
10716
|
-
if (!
|
|
10717
|
-
const
|
|
10718
|
-
|
|
10719
|
-
|
|
10720
|
-
const
|
|
10721
|
-
const
|
|
11484
|
+
const buildDiffPayload = (source, index, id) => {
|
|
11485
|
+
for (const group of source.groups()) {
|
|
11486
|
+
if (id !== void 0 && group.id !== id) continue;
|
|
11487
|
+
const step = group.steps.find((s) => s.index === index)?.step;
|
|
11488
|
+
if (!step) continue;
|
|
11489
|
+
const oldSchema = step.diff?.[0]?.oldSchema;
|
|
11490
|
+
const newSchema = step.diff?.[0]?.newSchema;
|
|
11491
|
+
if (!oldSchema || !newSchema) return null;
|
|
11492
|
+
const targetId = id ?? newSchema.id ?? oldSchema.id;
|
|
11493
|
+
const type = source.resolveType?.(newSchema, oldSchema);
|
|
10722
11494
|
return {
|
|
10723
|
-
category:
|
|
10724
|
-
type,
|
|
10725
|
-
lastValue:
|
|
10726
|
-
value:
|
|
10727
|
-
currentValue:
|
|
10728
|
-
targetLabel:
|
|
10729
|
-
id:
|
|
11495
|
+
category: source.category,
|
|
11496
|
+
...type !== void 0 ? { type } : {},
|
|
11497
|
+
lastValue: oldSchema,
|
|
11498
|
+
value: newSchema,
|
|
11499
|
+
currentValue: (targetId !== void 0 ? source.getCurrent(targetId) : null) || null,
|
|
11500
|
+
targetLabel: source.resolveLabel(newSchema, oldSchema, targetId),
|
|
11501
|
+
id: targetId
|
|
10730
11502
|
};
|
|
10731
11503
|
}
|
|
10732
11504
|
return null;
|
|
10733
11505
|
};
|
|
10734
|
-
|
|
10735
|
-
|
|
10736
|
-
|
|
10737
|
-
|
|
10738
|
-
|
|
10739
|
-
|
|
10740
|
-
|
|
10741
|
-
|
|
10742
|
-
|
|
10743
|
-
|
|
10744
|
-
}
|
|
10745
|
-
|
|
10746
|
-
|
|
10747
|
-
|
|
10748
|
-
|
|
10749
|
-
|
|
10750
|
-
|
|
10751
|
-
|
|
10752
|
-
|
|
10753
|
-
|
|
10754
|
-
value: newSchema,
|
|
10755
|
-
currentValue: currentSchema || null,
|
|
10756
|
-
targetLabel: newSchema.title || oldSchema.title || `${id}`,
|
|
10757
|
-
id
|
|
10758
|
-
};
|
|
10759
|
-
});
|
|
10760
|
-
const buildCodeBlockDiffPayload = (id, index) => findGroupStep(historyService.getCodeBlockHistoryGroups(), id, index, ({ oldContent, newContent }) => {
|
|
10761
|
-
if (!oldContent || !newContent) return null;
|
|
10762
|
-
return {
|
|
10763
|
-
category: "code-block",
|
|
10764
|
-
lastValue: oldContent,
|
|
10765
|
-
value: newContent,
|
|
10766
|
-
currentValue: codeBlockService.getCodeContentById(id) || null,
|
|
10767
|
-
targetLabel: newContent.name || oldContent.name || `${id}`,
|
|
10768
|
-
id
|
|
10769
|
-
};
|
|
10770
|
-
});
|
|
11506
|
+
const buildPageDiffPayload = (index) => buildDiffPayload({
|
|
11507
|
+
category: "node",
|
|
11508
|
+
groups: () => historyService.getPageHistoryGroups(),
|
|
11509
|
+
getCurrent: (id) => editorService.getNodeById(id),
|
|
11510
|
+
resolveType: (n, o) => n.type || o.type || "",
|
|
11511
|
+
resolveLabel: (n, o) => n.name || o.name || n.type || o.type || ""
|
|
11512
|
+
}, index);
|
|
11513
|
+
const buildDataSourceDiffPayload = (id, index) => buildDiffPayload({
|
|
11514
|
+
category: "data-source",
|
|
11515
|
+
groups: () => historyService.getDataSourceHistoryGroups(),
|
|
11516
|
+
getCurrent: (id) => dataSourceService.getDataSourceById(`${id}`),
|
|
11517
|
+
resolveType: (n, o) => n.type || o.type || "base",
|
|
11518
|
+
resolveLabel: (n, o, id) => n.title || o.title || `${id}`
|
|
11519
|
+
}, index, id);
|
|
11520
|
+
const buildCodeBlockDiffPayload = (id, index) => buildDiffPayload({
|
|
11521
|
+
category: "code-block",
|
|
11522
|
+
groups: () => historyService.getCodeBlockHistoryGroups(),
|
|
11523
|
+
getCurrent: (id) => codeBlockService.getCodeContentById(id),
|
|
11524
|
+
resolveLabel: (n, o, id) => n.name || o.name || `${id}`
|
|
11525
|
+
}, index, id);
|
|
10771
11526
|
const onPageDiff = (index) => {
|
|
10772
11527
|
const payload = buildPageDiffPayload(index);
|
|
10773
11528
|
if (payload) diffDialogRef.value?.open(payload);
|
|
@@ -10780,173 +11535,259 @@
|
|
|
10780
11535
|
const payload = buildCodeBlockDiffPayload(id, index);
|
|
10781
11536
|
if (payload) diffDialogRef.value?.open(payload);
|
|
10782
11537
|
};
|
|
10783
|
-
const onConfirmRevert = (0, vue.shallowRef)();
|
|
10784
11538
|
/**
|
|
10785
|
-
*
|
|
11539
|
+
* 「回滚」统一入口:把目标历史步骤的修改作为一次新操作反向应用(类 git revert),
|
|
10786
11540
|
* 不破坏原有栈结构。各 service 内部完成反向 + 入栈,并自带描述用于面板展示。
|
|
10787
11541
|
*
|
|
10788
|
-
*
|
|
10789
|
-
*
|
|
11542
|
+
* 交互:
|
|
11543
|
+
* - 可差异对比的步骤(单节点 / 单实体 update):弹出差异弹窗供用户确认,点「确定回滚」再执行;
|
|
11544
|
+
* - 无法对比的步骤(add / remove / 多节点更新,payload 为 null):弹出普通二次确认框,确认后执行。
|
|
11545
|
+
*
|
|
11546
|
+
* 页面 / 数据源 / 代码块三类回滚仅「差异入参构造」与「实际 revert 调用」不同,
|
|
11547
|
+
* 由调用方分别传入 payload 与 revert,公共的弹窗 / 确认流程在此收敛。
|
|
11548
|
+
*/
|
|
11549
|
+
const runRevert = (payload) => {
|
|
11550
|
+
if (payload && confirmDialogRef.value) return confirmDialogRef.value.confirm(payload);
|
|
11551
|
+
return confirmRevert();
|
|
11552
|
+
};
|
|
11553
|
+
/**
|
|
11554
|
+
* 回滚前置校验:若该历史步骤回滚所依赖的目标数据已被删除,则无法回滚。
|
|
11555
|
+
* - update(把旧值写回):被修改的目标必须仍存在;
|
|
11556
|
+
* - 页面 remove(还原被删节点):被删节点的原父容器必须仍存在,否则无处插回;
|
|
11557
|
+
* add(回滚即删除)即使目标已不在,也已达成「删除」目的,不视为失败。
|
|
11558
|
+
*
|
|
11559
|
+
* 命中时弹出「回滚失败」提示并返回 true,调用方据此中止本次回滚。
|
|
10790
11560
|
*/
|
|
11561
|
+
const isPageRevertTargetMissing = (index) => {
|
|
11562
|
+
const step = historyService.getPageStepList()[index]?.step;
|
|
11563
|
+
if (!step) return false;
|
|
11564
|
+
if (step.opType === "update") return (step.diff ?? []).some((item) => {
|
|
11565
|
+
const id = item.newSchema?.id ?? item.oldSchema?.id;
|
|
11566
|
+
return id !== void 0 && !editorService.getNodeById(id, false);
|
|
11567
|
+
});
|
|
11568
|
+
if (step.opType === "remove") return (step.diff ?? []).some((item) => item.parentId !== void 0 && !editorService.getNodeById(item.parentId, false));
|
|
11569
|
+
return false;
|
|
11570
|
+
};
|
|
11571
|
+
/** 数据源 update 步骤回滚时,对应数据源必须仍存在(已删除则无处写回旧值)。 */
|
|
11572
|
+
const isDataSourceRevertTargetMissing = (id, index) => {
|
|
11573
|
+
const step = historyService.getDataSourceStepList(id)[index]?.step;
|
|
11574
|
+
return Boolean(step && step.opType === "update" && !dataSourceService.getDataSourceById(`${id}`));
|
|
11575
|
+
};
|
|
11576
|
+
/** 代码块 update 步骤回滚时,对应代码块必须仍存在(已删除则无处写回旧值)。 */
|
|
11577
|
+
const isCodeBlockRevertTargetMissing = (id, index) => {
|
|
11578
|
+
const step = historyService.getCodeBlockStepList(id)[index]?.step;
|
|
11579
|
+
return Boolean(step && step.opType === "update" && !codeBlockService.getCodeContentById(id));
|
|
11580
|
+
};
|
|
11581
|
+
/** 目标数据已被删除、无法回滚时的统一提示。 */
|
|
11582
|
+
const showRevertTargetMissing = () => {
|
|
11583
|
+
_tmagic_design.tMagicMessage.error("回滚失败:该记录对应的数据已被删除");
|
|
11584
|
+
};
|
|
10791
11585
|
const onPageRevert = (index) => {
|
|
10792
|
-
|
|
10793
|
-
|
|
10794
|
-
|
|
10795
|
-
|
|
11586
|
+
if (isPageRevertTargetMissing(index)) {
|
|
11587
|
+
showRevertTargetMissing();
|
|
11588
|
+
return Promise.resolve(null);
|
|
11589
|
+
}
|
|
11590
|
+
return runRevert(buildPageDiffPayload(index)).then((result) => result ? editorService.revertPageStep(index) : null);
|
|
10796
11591
|
};
|
|
10797
11592
|
const onDataSourceRevert = (id, index) => {
|
|
10798
|
-
|
|
10799
|
-
|
|
10800
|
-
|
|
10801
|
-
|
|
11593
|
+
if (isDataSourceRevertTargetMissing(id, index)) {
|
|
11594
|
+
showRevertTargetMissing();
|
|
11595
|
+
return Promise.resolve(null);
|
|
11596
|
+
}
|
|
11597
|
+
return runRevert(buildDataSourceDiffPayload(id, index)).then((result) => result ? dataSourceService.revert(id, index) : null);
|
|
10802
11598
|
};
|
|
10803
11599
|
const onCodeBlockRevert = (id, index) => {
|
|
10804
|
-
|
|
10805
|
-
|
|
10806
|
-
|
|
10807
|
-
|
|
11600
|
+
if (isCodeBlockRevertTargetMissing(id, index)) {
|
|
11601
|
+
showRevertTargetMissing();
|
|
11602
|
+
return Promise.resolve(null);
|
|
11603
|
+
}
|
|
11604
|
+
return runRevert(buildCodeBlockDiffPayload(id, index)).then((result) => result ? codeBlockService.revert(id, index) : null);
|
|
11605
|
+
};
|
|
11606
|
+
/**
|
|
11607
|
+
* 「回滚」二次确认:新增 / 删除 / 多节点更新等无法做差异对比的步骤,
|
|
11608
|
+
* 不弹差异弹窗,改用一个普通确认框替代「确定回滚」按钮,避免点击后无任何提示直接执行。
|
|
11609
|
+
* 用户取消时返回 false,调用方据此中止回滚。
|
|
11610
|
+
*/
|
|
11611
|
+
const confirmRevert = () => confirmDialog("确定回滚该步骤吗?回滚会将该操作作为一条新记录反向应用(新增将被删除、删除将被还原),不影响后续历史记录。");
|
|
11612
|
+
/**
|
|
11613
|
+
* 通用二次确认弹窗:清空历史 / 无法差异对比的回滚等会改变状态的操作,先弹出确认框,
|
|
11614
|
+
* 用户点击「确定」返回 true,取消(confirm reject)时返回 false 并静默忽略。
|
|
11615
|
+
*/
|
|
11616
|
+
const confirmDialog = async (message) => {
|
|
11617
|
+
try {
|
|
11618
|
+
await _tmagic_design.tMagicMessageBox.confirm(message, "提示", {
|
|
11619
|
+
confirmButtonText: "确定",
|
|
11620
|
+
cancelButtonText: "取消",
|
|
11621
|
+
type: "warning"
|
|
11622
|
+
});
|
|
11623
|
+
return true;
|
|
11624
|
+
} catch (e) {
|
|
11625
|
+
return false;
|
|
11626
|
+
}
|
|
11627
|
+
};
|
|
11628
|
+
/**
|
|
11629
|
+
* 把内存中(已清空对应类别后的)历史状态重新写回 IndexedDB,
|
|
11630
|
+
* 使本地持久化的那份与内存保持一致——即「连同本地保存的一并删除」。
|
|
11631
|
+
* 不支持 IndexedDB 或写入失败时静默忽略(内存清空已生效)。
|
|
11632
|
+
*/
|
|
11633
|
+
const syncIndexedDB = async () => {
|
|
11634
|
+
try {
|
|
11635
|
+
await historyService.saveToIndexedDB();
|
|
11636
|
+
} catch (e) {}
|
|
11637
|
+
};
|
|
11638
|
+
const onPageClear = async () => {
|
|
11639
|
+
if (await confirmDialog("确定清空当前页面的历史记录吗?清空后将无法撤销/重做之前的操作,本地保存的记录也会一并删除。")) {
|
|
11640
|
+
historyService.clearPage();
|
|
11641
|
+
await syncIndexedDB();
|
|
11642
|
+
}
|
|
11643
|
+
};
|
|
11644
|
+
const onDataSourceClear = async () => {
|
|
11645
|
+
if (await confirmDialog("确定清空数据源的历史记录吗?清空后将无法撤销/重做之前的操作,本地保存的记录也会一并删除。")) {
|
|
11646
|
+
historyService.clearDataSource();
|
|
11647
|
+
await syncIndexedDB();
|
|
11648
|
+
}
|
|
10808
11649
|
};
|
|
10809
|
-
const
|
|
10810
|
-
|
|
11650
|
+
const onCodeBlockClear = async () => {
|
|
11651
|
+
if (await confirmDialog("确定清空代码块的历史记录吗?清空后将无法撤销/重做之前的操作,本地保存的记录也会一并删除。")) {
|
|
11652
|
+
historyService.clearCodeBlock();
|
|
11653
|
+
await syncIndexedDB();
|
|
11654
|
+
}
|
|
10811
11655
|
};
|
|
10812
11656
|
return (_ctx, _cache) => {
|
|
10813
|
-
return (0, vue.openBlock)(), (0, vue.createElementBlock)(vue.Fragment, null, [
|
|
10814
|
-
|
|
10815
|
-
|
|
10816
|
-
trigger: "click",
|
|
10817
|
-
visible: visible.value,
|
|
10818
|
-
width: 660
|
|
10819
|
-
}, {
|
|
10820
|
-
reference: (0, vue.withCtx)(() => [(0, vue.createVNode)((0, vue.unref)(_tmagic_design.TMagicTooltip), {
|
|
10821
|
-
effect: "dark",
|
|
11657
|
+
return (0, vue.openBlock)(), (0, vue.createElementBlock)(vue.Fragment, null, [
|
|
11658
|
+
(0, vue.createVNode)((0, vue.unref)(_tmagic_design.TMagicPopover), {
|
|
11659
|
+
"popper-class": "m-editor-history-list-popover",
|
|
10822
11660
|
placement: "bottom",
|
|
10823
|
-
|
|
11661
|
+
trigger: "click",
|
|
11662
|
+
visible: visible.value,
|
|
11663
|
+
"onUpdate:visible": _cache[3] || (_cache[3] = ($event) => visible.value = $event),
|
|
11664
|
+
width: 660
|
|
10824
11665
|
}, {
|
|
10825
|
-
|
|
10826
|
-
|
|
10827
|
-
|
|
10828
|
-
|
|
11666
|
+
reference: (0, vue.withCtx)(() => [(0, vue.createVNode)((0, vue.unref)(_tmagic_design.TMagicTooltip), {
|
|
11667
|
+
effect: "dark",
|
|
11668
|
+
placement: "bottom",
|
|
11669
|
+
content: "历史记录"
|
|
10829
11670
|
}, {
|
|
10830
|
-
|
|
11671
|
+
default: (0, vue.withCtx)(() => [(0, vue.createVNode)((0, vue.unref)(_tmagic_design.TMagicButton), {
|
|
11672
|
+
size: "small",
|
|
11673
|
+
link: "",
|
|
11674
|
+
onClick: _cache[2] || (_cache[2] = ($event) => visible.value = !visible.value)
|
|
11675
|
+
}, {
|
|
11676
|
+
icon: (0, vue.withCtx)(() => [(0, vue.createVNode)(Icon_default, { icon: (0, vue.unref)(ClockIcon) }, null, 8, ["icon"])]),
|
|
11677
|
+
_: 1
|
|
11678
|
+
})]),
|
|
10831
11679
|
_: 1
|
|
10832
11680
|
})]),
|
|
10833
|
-
|
|
10834
|
-
|
|
10835
|
-
|
|
10836
|
-
|
|
10837
|
-
placement: "top",
|
|
10838
|
-
content: "关闭"
|
|
10839
|
-
}, {
|
|
10840
|
-
default: (0, vue.withCtx)(() => [(0, vue.createVNode)((0, vue.unref)(_tmagic_design.TMagicButton), {
|
|
10841
|
-
class: "m-editor-history-list-close",
|
|
10842
|
-
size: "small",
|
|
10843
|
-
link: "",
|
|
10844
|
-
onClick: _cache[0] || (_cache[0] = ($event) => visible.value = false)
|
|
11681
|
+
default: (0, vue.withCtx)(() => [(0, vue.createElementVNode)("div", _hoisted_1$55, [(0, vue.createVNode)((0, vue.unref)(_tmagic_design.TMagicTooltip), {
|
|
11682
|
+
effect: "dark",
|
|
11683
|
+
placement: "top",
|
|
11684
|
+
content: "关闭"
|
|
10845
11685
|
}, {
|
|
10846
|
-
|
|
10847
|
-
|
|
10848
|
-
|
|
10849
|
-
|
|
10850
|
-
|
|
10851
|
-
|
|
10852
|
-
|
|
10853
|
-
class: "m-editor-history-list-tabs"
|
|
10854
|
-
}, {
|
|
10855
|
-
default: (0, vue.withCtx)(() => [
|
|
10856
|
-
((0, vue.openBlock)(), (0, vue.createBlock)((0, vue.resolveDynamicComponent)((0, vue.unref)(tabPaneComponent)?.component || "el-tab-pane"), (0, vue.normalizeProps)((0, vue.guardReactiveProps)((0, vue.unref)(tabPaneComponent)?.props({
|
|
10857
|
-
name: "page",
|
|
10858
|
-
label: `页面 (${(0, vue.unref)(pageGroups).length})`
|
|
10859
|
-
}) || {})), {
|
|
10860
|
-
default: (0, vue.withCtx)(() => [(0, vue.createVNode)(PageTab_default, {
|
|
10861
|
-
list: (0, vue.unref)(pageGroupsDisplay),
|
|
10862
|
-
expanded: (0, vue.unref)(expanded),
|
|
10863
|
-
onToggle: (0, vue.unref)(toggleGroup),
|
|
10864
|
-
onGoto: onPageGoto,
|
|
10865
|
-
onGotoInitial: onPageGotoInitial,
|
|
10866
|
-
onDiffStep: onPageDiff,
|
|
10867
|
-
onRevertStep: onPageRevert
|
|
10868
|
-
}, null, 8, [
|
|
10869
|
-
"list",
|
|
10870
|
-
"expanded",
|
|
10871
|
-
"onToggle"
|
|
10872
|
-
])]),
|
|
10873
|
-
_: 1
|
|
10874
|
-
}, 16)),
|
|
10875
|
-
!disabledDataSource.value ? ((0, vue.openBlock)(), (0, vue.createBlock)((0, vue.resolveDynamicComponent)((0, vue.unref)(tabPaneComponent)?.component || "el-tab-pane"), (0, vue.normalizeProps)((0, vue.mergeProps)({ key: 0 }, (0, vue.unref)(tabPaneComponent)?.props({
|
|
10876
|
-
name: "data-source",
|
|
10877
|
-
label: `数据源 (${(0, vue.unref)(dataSourceGroups).length})`
|
|
10878
|
-
}) || {})), {
|
|
10879
|
-
default: (0, vue.withCtx)(() => [(0, vue.createVNode)(BucketTab_default, {
|
|
10880
|
-
title: "数据源",
|
|
10881
|
-
prefix: "ds",
|
|
10882
|
-
buckets: (0, vue.unref)(dataSourceGroupsByTarget),
|
|
10883
|
-
expanded: (0, vue.unref)(expanded),
|
|
10884
|
-
"describe-group": (0, vue.unref)(describeDataSourceGroup),
|
|
10885
|
-
"describe-step": (0, vue.unref)(describeDataSourceStep),
|
|
10886
|
-
"is-step-diffable": isDataSourceStepDiffable,
|
|
10887
|
-
"is-step-revertable": (0, vue.unref)(isDataSourceStepRevertable),
|
|
10888
|
-
onToggle: (0, vue.unref)(toggleGroup),
|
|
10889
|
-
onGoto: onDataSourceGoto,
|
|
10890
|
-
onGotoInitial: onDataSourceGotoInitial,
|
|
10891
|
-
onDiffStep: onDataSourceDiff,
|
|
10892
|
-
onRevertStep: onDataSourceRevert
|
|
10893
|
-
}, null, 8, [
|
|
10894
|
-
"buckets",
|
|
10895
|
-
"expanded",
|
|
10896
|
-
"describe-group",
|
|
10897
|
-
"describe-step",
|
|
10898
|
-
"is-step-revertable",
|
|
10899
|
-
"onToggle"
|
|
10900
|
-
])]),
|
|
10901
|
-
_: 1
|
|
10902
|
-
}, 16)) : (0, vue.createCommentVNode)("v-if", true),
|
|
10903
|
-
!disabledCodeBlock.value ? ((0, vue.openBlock)(), (0, vue.createBlock)((0, vue.resolveDynamicComponent)((0, vue.unref)(tabPaneComponent)?.component || "el-tab-pane"), (0, vue.normalizeProps)((0, vue.mergeProps)({ key: 1 }, (0, vue.unref)(tabPaneComponent)?.props({
|
|
10904
|
-
name: "code-block",
|
|
10905
|
-
label: `代码块 (${(0, vue.unref)(codeBlockGroups).length})`
|
|
10906
|
-
}) || {})), {
|
|
10907
|
-
default: (0, vue.withCtx)(() => [(0, vue.createVNode)(BucketTab_default, {
|
|
10908
|
-
title: "代码块",
|
|
10909
|
-
prefix: "cb",
|
|
10910
|
-
buckets: (0, vue.unref)(codeBlockGroupsByTarget),
|
|
10911
|
-
expanded: (0, vue.unref)(expanded),
|
|
10912
|
-
"describe-group": (0, vue.unref)(describeCodeBlockGroup),
|
|
10913
|
-
"describe-step": (0, vue.unref)(describeCodeBlockStep),
|
|
10914
|
-
"is-step-diffable": isCodeBlockStepDiffable,
|
|
10915
|
-
"is-step-revertable": (0, vue.unref)(isCodeBlockStepRevertable),
|
|
10916
|
-
onToggle: (0, vue.unref)(toggleGroup),
|
|
10917
|
-
onGoto: onCodeBlockGoto,
|
|
10918
|
-
onGotoInitial: onCodeBlockGotoInitial,
|
|
10919
|
-
onDiffStep: onCodeBlockDiff,
|
|
10920
|
-
onRevertStep: onCodeBlockRevert
|
|
10921
|
-
}, null, 8, [
|
|
10922
|
-
"buckets",
|
|
10923
|
-
"expanded",
|
|
10924
|
-
"describe-group",
|
|
10925
|
-
"describe-step",
|
|
10926
|
-
"is-step-revertable",
|
|
10927
|
-
"onToggle"
|
|
10928
|
-
])]),
|
|
11686
|
+
default: (0, vue.withCtx)(() => [(0, vue.createVNode)((0, vue.unref)(_tmagic_design.TMagicButton), {
|
|
11687
|
+
class: "m-editor-history-list-close",
|
|
11688
|
+
size: "small",
|
|
11689
|
+
link: "",
|
|
11690
|
+
onClick: _cache[0] || (_cache[0] = ($event) => visible.value = false)
|
|
11691
|
+
}, {
|
|
11692
|
+
icon: (0, vue.withCtx)(() => [(0, vue.createVNode)(Icon_default, { icon: (0, vue.unref)(CloseIcon) }, null, 8, ["icon"])]),
|
|
10929
11693
|
_: 1
|
|
10930
|
-
}
|
|
10931
|
-
|
|
10932
|
-
|
|
10933
|
-
|
|
10934
|
-
|
|
10935
|
-
|
|
10936
|
-
|
|
10937
|
-
|
|
10938
|
-
|
|
10939
|
-
|
|
10940
|
-
|
|
11694
|
+
})]),
|
|
11695
|
+
_: 1
|
|
11696
|
+
}), (0, vue.createVNode)((0, vue.unref)(_tmagic_design.TMagicTabs), {
|
|
11697
|
+
modelValue: activeTab.value,
|
|
11698
|
+
"onUpdate:modelValue": _cache[1] || (_cache[1] = ($event) => activeTab.value = $event),
|
|
11699
|
+
class: "m-editor-history-list-tabs"
|
|
11700
|
+
}, {
|
|
11701
|
+
default: (0, vue.withCtx)(() => [
|
|
11702
|
+
((0, vue.openBlock)(), (0, vue.createBlock)((0, vue.resolveDynamicComponent)((0, vue.unref)(tabPaneComponent)?.component || "el-tab-pane"), (0, vue.normalizeProps)((0, vue.guardReactiveProps)((0, vue.unref)(tabPaneComponent)?.props({
|
|
11703
|
+
name: "page",
|
|
11704
|
+
label: `页面 (${(0, vue.unref)(pageGroups).length})`
|
|
11705
|
+
}) || {})), {
|
|
11706
|
+
default: (0, vue.withCtx)(() => [(0, vue.createVNode)(PageTab_default, {
|
|
11707
|
+
list: (0, vue.unref)(pageGroupsDisplay),
|
|
11708
|
+
expanded: (0, vue.unref)(expanded),
|
|
11709
|
+
marker: pageMarker.value,
|
|
11710
|
+
onToggle: (0, vue.unref)(toggleGroup),
|
|
11711
|
+
onGoto: onPageGoto,
|
|
11712
|
+
onGotoInitial: onPageGotoInitial,
|
|
11713
|
+
onDiffStep: onPageDiff,
|
|
11714
|
+
onRevertStep: onPageRevert,
|
|
11715
|
+
onSelect: onPageSelect,
|
|
11716
|
+
onClear: onPageClear
|
|
11717
|
+
}, null, 8, [
|
|
11718
|
+
"list",
|
|
11719
|
+
"expanded",
|
|
11720
|
+
"marker",
|
|
11721
|
+
"onToggle"
|
|
11722
|
+
])]),
|
|
11723
|
+
_: 1
|
|
11724
|
+
}, 16)),
|
|
11725
|
+
!disabledDataSource.value ? ((0, vue.openBlock)(), (0, vue.createBlock)((0, vue.resolveDynamicComponent)((0, vue.unref)(tabPaneComponent)?.component || "el-tab-pane"), (0, vue.normalizeProps)((0, vue.mergeProps)({ key: 0 }, (0, vue.unref)(tabPaneComponent)?.props({
|
|
11726
|
+
name: "data-source",
|
|
11727
|
+
label: `数据源 (${(0, vue.unref)(dataSourceGroups).length})`
|
|
11728
|
+
}) || {})), {
|
|
11729
|
+
default: (0, vue.withCtx)(() => [(0, vue.createVNode)(BucketTab_default, {
|
|
11730
|
+
config: dataSourceConfig,
|
|
11731
|
+
buckets: (0, vue.unref)(dataSourceGroupsByTarget),
|
|
11732
|
+
expanded: (0, vue.unref)(expanded),
|
|
11733
|
+
onToggle: (0, vue.unref)(toggleGroup),
|
|
11734
|
+
onGoto: onDataSourceGoto,
|
|
11735
|
+
onGotoInitial: onDataSourceGotoInitial,
|
|
11736
|
+
onDiffStep: onDataSourceDiff,
|
|
11737
|
+
onRevertStep: onDataSourceRevert,
|
|
11738
|
+
onClear: onDataSourceClear
|
|
11739
|
+
}, null, 8, [
|
|
11740
|
+
"buckets",
|
|
11741
|
+
"expanded",
|
|
11742
|
+
"onToggle"
|
|
11743
|
+
])]),
|
|
11744
|
+
_: 1
|
|
11745
|
+
}, 16)) : (0, vue.createCommentVNode)("v-if", true),
|
|
11746
|
+
!disabledCodeBlock.value ? ((0, vue.openBlock)(), (0, vue.createBlock)((0, vue.resolveDynamicComponent)((0, vue.unref)(tabPaneComponent)?.component || "el-tab-pane"), (0, vue.normalizeProps)((0, vue.mergeProps)({ key: 1 }, (0, vue.unref)(tabPaneComponent)?.props({
|
|
11747
|
+
name: "code-block",
|
|
11748
|
+
label: `代码块 (${(0, vue.unref)(codeBlockGroups).length})`
|
|
11749
|
+
}) || {})), {
|
|
11750
|
+
default: (0, vue.withCtx)(() => [(0, vue.createVNode)(BucketTab_default, {
|
|
11751
|
+
config: codeBlockConfig,
|
|
11752
|
+
buckets: (0, vue.unref)(codeBlockGroupsByTarget),
|
|
11753
|
+
expanded: (0, vue.unref)(expanded),
|
|
11754
|
+
onToggle: (0, vue.unref)(toggleGroup),
|
|
11755
|
+
onGoto: onCodeBlockGoto,
|
|
11756
|
+
onGotoInitial: onCodeBlockGotoInitial,
|
|
11757
|
+
onDiffStep: onCodeBlockDiff,
|
|
11758
|
+
onRevertStep: onCodeBlockRevert,
|
|
11759
|
+
onClear: onCodeBlockClear
|
|
11760
|
+
}, null, 8, [
|
|
11761
|
+
"buckets",
|
|
11762
|
+
"expanded",
|
|
11763
|
+
"onToggle"
|
|
11764
|
+
])]),
|
|
11765
|
+
_: 1
|
|
11766
|
+
}, 16)) : (0, vue.createCommentVNode)("v-if", true),
|
|
11767
|
+
((0, vue.openBlock)(true), (0, vue.createElementBlock)(vue.Fragment, null, (0, vue.renderList)((0, vue.unref)(extraTabs), (tab) => {
|
|
11768
|
+
return (0, vue.openBlock)(), (0, vue.createBlock)((0, vue.resolveDynamicComponent)((0, vue.unref)(tabPaneComponent)?.component || "el-tab-pane"), (0, vue.mergeProps)({ key: tab.name }, { ref_for: true }, (0, vue.unref)(tabPaneComponent)?.props({
|
|
11769
|
+
name: tab.name,
|
|
11770
|
+
label: resolveTabLabel(tab)
|
|
11771
|
+
}) || {}), {
|
|
11772
|
+
default: (0, vue.withCtx)(() => [((0, vue.openBlock)(), (0, vue.createBlock)((0, vue.resolveDynamicComponent)(tab.component), (0, vue.mergeProps)({ ref_for: true }, tab.props || {}, (0, vue.toHandlers)(tab.listeners || {})), null, 16))]),
|
|
11773
|
+
_: 2
|
|
11774
|
+
}, 1040);
|
|
11775
|
+
}), 128))
|
|
11776
|
+
]),
|
|
11777
|
+
_: 1
|
|
11778
|
+
}, 8, ["modelValue"])])]),
|
|
10941
11779
|
_: 1
|
|
10942
|
-
}, 8, ["
|
|
10943
|
-
|
|
10944
|
-
|
|
10945
|
-
|
|
10946
|
-
"extend-state"
|
|
10947
|
-
|
|
10948
|
-
|
|
10949
|
-
|
|
11780
|
+
}, 8, ["visible"]),
|
|
11781
|
+
(0, vue.createVNode)(HistoryDiffDialog_default, {
|
|
11782
|
+
ref: "diffDialog",
|
|
11783
|
+
"extend-state": (0, vue.unref)(extendFormState)
|
|
11784
|
+
}, null, 8, ["extend-state"]),
|
|
11785
|
+
(0, vue.createVNode)(HistoryDiffDialog_default, {
|
|
11786
|
+
ref: "confirmDialog",
|
|
11787
|
+
"is-confirm": true,
|
|
11788
|
+
"extend-state": (0, vue.unref)(extendFormState)
|
|
11789
|
+
}, null, 8, ["extend-state"])
|
|
11790
|
+
], 64);
|
|
10950
11791
|
};
|
|
10951
11792
|
}
|
|
10952
11793
|
});
|
|
@@ -12855,7 +13696,9 @@
|
|
|
12855
13696
|
props: /* @__PURE__ */ (0, vue.mergeModels)({
|
|
12856
13697
|
title: {},
|
|
12857
13698
|
values: {},
|
|
12858
|
-
disabled: { type: Boolean }
|
|
13699
|
+
disabled: { type: Boolean },
|
|
13700
|
+
editMethodName: {},
|
|
13701
|
+
editFieldPath: {}
|
|
12859
13702
|
}, {
|
|
12860
13703
|
"visible": {
|
|
12861
13704
|
type: Boolean,
|
|
@@ -12880,9 +13723,20 @@
|
|
|
12880
13723
|
const dataSourceConfig = (0, vue.ref)([]);
|
|
12881
13724
|
const { height: editorHeight } = useEditorContentHeight();
|
|
12882
13725
|
const { boxPosition, calcBoxPosition } = useNextFloatBoxPosition(uiService, (0, vue.inject)("parentFloating", (0, vue.ref)(null)));
|
|
13726
|
+
/** 供「方法定义」tab 内的字段消费,用于打开数据源详情后自动打开指定方法 */
|
|
13727
|
+
(0, vue.provide)("editingDataSourceMethodName", (0, vue.computed)(() => props.editMethodName));
|
|
13728
|
+
/** 供「数据定义」tab 内的字段消费,用于打开数据源详情后自动打开指定字段 */
|
|
13729
|
+
(0, vue.provide)("editingDataSourceFieldPath", (0, vue.computed)(() => props.editFieldPath || []));
|
|
12883
13730
|
(0, vue.watchEffect)(() => {
|
|
12884
13731
|
initValues.value = props.values;
|
|
12885
|
-
|
|
13732
|
+
const config = dataSourceService.getFormConfig(initValues.value.type);
|
|
13733
|
+
let activeTab = "";
|
|
13734
|
+
if (props.editMethodName) activeTab = "methods";
|
|
13735
|
+
else if (props.editFieldPath?.length) activeTab = "fields";
|
|
13736
|
+
dataSourceConfig.value = activeTab ? config.map((item) => item.type === "tab" ? {
|
|
13737
|
+
...item,
|
|
13738
|
+
active: activeTab
|
|
13739
|
+
} : item) : config;
|
|
12886
13740
|
});
|
|
12887
13741
|
const submitHandler = (values, data) => {
|
|
12888
13742
|
emit("submit", values, data);
|
|
@@ -13171,7 +14025,13 @@
|
|
|
13171
14025
|
const eventBus = (0, vue.inject)("eventBus");
|
|
13172
14026
|
const { dataSourceService } = useServices();
|
|
13173
14027
|
const { editDialog, dataSourceValues, dialogTitle, editable, editHandler, submitDataSourceHandler } = useDataSourceEdit(dataSourceService);
|
|
14028
|
+
/** 打开数据源详情时需要直接定位并打开的方法名,为空则正常展示「数据定义」tab */
|
|
14029
|
+
const editMethodName = (0, vue.ref)("");
|
|
14030
|
+
/** 打开数据源详情时需要直接定位并打开的字段路径,为空则不自动打开字段配置 */
|
|
14031
|
+
const editFieldPath = (0, vue.ref)([]);
|
|
13174
14032
|
const editDialogCloseHandler = () => {
|
|
14033
|
+
editMethodName.value = "";
|
|
14034
|
+
editFieldPath.value = [];
|
|
13175
14035
|
if (dataSourceListRef.value) for (const [, status] of dataSourceListRef.value.nodeStatusMap.entries()) status.selected = false;
|
|
13176
14036
|
};
|
|
13177
14037
|
(0, vue.watch)(dataSourceValues, (dataSourceValues) => {
|
|
@@ -13209,6 +14069,18 @@
|
|
|
13209
14069
|
dataSourceListRef.value?.filter(val);
|
|
13210
14070
|
};
|
|
13211
14071
|
eventBus?.on("edit-data-source", (id) => {
|
|
14072
|
+
editMethodName.value = "";
|
|
14073
|
+
editFieldPath.value = [];
|
|
14074
|
+
editHandler(id);
|
|
14075
|
+
});
|
|
14076
|
+
eventBus?.on("edit-data-source-method", (id, methodName) => {
|
|
14077
|
+
editMethodName.value = methodName;
|
|
14078
|
+
editFieldPath.value = [];
|
|
14079
|
+
editHandler(id);
|
|
14080
|
+
});
|
|
14081
|
+
eventBus?.on("edit-data-source-field", (id, fieldPath) => {
|
|
14082
|
+
editMethodName.value = "";
|
|
14083
|
+
editFieldPath.value = fieldPath;
|
|
13212
14084
|
editHandler(id);
|
|
13213
14085
|
});
|
|
13214
14086
|
eventBus?.on("remove-data-source", (id) => {
|
|
@@ -13257,12 +14129,16 @@
|
|
|
13257
14129
|
disabled: !(0, vue.unref)(editable),
|
|
13258
14130
|
values: (0, vue.unref)(dataSourceValues),
|
|
13259
14131
|
title: (0, vue.unref)(dialogTitle),
|
|
14132
|
+
"edit-method-name": editMethodName.value,
|
|
14133
|
+
"edit-field-path": editFieldPath.value,
|
|
13260
14134
|
onSubmit: (0, vue.unref)(submitDataSourceHandler),
|
|
13261
14135
|
onClose: editDialogCloseHandler
|
|
13262
14136
|
}, null, 8, [
|
|
13263
14137
|
"disabled",
|
|
13264
14138
|
"values",
|
|
13265
14139
|
"title",
|
|
14140
|
+
"edit-method-name",
|
|
14141
|
+
"edit-field-path",
|
|
13266
14142
|
"onSubmit"
|
|
13267
14143
|
]),
|
|
13268
14144
|
((0, vue.openBlock)(), (0, vue.createBlock)(vue.Teleport, { to: "body" }, [menuData.value.length ? ((0, vue.openBlock)(), (0, vue.createBlock)(ContentMenu_default, {
|
|
@@ -14242,7 +15118,11 @@
|
|
|
14242
15118
|
});
|
|
14243
15119
|
}
|
|
14244
15120
|
}, { immediate: true });
|
|
14245
|
-
const activeTabName = (0, vue.
|
|
15121
|
+
const activeTabName = (0, vue.computed)({
|
|
15122
|
+
get: () => uiService.get("sideBarActiveTabName"),
|
|
15123
|
+
set: (value) => uiService.set("sideBarActiveTabName", value)
|
|
15124
|
+
});
|
|
15125
|
+
uiService.set("sideBarActiveTabName", props.data?.status || "");
|
|
14246
15126
|
const getItemConfig = (data) => {
|
|
14247
15127
|
const map = {
|
|
14248
15128
|
[SideItemKey.COMPONENT_LIST]: {
|
|
@@ -15436,17 +16316,6 @@
|
|
|
15436
16316
|
],
|
|
15437
16317
|
sync: ["setCodeDslByIdSync"]
|
|
15438
16318
|
};
|
|
15439
|
-
/**
|
|
15440
|
-
* 「回滚」生成的新 step 简短描述。仅 service 层使用。
|
|
15441
|
-
*/
|
|
15442
|
-
var describeRevertCodeBlockStep = (step) => {
|
|
15443
|
-
const { oldContent, newContent, changeRecords, id } = step;
|
|
15444
|
-
if (oldContent === null && newContent) return `撤回新增 ${newContent.name || newContent.id || id}`;
|
|
15445
|
-
if (oldContent && newContent === null) return `还原已删除的 ${oldContent.name || oldContent.id || id}`;
|
|
15446
|
-
const name = newContent?.name || oldContent?.name || `${id}`;
|
|
15447
|
-
const propPath = changeRecords?.[0]?.propPath;
|
|
15448
|
-
return propPath ? `还原 ${name} · ${propPath}` : `还原 ${name}`;
|
|
15449
|
-
};
|
|
15450
16319
|
var CodeBlock = class extends BaseService {
|
|
15451
16320
|
state = (0, vue.reactive)({
|
|
15452
16321
|
codeDsl: null,
|
|
@@ -15455,6 +16324,16 @@
|
|
|
15455
16324
|
undeletableList: [],
|
|
15456
16325
|
paramsColConfig: void 0
|
|
15457
16326
|
});
|
|
16327
|
+
/**
|
|
16328
|
+
* 最近一次写入历史栈的代码块历史记录 uuid(单条写入场景:新增 / 更新)。
|
|
16329
|
+
* 供 setCodeDslById(Sync)AndGetHistoryId 取回,普通方法不读取它。
|
|
16330
|
+
*/
|
|
16331
|
+
lastPushedHistoryId = null;
|
|
16332
|
+
/**
|
|
16333
|
+
* deleteCodeDslByIds 一次删除多个代码块时,按写入顺序收集的历史记录 uuid 列表。
|
|
16334
|
+
* 在 deleteCodeDslByIds 入口处重置,供 deleteCodeDslByIdsAndGetHistoryId 取回。
|
|
16335
|
+
*/
|
|
16336
|
+
lastDeletedHistoryIds = [];
|
|
15458
16337
|
constructor() {
|
|
15459
16338
|
super([...canUsePluginMethods$4.async.map((methodName) => ({
|
|
15460
16339
|
name: methodName,
|
|
@@ -15537,13 +16416,13 @@
|
|
|
15537
16416
|
...codeConfigProcessed
|
|
15538
16417
|
};
|
|
15539
16418
|
const newContent = cloneDeep$1(codeDsl[id]);
|
|
15540
|
-
if (!doNotPushHistory) history_default.pushCodeBlock(id, {
|
|
16419
|
+
if (!doNotPushHistory) this.lastPushedHistoryId = history_default.pushCodeBlock(id, {
|
|
15541
16420
|
oldContent,
|
|
15542
16421
|
newContent,
|
|
15543
16422
|
changeRecords,
|
|
15544
16423
|
historyDescription,
|
|
15545
16424
|
source: historySource
|
|
15546
|
-
});
|
|
16425
|
+
})?.uuid ?? null;
|
|
15547
16426
|
this.emit("addOrUpdate", id, codeDsl[id]);
|
|
15548
16427
|
}
|
|
15549
16428
|
/**
|
|
@@ -15626,18 +16505,59 @@
|
|
|
15626
16505
|
async deleteCodeDslByIds(codeIds, { doNotPushHistory = false, historyDescription, historySource } = {}) {
|
|
15627
16506
|
const currentDsl = await this.getCodeDsl();
|
|
15628
16507
|
if (!currentDsl) return;
|
|
16508
|
+
this.lastDeletedHistoryIds = [];
|
|
15629
16509
|
codeIds.forEach((id) => {
|
|
15630
16510
|
const oldContent = currentDsl[id] ? cloneDeep$1(currentDsl[id]) : null;
|
|
15631
16511
|
delete currentDsl[id];
|
|
15632
|
-
if (oldContent && !doNotPushHistory)
|
|
15633
|
-
|
|
15634
|
-
|
|
15635
|
-
|
|
15636
|
-
|
|
15637
|
-
|
|
16512
|
+
if (oldContent && !doNotPushHistory) {
|
|
16513
|
+
const uuid = history_default.pushCodeBlock(id, {
|
|
16514
|
+
oldContent,
|
|
16515
|
+
newContent: null,
|
|
16516
|
+
historyDescription,
|
|
16517
|
+
source: historySource
|
|
16518
|
+
})?.uuid;
|
|
16519
|
+
if (uuid) this.lastDeletedHistoryIds.push(uuid);
|
|
16520
|
+
}
|
|
15638
16521
|
this.emit("remove", id);
|
|
15639
16522
|
});
|
|
15640
16523
|
}
|
|
16524
|
+
/**
|
|
16525
|
+
* 下列 *AndGetHistoryId 方法与对应的写入方法行为完全一致,
|
|
16526
|
+
* 返回值在 {@link DslOpWithHistoryIdsResult} 中同时包含原操作结果与本次写入的历史 uuid 列表,
|
|
16527
|
+
* 可用于精确引用 / 定位该条历史记录(埋点、revert、跨端同步等)。
|
|
16528
|
+
*
|
|
16529
|
+
* 当本次操作未写入历史(doNotPushHistory 为 true、或无对应记录)时 historyIds 为 `[]`。
|
|
16530
|
+
*/
|
|
16531
|
+
/** 等价于 {@link setCodeDslById},并额外返回本次写入历史记录的 uuid 列表(未入栈时 historyIds 为 `[]`)。 */
|
|
16532
|
+
async setCodeDslByIdAndGetHistoryId(id, codeConfig, options = {}) {
|
|
16533
|
+
this.lastPushedHistoryId = null;
|
|
16534
|
+
await this.setCodeDslById(id, codeConfig, options);
|
|
16535
|
+
return {
|
|
16536
|
+
result: void 0,
|
|
16537
|
+
historyIds: getLastPushedHistoryIds(this.lastPushedHistoryId)
|
|
16538
|
+
};
|
|
16539
|
+
}
|
|
16540
|
+
/** 等价于 {@link setCodeDslByIdSync},并额外返回本次写入历史记录的 uuid 列表(未入栈时 historyIds 为 `[]`)。 */
|
|
16541
|
+
setCodeDslByIdSyncAndGetHistoryId(id, codeConfig, force = true, options = {}) {
|
|
16542
|
+
this.lastPushedHistoryId = null;
|
|
16543
|
+
this.setCodeDslByIdSync(id, codeConfig, force, options);
|
|
16544
|
+
return {
|
|
16545
|
+
result: void 0,
|
|
16546
|
+
historyIds: getLastPushedHistoryIds(this.lastPushedHistoryId)
|
|
16547
|
+
};
|
|
16548
|
+
}
|
|
16549
|
+
/**
|
|
16550
|
+
* 等价于 {@link deleteCodeDslByIds},并额外返回本次写入的全部历史记录 uuid(按删除顺序)。
|
|
16551
|
+
* 一次删除多个代码块会产生多条历史记录;未写入任何历史时 historyIds 为 `[]`。
|
|
16552
|
+
*/
|
|
16553
|
+
async deleteCodeDslByIdsAndGetHistoryId(codeIds, options = {}) {
|
|
16554
|
+
this.lastDeletedHistoryIds = [];
|
|
16555
|
+
await this.deleteCodeDslByIds(codeIds, options);
|
|
16556
|
+
return {
|
|
16557
|
+
result: void 0,
|
|
16558
|
+
historyIds: [...this.lastDeletedHistoryIds]
|
|
16559
|
+
};
|
|
16560
|
+
}
|
|
15641
16561
|
setParamsColConfig(config) {
|
|
15642
16562
|
this.state.paramsColConfig = config;
|
|
15643
16563
|
}
|
|
@@ -15713,11 +16633,27 @@
|
|
|
15713
16633
|
async revert(id, index) {
|
|
15714
16634
|
const entry = history_default.getCodeBlockStepList(id)[index];
|
|
15715
16635
|
if (!entry?.applied) return null;
|
|
15716
|
-
|
|
15717
|
-
|
|
16636
|
+
const { oldSchema, newSchema, changeRecords } = entry.step.diff?.[0] ?? {};
|
|
16637
|
+
if (oldSchema && newSchema && !changeRecords?.length) return null;
|
|
16638
|
+
const description = `回滚 #${index + 1}: ${describeRevertStep(entry.step.id, entry.step.diff?.[0], (s) => s.name)}`;
|
|
15718
16639
|
return await this.applyRevertStep(entry.step, description);
|
|
15719
16640
|
}
|
|
15720
16641
|
/**
|
|
16642
|
+
* 通过历史记录 uuid 回滚代码块历史步骤,语义同 {@link revert},
|
|
16643
|
+
* 仅无需调用方再传 codeBlockId 与 index:内部会按 uuid 在全部代码块栈中定位对应步骤后再回滚。
|
|
16644
|
+
* 按数组顺序依次回滚,返回与入参同序的结果列表(某项失败时为 `null`)。
|
|
16645
|
+
*
|
|
16646
|
+
* @param uuids 目标历史记录的 uuid 列表,通常由 {@link setCodeDslByIdAndGetHistoryId} 等方法返回的 `historyIds`
|
|
16647
|
+
*/
|
|
16648
|
+
async revertById(uuids) {
|
|
16649
|
+
const results = [];
|
|
16650
|
+
for (const uuid of uuids) {
|
|
16651
|
+
const location = history_default.findCodeBlockStepLocationByUuid(uuid);
|
|
16652
|
+
results.push(location ? await this.revert(location.id, location.index) : null);
|
|
16653
|
+
}
|
|
16654
|
+
return results;
|
|
16655
|
+
}
|
|
16656
|
+
/**
|
|
15721
16657
|
* 生成代码块唯一id
|
|
15722
16658
|
* @returns {Id} 代码块唯一id
|
|
15723
16659
|
*/
|
|
@@ -15782,22 +16718,23 @@
|
|
|
15782
16718
|
* 差异仅在于通过公开的 setCodeDslByIdSync / deleteCodeDslByIds 触发 push。
|
|
15783
16719
|
*/
|
|
15784
16720
|
async applyRevertStep(step, historyDescription) {
|
|
15785
|
-
const { id
|
|
15786
|
-
|
|
16721
|
+
const { id } = step;
|
|
16722
|
+
const { oldSchema, newSchema, changeRecords } = step.diff?.[0] ?? {};
|
|
16723
|
+
if (!oldSchema && newSchema) {
|
|
15787
16724
|
await this.deleteCodeDslByIds([id], {
|
|
15788
16725
|
historyDescription,
|
|
15789
16726
|
historySource: "rollback"
|
|
15790
16727
|
});
|
|
15791
16728
|
return history_default.getCodeBlockStepList(id).slice(-1)[0]?.step ?? null;
|
|
15792
16729
|
}
|
|
15793
|
-
if (
|
|
15794
|
-
this.setCodeDslByIdSync(id, cloneDeep$1(
|
|
16730
|
+
if (oldSchema && !newSchema) {
|
|
16731
|
+
this.setCodeDslByIdSync(id, cloneDeep$1(oldSchema), true, {
|
|
15795
16732
|
historyDescription,
|
|
15796
16733
|
historySource: "rollback"
|
|
15797
16734
|
});
|
|
15798
16735
|
return history_default.getCodeBlockStepList(id).slice(-1)[0]?.step ?? null;
|
|
15799
16736
|
}
|
|
15800
|
-
if (!
|
|
16737
|
+
if (!oldSchema || !newSchema) return null;
|
|
15801
16738
|
if (changeRecords?.length) {
|
|
15802
16739
|
const current = this.getCodeContentById(id);
|
|
15803
16740
|
if (!current) return null;
|
|
@@ -15808,17 +16745,17 @@
|
|
|
15808
16745
|
fallbackToFullReplace = true;
|
|
15809
16746
|
break;
|
|
15810
16747
|
}
|
|
15811
|
-
const value = cloneDeep$1((0, _tmagic_utils.getValueByKeyPath)(record.propPath,
|
|
16748
|
+
const value = cloneDeep$1((0, _tmagic_utils.getValueByKeyPath)(record.propPath, oldSchema));
|
|
15812
16749
|
(0, _tmagic_utils.setValueByKeyPath)(record.propPath, value, patched);
|
|
15813
16750
|
}
|
|
15814
|
-
this.setCodeDslByIdSync(id, fallbackToFullReplace ? cloneDeep$1(
|
|
16751
|
+
this.setCodeDslByIdSync(id, fallbackToFullReplace ? cloneDeep$1(oldSchema) : patched, true, {
|
|
15815
16752
|
changeRecords,
|
|
15816
16753
|
historyDescription,
|
|
15817
16754
|
historySource: "rollback"
|
|
15818
16755
|
});
|
|
15819
16756
|
return history_default.getCodeBlockStepList(id).slice(-1)[0]?.step ?? null;
|
|
15820
16757
|
}
|
|
15821
|
-
this.setCodeDslByIdSync(id, cloneDeep$1(
|
|
16758
|
+
this.setCodeDslByIdSync(id, cloneDeep$1(oldSchema), true, {
|
|
15822
16759
|
historyDescription,
|
|
15823
16760
|
historySource: "rollback"
|
|
15824
16761
|
});
|
|
@@ -15839,19 +16776,20 @@
|
|
|
15839
16776
|
* @param reverse true=撤销,false=重做
|
|
15840
16777
|
*/
|
|
15841
16778
|
async applyHistoryStep(step, reverse) {
|
|
15842
|
-
const { id
|
|
15843
|
-
|
|
16779
|
+
const { id } = step;
|
|
16780
|
+
const { oldSchema, newSchema, changeRecords } = step.diff?.[0] ?? {};
|
|
16781
|
+
if (!oldSchema && newSchema) {
|
|
15844
16782
|
if (reverse) await this.deleteCodeDslByIds([id], { doNotPushHistory: true });
|
|
15845
|
-
else this.setCodeDslByIdSync(id, cloneDeep$1(
|
|
16783
|
+
else this.setCodeDslByIdSync(id, cloneDeep$1(newSchema), true, { doNotPushHistory: true });
|
|
15846
16784
|
return;
|
|
15847
16785
|
}
|
|
15848
|
-
if (
|
|
15849
|
-
if (reverse) this.setCodeDslByIdSync(id, cloneDeep$1(
|
|
16786
|
+
if (oldSchema && !newSchema) {
|
|
16787
|
+
if (reverse) this.setCodeDslByIdSync(id, cloneDeep$1(oldSchema), true, { doNotPushHistory: true });
|
|
15850
16788
|
else await this.deleteCodeDslByIds([id], { doNotPushHistory: true });
|
|
15851
16789
|
return;
|
|
15852
16790
|
}
|
|
15853
|
-
if (!
|
|
15854
|
-
const sourceForValues = reverse ?
|
|
16791
|
+
if (!oldSchema || !newSchema) return;
|
|
16792
|
+
const sourceForValues = reverse ? oldSchema : newSchema;
|
|
15855
16793
|
if (changeRecords?.length) {
|
|
15856
16794
|
const current = this.getCodeContentById(id);
|
|
15857
16795
|
if (!current) return;
|
|
@@ -15920,18 +16858,6 @@
|
|
|
15920
16858
|
"createId"
|
|
15921
16859
|
]
|
|
15922
16860
|
};
|
|
15923
|
-
/**
|
|
15924
|
-
* 「回滚」生成的新 step 简短描述。
|
|
15925
|
-
* 仅在 service 层使用,避免依赖 UI 层 composables。
|
|
15926
|
-
*/
|
|
15927
|
-
var describeRevertDataSourceStep = (step) => {
|
|
15928
|
-
const { oldSchema, newSchema, changeRecords, id } = step;
|
|
15929
|
-
if (oldSchema === null && newSchema) return `撤回新增 ${newSchema.title || newSchema.id || id}`;
|
|
15930
|
-
if (oldSchema && newSchema === null) return `还原已删除的 ${oldSchema.title || oldSchema.id || id}`;
|
|
15931
|
-
const title = newSchema?.title || oldSchema?.title || `${id}`;
|
|
15932
|
-
const propPath = changeRecords?.[0]?.propPath;
|
|
15933
|
-
return propPath ? `还原 ${title} · ${propPath}` : `还原 ${title}`;
|
|
15934
|
-
};
|
|
15935
16861
|
var DataSource = class extends BaseService {
|
|
15936
16862
|
state = (0, vue.reactive)({
|
|
15937
16863
|
datasourceTypeList: [],
|
|
@@ -15942,6 +16868,12 @@
|
|
|
15942
16868
|
events: {},
|
|
15943
16869
|
methods: {}
|
|
15944
16870
|
});
|
|
16871
|
+
/**
|
|
16872
|
+
* 最近一次写入历史栈的数据源历史记录 uuid。
|
|
16873
|
+
* 供 *AndGetHistoryId 系列方法在调用 add / update / remove 后取回本次产生的历史记录 id;
|
|
16874
|
+
* 普通方法不读取它,调用前由 *AndGetHistoryId 重置为 null。
|
|
16875
|
+
*/
|
|
16876
|
+
lastPushedHistoryId = null;
|
|
15945
16877
|
constructor() {
|
|
15946
16878
|
super(canUsePluginMethods$3.sync.map((methodName) => ({
|
|
15947
16879
|
name: methodName,
|
|
@@ -15991,12 +16923,12 @@
|
|
|
15991
16923
|
id: config.id && !this.getDataSourceById(config.id) ? config.id : this.createId()
|
|
15992
16924
|
};
|
|
15993
16925
|
this.get("dataSources").push(newConfig);
|
|
15994
|
-
if (!doNotPushHistory) history_default.pushDataSource(newConfig.id, {
|
|
16926
|
+
if (!doNotPushHistory) this.lastPushedHistoryId = history_default.pushDataSource(newConfig.id, {
|
|
15995
16927
|
oldSchema: null,
|
|
15996
16928
|
newSchema: newConfig,
|
|
15997
16929
|
historyDescription,
|
|
15998
16930
|
source: historySource
|
|
15999
|
-
});
|
|
16931
|
+
})?.uuid ?? null;
|
|
16000
16932
|
this.emit("add", newConfig);
|
|
16001
16933
|
return newConfig;
|
|
16002
16934
|
}
|
|
@@ -16014,13 +16946,13 @@
|
|
|
16014
16946
|
const oldConfig = dataSources[index];
|
|
16015
16947
|
const newConfig = cloneDeep$1(config);
|
|
16016
16948
|
dataSources[index] = newConfig;
|
|
16017
|
-
if (!doNotPushHistory) history_default.pushDataSource(newConfig.id, {
|
|
16949
|
+
if (!doNotPushHistory) this.lastPushedHistoryId = history_default.pushDataSource(newConfig.id, {
|
|
16018
16950
|
oldSchema: oldConfig ? cloneDeep$1(oldConfig) : null,
|
|
16019
16951
|
newSchema: newConfig,
|
|
16020
16952
|
changeRecords,
|
|
16021
16953
|
historyDescription,
|
|
16022
16954
|
source: historySource
|
|
16023
|
-
});
|
|
16955
|
+
})?.uuid ?? null;
|
|
16024
16956
|
this.emit("update", newConfig, {
|
|
16025
16957
|
oldConfig,
|
|
16026
16958
|
changeRecords
|
|
@@ -16039,15 +16971,47 @@
|
|
|
16039
16971
|
const index = dataSources.findIndex((ds) => ds.id === id);
|
|
16040
16972
|
const oldConfig = index !== -1 ? dataSources[index] : null;
|
|
16041
16973
|
dataSources.splice(index, 1);
|
|
16042
|
-
if (oldConfig && !doNotPushHistory) history_default.pushDataSource(id, {
|
|
16974
|
+
if (oldConfig && !doNotPushHistory) this.lastPushedHistoryId = history_default.pushDataSource(id, {
|
|
16043
16975
|
oldSchema: cloneDeep$1(oldConfig),
|
|
16044
16976
|
newSchema: null,
|
|
16045
16977
|
historyDescription,
|
|
16046
16978
|
source: historySource
|
|
16047
|
-
});
|
|
16979
|
+
})?.uuid ?? null;
|
|
16048
16980
|
this.emit("remove", id);
|
|
16049
16981
|
}
|
|
16050
16982
|
/**
|
|
16983
|
+
* 下列 *AndGetHistoryId 方法与对应的 add / update / remove 行为完全一致,
|
|
16984
|
+
* 返回值在 {@link DslOpWithHistoryIdsResult} 中同时包含原操作结果与本次写入历史栈的 uuid 列表({@link DataSourceStepValue.uuid}),
|
|
16985
|
+
* 可用于精确引用 / 定位该条历史记录(埋点、revert、跨端同步等)。
|
|
16986
|
+
*
|
|
16987
|
+
* 当本次操作未写入历史(doNotPushHistory 为 true、或无对应记录)时 historyIds 为 `[]`。
|
|
16988
|
+
*/
|
|
16989
|
+
/** 等价于 {@link add},并额外返回本次写入历史记录的 uuid 列表(未入栈时 historyIds 为 `[]`)。 */
|
|
16990
|
+
addAndGetHistoryId(config, options = {}) {
|
|
16991
|
+
this.lastPushedHistoryId = null;
|
|
16992
|
+
return {
|
|
16993
|
+
result: this.add(config, options),
|
|
16994
|
+
historyIds: getLastPushedHistoryIds(this.lastPushedHistoryId)
|
|
16995
|
+
};
|
|
16996
|
+
}
|
|
16997
|
+
/** 等价于 {@link update},并额外返回本次写入历史记录的 uuid 列表(未入栈时 historyIds 为 `[]`)。 */
|
|
16998
|
+
updateAndGetHistoryId(config, options = {}) {
|
|
16999
|
+
this.lastPushedHistoryId = null;
|
|
17000
|
+
return {
|
|
17001
|
+
result: this.update(config, options),
|
|
17002
|
+
historyIds: getLastPushedHistoryIds(this.lastPushedHistoryId)
|
|
17003
|
+
};
|
|
17004
|
+
}
|
|
17005
|
+
/** 等价于 {@link remove},并额外返回本次写入历史记录的 uuid 列表(未入栈时 historyIds 为 `[]`)。 */
|
|
17006
|
+
removeAndGetHistoryId(id, options = {}) {
|
|
17007
|
+
this.lastPushedHistoryId = null;
|
|
17008
|
+
this.remove(id, options);
|
|
17009
|
+
return {
|
|
17010
|
+
result: void 0,
|
|
17011
|
+
historyIds: getLastPushedHistoryIds(this.lastPushedHistoryId)
|
|
17012
|
+
};
|
|
17013
|
+
}
|
|
17014
|
+
/**
|
|
16051
17015
|
* 撤销指定数据源的最近一次变更。
|
|
16052
17016
|
*
|
|
16053
17017
|
* 内部走 add / update / remove,因此会自动触发 dataSourceService 的事件,
|
|
@@ -16115,10 +17079,25 @@
|
|
|
16115
17079
|
revert(id, index) {
|
|
16116
17080
|
const entry = history_default.getDataSourceStepList(id)[index];
|
|
16117
17081
|
if (!entry?.applied) return null;
|
|
16118
|
-
|
|
16119
|
-
|
|
17082
|
+
const { oldSchema, newSchema, changeRecords } = entry.step.diff?.[0] ?? {};
|
|
17083
|
+
if (oldSchema && newSchema && !changeRecords?.length) return null;
|
|
17084
|
+
const description = `回滚 #${index + 1}: ${describeRevertStep(entry.step.id, entry.step.diff?.[0], (s) => s.title)}`;
|
|
16120
17085
|
return this.applyRevertStep(entry.step, description);
|
|
16121
17086
|
}
|
|
17087
|
+
/**
|
|
17088
|
+
* 通过历史记录 uuid 回滚数据源历史步骤,语义同 {@link revert},
|
|
17089
|
+
* 仅无需调用方再传 dataSourceId 与 index:内部会按 uuid 在全部数据源栈中定位对应步骤后再回滚。
|
|
17090
|
+
* 按数组顺序依次回滚,返回与入参同序的结果列表(某项失败时为 `null`)。
|
|
17091
|
+
*
|
|
17092
|
+
* @param uuids 目标历史记录的 uuid 列表,通常由 {@link addAndGetHistoryId} 等方法返回的 `historyIds`
|
|
17093
|
+
*/
|
|
17094
|
+
revertById(uuids) {
|
|
17095
|
+
return uuids.map((uuid) => {
|
|
17096
|
+
const location = history_default.findDataSourceStepLocationByUuid(uuid);
|
|
17097
|
+
if (!location) return null;
|
|
17098
|
+
return this.revert(location.id, location.index);
|
|
17099
|
+
});
|
|
17100
|
+
}
|
|
16122
17101
|
createId() {
|
|
16123
17102
|
return `ds_${(0, _tmagic_utils.guid)()}`;
|
|
16124
17103
|
}
|
|
@@ -16177,15 +17156,16 @@
|
|
|
16177
17156
|
* 同构,差异仅在于走对应的公共 add / update / remove 而不是带 doNotPushHistory 的版本。
|
|
16178
17157
|
*/
|
|
16179
17158
|
applyRevertStep(step, historyDescription) {
|
|
16180
|
-
const { id
|
|
16181
|
-
|
|
17159
|
+
const { id } = step;
|
|
17160
|
+
const { oldSchema, newSchema, changeRecords } = step.diff?.[0] ?? {};
|
|
17161
|
+
if (!oldSchema && newSchema) {
|
|
16182
17162
|
this.remove(`${id}`, {
|
|
16183
17163
|
historyDescription,
|
|
16184
17164
|
historySource: "rollback"
|
|
16185
17165
|
});
|
|
16186
17166
|
return history_default.getDataSourceStepList(id).slice(-1)[0]?.step ?? null;
|
|
16187
17167
|
}
|
|
16188
|
-
if (oldSchema && newSchema
|
|
17168
|
+
if (oldSchema && !newSchema) {
|
|
16189
17169
|
this.add(cloneDeep$1(oldSchema), {
|
|
16190
17170
|
historyDescription,
|
|
16191
17171
|
historySource: "rollback"
|
|
@@ -16234,13 +17214,14 @@
|
|
|
16234
17214
|
* @param reverse true=撤销,false=重做
|
|
16235
17215
|
*/
|
|
16236
17216
|
applyHistoryStep(step, reverse) {
|
|
16237
|
-
const { id
|
|
16238
|
-
|
|
17217
|
+
const { id } = step;
|
|
17218
|
+
const { oldSchema, newSchema, changeRecords } = step.diff?.[0] ?? {};
|
|
17219
|
+
if (!oldSchema && newSchema) {
|
|
16239
17220
|
if (reverse) this.remove(`${id}`, { doNotPushHistory: true });
|
|
16240
17221
|
else this.add(cloneDeep$1(newSchema), { doNotPushHistory: true });
|
|
16241
17222
|
return;
|
|
16242
17223
|
}
|
|
16243
|
-
if (oldSchema && newSchema
|
|
17224
|
+
if (oldSchema && !newSchema) {
|
|
16244
17225
|
if (reverse) this.add(cloneDeep$1(oldSchema), { doNotPushHistory: true });
|
|
16245
17226
|
else this.remove(`${id}`, { doNotPushHistory: true });
|
|
16246
17227
|
return;
|
|
@@ -16891,7 +17872,7 @@
|
|
|
16891
17872
|
//#region packages/editor/src/initService.ts
|
|
16892
17873
|
var initServiceState = (props, { editorService, historyService, componentListService, propsService, eventsService, uiService, codeBlockService, keybindingService, dataSourceService, depService }) => {
|
|
16893
17874
|
(0, vue.watch)(() => props.modelValue, (modelValue) => {
|
|
16894
|
-
editorService.set("root", modelValue || null);
|
|
17875
|
+
editorService.set("root", modelValue || null, { historySource: "initial" });
|
|
16895
17876
|
}, { immediate: true });
|
|
16896
17877
|
(0, vue.watch)(() => props.disabledMultiSelect, (disabledMultiSelect) => {
|
|
16897
17878
|
editorService.set("disabledMultiSelect", disabledMultiSelect || false);
|
|
@@ -17755,7 +18736,8 @@
|
|
|
17755
18736
|
*/
|
|
17756
18737
|
const isCompareMode = (0, vue.computed)(() => Boolean(props.isCompare && props.lastValues));
|
|
17757
18738
|
const notEditable = (0, vue.computed)(() => (0, _tmagic_form.filterFunction)(mForm, props.config.notEditable, props));
|
|
17758
|
-
const
|
|
18739
|
+
const codeBlockSidePanel = (0, vue.computed)(() => (uiService.get("sideBarItems") || []).find((item) => item.$key === SideItemKey.CODE_BLOCK));
|
|
18740
|
+
const hasCodeBlockSidePanel = (0, vue.computed)(() => codeBlockSidePanel.value);
|
|
17759
18741
|
/**
|
|
17760
18742
|
* 根据代码块id获取代码块参数配置
|
|
17761
18743
|
* @param codeId 代码块ID
|
|
@@ -17810,6 +18792,8 @@
|
|
|
17810
18792
|
emit("change", props.model[props.name], eventData);
|
|
17811
18793
|
};
|
|
17812
18794
|
const editCode = (id) => {
|
|
18795
|
+
const sideBarItem = codeBlockSidePanel.value;
|
|
18796
|
+
if (sideBarItem) uiService.set("sideBarActiveTabName", sideBarItem.text || sideBarItem.$key || SideItemKey.CODE_BLOCK);
|
|
17813
18797
|
eventBus?.emit("edit-code", id);
|
|
17814
18798
|
};
|
|
17815
18799
|
return (_ctx, _cache) => {
|
|
@@ -17942,6 +18926,15 @@
|
|
|
17942
18926
|
calcBoxPosition();
|
|
17943
18927
|
addDialogVisible.value = true;
|
|
17944
18928
|
};
|
|
18929
|
+
const editField = (row, index) => {
|
|
18930
|
+
fieldValues.value = {
|
|
18931
|
+
...row,
|
|
18932
|
+
index
|
|
18933
|
+
};
|
|
18934
|
+
fieldTitle.value = `编辑${row.title}`;
|
|
18935
|
+
calcBoxPosition();
|
|
18936
|
+
addDialogVisible.value = true;
|
|
18937
|
+
};
|
|
17945
18938
|
const fieldChange = ({ index, ...value }, data) => {
|
|
17946
18939
|
addDialogVisible.value = false;
|
|
17947
18940
|
if (index > -1) emit("change", value, {
|
|
@@ -17993,13 +18986,7 @@
|
|
|
17993
18986
|
actions: [{
|
|
17994
18987
|
text: "编辑",
|
|
17995
18988
|
handler: (row, index) => {
|
|
17996
|
-
|
|
17997
|
-
...row,
|
|
17998
|
-
index
|
|
17999
|
-
};
|
|
18000
|
-
fieldTitle.value = `编辑${row.title}`;
|
|
18001
|
-
calcBoxPosition();
|
|
18002
|
-
addDialogVisible.value = true;
|
|
18989
|
+
editField(row, index);
|
|
18003
18990
|
}
|
|
18004
18991
|
}, {
|
|
18005
18992
|
text: "删除",
|
|
@@ -18186,6 +19173,20 @@
|
|
|
18186
19173
|
const addFromJsonDialogVisible = (0, vue.useModel)(__props, "visible1");
|
|
18187
19174
|
const { height: editorHeight } = useEditorContentHeight();
|
|
18188
19175
|
const { boxPosition, calcBoxPosition } = useNextFloatBoxPosition(uiService, (0, vue.inject)("parentFloating", (0, vue.ref)(null)));
|
|
19176
|
+
/**
|
|
19177
|
+
* 由 DataSourceConfigPanel 注入:打开数据源详情后需要直接打开的字段路径(字段名数组)。
|
|
19178
|
+
* 当前层消费 path[0],并把剩余路径下发给嵌套字段,实现逐层打开。
|
|
19179
|
+
*/
|
|
19180
|
+
const editingFieldPath = (0, vue.inject)("editingDataSourceFieldPath", (0, vue.computed)(() => []));
|
|
19181
|
+
(0, vue.provide)("editingDataSourceFieldPath", (0, vue.computed)(() => editingFieldPath.value.slice(1)));
|
|
19182
|
+
(0, vue.onMounted)(() => {
|
|
19183
|
+
const path = editingFieldPath.value;
|
|
19184
|
+
if (!path.length) return;
|
|
19185
|
+
const fields = props.model[props.name] || [];
|
|
19186
|
+
const index = fields.findIndex((field) => field.name === path[0]);
|
|
19187
|
+
if (index === -1) return;
|
|
19188
|
+
editField(fields[index], index);
|
|
19189
|
+
});
|
|
18189
19190
|
return (_ctx, _cache) => {
|
|
18190
19191
|
return (0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_1$36, [
|
|
18191
19192
|
(0, vue.createVNode)((0, vue.unref)(_tmagic_table.MagicTable), {
|
|
@@ -18567,6 +19568,19 @@
|
|
|
18567
19568
|
const codeConfig = (0, vue.ref)();
|
|
18568
19569
|
const codeBlockEditorRef = (0, vue.useTemplateRef)("codeBlockEditor");
|
|
18569
19570
|
let editIndex = -1;
|
|
19571
|
+
const editMethod = (method, index) => {
|
|
19572
|
+
let codeContent = "({ params, dataSource, app }) => {\n // place your code here\n}";
|
|
19573
|
+
if (method.content) if (typeof method.content !== "string") codeContent = method.content.toString();
|
|
19574
|
+
else codeContent = method.content;
|
|
19575
|
+
codeConfig.value = {
|
|
19576
|
+
...cloneDeep$1(method),
|
|
19577
|
+
content: codeContent
|
|
19578
|
+
};
|
|
19579
|
+
editIndex = index;
|
|
19580
|
+
(0, vue.nextTick)(() => {
|
|
19581
|
+
codeBlockEditorRef.value?.show();
|
|
19582
|
+
});
|
|
19583
|
+
};
|
|
18570
19584
|
const methodColumns = [
|
|
18571
19585
|
{
|
|
18572
19586
|
label: "名称",
|
|
@@ -18591,17 +19605,7 @@
|
|
|
18591
19605
|
actions: [{
|
|
18592
19606
|
text: "编辑",
|
|
18593
19607
|
handler: (method, index) => {
|
|
18594
|
-
|
|
18595
|
-
if (method.content) if (typeof method.content !== "string") codeContent = method.content.toString();
|
|
18596
|
-
else codeContent = method.content;
|
|
18597
|
-
codeConfig.value = {
|
|
18598
|
-
...cloneDeep$1(method),
|
|
18599
|
-
content: codeContent
|
|
18600
|
-
};
|
|
18601
|
-
editIndex = index;
|
|
18602
|
-
(0, vue.nextTick)(() => {
|
|
18603
|
-
codeBlockEditorRef.value?.show();
|
|
18604
|
-
});
|
|
19608
|
+
editMethod(method, index);
|
|
18605
19609
|
}
|
|
18606
19610
|
}, {
|
|
18607
19611
|
text: "删除",
|
|
@@ -18649,6 +19653,16 @@
|
|
|
18649
19653
|
codeConfig.value = void 0;
|
|
18650
19654
|
codeBlockEditorRef.value?.hide();
|
|
18651
19655
|
};
|
|
19656
|
+
/** 由 DataSourceConfigPanel 注入:打开数据源详情后需要直接打开的方法名 */
|
|
19657
|
+
const editingMethodName = (0, vue.inject)("editingDataSourceMethodName", (0, vue.computed)(() => ""));
|
|
19658
|
+
(0, vue.onMounted)(() => {
|
|
19659
|
+
const methodName = editingMethodName.value;
|
|
19660
|
+
if (!methodName) return;
|
|
19661
|
+
const methods = props.model[props.name] || [];
|
|
19662
|
+
const index = methods.findIndex((method) => method.name === methodName);
|
|
19663
|
+
if (index === -1) return;
|
|
19664
|
+
editMethod(methods[index], index);
|
|
19665
|
+
});
|
|
18652
19666
|
return (_ctx, _cache) => {
|
|
18653
19667
|
return (0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_1$34, [
|
|
18654
19668
|
(0, vue.createVNode)((0, vue.unref)(_tmagic_table.MagicTable), {
|
|
@@ -19076,7 +20090,7 @@
|
|
|
19076
20090
|
const eventBus = (0, vue.inject)("eventBus");
|
|
19077
20091
|
const emit = __emit;
|
|
19078
20092
|
const props = __props;
|
|
19079
|
-
const
|
|
20093
|
+
const dataSourceSidePanel = (0, vue.computed)(() => (uiService.get("sideBarItems") || []).find((item) => item.$key === SideItemKey.DATA_SOURCE));
|
|
19080
20094
|
const notEditable = (0, vue.computed)(() => (0, _tmagic_form.filterFunction)(mForm, props.config.notEditable, props));
|
|
19081
20095
|
/** 对比模式下隐藏查看/编辑操作按钮,仅保留只读展示。 */
|
|
19082
20096
|
const isCompare = (0, vue.computed)(() => Boolean(mForm?.isCompare));
|
|
@@ -19164,9 +20178,11 @@
|
|
|
19164
20178
|
emit("change", props.model[props.name], eventData);
|
|
19165
20179
|
};
|
|
19166
20180
|
const editCodeHandler = () => {
|
|
19167
|
-
const [id] = props.model[props.name];
|
|
20181
|
+
const [id, methodName] = props.model[props.name];
|
|
19168
20182
|
if (!dataSourceService.getDataSourceById(id)) return;
|
|
19169
|
-
|
|
20183
|
+
const sideBarItem = dataSourceSidePanel.value;
|
|
20184
|
+
if (sideBarItem) uiService.set("sideBarActiveTabName", sideBarItem.text || sideBarItem.$key || SideItemKey.DATA_SOURCE);
|
|
20185
|
+
eventBus?.emit("edit-data-source-method", id, methodName);
|
|
19170
20186
|
};
|
|
19171
20187
|
return (_ctx, _cache) => {
|
|
19172
20188
|
return (0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_1$31, [(0, vue.createElementVNode)("div", _hoisted_2$6, [(0, vue.createVNode)((0, vue.unref)(_tmagic_form.MCascader), {
|
|
@@ -19185,7 +20201,7 @@
|
|
|
19185
20201
|
"size",
|
|
19186
20202
|
"disabled",
|
|
19187
20203
|
"prop"
|
|
19188
|
-
]), __props.model[__props.name] && isCustomMethod.value &&
|
|
20204
|
+
]), __props.model[__props.name] && isCustomMethod.value && dataSourceSidePanel.value && !isCompare.value ? ((0, vue.openBlock)(), (0, vue.createBlock)((0, vue.unref)(_tmagic_design.TMagicTooltip), {
|
|
19189
20205
|
key: 0,
|
|
19190
20206
|
content: notEditable.value ? "查看" : "编辑"
|
|
19191
20207
|
}, {
|
|
@@ -19301,9 +20317,15 @@
|
|
|
19301
20317
|
modelValue.value = v;
|
|
19302
20318
|
emit("change", v);
|
|
19303
20319
|
};
|
|
19304
|
-
const
|
|
20320
|
+
const dataSourceSidePanel = (0, vue.computed)(() => uiService.get("sideBarItems").find((item) => item.$key === SideItemKey.DATA_SOURCE));
|
|
20321
|
+
const hasDataSourceSidePanel = (0, vue.computed)(() => dataSourceSidePanel.value);
|
|
19305
20322
|
const editHandler = (id) => {
|
|
19306
|
-
|
|
20323
|
+
const sideBarItem = dataSourceSidePanel.value;
|
|
20324
|
+
if (sideBarItem) uiService.set("sideBarActiveTabName", sideBarItem.text || sideBarItem.$key || SideItemKey.DATA_SOURCE);
|
|
20325
|
+
const dataSourceId = (0, _tmagic_utils.removeDataSourceFieldPrefix)(id);
|
|
20326
|
+
const fieldPath = selectFieldsId.value;
|
|
20327
|
+
if (fieldPath.length) eventBus?.emit("edit-data-source-field", dataSourceId, [...fieldPath]);
|
|
20328
|
+
else eventBus?.emit("edit-data-source", dataSourceId);
|
|
19307
20329
|
};
|
|
19308
20330
|
return (_ctx, _cache) => {
|
|
19309
20331
|
return (0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_1$30, [__props.dataSourceId ? ((0, vue.openBlock)(), (0, vue.createBlock)((0, vue.unref)(_tmagic_design.TMagicCascader), {
|
|
@@ -21522,6 +22544,13 @@
|
|
|
21522
22544
|
] }));
|
|
21523
22545
|
const selectDirection = (d) => direction.value = d || "";
|
|
21524
22546
|
const emit = __emit;
|
|
22547
|
+
const props = __props;
|
|
22548
|
+
const hasValue = (value) => value !== void 0 && value !== null && value !== "";
|
|
22549
|
+
const isConfigured = (d) => [
|
|
22550
|
+
"Width",
|
|
22551
|
+
"Color",
|
|
22552
|
+
"Style"
|
|
22553
|
+
].some((key) => hasValue(props.model?.[`border${d}${key}`]));
|
|
21525
22554
|
const change = (value, eventData) => {
|
|
21526
22555
|
eventData.changeRecords?.forEach((record) => {
|
|
21527
22556
|
emit("change", record.value, { modifyKey: record.propPath });
|
|
@@ -21531,25 +22560,40 @@
|
|
|
21531
22560
|
return (_ctx, _cache) => {
|
|
21532
22561
|
return (0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_1$1, [(0, vue.createElementVNode)("div", _hoisted_2, [
|
|
21533
22562
|
(0, vue.createElementVNode)("div", _hoisted_3, [(0, vue.createElementVNode)("div", {
|
|
21534
|
-
class: (0, vue.normalizeClass)(["border-icon border-icon-top", {
|
|
22563
|
+
class: (0, vue.normalizeClass)(["border-icon border-icon-top", {
|
|
22564
|
+
active: direction.value === "Top",
|
|
22565
|
+
configured: isConfigured("Top")
|
|
22566
|
+
}]),
|
|
21535
22567
|
onClick: _cache[0] || (_cache[0] = ($event) => selectDirection("Top"))
|
|
21536
22568
|
}, null, 2)]),
|
|
21537
22569
|
(0, vue.createElementVNode)("div", _hoisted_4, [
|
|
21538
22570
|
(0, vue.createElementVNode)("div", {
|
|
21539
|
-
class: (0, vue.normalizeClass)(["border-icon border-icon-left", {
|
|
22571
|
+
class: (0, vue.normalizeClass)(["border-icon border-icon-left", {
|
|
22572
|
+
active: direction.value === "Left",
|
|
22573
|
+
configured: isConfigured("Left")
|
|
22574
|
+
}]),
|
|
21540
22575
|
onClick: _cache[1] || (_cache[1] = ($event) => selectDirection("Left"))
|
|
21541
22576
|
}, null, 2),
|
|
21542
22577
|
(0, vue.createElementVNode)("div", {
|
|
21543
|
-
class: (0, vue.normalizeClass)(["border-icon", {
|
|
22578
|
+
class: (0, vue.normalizeClass)(["border-icon", {
|
|
22579
|
+
active: direction.value === "",
|
|
22580
|
+
configured: isConfigured("")
|
|
22581
|
+
}]),
|
|
21544
22582
|
onClick: _cache[2] || (_cache[2] = ($event) => selectDirection())
|
|
21545
22583
|
}, null, 2),
|
|
21546
22584
|
(0, vue.createElementVNode)("div", {
|
|
21547
|
-
class: (0, vue.normalizeClass)(["border-icon border-icon-right", {
|
|
22585
|
+
class: (0, vue.normalizeClass)(["border-icon border-icon-right", {
|
|
22586
|
+
active: direction.value === "Right",
|
|
22587
|
+
configured: isConfigured("Right")
|
|
22588
|
+
}]),
|
|
21548
22589
|
onClick: _cache[3] || (_cache[3] = ($event) => selectDirection("Right"))
|
|
21549
22590
|
}, null, 2)
|
|
21550
22591
|
]),
|
|
21551
22592
|
(0, vue.createElementVNode)("div", _hoisted_5, [(0, vue.createElementVNode)("div", {
|
|
21552
|
-
class: (0, vue.normalizeClass)(["border-icon border-icon-bottom", {
|
|
22593
|
+
class: (0, vue.normalizeClass)(["border-icon border-icon-bottom", {
|
|
22594
|
+
active: direction.value === "Bottom",
|
|
22595
|
+
configured: isConfigured("Bottom")
|
|
22596
|
+
}]),
|
|
21553
22597
|
onClick: _cache[4] || (_cache[4] = ($event) => selectDirection("Bottom"))
|
|
21554
22598
|
}, null, 2)])
|
|
21555
22599
|
]), (0, vue.createElementVNode)("div", _hoisted_6, [(0, vue.createVNode)((0, vue.unref)(_tmagic_form.MContainer), {
|
|
@@ -22166,6 +23210,7 @@
|
|
|
22166
23210
|
exports.H_GUIDE_LINE_STORAGE_KEY = H_GUIDE_LINE_STORAGE_KEY;
|
|
22167
23211
|
exports.HistoryDiffDialog = HistoryDiffDialog_default;
|
|
22168
23212
|
exports.HistoryListBucket = Bucket_default;
|
|
23213
|
+
exports.HistoryListBucketTab = BucketTab_default;
|
|
22169
23214
|
exports.Icon = Icon_default;
|
|
22170
23215
|
exports.IdleTask = IdleTask;
|
|
22171
23216
|
exports.KeyBindingCommand = KeyBindingCommand;
|
|
@@ -22215,17 +23260,24 @@
|
|
|
22215
23260
|
exports.classifyDragSources = classifyDragSources;
|
|
22216
23261
|
exports.codeBlockService = codeBlock_default;
|
|
22217
23262
|
exports.collectRelatedNodes = collectRelatedNodes;
|
|
23263
|
+
exports.createStackStep = createStackStep;
|
|
22218
23264
|
exports.dataSourceService = dataSource_default;
|
|
22219
23265
|
exports.debug = debug;
|
|
22220
23266
|
exports.default = plugin_default;
|
|
22221
23267
|
exports.defaultIsExpandable = defaultIsExpandable;
|
|
22222
23268
|
exports.depService = dep_default;
|
|
23269
|
+
exports.describeRevertStep = describeRevertStep;
|
|
23270
|
+
exports.describeStepForRevert = describeStepForRevert;
|
|
23271
|
+
exports.deserializeStacks = deserializeStacks;
|
|
22223
23272
|
Object.defineProperty(exports, "designPlugin", {
|
|
22224
23273
|
enumerable: true,
|
|
22225
23274
|
get: function() {
|
|
22226
23275
|
return _tmagic_design.default;
|
|
22227
23276
|
}
|
|
22228
23277
|
});
|
|
23278
|
+
exports.detectPageTargetId = detectPageTargetId;
|
|
23279
|
+
exports.detectPageTargetName = detectPageTargetName;
|
|
23280
|
+
exports.detectStackOpType = detectStackOpType;
|
|
22229
23281
|
exports.displayTabConfig = displayTabConfig;
|
|
22230
23282
|
exports.editorNodeMergeCustomizer = editorNodeMergeCustomizer;
|
|
22231
23283
|
exports.editorService = editor_default;
|
|
@@ -22255,22 +23307,33 @@
|
|
|
22255
23307
|
exports.getFormValue = getFormValue;
|
|
22256
23308
|
exports.getGuideLineFromCache = getGuideLineFromCache;
|
|
22257
23309
|
exports.getInitPositionStyle = getInitPositionStyle;
|
|
23310
|
+
exports.getLastPushedHistoryIds = getLastPushedHistoryIds;
|
|
22258
23311
|
exports.getNodeIndex = getNodeIndex;
|
|
23312
|
+
exports.getOrCreateStack = getOrCreateStack;
|
|
22259
23313
|
exports.getPageFragmentList = getPageFragmentList;
|
|
22260
23314
|
exports.getPageList = getPageList;
|
|
22261
23315
|
exports.getPageNameList = getPageNameList;
|
|
22262
23316
|
exports.getPositionInContainer = getPositionInContainer;
|
|
22263
23317
|
exports.getRelativeStyle = getRelativeStyle;
|
|
22264
23318
|
exports.historyService = history_default;
|
|
23319
|
+
exports.idbDelete = idbDelete;
|
|
23320
|
+
exports.idbGet = idbGet;
|
|
23321
|
+
exports.idbSet = idbSet;
|
|
22265
23322
|
exports.info = info;
|
|
22266
23323
|
exports.isIncludeDataSource = isIncludeDataSource;
|
|
23324
|
+
exports.isIndexedDBSupported = isIndexedDBSupported;
|
|
22267
23325
|
exports.loadMonaco = monaco_editor_default;
|
|
22268
23326
|
exports.log = log;
|
|
23327
|
+
exports.markStackSaved = markStackSaved;
|
|
23328
|
+
exports.mergePageSteps = mergePageSteps;
|
|
23329
|
+
exports.mergeStackSteps = mergeStackSteps;
|
|
22269
23330
|
exports.moveItemsInContainer = moveItemsInContainer;
|
|
22270
23331
|
exports.numberOptions = numberOptions;
|
|
23332
|
+
exports.openIndexedDB = openIndexedDB;
|
|
22271
23333
|
exports.propsService = props_default;
|
|
22272
23334
|
exports.resolveSelectedNode = resolveSelectedNode;
|
|
22273
23335
|
exports.serializeConfig = serializeConfig;
|
|
23336
|
+
exports.serializeStacks = serializeStacks;
|
|
22274
23337
|
exports.setChildrenLayout = setChildrenLayout;
|
|
22275
23338
|
exports.setEditorConfig = setEditorConfig;
|
|
22276
23339
|
exports.setLayout = setLayout;
|
|
@@ -22285,6 +23348,7 @@
|
|
|
22285
23348
|
});
|
|
22286
23349
|
exports.toggleFixedPosition = toggleFixedPosition;
|
|
22287
23350
|
exports.uiService = ui_default;
|
|
23351
|
+
exports.undoFloor = undoFloor;
|
|
22288
23352
|
exports.updateStatus = updateStatus;
|
|
22289
23353
|
exports.useCodeBlockEdit = useCodeBlockEdit;
|
|
22290
23354
|
exports.useEditorContentHeight = useEditorContentHeight;
|