import { set } from "lodash"; import loading from "@/components/Provider/Loading"; import { message } from "ant-design-vue"; export class UploadController { request: any; blobURLMaps = new Map(); constructor(request: any) { this.request = request; } getBlobURLName(url: string) { return this.blobURLMaps.get(url)?.name; } createObjectURL(obj: Blob): string { const url = URL.createObjectURL(obj); this.blobURLMaps.set(url, obj); return url; } revokeObjectURL(url: string) { URL.revokeObjectURL(url); this.blobURLMaps.delete(url); } selectFile(opts?: { accept?: string; multiple?: boolean }): Promise { return new Promise((resolve, reject) => { const fileInput = document.createElement("input"); fileInput.type = "file"; fileInput.accept = opts?.accept || "images/*"; fileInput.multiple = opts?.multiple || false; fileInput.onchange = function (this: any) { resolve([...this.files]); }; window.addEventListener( "focus", () => { setTimeout(() => { reject(console.warn("select file cancel")); }, 300); }, { once: true } ); fileInput.click(); }); } async uploadBlobImages(data: object) { const todoMap = new Map(); addBlobToList(data); const todoList = todoMap.entries(); let err = ""; for (const item of todoList) { const [blobUrl, path] = item; const file = this.blobURLMaps.get(blobUrl); if (file) { const paths = path.split(","); loading.show("上传中"); const ret = await this.uploadImage(file); if (ret.url) { paths.forEach((p) => { set(data, p, ret.url); }); this.revokeObjectURL(blobUrl); } else { err = ret.error || `上传文件失败[${path}]`; break; } } else { err = `上传文件为空[${path}]`; } } loading.hidden(); if (err) { message.error(err); throw err; } function addBlobToList(data: any, path = "") { if (data instanceof Object) { if (data instanceof Array) { data.forEach((item, i) => { addBlobToList(item, path ? path + "." + i : i.toString()); }); } else { Object.entries(data).forEach(([key, value]) => { addBlobToList(value, path ? path + "." + key : key); }); } } if (typeof data === "string" && /^blob:/.test(data)) { if (todoMap.has(data)) { path = todoMap.get(data) + "," + path; } todoMap.set(data, path); } } } async uploadImage(file: File): Promise<{ url?: string; error?: string }> { const fromData = new FormData(); fromData.append("image", file); try { const ret = await this.request("/upload/image", { method: "POST", data: fromData, headers: { "Content-Type": "multipart/form-data", }, }); if (ret.errorNo != 200) { return { error: "上传失败!" }; } const url = ret.result.url; return { url }; } catch (e) { return { error: "上传失败!" }; } } async uploadFile(file: File): Promise<{ url?: string; error?: string }> { const fromData = new FormData(); fromData.append("file", file); try { const ret = await this.request("/upload/file", { method: "POST", data: fromData, headers: { "Content-Type": "multipart/form-data", }, }); if (ret.errorNo != 200) { return { error: "上传失败!" }; } const url = ret.result.url; return { url }; } catch (e) { return { error: "上传失败!" }; } } getFileExt(file: File) { let ext: any = "unkown"; if (file) { const exp = /^.+\.(.+)$/; if (file.name && exp.test(file.name)) { ext = (exp.exec(file.name) as any)[1]; } else if (file.type) { ext = file.type.split("/").pop(); } return ext.toLowerCase(); } else { return ext; } } }