Support filtered-result primary action and optional export-selected menu. Co-authored-by: Cursor <cursoragent@cursor.com>
42 lines
1.2 KiB
TypeScript
42 lines
1.2 KiB
TypeScript
/** 从 Content-Disposition 解析文件名;失败则用 fallback */
|
|
export function filenameFromContentDisposition(
|
|
header: string | undefined,
|
|
fallback: string
|
|
): string {
|
|
if (!header) return fallback
|
|
const utf8 = /filename\*\s*=\s*UTF-8''([^;]+)/i.exec(header)
|
|
if (utf8?.[1]) {
|
|
try {
|
|
return decodeURIComponent(utf8[1].trim().replace(/["']/g, ''))
|
|
} catch {
|
|
/* ignore */
|
|
}
|
|
}
|
|
const plain = /filename\s*=\s*("?)([^";]+)\1/i.exec(header)
|
|
if (plain?.[2]) return plain[2].trim()
|
|
return fallback
|
|
}
|
|
|
|
export function triggerBlobDownload(blob: Blob, filename: string): void {
|
|
const url = URL.createObjectURL(blob)
|
|
const link = document.createElement('a')
|
|
link.href = url
|
|
link.download = filename
|
|
link.click()
|
|
URL.revokeObjectURL(url)
|
|
}
|
|
|
|
/** Axios 成功时若拦截器已把 data 设为 Blob,直接用;否则兼容 { data: Blob, headers } */
|
|
export function pickBlobFromExportResponse(res: any): { blob: Blob; filenameHeader?: string } {
|
|
if (res instanceof Blob) {
|
|
return { blob: res }
|
|
}
|
|
if (res?.data instanceof Blob) {
|
|
return {
|
|
blob: res.data,
|
|
filenameHeader: res.headers?.['content-disposition'] || res.headers?.['Content-Disposition']
|
|
}
|
|
}
|
|
throw new Error('导出响应不是文件')
|
|
}
|