import { apiClient } from "./client" // ───── 后端响应原始 dict(snake_case,仅 adapter 内部用,不导出)──────────── interface BackendCredentialSlot { app_id: string access_token: string updated_at: string } // ───── 前端响应类型(camelCase,导出给 UI 层 import)────────────────────── /** * 凭据槽位(后端响应)。 * 注意:access_token 已是脱敏掩码(末 4 位明文),不要把它当明文回写。 */ export interface CredentialSlot { appId: string accessTokenMasked: string // 后端返回的脱敏字符串 updatedAt: string // ISO 8601 } // ───── 提交载荷类型(camelCase 明文)────────────────────────────────────── /** * 凭据槽位更新载荷。 * 注意:accessToken 是明文,提交后将完整覆写后端记录。 */ export interface CredentialSlotUpdatePayload { appId: string accessToken: string // 明文 } // ───── adapter(后端 → 前端)───────────────────────────────────────────── function mapBackendCredentialSlot(raw: BackendCredentialSlot): CredentialSlot { return { appId: raw.app_id, accessTokenMasked: raw.access_token, updatedAt: raw.updated_at, } } // ───── API 函数 ────────────────────────────────────────────────────────── /** * 读取当前凭据槽位(access_token 字段为脱敏掩码)。 */ export const getCredentialSlot = async (): Promise => { const response = await apiClient.get('/v1/admin/credential-slot/') const data = response.data?.data || response.data // 仓库统一双保险解包 return mapBackendCredentialSlot(data) } /** * 全字段覆写凭据槽位(access_token 必须为明文;响应里返回的同样是脱敏掩码)。 */ export const updateCredentialSlot = async ( payload: CredentialSlotUpdatePayload ): Promise => { const body = { app_id: payload.appId, access_token: payload.accessToken, // 不带 updated_at —— 后端 auto_now 维护,与 updateOutfit / updateAiModel 风格一致 } const response = await apiClient.put('/v1/admin/credential-slot/', body) const data = response.data?.data || response.data return mapBackendCredentialSlot(data) }