roymondchen 3af247febb fix(playground): 画布尺寸切换无效
由于element-plus2.6后radio-button label属性改成value

fix #586
2024-04-08 14:25:33 +08:00

299 lines
7.8 KiB
Vue

<template>
<div class="editor-app">
<m-editor
v-model="value"
ref="editor"
:menu="menu"
:runtime-url="runtimeUrl"
:props-configs="propsConfigs"
:props-values="propsValues"
:event-method-list="eventMethodList"
:datasource-event-method-list="datasourceEventMethodList"
:datasource-configs="datasourceConfigs"
:datasource-values="datasourceValues"
:component-group-list="componentGroupList"
:datasource-list="datasourceList"
:default-selected="defaultSelected"
:moveable-options="moveableOptions"
:auto-scroll-into-view="true"
:stage-rect="stageRect"
@props-submit-error="propsSubmitErrorHandler"
>
<template #workspace-content>
<DeviceGroup ref="deviceGroup" v-model="stageRect"></DeviceGroup>
</template>
</m-editor>
<TMagicDialog v-model="previewVisible" destroy-on-close class="pre-viewer" title="预览" :width="stageRect?.width">
<iframe
v-if="previewVisible"
ref="iframe"
width="100%"
style="border: none"
:height="stageRect?.height"
:src="previewUrl"
></iframe>
</TMagicDialog>
</div>
</template>
<script lang="ts" setup>
import { computed, nextTick, onBeforeUnmount, ref, toRaw } from 'vue';
import { useRouter } from 'vue-router';
import { Coin, Connection, Document } from '@element-plus/icons-vue';
import serialize from 'serialize-javascript';
import { TMagicDialog, tMagicMessage, tMagicMessageBox } from '@tmagic/design';
import { DatasourceTypeOption, editorService, MenuBarData, MoveableOptions, TMagicEditor } from '@tmagic/editor';
import type { MContainer, MNode } from '@tmagic/schema';
import { NodeType } from '@tmagic/schema';
import type { CustomizeMoveableOptionsCallbackConfig } from '@tmagic/stage';
import { asyncLoadJs } from '@tmagic/utils';
import DeviceGroup from '../components/DeviceGroup.vue';
import componentGroupList from '../configs/componentGroupList';
import dsl from '../configs/dsl';
import { uaMap } from '../const';
const { VITE_RUNTIME_PATH, VITE_ENTRY_PATH } = import.meta.env;
const datasourceList: DatasourceTypeOption[] = [];
const runtimeUrl = `${VITE_RUNTIME_PATH}/playground/index.html`;
const router = useRouter();
const editor = ref<InstanceType<typeof TMagicEditor>>();
const deviceGroup = ref<InstanceType<typeof DeviceGroup>>();
const iframe = ref<HTMLIFrameElement>();
const previewVisible = ref(false);
const value = ref(dsl);
const defaultSelected = ref(dsl.items[0].id);
const propsValues = ref<Record<string, any>>({});
const propsConfigs = ref<Record<string, any>>({});
const eventMethodList = ref<Record<string, any>>({});
const datasourceEventMethodList = ref<Record<string, any>>({
base: {
events: [],
methods: [],
},
});
const datasourceConfigs = ref<Record<string, any>>({});
const datasourceValues = ref<Record<string, any>>({});
const stageRect = ref({
width: 375,
height: 817,
});
const previewUrl = computed(
() => `${VITE_RUNTIME_PATH}/page/index.html?localPreview=1&page=${editor.value?.editorService.get('page')?.id}`,
);
const menu: MenuBarData = {
left: [
{
type: 'text',
text: '魔方',
},
],
center: ['delete', 'undo', 'redo', 'guides', 'rule', 'zoom'],
right: [
{
type: 'button',
text: 'Form Playground',
handler: () => router.push('form'),
},
{
type: 'button',
text: 'Form Editor Playground',
handler: () => router.push('form-editor'),
},
{
type: 'button',
text: 'Table Playground',
handler: () => router.push('table'),
},
'/',
{
type: 'button',
text: '预览',
icon: Connection,
handler: async (services) => {
if (services?.editorService.get('modifiedNodeIds').size > 0) {
try {
await tMagicMessageBox.confirm('有修改未保存,是否先保存再预览', '提示', {
confirmButtonText: '保存并预览',
cancelButtonText: '预览',
type: 'warning',
});
save();
tMagicMessage.success('保存成功');
} catch (e) {
console.error(e);
}
}
previewVisible.value = true;
await nextTick();
if (!iframe.value?.contentWindow || !deviceGroup.value?.viewerDevice) return;
Object.defineProperty(iframe.value.contentWindow.navigator, 'userAgent', {
value: uaMap[deviceGroup.value.viewerDevice],
writable: true,
});
},
},
{
type: 'button',
text: '保存',
icon: Coin,
handler: () => {
save();
tMagicMessage.success('保存成功');
},
},
'/',
{
type: 'button',
icon: Document,
tooltip: '源码',
handler: (service) => service?.uiService.set('showSrc', !service?.uiService.get('showSrc')),
},
],
};
const moveableOptions = (config?: CustomizeMoveableOptionsCallbackConfig): MoveableOptions => {
const options: MoveableOptions = {};
if (!editor.value) return options;
const page = editor.value.editorService.get('page');
const ids = config?.targetElIds || [];
let isPage = page && ids.includes(`${page.id}`);
if (!isPage) {
const id = config?.targetElId;
if (id) {
const node = editor.value.editorService.getNodeById(id);
isPage = node?.type === NodeType.PAGE;
}
}
options.draggable = !isPage;
options.resizable = !isPage;
options.rotatable = !isPage;
// 双击后在弹层中编辑时,根组件不能拖拽
if (config?.targetEl?.parentElement?.classList.contains('tmagic-editor-sub-stage-wrap')) {
options.draggable = false;
options.resizable = false;
options.rotatable = false;
}
return options;
};
const save = () => {
localStorage.setItem(
'magicDSL',
serialize(toRaw(value.value), {
space: 2,
unsafe: true,
}).replace(/"(\w+)":\s/g, '$1: '),
);
editor.value?.editorService.resetModifiedNodeId();
};
asyncLoadJs(`${VITE_ENTRY_PATH}/config/index.umd.cjs`).then(() => {
propsConfigs.value = (globalThis as any).magicPresetConfigs;
});
asyncLoadJs(`${VITE_ENTRY_PATH}/value/index.umd.cjs`).then(() => {
propsValues.value = (globalThis as any).magicPresetValues;
});
asyncLoadJs(`${VITE_ENTRY_PATH}/event/index.umd.cjs`).then(() => {
eventMethodList.value = (globalThis as any).magicPresetEvents;
});
asyncLoadJs(`${VITE_ENTRY_PATH}/ds-config/index.umd.cjs`).then(() => {
datasourceConfigs.value = (globalThis as any).magicPresetDsConfigs;
});
asyncLoadJs(`${VITE_ENTRY_PATH}/ds-value/index.umd.cjs`).then(() => {
datasourceValues.value = (globalThis as any).magicPresetDsValues;
});
try {
// eslint-disable-next-line no-eval
const magicDSL = eval(`(${localStorage.getItem('magicDSL')})`);
if (!magicDSL) {
save();
} else {
value.value = magicDSL;
}
} catch (e) {
console.error(e);
save();
}
editorService.usePlugin({
beforeDoAdd: (config: MNode, parent: MContainer) => {
if (config.type === 'overlay') {
config.style = {
...config.style,
left: 0,
top: 0,
};
return [config, editorService.get('page') as MContainer];
}
return [config, parent];
},
});
onBeforeUnmount(() => {
editorService.removeAllPlugins();
});
const propsSubmitErrorHandler = async (e: any) => {
console.error(e);
tMagicMessage.closeAll();
tMagicMessage.error(e.message);
};
</script>
<style lang="scss">
html {
overflow: hidden;
}
#app {
width: 100%;
height: 100%;
display: flex;
}
.editor-app {
width: 100%;
height: 100%;
.m-editor {
flex: 1;
height: 100%;
}
.el-overlay-dialog {
display: flex;
}
.pre-viewer {
margin: auto;
.el-dialog__body {
padding: 0;
}
}
.menu-left {
.menu-item-text {
margin-left: 10px;
}
}
}
</style>