@tmagic/editor 1.8.0-manmanyu.11 → 1.8.0-manmanyu.12

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.
@@ -1,4 +1,3 @@
1
- import { useServices } from "../hooks/use-services.js";
2
1
  import { getCodeBlockFormConfig } from "../utils/code-block.js";
3
2
  import { MForm } from "@tmagic/form";
4
3
  import { HookType } from "@tmagic/core";
@@ -23,11 +22,10 @@ var CompareForm_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defi
23
22
  baseFormState: {},
24
23
  selfDiffFieldTypes: {},
25
24
  loadConfig: {},
26
- services: { default: () => useServices() }
25
+ services: {}
27
26
  },
28
27
  setup(__props, { expose: __expose }) {
29
28
  const props = __props;
30
- const { propsService, dataSourceService, codeBlockService, editorService } = props.services;
31
29
  provide("services", props.services);
32
30
  const config = ref([]);
33
31
  /** vs-code 编辑器的 monaco 配置项,沿用 Editor 顶层 provide('codeOptions', ...) 的注入。 */
@@ -107,16 +105,17 @@ var CompareForm_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defi
107
105
  * 作为 ctx.defaultLoadConfig 透传给自定义 `loadConfig`,方便复用与二次加工。
108
106
  */
109
107
  const defaultLoadConfig = async () => {
108
+ if (!props.services) return [];
110
109
  switch (props.category) {
111
110
  case "node":
112
111
  if (!props.type) return [];
113
- return removeStyleDisplayConfig(await propsService.getPropsConfig(props.type, { node: props.value }));
114
- case "data-source": return dataSourceService.getFormConfig(props.type || "base").map((item) => "type" in item && item.type === "tab" ? {
112
+ return removeStyleDisplayConfig(await props.services.propsService.getPropsConfig(props.type, { node: props.value }));
113
+ case "data-source": return props.services.dataSourceService.getFormConfig(props.type || "base").map((item) => "type" in item && item.type === "tab" ? {
115
114
  ...item,
116
115
  active: "fields"
117
116
  } : item);
118
117
  case "code-block": return getCodeBlockFormConfig({
119
- paramColConfig: codeBlockService.getParamsColConfig(),
118
+ paramColConfig: props.services.codeBlockService.getParamsColConfig(),
120
119
  isDataSource: () => Boolean(props.dataSourceType),
121
120
  dataSourceType: () => props.dataSourceType,
122
121
  codeOptions,
@@ -155,10 +154,9 @@ var CompareForm_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defi
155
154
  * - services:整个 useServices() 返回的服务集合;
156
155
  * - stage:当前 editorService.get('stage') 的最新值。
157
156
  */
158
- const stage = computed(() => editorService.get("stage"));
159
157
  watchEffect(() => {
160
- if (formRef.value) {
161
- formRef.value.formState.stage = stage.value;
158
+ if (formRef.value && props.services) {
159
+ formRef.value.formState.stage = props.services.editorService.get("stage");
162
160
  formRef.value.formState.services = props.services;
163
161
  }
164
162
  });
@@ -1,12 +1,15 @@
1
1
  import Bucket_default from "./Bucket.js";
2
2
  import { TMagicScrollbar } from "@tmagic/design";
3
- import { Fragment, createBlock, createElementBlock, createElementVNode, createVNode, defineComponent, openBlock, renderList, unref, withCtx } from "vue";
3
+ import { Fragment, createBlock, createCommentVNode, createElementBlock, createElementVNode, createVNode, defineComponent, openBlock, renderList, unref, withCtx } from "vue";
4
4
  //#region packages/editor/src/layouts/history-list/BucketTab.vue?vue&type=script&setup=true&lang.ts
5
5
  var _hoisted_1 = {
6
6
  key: 0,
7
7
  class: "m-editor-history-list-empty"
8
8
  };
9
- var _hoisted_2 = { class: "m-editor-history-list-toolbar" };
9
+ var _hoisted_2 = {
10
+ key: 0,
11
+ class: "m-editor-history-list-toolbar"
12
+ };
10
13
  var _hoisted_3 = ["title"];
11
14
  var BucketTab_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineComponent({
12
15
  name: "MEditorHistoryListBucketTab",
@@ -26,11 +29,11 @@ var BucketTab_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ define
26
29
  ],
27
30
  setup(__props) {
28
31
  return (_ctx, _cache) => {
29
- return !__props.buckets.length ? (openBlock(), createElementBlock("div", _hoisted_1, "暂无操作记录")) : (openBlock(), createElementBlock(Fragment, { key: 1 }, [createElementVNode("div", _hoisted_2, [createElementVNode("span", {
32
+ return !__props.buckets.length ? (openBlock(), createElementBlock("div", _hoisted_1, "暂无操作记录")) : (openBlock(), createElementBlock(Fragment, { key: 1 }, [__props.config.showClear !== false ? (openBlock(), createElementBlock("div", _hoisted_2, [createElementVNode("span", {
30
33
  class: "m-editor-history-list-clear",
31
34
  title: `清空${__props.config.title}的历史记录`,
32
35
  onClick: _cache[0] || (_cache[0] = ($event) => _ctx.$emit("clear"))
33
- }, "清空", 8, _hoisted_3)]), createVNode(unref(TMagicScrollbar), { "max-height": "360px" }, {
36
+ }, "清空", 8, _hoisted_3)])) : createCommentVNode("v-if", true), createVNode(unref(TMagicScrollbar), { "max-height": "360px" }, {
34
37
  default: withCtx(() => [(openBlock(true), createElementBlock(Fragment, null, renderList(__props.buckets, (bucket) => {
35
38
  return openBlock(), createBlock(Bucket_default, {
36
39
  key: `${__props.config.prefix}-${bucket.id}`,
@@ -1,4 +1,3 @@
1
- import { useServices } from "../../hooks/use-services.js";
2
1
  import CodeEditor_default from "../CodeEditor.js";
3
2
  import CompareForm_default from "../../components/CompareForm.js";
4
3
  import { TMagicButton, TMagicDialog, TMagicRadioButton, TMagicRadioGroup, TMagicTag } from "@tmagic/design";
@@ -25,7 +24,7 @@ var HistoryDiffDialog_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*
25
24
  name: "MEditorHistoryDiffDialog",
26
25
  __name: "HistoryDiffDialog",
27
26
  props: {
28
- services: { default: () => useServices() },
27
+ services: {},
29
28
  extendState: {},
30
29
  loadConfig: {},
31
30
  width: { default: "900px" },
@@ -66,6 +65,13 @@ var HistoryDiffDialog_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*
66
65
  };
67
66
  const dialogTitle = computed(() => props.onConfirm ? "确认回滚" : "查看修改差异");
68
67
  const hasCurrent = computed(() => payload.value?.currentValue !== void 0 && payload.value?.currentValue !== null);
68
+ /** 是否存在该步「修改后的值」:不存在(如仅删除)时「与修改前对比」无意义,置灰禁用。 */
69
+ const hasValue = computed(() => payload.value?.value !== void 0 && payload.value?.value !== null);
70
+ /**
71
+ * 计算 open 时的初始对比模式:
72
+ * 没有「修改后的值」但有当前值时(「与修改前对比」不可用),默认进入「与当前对比」;否则默认「与修改前对比」。
73
+ */
74
+ const resolveInitialMode = () => !hasValue.value && hasCurrent.value ? "current" : "before";
69
75
  /** 左侧(旧/参照)值 */
70
76
  const leftValue = computed(() => {
71
77
  if (!payload.value) return {};
@@ -108,7 +114,7 @@ var HistoryDiffDialog_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*
108
114
  });
109
115
  const open = (p) => {
110
116
  payload.value = p;
111
- mode.value = "before";
117
+ mode.value = resolveInitialMode();
112
118
  viewMode.value = "form";
113
119
  visible.value = true;
114
120
  };
@@ -200,10 +206,13 @@ var HistoryDiffDialog_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*
200
206
  size: "small",
201
207
  class: "m-editor-history-diff-dialog-mode"
202
208
  }, {
203
- default: withCtx(() => [createVNode(unref(TMagicRadioButton), { value: "before" }, {
209
+ default: withCtx(() => [createVNode(unref(TMagicRadioButton), {
210
+ value: "before",
211
+ disabled: !hasValue.value
212
+ }, {
204
213
  default: withCtx(() => [..._cache[7] || (_cache[7] = [createTextVNode("与修改前对比", -1)])]),
205
214
  _: 1
206
- }), createVNode(unref(TMagicRadioButton), {
215
+ }, 8, ["disabled"]), createVNode(unref(TMagicRadioButton), {
207
216
  value: "current",
208
217
  disabled: !hasCurrent.value
209
218
  }, {
@@ -150,12 +150,12 @@ var HistoryListPanel_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/
150
150
  /**
151
151
  * 「单步回滚」与「查看差异」的完整逻辑收敛到 useHistoryRevert,面板与业务方共用:
152
152
  * 二者均由 useHistoryRevert 内部按需动态挂载 HistoryDiffDialog,
153
- * 业务方亦可直接 import useHistoryRevert(services) 调用,无需自行挂载任何弹窗。
153
+ * 业务方亦可直接 import useHistoryRevert(options, services) 调用,无需自行挂载任何弹窗。
154
154
  */
155
- const { onPageRevert, onDataSourceRevert, onCodeBlockRevert, onPageDiff, onDataSourceDiff, onCodeBlockDiff } = useHistoryRevert(services, {
155
+ const { onPageRevert, onDataSourceRevert, onCodeBlockRevert, onPageDiff, onDataSourceDiff, onCodeBlockDiff } = useHistoryRevert({
156
156
  extendState: extendFormState,
157
157
  getPropsPanelFormState
158
- });
158
+ }, services);
159
159
  /**
160
160
  * 把内存中(已清空对应类别后的)历史状态重新写回 IndexedDB,
161
161
  * 使本地持久化的那份与内存保持一致——即「连同本地保存的一并删除」。
@@ -118,13 +118,12 @@ var viewHistoryDiffDialog = async (payload, options) => {
118
118
  * ```ts
119
119
  * import { useHistoryRevert } from '@tmagic/editor';
120
120
  *
121
- * const { onPageRevert, onPageDiff } = useHistoryRevert(editorRef.value); // editorRef.value 即 Editor 暴露的 services
121
+ * const { onPageRevert, onPageDiff } = useHistoryRevert({}, editorRef.value); // editorRef.value 即 Editor 暴露的 services
122
122
  * await onPageRevert(index); // 弹出差异 / 二次确认弹窗后回滚
123
123
  * onPageDiff(index); // 弹出只读差异弹窗查看前后值差异
124
124
  * ```
125
125
  */
126
- var useHistoryRevert = (services, options = {}) => {
127
- const { editorService, dataSourceService, codeBlockService, historyService } = services;
126
+ var useHistoryRevert = (options = {}, services) => {
128
127
  const appContext = options.appContext ?? getCurrentInstance()?.appContext ?? null;
129
128
  const { extendState, getPropsPanelFormState } = options;
130
129
  /** 目标数据已被删除、无法回滚时的统一提示。 */
@@ -153,22 +152,22 @@ var useHistoryRevert = (services, options = {}) => {
153
152
  };
154
153
  const buildPageDiffPayload = (index) => buildDiffPayload({
155
154
  category: "node",
156
- groups: () => historyService.getHistoryGroups("page", editorService.get("page")?.id),
157
- getCurrent: (id) => editorService.getNodeById(id),
155
+ groups: () => services?.historyService.getHistoryGroups("page", services?.editorService.get("page")?.id) ?? [],
156
+ getCurrent: (id) => services?.editorService.getNodeById(id),
158
157
  resolveType: (n, o) => n.type || o.type || "",
159
158
  resolveLabel: (n, o) => n.name || o.name || n.type || o.type || ""
160
159
  }, index);
161
160
  const buildDataSourceDiffPayload = (id, index) => buildDiffPayload({
162
161
  category: "data-source",
163
- groups: () => historyService.getHistoryGroups("dataSource"),
164
- getCurrent: (id) => dataSourceService.getDataSourceById(`${id}`),
162
+ groups: () => services?.historyService.getHistoryGroups("dataSource") ?? [],
163
+ getCurrent: (id) => services?.dataSourceService.getDataSourceById(`${id}`),
165
164
  resolveType: (n, o) => n.type || o.type || "base",
166
165
  resolveLabel: (n, o, id) => n.title || o.title || `${id}`
167
166
  }, index, id);
168
167
  const buildCodeBlockDiffPayload = (id, index) => buildDiffPayload({
169
168
  category: "code-block",
170
- groups: () => historyService.getHistoryGroups("codeBlock"),
171
- getCurrent: (id) => codeBlockService.getCodeContentById(id),
169
+ groups: () => services?.historyService.getHistoryGroups("codeBlock") ?? [],
170
+ getCurrent: (id) => services?.codeBlockService.getCodeContentById(id),
172
171
  resolveLabel: (n, o, id) => n.name || o.name || `${id}`
173
172
  }, index, id);
174
173
  /**
@@ -178,45 +177,45 @@ var useHistoryRevert = (services, options = {}) => {
178
177
  * add(回滚即删除)即使目标已不在,也已达成「删除」目的,不视为失败。
179
178
  */
180
179
  const isPageRevertTargetMissing = (index) => {
181
- const step = historyService.getStepList("page", editorService.get("page")?.id)[index]?.step;
180
+ const step = services?.historyService.getStepList("page", services?.editorService.get("page")?.id)[index]?.step;
182
181
  if (!step) return false;
183
182
  if (step.opType === "update") return (step.diff ?? []).some((item) => {
184
183
  const id = item.newSchema?.id ?? item.oldSchema?.id;
185
- return id !== void 0 && !editorService.getNodeById(id, false);
184
+ return id !== void 0 && !services?.editorService.getNodeById(id, false);
186
185
  });
187
- if (step.opType === "remove") return (step.diff ?? []).some((item) => item.parentId !== void 0 && !editorService.getNodeById(item.parentId, false));
186
+ if (step.opType === "remove") return (step.diff ?? []).some((item) => item.parentId !== void 0 && !services?.editorService.getNodeById(item.parentId, false));
188
187
  return false;
189
188
  };
190
189
  /** 数据源 update 步骤回滚时,对应数据源必须仍存在(已删除则无处写回旧值)。 */
191
190
  const isDataSourceRevertTargetMissing = (id, index) => {
192
- const step = historyService.getStepList("dataSource", id)[index]?.step;
193
- return Boolean(step?.opType === "update" && !dataSourceService.getDataSourceById(`${id}`));
191
+ const step = services?.historyService.getStepList("dataSource", id)[index]?.step;
192
+ return Boolean(step?.opType === "update" && !services?.dataSourceService.getDataSourceById(`${id}`));
194
193
  };
195
194
  /** 代码块 update 步骤回滚时,对应代码块必须仍存在(已删除则无处写回旧值)。 */
196
195
  const isCodeBlockRevertTargetMissing = (id, index) => {
197
- const step = historyService.getStepList("codeBlock", id)[index]?.step;
198
- return Boolean(step?.opType === "update" && !codeBlockService.getCodeContentById(id));
196
+ const step = services?.historyService.getStepList("codeBlock", id)[index]?.step;
197
+ return Boolean(step?.opType === "update" && !services?.codeBlockService.getCodeContentById(id));
199
198
  };
200
199
  const onPageRevert = (index) => {
201
200
  if (isPageRevertTargetMissing(index)) {
202
201
  showRevertTargetMissing();
203
202
  return Promise.resolve(null);
204
203
  }
205
- return runRevert(buildPageDiffPayload(index), { compareFormState: getPropsPanelFormState?.() }).then((result) => result ? editorService.revertPageStep(index) : null);
204
+ return runRevert(buildPageDiffPayload(index), { compareFormState: getPropsPanelFormState?.() }).then((result) => result ? services?.editorService.revertPageStep(index) : null);
206
205
  };
207
206
  const onDataSourceRevert = (id, index) => {
208
207
  if (isDataSourceRevertTargetMissing(id, index)) {
209
208
  showRevertTargetMissing();
210
209
  return Promise.resolve(null);
211
210
  }
212
- return runRevert(buildDataSourceDiffPayload(id, index)).then((result) => result ? dataSourceService.revert(id, index) : null);
211
+ return runRevert(buildDataSourceDiffPayload(id, index)).then((result) => result ? services?.dataSourceService.revert(id, index) : null);
213
212
  };
214
213
  const onCodeBlockRevert = (id, index) => {
215
214
  if (isCodeBlockRevertTargetMissing(id, index)) {
216
215
  showRevertTargetMissing();
217
216
  return Promise.resolve(null);
218
217
  }
219
- return runRevert(buildCodeBlockDiffPayload(id, index)).then((result) => result ? codeBlockService.revert(id, index) : null);
218
+ return runRevert(buildCodeBlockDiffPayload(id, index)).then((result) => result ? services?.codeBlockService.revert(id, index) : null);
220
219
  };
221
220
  /**
222
221
  * 「查看差异」:可差异对比的步骤(单实体 update)动态挂载只读 HistoryDiffDialog 展示前后值差异,
@@ -56,6 +56,7 @@ var CodeBlock = class extends BaseService {
56
56
  async setCodeDsl(codeDsl) {
57
57
  this.state.codeDsl = codeDsl;
58
58
  this.emit("code-dsl-change", this.state.codeDsl);
59
+ this.emit("change", this.state.codeDsl);
59
60
  }
60
61
  /**
61
62
  * 获取活动的代码块dsl数据源(默认从dsl中的codeBlocks字段读取)
@@ -132,6 +133,7 @@ var CodeBlock = class extends BaseService {
132
133
  this.lastPushedHistoryId = (step ? history_default.push("codeBlock", step, id) : null)?.uuid ?? null;
133
134
  }
134
135
  this.emit("addOrUpdate", id, codeDsl[id]);
136
+ this.emit("change", this.getCodeDsl());
135
137
  }
136
138
  /**
137
139
  * 根据代码块id数组获取代码dsl
@@ -229,6 +231,7 @@ var CodeBlock = class extends BaseService {
229
231
  }
230
232
  this.emit("remove", id);
231
233
  });
234
+ this.emit("change", this.getCodeDsl());
232
235
  }
233
236
  /**
234
237
  * 下列 *AndGetHistoryId 方法与对应的写入方法行为完全一致,
@@ -102,6 +102,7 @@ var DataSource = class extends BaseService {
102
102
  this.lastPushedHistoryId = (step ? history_default.push("dataSource", step, newConfig.id) : null)?.uuid ?? null;
103
103
  }
104
104
  this.emit("add", newConfig);
105
+ this.emit("change", this.get("dataSources"));
105
106
  return newConfig;
106
107
  }
107
108
  /**
@@ -132,6 +133,7 @@ var DataSource = class extends BaseService {
132
133
  oldConfig,
133
134
  changeRecords
134
135
  });
136
+ this.emit("change", this.get("dataSources"));
135
137
  return newConfig;
136
138
  }
137
139
  /**
@@ -156,6 +158,7 @@ var DataSource = class extends BaseService {
156
158
  this.lastPushedHistoryId = (step ? history_default.push("dataSource", step, id) : null)?.uuid ?? null;
157
159
  }
158
160
  this.emit("remove", id);
161
+ this.emit("change", this.get("dataSources"));
159
162
  }
160
163
  /**
161
164
  * 下列 *AndGetHistoryId 方法与对应的 add / update / remove 行为完全一致,
@@ -335,6 +335,13 @@ var Editor = class extends BaseService {
335
335
  } else this.selectionBeforeOp = null;
336
336
  }
337
337
  this.emit("add", newNodes);
338
+ this.emit("change", {
339
+ type: "add",
340
+ data: newNodes.map((node) => ({
341
+ node,
342
+ page: this.getPageOfNode(node.id)
343
+ }))
344
+ });
338
345
  return Array.isArray(addNode) ? newNodes : newNodes[0];
339
346
  }
340
347
  async doRemove(node, { doNotSelect = false, doNotSwitchPage = false } = {}) {
@@ -398,6 +405,10 @@ var Editor = class extends BaseService {
398
405
  async remove(nodeOrNodeList, { doNotSelect = false, doNotSwitchPage = false, doNotPushHistory = false, historyDescription, historySource } = {}) {
399
406
  this.captureSelectionBeforeOp();
400
407
  const nodes = Array.isArray(nodeOrNodeList) ? nodeOrNodeList : [nodeOrNodeList];
408
+ const changeItems = nodes.map((node) => ({
409
+ node,
410
+ page: this.getPageOfNode(node.id)
411
+ }));
401
412
  const removedItems = [];
402
413
  let pageForOp = null;
403
414
  if (!(isPage(nodes[0]) || isPageFragment(nodes[0]))) for (const n of nodes) {
@@ -427,6 +438,10 @@ var Editor = class extends BaseService {
427
438
  });
428
439
  else this.selectionBeforeOp = null;
429
440
  this.emit("remove", nodes);
441
+ this.emit("change", {
442
+ type: "remove",
443
+ data: changeItems
444
+ });
430
445
  }
431
446
  async doUpdate(config, { changeRecords = [], historySource } = {}) {
432
447
  if (!this.get("root")) throw new Error("root为空");
@@ -512,6 +527,13 @@ var Editor = class extends BaseService {
512
527
  } else this.selectionBeforeOp = null;
513
528
  }
514
529
  this.emit("update", updateData);
530
+ this.emit("change", {
531
+ type: "update",
532
+ data: updateData.map((node) => ({
533
+ node,
534
+ page: this.getPageOfNode(node.newNode.id)
535
+ }))
536
+ });
515
537
  return Array.isArray(config) ? updateData.map((item) => item.newNode) : updateData[0].newNode;
516
538
  }
517
539
  /**
@@ -677,6 +699,14 @@ var Editor = class extends BaseService {
677
699
  });
678
700
  } else this.selectionBeforeOp = null;
679
701
  this.emit("move-layer", offset);
702
+ this.emit("change", {
703
+ type: "move-layer",
704
+ data: [{
705
+ node,
706
+ page: this.getPageOfNode(node.id)
707
+ }],
708
+ offset
709
+ });
680
710
  }
681
711
  /**
682
712
  * 移动一个或多个节点到指定容器中。
@@ -806,6 +836,15 @@ var Editor = class extends BaseService {
806
836
  configs,
807
837
  targetParent
808
838
  });
839
+ this.emit("change", {
840
+ type: "drag-to",
841
+ data: configs.map((node) => ({
842
+ node,
843
+ page: this.getPageOfNode(node.id)
844
+ })),
845
+ targetIndex,
846
+ targetParent
847
+ });
809
848
  }
810
849
  /**
811
850
  * 下列 *AndGetHistoryId 方法与对应的普通操作(add / remove / update ...)行为完全一致,
@@ -1064,6 +1103,19 @@ var Editor = class extends BaseService {
1064
1103
  addModifiedNodeId(id) {
1065
1104
  this.get("modifiedNodeIds").set(id, id);
1066
1105
  }
1106
+ /**
1107
+ * 获取指定节点所属的页面 / 页面片:
1108
+ * - 普通节点返回其所在的 page;
1109
+ * - 节点本身就是 page / pageFragment 时返回它自己;
1110
+ * - 找不到时返回 null。
1111
+ * 供 `change` 事件携带「变更节点对应的 page」(而非编辑器当前选中页)。
1112
+ */
1113
+ getPageOfNode(id) {
1114
+ const { node, page } = this.getNodeInfo(id, false);
1115
+ if (page) return page;
1116
+ if (node && (isPage(node) || isPageFragment(node))) return node;
1117
+ return null;
1118
+ }
1067
1119
  captureSelectionBeforeOp() {
1068
1120
  if (this.selectionBeforeOp) return;
1069
1121
  this.selectionBeforeOp = this.get("nodes").map((n) => n.id);