Open longsiping opened 1 month ago
import React, { memo, useState, useEffect, useCallback } from "react"; import { Editor, Toolbar } from '@wangeditor/editor-for-react'; import { IDomEditor, IEditorConfig, IToolbarConfig, DomEditor } from '@wangeditor/editor'; import '@wangeditor/editor/dist/css/style.css'; import { message, Spin } from '@alipay/bigfish/antd'; import { uploadFile } from "@/services/upload_file";
type InsertFnType = (url: string, alt: string, href: string) => void
interface getFileUrlType { id: number; orderId: number; filePosition: string; moduleType: string; fileType: string; fileName: string; fileSize: string; gmtCreate: string; gmtModified: string; url: string; };
interface MonoContext { html: string; setHtml: (html: string) => void; flag?: boolean; width?: number; height?: number; onChange?: (value: string) => void; maxLength: number; isUploadImage?: boolean; orderId?: string; filePosition?: string; moduleType?: string; getWork?: () => void; setCurrentImage?: (value: any) => void; };
export default memo((props: MonoContext) => {
const { html, setHtml, flag, width = 480, height = 400, onChange, isUploadImage = false, orderId, filePosition, moduleType, getWork, setCurrentImage } = props;
const [loading, setLoading] = useState<boolean>(false);
const [editor, setEditor] = useState<IDomEditor | null>(null);
//工具栏配置
const toolbarConfig: Partial<IToolbarConfig> = {
//排除掉哪些功能
// excludeKeys: [
// 'group-video',
// 'group-image',
// "sup",
// "sub",
// "fullScreen",
// "insertTable",
// "fontFamily",
// 'undo',
// 'redo'
// ],
//重新配置某些功能
toolbarKeys: [
"headerSelect",
"fontSize",
"bold",
"italic",
"underline",
"through",
"color",
"bgColor",
// "lineHeight",
{
key: "group-more-style",
title: '更多',
menuKeys: [
"divider",
"codeBlock",
"bulletedList",
"numberedList",
// "todo",
// "code",
"insertLink",
'blockquote',
isUploadImage ? "uploadImage" : '',
"insertTable",
"fullScreen"
],
iconSvg: `<svg viewBox="0 0 1024 1024"><path d="M204.8 505.6m-76.8 0a76.8 76.8 0 1 0 153.6 0 76.8 76.8 0 1 0-153.6 0Z"></path><path d="M505.6 505.6m-76.8 0a76.8 76.8 0 1 0 153.6 0 76.8 76.8 0 1 0-153.6 0Z"></path><path d="M806.4 505.6m-76.8 0a76.8 76.8 0 1 0 153.6 0 76.8 76.8 0 1 0-153.6 0Z"></path></svg>`
}
]
// modalAppendToBody:true
};
//编辑器配置
const editorConfig: Partial<IEditorConfig> = {
placeholder: '请输入内容...',
readOnly: flag, //是否只读
MENU_CONF: {
'fontSize': {
fontSizeList: [
{ name: '初号', value: '56px' },
{ name: '小初', value: '48px' },
{ name: '一号', value: '34px' },
{ name: '小一', value: '32px' },
{ name: '二号', value: '29px' },
{ name: '小二', value: '24px' },
{ name: '三号', value: '21px' },
{ name: '小三', value: '20px' },
{ name: '四号', value: '18px' },
{ name: '小四', value: '16px' },
{ name: '五号', value: '14px' },
{ name: '小五', value: '12px' },
]
},
// 'fontFamily': {
// fontFamilyList: [
// {
// name: '黑体', value: '黑体'
// },
// {
// name: '楷体', value: '楷体'
// },
// {
// name: '仿宋', value: '仿宋'
// },
// {
// name: '宋体', value: '宋体'
// }
// ]
// },
// 'lineHeight': {
// lineHeightList: ['1', '1.5', '2', '2.5']
// },
//上传图片的拦截
'uploadImage': isUploadImage ? {
fieldName: 'file',
allowedFileTypes: ['image/*'],
//server: '/api/v1/napa/web/transformWorkOrder/uploadFile',
maxNumberOfFiles: 2,
// meta: {
// orderId,
// filePosition,
// moduleType
// },
// headers: {
// accept: 'application/json'
// },
//自定义上传逻辑,
customUpload: async (file: File, insertFn: InsertFnType) => {
const formData = new FormData();
formData.append('file', file);
formData.append('orderId', orderId);
formData.append('filePosition', filePosition);
formData.append('moduleType', moduleType);
const res: any = await uploadFile(formData, {}).catch((err) => {
message.error('上传失败');
}).finally(() => setLoading(false));
if (res.success) {
message.success('上传成功');
if (typeof getWork === 'function') {
const data: any = await getWork();
const filerFile = data?.bkBankFileUploadInfoModels?.filter((item: getFileUrlType) => item.filePosition == filePosition) ?? [];
if (filerFile?.length > 0) {
const url = filerFile[filerFile.length - 1].url;
const poster = filerFile[filerFile.length - 1].url;
const alt = filerFile[filerFile.length - 1].fileName;
insertFn(url, alt,poster);
}
};
};
},
//上传前拦截
onBeforeUpload: (file: File) => {
let flag = true;
for (let key in file) {
flag = file[key].type.includes('image');
};
if (flag) {
return file
} else {
return false;
}
}
} : {},
//上传视频的拦截
'uploadVideo': {
onInsertedVideo(videoNode) {
return message.error('识别错误')
}
},
'codeSelectLang': {
codeLangs: [
{ text: 'CSS', value: 'css' },
{ text: 'HTML', value: 'html' },
{ text: 'XML', value: 'xml' },
{ text: 'JSON', value: 'json' },
{ test: 'JavaScript', value: 'javascript' },
{ text: 'JAVA', value: 'java' },
]
}
},
//告警配置
customAlert: (s, t) => {
switch (t) {
case 'success':
message.success(s)
break
case 'info':
message.info(s)
break
case 'warning':
message.warning(s)
break
case 'error':
message.error(s)
break
default:
message.info(s)
break
}
},
//粘贴配置
customPaste: (editor: IDomEditor, event: any) => {
const html = event.clipboardData.getData('text/html');
const text = event.clipboardData.getData('text/plain');
const rtf = event.clipboardData.getData('text/rtf');
if (!html && !text) {
message.error('无法识别复制内容')
return false;
};
return true
}
};
useEffect(() => {
//富文本实例
//@ts-ignore
const toolbar = DomEditor.getToolbar(editor);
// console.log(toolbar?.getConfig().toolbarKeys, '默认配置');
// console.log(editor?.getAllMenuKeys(), '查询编辑器注册的所有菜单key');
return () => {
if (editor == null) return;
editor.destroy()
setEditor(null)
}
}, [editor]);
return <>
<div style={{ border: '1px solid #ccc', zIndex: 100, width: width }}>
<Toolbar
editor={editor}
defaultConfig={toolbarConfig}
mode="default"
style={{ borderBottom: '1px solid #ccc' }}
/>
<Spin spinning={loading}>
<Editor
defaultConfig={editorConfig}
value={html}
onCreated={setEditor}
onChange={editor => {
const text = editor.getText();
const html = editor.getHtml();
const isEmpty = editor.isEmpty();
if (typeof setCurrentImage === 'function') {
setCurrentImage(editor?.getElemsByType('image'));
};
setHtml(isEmpty ? '' : html);
if (onChange && typeof onChange === 'function') {
onChange(isEmpty ? '' : html);
}
// setContentFlag(editor.isEmpty());
}}
mode="default"
style={{ height: height }}
/>
</Spin>
</div>
</>
});
bug 描述
使用wangEditor5.1.23版本,customUpload自定义上传功能,调用insertFn方法插入富文本内时,只上传一张图片没啥问题,上传完成后,再继续上传一张,就提示子节点无法找到;[Unhandled Rejection (Error): Cannot find a descendant at path [0,4] in node: {"children"](global.js:1 Uncaught (in promise) Error: Cannot find a descendant at path [1] in node: {"children":[{"type":"paragraph","children":[{"text":"1231"}]}],"operations":[],"selection":{"anchor":{"path":[1,0],"offset":0},"focus":{"path":[1,0],"offset":0}},"marks":null,"id":"wangEditor-10","isDestroyed":false,"isFullScreen":false,"history":{"undos":[[{"type":"split_node","path":[0,0],"position":4,"properties":{}},{"type":"split_node","path":[0],"position":1,"properties":{"type":"paragraph"}}],[{"type":"remove_text","path":[0,0],"offset":0,"text":"1231"},{"type":"remove_node","path":[0],"node":{"type":"paragraph","children":[{"text":""}]}},{"type":"remove_node","path":[0],"node":{"type":"paragraph","children":[{"text":""}]}},{"type":"insert_node","path":[0],"node":{"type":"paragraph","children":[{"text":"1231"}]}},{"type":"set_selection","properties":{"anchor":{"path":[0,0],"offset":4},"focus":{"path":[0,0],"offset":4}},"newProperties":{"anchor":{"path":[1,0],"offset":0},"focus":{"path":[1,0],"offset":0}}}]],"redos":[]}})
代码