|
|
@@ -37,73 +37,6 @@ import {
|
|
|
NUMBER_TYPES
|
|
|
} from './number-format-utils'
|
|
|
|
|
|
-/**
|
|
|
- * 将 Content-Disposition 中的 filename 进行容错解码,修复常见中文文件名乱码
|
|
|
- * @param {string|undefined|null} disposition
|
|
|
- * @param {string} fallback
|
|
|
- * @returns {string}
|
|
|
- */
|
|
|
-function resolveDownloadFilename(disposition, fallback) {
|
|
|
- if (!disposition) return fallback
|
|
|
- try {
|
|
|
- const starMatch = /filename\*=([^']*)''([^;\n]+)/i.exec(disposition)
|
|
|
- if (starMatch && starMatch[2]) {
|
|
|
- return decodeURIComponent(starMatch[2])
|
|
|
- }
|
|
|
-
|
|
|
- const plainMatch = /filename="?([^;\n"]+)"?/i.exec(disposition)
|
|
|
- if (plainMatch && plainMatch[1]) {
|
|
|
- const raw = String(plainMatch[1])
|
|
|
- const urlDecoded = tryDecodeURIComponent(raw)
|
|
|
- return maybeDecodeLatin1ToUtf8(urlDecoded)
|
|
|
- }
|
|
|
- } catch (e) {
|
|
|
- // ignore
|
|
|
- }
|
|
|
- return fallback
|
|
|
-}
|
|
|
-
|
|
|
-/**
|
|
|
- * @param {string} value
|
|
|
- * @returns {string}
|
|
|
- */
|
|
|
-function tryDecodeURIComponent(value) {
|
|
|
- try {
|
|
|
- return decodeURIComponent(value.replace(/\+/g, '%20'))
|
|
|
- } catch (e) {
|
|
|
- return value
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-/**
|
|
|
- * 常见场景:后端直接输出 UTF-8 字节到 header,浏览器按 latin1 解码,导致文件名变成“éå®...”
|
|
|
- * @param {string} value
|
|
|
- * @returns {string}
|
|
|
- */
|
|
|
-function maybeDecodeLatin1ToUtf8(value) {
|
|
|
- if (!value) return value
|
|
|
-
|
|
|
- const chars = Array.from(value)
|
|
|
- const isLatin1 = chars.every(ch => ch.charCodeAt(0) <= 0xFF)
|
|
|
- if (!isLatin1) return value
|
|
|
-
|
|
|
- try {
|
|
|
- if (typeof TextDecoder === 'function') {
|
|
|
- const bytes = Uint8Array.from(chars.map(ch => ch.charCodeAt(0)))
|
|
|
- return new TextDecoder('utf-8').decode(bytes)
|
|
|
- }
|
|
|
- } catch (e) {
|
|
|
- // ignore
|
|
|
- }
|
|
|
-
|
|
|
- try {
|
|
|
- // 兼容没有 TextDecoder 的环境
|
|
|
- return decodeURIComponent(escape(value))
|
|
|
- } catch (e) {
|
|
|
- return value
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
|
|
|
|
|
|
// 使用本地 PaginationConfig 作为分页数据结构描述
|
|
|
@@ -675,7 +608,13 @@ export default {
|
|
|
const res = await downloadSalesOrderTemplate()
|
|
|
|
|
|
const disposition = res?.headers?.['content-disposition'] || res?.headers?.['Content-Disposition']
|
|
|
- const filename = resolveDownloadFilename(disposition, '销售订单模板.xlsx')
|
|
|
+ let filename = '销售订单模板.xlsx'
|
|
|
+ if (disposition) {
|
|
|
+ const utf8Match = /filename\*=UTF-8''([^;\n]+)/i.exec(disposition)
|
|
|
+ const plainMatch = /filename="?([^;\n"]+)"?/i.exec(disposition)
|
|
|
+ const raw = utf8Match ? decodeURIComponent(utf8Match[1]) : (plainMatch ? plainMatch[1] : '')
|
|
|
+ if (raw) filename = raw
|
|
|
+ }
|
|
|
|
|
|
const blob = new Blob([res.data], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' })
|
|
|
const url = window.URL.createObjectURL(blob)
|