/** * @description helper fns * @author wangfupeng */ import Uppy, { UppyFile } from '@uppy/core' import { IDomEditor } from '@wangeditor/editor' import { createUploader } from '@wangeditor/editor' import { AttachmentElement } from '../custom-types' import { IUploadConfigForAttachment } from './config' function getUploadAttachmentMenuConfig(editor: IDomEditor): IUploadConfigForAttachment { // 获取配置,见 `./config.js` return editor.getMenuConfig('uploadAttachment') as IUploadConfigForAttachment } /** * 插入 attachment 节点 * @param fileName fileName * @param link link */ export function insertAttachment(editor: IDomEditor, fileName: string, link: string) { if (!fileName || !link) return // 还原选区 editor.restoreSelection() // 插入节点 const attachmentElem: AttachmentElement = { type: 'attachment', fileName, link, children: [{ text: '' }], } editor.insertNode(attachmentElem) editor.move(1) // 回调 const { onInsertedAttachment } = getUploadAttachmentMenuConfig(editor) if (onInsertedAttachment) onInsertedAttachment(attachmentElem) } /** * 上传附件文件 * @param editor editor * @param files files */ export async function uploadAttachments(editor: IDomEditor, files: FileList | null) { if (files == null) return const fileList = Array.prototype.slice.call(files) // 获取菜单配置 const { customUpload } = getUploadAttachmentMenuConfig(editor) // 按顺序上传 for await (const file of fileList) { // 上传 if (customUpload) { // 自定义上传 await customUpload(file, (fileName: string, link: string) => insertAttachment(editor, fileName, link) ) } else { // 默认上传 await uploadFile(editor, file) } } } /** * 上传文件 * @param editor editor * @param file file */ async function uploadFile(editor: IDomEditor, file: File) { const uppy = getUppy(editor) const { name, type, size } = file uppy.addFile({ name, type, size, data: file, }) await uppy.upload() } // 存储 editor uppy 的关系 - 缓存 uppy ,不重复创建 const EDITOR_TO_UPPY_MAP = new WeakMap() /** * 获取 uppy 实例(并通过 editor 缓存) * @param editor editor */ function getUppy(editor: IDomEditor): Uppy { // 从缓存中获取 let uppy = EDITOR_TO_UPPY_MAP.get(editor) if (uppy != null) return uppy const menuConfig = getUploadAttachmentMenuConfig(editor) const { onSuccess, onProgress, onFailed, customInsert, onError } = menuConfig // 上传完成之后 const successHandler = (file: UppyFile, res: any) => { // 预期 res 格式: // 成功:{ errno: 0, data: { url } } // 失败:{ errno: !0, message: '失败信息' } if (customInsert) { // 用户自定义插入文件,此时 res 格式可能不符合预期 customInsert(res, file, (fileName: string, link: string) => insertAttachment(editor, fileName, link) ) return } const { errno = 1, data = {} } = res if (errno !== 0) { console.error(`'${file.name}' upload failed`, res) // failed 回调 onFailed(file, res) return } const { url = '' } = data insertAttachment(editor, file.name, url) // success 回调 onSuccess(file, res) } // progress 显示进度条 const progressHandler = (progress: number) => { editor.showProgressBar(progress) // 回调函数 onProgress && onProgress(progress) } // onError 提示错误 const errorHandler = (file: any, err: any, res: any) => { const fileName = file.name console.error(`'${fileName} upload error`, err, res) // 回调函数 onError && onError(file, err, res) } // 创建 uppy uppy = createUploader({ ...menuConfig, onProgress: progressHandler, onSuccess: successHandler, onError: errorHandler, }) // 缓存 uppy EDITOR_TO_UPPY_MAP.set(editor, uppy) return uppy }