diff --git a/qy-lty-admin/lib/api/credential-slot.ts b/qy-lty-admin/lib/api/credential-slot.ts new file mode 100644 index 0000000..fc7229b --- /dev/null +++ b/qy-lty-admin/lib/api/credential-slot.ts @@ -0,0 +1,64 @@ +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) +}