UNPKG

@cqmcui/cqmcui

Version:

轻量级移动端 Vue2、Vue3 组件库(支持小程序开发)

474 lines (473 loc) 16.8 kB
var __defProp = Object.defineProperty; var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __publicField = (obj, key, value) => { __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value); return value; }; import { reactive, computed, h, resolveComponent, openBlock, createElementBlock, normalizeClass, renderSlot, createBlock, resolveDynamicComponent, createCommentVNode, Fragment, renderList, createElementVNode, toDisplayString, createVNode } from "vue"; import { c as createComponent } from "./component-81a4c1d0.js"; import { f as funInterceptor } from "./interceptor-956b24fc.js"; import Progress from "./Progress.js"; import { Photograph, Failure, Loading, Del, Link } from "@cqmcui/icons-vue"; import { _ as _export_sfc } from "./_plugin-vue_export-helper-cc2b3d55.js"; import "../locale/lang"; class UploadOptions { constructor() { __publicField(this, "url", ""); __publicField(this, "name", "file"); __publicField(this, "fileType", "image"); __publicField(this, "formData"); __publicField(this, "sourceFile"); __publicField(this, "method", "post"); __publicField(this, "xhrState", 200); __publicField(this, "timeout", 30 * 1e3); __publicField(this, "headers", {}); __publicField(this, "withCredentials", false); __publicField(this, "onStart"); __publicField(this, "taroFilePath"); __publicField(this, "onProgress"); __publicField(this, "onSuccess"); __publicField(this, "onFailure"); __publicField(this, "beforeXhrUpload"); } } class Uploader { constructor(options) { __publicField(this, "options"); this.options = options; } upload() { var _a; const options = this.options; const xhr = new XMLHttpRequest(); xhr.timeout = options.timeout; if (xhr.upload) { xhr.upload.addEventListener( "progress", (e) => { var _a2; (_a2 = options.onProgress) == null ? void 0 : _a2.call(options, e, options); }, false ); xhr.onreadystatechange = () => { var _a2, _b; if (xhr.readyState === 4) { if (xhr.status == options.xhrState) { (_a2 = options.onSuccess) == null ? void 0 : _a2.call(options, xhr.responseText, options); } else { (_b = options.onFailure) == null ? void 0 : _b.call(options, xhr.responseText, options); } } }; xhr.withCredentials = options.withCredentials; xhr.open(options.method, options.url, true); for (const [key, value] of Object.entries(options.headers)) { xhr.setRequestHeader(key, value); } (_a = options.onStart) == null ? void 0 : _a.call(options, options); if (options.beforeXhrUpload) { options.beforeXhrUpload(xhr, options); } else { xhr.send(options.formData); } } else { console.warn("浏览器不支持 XMLHttpRequest"); } } } const { translate: translate$1 } = createComponent("uploader"); class FileItem { constructor() { __publicField(this, "status", "ready"); __publicField(this, "message", translate$1("ready")); __publicField(this, "uid", (/* @__PURE__ */ new Date()).getTime().toString()); __publicField(this, "name"); __publicField(this, "url"); __publicField(this, "type"); __publicField(this, "path"); __publicField(this, "percentage", 0); __publicField(this, "formData", {}); } } const { componentName, create, translate } = createComponent("uploader"); const _sfc_main = create({ components: { [Progress.name]: Progress, Photograph, Failure, Loading, Del, Link }, props: { name: { type: String, default: "file" }, url: { type: String, default: "" }, // defaultFileList: { type: Array, default: () => new Array<FileItem>() }, timeout: { type: [Number, String], default: 1e3 * 30 }, fileList: { type: Array, default: () => [] }, isPreview: { type: Boolean, default: true }, // picture、list listType: { type: String, default: "picture" }, isDeletable: { type: Boolean, default: true }, method: { type: String, default: "post" }, capture: { type: Boolean, default: false }, maximize: { type: [Number, String], default: Number.MAX_VALUE }, maximum: { type: [Number, String], default: 1 }, clearInput: { type: Boolean, default: true }, accept: { type: String, default: "*" }, headers: { type: Object, default: {} }, data: { type: Object, default: {} }, xhrState: { type: [Number, String], default: 200 }, withCredentials: { type: Boolean, default: false }, multiple: { type: Boolean, default: false }, disabled: { type: Boolean, default: false }, autoUpload: { type: Boolean, default: true }, beforeUpload: { type: Function, default: null }, beforeXhrUpload: { type: Function, default: null }, beforeDelete: { type: Function, default: (file, files) => { return true; } }, onChange: { type: Function } }, emits: [ "start", "progress", "oversize", "success", "failure", "change", "delete", "update:fileList", "file-item-click" ], setup(props, { emit }) { const fileList = reactive(props.fileList); let uploadQueue = []; const classes = computed(() => { const prefixCls = componentName; return { [prefixCls]: true }; }); const renderInput = () => { let params = { class: `cqmc-uploader__input`, type: "file", accept: props.accept, multiple: props.multiple, name: props.name, disabled: props.disabled }; if (props.capture) params.capture = "camera"; return h("input", params); }; const clearInput = (el) => { el.value = ""; }; const fileItemClick = (fileItem) => { emit("file-item-click", { fileItem }); }; const executeUpload = (fileItem, index2) => { const uploadOption = new UploadOptions(); uploadOption.url = props.url; uploadOption.formData = fileItem.formData; uploadOption.timeout = props.timeout * 1; uploadOption.method = props.method; uploadOption.xhrState = props.xhrState; uploadOption.headers = props.headers; uploadOption.withCredentials = props.withCredentials; uploadOption.beforeXhrUpload = props.beforeXhrUpload; try { uploadOption.sourceFile = fileItem.formData.get(props.name); } catch (error) { } uploadOption.onStart = (option) => { fileItem.status = "ready"; fileItem.message = translate("readyUpload"); clearUploadQueue(index2); emit("start", option); }; uploadOption.onProgress = (event, option) => { fileItem.status = "uploading"; fileItem.message = translate("uploading"); fileItem.percentage = (event.loaded / event.total * 100).toFixed(0); emit("progress", { event, option, percentage: fileItem.percentage }); }; uploadOption.onSuccess = (responseText, option) => { fileItem.status = "success"; fileItem.message = translate("success"); emit("success", { responseText, option, fileItem }); emit("update:fileList", fileList); }; uploadOption.onFailure = (responseText, option) => { fileItem.status = "error"; fileItem.message = translate("error"); emit("failure", { responseText, option, fileItem }); }; let task = new Uploader(uploadOption); if (props.autoUpload) { task.upload(); } else { uploadQueue.push( new Promise((resolve, reject) => { resolve(task); }) ); } }; const clearUploadQueue = (index2 = -1) => { if (index2 > -1) { uploadQueue.splice(index2, 1); } else { uploadQueue = []; fileList.splice(0, fileList.length); } }; const submit = () => { Promise.all(uploadQueue).then((res) => { res.forEach((i) => i.upload()); }); }; const readFile = (files) => { files.forEach((file, index2) => { const formData = new FormData(); for (const [key, value] of Object.entries(props.data)) { formData.append(key, value); } formData.append(props.name, file); const fileItem = reactive(new FileItem()); fileItem.name = file.name; fileItem.status = "ready"; fileItem.type = file.type; fileItem.formData = formData; fileItem.message = translate("waitingUpload"); executeUpload(fileItem, index2); if (props.isPreview && file.type.includes("image")) { const reader = new FileReader(); reader.onload = (event) => { fileItem.url = event.target.result; fileList.push(fileItem); }; reader.readAsDataURL(file); } else { fileList.push(fileItem); } }); }; const filterFiles = (files) => { const maximum = props.maximum * 1; const maximize = props.maximize * 1; const oversizes = new Array(); files = files.filter((file) => { if (file.size > maximize) { oversizes.push(file); return false; } else { return true; } }); if (oversizes.length) { emit("oversize", oversizes); } let currentFileLength = files.length + fileList.length; if (currentFileLength > maximum) { files.splice(files.length - (currentFileLength - maximum)); } return files; }; const deleted = (file, index2) => { fileList.splice(index2, 1); emit("delete", { file, fileList, index: index2 }); }; const onDelete = (file, index2) => { clearUploadQueue(index2); funInterceptor(props.beforeDelete, { args: [file, fileList], done: () => deleted(file, index2) }); }; const onChange = (event) => { if (props.disabled) { return; } const $el = event.target; let { files } = $el; if (props.beforeUpload) { props.beforeUpload(files).then((f) => changeReadFile(f)); } else { changeReadFile(files); } emit("change", { fileList, event }); if (props.clearInput) { clearInput($el); } }; const changeReadFile = (f) => { const _files = filterFiles(new Array().slice.call(f)); readFile(_files); }; return { onChange, onDelete, fileList, classes, fileItemClick, clearUploadQueue, submit, renderInput }; } }); const _hoisted_1 = { key: 0, class: "cqmc-uploader__slot" }; const _hoisted_2 = { key: 0, class: "cqmc-uploader__preview-img" }; const _hoisted_3 = { key: 0, class: "cqmc-uploader__preview__progress" }; const _hoisted_4 = { class: "cqmc-uploader__preview__progress__msg" }; const _hoisted_5 = ["onClick"]; const _hoisted_6 = ["onClick", "src"]; const _hoisted_7 = { key: 3, class: "cqmc-uploader__preview-img__file" }; const _hoisted_8 = ["onClick"]; const _hoisted_9 = { class: "file__name_tips" }; const _hoisted_10 = { class: "tips" }; const _hoisted_11 = { key: 1, class: "cqmc-uploader__preview-list" }; const _hoisted_12 = ["onClick"]; const _hoisted_13 = { class: "file__name_tips" }; function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) { const _component_Failure = resolveComponent("Failure"); const _component_Loading = resolveComponent("Loading"); const _component_Link = resolveComponent("Link"); const _component_Del = resolveComponent("Del"); const _component_nut_progress = resolveComponent("cqmc-progress"); const _component_Photograph = resolveComponent("Photograph"); return openBlock(), createElementBlock("view", { class: normalizeClass(_ctx.classes) }, [ _ctx.$slots.default ? (openBlock(), createElementBlock("view", _hoisted_1, [ renderSlot(_ctx.$slots, "default"), Number(_ctx.maximum) - _ctx.fileList.length ? (openBlock(), createBlock(resolveDynamicComponent(_ctx.renderInput), { key: 0, onChange: _ctx.onChange }, null, 40, ["onChange"])) : createCommentVNode("", true) ])) : createCommentVNode("", true), (openBlock(true), createElementBlock(Fragment, null, renderList(_ctx.fileList, (item, index2) => { var _a; return openBlock(), createElementBlock("view", { class: normalizeClass(["cqmc-uploader__preview", [_ctx.listType]]), key: item.uid }, [ _ctx.listType == "picture" && !_ctx.$slots.default ? (openBlock(), createElementBlock("view", _hoisted_2, [ item.status != "success" ? (openBlock(), createElementBlock("view", _hoisted_3, [ item.status != "ready" ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [ item.status == "error" ? (openBlock(), createBlock(_component_Failure, { key: 0, color: "#fff" })) : (openBlock(), createBlock(_component_Loading, { key: 1, name: "loading", color: "#fff" })) ], 64)) : createCommentVNode("", true), createElementVNode("view", _hoisted_4, toDisplayString(item.message), 1) ])) : createCommentVNode("", true), _ctx.isDeletable ? (openBlock(), createElementBlock("view", { key: 1, class: "close", onClick: ($event) => _ctx.onDelete(item, index2) }, [ renderSlot(_ctx.$slots, "delete-icon", {}, () => [ createVNode(_component_Failure) ]) ], 8, _hoisted_5)) : createCommentVNode("", true), ((_a = item == null ? void 0 : item.type) == null ? void 0 : _a.includes("image")) && item.url ? (openBlock(), createElementBlock("img", { key: 2, class: "cqmc-uploader__preview-img__c", onClick: ($event) => _ctx.fileItemClick(item), src: item.url }, null, 8, _hoisted_6)) : (openBlock(), createElementBlock("view", _hoisted_7, [ createElementVNode("view", { onClick: ($event) => _ctx.fileItemClick(item), class: "cqmc-uploader__preview-img__file__name" }, [ createElementVNode("view", _hoisted_9, toDisplayString(item.name), 1) ], 8, _hoisted_8) ])), createElementVNode("view", _hoisted_10, toDisplayString(item.name), 1) ])) : _ctx.listType == "list" ? (openBlock(), createElementBlock("view", _hoisted_11, [ createElementVNode("view", { onClick: ($event) => _ctx.fileItemClick(item), class: normalizeClass(["cqmc-uploader__preview-img__file__name", [item.status]]) }, [ createVNode(_component_Link, { class: "cqmc-uploader__preview-img__file__link" }), createElementVNode("view", _hoisted_13, toDisplayString(item.name), 1), _ctx.isDeletable ? (openBlock(), createBlock(_component_Del, { key: 0, color: "#808080", class: "cqmc-uploader__preview-img__file__del", onClick: ($event) => _ctx.onDelete(item, index2) }, null, 8, ["onClick"])) : createCommentVNode("", true) ], 10, _hoisted_12), item.status == "uploading" ? (openBlock(), createBlock(_component_nut_progress, { key: 0, size: "small", percentage: item.percentage, "stroke-color": "linear-gradient(270deg, rgba(18,126,255,1) 0%,rgba(32,147,255,1) 32.815625%,rgba(13,242,204,1) 100%)", "show-text": false }, null, 8, ["percentage"])) : createCommentVNode("", true) ])) : createCommentVNode("", true) ], 2); }), 128)), _ctx.listType == "picture" && !_ctx.$slots.default && Number(_ctx.maximum) - _ctx.fileList.length ? (openBlock(), createElementBlock("view", { key: 1, class: normalizeClass(["cqmc-uploader__upload", [_ctx.listType]]) }, [ renderSlot(_ctx.$slots, "upload-icon", {}, () => [ createVNode(_component_Photograph, { color: "#808080" }) ]), (openBlock(), createBlock(resolveDynamicComponent(_ctx.renderInput), { onChange: _ctx.onChange }, null, 40, ["onChange"])) ], 2)) : createCommentVNode("", true) ], 2); } const index = /* @__PURE__ */ _export_sfc(_sfc_main, [["render", _sfc_render]]); export { index as default };