UNPKG

vue-cloud-upload

Version:

基于vue+elementui的通用云上传组件,无缝衔接腾讯云,华为云,火山云等桶平台,开箱即用

1,104 lines (1,103 loc) 36 kB
var B = Object.defineProperty, A = Object.defineProperties; var j = Object.getOwnPropertyDescriptors; var L = Object.getOwnPropertySymbols; var D = Object.prototype.hasOwnProperty, M = Object.prototype.propertyIsEnumerable; var R = (i, e, t) => e in i ? B(i, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : i[e] = t, x = (i, e) => { for (var t in e || (e = {})) D.call(e, t) && R(i, t, e[t]); if (L) for (var t of L(e)) M.call(e, t) && R(i, t, e[t]); return i; }, N = (i, e) => A(i, j(e)); var m = (i, e, t) => R(i, typeof e != "symbol" ? e + "" : e, t); var u = (i, e, t) => new Promise((s, r) => { var l = (c) => { try { a(t.next(c)); } catch (n) { r(n); } }, o = (c) => { try { a(t.throw(c)); } catch (n) { r(n); } }, a = (c) => c.done ? s(c.value) : Promise.resolve(c.value).then(l, o); a((t = t.apply(i, e)).next()); }); import F from "vue"; import { Upload as V, Image as J, Tooltip as q, Dialog as W, Loading as G } from "element-ui"; class p { /** * 获取文件后缀名(不带点) * @param {File|string} file 文件对象或文件名 * @return {string} 文件后缀 */ static getFileExtension(e) { return (typeof e == "string" ? e : e.name).split(".").pop().toLowerCase(); } /** * 获取文件大小(MB为单位) * @param {File} file 文件对象 * @return {number} 文件大小MB */ static getFileSizeMB(e) { return parseFloat((e.size / (1024 * 1024)).toFixed(2)); } /** * 获取文件大小带单位自动转换(B/KB/MB/GB) * @param {File} file 文件对象 * @return {string} 带单位的文件大小 */ static getFileSizeAuto(e) { const t = e.size; return t < 1024 ? t + " B" : t < 1048576 ? (t / 1024).toFixed(2) + " KB" : t < 1073741824 ? (t / 1048576).toFixed(2) + " MB" : (t / 1073741824).toFixed(2) + " GB"; } /** * 检查文件类型是否在允许列表中 * @param {File} file 文件对象 * @param {string[]} allowedTypes 允许的后缀名数组(如 ['jpg', 'png']) * @return {boolean} 是否允许 */ static checkFileType(e, t) { const s = p.getFileExtension(e); return t.includes(s); } /** * 生成文件预览URL(适用于图片/PDF等) * @param {File} file 文件对象 * @return {Promise<string>} 预览URL */ static generatePreviewURL(e) { return new Promise((t, s) => { const r = new FileReader(); r.onload = (l) => t(l.target.result), r.onerror = (l) => s(l), r.readAsDataURL(e); }); } /** * 通用文件下载方法 * @param {string} url - 文件下载地址 * @param {string} [filename] - 可选自定义文件名 */ static downloadFile(e, t) { let s = ""; if (t) s = t; else { const r = decodeURIComponent(e); s = r.substring(r.lastIndexOf("/") + 1).split("?")[0]; } fetch(e).then((r) => r.blob()).then((r) => { const l = document.createElement("a"); l.href = URL.createObjectURL(r), l.download = s, document.body.appendChild(l), l.click(), document.body.removeChild(l), URL.revokeObjectURL(l.href); }).catch((r) => console.error("下载失败:", r)); } /** * 获取文件分类 * @param {Object} file - 文件对象 */ static getFileType(e) { let t = ""; if (e.name && e.name != "") t = p.getFileExtension(e); else { if (!e.url) return "other"; t = p.getFileExtension(e.url); } if (p.getIfImage(e)) return "image"; let s = ""; switch (t) { case "doc": case "docx": s = "word"; break; case "pdf": s = "pdf"; break; case "ppt": case "pptx": s = "ppt"; break; case "xls": case "xlsx": case "csv": s = "excel"; break; case "rar": case "zip": case "7z": case "gzip": case "tar": s = "rar"; break; case "mp4": case "webm": case "ogg": case "mpeg": s = "video"; break; case "mp3": case "aac": case "wav": case "flac": case "opus": s = "audio"; break; case "txt": s = "txt"; break; default: s = "other"; break; } return s; } /** * 判断文件是否为图片 * @param {Object} file - 文件对象 */ static getIfImage(e) { let t = ""; if (e.name && e.name != "") t = p.getFileExtension(e); else { if (!e.url) return !1; t = p.getFileExtension(e.url); } return ["png", "jpg", "jpeg", "bmp", "gif", "webp", "svg"].some((r) => r === t); } /** * 获取文件名 * @param {Object} file - 文件对象 */ static getFileName(e) { if (e.name) return e.name; if (e.url && e.url != "") { const t = decodeURIComponent(e.url); return t.substring(t.lastIndexOf("/") + 1).split("?")[0]; } else return ""; } } function z(i, e, t, s, r, l, o, a) { var c = typeof i == "function" ? i.options : i; return e && (c.render = e, c.staticRenderFns = t, c._compiled = !0), l && (c._scopeId = "data-v-" + l), { exports: i, options: c }; } const X = { props: { visible: { type: Boolean }, file: { type: Object, required: !0 } }, data() { return { currentVisible: this.visible, fileType: "", fileName: "", fileRaw: null, pdfUrl: "", fileContent: "", loading: !1, fullscreen: !1 }; }, computed: { formattedText() { return this.fileContent.replace(/\n/g, "<br>"); }, dialogWidth() { return this.fileType == "audio" ? "30%" : "75%"; } }, methods: { handleOpen() { }, handleClose() { this.$emit("update:visible", !1); }, initTxtContent() { if (!this.fileRaw) return; const i = new FileReader(); i.onload = (e) => { this.fileContent = e.target.result; }, i.readAsText(this.fileRaw); }, initPdfContent() { this.pdfUrl = URL.createObjectURL(this.fileRaw); } }, watch: { visible(i) { this.currentVisible = i; }, file: function(i) { return u(this, null, function* () { if (this.loading = !0, this.fileName = p.getFileName(i), this.fileType = p.getFileType(i), i.raw && i.raw instanceof File) this.fileRaw = i.raw; else if (this.fileType == "txt" || this.fileType == "pdf") try { const t = yield (yield fetch(i.url)).blob(); this.fileRaw = t; } catch (e) { console.error("文件下载失败:", e); return; } switch (this.fileType) { case "txt": this.initTxtContent(); break; case "pdf": this.initPdfContent(); break; } this.loading = !1; }); } } }; var Q = function() { var e = this, t = e._self._c; return t("el-dialog", { attrs: { visible: e.currentVisible, title: e.fileName, "custom-class": "file-preview-dialog", "append-to-body": "", fullscreen: e.fullscreen, width: e.dialogWidth }, on: { "update:visible": function(s) { e.currentVisible = s; }, open: e.handleOpen, close: e.handleClose }, scopedSlots: e._u([{ key: "title", fn: function() { return [t("div", { staticClass: "dialog-header" }, [t("span", [e._v(e._s(e.fileName))]), t("i", { class: [ "preview-header-icon", e.fullscreen ? "el-icon-copy-document" : "el-icon-full-screen" ], on: { click: function(s) { e.fullscreen = !e.fullscreen; } } })])]; }, proxy: !0 }]) }, [t("div", { directives: [{ name: "loading", rawName: "v-loading", value: e.loading, expression: "loading" }], class: [ "file-preview-content", e.fileType == "audio" ? "preview-audio" : "" ] }, [e.fileType == "txt" ? t("div", { domProps: { innerHTML: e._s(e.formattedText) } }) : e._e(), e.fileType == "pdf" ? t("iframe", { staticClass: "pdf-container", attrs: { src: e.pdfUrl, frameborder: "0" } }) : e._e(), e.fileType == "video" && e.currentVisible ? t("video", { ref: "cloud-upload-video", attrs: { controls: "", src: e.file.url, autoplay: "", preload: "auto", crossorigin: "" } }) : e._e(), e.fileType == "audio" && e.currentVisible ? t("audio", { attrs: { controls: "", src: e.file.url, autoplay: "", preload: "auto", crossorigin: "" } }) : e._e()])]); }, Y = [], Z = /* @__PURE__ */ z( X, Q, Y, !1, null, "ab02c2c8" ); const H = Z.exports, ee = "useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict"; let P = (i = 21) => { let e = "", t = crypto.getRandomValues(new Uint8Array(i |= 0)); for (; i--; ) e += ee[t[i] & 63]; return e; }, k = null, E = null; F.component("el-upload", V); F.component("el-image", J); F.component("el-tooltip", q); F.component("el-dialog", W); F.use(G.directive); const te = { name: "CloudUpload", inheritAttrs: !1, props: { /** * 是否支持多选文件 */ multiple: { type: Boolean, default: !1 }, /** * 是否显示已上传文件列表 */ showFileList: { type: Boolean, default: !0 }, /** * 是否启用拖拽上传 */ drag: { type: Boolean, default: !1 }, /** * 接受上传的文件类型(thumbnail-mode 模式下此参数无效) */ accept: { type: String }, /** * 文件列表的类型 text/picture/picture-card */ listType: { type: String, default: "picture-card", validator: (i) => { const e = ["text", "picture", "picture-card"]; return e.includes(i) ? !0 : (console.error( `listType参数必须是以下值之一: ${e.join(", ")} 当前值: "${i}"将回退到默认值"picture-card"` ), !1); } }, /** * 是否禁用 */ disabled: { type: Boolean, default: !1 }, /** * 最大允许上传个数 */ limit: { type: Number }, /** * 单个附件大小限制mb */ maxSize: { type: Number }, /** * 默认ui组件大小 medium / small / mini */ size: { type: String, default: "small", validator: (i) => { const e = ["medium", "small", "mini"]; return e.includes(i) ? !0 : (console.error( `listType参数必须是以下值之一: ${e.join(", ")} 当前值: "${i}"将回退到默认值"small"` ), !1); } }, /** * 触发分块上传的阈值 默认10Mb */ sliceSize: { type: Number, default: 1024 * 1024 * 10 }, /** * 分块大小,默认5MB,非必须 */ chunkSize: { type: Number, default: 1024 * 1024 * 5 }, /** * 对象存储桶中文件的key配置 */ fileKey: { type: String, default: "uuid+name", validator: (i) => { const e = ["uuid", "name", "uuid+name"]; return e.includes(i) ? !0 : (console.error( `listType参数必须是以下值之一: ${e.join(", ")} 当前值: "${i}"将回退到默认值"uuid+name"` ), !1); } }, /** * 使用的云平台类型 tencent腾讯云桶 */ cloudType: { type: String, default: "tencent", validator: (i) => { const e = ["tencent", "huawei"]; return e.includes(i) ? !0 : (console.error( `listType参数必须是以下值之一: ${e.join(", ")} 当前值: "${i}"将回退到默认值"tencent"` ), !1); } }, /** * 云平台配置参数,包含桶名,地域,上传目录,凭证获取等 */ cloudConfig: { type: Object, required: !0, default: () => ({ bucket: "", region: "", path: "", getTempCredential: () => ({ TmpSecretId: "", TmpSecretKey: "", SecurityToken: "", StartTime: "", ExpiredTime: "" }) }) }, /** * 附件预览/在线查看配置 */ previewConfig: { type: Object, required: !1 }, /** * 自定义v-model */ value: { type: Array, default: () => { } }, /** * 上传文件之前的钩子,参数为上传的文件,若返回 false 或者返回 Promise 且被 reject,则停止上传。 */ beforeUpload: { type: Function, required: !1 }, /** * 文件超出个数限制时的钩子 */ onExceed: { type: Function, required: !1 } }, data() { return { fileList: this.value, previewUrl: "", previewVisible: !1, previewFile: {} }; }, computed: { getPreviewList() { let i = []; return this.fileList.forEach((e) => { this.getIfImage(e) && i.push(e.url); }), i; }, getPreviewConfig() { return Object.assign( { image: !0, //图片附件默认开启预览 video: !0, //视频附件默认不开启预览 audio: !0, //音频附件默认不开启预览 word: !1, //word excel: !1, //excel ppt: !1, //ppt txt: !0, //txt pdf: !0, //pdf rar: !1 //压缩包 }, this.previewConfig ); } }, created() { this.checkAndInit(this.cloudConfig); }, beforeDestroy() { k.destroyInstance(); }, methods: { /** * 检查关键props传入是否规范并初始化上传实例 */ checkAndInit(i) { return u(this, null, function* () { const e = ["tencent", "huawei"]; switch (this.cloudType ? e.includes(this.cloudType) || console.warn(`云平台类型cloudType设置错误,应为${e.join("/")}`) : console.warn("未设置云平台类型cloudType!"), this.cloudType) { case "tencent": k = (yield Promise.resolve().then(() => ae)).default, k.getInstance(i); break; case "huawei": E = (yield Promise.resolve().then(() => ne)).default, E.getInstance(i); } }); }, getImgRef(i) { return `previewImg${this.getPreviewList.findIndex((e) => e == i.url)}`; }, getFileName(i) { return p.getFileName(i); }, getIfImage(i) { return p.getIfImage(i); }, getFileType(i) { return p.getFileType(i); }, getFileIcon(i) { const e = this.getFileType(i); return { image: "", video: "icon-video", audio: "icon-audio", rar: "icon-yasuobao", word: "icon-WORD", excel: "icon-EXCEL", ppt: "icon-ppt", txt: "icon-txt", pdf: "icon-Pdf", other: "icon-fujian1" }[e]; }, getFileLoading(i) { var t; if (!((t = this.$refs.innerUpload) != null && t.uploadFiles)) return !1; const e = this.$refs.innerUpload.uploadFiles.find( (s) => s.uid == i.uid || s.url == i.url ); return e ? !!(e.percentage && e.percentage < 1) : !1; }, getFilePercent(i) { var t; if (!((t = this.$refs.innerUpload) != null && t.uploadFiles)) return ""; const e = this.$refs.innerUpload.uploadFiles.find( (s) => s.uid == i.uid || s.url == i.url ); return e ? e.percentage && e.percentage < 1 ? `上传中${Math.round(e.percentage * 1e3) / 10}%` : "上传完成" : ""; }, // 自定义上传方法 customUpload(i) { return u(this, null, function* () { const { file: e, onProgress: t, onSuccess: s, onError: r } = i; let l = this.generateKey(e.name); const o = N(x({ file: e, key: l, chunkSize: this.chunkSize, sliceSize: this.sliceSize }, this.cloudConfig), { onProgress: (a) => { console.log("当前进度:", a), t({ percent: a }), this.$emit("progress", a, e); } }); try { let a; switch (this.cloudType) { case "tencent": if (a = yield k.getInstance().uploadFile(o), a.statusCode == 200) { const c = this.$refs.innerUpload.uploadFiles.findIndex( (d) => d.uid == e.uid ); let n = this.$refs.innerUpload.uploadFiles[c]; const h = Object.assign(n, { url: a.url, response: a }); this.$refs.innerUpload.uploadFiles.splice(c, 1, h), this.fileList = this.$refs.innerUpload.uploadFiles; } break; case "huawei": if (a = yield E.getInstance().uploadFile(o), a.CommonMsg.Status == 200) { const c = this.$refs.innerUpload.uploadFiles.findIndex( (d) => d.uid == e.uid ); let n = this.$refs.innerUpload.uploadFiles[c]; const h = Object.assign(n, { response: a }); this.$refs.innerUpload.uploadFiles.splice(c, 1, h), this.fileList = this.$refs.innerUpload.uploadFiles; } break; default: throw new Error(`Unsupported cloudType: ${this.cloudType}`); } s(a, e), this.$emit("success", a, e), this.$emit("input", this.fileList); } catch (a) { r(a, e), this.$emit("error", a, e); } }); }, generateKey(i) { let e = ""; switch (this.fileKey) { case "name": e = `${this.cloudConfig.path}${i}`; break; case "uuid": const t = p.getFileExtension(i); e = `${this.cloudConfig.path}${P()}.${t}`; break; case "uuid+name": e = `${this.cloudConfig.path}${P()}/${i}`; break; } return e; }, onbeforeUpload(i) { if (this.beforeUpload && typeof this.beforeUpload == "function") return this.beforeUpload(); { let e = !0; if (this.accept) { const s = this.accept.split(",").map((r) => r.replace(".", "")); e = p.checkFileType(i, s); } const t = this.maxSize ? p.getFileSizeMB(i) < this.maxSize : !0; return e ? t ? !0 : (this.$message.error(`文件大小不能超过 ${this.maxSize}MB!`), !1) : (this.$message.error(`文件类型必须是 ${this.accept} 中的一种!`), !1); } }, handleRemove(i, e) { this.fileList = this.fileList.filter( (t) => t.uid != i.uid && t.url != i.url ), this.$emit("input", this.fileList); }, handlePreview(i) { if (this.onPreview && typeof this.onPreview == "function") this.onPreview(i); else if (this.getFileType(i) == "image") { const t = this.getImgRef(i); this.$refs[t].clickHandler(); } else this.previewFile = i, this.previewVisible = !0; }, handleDown(i) { this.$message.success("文件开始下载,请稍等!"), p.downloadFile(i.url, i.name); }, handleExceed(i, e) { this.onExceed && typeof this.onExceed == "function" ? this.onExceed(i, e) : this.$message.warning(`当前限制最多选择${this.limit}个文件!`); } }, watch: { value(i) { this.fileList = i; }, cloudType(i) { this.checkAndInit(this.cloudConfig); }, cloudConfig: { deep: !0, //immediate: true, handler(i) { this.checkAndInit(i); } } }, components: { FilePreview: H } }; var ie = function() { var e = this, t = e._self._c; return t("div", { class: ["cloud-upload", "cloud-upload-" + e.size] }, [t("el-upload", e._g(e._b({ ref: "innerUpload", attrs: { action: "#", "file-list": e.fileList, multiple: e.multiple, accept: e.accept, limit: e.limit, drag: e.drag, "show-file-list": e.showFileList, "on-exceed": e.handleExceed, "on-remove": e.handleRemove, "on-preview": e.handlePreview, "before-upload": e.onbeforeUpload, "http-request": e.customUpload, "list-type": e.listType }, scopedSlots: e._u([{ key: "file", fn: function({ file: s }) { return !e.$scopedSlots.file && e.listType == "picture-card" ? [e.getIfImage(s) ? t("el-image", { directives: [{ name: "loading", rawName: "v-loading", value: e.getFileLoading(s), expression: "getFileLoading(file)" }], ref: e.getImgRef(s), staticClass: "el-upload-list__item-thumbnail", attrs: { "preview-src-list": e.getPreviewList, fit: "contain", "element-loading-text": e.getFilePercent(s), src: s.url } }) : t("div", { directives: [{ name: "loading", rawName: "v-loading", value: e.getFileLoading(s), expression: "getFileLoading(file)" }], staticClass: "el-upload-list__item-thumbnail previewIcon", attrs: { "element-loading-text": e.getFilePercent(s) } }, [t("i", { class: ["cloud-upload-icon", e.getFileIcon(s)] })]), t("span", { staticClass: "el-upload-list__item-actions" }, [e.getPreviewConfig[e.getFileType(s)] && s.status == "success" ? t("span", { staticClass: "el-upload-list__item-preview" }, [t("i", { staticClass: "el-icon-view", on: { click: () => e.handlePreview(s) } })]) : e._e(), t("span", { staticClass: "el-upload-list__item-delete" }, [t("i", { staticClass: "el-icon-download", on: { click: () => e.handleDown(s) } })]), e.disabled ? e._e() : t("span", { staticClass: "el-upload-list__item-delete", on: { click: () => e.handleRemove(s) } }, [t("i", { staticClass: "el-icon-delete" })])]), t("el-tooltip", { staticClass: "item", attrs: { effect: "light", content: e.getFileName(s), placement: "top" } }, [t("span", { staticClass: "file-name", on: { click: () => e.handleDown(s) } }, [e._v(e._s(e.getFileName(s)))])])] : void 0; } }], null, !0) }, "el-upload", e.$attrs, !1), e.$listeners), [e.$scopedSlots.default ? e._e() : [e.listType == "picture-card" ? t("div", { staticClass: "default-content" }, [t("i", { staticClass: "el-icon-upload", attrs: { slot: "default" }, slot: "default" }), t("span", { directives: [{ name: "show", rawName: "v-show", value: !e.disabled, expression: "!disabled" }] }, [e._v("点击上传")])]) : t("el-button", { attrs: { size: e.size, type: "primary" } }, [e._v("点击上传")])], e._l(e.$scopedSlots, function(s, r) { return [e._t(r, null, null, e.scoped)]; })], 2), t("FilePreview", { attrs: { visible: e.previewVisible, file: e.previewFile }, on: { "update:visible": function(s) { e.previewVisible = s; } } })], 1); }, se = [], re = /* @__PURE__ */ z( te, ie, se, !1, null, "ef761d25" ); const I = re.exports, v = class v { constructor(e) { // 外部传入的OBS对象 m(this, "obsClient", null); m(this, "tempCredential", null); m(this, "accessKeyId", null); m(this, "secretAccessKey", null); m(this, "securityToken", null); m(this, "server", null); e && e.server && (this.server = e.server), e && e.accessKeyId && e.secretAccessKey && (this.accessKeyId = e.accessKeyId, this.secretAccessKey = e.secretAccessKey), this.initClient(e); } // 设置外部OBS对象的静态方法 static setExternalOBS(e) { this.externalOBS = e; } static getInstance(e) { return this.instance || e && (e.accessKeyId && e.secretAccessKey && !e.getTempCredential || e.getTempCredential && typeof e.getTempCredential == "function") && (this.instance = new v(e)), this.instance; } static destroyInstance() { this.instance = null, this.obsClient = null, this.tempCredential = null, localStorage.removeItem("obsCpDatas"), localStorage.removeItem("obsCredential"); } initClient(e) { return u(this, null, function* () { let t = v.externalOBS; if (this.accessKeyId && this.secretAccessKey && !e.getTempCredential) this.obsClient = new t({ access_key_id: this.accessKeyId, secret_access_key: this.secretAccessKey, server: this.server }); else if (e.getTempCredential) yield this.getTempCredential(e.getTempCredential), this.obsClient = new t({ access_key_id: this.tempCredential.accessKeyId, secret_access_key: this.tempCredential.secretAccessKey, security_token: this.tempCredential.securityToken, server: this.server }); else throw new Error( "缺少必要的认证信息:需要提供永久密钥或getTempCredential函数" ); this.obsClient.initLog({ level: "warn" // 配置日志级别 }); }); } getTempCredential(e) { return u(this, null, function* () { let t = localStorage.getItem("obsCredential"); if (t && (t = JSON.parse(t)), t && !this.isCredentialExpired(t)) { this.tempCredential = t; return; } try { const s = yield e(); s && typeof s == "object" && (this.tempCredential = { accessKeyId: s.credentials.accessKeyId, secretAccessKey: s.credentials.secretAccessKey, securityToken: s.credentials.securityToken, expiredTime: s.expiredTime }, localStorage.setItem( "obsCredential", JSON.stringify(this.tempCredential) )); } catch (s) { throw new Error("获取临时凭证失败: " + s.message); } }); } isCredentialExpired(e = this.tempCredential) { return e ? Math.floor(Date.now() / 1e3) >= e.expiredTime - 60 : !0; } // 确保使用有效的凭证 ensureValidCredential(e) { return u(this, null, function* () { if (e && (!this.tempCredential || this.isCredentialExpired())) { yield this.getTempCredential(e); let t = v.externalOBS; this.obsClient = new t({ access_key_id: this.tempCredential.accessKeyId, secret_access_key: this.tempCredential.secretAccessKey, security_token: this.tempCredential.securityToken, server: this.server }); } }); } // 单文件上传 uploadFile(c) { return u(this, arguments, function* ({ bucket: e, key: t, file: s, sliceSize: r, chunkSize: l, onProgress: o, getTempCredential: a }) { if (yield this.ensureValidCredential(a), s.size < r) try { const n = yield this.obsClient.putObject({ Bucket: e, Key: t, SourceFile: s, ProgressCallback: (h, d, C) => { o && typeof o == "function" && o(h / d); } }); if (n.CommonMsg.Status < 300) return x({ key: t, name: s.name }, n); throw new Error(`上传失败: ${n.CommonMsg.Code}`); } catch (n) { throw new Error(`华为云OBS上传失败: ${n.message}`); } else try { let n = []; const h = localStorage.getItem("obsCpDatas"); h && (n = JSON.parse(h)); const d = `${s.name}-${s.size}-${s.lastModified}`, C = n.findIndex((y) => y.key == d), w = C >= 0; let f = w ? n[C].cp : null, T; if (f ? (f.sourceFile = s, T = yield this.obsClient.uploadFile({ UploadCheckpoint: f, ProgressCallback: (y, g, U) => { o && typeof o == "function" && o(y / g); }, EventCallback: function(y, g, U) { if (y == "uploadPartSucceed") { const O = n.findIndex((b) => b.key == d), K = f.parts.findIndex( (b) => b.partNumber == g.partNumber ); f.parts[K].isCompleted = !0, n[O].cp = f, localStorage.setItem("obsCpDatas", JSON.stringify(n)); } } })) : T = yield this.obsClient.uploadFile({ Bucket: e, Key: t, SourceFile: s, PartSize: l, ProgressCallback: (y, g, U) => { o && typeof o == "function" && o(y / g); }, ResumeCallback: function(y, g) { console.log("记录断点:", g), f = g, w ? n[C].cp = f : (n.push({ key: d, cp: f }), localStorage.setItem("obsCpDatas", JSON.stringify(n))); }, EventCallback: function(y, g, U) { if (y == "uploadPartSucceed") { const O = n.findIndex((b) => b.key == d), K = f.parts.findIndex( (b) => b.partNumber == g.partNumber ); f.parts[K].isCompleted = !0, n[O].cp = f, localStorage.setItem("obsCpDatas", JSON.stringify(n)); } } }), T.CommonMsg.Status < 300) { const y = n.findIndex((g) => g.key == d); return n.splice(y, 1), localStorage.setItem("obsCpDatas", JSON.stringify(n)), x({ key: t, name: s.name }, T); } else throw new Error(`上传失败: ${T.CommonMsg.Code}`); } catch (n) { throw new Error(`华为云OBS上传失败: ${n.message}`); } }); } // 图片加水印(华为云OBS处理方式) addWatermark(l) { return u(this, arguments, function* ({ bucket: e, region: t, key: s, watermarkText: r }) { try { return { processedUrl: `https://${e}.obs.${t}.myhuaweicloud.com/${s}?x-image-process=image/watermark,text_${encodeURIComponent( r )},color_FFFFFF,size_20,g_se,x_20,y_20`, originalKey: s }; } catch (o) { throw new Error(`添加水印失败: ${o.message}`); } }); } }; m(v, "instance", null), m(v, "externalOBS", null); let _ = v; const ne = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({ __proto__: null, default: _ }, Symbol.toStringTag, { value: "Module" })), S = class S { constructor(e) { // 外部传入的COS对象 m(this, "cosClient", null); m(this, "tempCredential", null); m(this, "secretId", null); m(this, "secretKey", null); e && e.secretId && e.secretKey && (this.secretId = e.secretId, this.secretKey = e.secretKey), this.initClient(e); } // 设置外部COS对象的静态方法 static setExternalCOS(e) { this.externalCOS = e; } static getInstance(e) { return this.instance || e && (e.secretId && e.secretKey || e.getTempCredential && typeof e.getTempCredential == "function") && (this.instance = new S(e)), this.instance; } static destroyInstance() { this.instance = null, this.cosClient = null, this.tempCredential = null, localStorage.removeItem("cosCredential"); } initClient(e) { return u(this, null, function* () { let t = S.externalCOS; if (this.secretId && this.secretKey) this.cosClient = new t({ SecretId: this.secretId, SecretKey: this.secretKey }); else { const s = e.getTempCredential; yield this.getTempCredential(s), this.cosClient = new t({ getAuthorization: (r, l) => u(this, null, function* () { try { (!this.tempCredential || this.isCredentialExpired()) && (yield this.getTempCredential(s)), l({ TmpSecretId: this.tempCredential.tmpSecretId, TmpSecretKey: this.tempCredential.tmpSecretKey, SecurityToken: this.tempCredential.sessionToken, StartTime: this.tempCredential.startTime, ExpiredTime: this.tempCredential.expiredTime }); } catch (o) { console.error("获取临时凭证失败:", o); } }) }); } }); } getTempCredential(e) { return u(this, null, function* () { let t = localStorage.getItem("cosCredential"); if (t && (t = JSON.parse(t)), t && !this.isCredentialExpired(t)) { this.tempCredential = t; return; } try { const s = yield e(); s && typeof s == "object" && (this.tempCredential = { tmpSecretId: s.credentials.tmpSecretId, tmpSecretKey: s.credentials.tmpSecretKey, sessionToken: s.credentials.sessionToken, startTime: s.startTime, expiredTime: s.expiredTime }, localStorage.setItem( "cosCredential", JSON.stringify(this.tempCredential) )); } catch (s) { throw new Error("获取临时凭证失败: " + s.message); } }); } isCredentialExpired(e = this.tempCredential) { return e ? Math.floor(Date.now() / 1e3) >= e.expiredTime - 60 : !0; } // 单文件上传 uploadFile({ bucket: e, region: t, key: s, file: r, sliceSize: l, chunkSize: o, onProgress: a }) { return new Promise((c, n) => u(this, null, function* () { const h = yield this.isBucketPublicRead({ bucket: e, region: t }); this.cosClient.uploadFile( { Bucket: e, Region: t, Key: s, Body: r, SliceSize: l, // 触发分块上传的阈值,超过5MB使用分块上传,默认 1MB,非必须 ChunkSize: o, // 分块大小,默认 1MB,非必须 onProgress: (d) => { a && typeof a == "function" && a(d.percent); } }, (d, C) => { if (d) n(d); else if (h) { const w = C.Location.startsWith("https://") ? C.Location : "https://" + C.Location; c(x({ url: w, key: s, name: r.name }, C)); } else this.cosClient.getObjectUrl( { Bucket: e, Region: t, Key: s, Sign: !0 }, function(w, f) { w ? console.log(w) : c(x({ url: f.Url, key: s, name: r.name }, C)); } ); } ); })); } // 图片加水印 addWatermark(l) { return u(this, arguments, function* ({ bucket: e, region: t, key: s, watermarkText: r }) { const o = { Bucket: e, Region: t, Key: s, PicOperations: JSON.stringify({ is_pic_info: 1, rules: [ { fileid: `watermark_${s}`, rule: `watermark/2/text/${encodeURIComponent( r )}/fill/IzAwMDAwMA/fontsize/20/dissolve/50/gravity/southeast/dx/20/dy/20` } ] }) }; return new Promise((a, c) => { this.cosClient.ciPutObjectFromLocalFile(o, (n, h) => { n ? c(n) : a(h); }); }); }); } // 获取存储桶ACL(访问控制列表) getBucketAcl(s) { return u(this, arguments, function* ({ bucket: e, region: t }) { return new Promise((r, l) => { this.cosClient.getBucketAcl( { Bucket: e, Region: t }, (o, a) => { o ? l(o) : r(a); } ); }); }); } // 检查存储桶是否为公有读 isBucketPublicRead(s) { return u(this, arguments, function* ({ bucket: e, region: t }) { try { return (yield this.getBucketAcl({ bucket: e, region: t })).Grants.some( (l) => l.Grantee.URI === "http://cam.qcloud.com/groups/global/AllUsers" && l.Permission === "READ" ); } catch (r) { return console.error("检查存储桶权限失败:", r), !0; } }); } }; m(S, "instance", null), m(S, "externalCOS", null); let $ = S; const ae = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({ __proto__: null, default: $ }, Symbol.toStringTag, { value: "Module" })); function de(i) { $.setExternalCOS(i); } function ue(i) { _.setExternalOBS(i); } I.install = function(i) { i.component(I.name, I); }; typeof window != "undefined" && window.Vue && window.Vue.component(I.name, I); export { I as default, de as setExternalCOS, ue as setExternalOBS };