@tmagic/editor 1.8.0-beta.13 → 1.8.0-beta.15
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 +15 -3
- package/dist/es/components/ContentMenu.vue_vue_type_script_setup_true_lang.js +31 -8
- package/dist/es/components/FloatingBox.vue_vue_type_script_setup_true_lang.js +7 -2
- package/dist/es/fields/Code.vue_vue_type_script_setup_true_lang.js +15 -4
- package/dist/es/fields/CodeLink.vue_vue_type_script_setup_true_lang.js +4 -1
- package/dist/es/fields/CodeSelect.vue_vue_type_script_setup_true_lang.js +80 -55
- package/dist/es/fields/CodeSelectCol.vue_vue_type_script_setup_true_lang.js +5 -1
- package/dist/es/fields/CondOpSelect.vue_vue_type_script_setup_true_lang.js +4 -1
- package/dist/es/fields/DataSourceFieldSelect/Index.vue_vue_type_script_setup_true_lang.js +10 -7
- package/dist/es/fields/DataSourceFields.vue_vue_type_script_setup_true_lang.js +4 -1
- package/dist/es/fields/DataSourceInput.vue_vue_type_script_setup_true_lang.js +4 -1
- package/dist/es/fields/DataSourceMethodSelect.vue_vue_type_script_setup_true_name_true_lang.js +4 -1
- package/dist/es/fields/DataSourceMethods.vue_vue_type_script_setup_true_lang.js +4 -1
- package/dist/es/fields/DataSourceMocks.vue_vue_type_script_setup_true_lang.js +4 -1
- package/dist/es/fields/DataSourceSelect.vue_vue_type_script_setup_true_lang.js +4 -1
- package/dist/es/fields/DisplayConds.vue_vue_type_script_setup_true_lang.js +8 -2
- package/dist/es/fields/EventSelect.vue_vue_type_script_setup_true_lang.js +99 -64
- package/dist/es/fields/KeyValue.vue_vue_type_script_setup_true_lang.js +4 -1
- package/dist/es/fields/PageFragmentSelect.vue_vue_type_script_setup_true_lang.js +4 -1
- package/dist/es/fields/StyleSetter/Index.vue_vue_type_script_setup_true_lang.js +5 -4
- package/dist/es/fields/StyleSetter/components/BackgroundPosition.vue_vue_type_script_setup_true_lang.js +4 -1
- package/dist/es/fields/StyleSetter/components/Border.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/es/fields/StyleSetter/icons/align-items/Center.js +31 -0
- package/dist/es/fields/StyleSetter/icons/align-items/FlexEnd.js +31 -0
- package/dist/es/fields/StyleSetter/icons/align-items/FlexStart.js +31 -0
- package/dist/es/fields/StyleSetter/icons/align-items/SpaceAround.js +50 -0
- package/dist/es/fields/StyleSetter/icons/align-items/SpaceBetween.js +50 -0
- package/dist/es/fields/StyleSetter/icons/background-repeat/NoRepeat.js +6 -6
- package/dist/es/fields/StyleSetter/icons/background-repeat/Repeat.js +5 -2
- package/dist/es/fields/StyleSetter/icons/background-repeat/RepeatX.js +28 -5
- package/dist/es/fields/StyleSetter/icons/background-repeat/RepeatY.js +31 -5
- package/dist/es/fields/StyleSetter/icons/flex-direction/Column.js +10 -2
- package/dist/es/fields/StyleSetter/icons/flex-direction/ColumnReverse.js +10 -2
- package/dist/es/fields/StyleSetter/icons/flex-direction/Row.js +10 -2
- package/dist/es/fields/StyleSetter/icons/flex-direction/RowReverse.js +10 -2
- package/dist/es/fields/StyleSetter/icons/justify-content/Center.js +16 -2
- package/dist/es/fields/StyleSetter/icons/justify-content/FlexEnd.js +18 -2
- package/dist/es/fields/StyleSetter/icons/justify-content/FlexStart.js +18 -2
- package/dist/es/fields/StyleSetter/icons/justify-content/SpaceAround.js +36 -2
- package/dist/es/fields/StyleSetter/icons/justify-content/SpaceBetween.js +32 -2
- package/dist/es/fields/StyleSetter/pro/Background.vue_vue_type_script_setup_true_lang.js +7 -6
- package/dist/es/fields/StyleSetter/pro/Font.vue_vue_type_script_setup_true_lang.js +6 -3
- package/dist/es/fields/StyleSetter/pro/Layout.vue_vue_type_script_setup_true_lang.js +47 -25
- package/dist/es/fields/UISelect.vue_vue_type_script_setup_true_lang.js +4 -1
- package/dist/es/icons/DatasourceIcon.js +17 -0
- package/dist/es/index.js +2 -2
- package/dist/es/layouts/Framework.vue_vue_type_script_setup_true_lang.js +14 -10
- package/dist/es/layouts/props-panel/PropsPanel.vue_vue_type_script_setup_true_lang.js +13 -4
- package/dist/es/layouts/sidebar/Sidebar.vue_vue_type_script_setup_true_lang.js +3 -3
- package/dist/es/plugin.js +2 -1
- package/dist/es/services/editor.js +86 -24
- package/dist/es/services/history.js +16 -0
- package/dist/es/services/ui.js +5 -3
- package/dist/es/style.css +307 -40
- package/dist/es/utils/config.js +4 -1
- package/dist/es/utils/const.js +2 -2
- package/dist/es/utils/data-source/index.js +4 -2
- package/dist/es/utils/props.js +43 -29
- package/dist/es/utils/type-match-rules.js +12 -5
- package/dist/style.css +307 -40
- package/dist/themes/magic-admin.css +3004 -0
- package/dist/tmagic-editor.umd.cjs +1161 -476
- package/package.json +7 -7
- package/src/Editor.vue +22 -1
- package/src/components/ContentMenu.vue +44 -8
- package/src/components/FloatingBox.vue +8 -2
- package/src/editorProps.ts +4 -0
- package/src/fields/Code.vue +10 -2
- package/src/fields/CodeSelect.vue +54 -43
- package/src/fields/CodeSelectCol.vue +1 -0
- package/src/fields/DataSourceFieldSelect/Index.vue +14 -5
- package/src/fields/DisplayConds.vue +4 -1
- package/src/fields/EventSelect.vue +56 -32
- package/src/fields/StyleSetter/Index.vue +1 -4
- package/src/fields/StyleSetter/components/Border.vue +1 -1
- package/src/fields/StyleSetter/icons/align-items/Center.vue +19 -0
- package/src/fields/StyleSetter/icons/align-items/FlexEnd.vue +19 -0
- package/src/fields/StyleSetter/icons/align-items/FlexStart.vue +19 -0
- package/src/fields/StyleSetter/icons/align-items/SpaceAround.vue +34 -0
- package/src/fields/StyleSetter/icons/align-items/SpaceBetween.vue +34 -0
- package/src/fields/StyleSetter/icons/align-items/index.ts +5 -0
- package/src/fields/StyleSetter/icons/background-repeat/NoRepeat.vue +20 -4
- package/src/fields/StyleSetter/icons/background-repeat/Repeat.vue +10 -28
- package/src/fields/StyleSetter/icons/background-repeat/RepeatX.vue +4 -5
- package/src/fields/StyleSetter/icons/background-repeat/RepeatY.vue +4 -5
- package/src/fields/StyleSetter/icons/flex-direction/Column.vue +4 -3
- package/src/fields/StyleSetter/icons/flex-direction/ColumnReverse.vue +4 -3
- package/src/fields/StyleSetter/icons/flex-direction/Row.vue +4 -3
- package/src/fields/StyleSetter/icons/flex-direction/RowReverse.vue +4 -3
- package/src/fields/StyleSetter/icons/justify-content/Center.vue +5 -2
- package/src/fields/StyleSetter/icons/justify-content/FlexEnd.vue +15 -2
- package/src/fields/StyleSetter/icons/justify-content/FlexStart.vue +15 -2
- package/src/fields/StyleSetter/icons/justify-content/SpaceAround.vue +28 -3
- package/src/fields/StyleSetter/icons/justify-content/SpaceBetween.vue +28 -2
- package/src/fields/StyleSetter/pro/Background.vue +7 -2
- package/src/fields/StyleSetter/pro/Font.vue +3 -3
- package/src/fields/StyleSetter/pro/Layout.vue +98 -28
- package/src/icons/DatasourceIcon.vue +7 -0
- package/src/index.ts +3 -0
- package/src/layouts/Framework.vue +7 -1
- package/src/layouts/props-panel/PropsPanel.vue +38 -12
- package/src/layouts/sidebar/Sidebar.vue +3 -3
- package/src/plugin.ts +3 -2
- package/src/services/editor.ts +76 -11
- package/src/services/history.ts +22 -1
- package/src/services/ui.ts +20 -5
- package/src/theme/code-block.scss +37 -0
- package/src/theme/common/var.scss +1 -1
- package/src/theme/component-list-panel.scss +2 -2
- package/src/theme/data-source-field.scss +4 -0
- package/src/theme/display-conds.scss +11 -0
- package/src/theme/event.scss +58 -4
- package/src/theme/framework.scss +4 -1
- package/src/theme/history-list-panel.scss +9 -9
- package/src/theme/nav-menu.scss +5 -1
- package/src/theme/props-panel.scss +2 -1
- package/src/theme/style-setter/border.scss +14 -5
- package/src/theme/theme.scss +1 -0
- package/src/theme/themes/magic-admin/index.scss +214 -0
- package/src/theme/ui-select.scss +1 -1
- package/src/type.ts +33 -6
- package/src/utils/config.ts +9 -1
- package/src/utils/const.ts +3 -2
- package/src/utils/data-source/index.ts +3 -3
- package/src/utils/props.ts +22 -9
- package/src/utils/type-match-rules.ts +11 -5
- package/types/index.d.ts +114 -35
package/package.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "1.8.0-beta.
|
|
2
|
+
"version": "1.8.0-beta.15",
|
|
3
3
|
"name": "@tmagic/editor",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"sideEffects": [
|
|
@@ -58,11 +58,11 @@
|
|
|
58
58
|
"moveable": "^0.53.0",
|
|
59
59
|
"serialize-javascript": "^7.0.0",
|
|
60
60
|
"sortablejs": "^1.15.6",
|
|
61
|
-
"@tmagic/
|
|
62
|
-
"@tmagic/
|
|
63
|
-
"@tmagic/
|
|
64
|
-
"@tmagic/utils": "1.8.0-beta.
|
|
65
|
-
"@tmagic/
|
|
61
|
+
"@tmagic/design": "1.8.0-beta.15",
|
|
62
|
+
"@tmagic/form": "1.8.0-beta.15",
|
|
63
|
+
"@tmagic/table": "1.8.0-beta.15",
|
|
64
|
+
"@tmagic/utils": "1.8.0-beta.15",
|
|
65
|
+
"@tmagic/stage": "1.8.0-beta.15"
|
|
66
66
|
},
|
|
67
67
|
"devDependencies": {
|
|
68
68
|
"@types/events": "^3.0.3",
|
|
@@ -76,7 +76,7 @@
|
|
|
76
76
|
"type-fest": "^5.2.0",
|
|
77
77
|
"typescript": "^6.0.3",
|
|
78
78
|
"vue": "^3.5.40",
|
|
79
|
-
"@tmagic/core": "1.8.0-beta.
|
|
79
|
+
"@tmagic/core": "1.8.0-beta.15"
|
|
80
80
|
},
|
|
81
81
|
"peerDependenciesMeta": {
|
|
82
82
|
"typescript": {
|
package/src/Editor.vue
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
:page-bar-sort-options="pageBarSortOptions"
|
|
5
5
|
:page-filter-function="pageFilterFunction"
|
|
6
6
|
:hide-sidebar="hideSidebar"
|
|
7
|
+
:theme="theme"
|
|
7
8
|
>
|
|
8
9
|
<template #header>
|
|
9
10
|
<slot name="header"></slot>
|
|
@@ -135,9 +136,10 @@
|
|
|
135
136
|
<script lang="ts" setup>
|
|
136
137
|
import { EventEmitter } from 'events';
|
|
137
138
|
|
|
138
|
-
import { provide, ref } from 'vue';
|
|
139
|
+
import { computed, provide, ref } from 'vue';
|
|
139
140
|
|
|
140
141
|
import type { MApp } from '@tmagic/core';
|
|
142
|
+
import { M_THEME_KEY } from '@tmagic/design';
|
|
141
143
|
|
|
142
144
|
import Framework from './layouts/Framework.vue';
|
|
143
145
|
import TMagicNavMenu from './layouts/NavMenu.vue';
|
|
@@ -241,6 +243,15 @@ provide(ENABLE_PROPS_FORM_VALIDATE, props.enablePropsFormValidate ?? false);
|
|
|
241
243
|
* 与 PropsPanel 通过 `:extend-state` 显式传入的方式保持等价。
|
|
242
244
|
*/
|
|
243
245
|
provide('extendFormState', props.extendFormState);
|
|
246
|
+
|
|
247
|
+
// 用 computed 包一层再 provide,否则传下去的是 provide 那一刻的值快照,
|
|
248
|
+
// props.isLargeStageContainer 后续变化不会同步到子孙(如 @tmagic/design/ColorPicker)。
|
|
249
|
+
// 子孙侧 `inject<ComputedRef<boolean>>('isLargeStageContainer', computed(() => false))`
|
|
250
|
+
// 用 `.value` 或模板自动解包读取即可拿到最新值。
|
|
251
|
+
provide(
|
|
252
|
+
'isLargeStageContainer',
|
|
253
|
+
computed(() => props.isLargeStageContainer),
|
|
254
|
+
);
|
|
244
255
|
/**
|
|
245
256
|
* 提供 PropsPanel 主属性表单的 formState getter,供历史差异弹窗复用,
|
|
246
257
|
* 让 CompareForm 与 PropsPanel 的 filterFunction 上下文保持一致。
|
|
@@ -256,6 +267,16 @@ provide('historyListExtraTabs', props.historyListExtraTabs);
|
|
|
256
267
|
|
|
257
268
|
provide<EventBus>('eventBus', new EventEmitter());
|
|
258
269
|
|
|
270
|
+
/**
|
|
271
|
+
* 把当前主题以响应式 ref 形式 provide 给后代,供包含 `Teleport` 的组件
|
|
272
|
+
* (如 `TMagicPopover` / `FloatingBox` / `ContentMenu`)在传送目标上挂 `m-theme--<theme>`
|
|
273
|
+
* 类,让主题级 CSS 变量在 portal 节点上也能命中。详见 `@tmagic/design/theme.ts`。
|
|
274
|
+
*/
|
|
275
|
+
provide(
|
|
276
|
+
M_THEME_KEY,
|
|
277
|
+
computed(() => props.theme ?? ''),
|
|
278
|
+
);
|
|
279
|
+
|
|
259
280
|
const propsPanelMountedHandler = (e: InstanceType<typeof FormPanel>) => {
|
|
260
281
|
propsPanelRef.value = e;
|
|
261
282
|
emit('props-panel-mounted', e);
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
<transition name="fade">
|
|
3
3
|
<div
|
|
4
4
|
v-show="visible"
|
|
5
|
-
class="magic-editor-content-menu"
|
|
6
5
|
ref="menu"
|
|
6
|
+
:class="['magic-editor-content-menu', themeClass]"
|
|
7
7
|
:style="menuStyle"
|
|
8
8
|
@mouseenter="mouseenterHandler()"
|
|
9
9
|
@contextmenu.prevent
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
<script lang="ts" setup>
|
|
40
40
|
import { computed, nextTick, onBeforeUnmount, onMounted, type Ref, ref, useTemplateRef } from 'vue';
|
|
41
41
|
|
|
42
|
-
import { useZIndex } from '@tmagic/design';
|
|
42
|
+
import { useThemeClass, useZIndex } from '@tmagic/design';
|
|
43
43
|
|
|
44
44
|
import { MenuButton, MenuComponent } from '@editor/type';
|
|
45
45
|
|
|
@@ -73,6 +73,14 @@ const menuEl = useTemplateRef<HTMLDivElement>('menu');
|
|
|
73
73
|
const buttonRefs = useTemplateRef<InstanceType<typeof ToolButton>[]>('buttons');
|
|
74
74
|
const subMenuRef = useTemplateRef<any>('subMenu');
|
|
75
75
|
const visible = ref(false);
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* 主题修饰类(来自最近的 `<MEditor>` / `<MForm>` 祖先 provide)。
|
|
79
|
+
* - 顶层 `ContentMenu` 渲染在编辑器子树中,加上去是冗余但无害;
|
|
80
|
+
* - 子菜单(递归 `<content-menu :is-sub-menu="true">` 被 `<teleport to="body">` 送到 body)
|
|
81
|
+
* 不在编辑器子树中,必须显式挂上主题类,主题级 CSS 变量才能命中。
|
|
82
|
+
*/
|
|
83
|
+
const themeClass = useThemeClass();
|
|
76
84
|
const subMenuData: Ref<(MenuButton | MenuComponent)[]> = ref<(MenuButton | MenuComponent)[]>([]);
|
|
77
85
|
const zIndex = useZIndex();
|
|
78
86
|
const curZIndex = ref<number>(0);
|
|
@@ -120,20 +128,42 @@ const outsideClickHideHandler = (e: MouseEvent) => {
|
|
|
120
128
|
hide();
|
|
121
129
|
};
|
|
122
130
|
|
|
123
|
-
|
|
124
|
-
|
|
131
|
+
// 根据菜单实际尺寸修正位置,避免超出可视范围
|
|
132
|
+
const fixPosition = () => {
|
|
133
|
+
const menu = menuEl.value;
|
|
134
|
+
if (!menu || !visible.value) return;
|
|
135
|
+
|
|
136
|
+
const menuHeight = menu.clientHeight;
|
|
137
|
+
const menuWidth = menu.clientWidth;
|
|
138
|
+
|
|
139
|
+
let { top, left } = menuPosition.value;
|
|
125
140
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
top = document.body.clientHeight - menuHeight;
|
|
141
|
+
if (top + menuHeight > document.body.clientHeight) {
|
|
142
|
+
top = Math.max(0, document.body.clientHeight - menuHeight);
|
|
129
143
|
}
|
|
130
144
|
|
|
145
|
+
if (left + menuWidth > document.body.clientWidth) {
|
|
146
|
+
left = Math.max(0, document.body.clientWidth - menuWidth);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
if (top !== menuPosition.value.top || left !== menuPosition.value.left) {
|
|
150
|
+
menuPosition.value = { top, left };
|
|
151
|
+
}
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
const setPosition = (e: { clientY: number; clientX: number }) => {
|
|
131
155
|
menuPosition.value = {
|
|
132
|
-
top,
|
|
156
|
+
top: e.clientY,
|
|
133
157
|
left: e.clientX,
|
|
134
158
|
};
|
|
159
|
+
fixPosition();
|
|
135
160
|
};
|
|
136
161
|
|
|
162
|
+
// 菜单大小动态变化(如菜单项更新)后重新修正位置
|
|
163
|
+
const resizeObserver = new ResizeObserver(() => {
|
|
164
|
+
fixPosition();
|
|
165
|
+
});
|
|
166
|
+
|
|
137
167
|
const show = (e?: { clientY: number; clientX: number }) => {
|
|
138
168
|
visible.value = true;
|
|
139
169
|
|
|
@@ -178,12 +208,18 @@ const mouseenterHandler = () => {
|
|
|
178
208
|
};
|
|
179
209
|
|
|
180
210
|
onMounted(() => {
|
|
211
|
+
if (menuEl.value) {
|
|
212
|
+
resizeObserver.observe(menuEl.value);
|
|
213
|
+
}
|
|
214
|
+
|
|
181
215
|
if (props.isSubMenu) return;
|
|
182
216
|
|
|
183
217
|
globalThis.addEventListener('mousedown', outsideClickHideHandler, true);
|
|
184
218
|
});
|
|
185
219
|
|
|
186
220
|
onBeforeUnmount(() => {
|
|
221
|
+
resizeObserver.disconnect();
|
|
222
|
+
|
|
187
223
|
if (props.isSubMenu) return;
|
|
188
224
|
|
|
189
225
|
globalThis.removeEventListener('mousedown', outsideClickHideHandler, true);
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
<Teleport to="body" v-if="visible">
|
|
3
3
|
<div
|
|
4
4
|
ref="target"
|
|
5
|
-
class="m-editor-float-box"
|
|
5
|
+
:class="['m-editor-float-box', themeClass]"
|
|
6
6
|
v-bind="$attrs"
|
|
7
7
|
:style="{ ...style, zIndex: curZIndex }"
|
|
8
8
|
@mousedown="nextZIndex"
|
|
@@ -27,7 +27,7 @@ import { computed, type CSSProperties, nextTick, onBeforeUnmount, provide, ref,
|
|
|
27
27
|
import { Close } from '@element-plus/icons-vue';
|
|
28
28
|
import VanillaMoveable from 'moveable';
|
|
29
29
|
|
|
30
|
-
import { TMagicButton, useZIndex } from '@tmagic/design';
|
|
30
|
+
import { TMagicButton, useThemeClass, useZIndex } from '@tmagic/design';
|
|
31
31
|
|
|
32
32
|
import MIcon from '@editor/components/Icon.vue';
|
|
33
33
|
|
|
@@ -62,6 +62,12 @@ const props = withDefaults(
|
|
|
62
62
|
const targetEl = useTemplateRef<HTMLDivElement>('target');
|
|
63
63
|
const titleEl = useTemplateRef<HTMLDivElement>('title');
|
|
64
64
|
|
|
65
|
+
/**
|
|
66
|
+
* 主题修饰类(来自最近的 `<MEditor>` / `<MForm>` 祖先 provide)。
|
|
67
|
+
* 挂在 `Teleport` 出去的浮动面板根节点上,让主题级 CSS 变量在 portal 节点上也能命中。
|
|
68
|
+
*/
|
|
69
|
+
const themeClass = useThemeClass();
|
|
70
|
+
|
|
65
71
|
const zIndex = useZIndex();
|
|
66
72
|
const curZIndex = ref<number>(0);
|
|
67
73
|
|
package/src/editorProps.ts
CHANGED
|
@@ -35,6 +35,10 @@ import type {
|
|
|
35
35
|
export const ENABLE_PROPS_FORM_VALIDATE: InjectionKey<boolean> = Symbol('enablePropsFormValidate');
|
|
36
36
|
|
|
37
37
|
export interface EditorProps {
|
|
38
|
+
/** 是否是大屏模拟器容器,大屏容器时,左侧属性面板会扩展为两列(正常3列),颜色表单不扩展两列等 */
|
|
39
|
+
isLargeStageContainer?: boolean;
|
|
40
|
+
|
|
41
|
+
theme?: string;
|
|
38
42
|
/** 页面初始值 */
|
|
39
43
|
modelValue?: MApp;
|
|
40
44
|
/** 左侧面板中的组件类型列表 */
|
package/src/fields/Code.vue
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<MagicCodeEditor
|
|
3
|
+
v-if="!silentMode"
|
|
3
4
|
:height="config.height"
|
|
4
5
|
:type="diffMode ? 'diff' : undefined"
|
|
5
6
|
:init-values="diffMode ? (lastValues || {})[name] : model[name]"
|
|
@@ -17,9 +18,9 @@
|
|
|
17
18
|
</template>
|
|
18
19
|
|
|
19
20
|
<script lang="ts" setup>
|
|
20
|
-
import { computed } from 'vue';
|
|
21
|
+
import { computed, inject } from 'vue';
|
|
21
22
|
|
|
22
|
-
import type
|
|
23
|
+
import { type CodeConfig, type FieldProps, FORM_SILENT_MODE_KEY } from '@tmagic/form';
|
|
23
24
|
|
|
24
25
|
import MagicCodeEditor from '@editor/layouts/CodeEditor.vue';
|
|
25
26
|
|
|
@@ -27,6 +28,13 @@ defineOptions({
|
|
|
27
28
|
name: 'MFieldsVsCode',
|
|
28
29
|
});
|
|
29
30
|
|
|
31
|
+
/**
|
|
32
|
+
* 静默模式(submitForm/validateForm 隐藏挂载)下跳过 monaco 渲染:
|
|
33
|
+
* 校验由 FormItem 针对 model 中的值完成,与编辑器实例无关;本组件挂载无值副作用
|
|
34
|
+
* (save 仅由用户操作/编辑器内容变更触发),跳过可省去 monaco worker/model 的无谓实例化。
|
|
35
|
+
*/
|
|
36
|
+
const silentMode = inject(FORM_SILENT_MODE_KEY, false);
|
|
37
|
+
|
|
30
38
|
const emit = defineEmits<{
|
|
31
39
|
change: [value: string | any];
|
|
32
40
|
}>();
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div class="m-fields-code-select" :class="config.className">
|
|
3
|
-
<TMagicCard>
|
|
3
|
+
<TMagicCard :flat="config.flat">
|
|
4
4
|
<MContainer
|
|
5
5
|
:config="codeConfig"
|
|
6
6
|
:size="size"
|
|
7
|
+
class="code-select-content"
|
|
7
8
|
:prop="prop"
|
|
8
9
|
:disabled="disabled"
|
|
9
10
|
:is-compare="isCompareMode"
|
|
@@ -12,16 +13,20 @@
|
|
|
12
13
|
@change="changeHandler"
|
|
13
14
|
>
|
|
14
15
|
</MContainer>
|
|
16
|
+
<TMagicButton class="create-button fullWidth" :icon="Plus" :size="size" :disabled="disabled" @click="newHandler()"
|
|
17
|
+
>添加{{ config.text }}</TMagicButton
|
|
18
|
+
>
|
|
15
19
|
</TMagicCard>
|
|
16
20
|
</div>
|
|
17
21
|
</template>
|
|
18
22
|
|
|
19
23
|
<script lang="ts" setup>
|
|
20
24
|
import { computed, watch } from 'vue';
|
|
25
|
+
import { Plus } from '@element-plus/icons-vue';
|
|
21
26
|
import { isEmpty } from 'lodash-es';
|
|
22
27
|
|
|
23
28
|
import { HookCodeType, HookType } from '@tmagic/core';
|
|
24
|
-
import { TMagicCard } from '@tmagic/design';
|
|
29
|
+
import { TMagicButton, TMagicCard } from '@tmagic/design';
|
|
25
30
|
import type { CodeSelectConfig, ContainerChangeEventData, FieldProps, GroupListConfig } from '@tmagic/form';
|
|
26
31
|
import { MContainer } from '@tmagic/form';
|
|
27
32
|
|
|
@@ -53,12 +58,23 @@ const props = withDefaults(defineProps<FieldProps<CodeSelectConfig>>(), {});
|
|
|
53
58
|
* 仅当存在历史值时才启用对比,避免 lastValues 缺失时退化为「全部新增」的空对比。
|
|
54
59
|
*/
|
|
55
60
|
const isCompareMode = computed(() => Boolean(props.isCompare && props.lastValues));
|
|
56
|
-
|
|
61
|
+
const newHandler = () => {
|
|
62
|
+
const defaultCode = {
|
|
63
|
+
codeType: HookCodeType.CODE,
|
|
64
|
+
codeId: '',
|
|
65
|
+
};
|
|
66
|
+
const name = props.config.name || '';
|
|
67
|
+
const hookData = props.model[name]?.hookData || [];
|
|
68
|
+
emit('change', defaultCode, {
|
|
69
|
+
modifyKey: `hookData.${hookData.length}`,
|
|
70
|
+
});
|
|
71
|
+
};
|
|
57
72
|
const codeConfig = computed<GroupListConfig>(() => ({
|
|
58
73
|
type: 'group-list',
|
|
59
74
|
name: 'hookData',
|
|
60
75
|
enableToggleMode: false,
|
|
61
76
|
expandAll: true,
|
|
77
|
+
addable: () => false,
|
|
62
78
|
title: (mForm, { model, index }: any) => {
|
|
63
79
|
if (model.codeType === HookCodeType.DATA_SOURCE_METHOD) {
|
|
64
80
|
if (Array.isArray(model.codeId)) {
|
|
@@ -81,49 +97,44 @@ const codeConfig = computed<GroupListConfig>(() => ({
|
|
|
81
97
|
|
|
82
98
|
return model.codeId || index;
|
|
83
99
|
},
|
|
100
|
+
titlePrefix: props.config.name === undefined ? undefined : String(props.config.name),
|
|
84
101
|
items: [
|
|
85
102
|
{
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
{ value: HookCodeType.DATA_SOURCE_METHOD, text: '数据源方法' },
|
|
95
|
-
],
|
|
96
|
-
rules: [{ typeMatch: true, trigger: 'change' }],
|
|
97
|
-
defaultValue: HookCodeType.CODE,
|
|
98
|
-
onChange: (_mForm, v: HookCodeType, { setModel }) => {
|
|
99
|
-
if (v === HookCodeType.DATA_SOURCE_METHOD) {
|
|
100
|
-
setModel('codeId', []);
|
|
101
|
-
} else {
|
|
102
|
-
setModel('codeId', '');
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
return v;
|
|
106
|
-
},
|
|
107
|
-
},
|
|
108
|
-
{
|
|
109
|
-
type: 'code-select-col',
|
|
110
|
-
name: 'codeId',
|
|
111
|
-
span: 18,
|
|
112
|
-
labelWidth: 0,
|
|
113
|
-
display: (_mForm, { model }) => model.codeType !== HookCodeType.DATA_SOURCE_METHOD,
|
|
114
|
-
notEditable: () => !codeBlockService.getEditStatus(),
|
|
115
|
-
rules: [{ typeMatch: true, trigger: 'change' }],
|
|
116
|
-
},
|
|
117
|
-
{
|
|
118
|
-
type: 'data-source-method-select',
|
|
119
|
-
name: 'codeId',
|
|
120
|
-
span: 18,
|
|
121
|
-
labelWidth: 0,
|
|
122
|
-
display: (_mForm, { model }) => model.codeType === HookCodeType.DATA_SOURCE_METHOD,
|
|
123
|
-
notEditable: () => !dataSourceService.get('editable'),
|
|
124
|
-
rules: [{ typeMatch: true, trigger: 'change' }],
|
|
125
|
-
},
|
|
103
|
+
text: '代码类型',
|
|
104
|
+
type: 'select',
|
|
105
|
+
name: 'codeType',
|
|
106
|
+
labelPosition: 'right',
|
|
107
|
+
rules: [{ typeMatch: true, trigger: 'change' }],
|
|
108
|
+
options: [
|
|
109
|
+
{ value: HookCodeType.CODE, text: '代码块' },
|
|
110
|
+
{ value: HookCodeType.DATA_SOURCE_METHOD, text: '数据源方法' },
|
|
126
111
|
],
|
|
112
|
+
defaultValue: HookCodeType.CODE,
|
|
113
|
+
onChange: (_mForm, v: HookCodeType, { setModel }) => {
|
|
114
|
+
if (v === HookCodeType.DATA_SOURCE_METHOD) {
|
|
115
|
+
setModel('codeId', []);
|
|
116
|
+
} else {
|
|
117
|
+
setModel('codeId', '');
|
|
118
|
+
}
|
|
119
|
+
return v;
|
|
120
|
+
},
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
type: 'code-select-col',
|
|
124
|
+
name: 'codeId',
|
|
125
|
+
text: '代码块',
|
|
126
|
+
rules: [{ typeMatch: true, trigger: 'change' }],
|
|
127
|
+
|
|
128
|
+
display: (_mForm, { model }) => model.codeType !== HookCodeType.DATA_SOURCE_METHOD,
|
|
129
|
+
notEditable: () => !codeBlockService.getEditStatus(),
|
|
130
|
+
},
|
|
131
|
+
{
|
|
132
|
+
type: 'data-source-method-select',
|
|
133
|
+
name: 'codeId',
|
|
134
|
+
text: '数据源字段',
|
|
135
|
+
rules: [{ typeMatch: true, trigger: 'change' }],
|
|
136
|
+
display: (_mForm, { model }) => model.codeType === HookCodeType.DATA_SOURCE_METHOD,
|
|
137
|
+
notEditable: () => !dataSourceService.get('editable'),
|
|
127
138
|
},
|
|
128
139
|
],
|
|
129
140
|
}));
|
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div
|
|
2
|
+
<div
|
|
3
|
+
class="m-fields-data-source-field-select"
|
|
4
|
+
:class="{
|
|
5
|
+
[`data-source-field-${type}`]: !isSelectValid,
|
|
6
|
+
}"
|
|
7
|
+
>
|
|
3
8
|
<FieldSelect
|
|
4
|
-
v-if="
|
|
9
|
+
v-if="isSelectValid"
|
|
5
10
|
:model-value="model[name]"
|
|
6
11
|
:disabled="disabled"
|
|
7
12
|
:size="size"
|
|
@@ -37,15 +42,14 @@
|
|
|
37
42
|
:size="size"
|
|
38
43
|
:disabled="disabled"
|
|
39
44
|
@click="onToggleDataSourceFieldSelectHandler"
|
|
40
|
-
><MIcon :icon="
|
|
41
|
-
|
|
45
|
+
><MIcon :icon="dataSourceIcon"></MIcon>
|
|
46
|
+
</TMagicButton>
|
|
42
47
|
</TMagicTooltip>
|
|
43
48
|
</div>
|
|
44
49
|
</template>
|
|
45
50
|
|
|
46
51
|
<script setup lang="ts">
|
|
47
52
|
import { computed, inject, ref, resolveComponent, watch } from 'vue';
|
|
48
|
-
import { Coin } from '@element-plus/icons-vue';
|
|
49
53
|
|
|
50
54
|
import { DataSchema } from '@tmagic/core';
|
|
51
55
|
import { TMagicButton, tMagicMessage, TMagicTooltip } from '@tmagic/design';
|
|
@@ -61,6 +65,8 @@ import { DATA_SOURCE_FIELDS_SELECT_VALUE_PREFIX, removeDataSourceFieldPrefix } f
|
|
|
61
65
|
import MIcon from '@editor/components/Icon.vue';
|
|
62
66
|
import { useServices } from '@editor/hooks/use-services';
|
|
63
67
|
|
|
68
|
+
import dataSourceIcon from '../../icons/DatasourceIcon.vue';
|
|
69
|
+
|
|
64
70
|
import FieldSelect from './FieldSelect.vue';
|
|
65
71
|
|
|
66
72
|
defineOptions({
|
|
@@ -75,6 +81,9 @@ const props = withDefaults(defineProps<FieldProps<DataSourceFieldSelectConfig>>(
|
|
|
75
81
|
|
|
76
82
|
const showDataSourceFieldSelect = ref(false);
|
|
77
83
|
|
|
84
|
+
const isSelectValid = computed(
|
|
85
|
+
() => !disabledDataSource.value && (showDataSourceFieldSelect.value || !props.config.fieldConfig),
|
|
86
|
+
);
|
|
78
87
|
watch(
|
|
79
88
|
() => props.model[props.name],
|
|
80
89
|
(value) => {
|
|
@@ -68,12 +68,15 @@ const config = computed<GroupListConfig>(() => ({
|
|
|
68
68
|
titlePrefix: props.config.titlePrefix,
|
|
69
69
|
expandAll: true,
|
|
70
70
|
enableToggleMode: false,
|
|
71
|
+
flat: props.config.flat,
|
|
71
72
|
items: [
|
|
72
73
|
{
|
|
73
74
|
type: 'table',
|
|
74
75
|
name: 'cond',
|
|
75
|
-
operateColWidth:
|
|
76
|
+
operateColWidth: props.config.operateColWidth,
|
|
76
77
|
enableToggleMode: false,
|
|
78
|
+
fixed: props.config.fixed,
|
|
79
|
+
flat: props.config.flat,
|
|
77
80
|
items: [
|
|
78
81
|
parentFields.value.length
|
|
79
82
|
? {
|
|
@@ -12,16 +12,21 @@
|
|
|
12
12
|
@change="onChangeHandler"
|
|
13
13
|
></MTable>
|
|
14
14
|
|
|
15
|
-
<div v-else class="fullWidth">
|
|
16
|
-
<
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
15
|
+
<div v-else class="fullWidth event-select-container">
|
|
16
|
+
<div class="event-select-header">
|
|
17
|
+
<div class="event-select-title">事件配置</div>
|
|
18
|
+
<TMagicButton
|
|
19
|
+
v-if="!isCompareMode && displayList.length > 0"
|
|
20
|
+
class="create-button"
|
|
21
|
+
text
|
|
22
|
+
type="primary"
|
|
23
|
+
:icon="Plus"
|
|
24
|
+
:size="size"
|
|
25
|
+
:disabled="disabled"
|
|
26
|
+
@click="addEvent()"
|
|
27
|
+
>添加事件</TMagicButton
|
|
28
|
+
>
|
|
29
|
+
</div>
|
|
25
30
|
<MPanel
|
|
26
31
|
v-for="entry in displayList"
|
|
27
32
|
:key="entry.index"
|
|
@@ -32,32 +37,45 @@
|
|
|
32
37
|
:model="entry.cardItem"
|
|
33
38
|
:last-values="entry.lastCardItem"
|
|
34
39
|
:is-compare="isCompareMode"
|
|
40
|
+
:hide-expand="true"
|
|
35
41
|
:label-width="config.labelWidth || '100px'"
|
|
36
42
|
@change="onChangeHandler"
|
|
37
43
|
>
|
|
38
44
|
<template #header>
|
|
39
|
-
<
|
|
40
|
-
class="
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
45
|
+
<div class="event-item-header">
|
|
46
|
+
<div class="event-item-title">事件{{ Number(entry.index) + 1 }}</div>
|
|
47
|
+
<MFormContainer
|
|
48
|
+
class="fullWidth"
|
|
49
|
+
:config="eventNameConfig"
|
|
50
|
+
:model="entry.cardItem"
|
|
51
|
+
:last-values="entry.lastCardItem"
|
|
52
|
+
:is-compare="isCompareMode"
|
|
53
|
+
:disabled="disabled"
|
|
54
|
+
:size="size"
|
|
55
|
+
:prop="`${prop}.${entry.index}`"
|
|
56
|
+
@change="eventNameChangeHandler"
|
|
57
|
+
></MFormContainer>
|
|
58
|
+
<TMagicButton
|
|
59
|
+
class="event-item-delete-button"
|
|
60
|
+
v-if="!isCompareMode"
|
|
61
|
+
link
|
|
62
|
+
:icon="Delete"
|
|
63
|
+
:disabled="disabled"
|
|
64
|
+
:size="size"
|
|
65
|
+
@click="removeEvent(Number(entry.index))"
|
|
66
|
+
></TMagicButton>
|
|
67
|
+
</div>
|
|
59
68
|
</template>
|
|
60
69
|
</MPanel>
|
|
70
|
+
|
|
71
|
+
<TMagicButton
|
|
72
|
+
v-if="!isCompareMode"
|
|
73
|
+
class="create-button fullWidth"
|
|
74
|
+
:icon="Plus"
|
|
75
|
+
:disabled="disabled"
|
|
76
|
+
@click="addEvent()"
|
|
77
|
+
>添加事件</TMagicButton
|
|
78
|
+
>
|
|
61
79
|
</div>
|
|
62
80
|
</div>
|
|
63
81
|
</template>
|
|
@@ -65,6 +83,7 @@
|
|
|
65
83
|
<script lang="ts" setup>
|
|
66
84
|
import { computed } from 'vue';
|
|
67
85
|
import { Delete } from '@element-plus/icons-vue';
|
|
86
|
+
import { Plus } from '@element-plus/icons-vue';
|
|
68
87
|
import { has } from 'lodash-es';
|
|
69
88
|
|
|
70
89
|
import { ActionType } from '@tmagic/core';
|
|
@@ -108,7 +127,7 @@ const { editorService, dataSourceService, eventsService, codeBlockService, props
|
|
|
108
127
|
const eventNameConfig = computed(() => {
|
|
109
128
|
const defaultEventNameConfig = {
|
|
110
129
|
name: 'name',
|
|
111
|
-
text: '
|
|
130
|
+
text: '事件类型',
|
|
112
131
|
type: (mForm: FormState | undefined, { formValue }: any) => {
|
|
113
132
|
if (
|
|
114
133
|
props.config.src !== 'component' ||
|
|
@@ -118,7 +137,7 @@ const eventNameConfig = computed(() => {
|
|
|
118
137
|
}
|
|
119
138
|
return 'select';
|
|
120
139
|
},
|
|
121
|
-
labelWidth: '
|
|
140
|
+
labelWidth: '70px',
|
|
122
141
|
checkStrictly: () => props.config.src !== 'component',
|
|
123
142
|
valueSeparator: '.',
|
|
124
143
|
options: (_mForm: FormState, { formValue }: any) => getEventNameOptions(props.config.src, formValue),
|
|
@@ -178,6 +197,7 @@ const actionTypeConfig = computed(() => {
|
|
|
178
197
|
name: 'actionType',
|
|
179
198
|
text: '联动类型',
|
|
180
199
|
type: 'select',
|
|
200
|
+
labelPosition: 'left',
|
|
181
201
|
defaultValue: ActionType.COMP,
|
|
182
202
|
options: actionTypeOptions.value,
|
|
183
203
|
rules: [
|
|
@@ -200,6 +220,7 @@ const targetCompConfig = computed(() => {
|
|
|
200
220
|
name: 'to',
|
|
201
221
|
text: '联动组件',
|
|
202
222
|
type: 'ui-select',
|
|
223
|
+
labelPosition: 'left',
|
|
203
224
|
display: (_mForm, { model }) => model.actionType === ActionType.COMP,
|
|
204
225
|
onChange: (_MForm, _v, { setModel }) => {
|
|
205
226
|
setModel('method', '');
|
|
@@ -219,6 +240,7 @@ const compActionConfig = computed(() => {
|
|
|
219
240
|
const defaultCompActionConfig: DynamicTypeConfig = {
|
|
220
241
|
name: 'method',
|
|
221
242
|
text: '动作',
|
|
243
|
+
labelPosition: 'left',
|
|
222
244
|
type: (mForm: FormState | undefined, { model }: any) => {
|
|
223
245
|
const to = editorService.getNodeById(model.to);
|
|
224
246
|
|
|
@@ -317,6 +339,7 @@ const actionsConfig = computed(
|
|
|
317
339
|
() =>
|
|
318
340
|
defineFormItem({
|
|
319
341
|
type: 'panel',
|
|
342
|
+
labelPosition: 'left',
|
|
320
343
|
items: [
|
|
321
344
|
{
|
|
322
345
|
type: 'group-list',
|
|
@@ -324,6 +347,7 @@ const actionsConfig = computed(
|
|
|
324
347
|
expandAll: true,
|
|
325
348
|
enableToggleMode: false,
|
|
326
349
|
titlePrefix: '动作',
|
|
350
|
+
labelPosition: 'left',
|
|
327
351
|
items: [
|
|
328
352
|
actionTypeConfig.value,
|
|
329
353
|
targetCompConfig.value,
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
<TMagicCollapse class="m-fields-style-setter" v-model="collapseValue">
|
|
3
3
|
<template v-for="(item, index) in list" :key="index">
|
|
4
4
|
<TMagicCollapseItem :name="`${index}`">
|
|
5
|
-
<template #title
|
|
5
|
+
<template #title>{{ item.title }}</template>
|
|
6
6
|
<component
|
|
7
7
|
v-if="item.component"
|
|
8
8
|
:is="item.component"
|
|
@@ -22,14 +22,11 @@
|
|
|
22
22
|
|
|
23
23
|
<script setup lang="ts">
|
|
24
24
|
import { shallowRef } from 'vue';
|
|
25
|
-
import { Grid } from '@element-plus/icons-vue';
|
|
26
25
|
|
|
27
26
|
import { TMagicCollapse, TMagicCollapseItem } from '@tmagic/design';
|
|
28
27
|
import type { ContainerChangeEventData, FieldProps } from '@tmagic/form';
|
|
29
28
|
import type { StyleSchema } from '@tmagic/schema';
|
|
30
29
|
|
|
31
|
-
import MIcon from '@editor/components/Icon.vue';
|
|
32
|
-
|
|
33
30
|
import { Background, Border, Font, Layout, Position, Transform } from './pro/';
|
|
34
31
|
|
|
35
32
|
defineOptions({
|