gaoluyang
8 小时以前 801a3bc53415f6214800c561a562d17ea58b88f1
src/views/basicData/product/index.vue
@@ -172,6 +172,7 @@
        :limit="1"
        accept=".xlsx,.xls"
        :action="importUpload.url"
        :http-request="importUpload.httpRequest"
        :headers="importUpload.headers"
        :before-upload="importUpload.beforeUpload"
        :on-success="importUpload.onSuccess"
@@ -198,6 +199,7 @@
<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";
@@ -314,12 +316,79 @@
});
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;
@@ -342,7 +411,7 @@
  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) {
@@ -621,11 +690,6 @@
}
:deep(.el-upload--picture-card) {
  width: 148px;
  height: 148px;
}
:deep(.el-upload-list__item) {
  width: 148px;
  height: 148px;
}