Files
workspace/code/container-ocr/ocr-vue/src/components/wang-editor/index.vue
T
2026-03-23 17:29:20 +08:00

237 lines
4.6 KiB
Vue

<script setup>
import { Editor, Toolbar } from "@wangeditor/editor-for-vue";
import { ElMessage } from "element-plus";
import {
computed,
defineExpose,
nextTick,
onBeforeUnmount,
onMounted,
ref,
shallowRef,
watch,
} from "vue";
import { uploadFile, uploadImage, uploadVideo } from "@/utils/file";
import { registerPreviewMenu, toolbarConfig } from "./config";
import Direcotry from "./modules/directory.vue";
import Preview from "./modules/preview.vue";
import "@wangeditor/editor/dist/css/style.css";
const props = defineProps({
displayMode: {
type: String,
default: "edit", // edit / view
},
modelValue: {
type: String,
default: "",
},
showDirecotry: {
type: Boolean,
default: false,
},
moduleId: {
type: String,
required: true,
},
father: {
type: [String, Number],
required: true,
},
});
const emit = defineEmits(["update:modelValue"]);
const previewHtml = ref("");
const showPreview = ref(false);
// 内容
const valueHtml = ref("");
onMounted(() => {
registerPreviewMenu(() => {
previewHtml.value = valueHtml.value;
showPreview.value = true;
});
});
// 编辑器实例
const editorRef = shallowRef();
watch(
() => props.modelValue,
(val) => {
valueHtml.value = val;
},
{ immediate: true },
);
const toolbarClass = computed(() =>
props.displayMode === "view" ? "toolbar-view" : "toolbar-edit",
);
const editorClass = computed(() => (props.displayMode === "view" ? "editor-view" : "editor-edit"));
defineExpose({
getText: () => {
return editorRef.value ? editorRef.value.getText() : "";
},
});
function handleChange() {
emit("update:modelValue", valueHtml.value);
}
// ================= 编辑器配置 =================
const editorConfig = {
placeholder: props.displayMode === "edit" ? "请输入内容..." : "",
readOnly: props.displayMode === "view",
MENU_CONF: {},
};
// 图片上传
editorConfig.MENU_CONF.uploadImage = {
async customBrowseAndUpload(insertFn) {
try {
const data = await uploadImage();
if (!data) return;
const res = await uploadFile(
data.blob,
data.fileName,
data.fileExt,
data.fileSize,
0,
props.moduleId,
props.father,
"",
);
insertFn(res.mx_mapfilename, res.mx_filename, "");
} catch (e) {
ElMessage.error("图片上传失败");
console.log(e);
}
},
};
// 视频上传
editorConfig.MENU_CONF.uploadVideo = {
async customBrowseAndUpload(insertFn) {
try {
const data = await uploadVideo();
if (!data) return;
const res = await uploadFile(
data.blob,
data.fileName,
data.fileExt,
data.fileSize,
0,
props.moduleId,
props.father,
"",
);
insertFn(res.mx_mapfilename, res.mx_filename, "");
} catch (e) {
ElMessage.error("视频上传失败");
}
},
};
// 销毁编辑器
onBeforeUnmount(() => {
const editor = editorRef.value;
if (editor) editor.destroy();
});
function handleCreated(editor) {
editorRef.value = editor;
nextTick(() => {});
}
</script>
<template>
<div v-loading="false" class="w-full h-full editor-container">
<div class="main">
<Toolbar
v-if="props.displayMode === 'edit'"
class="toolbar"
:class="toolbarClass"
:editor="editorRef"
:default-config="toolbarConfig"
/>
<Editor
key="main"
v-model="valueHtml"
class="editor"
:class="editorClass"
:default-config="editorConfig"
@on-change="handleChange"
@on-created="handleCreated"
/>
</div>
<Direcotry v-if="showDirecotry" v-model:content="valueHtml" class="directory" />
</div>
<Preview v-model:visible="showPreview" :content="previewHtml" />
</template>
<style scoped>
.toolbar {
}
.toolbar-view {
}
.toolbar-edit {
border: 1px solid #ccc;
}
.editor {
overflow-y: hidden;
}
/* 原来 .editor 内嵌的 :deep */
.editor :deep(.w-e-text-container video) {
width: 100% !important;
}
.editor-view {
height: auto;
}
/* 原来 .editor-view 内嵌的 :deep */
.editor-view :deep(.w-e-text-container) {
background-color: transparent;
}
.editor-view :deep(.w-e-text-container .w-e-scroll [data-slate-editor]) {
overflow-y: auto;
padding: 0 !important;
}
.editor-edit {
height: 500px !important;
border: 1px solid #ccc;
border-top: transparent;
}
.editor-container {
display: flex;
gap: 44px;
}
/* 原来 .editor-container 内嵌的 .directory */
.editor-container .directory {
width: 200px;
height: 450px;
}
/* 原来 .editor-container 内嵌的 .main */
.editor-container .main {
flex: 1;
}
</style>