import { SYSTEM_SERVICE_PREFIX } from '@/constants/service'; import { request } from '../request'; import { type ServiceRequestResult, mapServiceResult } from './shared'; const FILE_PREFIX = `${SYSTEM_SERVICE_PREFIX}/file`; /** * 拼接文件永久代理路径,用于富文本 。 * * 后端 GET 接口匿名访问、Content-Disposition: inline,私有桶下也不会过期。 * 调用方拿到上传响应里的 configId + path 后直接调用本函数得到可写入 HTML 的 url。 */ export function buildFileProxyUrl(configId: string, path: string) { return `${FILE_PREFIX}/${configId}/get/${encodeURI(path)}`; } export interface UploadFileResult { /** infra_file.id 的字符串形式(避免 Long 精度丢失) */ id: string; /** 对象存储配置编号(字符串形式),与 path 一起拼接永久代理路径 */ configId: string; /** 文件相对路径(含日期目录、文件名),与 configId 一起拼接永久代理路径 */ path: string; /** * 文件访问 URL:私有桶带签名(24h 过期)、公开桶裸 URL。 * ⚠️ 仅供后端调试 / 历史兼容,禁止写进富文本 —— 会随签名过期导致回显失效。 * 富文本图片请用 buildFileProxyUrl(configId, path) 的返回值。 */ url: string; } type UploadFileResponse = { id: string | number; configId: string | number; path: string; url: string; }; /** 上传文件(模式一:后端中转) */ export async function uploadFile(file: File, directory?: string) { const formData = new FormData(); formData.append('file', file); if (directory) { formData.append('directory', directory); } const result = await request({ url: `${FILE_PREFIX}/upload`, method: 'post', data: formData }); return mapServiceResult(result as ServiceRequestResult, data => ({ id: String(data.id), configId: String(data.configId), path: data.path, url: data.url })); } /** * 删除文件 * * 业务表单"取消/关闭/标记删除"场景调用本接口清理孤儿文件。 * 删除已不存在的文件(后端返回错误码 `1001003001`)应由调用方视为成功并吞掉。 */ export function deleteFile(id: string) { return request({ url: `${FILE_PREFIX}/delete`, method: 'delete', params: { id } }); } /** * 下载文件(流) * * 走后端代理接口 `/system/file/download?id=xxx`,由后端读取对象存储并以字节流返回。 * 私有桶下不要直接打开 `infra_file.url`,签名地址会过期。 */ export function downloadFile(id: string) { return request({ url: `${FILE_PREFIX}/download`, method: 'get', params: { id }, responseType: 'blob' }); }