@tmagic/editor 1.8.0-beta.1 → 1.8.0-beta.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/es/Editor.vue_vue_type_script_setup_true_lang.js +31 -5
- package/dist/es/components/CodeBlockEditor.vue_vue_type_script_setup_true_lang.js +21 -113
- package/dist/es/components/CodeParams.vue_vue_type_script_setup_true_lang.js +7 -1
- package/dist/es/components/CompareForm.js +5 -0
- package/dist/es/components/CompareForm.vue_vue_type_script_setup_true_lang.js +196 -0
- package/dist/es/components/ContentMenu.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/es/components/FloatingBox.vue_vue_type_script_setup_true_lang.js +2 -2
- package/dist/es/components/Icon.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/es/components/Resizer.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/es/components/ScrollBar.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/es/components/ScrollViewer.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/es/components/SearchInput.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/es/components/SplitView.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/es/components/ToolButton.vue_vue_type_script_setup_true_lang.js +7 -7
- package/dist/es/components/Tree.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/es/components/TreeNode.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/es/editorProps.js +2 -0
- package/dist/es/fields/Code.vue_vue_type_script_setup_true_lang.js +20 -4
- package/dist/es/fields/CodeLink.vue_vue_type_script_setup_true_lang.js +3 -6
- package/dist/es/fields/CodeSelect.vue_vue_type_script_setup_true_lang.js +19 -3
- package/dist/es/fields/CodeSelectCol.vue_vue_type_script_setup_true_lang.js +42 -8
- package/dist/es/fields/CondOpSelect.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/es/fields/DataSourceFieldSelect/FieldSelect.vue_vue_type_script_setup_true_lang.js +14 -6
- package/dist/es/fields/DataSourceFieldSelect/Index.vue_vue_type_script_setup_true_lang.js +3 -3
- package/dist/es/fields/DataSourceFields.vue_vue_type_script_setup_true_lang.js +41 -16
- package/dist/es/fields/DataSourceInput.vue_vue_type_script_setup_true_lang.js +2 -2
- package/dist/es/fields/DataSourceMethodSelect.vue_vue_type_script_setup_true_name_true_lang.js +9 -5
- package/dist/es/fields/DataSourceMethods.vue_vue_type_script_setup_true_lang.js +40 -19
- package/dist/es/fields/DataSourceMocks.vue_vue_type_script_setup_true_lang.js +17 -9
- package/dist/es/fields/DataSourceSelect.vue_vue_type_script_setup_true_lang.js +4 -2
- package/dist/es/fields/DisplayConds.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/es/fields/EventSelect.vue_vue_type_script_setup_true_lang.js +59 -12
- package/dist/es/fields/KeyValue.vue_vue_type_script_setup_true_lang.js +12 -7
- package/dist/es/fields/PageFragmentSelect.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/es/fields/StyleSetter/Index.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/es/fields/StyleSetter/components/BackgroundPosition.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/es/fields/StyleSetter/components/Border.vue_vue_type_script_setup_true_lang.js +28 -6
- package/dist/es/fields/StyleSetter/components/Box.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/es/fields/StyleSetter/icons/background-repeat/NoRepeat.js +1 -1
- package/dist/es/fields/StyleSetter/icons/background-repeat/Repeat.js +1 -1
- package/dist/es/fields/StyleSetter/icons/background-repeat/RepeatX.js +1 -1
- package/dist/es/fields/StyleSetter/icons/background-repeat/RepeatY.js +1 -1
- package/dist/es/fields/StyleSetter/icons/display/Block.js +1 -1
- package/dist/es/fields/StyleSetter/icons/display/Flex.js +1 -1
- package/dist/es/fields/StyleSetter/icons/display/Inline.js +1 -1
- package/dist/es/fields/StyleSetter/icons/display/InlineBlock.js +1 -1
- package/dist/es/fields/StyleSetter/icons/display/None.js +1 -1
- package/dist/es/fields/StyleSetter/icons/flex-direction/Column.js +1 -1
- package/dist/es/fields/StyleSetter/icons/flex-direction/ColumnReverse.js +1 -1
- package/dist/es/fields/StyleSetter/icons/flex-direction/Row.js +1 -1
- package/dist/es/fields/StyleSetter/icons/flex-direction/RowReverse.js +1 -1
- package/dist/es/fields/StyleSetter/icons/justify-content/Center.js +1 -1
- package/dist/es/fields/StyleSetter/icons/justify-content/FlexEnd.js +1 -1
- package/dist/es/fields/StyleSetter/icons/justify-content/FlexStart.js +1 -1
- package/dist/es/fields/StyleSetter/icons/justify-content/SpaceAround.js +1 -1
- package/dist/es/fields/StyleSetter/icons/justify-content/SpaceBetween.js +1 -1
- package/dist/es/fields/StyleSetter/icons/text-align/Center.js +1 -1
- package/dist/es/fields/StyleSetter/icons/text-align/Left.js +1 -1
- package/dist/es/fields/StyleSetter/icons/text-align/Right.js +1 -1
- package/dist/es/fields/StyleSetter/pro/Background.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/es/fields/StyleSetter/pro/Border.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/es/fields/StyleSetter/pro/Font.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/es/fields/StyleSetter/pro/Layout.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/es/fields/StyleSetter/pro/Position.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/es/fields/StyleSetter/pro/Transform.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/es/fields/UISelect.vue_vue_type_script_setup_true_lang.js +9 -6
- package/dist/es/hooks/use-code-block-edit.js +7 -4
- package/dist/es/hooks/use-data-source-edit.js +5 -2
- package/dist/es/hooks/use-stage.js +22 -10
- package/dist/es/icons/CenterIcon.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/es/icons/CodeIcon.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/es/icons/FolderMinusIcon.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/es/index.js +14 -3
- package/dist/es/initService.js +7 -7
- package/dist/es/layouts/AddPageBox.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/es/layouts/CodeEditor.vue_vue_type_script_setup_true_lang.js +7 -6
- package/dist/es/layouts/Framework.vue_vue_type_script_setup_true_lang.js +14 -9
- package/dist/es/layouts/NavMenu.vue_vue_type_script_setup_true_lang.js +12 -4
- package/dist/es/layouts/NavMenuColumn.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/es/layouts/history-list/Bucket.js +5 -0
- package/dist/es/layouts/history-list/Bucket.vue_vue_type_script_setup_true_lang.js +71 -0
- package/dist/es/layouts/history-list/BucketTab.js +5 -0
- package/dist/es/layouts/history-list/BucketTab.vue_vue_type_script_setup_true_lang.js +62 -0
- package/dist/es/layouts/history-list/GroupRow.js +5 -0
- package/dist/es/layouts/history-list/GroupRow.vue_vue_type_script_setup_true_lang.js +269 -0
- package/dist/es/layouts/history-list/HistoryDiffDialog.js +5 -0
- package/dist/es/layouts/history-list/HistoryDiffDialog.vue_vue_type_script_setup_true_lang.js +294 -0
- package/dist/es/layouts/history-list/HistoryListPanel.js +5 -0
- package/dist/es/layouts/history-list/HistoryListPanel.vue_vue_type_script_setup_true_lang.js +327 -0
- package/dist/es/layouts/history-list/InitialRow.js +5 -0
- package/dist/es/layouts/history-list/InitialRow.vue_vue_type_script_setup_true_lang.js +83 -0
- package/dist/es/layouts/history-list/PageTab.js +5 -0
- package/dist/es/layouts/history-list/PageTab.vue_vue_type_script_setup_true_lang.js +95 -0
- package/dist/es/layouts/history-list/composables.js +184 -0
- package/dist/es/layouts/history-list/useHistoryList.js +56 -0
- package/dist/es/layouts/history-list/useHistoryRevert.js +313 -0
- package/dist/es/layouts/page-bar/AddButton.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/es/layouts/page-bar/PageBar.vue_vue_type_script_setup_true_lang.js +5 -3
- package/dist/es/layouts/page-bar/PageBarScrollContainer.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/es/layouts/page-bar/PageList.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/es/layouts/page-bar/Search.vue_vue_type_script_setup_true_lang.js +2 -2
- package/dist/es/layouts/props-panel/FormPanel.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/es/layouts/props-panel/PropsPanel.vue_vue_type_script_setup_true_lang.js +6 -2
- package/dist/es/layouts/sidebar/ComponentListPanel.vue_vue_type_script_setup_true_lang.js +2 -2
- package/dist/es/layouts/sidebar/Sidebar.vue_vue_type_script_setup_true_lang.js +8 -4
- package/dist/es/layouts/sidebar/code-block/CodeBlockList.vue_vue_type_script_setup_true_lang.js +4 -4
- package/dist/es/layouts/sidebar/code-block/CodeBlockListPanel.vue_vue_type_script_setup_true_lang.js +2 -2
- package/dist/es/layouts/sidebar/code-block/useContentMenu.js +1 -1
- package/dist/es/layouts/sidebar/data-source/DataSourceAddButton.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/es/layouts/sidebar/data-source/DataSourceConfigPanel.vue_vue_type_script_setup_true_lang.js +19 -6
- package/dist/es/layouts/sidebar/data-source/DataSourceList.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/es/layouts/sidebar/data-source/DataSourceListPanel.vue_vue_type_script_setup_true_lang.js +25 -3
- package/dist/es/layouts/sidebar/data-source/useContentMenu.js +1 -1
- package/dist/es/layouts/sidebar/layer/LayerMenu.vue_vue_type_script_setup_true_lang.js +6 -6
- package/dist/es/layouts/sidebar/layer/LayerNodeTool.vue_vue_type_script_setup_true_lang.js +2 -2
- package/dist/es/layouts/sidebar/layer/LayerPanel.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/es/layouts/sidebar/layer/use-node-status.js +1 -1
- package/dist/es/layouts/workspace/Breadcrumb.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/es/layouts/workspace/Workspace.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/es/layouts/workspace/viewer/NodeListMenu.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/es/layouts/workspace/viewer/Stage.vue_vue_type_script_setup_true_lang.js +2 -2
- package/dist/es/layouts/workspace/viewer/StageOverlay.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/es/layouts/workspace/viewer/ViewerMenu.vue_vue_type_script_setup_true_lang.js +9 -9
- package/dist/es/services/BaseService.js +31 -68
- package/dist/es/services/codeBlock.js +286 -8
- package/dist/es/services/componentList.js +2 -2
- package/dist/es/services/dataSource.js +287 -8
- package/dist/es/services/dep.js +21 -9
- package/dist/es/services/editor.js +655 -194
- package/dist/es/services/events.js +2 -2
- package/dist/es/services/history.js +390 -47
- package/dist/es/services/keybinding.js +5 -5
- package/dist/es/services/props.js +8 -8
- package/dist/es/services/stageOverlay.js +2 -2
- package/dist/es/services/storage.js +2 -2
- package/dist/es/services/ui.js +5 -2
- package/dist/es/style.css +456 -8
- package/dist/es/utils/code-block.js +122 -0
- package/dist/es/utils/content-menu.js +19 -12
- package/dist/es/utils/data-source/index.js +2 -0
- package/dist/es/utils/dep/worker.js +1 -1
- package/dist/es/utils/editor.js +105 -51
- package/dist/es/utils/history.js +220 -0
- package/dist/es/utils/indexed-db.js +86 -0
- package/dist/es/utils/undo-redo.js +80 -1
- package/dist/style.css +456 -8
- package/dist/tmagic-editor.umd.cjs +11149 -6646
- package/package.json +8 -8
- package/src/Editor.vue +25 -1
- package/src/components/CodeBlockEditor.vue +20 -109
- package/src/components/CodeParams.vue +6 -0
- package/src/components/CompareForm.vue +277 -0
- package/src/components/ToolButton.vue +2 -2
- package/src/editorProps.ts +9 -0
- package/src/fields/Code.vue +19 -3
- package/src/fields/CodeLink.vue +2 -5
- package/src/fields/CodeSelect.vue +17 -1
- package/src/fields/CodeSelectCol.vue +37 -3
- package/src/fields/DataSourceFieldSelect/FieldSelect.vue +23 -3
- package/src/fields/DataSourceFieldSelect/Index.vue +2 -2
- package/src/fields/DataSourceFields.vue +48 -10
- package/src/fields/DataSourceInput.vue +3 -3
- package/src/fields/DataSourceMethodSelect.vue +12 -4
- package/src/fields/DataSourceMethods.vue +55 -24
- package/src/fields/DataSourceMocks.vue +13 -3
- package/src/fields/DataSourceSelect.vue +4 -1
- package/src/fields/EventSelect.vue +57 -8
- package/src/fields/KeyValue.vue +17 -4
- package/src/fields/StyleSetter/components/Border.vue +15 -6
- package/src/fields/UISelect.vue +5 -2
- package/src/hooks/use-code-block-edit.ts +9 -5
- package/src/hooks/use-data-source-edit.ts +2 -2
- package/src/hooks/use-stage.ts +26 -9
- package/src/index.ts +8 -0
- package/src/initService.ts +1 -1
- package/src/layouts/CodeEditor.vue +17 -5
- package/src/layouts/Framework.vue +11 -6
- package/src/layouts/NavMenu.vue +12 -3
- package/src/layouts/history-list/Bucket.vue +91 -0
- package/src/layouts/history-list/BucketTab.vue +72 -0
- package/src/layouts/history-list/GroupRow.vue +304 -0
- package/src/layouts/history-list/HistoryDiffDialog.vue +281 -0
- package/src/layouts/history-list/HistoryListPanel.vue +367 -0
- package/src/layouts/history-list/InitialRow.vue +71 -0
- package/src/layouts/history-list/PageTab.vue +118 -0
- package/src/layouts/history-list/composables.ts +309 -0
- package/src/layouts/history-list/useHistoryList.ts +60 -0
- package/src/layouts/history-list/useHistoryRevert.ts +421 -0
- package/src/layouts/page-bar/PageBar.vue +4 -2
- package/src/layouts/props-panel/PropsPanel.vue +5 -1
- package/src/layouts/sidebar/ComponentListPanel.vue +9 -5
- package/src/layouts/sidebar/Sidebar.vue +8 -3
- package/src/layouts/sidebar/code-block/CodeBlockList.vue +5 -5
- package/src/layouts/sidebar/code-block/CodeBlockListPanel.vue +1 -1
- package/src/layouts/sidebar/code-block/useContentMenu.ts +1 -1
- package/src/layouts/sidebar/data-source/DataSourceConfigPanel.vue +31 -2
- package/src/layouts/sidebar/data-source/DataSourceListPanel.vue +27 -2
- package/src/layouts/sidebar/data-source/useContentMenu.ts +1 -1
- package/src/layouts/sidebar/layer/LayerMenu.vue +19 -11
- package/src/layouts/sidebar/layer/LayerNodeTool.vue +7 -4
- package/src/layouts/sidebar/layer/use-node-status.ts +9 -6
- package/src/layouts/workspace/viewer/Stage.vue +1 -1
- package/src/layouts/workspace/viewer/ViewerMenu.vue +8 -8
- package/src/services/BaseService.ts +35 -86
- package/src/services/codeBlock.ts +361 -5
- package/src/services/dataSource.ts +336 -6
- package/src/services/dep.ts +32 -9
- package/src/services/editor.ts +834 -194
- package/src/services/history.ts +509 -49
- package/src/services/keybinding.ts +3 -3
- package/src/services/props.ts +2 -2
- package/src/services/ui.ts +7 -0
- package/src/theme/history-list-panel.scss +557 -0
- package/src/theme/page-bar.scss +0 -4
- package/src/theme/props-panel.scss +3 -3
- package/src/theme/style-setter/border.scss +4 -1
- package/src/theme/theme.scss +1 -0
- package/src/type.ts +613 -31
- package/src/utils/code-block.ts +150 -0
- package/src/utils/content-menu.ts +25 -13
- package/src/utils/data-source/index.ts +2 -0
- package/src/utils/dep/worker.ts +5 -3
- package/src/utils/editor.ts +166 -60
- package/src/utils/history.ts +286 -0
- package/src/utils/index.ts +3 -0
- package/src/utils/indexed-db.ts +122 -0
- package/src/utils/undo-redo.ts +111 -0
- package/types/index.d.ts +3197 -896
- package/dist/es/utils/compose.js +0 -44
- package/dist/es/utils/editor-history.js +0 -100
- package/src/utils/compose.ts +0 -52
- package/src/utils/editor-history.ts +0 -138
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<li
|
|
3
|
+
class="m-editor-history-list-item m-editor-history-list-group"
|
|
4
|
+
:class="{ 'is-undone': !group.applied, 'is-merged': merged, 'is-current': group.isCurrent }"
|
|
5
|
+
>
|
|
6
|
+
<div
|
|
7
|
+
class="m-editor-history-list-group-head"
|
|
8
|
+
:class="{ 'is-clickable': isHeadClickable }"
|
|
9
|
+
:title="headTitle"
|
|
10
|
+
@click="onHeadClick"
|
|
11
|
+
>
|
|
12
|
+
<span class="m-editor-history-list-item-index" :title="headIndexTitle">{{ headIndexLabel }}</span>
|
|
13
|
+
<span class="m-editor-history-list-item-op" :class="`op-${group.opType}`">{{ opLabel(group.opType) }}</span>
|
|
14
|
+
<span class="m-editor-history-list-item-desc">{{ group.desc }}</span>
|
|
15
|
+
|
|
16
|
+
<span v-if="headSaved" class="m-editor-history-list-item-saved" title="该记录为最近一次保存的状态">已保存</span>
|
|
17
|
+
|
|
18
|
+
<span
|
|
19
|
+
v-if="!merged && (headRevertable || headDiffable || canHeadGoto)"
|
|
20
|
+
class="m-editor-history-list-item-actions"
|
|
21
|
+
>
|
|
22
|
+
<span
|
|
23
|
+
v-if="headRevertable"
|
|
24
|
+
class="m-editor-history-list-item-revert"
|
|
25
|
+
title="将该步骤的修改作为一次新操作反向应用(不影响后续历史)"
|
|
26
|
+
@click.stop="onRevertClick(group.subSteps[0].index)"
|
|
27
|
+
>回滚</span
|
|
28
|
+
>
|
|
29
|
+
<span
|
|
30
|
+
v-if="canHeadGoto"
|
|
31
|
+
class="m-editor-history-list-item-goto"
|
|
32
|
+
title="回到该记录"
|
|
33
|
+
@click.stop="onGotoClick(group.subSteps[0].index)"
|
|
34
|
+
>回到</span
|
|
35
|
+
>
|
|
36
|
+
<span
|
|
37
|
+
v-if="headDiffable"
|
|
38
|
+
class="m-editor-history-list-item-diff"
|
|
39
|
+
title="查看修改差异"
|
|
40
|
+
@click.stop="onDiffClick(group.subSteps[0].index)"
|
|
41
|
+
>查看差异</span
|
|
42
|
+
>
|
|
43
|
+
</span>
|
|
44
|
+
|
|
45
|
+
<span
|
|
46
|
+
v-if="!merged && sourceLabel(group.source)"
|
|
47
|
+
class="m-editor-history-list-item-source"
|
|
48
|
+
:title="`操作途径:${sourceLabel(group.source)}`"
|
|
49
|
+
>{{ sourceLabel(group.source) }}</span
|
|
50
|
+
>
|
|
51
|
+
|
|
52
|
+
<span
|
|
53
|
+
v-if="!merged && group.operator"
|
|
54
|
+
class="m-editor-history-list-item-operator"
|
|
55
|
+
:title="`操作人:${group.operator}`"
|
|
56
|
+
>{{ group.operator }}</span
|
|
57
|
+
>
|
|
58
|
+
|
|
59
|
+
<span
|
|
60
|
+
v-if="!merged && group.time"
|
|
61
|
+
class="m-editor-history-list-item-time"
|
|
62
|
+
:title="group.timeTitle || group.time"
|
|
63
|
+
>{{ group.time }}</span
|
|
64
|
+
>
|
|
65
|
+
|
|
66
|
+
<span v-if="merged" class="m-editor-history-list-item-merge">合并 {{ stepCount }} 步</span>
|
|
67
|
+
<span v-if="merged" class="m-editor-history-list-group-toggle" :class="{ 'is-expanded': expanded }">▾</span>
|
|
68
|
+
</div>
|
|
69
|
+
|
|
70
|
+
<ul v-if="merged && expanded" class="m-editor-history-list-substeps">
|
|
71
|
+
<li
|
|
72
|
+
v-for="s in subStepsDisplay"
|
|
73
|
+
:key="s.index"
|
|
74
|
+
:class="{ 'is-undone': !s.applied, 'is-current': s.isCurrent, 'is-clickable': selectEnabled }"
|
|
75
|
+
:title="subStepTitle(s)"
|
|
76
|
+
@click="onSubStepClick(s.index)"
|
|
77
|
+
>
|
|
78
|
+
<span class="m-editor-history-list-item-index">#{{ s.index + 1 }}</span>
|
|
79
|
+
<span class="m-editor-history-list-substep-desc">{{ s.desc }}</span>
|
|
80
|
+
<span v-if="s.saved" class="m-editor-history-list-item-saved" title="该记录为最近一次保存的状态">已保存</span>
|
|
81
|
+
<span
|
|
82
|
+
v-if="s.revertable || s.diffable || (gotoEnabled && !s.isCurrent)"
|
|
83
|
+
class="m-editor-history-list-item-actions"
|
|
84
|
+
>
|
|
85
|
+
<span
|
|
86
|
+
v-if="s.revertable"
|
|
87
|
+
class="m-editor-history-list-item-revert"
|
|
88
|
+
title="将该步骤的修改作为一次新操作反向应用(不影响后续历史)"
|
|
89
|
+
@click.stop="onRevertClick(s.index)"
|
|
90
|
+
>回滚</span
|
|
91
|
+
>
|
|
92
|
+
<span
|
|
93
|
+
v-if="gotoEnabled && !s.isCurrent"
|
|
94
|
+
class="m-editor-history-list-item-goto"
|
|
95
|
+
title="回到该记录"
|
|
96
|
+
@click.stop="onGotoClick(s.index)"
|
|
97
|
+
>回到</span
|
|
98
|
+
>
|
|
99
|
+
<span
|
|
100
|
+
v-if="s.diffable"
|
|
101
|
+
class="m-editor-history-list-item-diff"
|
|
102
|
+
title="查看修改差异"
|
|
103
|
+
@click.stop="onDiffClick(s.index)"
|
|
104
|
+
>查看差异</span
|
|
105
|
+
>
|
|
106
|
+
</span>
|
|
107
|
+
<span
|
|
108
|
+
v-if="sourceLabel(s.source)"
|
|
109
|
+
class="m-editor-history-list-item-source"
|
|
110
|
+
:title="`操作途径:${sourceLabel(s.source)}`"
|
|
111
|
+
>{{ sourceLabel(s.source) }}</span
|
|
112
|
+
>
|
|
113
|
+
<span v-if="s.operator" class="m-editor-history-list-item-operator" :title="`操作人:${s.operator}`">{{
|
|
114
|
+
s.operator
|
|
115
|
+
}}</span>
|
|
116
|
+
<span v-if="s.time" class="m-editor-history-list-item-time" :title="s.timeTitle || s.time">{{ s.time }}</span>
|
|
117
|
+
</li>
|
|
118
|
+
</ul>
|
|
119
|
+
</li>
|
|
120
|
+
</template>
|
|
121
|
+
|
|
122
|
+
<script lang="ts" setup>
|
|
123
|
+
import { computed } from 'vue';
|
|
124
|
+
|
|
125
|
+
import type { HistoryRowGroup, HistoryRowStep } from './composables';
|
|
126
|
+
import { opLabel, sourceLabel } from './composables';
|
|
127
|
+
|
|
128
|
+
defineOptions({
|
|
129
|
+
name: 'MEditorHistoryListGroupRow',
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
const props = withDefaults(
|
|
133
|
+
defineProps<{
|
|
134
|
+
/**
|
|
135
|
+
* 该组的视图模型(由 `toRowGroup` 统一派生):包含 key、应用状态、操作类型、描述、
|
|
136
|
+
* 来源 / 时间等头部信息以及子步列表。原先散落的十余个扁平 props 收敛于此单一对象。
|
|
137
|
+
*/
|
|
138
|
+
group: HistoryRowGroup;
|
|
139
|
+
/** 当前组是否处于展开状态(合并组默认展开)。仅在合并组(子步数 > 1)时生效,控制子步列表是否渲染。 */
|
|
140
|
+
expanded: boolean;
|
|
141
|
+
/**
|
|
142
|
+
* 是否支持「跳转到该记录」(goto)。默认 true。
|
|
143
|
+
* 为 false 时:单步组头部与子步条目都不再可点击跳转、也不会触发 goto 事件,
|
|
144
|
+
* 仅保留合并组头部的展开 / 收起能力,以及查看差异、回滚等其它入口。
|
|
145
|
+
*/
|
|
146
|
+
gotoEnabled?: boolean;
|
|
147
|
+
/**
|
|
148
|
+
* 是否支持「点击记录选中对应节点」。默认 false(仅页面 tab 启用,数据源 / 代码块无节点概念)。
|
|
149
|
+
* 为 true 时:点击单步组头部、子步条目或合并组头部都会发出 `select` 事件(携带对应 step 索引),
|
|
150
|
+
* 由上层解析出节点 id 并在画布选中;合并组头部同时保留展开 / 收起能力。
|
|
151
|
+
*/
|
|
152
|
+
selectEnabled?: boolean;
|
|
153
|
+
}>(),
|
|
154
|
+
{
|
|
155
|
+
gotoEnabled: true,
|
|
156
|
+
selectEnabled: false,
|
|
157
|
+
},
|
|
158
|
+
);
|
|
159
|
+
|
|
160
|
+
const emit = defineEmits<{
|
|
161
|
+
/**
|
|
162
|
+
* 用户点击合并组头部时触发,携带 group.key;上层用其切换 expanded 状态。
|
|
163
|
+
* 对单步组(非合并)头部点击不会发该事件——因为单步组没有"展开"的概念。
|
|
164
|
+
*/
|
|
165
|
+
(_e: 'toggle', _key: string): void;
|
|
166
|
+
/**
|
|
167
|
+
* 用户希望跳转到该记录时触发,携带"目标 step 在所属栈中的索引"——上层据此计算目标 cursor (= index + 1)。
|
|
168
|
+
* 触发场景:
|
|
169
|
+
* - 单步组(非合并)头部:取该唯一 step 的 index;
|
|
170
|
+
* - 子步条目:取该子步的 index。
|
|
171
|
+
* 合并组头部不再触发 goto,避免与展开/收起冲突;用户应展开后点具体子步精准跳转。
|
|
172
|
+
* 当前所在的步骤(isCurrent)始终不会触发 goto。
|
|
173
|
+
*/
|
|
174
|
+
(_e: 'goto', _index: number): void;
|
|
175
|
+
/**
|
|
176
|
+
* 用户希望查看该 step 的修改差异(旧值 vs 新值)。
|
|
177
|
+
* 只在 step 满足"前后值都存在"(如 update / 数据源、代码块的 update)时由 `toRowGroup` 标记 `diffable=true`。
|
|
178
|
+
* payload 为该 step 在所属栈中的索引,由上层根据 index 取 step 内容并展示对比。
|
|
179
|
+
*/
|
|
180
|
+
(_e: 'diff-step', _index: number): void;
|
|
181
|
+
/**
|
|
182
|
+
* 用户希望「回滚」该 step——把它的修改作为一次新操作反向应用(类 git revert)。
|
|
183
|
+
* payload 为该 step 在所属栈中的索引。仅在单步组头部(headRevertable)或合并组的可回滚子步上触发。
|
|
184
|
+
*/
|
|
185
|
+
(_e: 'revert-step', _index: number): void;
|
|
186
|
+
/**
|
|
187
|
+
* 用户希望「选中该记录对应的节点」。payload 为该 step 在所属栈中的索引,
|
|
188
|
+
* 由上层据 index 取出 step、解析出节点 id 并在画布选中。仅在 `selectEnabled` 为 true 时触发。
|
|
189
|
+
*/
|
|
190
|
+
(_e: 'select', _index: number): void;
|
|
191
|
+
}>();
|
|
192
|
+
|
|
193
|
+
/** 子步数大于 1 即为合并组:决定是否展示合并标记与可展开的子步列表。 */
|
|
194
|
+
const merged = computed(() => props.group.subSteps.length > 1);
|
|
195
|
+
|
|
196
|
+
/** 组内 step 总数,仅在合并组时显示为 "合并 N 步"。 */
|
|
197
|
+
const stepCount = computed(() => props.group.subSteps.length);
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* 头部可点击的场景:
|
|
201
|
+
* - 合并组:点击切换展开 / 收起;
|
|
202
|
+
* - 开启 `selectEnabled`(页面 tab):点击选中对应节点。
|
|
203
|
+
* 单步组的跳转仍由头部的「回到」按钮触发。
|
|
204
|
+
*/
|
|
205
|
+
const isHeadClickable = computed(() => merged.value || props.selectEnabled);
|
|
206
|
+
|
|
207
|
+
const headTitle = computed(() => {
|
|
208
|
+
if (merged.value) {
|
|
209
|
+
const expandHint = props.expanded ? '点击收起子步' : '点击展开子步';
|
|
210
|
+
return props.selectEnabled ? `${expandHint}(并选中该节点)` : expandHint;
|
|
211
|
+
}
|
|
212
|
+
if (props.selectEnabled) return '点击选中该节点';
|
|
213
|
+
if (props.group.isCurrent) return '当前所在记录';
|
|
214
|
+
return '';
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* 头部点击行为:
|
|
219
|
+
* - 开启 selectEnabled 时,发出 select(携带组内首步 index,上层据此选中节点);
|
|
220
|
+
* - 合并组同时切换展开 / 收起。
|
|
221
|
+
*/
|
|
222
|
+
const onHeadClick = () => {
|
|
223
|
+
if (props.selectEnabled && props.group.subSteps.length) {
|
|
224
|
+
emit('select', props.group.subSteps[0].index);
|
|
225
|
+
}
|
|
226
|
+
if (merged.value) {
|
|
227
|
+
emit('toggle', props.group.key);
|
|
228
|
+
}
|
|
229
|
+
};
|
|
230
|
+
|
|
231
|
+
const onGotoClick = (index: number) => {
|
|
232
|
+
if (!props.gotoEnabled) return;
|
|
233
|
+
emit('goto', index);
|
|
234
|
+
};
|
|
235
|
+
|
|
236
|
+
/** 点击子步行:开启 selectEnabled 时选中该子步对应的节点。 */
|
|
237
|
+
const onSubStepClick = (index: number) => {
|
|
238
|
+
if (!props.selectEnabled) return;
|
|
239
|
+
emit('select', index);
|
|
240
|
+
};
|
|
241
|
+
|
|
242
|
+
const subStepTitle = (s: { isCurrent?: boolean }) => {
|
|
243
|
+
if (props.selectEnabled) return '点击选中该节点';
|
|
244
|
+
if (s.isCurrent) return '当前所在记录';
|
|
245
|
+
return '';
|
|
246
|
+
};
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* 头部是否展示「已保存」标记:
|
|
250
|
+
* - 单步组:取该唯一子步的 saved;
|
|
251
|
+
* - 合并组:组内任一子步为已保存即在头部提示(具体落在哪一步可展开查看)。
|
|
252
|
+
*/
|
|
253
|
+
const headSaved = computed(() =>
|
|
254
|
+
merged.value ? props.group.subSteps.some((s) => s.saved) : Boolean(props.group.subSteps[0]?.saved),
|
|
255
|
+
);
|
|
256
|
+
|
|
257
|
+
/** 单步组头部是否展示"查看差异"入口:要求该唯一子步本身可对比。 */
|
|
258
|
+
const headDiffable = computed(() => !merged.value && Boolean(props.group.subSteps[0]?.diffable));
|
|
259
|
+
|
|
260
|
+
/** 单步组头部是否展示"回滚"入口:要求该唯一子步本身可回滚(已应用)。 */
|
|
261
|
+
const headRevertable = computed(() => !merged.value && Boolean(props.group.subSteps[0]?.revertable));
|
|
262
|
+
|
|
263
|
+
/** 单步组头部是否展示"回到"入口:可跳转、非当前、且存在唯一子步。 */
|
|
264
|
+
const canHeadGoto = computed(
|
|
265
|
+
() => !merged.value && props.gotoEnabled && !props.group.isCurrent && props.group.subSteps.length > 0,
|
|
266
|
+
);
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* 合并组展开后的子步渲染顺序:与外层分组列表保持一致——倒序展示(最新的子步在最上方)。
|
|
270
|
+
* 外层 page tab / bucket 都已对 groups 做了 reverse,子步沿用同样的视觉规则更直观。
|
|
271
|
+
* 注意:仅用于渲染,原 `subSteps` 保持时间正序,`headIndexLabel` 等基于首尾索引的展示语义不变。
|
|
272
|
+
*/
|
|
273
|
+
const subStepsDisplay = computed<HistoryRowStep[]>(() => props.group.subSteps.slice().reverse());
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* 头部索引展示:
|
|
277
|
+
* - 单步组(非合并):显示该唯一 step 的编号,如 `#5`;
|
|
278
|
+
* - 合并组:显示组内 step 的编号范围,如 `#3-#7`(首尾相同则退化为 `#5`)。
|
|
279
|
+
*
|
|
280
|
+
* 这里展示的是 step.index + 1(与子步列表 `#{{ s.index + 1 }}` 保持一致),从 1 起编号更符合直觉。
|
|
281
|
+
*/
|
|
282
|
+
const headIndexLabel = computed(() => {
|
|
283
|
+
const list = props.group.subSteps;
|
|
284
|
+
if (!list.length) return '';
|
|
285
|
+
const first = list[0].index + 1;
|
|
286
|
+
const last = list[list.length - 1].index + 1;
|
|
287
|
+
if (!merged.value || first === last) return `#${first}`;
|
|
288
|
+
return `#${first}-#${last}`;
|
|
289
|
+
});
|
|
290
|
+
|
|
291
|
+
const headIndexTitle = computed(() => {
|
|
292
|
+
const list = props.group.subSteps;
|
|
293
|
+
if (!merged.value) return `历史步骤编号 #${list[0]?.index + 1}`;
|
|
294
|
+
return `合并了第 ${list[0]?.index + 1} 至第 ${list[list.length - 1]?.index + 1} 共 ${list.length} 条历史步骤`;
|
|
295
|
+
});
|
|
296
|
+
|
|
297
|
+
const onDiffClick = (index: number) => {
|
|
298
|
+
emit('diff-step', index);
|
|
299
|
+
};
|
|
300
|
+
|
|
301
|
+
const onRevertClick = (index: number) => {
|
|
302
|
+
emit('revert-step', index);
|
|
303
|
+
};
|
|
304
|
+
</script>
|
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<TMagicDialog
|
|
3
|
+
v-model="visible"
|
|
4
|
+
class="m-editor-history-diff-dialog"
|
|
5
|
+
:title="dialogTitle"
|
|
6
|
+
top="5vh"
|
|
7
|
+
destroy-on-close
|
|
8
|
+
append-to-body
|
|
9
|
+
:width="width"
|
|
10
|
+
@close="onClose"
|
|
11
|
+
>
|
|
12
|
+
<div v-if="payload && visible" class="m-editor-history-diff-dialog-body">
|
|
13
|
+
<div v-if="onConfirm" class="m-editor-history-diff-dialog-notice">仅回滚有差异的字段</div>
|
|
14
|
+
|
|
15
|
+
<div class="m-editor-history-diff-dialog-header">
|
|
16
|
+
<span class="m-editor-history-diff-dialog-target">{{ targetText }}</span>
|
|
17
|
+
<div class="m-editor-history-diff-dialog-controls">
|
|
18
|
+
<TMagicRadioGroup v-model="viewMode" size="small" class="m-editor-history-diff-dialog-view">
|
|
19
|
+
<TMagicRadioButton value="form">表单对比</TMagicRadioButton>
|
|
20
|
+
<TMagicRadioButton value="code">源码对比</TMagicRadioButton>
|
|
21
|
+
</TMagicRadioGroup>
|
|
22
|
+
|
|
23
|
+
<TMagicRadioGroup v-model="mode" size="small" class="m-editor-history-diff-dialog-mode">
|
|
24
|
+
<TMagicRadioButton value="before" :disabled="!hasValue">与修改前对比</TMagicRadioButton>
|
|
25
|
+
<TMagicRadioButton value="current" :disabled="!hasCurrent">与当前对比</TMagicRadioButton>
|
|
26
|
+
</TMagicRadioGroup>
|
|
27
|
+
</div>
|
|
28
|
+
</div>
|
|
29
|
+
|
|
30
|
+
<div class="m-editor-history-diff-dialog-legend">
|
|
31
|
+
<TMagicTag size="small" type="danger">{{ leftLabel }}</TMagicTag>
|
|
32
|
+
<span class="m-editor-history-diff-dialog-arrow">→</span>
|
|
33
|
+
<TMagicTag size="small" type="success">{{ rightLabel }}</TMagicTag>
|
|
34
|
+
<span v-if="mode === 'current' && isSameAsCurrent" class="m-editor-history-diff-dialog-tip">
|
|
35
|
+
当前值与该步修改后一致,无差异
|
|
36
|
+
</span>
|
|
37
|
+
</div>
|
|
38
|
+
|
|
39
|
+
<CompareForm
|
|
40
|
+
v-if="viewMode === 'form'"
|
|
41
|
+
:category="payload.category"
|
|
42
|
+
:type="payload.type"
|
|
43
|
+
:data-source-type="payload.dataSourceType"
|
|
44
|
+
:value="rightValue"
|
|
45
|
+
:last-value="leftValue"
|
|
46
|
+
:base-form-state="compareFormState"
|
|
47
|
+
:extend-state="extendState"
|
|
48
|
+
:load-config="loadConfig"
|
|
49
|
+
:self-diff-field-types="selfDiffFieldTypes"
|
|
50
|
+
:services="props.services"
|
|
51
|
+
height="70vh"
|
|
52
|
+
/>
|
|
53
|
+
|
|
54
|
+
<CodeEditor
|
|
55
|
+
v-else
|
|
56
|
+
type="diff"
|
|
57
|
+
language="json"
|
|
58
|
+
:init-values="leftValue"
|
|
59
|
+
:modified-values="rightValue"
|
|
60
|
+
:options="codeDiffOptions"
|
|
61
|
+
disabled-full-screen
|
|
62
|
+
height="70vh"
|
|
63
|
+
/>
|
|
64
|
+
</div>
|
|
65
|
+
|
|
66
|
+
<template #footer>
|
|
67
|
+
<template v-if="isConfirm">
|
|
68
|
+
<TMagicButton size="small" @click="visible = false">取消</TMagicButton>
|
|
69
|
+
<TMagicButton size="small" type="primary" @click="onConfirmClick">确定回滚</TMagicButton>
|
|
70
|
+
</template>
|
|
71
|
+
<TMagicButton v-else size="small" @click="visible = false">关闭</TMagicButton>
|
|
72
|
+
</template>
|
|
73
|
+
</TMagicDialog>
|
|
74
|
+
</template>
|
|
75
|
+
|
|
76
|
+
<script lang="ts" setup>
|
|
77
|
+
import { computed, ref, watch } from 'vue';
|
|
78
|
+
import { isEqual } from 'lodash-es';
|
|
79
|
+
|
|
80
|
+
import { TMagicButton, TMagicDialog, TMagicRadioButton, TMagicRadioGroup, TMagicTag } from '@tmagic/design';
|
|
81
|
+
import type { FormState } from '@tmagic/form';
|
|
82
|
+
|
|
83
|
+
import CompareForm from '@editor/components/CompareForm.vue';
|
|
84
|
+
import CodeEditor from '@editor/layouts/CodeEditor.vue';
|
|
85
|
+
import type { CompareCategory, CompareFormLoadConfig, DiffDialogPayload, Services } from '@editor/type';
|
|
86
|
+
|
|
87
|
+
defineOptions({
|
|
88
|
+
name: 'MEditorHistoryDiffDialog',
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
const props = withDefaults(
|
|
92
|
+
defineProps<{
|
|
93
|
+
/** 编辑器服务集合,由调用方传入(不再通过 inject('services') 获取)。 */
|
|
94
|
+
services?: Services;
|
|
95
|
+
/**
|
|
96
|
+
* 来自 Editor 顶层的 `extendFormState`,用于扩展 MForm.formState。
|
|
97
|
+
* 透传给 CompareForm,从而让差异对比时表单 item 中依赖业务上下文的
|
|
98
|
+
* `display` / `disabled` 等 filterFunction 正常工作。
|
|
99
|
+
*/
|
|
100
|
+
extendState?: (_state: FormState) => Record<string, any> | Promise<Record<string, any>>;
|
|
101
|
+
/**
|
|
102
|
+
* 自定义 FormConfig 加载逻辑,透传给 CompareForm。传入后将接管内置的按 `category`
|
|
103
|
+
* 取配置逻辑,可通过 `ctx.defaultLoadConfig()` 复用默认结果再做二次加工。
|
|
104
|
+
*/
|
|
105
|
+
loadConfig?: CompareFormLoadConfig;
|
|
106
|
+
width?: string;
|
|
107
|
+
isConfirm?: boolean;
|
|
108
|
+
onConfirm?: () => void;
|
|
109
|
+
selfDiffFieldTypes?: string[];
|
|
110
|
+
compareFormState?: FormState;
|
|
111
|
+
}>(),
|
|
112
|
+
{
|
|
113
|
+
width: '900px',
|
|
114
|
+
},
|
|
115
|
+
);
|
|
116
|
+
|
|
117
|
+
const emit = defineEmits(['close']);
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* 差异对比模式:
|
|
121
|
+
* - before:该步骤修改前 vs 该步骤修改后(默认行为,体现这一步带来的变化)
|
|
122
|
+
* - current:该步骤修改后 vs 当前最新值(用于查看「该步骤之后是否还被改过」)
|
|
123
|
+
*/
|
|
124
|
+
type DiffMode = 'before' | 'current';
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* 展示形态:
|
|
128
|
+
* - form:以属性表单形式逐字段对比(默认,可读性更好)
|
|
129
|
+
* - code:以 JSON 源码形式做整体 diff(贴近"看原始数据差异",可看到表单未覆盖的字段)
|
|
130
|
+
*/
|
|
131
|
+
type ViewMode = 'form' | 'code';
|
|
132
|
+
|
|
133
|
+
const visible = ref(false);
|
|
134
|
+
const payload = ref<DiffDialogPayload | null>(null);
|
|
135
|
+
const mode = ref<DiffMode>('before');
|
|
136
|
+
const viewMode = ref<ViewMode>('form');
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* 源码对比始终只读,关闭小地图,强制左右并排(side-by-side)展示。
|
|
140
|
+
*
|
|
141
|
+
* monaco diff 编辑器在宽度低于 `renderSideBySideInlineBreakpoint`(默认 900px)时
|
|
142
|
+
* 会自动退化为 inline(上下/单栏)视图。本弹窗宽度约 900px,去掉内边距后编辑器实际
|
|
143
|
+
* 宽度小于该阈值,会被切到 inline。这里通过 `useInlineViewWhenSpaceIsLimited: false`
|
|
144
|
+
* 关闭该自动降级,确保始终保持左右两栏对比。
|
|
145
|
+
*/
|
|
146
|
+
const codeDiffOptions = {
|
|
147
|
+
readOnly: true,
|
|
148
|
+
tabSize: 2,
|
|
149
|
+
minimap: { enabled: false },
|
|
150
|
+
renderSideBySide: true,
|
|
151
|
+
useInlineViewWhenSpaceIsLimited: false,
|
|
152
|
+
scrollBeyondLastLine: false,
|
|
153
|
+
hideUnchangedRegions: {
|
|
154
|
+
enabled: true,
|
|
155
|
+
},
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
const dialogTitle = computed(() => (props.onConfirm ? '确认回滚' : '查看修改差异'));
|
|
159
|
+
|
|
160
|
+
const hasCurrent = computed(() => payload.value?.currentValue !== undefined && payload.value?.currentValue !== null);
|
|
161
|
+
|
|
162
|
+
/** 是否存在该步「修改后的值」:不存在(如仅删除)时「与修改前对比」无意义,置灰禁用。 */
|
|
163
|
+
const hasValue = computed(() => payload.value?.value !== undefined && payload.value?.value !== null);
|
|
164
|
+
|
|
165
|
+
/** 指定模式当前是否可用:before 依赖「修改后的值」,current 依赖「当前值」。 */
|
|
166
|
+
const isModeAvailable = (m: DiffMode): boolean => (m === 'current' ? hasCurrent.value : hasValue.value);
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* 计算 open 时的初始对比模式:
|
|
170
|
+
* - 调用方通过 payload.mode 指定且该模式可用时,优先使用指定模式;
|
|
171
|
+
* - 否则没有「修改后的值」但有当前值时(「与修改前对比」不可用),默认进入「与当前对比」;
|
|
172
|
+
* - 其余情况默认「与修改前对比」。
|
|
173
|
+
*/
|
|
174
|
+
const resolveInitialMode = (specified?: DiffMode): DiffMode => {
|
|
175
|
+
if (specified && isModeAvailable(specified)) return specified;
|
|
176
|
+
return !hasValue.value && hasCurrent.value ? 'current' : 'before';
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
/** 左侧(旧/参照)值 */
|
|
180
|
+
const leftValue = computed<Record<string, any>>(() => {
|
|
181
|
+
if (!payload.value) return {};
|
|
182
|
+
if (mode.value === 'current') return payload.value.value;
|
|
183
|
+
return payload.value.lastValue;
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
/** 右侧(新/对比)值 */
|
|
187
|
+
const rightValue = computed<Record<string, any>>(() => {
|
|
188
|
+
if (!payload.value) return {};
|
|
189
|
+
if (mode.value === 'current') return payload.value.currentValue || {};
|
|
190
|
+
return payload.value.value;
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
const leftLabel = computed(() => (mode.value === 'current' ? '该步修改后' : '修改前'));
|
|
194
|
+
const rightLabel = computed(() => (mode.value === 'current' ? '当前' : '修改后'));
|
|
195
|
+
|
|
196
|
+
/** 「与当前对比」模式下,若当前值与该步修改后值相等,则展示提示 */
|
|
197
|
+
const isSameAsCurrent = computed(() => {
|
|
198
|
+
if (mode.value !== 'current' || !payload.value) return false;
|
|
199
|
+
return isEqual(payload.value.value, payload.value.currentValue);
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
/** confirm() 的 resolve,仅在「等待用户确认回滚」期间存在 */
|
|
203
|
+
let confirmResolve: ((_value: boolean) => void) | null = null;
|
|
204
|
+
|
|
205
|
+
const onConfirmClick = () => {
|
|
206
|
+
props.onConfirm?.();
|
|
207
|
+
|
|
208
|
+
// 用户确认回滚:resolve(true),并清空以避免随后 visible=false 再 resolve(false)
|
|
209
|
+
confirmResolve?.(true);
|
|
210
|
+
confirmResolve = null;
|
|
211
|
+
|
|
212
|
+
visible.value = false;
|
|
213
|
+
};
|
|
214
|
+
|
|
215
|
+
const targetText = computed(() => {
|
|
216
|
+
if (!payload.value) return '';
|
|
217
|
+
const categoryText: Record<CompareCategory, string> = {
|
|
218
|
+
node: '节点',
|
|
219
|
+
'data-source': '数据源',
|
|
220
|
+
'code-block': '代码块',
|
|
221
|
+
};
|
|
222
|
+
const { category } = payload.value;
|
|
223
|
+
const prefix = category ? categoryText[category] : '';
|
|
224
|
+
const label = payload.value.targetLabel || payload.value.type || '';
|
|
225
|
+
const { id } = payload.value;
|
|
226
|
+
const labelWithId = id !== undefined && id !== '' ? `${label}(${id})` : label;
|
|
227
|
+
return [prefix, labelWithId].filter(Boolean).join(':');
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
const open = (p: DiffDialogPayload) => {
|
|
231
|
+
payload.value = p;
|
|
232
|
+
// 每次打开按 payload 重置对比模式(hasValue / hasCurrent 依赖 payload,需先赋值):
|
|
233
|
+
// 优先使用 payload.mode 指定的模式;不可用或未指定时按数据自动推断。
|
|
234
|
+
mode.value = resolveInitialMode(p.mode);
|
|
235
|
+
// 默认回到表单对比形态,避免残留上一次选择的源码模式
|
|
236
|
+
viewMode.value = 'form';
|
|
237
|
+
visible.value = true;
|
|
238
|
+
};
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* 以 Promise 形式打开确认回滚弹窗:
|
|
242
|
+
* - 用户点击「确定回滚」时 resolve(true);
|
|
243
|
+
* - 取消 / 关闭 / 按 Esc 等其他方式关闭弹窗时 resolve(false)。
|
|
244
|
+
*
|
|
245
|
+
* 同一时刻只允许一个待确认流程,重复调用会先 resolve(false) 掉上一个。
|
|
246
|
+
*/
|
|
247
|
+
const confirm = (p: DiffDialogPayload): Promise<boolean> => {
|
|
248
|
+
// 终止上一个未完成的确认流程,避免悬挂的 Promise
|
|
249
|
+
confirmResolve?.(false);
|
|
250
|
+
confirmResolve = null;
|
|
251
|
+
|
|
252
|
+
return new Promise<boolean>((resolve) => {
|
|
253
|
+
confirmResolve = resolve;
|
|
254
|
+
open(p);
|
|
255
|
+
});
|
|
256
|
+
};
|
|
257
|
+
|
|
258
|
+
const close = () => {
|
|
259
|
+
visible.value = false;
|
|
260
|
+
};
|
|
261
|
+
|
|
262
|
+
// 关闭后清理 payload,避免下一次打开时残留旧值闪现
|
|
263
|
+
watch(visible, (v) => {
|
|
264
|
+
if (!v) {
|
|
265
|
+
payload.value = null;
|
|
266
|
+
// 非「确定回滚」方式关闭(取消 / Esc / 点遮罩等)时,resolve(false)
|
|
267
|
+
confirmResolve?.(false);
|
|
268
|
+
confirmResolve = null;
|
|
269
|
+
}
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
const onClose = () => {
|
|
273
|
+
emit('close');
|
|
274
|
+
};
|
|
275
|
+
|
|
276
|
+
defineExpose({
|
|
277
|
+
open,
|
|
278
|
+
confirm,
|
|
279
|
+
close,
|
|
280
|
+
});
|
|
281
|
+
</script>
|