From 4e4b9a730d4494bbfed7a1a8b154a85ddfdc5b64 Mon Sep 17 00:00:00 2001 From: linxd <544554903@qq.com> Date: Tue, 1 Jul 2025 09:25:22 +0800 Subject: [PATCH] =?UTF-8?q?=E5=B0=81=E8=A3=85=E5=AF=BC=E5=87=BA=E5=B7=A5?= =?UTF-8?q?=E5=85=B7=E7=B1=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../supplierAnnualStatistics.tsx | 24 +---- .../supplierEvaluateStatistics.tsx | 17 +--- .../supplierExitStatistics.tsx | 17 +--- ...supplierQualificationWarningStatistics.tsx | 17 +--- src/utils/download.ts | 95 +++++++++---------- 5 files changed, 57 insertions(+), 113 deletions(-) diff --git a/src/pages/dataStatistics/supplierAnnualStatistics/supplierAnnualStatistics.tsx b/src/pages/dataStatistics/supplierAnnualStatistics/supplierAnnualStatistics.tsx index 541efb0..036b861 100644 --- a/src/pages/dataStatistics/supplierAnnualStatistics/supplierAnnualStatistics.tsx +++ b/src/pages/dataStatistics/supplierAnnualStatistics/supplierAnnualStatistics.tsx @@ -2,13 +2,11 @@ import React, { useState, useEffect } from 'react'; import { Button, Table, - Space, Input, Select, Form, Tooltip, Tag, - DatePicker, message } from 'antd'; import type { TablePaginationConfig } from 'antd'; @@ -17,10 +15,10 @@ import { DeleteOutlined, ExportOutlined } from '@ant-design/icons'; -import CategorySelector from '@/components/CategorySelector/CategorySelector'; -import { AnnualReviewYears, AnnualReviewResultText, AnnualReviewResultColor, SupplierTypeText } from '@/dicts/dataStatistics'; -import { getSupplierAnnualReviewStatistics, exportSupplierAnnualReviewStatistics } from '@/servers/api/dataStatistics'; +import { AnnualReviewYears, AnnualReviewResultText, AnnualReviewResultColor } from '@/dicts/dataStatistics'; +import { getSupplierAnnualReviewStatistics } from '@/servers/api/dataStatistics'; import './supplierAnnualStatistics.less'; +import { downloadFile } from '@/utils/download'; const { Option } = Select; @@ -190,21 +188,7 @@ const SupplierAnnualStatistics: React.FC = () => { // 导出功能 const handleExport = () => { const values = form.getFieldsValue(); - exportSupplierAnnualReviewStatistics(values) - .then(response => { - // 创建a标签进行下载 - const url = window.URL.createObjectURL(new Blob([response])); - const link = document.createElement('a'); - link.href = url; - link.setAttribute('download', `供应商年审情况统计_${new Date().getTime()}.xlsx`); - document.body.appendChild(link); - link.click(); - document.body.removeChild(link); - }) - .catch(error => { - console.error('导出失败:', error); - message.error('导出失败'); - }); + downloadFile('/dataStatistics/exportSupplierAnnualReviewStatistics', 'GET', values); }; return ( diff --git a/src/pages/dataStatistics/supplierEvaluateStatistics/supplierEvaluateStatistics.tsx b/src/pages/dataStatistics/supplierEvaluateStatistics/supplierEvaluateStatistics.tsx index 383186d..a516f58 100644 --- a/src/pages/dataStatistics/supplierEvaluateStatistics/supplierEvaluateStatistics.tsx +++ b/src/pages/dataStatistics/supplierEvaluateStatistics/supplierEvaluateStatistics.tsx @@ -23,6 +23,7 @@ import { getSupplierEvaluateStatistics, exportSupplierEvaluateStatistics } from import { getAllEvaluateRules } from '@/servers/api/supplierEvaluate'; import type { EvaluateRuleItem } from '@/servers/dao/supplierEvaluateTask'; import './supplierEvaluateStatistics.less'; +import { downloadFile } from '@/utils/download'; const { Option } = Select; const { RangePicker } = DatePicker; @@ -209,21 +210,7 @@ const SupplierEvaluateStatistics: React.FC = () => { // 更新handleExport方法实现真实导出功能 const handleExport = () => { const values = form.getFieldsValue(); - exportSupplierEvaluateStatistics(values) - .then(response => { - // 创建a标签进行下载 - const url = window.URL.createObjectURL(new Blob([response])); - const link = document.createElement('a'); - link.href = url; - link.setAttribute('download', `供应商评价情况统计_${new Date().getTime()}.xlsx`); - document.body.appendChild(link); - link.click(); - document.body.removeChild(link); - }) - .catch(error => { - console.error('导出失败:', error); - message.error('导出失败'); - }); + downloadFile('/dataStatistics/exportSupplierEvaluateStatistics', 'GET', values); }; return ( diff --git a/src/pages/dataStatistics/supplierExitStatistics/supplierExitStatistics.tsx b/src/pages/dataStatistics/supplierExitStatistics/supplierExitStatistics.tsx index c29f413..d78cf75 100644 --- a/src/pages/dataStatistics/supplierExitStatistics/supplierExitStatistics.tsx +++ b/src/pages/dataStatistics/supplierExitStatistics/supplierExitStatistics.tsx @@ -22,6 +22,7 @@ import { SupplierTypeText } from '@/dicts/dataStatistics'; import { getSupplierExitStatistics, exportSupplierExitStatistics } from '@/servers/api/dataStatistics'; import moment from 'moment'; import './supplierExitStatistics.less'; +import { downloadFile } from '@/utils/download'; const { Option } = Select; const { RangePicker } = DatePicker; @@ -199,21 +200,7 @@ const SupplierExitStatistics: React.FC = () => { // 导出功能 const handleExport = () => { const values = form.getFieldsValue(); - exportSupplierExitStatistics(values) - .then(response => { - // 创建a标签进行下载 - const url = window.URL.createObjectURL(new Blob([response])); - const link = document.createElement('a'); - link.href = url; - link.setAttribute('download', `供应商退出情况统计_${new Date().getTime()}.xlsx`); - document.body.appendChild(link); - link.click(); - document.body.removeChild(link); - }) - .catch(error => { - console.error('导出失败:', error); - message.error('导出失败'); - }); + downloadFile('/dataStatistics/exportSupplierExitStatistics', 'GET', values); }; return ( diff --git a/src/pages/dataStatistics/supplierQualificationWarningStatistics/supplierQualificationWarningStatistics.tsx b/src/pages/dataStatistics/supplierQualificationWarningStatistics/supplierQualificationWarningStatistics.tsx index 0ac6a72..16479f3 100644 --- a/src/pages/dataStatistics/supplierQualificationWarningStatistics/supplierQualificationWarningStatistics.tsx +++ b/src/pages/dataStatistics/supplierQualificationWarningStatistics/supplierQualificationWarningStatistics.tsx @@ -22,6 +22,7 @@ import { SupplierTypeText } from '@/dicts/dataStatistics'; import { getSupplierQualificationExpire, exportSupplierQualificationExpire } from '@/servers/api/dataStatistics'; import moment from 'moment'; import './supplierQualificationWarningStatistics.less'; +import { downloadFile } from '@/utils/download'; const { Option } = Select; const { RangePicker } = DatePicker; @@ -230,21 +231,7 @@ const SupplierQualificationWarningStatistics: React.FC = () => { ]; } - exportSupplierQualificationExpire(exportParams) - .then(response => { - // 创建a标签进行下载 - const url = window.URL.createObjectURL(new Blob([response])); - const link = document.createElement('a'); - link.href = url; - link.setAttribute('download', `供应商资质预警统计_${new Date().getTime()}.xlsx`); - document.body.appendChild(link); - link.click(); - document.body.removeChild(link); - }) - .catch(error => { - console.error('导出失败:', error); - message.error('导出失败'); - }); + downloadFile('/dataStatistics/exportSupplierQualificationExpire', 'GET', exportParams); }; return ( diff --git a/src/utils/download.ts b/src/utils/download.ts index 911d020..907329d 100644 --- a/src/utils/download.ts +++ b/src/utils/download.ts @@ -1,58 +1,57 @@ -/** - * 通用文件下载工具(基于 umi-request + file-saver) - */ - -import { extend } from 'umi-request'; import { saveAs } from 'file-saver'; -// 单独配置一个不拦截响应的 request 实例 -const downloadRequest = extend({ - timeout: 10000, - responseType: 'blob', // 关键 - credentials: 'include', // 根据实际需要携带 cookie - prefix: REQUEST_BASE, -}); - /** - * 下载文件通用函数 - * @param url 请求地址 - * @param params 请求参数(可选) - * @param filename 下载后的文件名(可选) - * @param method 请求方法(默认 POST) + * 更稳妥的文件下载方法(绕过 umi-request,避免被 JSON 解析) */ -export async function downloadFile({ - url, - params, - filename, - method = 'POST', -}: { - url: string; - params?: Record; - filename?: string; - method?: 'GET' | 'POST'; -}) { +export async function downloadFile( + url: string, + method: 'GET' | 'POST' = 'POST', + params?: Record +) { try { - const blob: Blob = await downloadRequest(url, { - method, - data: method === 'POST' ? params : undefined, - params: method === 'GET' ? params : undefined, - }); - - // 尝试从响应头中获取文件名 - const contentDisposition = (blob as any).response?.headers?.get?.('content-disposition'); - let finalFilename = filename; - - if (!finalFilename && contentDisposition) { - const match = contentDisposition.match(/filename="?([^"]+)"?/); - if (match && match[1]) { - finalFilename = decodeURIComponent(match[1]); - } + const cleanedParams: Record = {}; + if (params) { + Object.entries(params).forEach(([key, value]) => { + if (value !== undefined && value !== null && value !== '') { + cleanedParams[key] = value; + } + }); } - finalFilename = finalFilename || '下载文件'; + const fetchUrl = + method === 'GET' && params + ? `${REQUEST_BASE}${url}?${new URLSearchParams(cleanedParams as any).toString()}` + : `${REQUEST_BASE}${url}`; - saveAs(blob, finalFilename); - } catch (error) { - console.error('文件下载失败:', error); + const response = await fetch(fetchUrl, { + method, + headers: { + 'Content-Type': 'application/json', + }, + body: method === 'POST' ? JSON.stringify(params) : undefined, + credentials: 'include', + }); + + const contentType = response.headers.get('content-type') || ''; + if (contentType.includes('text/html')) { + const htmlText = await response.text(); + console.error('服务器返回 HTML 页面,可能是未登录或接口错误:', htmlText.slice(0, 300)); + return; + } + + if (!response.ok) { + const text = await response.text(); + console.error(`请求失败(${response.status}):`, text); + return; + } + + const disposition = response.headers.get('content-disposition') || ''; + const match = disposition.match(/filename="?([^"]+)"?/); + const fileName = match ? decodeURIComponent(match[1]) : '下载文件.xlsx'; + + const blob = await response.blob(); + saveAs(blob, fileName); + } catch (err) { + console.error('下载失败:', err); } }