mirror of
https://github.com/Tencent/tmagic-editor.git
synced 2025-12-29 03:00:18 +00:00
306 lines
7.6 KiB
Vue
306 lines
7.6 KiB
Vue
<template>
|
|
<!-- 代码块编辑区 -->
|
|
<FloatingBox v-model:visible="boxVisible" title="代码编辑" :position="boxPosition" :before-close="beforeClose">
|
|
<template #body>
|
|
<div ref="floatingBoxBody"></div>
|
|
</template>
|
|
</FloatingBox>
|
|
|
|
<Teleport :to="floatingBoxBody" :disabled="slideType === 'box'" v-if="editVisible">
|
|
<MFormBox
|
|
class="m-editor-code-block-editor"
|
|
ref="formBox"
|
|
label-width="80px"
|
|
:close-on-press-escape="false"
|
|
:title="content.name"
|
|
:width="size"
|
|
:config="functionConfig"
|
|
:values="content"
|
|
:disabled="disabled"
|
|
@change="changeHandler"
|
|
@submit="submitForm"
|
|
@error="errorHandler"
|
|
@open="openHandler"
|
|
@closed="closedHandler"
|
|
>
|
|
<template #left>
|
|
<TMagicButton type="primary" link @click="difVisible = true">查看修改</TMagicButton>
|
|
</template>
|
|
</MFormBox>
|
|
</Teleport>
|
|
|
|
<TMagicDialog v-model="difVisible" title="查看修改" fullscreen>
|
|
<div style="display: flex; margin-bottom: 10px">
|
|
<div style="flex: 1"><TMagicTag size="small" type="info">修改前</TMagicTag></div>
|
|
<div style="flex: 1"><TMagicTag size="small" type="success">修改后</TMagicTag></div>
|
|
</div>
|
|
|
|
<CodeEditor
|
|
v-if="difVisible"
|
|
ref="magicVsEditor"
|
|
type="diff"
|
|
language="json"
|
|
:initValues="content.content"
|
|
:modifiedValues="formBox?.form?.values.content"
|
|
:style="`height: ${height - 200}px`"
|
|
></CodeEditor>
|
|
|
|
<template #footer>
|
|
<span class="dialog-footer">
|
|
<TMagicButton size="small" @click="difVisible = false">取消</TMagicButton>
|
|
<TMagicButton size="small" type="primary" @click="diffChange">确定</TMagicButton>
|
|
</span>
|
|
</template>
|
|
</TMagicDialog>
|
|
</template>
|
|
|
|
<script lang="ts" setup>
|
|
import { computed, inject, nextTick, onBeforeUnmount, ref } from 'vue';
|
|
|
|
import { TMagicButton, TMagicDialog, tMagicMessage, tMagicMessageBox, TMagicTag } from '@tmagic/design';
|
|
import { ColumnConfig, FormConfig, FormState, MFormBox } from '@tmagic/form';
|
|
import type { CodeBlockContent } from '@tmagic/schema';
|
|
|
|
import FloatingBox from '@editor/components/FloatingBox.vue';
|
|
import CodeEditor from '@editor/layouts/CodeEditor.vue';
|
|
import type { Services, SlideType } from '@editor/type';
|
|
import { getConfig } from '@editor/utils/config';
|
|
|
|
defineOptions({
|
|
name: 'MEditorCodeBlockEditor',
|
|
});
|
|
|
|
const props = defineProps<{
|
|
content: CodeBlockContent;
|
|
disabled?: boolean;
|
|
isDataSource?: boolean;
|
|
dataSourceType?: string;
|
|
slideType?: SlideType;
|
|
}>();
|
|
|
|
const emit = defineEmits<{
|
|
submit: [values: CodeBlockContent];
|
|
}>();
|
|
|
|
const services = inject<Services>('services');
|
|
|
|
const difVisible = ref(false);
|
|
const height = ref(globalThis.innerHeight);
|
|
|
|
const windowResizeHandler = () => {
|
|
height.value = globalThis.innerHeight;
|
|
};
|
|
|
|
globalThis.addEventListener('resize', windowResizeHandler);
|
|
|
|
onBeforeUnmount(() => {
|
|
globalThis.removeEventListener('resize', windowResizeHandler);
|
|
});
|
|
|
|
const magicVsEditor = ref<InstanceType<typeof CodeEditor>>();
|
|
|
|
const diffChange = () => {
|
|
if (!magicVsEditor.value || !formBox.value?.form) {
|
|
return;
|
|
}
|
|
|
|
formBox.value.form.values.content = magicVsEditor.value.getEditorValue();
|
|
|
|
difVisible.value = false;
|
|
};
|
|
|
|
const columnWidth = computed(() => services?.uiService.get('columnWidth'));
|
|
const size = computed(() =>
|
|
columnWidth.value ? columnWidth.value.center + columnWidth.value.right - (props.isDataSource ? 100 : 0) : 600,
|
|
);
|
|
|
|
const codeEditorHeight = ref('600px');
|
|
|
|
const defaultParamColConfig: ColumnConfig = {
|
|
type: 'row',
|
|
label: '参数类型',
|
|
items: [
|
|
{
|
|
text: '参数类型',
|
|
labelWidth: '70px',
|
|
type: 'select',
|
|
name: 'type',
|
|
options: [
|
|
{
|
|
text: '数字',
|
|
label: '数字',
|
|
value: 'number',
|
|
},
|
|
{
|
|
text: '字符串',
|
|
label: '字符串',
|
|
value: 'text',
|
|
},
|
|
{
|
|
text: '组件',
|
|
label: '组件',
|
|
value: 'ui-select',
|
|
},
|
|
],
|
|
},
|
|
],
|
|
};
|
|
|
|
const functionConfig = computed<FormConfig>(() => [
|
|
{
|
|
text: '名称',
|
|
name: 'name',
|
|
rules: [{ required: true, message: '请输入名称', trigger: 'blur' }],
|
|
},
|
|
{
|
|
text: '描述',
|
|
name: 'desc',
|
|
},
|
|
{
|
|
text: '执行时机',
|
|
name: 'timing',
|
|
type: 'select',
|
|
options: () => {
|
|
const options = [
|
|
{ text: '初始化前', value: 'beforeInit' },
|
|
{ text: '初始化后', value: 'afterInit' },
|
|
];
|
|
if (props.dataSourceType !== 'base') {
|
|
options.push({ text: '请求前', value: 'beforeRequest' });
|
|
options.push({ text: '请求后', value: 'afterRequest' });
|
|
}
|
|
return options;
|
|
},
|
|
display: () => props.isDataSource,
|
|
},
|
|
{
|
|
type: 'table',
|
|
border: true,
|
|
text: '参数',
|
|
enableFullscreen: false,
|
|
enableToggleMode: false,
|
|
name: 'params',
|
|
dropSort: false,
|
|
items: [
|
|
{
|
|
type: 'text',
|
|
label: '参数名',
|
|
name: 'name',
|
|
},
|
|
{
|
|
type: 'text',
|
|
label: '描述',
|
|
name: 'extra',
|
|
},
|
|
services?.codeBlockService.getParamsColConfig() || defaultParamColConfig,
|
|
],
|
|
},
|
|
{
|
|
name: 'content',
|
|
type: 'vs-code',
|
|
options: inject('codeOptions', {}),
|
|
height: codeEditorHeight.value,
|
|
onChange: (formState: FormState | undefined, code: string) => {
|
|
try {
|
|
// 检测js代码是否存在语法错误
|
|
getConfig('parseDSL')(code);
|
|
|
|
return code;
|
|
} catch (error: any) {
|
|
tMagicMessage.error(error.message);
|
|
|
|
throw error;
|
|
}
|
|
},
|
|
},
|
|
]);
|
|
|
|
const submitForm = (values: CodeBlockContent) => {
|
|
changedValue.value = undefined;
|
|
emit('submit', values);
|
|
};
|
|
|
|
const errorHandler = (error: any) => {
|
|
tMagicMessage.error(error.message);
|
|
};
|
|
|
|
const formBox = ref<InstanceType<typeof MFormBox>>();
|
|
|
|
const openHandler = () => {
|
|
setTimeout(() => {
|
|
if (formBox.value) {
|
|
const height = formBox.value?.bodyHeight - 348 - (props.isDataSource ? 50 : 0);
|
|
codeEditorHeight.value = `${height > 100 ? height : 600}px`;
|
|
}
|
|
});
|
|
};
|
|
|
|
const changedValue = ref<CodeBlockContent>();
|
|
const changeHandler = (values: CodeBlockContent) => {
|
|
changedValue.value = values;
|
|
};
|
|
|
|
const beforeClose = (done: (cancel?: boolean) => void) => {
|
|
if (!changedValue.value) {
|
|
editVisible.value = false;
|
|
done();
|
|
return;
|
|
}
|
|
tMagicMessageBox
|
|
.confirm('当前代码块已修改,是否保存?', '提示', {
|
|
confirmButtonText: '保存并关闭',
|
|
cancelButtonText: '不保存并关闭',
|
|
type: 'warning',
|
|
distinguishCancelAndClose: true,
|
|
})
|
|
.then(() => {
|
|
changedValue.value && submitForm(changedValue.value);
|
|
editVisible.value = false;
|
|
done();
|
|
})
|
|
.catch((action: string) => {
|
|
if (action === 'cancel') {
|
|
editVisible.value = false;
|
|
}
|
|
done(action === 'cancel');
|
|
});
|
|
};
|
|
|
|
const closedHandler = () => {
|
|
changedValue.value = undefined;
|
|
};
|
|
|
|
const boxVisible = ref<boolean>(false);
|
|
const editVisible = ref<boolean>(false);
|
|
const floatingBoxBody = ref<HTMLDivElement>();
|
|
|
|
const boxPosition = computed(() => {
|
|
const columnWidth = services?.uiService?.get('columnWidth');
|
|
const navMenuRect = services?.uiService?.get('navMenuRect');
|
|
return {
|
|
left: columnWidth?.left ?? 0,
|
|
top: (navMenuRect?.top ?? 0) + (navMenuRect?.height ?? 0),
|
|
};
|
|
});
|
|
|
|
defineExpose({
|
|
async show() {
|
|
if (props.slideType !== 'box') {
|
|
boxVisible.value = true;
|
|
await nextTick();
|
|
}
|
|
|
|
editVisible.value = true;
|
|
},
|
|
|
|
async hide() {
|
|
editVisible.value = false;
|
|
|
|
if (props.slideType !== 'box') {
|
|
await nextTick();
|
|
boxVisible.value = false;
|
|
}
|
|
},
|
|
});
|
|
</script>
|