download-attachment.ts 1.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263
  1. import { ElMessage } from 'element-plus'
  2. import { fetchAttachmentDownloadUrl } from '@/api/admin'
  3. export type AttachmentDownloadItem = {
  4. fileUrl?: string
  5. fileName?: string
  6. }
  7. /** 将 JSON 数组或逗号分隔的附件 URL 统一为逗号分隔字符串 */
  8. export function normalizeAttachmentUrls(raw?: string | null): string {
  9. if (!raw) return ''
  10. const trimmed = String(raw).trim()
  11. if (!trimmed) return ''
  12. if (trimmed.startsWith('[')) {
  13. try {
  14. const parsed = JSON.parse(trimmed)
  15. if (Array.isArray(parsed)) {
  16. return parsed.map((url) => String(url).trim()).filter(Boolean).join(',')
  17. }
  18. } catch {
  19. /* ignore */
  20. }
  21. }
  22. return trimmed
  23. }
  24. function triggerAnchorDownload(href: string, fileName: string) {
  25. const a = document.createElement('a')
  26. a.href = href
  27. a.download = fileName
  28. a.rel = 'noopener'
  29. document.body.appendChild(a)
  30. a.click()
  31. document.body.removeChild(a)
  32. }
  33. /** 附件下载:优先走后端预签名 URL,保证跨域场景下保留原始文件名与后缀。 */
  34. export async function downloadAttachmentFile(
  35. file: AttachmentDownloadItem,
  36. options?: { fullFileUrl?: (url: string) => string }
  37. ) {
  38. const fileUrl = String(file.fileUrl || '').trim()
  39. if (!fileUrl) return
  40. const fileName = String(file.fileName || '').trim() || fileUrl.split('/').pop() || 'download'
  41. try {
  42. const res = await fetchAttachmentDownloadUrl({ fileUrl, fileName })
  43. if (res?.downloadUrl) {
  44. triggerAnchorDownload(res.downloadUrl, fileName)
  45. return
  46. }
  47. } catch {
  48. // 预签名失败时回退直连
  49. }
  50. const resolveUrl = options?.fullFileUrl || ((url: string) => url)
  51. const href = resolveUrl(fileUrl)
  52. if (!href) {
  53. ElMessage.error('无法下载附件')
  54. return
  55. }
  56. triggerAnchorDownload(href, fileName)
  57. }