187 lines
3.7 KiB
Vue
187 lines
3.7 KiB
Vue
<template>
|
|
<div class="space-y-4">
|
|
<!-- Content Tab -->
|
|
<div v-if="editTab === 'content'" class="space-y-4">
|
|
<div class="border-t-2 border-gray-100 pt-4 first:border-t-0 first:pt-0">
|
|
<h3 class="mb-3 font-medium">{{ $t('system.diy.richTextContent') }}</h3>
|
|
|
|
<a-form :label-col="{ span: 6 }" :wrapper-col="{ span: 18 }">
|
|
<!-- Rich Text Editor -->
|
|
<a-form-item :label="$t('system.diy.content')">
|
|
<div class="border rounded">
|
|
<Toolbar
|
|
:editor="editorRef"
|
|
:defaultConfig="toolbarConfig"
|
|
:mode="'default'"
|
|
class="border-b"
|
|
/>
|
|
<Editor
|
|
:defaultConfig="editorConfig"
|
|
:mode="'default'"
|
|
v-model="localValue.html"
|
|
@onCreated="handleCreated"
|
|
class="h-[400px]"
|
|
/>
|
|
</div>
|
|
</a-form-item>
|
|
</a-form>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Style Tab -->
|
|
<div v-if="editTab === 'style'" class="space-y-4">
|
|
<ComponentStyleEditor
|
|
:value="localValue"
|
|
@update:value="updateLocalValue"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { ref, shallowRef, watch, onBeforeUnmount } from 'vue';
|
|
import { Editor, Toolbar } from '@wangeditor/editor-for-vue';
|
|
import { cloneDeep } from 'lodash-es';
|
|
|
|
import ComponentStyleEditor from './component-style-editor.vue';
|
|
|
|
interface Props {
|
|
value: any;
|
|
editTab: 'content' | 'style';
|
|
}
|
|
|
|
interface Emits {
|
|
(e: 'update:value', value: any): void;
|
|
}
|
|
|
|
const props = defineProps<Props>();
|
|
const emit = defineEmits<Emits>();
|
|
|
|
const editorRef = shallowRef();
|
|
const localValue = ref<any>({
|
|
html: '',
|
|
margin: {
|
|
top: 0,
|
|
bottom: 10,
|
|
both: 0,
|
|
},
|
|
topRounded: 0,
|
|
bottomRounded: 0,
|
|
componentStartBgColor: '',
|
|
componentEndBgColor: '',
|
|
componentGradientAngle: 'to bottom',
|
|
componentBgUrl: '',
|
|
componentBgAlpha: 2,
|
|
isHidden: false,
|
|
});
|
|
|
|
const toolbarConfig = {
|
|
toolbarKeys: [
|
|
'headerSelect',
|
|
'blockquote',
|
|
'|',
|
|
'bold',
|
|
'underline',
|
|
'italic',
|
|
'color',
|
|
'bgColor',
|
|
'|',
|
|
'fontSize',
|
|
'fontFamily',
|
|
'lineHeight',
|
|
'|',
|
|
'bulletedList',
|
|
'numberedList',
|
|
'|',
|
|
'insertLink',
|
|
'insertImage',
|
|
'|',
|
|
'emotion',
|
|
'|',
|
|
'undo',
|
|
'redo',
|
|
],
|
|
};
|
|
|
|
const editorConfig = {
|
|
placeholder: '请输入内容...',
|
|
MENU_CONF: {
|
|
uploadImage: {
|
|
server: '/api/upload/image',
|
|
fieldName: 'file',
|
|
maxFileSize: 2 * 1024 * 1024,
|
|
allowedFileTypes: ['image/*'],
|
|
meta: {
|
|
type: 'rich_text',
|
|
},
|
|
customInsert: (res: any, insertFn: Function) => {
|
|
insertFn(res.data.url);
|
|
},
|
|
},
|
|
},
|
|
};
|
|
|
|
const handleCreated = (editor: any) => {
|
|
editorRef.value = editor;
|
|
};
|
|
|
|
const updateLocalValue = (newValue: any) => {
|
|
localValue.value = {
|
|
...localValue.value,
|
|
...newValue,
|
|
};
|
|
};
|
|
|
|
// Initialize local value
|
|
const initLocalValue = () => {
|
|
if (props.value) {
|
|
localValue.value = {
|
|
...localValue.value,
|
|
...props.value,
|
|
};
|
|
}
|
|
};
|
|
|
|
// Watch for value changes
|
|
watch(
|
|
() => props.value,
|
|
() => {
|
|
initLocalValue();
|
|
},
|
|
{ immediate: true, deep: true }
|
|
);
|
|
|
|
// Watch for local changes
|
|
watch(
|
|
localValue,
|
|
(newValue) => {
|
|
emit('update:value', newValue);
|
|
},
|
|
{ deep: true }
|
|
);
|
|
|
|
// Destroy editor on unmount
|
|
onBeforeUnmount(() => {
|
|
const editor = editorRef.value;
|
|
if (editor) {
|
|
editor.destroy();
|
|
}
|
|
});
|
|
|
|
// Initialize
|
|
initLocalValue();
|
|
</script>
|
|
|
|
<style scoped>
|
|
:deep(.w-e-text-container) {
|
|
min-height: 400px !important;
|
|
}
|
|
|
|
:deep(.ant-form-item) {
|
|
margin-bottom: 16px;
|
|
}
|
|
|
|
:deep(.ant-form-item:last-child) {
|
|
margin-bottom: 0;
|
|
}
|
|
</style> |