|
|
|
@ -1,6 +1,22 @@ |
|
|
|
<template> |
|
|
|
<div> |
|
|
|
<el-upload |
|
|
|
:action="uploadUrl" |
|
|
|
:before-upload="handleBeforeUpload" |
|
|
|
:on-success="handleUploadSuccess" |
|
|
|
:on-error="handleUploadError" |
|
|
|
name="file" |
|
|
|
:show-file-list="false" |
|
|
|
:headers="headers" |
|
|
|
class="editor-img-uploader" |
|
|
|
v-if="type == 'url'" |
|
|
|
> |
|
|
|
<i ref="uploadRef" class="editor-img-uploader"></i> |
|
|
|
</el-upload> |
|
|
|
</div> |
|
|
|
<div class="editor"> |
|
|
|
<quill-editor |
|
|
|
ref="quillEditorRef" |
|
|
|
v-model:content="content" |
|
|
|
contentType="html" |
|
|
|
@textChange="(e) => $emit('update:modelValue', content)" |
|
|
|
@ -11,8 +27,17 @@ |
|
|
|
</template> |
|
|
|
|
|
|
|
<script setup> |
|
|
|
import { QuillEditor } from '@vueup/vue-quill'; |
|
|
|
import '@vueup/vue-quill/dist/vue-quill.snow.css'; |
|
|
|
import { QuillEditor } from "@vueup/vue-quill"; |
|
|
|
import "@vueup/vue-quill/dist/vue-quill.snow.css"; |
|
|
|
import { getToken } from "@/utils/auth"; |
|
|
|
|
|
|
|
const { proxy } = getCurrentInstance(); |
|
|
|
|
|
|
|
const quillEditorRef = ref(); |
|
|
|
const uploadUrl = ref(import.meta.env.VITE_APP_BASE_API + "/common/upload"); // 上传的图片服务器地址 |
|
|
|
const headers = ref({ |
|
|
|
Authorization: "Bearer " + getToken() |
|
|
|
}); |
|
|
|
|
|
|
|
const props = defineProps({ |
|
|
|
/* 编辑器的内容 */ |
|
|
|
@ -34,6 +59,16 @@ const props = defineProps({ |
|
|
|
type: Boolean, |
|
|
|
default: false, |
|
|
|
}, |
|
|
|
/* 上传文件大小限制(MB) */ |
|
|
|
fileSize: { |
|
|
|
type: Number, |
|
|
|
default: 5, |
|
|
|
}, |
|
|
|
/* 类型(base64格式、url格式) */ |
|
|
|
type: { |
|
|
|
type: String, |
|
|
|
default: "url", |
|
|
|
} |
|
|
|
}); |
|
|
|
|
|
|
|
const options = ref({ |
|
|
|
@ -55,7 +90,7 @@ const options = ref({ |
|
|
|
["link", "image", "video"] // 链接、图片、视频 |
|
|
|
], |
|
|
|
}, |
|
|
|
placeholder: '请输入内容', |
|
|
|
placeholder: "请输入内容", |
|
|
|
readOnly: props.readOnly |
|
|
|
}); |
|
|
|
|
|
|
|
@ -68,7 +103,7 @@ const styles = computed(() => { |
|
|
|
style.height = `${props.height}px`; |
|
|
|
} |
|
|
|
return style; |
|
|
|
}) |
|
|
|
}); |
|
|
|
|
|
|
|
const content = ref(""); |
|
|
|
watch(() => props.modelValue, (v) => { |
|
|
|
@ -77,10 +112,68 @@ watch(() => props.modelValue, (v) => { |
|
|
|
} |
|
|
|
}, { immediate: true }); |
|
|
|
|
|
|
|
// 如果设置了上传地址则自定义图片上传事件 |
|
|
|
onMounted(() => { |
|
|
|
if (props.type == 'url') { |
|
|
|
let quill = quillEditorRef.value.getQuill(); |
|
|
|
let toolbar = quill.getModule("toolbar"); |
|
|
|
toolbar.addHandler("image", (value) => { |
|
|
|
if (value) { |
|
|
|
proxy.$refs.uploadRef.click(); |
|
|
|
} else { |
|
|
|
quill.format("image", false); |
|
|
|
} |
|
|
|
}); |
|
|
|
} |
|
|
|
}); |
|
|
|
|
|
|
|
// 上传前校检格式和大小 |
|
|
|
function handleBeforeUpload(file) { |
|
|
|
const type = ["image/jpeg", "image/jpg", "image/png", "image/svg"]; |
|
|
|
const isJPG = type.includes(file.type); |
|
|
|
//检验文件格式 |
|
|
|
if (!isJPG) { |
|
|
|
proxy.$modal.msgError(`图片格式错误!`); |
|
|
|
return false; |
|
|
|
} |
|
|
|
// 校检文件大小 |
|
|
|
if (props.fileSize) { |
|
|
|
const isLt = file.size / 1024 / 1024 < props.fileSize; |
|
|
|
if (!isLt) { |
|
|
|
proxy.$modal.msgError(`上传文件大小不能超过 ${props.fileSize} MB!`); |
|
|
|
return false; |
|
|
|
} |
|
|
|
} |
|
|
|
return true; |
|
|
|
} |
|
|
|
|
|
|
|
// 上传成功处理 |
|
|
|
function handleUploadSuccess(res, file) { |
|
|
|
// 如果上传成功 |
|
|
|
if (res.code == 200) { |
|
|
|
// 获取富文本实例 |
|
|
|
let quill = toRaw(quillEditorRef.value).getQuill(); |
|
|
|
// 获取光标位置 |
|
|
|
let length = quill.selection.savedRange.index; |
|
|
|
// 插入图片,res.url为服务器返回的图片链接地址 |
|
|
|
quill.insertEmbed(length, "image", import.meta.env.VITE_APP_BASE_API + res.fileName); |
|
|
|
// 调整光标到最后 |
|
|
|
quill.setSelection(length + 1); |
|
|
|
} else { |
|
|
|
proxy.$modal.msgError("图片插入失败"); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// 上传失败处理 |
|
|
|
function handleUploadError() { |
|
|
|
proxy.$modal.msgError("图片插入失败"); |
|
|
|
} |
|
|
|
</script> |
|
|
|
|
|
|
|
<style> |
|
|
|
.editor-img-uploader { |
|
|
|
display: none; |
|
|
|
} |
|
|
|
.editor, .ql-toolbar { |
|
|
|
white-space: pre-wrap !important; |
|
|
|
line-height: normal !important; |
|
|
|
@ -96,11 +189,9 @@ watch(() => props.modelValue, (v) => { |
|
|
|
content: "保存"; |
|
|
|
padding-right: 0px; |
|
|
|
} |
|
|
|
|
|
|
|
.ql-snow .ql-tooltip[data-mode="video"]::before { |
|
|
|
content: "请输入视频地址:"; |
|
|
|
} |
|
|
|
|
|
|
|
.ql-snow .ql-picker.ql-size .ql-picker-label::before, |
|
|
|
.ql-snow .ql-picker.ql-size .ql-picker-item::before { |
|
|
|
content: "14px"; |
|
|
|
@ -117,7 +208,6 @@ watch(() => props.modelValue, (v) => { |
|
|
|
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="huge"]::before { |
|
|
|
content: "32px"; |
|
|
|
} |
|
|
|
|
|
|
|
.ql-snow .ql-picker.ql-header .ql-picker-label::before, |
|
|
|
.ql-snow .ql-picker.ql-header .ql-picker-item::before { |
|
|
|
content: "文本"; |
|
|
|
@ -146,7 +236,6 @@ watch(() => props.modelValue, (v) => { |
|
|
|
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="6"]::before { |
|
|
|
content: "标题6"; |
|
|
|
} |
|
|
|
|
|
|
|
.ql-snow .ql-picker.ql-font .ql-picker-label::before, |
|
|
|
.ql-snow .ql-picker.ql-font .ql-picker-item::before { |
|
|
|
content: "标准字体"; |
|
|
|
|