fix: support sms signature file download
Build and Deploy Vue3 / build (push) Successful in 1m38s
Build and Deploy Vue3 / deploy (push) Successful in 46s

This commit is contained in:
shiran
2026-07-17 17:26:10 +08:00
parent 9b369a4dd5
commit afc00141f7
+91 -3
View File
@@ -288,8 +288,17 @@
</div>
<div class="detail-file-row">
<span class="detail-img-label">申请文件</span>
<el-link v-if="detailData.application_file_url" type="primary" :href="detailData.application_file_url" target="_blank">查看申请文件</el-link>
<span v-else class="detail-empty-text">未上传</span>
<el-button
v-if="getApplicationFileUrl(detailData)"
link
type="primary"
:loading="applicationFileDownloading"
@click="downloadApplicationFile(detailData)"
>
<el-icon v-if="!applicationFileDownloading"><Download /></el-icon>
下载申请文件
</el-button>
<span v-else class="detail-empty-text">暂无可下载文件</span>
</div>
</div>
<template #footer>
@@ -314,8 +323,9 @@
<script setup>
import { ref, reactive, onMounted } from 'vue'
import axios from 'axios'
import { ElMessage, ElMessageBox } from 'element-plus'
import { Plus, User, Close, Picture } from '@element-plus/icons-vue'
import { Plus, User, Close, Picture, Download } from '@element-plus/icons-vue'
import { formatDate } from '@/utils/tool'
import {
getSmsServiceList,
@@ -392,6 +402,7 @@ const currentRow = ref(null)
const detailVisible = ref(false)
const detailData = ref(null)
const applicationFileDownloading = ref(false)
const userSelectorVisible = ref(false)
const selectedUserInfo = ref(null)
@@ -466,6 +477,83 @@ const handleDetail = (row) => {
detailVisible.value = true
}
const getSignatureService = (row) => {
const serviceId = row.service_id || queryParams.service_id
return serviceOptions.value.find(item => String(item.id) === String(serviceId))
}
const getApplicationFileUrl = (row) => {
if (!row?.ID || !row?.application_file_url) return ''
const service = getSignatureService(row)
const endpoint = String(service?.host || '').replace(/\/+$/, '')
if (!endpoint) return ''
return `${endpoint}/api/sms/admin/signature/${row.ID}/application-file`
}
const getDownloadFilename = (headers, signatureId) => {
const disposition = headers?.['content-disposition'] || ''
const utf8Match = disposition.match(/filename\*=UTF-8''([^;]+)/i)
const plainMatch = disposition.match(/filename="?([^";]+)"?/i)
const encodedName = utf8Match?.[1] || plainMatch?.[1]
if (!encodedName) return `签名申请文件_${signatureId}.xlsx`
try {
return decodeURIComponent(encodedName)
} catch {
return encodedName
}
}
const downloadApplicationFile = async (row) => {
const url = getApplicationFileUrl(row)
if (!url || applicationFileDownloading.value) return
const service = getSignatureService(row)
const endpoint = String(service?.host || '').replace(/\/+$/, '')
const serviceToken = service?.serviceToken || service?.service_token
if (!serviceToken) {
ElMessage.error('当前短信平台未配置 Service Token')
return
}
applicationFileDownloading.value = true
try {
const loginResponse = await axios.post(
`${endpoint}/api/auth/service-token-login`,
{ service_token: serviceToken },
{ timeout: 15000 }
)
const loginBody = loginResponse.data || {}
const platformToken = loginBody.data?.token
if (loginBody.code !== 200 || !platformToken) {
throw new Error(loginBody.message || '短信平台 Token 获取失败')
}
const response = await axios.get(url, {
headers: { Authorization: `Bearer ${platformToken}` },
responseType: 'blob',
timeout: 60000
})
const contentType = response.headers?.['content-type'] || ''
if (contentType.includes('application/json')) {
const body = JSON.parse(await response.data.text())
throw new Error(body.message || body.msg || '下载申请文件失败')
}
const objectUrl = window.URL.createObjectURL(response.data)
const link = document.createElement('a')
link.href = objectUrl
link.download = getDownloadFilename(response.headers, row.ID)
document.body.appendChild(link)
link.click()
link.remove()
window.URL.revokeObjectURL(objectUrl)
} catch (error) {
ElMessage.error(error.message || '下载申请文件失败')
} finally {
applicationFileDownloading.value = false
}
}
const handleAdd = () => {
dialogType.value = 'add'
selectedUserInfo.value = null