| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181 |
- <template>
- <div ref="divRef" :style="{ height, minHeight }" />
- </template>
- <script setup lang="ts">
- import { propTypes } from "@/utils/propTypes";
- import { globalHeaders } from "@/utils/request";
- import { AiEditor } from "aieditor";
- import "aieditor/dist/style.css";
- const divRef = ref();
- let aiEditor = ref<AiEditor | null>(null);
- const baseUrl = import.meta.env.VITE_APP_BASE_API;
- const uploadFileUrl = ref(baseUrl + '/resource/oss/upload'); // 上
- const headers = ref(globalHeaders());
- const props = defineProps({
- /* 编辑器的内容 */
- modelValue: propTypes.string.def(''),
- /* 高度 */
- height: propTypes.number.def(400),
- /* 最小高度 */
- minHeight: propTypes.number.def(400),
- /* 只读 */
- readOnly: propTypes.bool.def(false),
- /* 上传文件大小限制(MB) */
- fileSize: propTypes.number.def(5),
- /* 类型(base64格式、url格式) */
- type: propTypes.string.def('url'),
- placeholder: propTypes.string,
- });
- const emit = defineEmits(['update:modelValue']);
- const { proxy } = getCurrentInstance() as ComponentInternalInstance;
- const initEditor = () => {
- aiEditor.value = new AiEditor({
- element: divRef.value as Element,
- placeholder: props.placeholder || '请输入内容',
- draggable: true,
- content: props.modelValue,
- toolbarKeys: ["undo", "redo", "brush", "eraser",
- "|", "heading", "font-family", "font-size",
- "|", "bold", "italic", "underline", "strike", "link", "code", "subscript", "superscript", "hr", "todo", "emoji",
- "|", "highlight", "font-color",
- "|", "align", "line-height",
- "|", "bullet-list", "ordered-list", "indent-decrease", "indent-increase", "break",
- "|", "image", "video", "attachment", "quote", "code-block", "table",
- "|", "source-code", "printer", "fullscreen",
- ],
- image: {
- allowBase64: true,
- defaultSize: 350,
- // customMenuInvoke: (editor: AiEditor) => {
- // },
- uploadUrl: uploadFileUrl.value,
- uploadFormName: "file", //上传时的文件表单名称
- uploadHeaders: {
- ...headers.value
- },
- uploaderEvent: {
- onUploadBefore: (file, uploadUrl, headers) => {
- //监听图片上传之前,此方法可以不用回任何内容,但若返回 false,则终止上传
- return handleBeforeUpload(file);
- },
- onSuccess: (file, response) => {
- //监听图片上传成功
- //注意:
- // 1、如果此方法返回 false,则图片不会被插入到编辑器
- // 2、可以在这里返回一个新的 json 给编辑器
- if (response.code == 200) {
- proxy?.$modal.closeLoading();
- // 根据图片宽高设置默认显示大小
- return {
- "errorCode": 0,
- "data": {
- src: response.data.url,
- alt: file.name,
- loading: true,
- "align": "left",
- "width": "400px",
- "height": "auto",
- 'data-src': response.data.url
- }
- }
- }
- },
- onFailed: (file, response) => {
- //监听图片上传失败,或者返回的 json 信息不正确
- console.log('onFailed', file, response);
- },
- onError: (file, error) => {
- //监听图片上传错误,比如网络超时等
- },
- },
- bubbleMenuItems: ["AlignLeft", "AlignCenter", "AlignRight", "delete"]
- },
- video: {
- uploadHeaders: {
- ...headers.value
- },
- uploadUrl: uploadFileUrl.value,
- uploadFormName: "file", //上传时的文件表单名称
- uploaderEvent: {
- onUploadBefore: (file, uploadUrl, headers) => {
- console.log(file);
- //监听视频上传之前,此方法可以不用回任何内容,但若返回 false,则终止上传
- return handleBeforeUpload(file);
- },
- onSuccess: (file, response) => {
- //监听视频上传成功
- //注意:
- // 1、如果此方法返回 false,则视频不会被插入到编辑器
- // 2、可以在这里返回一个新的 json 给编辑器
- if (response.code == 200) {
- proxy?.$modal.closeLoading();
- return {
- "errorCode": 0,
- "data": {
- src: response.data.url,
- poster: "",
- "width": "480px",
- "height": "320px",
- controls: true,
- 'data-src': response.data.url
- }
- }
- }
- },
- onFailed: (file, response) => {
- //监听视频上传失败,或者返回的 json 信息不正确
- console.log('onFailed', file, response);
- },
- onError: (file, error) => {
- //监听视频上传错误,比如网络超时等
- },
- },
- },
- onChange: (aiEditor) => {
- // 监听到用编辑器内容发生变化了,控制台打印编辑器的 html 内容...
- emit('update:modelValue', aiEditor.getHtml());
- }
- })
- }
- onMounted(() => {
- // 等待1s,确保modelValue有值
- setTimeout(() => {
- initEditor();
- }, 1000);
- })
- // 图片上传前拦截
- const handleBeforeUpload = (file: any) => {
- 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;
- }
- }
- proxy?.$modal.loading('正在上传文件,请稍候...');
- return true;
- };
- onUnmounted(() => {
- aiEditor.value && aiEditor.value.destroy();
- })
- </script>
- <style>
- .aie-content p {
- margin: 0;
- }
- </style>
|