@tmagic/editor 1.8.0-beta.1 → 1.8.0-beta.10
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 +287 -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 +306 -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 +10135 -5646
- 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 +273 -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 +405 -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 +594 -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 +3171 -889
- 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
package/src/fields/KeyValue.vue
CHANGED
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
></TMagicInput>
|
|
20
20
|
|
|
21
21
|
<TMagicButton
|
|
22
|
+
v-if="!isCompare"
|
|
22
23
|
class="m-fields-key-value-delete"
|
|
23
24
|
type="danger"
|
|
24
25
|
:size="size"
|
|
@@ -30,7 +31,14 @@
|
|
|
30
31
|
></TMagicButton>
|
|
31
32
|
</div>
|
|
32
33
|
|
|
33
|
-
<TMagicButton
|
|
34
|
+
<TMagicButton
|
|
35
|
+
v-if="!isCompare"
|
|
36
|
+
type="primary"
|
|
37
|
+
:size="size"
|
|
38
|
+
:disabled="disabled"
|
|
39
|
+
plain
|
|
40
|
+
:icon="Plus"
|
|
41
|
+
@click="addHandler"
|
|
34
42
|
>添加</TMagicButton
|
|
35
43
|
>
|
|
36
44
|
</div>
|
|
@@ -52,7 +60,7 @@
|
|
|
52
60
|
></MagicCodeEditor>
|
|
53
61
|
|
|
54
62
|
<TMagicButton
|
|
55
|
-
v-if="config.advanced"
|
|
63
|
+
v-if="config.advanced && !isCompare"
|
|
56
64
|
size="default"
|
|
57
65
|
:disabled="disabled"
|
|
58
66
|
link
|
|
@@ -63,11 +71,11 @@
|
|
|
63
71
|
</template>
|
|
64
72
|
|
|
65
73
|
<script setup lang="ts">
|
|
66
|
-
import { ref, watchEffect } from 'vue';
|
|
74
|
+
import { computed, inject, ref, watchEffect } from 'vue';
|
|
67
75
|
import { Delete, Plus } from '@element-plus/icons-vue';
|
|
68
76
|
|
|
69
77
|
import { TMagicButton, TMagicInput } from '@tmagic/design';
|
|
70
|
-
import type { FieldProps, KeyValueConfig } from '@tmagic/form';
|
|
78
|
+
import type { FieldProps, FormState, KeyValueConfig } from '@tmagic/form';
|
|
71
79
|
|
|
72
80
|
import CodeIcon from '@editor/icons/CodeIcon.vue';
|
|
73
81
|
import MagicCodeEditor from '@editor/layouts/CodeEditor.vue';
|
|
@@ -84,6 +92,11 @@ const emit = defineEmits<{
|
|
|
84
92
|
change: [value: Record<string, any>];
|
|
85
93
|
}>();
|
|
86
94
|
|
|
95
|
+
const mForm = inject<FormState | undefined>('mForm');
|
|
96
|
+
|
|
97
|
+
/** 对比模式下隐藏增删/代码切换等操作按钮,仅保留只读展示。 */
|
|
98
|
+
const isCompare = computed(() => Boolean(mForm?.isCompare));
|
|
99
|
+
|
|
87
100
|
const records = ref<[string, string][]>([]);
|
|
88
101
|
const showCode = ref(false);
|
|
89
102
|
|
|
@@ -4,27 +4,31 @@
|
|
|
4
4
|
<div class="border-icon-container-row">
|
|
5
5
|
<div
|
|
6
6
|
class="border-icon border-icon-top"
|
|
7
|
-
:class="{ active: direction === 'Top' }"
|
|
7
|
+
:class="{ active: direction === 'Top', configured: isConfigured('Top') }"
|
|
8
8
|
@click="selectDirection('Top')"
|
|
9
9
|
></div>
|
|
10
10
|
</div>
|
|
11
11
|
<div class="border-icon-container-row">
|
|
12
12
|
<div
|
|
13
13
|
class="border-icon border-icon-left"
|
|
14
|
-
:class="{ active: direction === 'Left' }"
|
|
14
|
+
:class="{ active: direction === 'Left', configured: isConfigured('Left') }"
|
|
15
15
|
@click="selectDirection('Left')"
|
|
16
16
|
></div>
|
|
17
|
-
<div
|
|
17
|
+
<div
|
|
18
|
+
class="border-icon"
|
|
19
|
+
:class="{ active: direction === '', configured: isConfigured('') }"
|
|
20
|
+
@click="selectDirection()"
|
|
21
|
+
></div>
|
|
18
22
|
<div
|
|
19
23
|
class="border-icon border-icon-right"
|
|
20
|
-
:class="{ active: direction === 'Right' }"
|
|
24
|
+
:class="{ active: direction === 'Right', configured: isConfigured('Right') }"
|
|
21
25
|
@click="selectDirection('Right')"
|
|
22
26
|
></div>
|
|
23
27
|
</div>
|
|
24
28
|
<div class="border-icon-container-row">
|
|
25
29
|
<div
|
|
26
30
|
class="border-icon border-icon-bottom"
|
|
27
|
-
:class="{ active: direction === 'Bottom' }"
|
|
31
|
+
:class="{ active: direction === 'Bottom', configured: isConfigured('Bottom') }"
|
|
28
32
|
@click="selectDirection('Bottom')"
|
|
29
33
|
></div>
|
|
30
34
|
</div>
|
|
@@ -98,7 +102,7 @@ const emit = defineEmits<{
|
|
|
98
102
|
addDiffCount: [];
|
|
99
103
|
}>();
|
|
100
104
|
|
|
101
|
-
withDefaults(
|
|
105
|
+
const props = withDefaults(
|
|
102
106
|
defineProps<{
|
|
103
107
|
model: FormValue;
|
|
104
108
|
lastValues?: FormValue;
|
|
@@ -109,6 +113,11 @@ withDefaults(
|
|
|
109
113
|
{},
|
|
110
114
|
);
|
|
111
115
|
|
|
116
|
+
const hasValue = (value: unknown) => value !== undefined && value !== null && value !== '';
|
|
117
|
+
|
|
118
|
+
const isConfigured = (d: string) =>
|
|
119
|
+
['Width', 'Color', 'Style'].some((key) => hasValue(props.model?.[`border${d}${key}`]));
|
|
120
|
+
|
|
112
121
|
const change = (value: StyleSchema, eventData: ContainerChangeEventData) => {
|
|
113
122
|
eventData.changeRecords?.forEach((record) => {
|
|
114
123
|
emit('change', record.value, {
|
package/src/fields/UISelect.vue
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
</div>
|
|
7
7
|
<div class="m-fields-ui-select" v-else style="display: flex">
|
|
8
8
|
<template v-if="val">
|
|
9
|
-
<TMagicTooltip content="清除" placement="top">
|
|
9
|
+
<TMagicTooltip v-if="!isCompare" content="清除" placement="top">
|
|
10
10
|
<TMagicButton
|
|
11
11
|
style="padding: 0"
|
|
12
12
|
type="danger"
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
</TMagicTooltip>
|
|
33
33
|
</template>
|
|
34
34
|
|
|
35
|
-
<TMagicTooltip v-else content="点击此处选择" placement="top">
|
|
35
|
+
<TMagicTooltip v-else-if="!isCompare" content="点击此处选择" placement="top">
|
|
36
36
|
<TMagicButton link style="padding: 0; margin: 0" :disabled="disabled" :size="size" @click="startSelect"
|
|
37
37
|
>点击此处选择</TMagicButton
|
|
38
38
|
>
|
|
@@ -67,6 +67,9 @@ const mForm = inject<FormState>('mForm');
|
|
|
67
67
|
const val = computed(() => props.model[props.name]);
|
|
68
68
|
const uiSelectMode = ref(false);
|
|
69
69
|
|
|
70
|
+
/** 对比模式下隐藏清除/选择等操作按钮,仅保留只读展示。 */
|
|
71
|
+
const isCompare = computed(() => Boolean(mForm?.isCompare));
|
|
72
|
+
|
|
70
73
|
const cancelHandler = () => {
|
|
71
74
|
uiService.set('uiSelectMode', false);
|
|
72
75
|
uiSelectMode.value = false;
|
|
@@ -3,9 +3,10 @@ import { cloneDeep } from 'lodash-es';
|
|
|
3
3
|
|
|
4
4
|
import type { CodeBlockContent } from '@tmagic/core';
|
|
5
5
|
import { tMagicMessage } from '@tmagic/design';
|
|
6
|
+
import type { ContainerChangeEventData } from '@tmagic/form';
|
|
6
7
|
|
|
7
8
|
import CodeBlockEditor from '@editor/components/CodeBlockEditor.vue';
|
|
8
|
-
import type { Services } from '@editor/type';
|
|
9
|
+
import type { HistoryOpSource, Services } from '@editor/type';
|
|
9
10
|
|
|
10
11
|
export const useCodeBlockEdit = (codeBlockService: Services['codeBlockService']) => {
|
|
11
12
|
const codeConfig = ref<Omit<CodeBlockContent, 'content'> & { content: string }>();
|
|
@@ -57,14 +58,17 @@ export const useCodeBlockEdit = (codeBlockService: Services['codeBlockService'])
|
|
|
57
58
|
};
|
|
58
59
|
|
|
59
60
|
// 删除代码块
|
|
60
|
-
const deleteCode = async (key: string) => {
|
|
61
|
-
codeBlockService.deleteCodeDslByIds([key]);
|
|
61
|
+
const deleteCode = async (key: string, { historySource }: { historySource?: HistoryOpSource } = {}) => {
|
|
62
|
+
codeBlockService.deleteCodeDslByIds([key], { historySource });
|
|
62
63
|
};
|
|
63
64
|
|
|
64
|
-
const submitCodeBlockHandler = async (values: CodeBlockContent) => {
|
|
65
|
+
const submitCodeBlockHandler = async (values: CodeBlockContent, eventData?: ContainerChangeEventData) => {
|
|
65
66
|
if (!codeId.value) return;
|
|
66
67
|
|
|
67
|
-
await codeBlockService.setCodeDslById(codeId.value, values
|
|
68
|
+
await codeBlockService.setCodeDslById(codeId.value, values, {
|
|
69
|
+
changeRecords: eventData?.changeRecords,
|
|
70
|
+
historySource: 'props',
|
|
71
|
+
});
|
|
68
72
|
|
|
69
73
|
codeBlockEditorRef.value?.hide();
|
|
70
74
|
};
|
|
@@ -27,9 +27,9 @@ export const useDataSourceEdit = (dataSourceService: Services['dataSourceService
|
|
|
27
27
|
|
|
28
28
|
const submitDataSourceHandler = (value: DataSourceSchema, eventData: ContainerChangeEventData) => {
|
|
29
29
|
if (value.id) {
|
|
30
|
-
dataSourceService.update(value, { changeRecords: eventData.changeRecords });
|
|
30
|
+
dataSourceService.update(value, { changeRecords: eventData.changeRecords, historySource: 'props' });
|
|
31
31
|
} else {
|
|
32
|
-
dataSourceService.add(value);
|
|
32
|
+
dataSourceService.add(value, { historySource: 'props' });
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
editDialog.value?.hide();
|
package/src/hooks/use-stage.ts
CHANGED
|
@@ -48,6 +48,7 @@ export const useStage = (stageOptions: StageOptions) => {
|
|
|
48
48
|
disabledMultiSelect: stageOptions.disabledMultiSelect,
|
|
49
49
|
alwaysMultiSelect: stageOptions.alwaysMultiSelect,
|
|
50
50
|
disabledRule: stageOptions.disabledRule,
|
|
51
|
+
disabledFlashTip: stageOptions.disabledFlashTip,
|
|
51
52
|
});
|
|
52
53
|
|
|
53
54
|
watch(
|
|
@@ -97,32 +98,48 @@ export const useStage = (stageOptions: StageOptions) => {
|
|
|
97
98
|
|
|
98
99
|
stage.on('update', (ev: UpdateEventData) => {
|
|
99
100
|
if (ev.parentEl) {
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
101
|
+
// 拖动多选元素到一个新容器:整批合成一次 moveToContainer,只产生一条历史记录
|
|
102
|
+
const pId = getIdFromEl()(ev.parentEl);
|
|
103
|
+
if (!pId) return;
|
|
104
|
+
const configs = ev.data
|
|
105
|
+
.map((data) => {
|
|
106
|
+
const id = getIdFromEl()(data.el);
|
|
107
|
+
if (!id) return null;
|
|
108
|
+
const cfg: MNode = { id, style: data.style };
|
|
109
|
+
return cfg;
|
|
110
|
+
})
|
|
111
|
+
.filter((cfg): cfg is MNode => Boolean(cfg));
|
|
112
|
+
if (configs.length > 0) {
|
|
113
|
+
editorService.moveToContainer(configs, pId);
|
|
104
114
|
}
|
|
105
115
|
return;
|
|
106
116
|
}
|
|
107
117
|
|
|
108
|
-
//
|
|
118
|
+
// 多选拖动 / 多选缩放:所有元素整批走一次 update,避免历史栈被切成 N 条
|
|
119
|
+
// changeRecordList 与 configs 同序,每个节点保留自己的 records;
|
|
120
|
+
// 不能把多个节点的 records 合并到同一个数组里,否则 doUpdate / nodeUpdateHandler 会把别的节点的 propPath 当成自己的。
|
|
121
|
+
const configs: MNode[] = [];
|
|
122
|
+
const changeRecordList: ReturnType<typeof buildChangeRecords>[] = [];
|
|
109
123
|
ev.data.forEach((data) => {
|
|
110
124
|
const id = getIdFromEl()(data.el);
|
|
111
125
|
if (!id) return;
|
|
112
126
|
|
|
113
127
|
const { style = {} } = data;
|
|
114
|
-
|
|
115
|
-
|
|
128
|
+
configs.push({ id, style });
|
|
129
|
+
changeRecordList.push(buildChangeRecords(style, 'style'));
|
|
116
130
|
});
|
|
131
|
+
if (configs.length === 0) return;
|
|
132
|
+
|
|
133
|
+
editorService.update(configs, { changeRecordList, historySource: 'stage' });
|
|
117
134
|
});
|
|
118
135
|
|
|
119
136
|
stage.on('sort', (ev: SortEventData) => {
|
|
120
|
-
editorService.sort(ev.src, ev.dist);
|
|
137
|
+
editorService.sort(ev.src, ev.dist, { historySource: 'stage' });
|
|
121
138
|
});
|
|
122
139
|
|
|
123
140
|
stage.on('remove', (ev: RemoveEventData) => {
|
|
124
141
|
const nodes = ev.data.map(({ el }) => editorService.getNodeById(getIdFromEl()(el) || ''));
|
|
125
|
-
editorService.remove(nodes.filter((node) => Boolean(node)) as MNode[]);
|
|
142
|
+
editorService.remove(nodes.filter((node) => Boolean(node)) as MNode[], { historySource: 'stage' });
|
|
126
143
|
});
|
|
127
144
|
|
|
128
145
|
stage.on('select-parent', () => {
|
package/src/index.ts
CHANGED
|
@@ -44,6 +44,8 @@ export { default as stageOverlayService } from './services/stageOverlay';
|
|
|
44
44
|
export { default as uiService } from './services/ui';
|
|
45
45
|
export { default as codeBlockService } from './services/codeBlock';
|
|
46
46
|
export { default as depService } from './services/dep';
|
|
47
|
+
export { default as componentListService } from './services/componentList';
|
|
48
|
+
export { default as keybindingService } from './services/keybinding';
|
|
47
49
|
export { default as ComponentListPanel } from './layouts/sidebar/ComponentListPanel.vue';
|
|
48
50
|
export { default as LayerPanel } from './layouts/sidebar/layer/LayerPanel.vue';
|
|
49
51
|
export { default as CodeSelect } from './fields/CodeSelect.vue';
|
|
@@ -70,6 +72,12 @@ export { default as LayoutContainer } from './components/SplitView.vue';
|
|
|
70
72
|
export { default as SplitView } from './components/SplitView.vue';
|
|
71
73
|
export { default as Resizer } from './components/Resizer.vue';
|
|
72
74
|
export { default as CodeBlockEditor } from './components/CodeBlockEditor.vue';
|
|
75
|
+
export { default as CompareForm } from './components/CompareForm.vue';
|
|
76
|
+
export { default as HistoryListBucket } from './layouts/history-list/Bucket.vue';
|
|
77
|
+
export { default as HistoryListBucketTab } from './layouts/history-list/BucketTab.vue';
|
|
78
|
+
export { default as HistoryDiffDialog } from './layouts/history-list/HistoryDiffDialog.vue';
|
|
79
|
+
export { confirmHistoryAction } from './layouts/history-list/composables';
|
|
80
|
+
export { useHistoryRevert } from './layouts/history-list/useHistoryRevert';
|
|
73
81
|
export { default as FloatingBox } from './components/FloatingBox.vue';
|
|
74
82
|
export { default as Tree } from './components/Tree.vue';
|
|
75
83
|
export { default as TreeNode } from './components/TreeNode.vue';
|
package/src/initService.ts
CHANGED
|
@@ -21,12 +21,12 @@ import { computed, nextTick, onBeforeUnmount, onMounted, onUnmounted, ref, useTe
|
|
|
21
21
|
import { FullScreen } from '@element-plus/icons-vue';
|
|
22
22
|
import { throttle } from 'lodash-es';
|
|
23
23
|
import type * as Monaco from 'monaco-editor';
|
|
24
|
-
import serialize from 'serialize-javascript';
|
|
25
24
|
|
|
26
25
|
import { TMagicButton } from '@tmagic/design';
|
|
27
26
|
|
|
28
27
|
import MIcon from '@editor/components/Icon.vue';
|
|
29
28
|
import { getEditorConfig } from '@editor/utils/config';
|
|
29
|
+
import { serializeConfig } from '@editor/utils/editor';
|
|
30
30
|
import loadMonaco from '@editor/utils/monaco-editor';
|
|
31
31
|
|
|
32
32
|
defineOptions({
|
|
@@ -163,10 +163,7 @@ const toString = (v: string | any, language: string): string => {
|
|
|
163
163
|
if (language === 'json') {
|
|
164
164
|
value = JSON.stringify(v, null, 2);
|
|
165
165
|
} else {
|
|
166
|
-
value =
|
|
167
|
-
space: 2,
|
|
168
|
-
unsafe: true,
|
|
169
|
-
}).replace(/"(\w+)":\s/g, '$1: ');
|
|
166
|
+
value = serializeConfig(v);
|
|
170
167
|
}
|
|
171
168
|
} else {
|
|
172
169
|
value = v;
|
|
@@ -330,6 +327,21 @@ watch(
|
|
|
330
327
|
},
|
|
331
328
|
);
|
|
332
329
|
|
|
330
|
+
// diff 模式下,对比的"当前值"(modifiedValues)也可能在外部变化(例如 lastValues 不变、当前 model 变了),
|
|
331
|
+
// 此时同样需要重新设置编辑器值,否则右侧编辑器内容会停留在初始化时的快照。
|
|
332
|
+
watch(
|
|
333
|
+
() => props.modifiedValues,
|
|
334
|
+
(v, preV) => {
|
|
335
|
+
if (props.type !== 'diff') return;
|
|
336
|
+
if (v !== preV) {
|
|
337
|
+
setEditorValue(props.initValues, props.modifiedValues);
|
|
338
|
+
}
|
|
339
|
+
},
|
|
340
|
+
{
|
|
341
|
+
deep: true,
|
|
342
|
+
},
|
|
343
|
+
);
|
|
344
|
+
|
|
333
345
|
watch(
|
|
334
346
|
() => props.options,
|
|
335
347
|
(v) => {
|
|
@@ -23,15 +23,15 @@
|
|
|
23
23
|
left-class="m-editor-framework-left"
|
|
24
24
|
center-class="m-editor-framework-center"
|
|
25
25
|
right-class="m-editor-framework-right"
|
|
26
|
-
:left="columnWidth.left"
|
|
26
|
+
:left="hideSidebar ? undefined : columnWidth.left"
|
|
27
27
|
:right="columnWidth.right"
|
|
28
|
-
:min-left="MIN_LEFT_COLUMN_WIDTH"
|
|
28
|
+
:min-left="hideSidebar ? 0 : MIN_LEFT_COLUMN_WIDTH"
|
|
29
29
|
:min-right="MIN_RIGHT_COLUMN_WIDTH"
|
|
30
30
|
:min-center="MIN_CENTER_COLUMN_WIDTH"
|
|
31
31
|
:width="frameworkRect.width"
|
|
32
32
|
@change="columnWidthChange"
|
|
33
33
|
>
|
|
34
|
-
<template #left>
|
|
34
|
+
<template v-if="!hideSidebar" #left>
|
|
35
35
|
<slot name="sidebar"></slot>
|
|
36
36
|
</template>
|
|
37
37
|
|
|
@@ -94,10 +94,12 @@ defineOptions({
|
|
|
94
94
|
name: 'MEditorFramework',
|
|
95
95
|
});
|
|
96
96
|
|
|
97
|
-
defineProps<{
|
|
97
|
+
const props = defineProps<{
|
|
98
98
|
disabledPageFragment: boolean;
|
|
99
99
|
pageBarSortOptions?: PageBarSortOptions;
|
|
100
100
|
pageFilterFunction?: (_page: MPage | MPageFragment, _keyword: string) => boolean;
|
|
101
|
+
/** 是否隐藏左侧面板 */
|
|
102
|
+
hideSidebar?: boolean;
|
|
101
103
|
}>();
|
|
102
104
|
|
|
103
105
|
const codeOptions = inject('codeOptions', {});
|
|
@@ -132,7 +134,10 @@ watch(
|
|
|
132
134
|
);
|
|
133
135
|
|
|
134
136
|
const columnWidthChange = (columnW: GetColumnWidth) => {
|
|
135
|
-
|
|
137
|
+
// 隐藏左侧面板时 left 恒为 0,不覆盖已持久化的左栏宽度,避免重新展示时丢失宽度
|
|
138
|
+
if (!props.hideSidebar) {
|
|
139
|
+
storageService.setItem(LEFT_COLUMN_WIDTH_STORAGE_KEY, columnW.left, { protocol: Protocol.NUMBER });
|
|
140
|
+
}
|
|
136
141
|
storageService.setItem(RIGHT_COLUMN_WIDTH_STORAGE_KEY, columnW.right, { protocol: Protocol.NUMBER });
|
|
137
142
|
|
|
138
143
|
uiService.set('columnWidth', columnW);
|
|
@@ -163,7 +168,7 @@ onBeforeUnmount(() => {
|
|
|
163
168
|
const saveCode = (value: string) => {
|
|
164
169
|
try {
|
|
165
170
|
const parseDSL = getEditorConfig('parseDSL');
|
|
166
|
-
editorService.set('root', parseDSL(value));
|
|
171
|
+
editorService.set('root', parseDSL(value), { historySource: 'root-code' });
|
|
167
172
|
} catch (e: any) {
|
|
168
173
|
console.error(e);
|
|
169
174
|
}
|
package/src/layouts/NavMenu.vue
CHANGED
|
@@ -19,6 +19,7 @@ import { NodeType } from '@tmagic/core';
|
|
|
19
19
|
import { useServices } from '@editor/hooks/use-services';
|
|
20
20
|
import { ColumnLayout, MenuBarData, MenuButton, MenuComponent, MenuItem } from '@editor/type';
|
|
21
21
|
|
|
22
|
+
import HistoryListPanel from './history-list/HistoryListPanel.vue';
|
|
22
23
|
import NavMenuColumn from './NavMenuColumn.vue';
|
|
23
24
|
|
|
24
25
|
defineOptions({
|
|
@@ -79,7 +80,7 @@ const getConfig = (item: MenuItem): (MenuButton | MenuComponent)[] => {
|
|
|
79
80
|
disabled: () => editorService.get('node')?.type === NodeType.PAGE,
|
|
80
81
|
handler: () => {
|
|
81
82
|
const node = editorService.get('node');
|
|
82
|
-
node && editorService.remove(node);
|
|
83
|
+
node && editorService.remove(node, { historySource: 'toolbar' });
|
|
83
84
|
},
|
|
84
85
|
});
|
|
85
86
|
break;
|
|
@@ -89,7 +90,7 @@ const getConfig = (item: MenuItem): (MenuButton | MenuComponent)[] => {
|
|
|
89
90
|
className: 'undo',
|
|
90
91
|
icon: markRaw(Back),
|
|
91
92
|
tooltip: `后退(${ctrl}+z)`,
|
|
92
|
-
disabled: () => !historyService.
|
|
93
|
+
disabled: () => !historyService.canUndo('page', editorService.get('page')?.id),
|
|
93
94
|
handler: () => editorService.undo(),
|
|
94
95
|
});
|
|
95
96
|
break;
|
|
@@ -99,10 +100,18 @@ const getConfig = (item: MenuItem): (MenuButton | MenuComponent)[] => {
|
|
|
99
100
|
className: 'redo',
|
|
100
101
|
icon: markRaw(Right),
|
|
101
102
|
tooltip: `前进(${ctrl}+Shift+z)`,
|
|
102
|
-
disabled: () => !historyService.
|
|
103
|
+
disabled: () => !historyService.canRedo('page', editorService.get('page')?.id),
|
|
103
104
|
handler: () => editorService.redo(),
|
|
104
105
|
});
|
|
105
106
|
break;
|
|
107
|
+
case 'history-list':
|
|
108
|
+
// 历史记录面板:以 component 形式挂入,自带 popover;点击 nav 上的图标弹出。
|
|
109
|
+
config.push({
|
|
110
|
+
type: 'component',
|
|
111
|
+
className: 'history-list',
|
|
112
|
+
component: markRaw(HistoryListPanel),
|
|
113
|
+
});
|
|
114
|
+
break;
|
|
106
115
|
case 'zoom-in':
|
|
107
116
|
config.push({
|
|
108
117
|
type: 'button',
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="m-editor-history-list-bucket">
|
|
3
|
+
<div class="m-editor-history-list-bucket-title">
|
|
4
|
+
<span>{{ config.title }}</span>
|
|
5
|
+
<code>{{ String(bucketId) }}</code>
|
|
6
|
+
<span class="m-editor-history-list-bucket-count">{{ groups.length }} 组</span>
|
|
7
|
+
</div>
|
|
8
|
+
|
|
9
|
+
<ul class="m-editor-history-list-ul">
|
|
10
|
+
<GroupRow
|
|
11
|
+
v-for="group in groups"
|
|
12
|
+
:key="rowKey(group)"
|
|
13
|
+
:group="toRow(group)"
|
|
14
|
+
:expanded="isHistoryGroupExpanded(expanded, rowKey(group))"
|
|
15
|
+
:goto-enabled="config.gotoEnabled"
|
|
16
|
+
@toggle="(key: string) => $emit('toggle', key)"
|
|
17
|
+
@goto="(index: number) => $emit('goto', bucketId, index)"
|
|
18
|
+
@diff-step="(index: number) => $emit('diff-step', bucketId, index)"
|
|
19
|
+
@revert-step="(index: number) => $emit('revert-step', bucketId, index)"
|
|
20
|
+
/>
|
|
21
|
+
<!--
|
|
22
|
+
初始状态项:永远位于该 bucket 列表底部(同样按倒序展示,最底部 = 最早状态)。
|
|
23
|
+
当 bucket 内所有 group 都未 applied 时即为当前位置。
|
|
24
|
+
config.showInitial=false 时不展示(用于没有"撤销到初始状态"语义的自定义历史,如业务模块历史)。
|
|
25
|
+
-->
|
|
26
|
+
<InitialRow
|
|
27
|
+
v-if="config.showInitial !== false"
|
|
28
|
+
:is-current="isInitial"
|
|
29
|
+
:goto-enabled="config.gotoEnabled"
|
|
30
|
+
@goto-initial="$emit('goto-initial', bucketId)"
|
|
31
|
+
/>
|
|
32
|
+
</ul>
|
|
33
|
+
</div>
|
|
34
|
+
</template>
|
|
35
|
+
|
|
36
|
+
<script lang="ts" setup generic="T extends BaseStepValue = BaseStepValue">
|
|
37
|
+
import { computed } from 'vue';
|
|
38
|
+
|
|
39
|
+
import type { BaseStepValue, HistoryBucketConfig } from '@editor/type';
|
|
40
|
+
|
|
41
|
+
import type { HistoryBucketGroup, HistoryRowGroup } from './composables';
|
|
42
|
+
import { isHistoryGroupExpanded, toRowGroup } from './composables';
|
|
43
|
+
import GroupRow from './GroupRow.vue';
|
|
44
|
+
import InitialRow from './InitialRow.vue';
|
|
45
|
+
|
|
46
|
+
defineOptions({
|
|
47
|
+
name: 'MEditorHistoryListBucket',
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
const props = defineProps<{
|
|
51
|
+
/**
|
|
52
|
+
* 该类历史的整体渲染配置(title / prefix / describe* / isStep* / showInitial / gotoEnabled)。
|
|
53
|
+
* 由父组件按业务类型注入,组件内部按需读取,避免逐项透传多个 props。
|
|
54
|
+
*/
|
|
55
|
+
config: HistoryBucketConfig<T>;
|
|
56
|
+
/** 当前 bucket 对应的目标 id(dataSource.id 或 codeBlock.id),同时用于组装子项的 key。 */
|
|
57
|
+
bucketId: string | number;
|
|
58
|
+
/** 当前 bucket 下的所有历史分组,按时间倒序展示(最近的操作在前)。 */
|
|
59
|
+
groups: HistoryBucketGroup<T>[];
|
|
60
|
+
/** 共享的折叠状态表(key -> 是否展开,缺省或 true 为展开、false 为收起),由顶层 panel 统一维护以便跨 tab 复用。 */
|
|
61
|
+
expanded: Record<string, boolean>;
|
|
62
|
+
}>();
|
|
63
|
+
|
|
64
|
+
defineEmits<{
|
|
65
|
+
/** 透传子组件 GroupRow 的 toggle,由上层 panel 更新 expanded。 */
|
|
66
|
+
(_e: 'toggle', _key: string): void;
|
|
67
|
+
/**
|
|
68
|
+
* 透传子组件 GroupRow 的 goto,并附带当前 bucket 对应的 id(dataSourceId / codeBlockId),
|
|
69
|
+
* 上层据此调用对应 service.goto(id, targetCursor)。
|
|
70
|
+
*/
|
|
71
|
+
(_e: 'goto', _bucketId: string | number, _index: number): void;
|
|
72
|
+
/** 用户点击初始项希望该 bucket 回到未修改状态;携带 bucketId 用于上层路由到正确的 service。 */
|
|
73
|
+
(_e: 'goto-initial', _bucketId: string | number): void;
|
|
74
|
+
/** 用户点击"查看差异",携带 bucketId 与 step 索引。 */
|
|
75
|
+
(_e: 'diff-step', _bucketId: string | number, _index: number): void;
|
|
76
|
+
/** 用户点击"回滚"按钮,携带 bucketId 与 step 索引,类 git revert。 */
|
|
77
|
+
(_e: 'revert-step', _bucketId: string | number, _index: number): void;
|
|
78
|
+
}>();
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* 子项 / 折叠状态 key:`${prefix}-${bucketId}-${组内首步 index}`。
|
|
82
|
+
* 以稳定的 step 索引(而非展示位置)标识分组,历史数据更新后已展开的分组状态仍能正确保持。
|
|
83
|
+
*/
|
|
84
|
+
const rowKey = (group: HistoryBucketGroup<T>) => `${props.config.prefix}-${props.bucketId}-${group.steps[0]?.index}`;
|
|
85
|
+
|
|
86
|
+
/** 把原始分组派生为 GroupRow 直接消费的视图模型。 */
|
|
87
|
+
const toRow = (group: HistoryBucketGroup<T>): HistoryRowGroup => toRowGroup(group, rowKey(group), props.config);
|
|
88
|
+
|
|
89
|
+
/** 该 bucket 是否处于初始状态(栈 cursor=0),等价于全部 group 都未 applied。 */
|
|
90
|
+
const isInitial = computed(() => props.groups.length > 0 && props.groups.every((g) => !g.applied));
|
|
91
|
+
</script>
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div v-if="!buckets.length" class="m-editor-history-list-empty">暂无操作记录</div>
|
|
3
|
+
<template v-else>
|
|
4
|
+
<div v-if="config.showClear !== false" class="m-editor-history-list-toolbar">
|
|
5
|
+
<span class="m-editor-history-list-clear" :title="`清空${config.title}的历史记录`" @click="$emit('clear')"
|
|
6
|
+
>清空</span
|
|
7
|
+
>
|
|
8
|
+
</div>
|
|
9
|
+
<TMagicScrollbar max-height="360px">
|
|
10
|
+
<Bucket
|
|
11
|
+
v-for="bucket in buckets"
|
|
12
|
+
:key="`${config.prefix}-${bucket.id}`"
|
|
13
|
+
:config="config"
|
|
14
|
+
:bucket-id="bucket.id"
|
|
15
|
+
:groups="bucket.groups"
|
|
16
|
+
:expanded="expanded"
|
|
17
|
+
@toggle="(key: string) => $emit('toggle', key)"
|
|
18
|
+
@goto="(id: string | number, index: number) => $emit('goto', id, index)"
|
|
19
|
+
@goto-initial="(id: string | number) => $emit('goto-initial', id)"
|
|
20
|
+
@diff-step="(id: string | number, index: number) => $emit('diff-step', id, index)"
|
|
21
|
+
@revert-step="(id: string | number, index: number) => $emit('revert-step', id, index)"
|
|
22
|
+
/>
|
|
23
|
+
</TMagicScrollbar>
|
|
24
|
+
</template>
|
|
25
|
+
</template>
|
|
26
|
+
|
|
27
|
+
<script lang="ts" setup generic="T extends BaseStepValue = BaseStepValue">
|
|
28
|
+
import { TMagicScrollbar } from '@tmagic/design';
|
|
29
|
+
|
|
30
|
+
import type { BaseStepValue, HistoryBucketConfig } from '@editor/type';
|
|
31
|
+
|
|
32
|
+
import Bucket from './Bucket.vue';
|
|
33
|
+
import type { HistoryBucketGroup } from './composables';
|
|
34
|
+
|
|
35
|
+
defineOptions({
|
|
36
|
+
name: 'MEditorHistoryListBucketTab',
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
defineProps<{
|
|
40
|
+
/**
|
|
41
|
+
* 该类历史的整体渲染配置(title / prefix / describe* / isStep* / showInitial / gotoEnabled / showClear),
|
|
42
|
+
* 由父组件按业务类型注入并整体透传给 Bucket,避免逐项透传多个 props。
|
|
43
|
+
*/
|
|
44
|
+
config: HistoryBucketConfig<T>;
|
|
45
|
+
/**
|
|
46
|
+
* 已按目标 id 聚拢成的 bucket 列表,每个 bucket 内部的 groups 已按时间倒序排好。
|
|
47
|
+
* 空数组时显示空态。
|
|
48
|
+
*/
|
|
49
|
+
buckets: { id: string | number; groups: HistoryBucketGroup<T>[] }[];
|
|
50
|
+
/**
|
|
51
|
+
* 共享的折叠状态表(key -> 是否展开),由顶层 panel 统一维护。
|
|
52
|
+
* key 形如 `${prefix}-${id}-${组内首步 index}`——以稳定的 step 索引而非展示位置标识分组,
|
|
53
|
+
* 这样历史数据更新后已展开的分组状态仍能正确保持。
|
|
54
|
+
*/
|
|
55
|
+
expanded: Record<string, boolean>;
|
|
56
|
+
}>();
|
|
57
|
+
|
|
58
|
+
defineEmits<{
|
|
59
|
+
/** 透传子组件 Bucket 的 toggle 事件给上层 panel,由其更新 expanded。 */
|
|
60
|
+
(_e: 'toggle', _key: string): void;
|
|
61
|
+
/** 透传 Bucket 的 goto 事件,携带目标 id 与目标 step 索引。 */
|
|
62
|
+
(_e: 'goto', _targetId: string | number, _index: number): void;
|
|
63
|
+
/** 透传 Bucket 的 goto-initial 事件,携带目标 id(回到该目标未修改时的状态)。 */
|
|
64
|
+
(_e: 'goto-initial', _targetId: string | number): void;
|
|
65
|
+
/** 透传 Bucket 的 diff-step 事件,携带目标 id 与 step 索引。 */
|
|
66
|
+
(_e: 'diff-step', _targetId: string | number, _index: number): void;
|
|
67
|
+
/** 透传 Bucket 的 revert-step 事件,携带目标 id 与 step 索引(类 git revert)。 */
|
|
68
|
+
(_e: 'revert-step', _targetId: string | number, _index: number): void;
|
|
69
|
+
/** 用户点击"清空"按钮,请求清空该类(数据源 / 代码块)的全部历史记录(由上层弹窗二次确认后执行)。 */
|
|
70
|
+
(_e: 'clear'): void;
|
|
71
|
+
}>();
|
|
72
|
+
</script>
|