import { inject, onBeforeUnmount, provide, ref, watch, type InjectionKey, type Ref } from 'vue' import type { AgentClient } from '@agent-server/client' /** 组件只需要带鉴权地下载文件:AgentClient 与 BotClient 都满足 */ export type FileClient = Pick const CLIENT_KEY: InjectionKey = Symbol('agent-client') export function provideClient(client: FileClient) { provide(CLIENT_KEY, client) } export function useClient(): FileClient { const c = inject(CLIENT_KEY) if (!c) throw new Error('chat-ui: 缺少 AgentClient(请在外层使用 或 provideClient)') return c } /** 带鉴权地加载文件为 object URL(Agent Key 模式下 无法携带请求头) */ export function useFileObjectUrl(fileId: Ref): Ref { const client = useClient() const url = ref(null) let current: string | null = null const release = () => { if (current) URL.revokeObjectURL(current) current = null } watch(fileId, async id => { release() url.value = null if (!id) return try { current = URL.createObjectURL(await client.fileBlob(id)) url.value = current } catch { url.value = null } }, { immediate: true }) onBeforeUnmount(release) return url } export async function downloadFile(client: FileClient, fileId: string, name: string) { const blob = await client.fileBlob(fileId) const href = URL.createObjectURL(blob) const a = document.createElement('a') a.href = href a.download = name a.click() setTimeout(() => URL.revokeObjectURL(href), 10_000) }