feat(usage): 记录并展示失败请求(用户端+管理端)

- 记录失败请求并在用户端/管理端展示;分类下拉改用统一 Select 组件
- 模型过滤改后端 ILIKE 模糊匹配;新增「Key 名称」列(含已删除标记)与按 Key 过滤;时间列移至末列
- 用户可见「已删除 key 失败请求」:OpsErrorLogFilter 加 MatchDeletedKeyOwner,用户侧归属
  放宽为 (user_id OR deleted_key_owner_user_id),让 key 原所有者能看到删除 key 后继续请求
  导致的认证失败记录(他人仍 NotFound,不泄露存在性)
- 迁移 148:ops_error_logs 用户+时间索引

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
DaydreamCoding
2026-06-05 14:00:57 +08:00
committed by QTom
co-authored by Claude Opus 4.8
parent ddf063352a
commit cfb195c7b2
37 changed files with 1746 additions and 84 deletions
+2
View File
@@ -1084,6 +1084,8 @@ export type OpsErrorListQueryParams = {
platform?: string
group_id?: number | null
account_id?: number | null
user_id?: number
api_key_id?: number
phase?: string
error_owner?: string
+5
View File
@@ -612,6 +612,9 @@ export interface SystemSettings {
// OpenAI fast/flex policy
openai_fast_policy_settings?: OpenAIFastPolicySettings;
// Allow user view error requests
allow_user_view_error_requests: boolean;
}
export interface UpdateSettingsRequest {
@@ -842,6 +845,8 @@ export interface UpdateSettingsRequest {
// OpenAI fast/flex policy
openai_fast_policy_settings?: OpenAIFastPolicySettings;
allow_user_view_error_requests?: boolean;
}
/**
+24 -2
View File
@@ -10,7 +10,10 @@ import type {
UsageStatsResponse,
PaginatedResponse,
TrendDataPoint,
ModelStat
ModelStat,
UserErrorRequest,
UserErrorRequestDetail,
UserErrorListParams
} from '@/types'
// ==================== Dashboard Types ====================
@@ -304,6 +307,22 @@ export async function getDashboardApiKeysUsage(
return data
}
export async function listMyErrorRequests(
params: UserErrorListParams,
config: { signal?: AbortSignal } = {}
): Promise<PaginatedResponse<UserErrorRequest>> {
const { data } = await apiClient.get<PaginatedResponse<UserErrorRequest>>('/usage/errors', {
...config,
params
})
return data
}
export async function getMyErrorDetail(id: number): Promise<UserErrorRequestDetail> {
const { data } = await apiClient.get<UserErrorRequestDetail>(`/usage/errors/${id}`)
return data
}
export const usageAPI = {
list,
query,
@@ -316,7 +335,10 @@ export const usageAPI = {
getDashboardTrend,
getDashboardModels,
getMyApiKeyDailyUsage,
getDashboardApiKeysUsage
getDashboardApiKeysUsage,
// Error requests
listMyErrorRequests,
getMyErrorDetail,
}
export default usageAPI