Files
wwjcloud-nest-v1/admin-vben/apps/web-antd/src/views/diy/design/components/edit-rich-text.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>