864c22ffc7
上游 ai.t8star.org 实测约 1/8 单请求完全不应答(主机 A 上 JDK 客户端 HTTP/1.1 与 HTTP/2 均复现),检测只有一次机会时用户会看到 「网络不可达:HttpTimeoutException: request timed out」。 - 传输层失败(超时/网络不可达)对直连最后一跳重试一次(800ms 间隔); 代理模块不重试——jikip 按提取次数计费,重试会多扣一次 - 失败文案中文化(新增 CODE_TIMEOUT),英文异常串只进服务端日志 - 探测提问改「你好」(最简一次调用) - 检测面板标明检测对象(配置密钥 sk-**** / 输入值(未保存)), 检测接口超时单独放宽(客户端 60s / 后台 180s),避免重试期间前端先超时
91 lines
3.0 KiB
TypeScript
91 lines
3.0 KiB
TypeScript
import { http } from './http'
|
||
import { unwrap } from './envelope'
|
||
|
||
/** 单模块状态(脱敏值 + 连通性)。 */
|
||
export interface AdminUserSecretModule {
|
||
moduleKey: string
|
||
moduleLabel: string
|
||
masked: string
|
||
/** 完整明文值:仅代理列有值(后端对密钥列不下发明文)。 */
|
||
full: string
|
||
exists: boolean
|
||
checkStatus: string
|
||
checkCode: string
|
||
checkMessage: string
|
||
checkLatencyMs: number | null
|
||
checkedAt: string | null
|
||
updatedAt: string | null
|
||
}
|
||
|
||
/** 一行一用户:三个字段列 + 行级状态(三类都检测通过才算 passed)。 */
|
||
export interface AdminUserSecretRow {
|
||
userId: number
|
||
username: string
|
||
/** 所属数据权限分组名(可能多个)。 */
|
||
groups: string[]
|
||
/** 所属主管(创建人)用户名;无分组时的兜底展示。 */
|
||
leaderUsername: string
|
||
similarAsin: AdminUserSecretModule
|
||
appearancePatent: AdminUserSecretModule
|
||
proxy: AdminUserSecretModule
|
||
status: string
|
||
statusMessage: string
|
||
updatedAt: string | null
|
||
}
|
||
|
||
export interface AdminUserSecretPage {
|
||
items: AdminUserSecretRow[]
|
||
total: number
|
||
page: number
|
||
pageSize: number
|
||
/** 分组筛选项(超管=全部;主管=自己带的分组)。 */
|
||
groupOptions?: GroupOption[]
|
||
}
|
||
|
||
export interface GroupOption {
|
||
id: number
|
||
groupName: string
|
||
}
|
||
|
||
export interface UserSecretQuery {
|
||
keyword?: string
|
||
checkStatus?: string
|
||
/** 按数据权限分组筛选(仅超管生效);后端参数为 snake_case。 */
|
||
groupId?: number
|
||
page: number
|
||
pageSize: number
|
||
}
|
||
|
||
/** 分页查询用户密钥(一行一用户):GET /api/admin/user-secrets(筛选参数必须 snake_case,camel 会被后端静默忽略)。 */
|
||
export async function fetchUserSecretList(params: UserSecretQuery): Promise<AdminUserSecretPage> {
|
||
const query: Record<string, string | number> = { page: params.page, pageSize: params.pageSize }
|
||
if (params.keyword) query.keyword = params.keyword
|
||
if (params.checkStatus) query.checkStatus = params.checkStatus
|
||
if (params.groupId) query.group_id = params.groupId
|
||
const { data } = await http.get('/api/admin/user-secrets', { params: query })
|
||
return unwrap<AdminUserSecretPage>(data)
|
||
}
|
||
|
||
/** 立即检测该用户全部已配置项:POST /api/admin/user-secrets/{userId}/check
|
||
* 逐模块检测(每项最多「首查 + 传输层失败重试一次」,最坏约 31s/项),故放宽超时到 180s。 */
|
||
export async function checkUserSecret(userId: number) {
|
||
const { data } = await http.post(`/api/admin/user-secrets/${userId}/check`, undefined, { timeout: 180_000 })
|
||
return unwrap<
|
||
Array<{
|
||
moduleKey: string
|
||
checkStatus: string
|
||
checkCode: string
|
||
checkMessage: string
|
||
checkLatencyMs: number | null
|
||
checkedAt: string | null
|
||
viaProxy: boolean
|
||
}>
|
||
>(data)
|
||
}
|
||
|
||
/** 清空该用户全部密钥与代理配置:DELETE /api/admin/user-secrets/{userId} */
|
||
export async function deleteUserSecret(userId: number): Promise<void> {
|
||
const { data } = await http.delete(`/api/admin/user-secrets/${userId}`)
|
||
unwrap<unknown>(data)
|
||
}
|