/** * 功能:配送合同 PDF 附件的上传、失败清理与鉴权预览客户端。 * 版本:v1.0.0 */ import { getToken } from '@/utils/auth'; const platformApiBaseURL = import.meta.env.VITE_API_BASE_URL || 'http://localhost:12426/heqi/platform/v1'; export type ContractAttachmentMetadata = { has_file: boolean; available: boolean; requires_reupload: boolean; display_name: string; version: string; }; export type ContractAttachmentUploadReply = { receipt: string; cleanup_token: string; display_name: string; size: number; }; type ApiEnvelope = { code?: number; message?: string; details?: T }; /** 返回当前登录凭证请求头。 */ function authorizationHeaders(): Record { const token = getToken(); return token ? { Authorization: token } : {}; } /** 上传经过前端预检的单个 PDF,服务端仍会验证真实内容。 */ async function upload(file: File): Promise { const form = new FormData(); form.append('file', file); const response = await fetch( `${platformApiBaseURL}/gasorder_contract/attachment/upload`, { method: 'POST', headers: authorizationHeaders(), body: form }, ); const payload = (await response.json()) as ApiEnvelope; if (!response.ok || payload.code !== 0 || !payload.details) { throw new Error(payload.message || '合同附件上传失败'); } return payload.details; } /** 使用受签名保护的清理凭证删除尚未绑定的临时文件。 */ async function cleanup(cleanupToken: string): Promise { const response = await fetch( `${platformApiBaseURL}/gasorder_contract/attachment/cleanup`, { method: 'POST', headers: { 'Content-Type': 'application/json', ...authorizationHeaders() }, body: JSON.stringify({ cleanup_token: cleanupToken }), }, ); if (!response.ok) throw new Error('临时合同附件清理失败'); const payload = (await response.json()) as ApiEnvelope<{ deleted: boolean }>; if (payload.code !== 0) throw new Error(payload.message || '临时合同附件清理失败'); } /** 获取鉴权 PDF Blob;内部存储 URI 始终不会暴露给浏览器。 */ async function load(identity: string): Promise { const response = await fetch( `${platformApiBaseURL}/gasorder_contract/${encodeURIComponent(identity)}/attachment`, { headers: authorizationHeaders() }, ); if (!response.ok) throw new Error('合同附件不可用,请重新上传'); return response.blob(); } export const contractAttachmentApi = { upload, cleanup, load };