From a0d0b9c1ad3ce50b25dbcba81dfcc8b5af415a89 Mon Sep 17 00:00:00 2001 From: pmc <740076875@qq.com> Date: Fri, 8 May 2026 11:02:35 +0800 Subject: [PATCH] =?UTF-8?q?feat(01-01):=20=E6=96=B0=E5=BB=BA=20lib/api/cre?= =?UTF-8?q?dential-slot.ts=20=E5=87=AD=E6=8D=AE=E6=A7=BD=E4=BD=8D=20API=20?= =?UTF-8?q?=E5=AE=A2=E6=88=B7=E7=AB=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 类型 CredentialSlot { appId, accessTokenMasked, updatedAt }(脱敏掩码语义命名) - 类型 CredentialSlotUpdatePayload { appId, accessToken }(明文语义命名) - 内部接口 BackendCredentialSlot(snake_case,不导出) - adapter mapBackendCredentialSlot 把 snake → camel - getCredentialSlot() 走 apiClient.get '/v1/admin/credential-slot/' - updateCredentialSlot(payload) 走 apiClient.put '/v1/admin/credential-slot/',body 仅 { app_id, access_token } 不带 updated_at - GET / PUT 各含一次 response.data?.data || response.data 双保险解包 - 1:1 复刻 lib/api/ai-models.ts 风格 --- qy-lty-admin/lib/api/credential-slot.ts | 64 +++++++++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 qy-lty-admin/lib/api/credential-slot.ts 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) +}