import { $fetch } from 'ofetch' import { createError, defineEventHandler, getHeader, getCookie, getQuery } from 'h3' import { useRuntimeConfig } from '#imports' import { getTenantFromContext } from '../../utils/tenant' /** * 取附件下载票据(一次性、短时)。 * GET /api/tender/attachment-ticket?kind=tender&orderNo=xxx&index=0 * GET /api/tender/attachment-ticket?kind=bulletin&projectNo=xxx&index=0 * * 为什么要它:一站式的静态文件服务加了鉴权,附件不再直连,改由后端反代 * (工作区根目录 `docs/adr/0007-attachment-download-via-platform-proxy.md`)。 * 下发给前端的附件地址是**本平台的资源地址**(只有 kind/订单号或项目编号/序号, * 没有路径、也没有票据);**点击下载时**才来这里换一张票据,再用票据去 * `{modulesApiBase}/api/hjc/attachment?ticket=…` 取文件。 * * 为什么票据要现取而不能直接放进列表里的地址:票据很短命,"页面开着放一会儿再点" * 会撞过期;现取则永远新鲜(ADR 0007 补记)。 * * 约定:原样透传 ApiResult{code,message,data},HTTP 状态码恒为 200。 * `code=401`(未登录)与 `code=403`(未支付/无权/已下架)都是**业务码**, * 前端必须按 code 判定——401 要清凭据跳登录,403 只提示。 */ export default defineEventHandler(async (event) => { const config = useRuntimeConfig() const ctx = getTenantFromContext(event, config) const { kind, orderNo, projectNo, index } = getQuery(event) const cookieToken = getCookie(event, 'hjc_token') const auth = getHeader(event, 'authorization') || (cookieToken ? `Bearer ${cookieToken}` : null) try { return await $fetch('/hjc/attachment/ticket', { baseURL: config.public.modulesApiBase, method: 'GET', headers: { TenantId: ctx.tenantId, ...(auth ? { Authorization: auth } : {}) }, query: { TenantId: ctx.tenantId, kind, index, ...(orderNo ? { orderNo } : {}), ...(projectNo ? { projectNo } : {}) } }) } catch (error: any) { throw createError({ statusCode: error?.statusCode || error?.response?.status || 502, statusMessage: error?.statusMessage || 'Failed to fetch attachment ticket' }) } })