| | |
| | | :limit="1" |
| | | accept=".xlsx,.xls" |
| | | :action="importUpload.url" |
| | | :http-request="importUpload.httpRequest" |
| | | :headers="importUpload.headers" |
| | | :before-upload="importUpload.beforeUpload" |
| | | :on-success="importUpload.onSuccess" |
| | |
| | | |
| | | <script setup> |
| | | import { ref, reactive, onMounted } from "vue"; |
| | | import axios from "axios"; |
| | | import { ElMessageBox } from "element-plus"; |
| | | import { Plus } from "@element-plus/icons-vue"; |
| | | import { getToken } from "@/utils/auth.js"; |
| | |
| | | }); |
| | | const { modelForm, modelRules } = toRefs(data); |
| | | |
| | | const downloadImportErrorFile = (blob, filename = "import-error.xlsx") => { |
| | | const downloadElement = document.createElement("a"); |
| | | const href = window.URL.createObjectURL(blob); |
| | | downloadElement.href = href; |
| | | downloadElement.download = filename; |
| | | document.body.appendChild(downloadElement); |
| | | downloadElement.click(); |
| | | document.body.removeChild(downloadElement); |
| | | window.URL.revokeObjectURL(href); |
| | | }; |
| | | |
| | | const tryParseJsonBlob = async (blob) => { |
| | | try { |
| | | const text = await blob.text(); |
| | | if (!text || !text.trim()) { |
| | | return null; |
| | | } |
| | | return JSON.parse(text); |
| | | } catch (_) { |
| | | return null; |
| | | } |
| | | }; |
| | | |
| | | const importUpload = reactive({ |
| | | title: "产品导入", |
| | | open: false, |
| | | url: import.meta.env.VITE_APP_BASE_API + "/basic/product/import", |
| | | headers: { Authorization: "Bearer " + getToken() }, |
| | | isUploading: false, |
| | | httpRequest: async (options) => { |
| | | const { file, onProgress, onSuccess, onError } = options; |
| | | importUpload.isUploading = true; |
| | | const formData = new FormData(); |
| | | formData.append("file", file); |
| | | try { |
| | | const response = await axios({ |
| | | url: importUpload.url, |
| | | method: "post", |
| | | headers: { |
| | | ...importUpload.headers, |
| | | "Content-Type": "multipart/form-data", |
| | | }, |
| | | data: formData, |
| | | responseType: "blob", |
| | | onUploadProgress: (progressEvent) => { |
| | | const total = progressEvent.total || 1; |
| | | const percent = Math.round((progressEvent.loaded * 100) / total); |
| | | onProgress?.({ percent }, file); |
| | | }, |
| | | }); |
| | | importUpload.isUploading = false; |
| | | const blob = response.data; |
| | | // Contract: success => empty response body; failure => binary error file. |
| | | if (!blob || blob.size === 0) { |
| | | onSuccess?.({ code: 200, msg: "import success" }, file); |
| | | return; |
| | | } |
| | | const json = await tryParseJsonBlob(blob); |
| | | if (json) { |
| | | if (String(json.code) === "200" || json.success === true) { |
| | | onSuccess?.(json, file); |
| | | } else { |
| | | onError?.(new Error(json.msg || json.message || "import failed"), file); |
| | | } |
| | | return; |
| | | } |
| | | downloadImportErrorFile(blob); |
| | | onError?.(new Error("import failed, error file downloaded"), file); |
| | | } catch (error) { |
| | | importUpload.isUploading = false; |
| | | onError?.(error, file); |
| | | } |
| | | }, |
| | | beforeUpload: (file) => { |
| | | const isExcel = file.name.endsWith('.xlsx') || file.name.endsWith('.xls'); |
| | | const isLt10M = file.size / 1024 / 1024 < 10; |
| | |
| | | onSuccess: (response, file, fileList) => { |
| | | console.log('上传成功', response, file, fileList); |
| | | importUpload.isUploading = false; |
| | | if (response.code === 200) { |
| | | if (String(response?.code) === "200" || response?.success === true) { |
| | | proxy.$modal.msgSuccess("导入成功"); |
| | | importDia.value = false; |
| | | if (importUploadRef.value) { |
| | |
| | | } |
| | | |
| | | :deep(.el-upload--picture-card) { |
| | | width: 148px; |
| | | height: 148px; |
| | | } |
| | | |
| | | :deep(.el-upload-list__item) { |
| | | width: 148px; |
| | | height: 148px; |
| | | } |