feat(01-01): 新建 lib/api/credential-slot.ts 凭据槽位 API 客户端

- 类型 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 风格
This commit is contained in:
pmc 2026-05-08 11:02:35 +08:00
parent 7d7fc2867d
commit a0d0b9c1ad

View File

@ -0,0 +1,64 @@
import { apiClient } from "./client"
// ───── 后端响应原始 dictsnake_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<CredentialSlot> => {
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<CredentialSlot> => {
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)
}