import { fetchApi, ApiError } from '@/utils/request' import { useQuery, useMutation, useQueryCache } from '@pinia/colada' import type { Ref } from 'vue' // ---- Types ---- export interface FieldSchema { title: string description?: string type: 'string' | 'secret' | 'bool' | 'number' | 'enum' required?: boolean enum?: string[] example?: unknown } export interface ConfigSchema { version: number fields: Record } export interface ChannelCapabilities { text: boolean markdown: boolean rich_text: boolean attachments: boolean media: boolean reactions: boolean buttons: boolean reply: boolean threads: boolean streaming: boolean polls: boolean edit: boolean unsend: boolean native_commands: boolean block_streaming: boolean chat_types?: string[] } export interface ChannelMeta { type: string display_name: string configless: boolean capabilities: ChannelCapabilities config_schema: ConfigSchema user_config_schema: ConfigSchema target_spec: { format: string; description: string } } export interface ChannelConfig { id: string botID: string channelType: string credentials: Record externalIdentity: string selfIdentity: Record routing: Record status: string verifiedAt: string createdAt: string updatedAt: string } export interface UpsertConfigRequest { credentials: Record external_identity?: string self_identity?: Record routing?: Record status?: string } export interface BotChannelItem { meta: ChannelMeta config: ChannelConfig | null configured: boolean } // ---- Query: 获取可用渠道类型元信息 ---- export function useChannelMetas() { return useQuery({ key: ['channel-metas'], query: () => fetchApi('/channels'), }) } // ---- Query: 获取某 Bot 的所有渠道配置(组合查询) ---- export function useBotChannels(botId: Ref) { const queryCache = useQueryCache() const query = useQuery({ key: () => ['bot-channels', botId.value], query: async (): Promise => { // 1. 获取所有渠道元信息 const metas = await fetchApi('/channels') // 2. 过滤掉 configless 的类型(cli / web 等本地渠道) const configurableTypes = metas.filter((m) => !m.configless) // 3. 并行获取每种类型的 bot 配置 const results = await Promise.all( configurableTypes.map(async (meta) => { try { const config = await fetchApi( `/bots/${botId.value}/channel/${meta.type}`, ) return { meta, config, configured: true } as BotChannelItem } catch (err) { // 404 = 尚未配置,其他错误也视为未配置 if (err instanceof ApiError && err.status === 404) { return { meta, config: null, configured: false } as BotChannelItem } return { meta, config: null, configured: false } as BotChannelItem } }), ) return results }, enabled: () => !!botId.value, }) return { ...query, invalidate: () => queryCache.invalidateQueries({ key: ['bot-channels', botId.value] }), } } // ---- Mutation: 创建/更新 Bot 渠道配置 ---- export function useUpsertBotChannel(botId: Ref) { const queryCache = useQueryCache() return useMutation({ mutation: ({ platform, data }: { platform: string; data: UpsertConfigRequest }) => fetchApi(`/bots/${botId.value}/channel/${platform}`, { method: 'PUT', body: data, }), onSettled: () => queryCache.invalidateQueries({ key: ['bot-channels', botId.value] }), }) }