fix(bugcollect-web): 修复前端 API 类型与后端对齐

- BugCollectIssue: type→level, isResolved→status, appVersion→release, 新增 affectedUsers/assignee
- BugCollectEventItem: 扁平 message/stack/metadata 字段替换为 exception 对象结构,与 IssueEventResponse 对齐
- BugCollectWebhook: eventTypes/cooldownSeconds→events/cooldownSec,新增 hasSecret,移除 updatedAt
- BugCollectWebhookRequest: 新增独立请求类型,含 secret 字段
- 新增 resolveIssue / ignoreIssue / assignIssue / deleteIssue / bulkUpdateIssues / issueEvents API
- frequencyRanking / riskRanking 支持 from/to/limit 参数
- issues() 新增 assignee / environment / q / status 过滤参数
- webhooks.create 改为直接传 BugCollectWebhookRequest(移除冗余 appKey params)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
这个提交包含在:
XuqmGroup 2026-06-18 09:27:43 +08:00
父节点 11f11eac34
当前提交 a58d25fc24

查看文件

@ -8,7 +8,7 @@ export interface BugCollectOverview {
affectedUsers: number
crashRate: number
crashRateTrend: { date: string; rate: number }[]
topIssues: { id: string; title: string; type: string; count: number }[]
topIssues: { id: string; title: string; level: string; count: number }[]
}
// Matches backend IssueResponse
@ -16,59 +16,63 @@ export interface BugCollectIssue {
id: number
appKey: string
fingerprint?: string
type: string
level: string
status: string
title: string
firstSeenAt: string
lastSeenAt: string
count: number
isResolved: boolean
platform: string
appVersion?: string
affectedUsers: number
assignee?: string
platform?: string
release?: string
}
// Matches backend IssueResponse (with events embedded)
export interface BugCollectIssueDetail {
id: number
appKey: string
fingerprint?: string
type: string
title: string
firstSeenAt: string
lastSeenAt: string
count: number
isResolved: boolean
platform: string
appVersion?: string
events?: BugCollectEventItem[]
// Matches backend IssueEventResponse.ExceptionInfo
export interface BugCollectExceptionInfo {
type?: string
value?: string
stacktrace?: string
stackSymbolicated?: string
}
// Matches backend IssueEventResponse
export interface BugCollectEventItem {
id: number
issueId?: number
eventId?: string
appKey?: string
userId?: string
sessionId?: string
message?: string
stack?: string
stackSymbolicated?: string
metadata?: string
exception?: BugCollectExceptionInfo
breadcrumbs?: unknown
tags?: unknown
device?: unknown
platform?: string
appVersion?: string
release?: string
environment?: string
sdkName?: string
sdkVersion?: string
createdAt: string
}
// IssueResponse with events embedded (detail view)
export interface BugCollectIssueDetail extends BugCollectIssue {
events?: BugCollectEventItem[]
}
// Matches backend IssueResponse used for rankings
export interface BugCollectIssueRanking {
id: number
title: string
type: string
platform: string
level: string
status: string
platform?: string
count: number
isResolved: boolean
affectedUsers: number
firstSeenAt: string
lastSeenAt: string
appVersion?: string
release?: string
riskScore?: number
}
@ -80,15 +84,24 @@ export interface BugCollectFunnelStep {
export interface BugCollectWebhook {
id: string
appKey: string
url: string
eventTypes: string[]
cooldownSeconds: number
events: string[]
cooldownSec: number
enabled: boolean
hasSecret: boolean
createdAt: string
updatedAt: string
}
// Matches backend PageResult<T> (items/total, not content/totalElements)
export interface BugCollectWebhookRequest {
appKey: string
url: string
events: string[]
cooldownSec: number
secret?: string
}
// Matches backend PageResult<T>
export interface BugCollectPageResult<T> {
items: T[]
page: number
@ -105,8 +118,12 @@ export const bugCollectApi = {
// Issues — page is 1-based (backend convention); startDate/endDate mapped to from/to
issues(appKey: string, params: {
type?: string
level?: string
platform?: string
status?: string
q?: string
assignee?: string
environment?: string
startDate?: string
endDate?: string
page?: number
@ -118,20 +135,52 @@ export const bugCollectApi = {
})
},
issueDetail(id: string) {
issueDetail(id: string | number) {
return client.get<{ data: BugCollectIssueDetail }>(`/bugcollect/v1/issues/${id}`)
},
resolveIssue(id: string | number) {
return client.put<{ data: void }>(`/bugcollect/v1/issues/${id}/resolve`)
},
ignoreIssue(id: string | number) {
return client.put<{ data: void }>(`/bugcollect/v1/issues/${id}/ignore`)
},
assignIssue(id: string | number, assignee: string) {
return client.put<{ data: void }>(`/bugcollect/v1/issues/${id}/assign`, { assignee })
},
deleteIssue(id: string | number) {
return client.delete(`/bugcollect/v1/issues/${id}`)
},
bulkUpdateIssues(appKey: string, ids: number[], action: string) {
return client.post<{ data: void }>('/bugcollect/v1/issues/bulk', { ids, action }, { params: { appKey } })
},
// Rankings
frequencyRanking(appKey: string) {
return client.get<{ data: BugCollectIssueRanking[] }>('/bugcollect/v1/issues/rankings/frequency', { params: { appKey } })
frequencyRanking(appKey: string, params?: { from?: string; to?: string; limit?: number }) {
return client.get<{ data: BugCollectIssueRanking[] }>('/bugcollect/v1/issues/rankings/frequency', {
params: { appKey, ...params },
})
},
riskRanking(appKey: string) {
return client.get<{ data: BugCollectIssueRanking[] }>('/bugcollect/v1/issues/rankings/risk', { params: { appKey } })
riskRanking(appKey: string, params?: { from?: string; to?: string; limit?: number }) {
return client.get<{ data: BugCollectIssueRanking[] }>('/bugcollect/v1/issues/rankings/risk', {
params: { appKey, ...params },
})
},
// Events — eventName→name, startDate/endDate→from/to, page is 0-based from caller → +1 for backend
// Issue events
issueEvents(id: string | number, params?: { from?: string; to?: string; page?: number; size?: number }) {
const { page, ...rest } = params ?? {}
return client.get<{ data: BugCollectPageResult<BugCollectEventItem> }>(`/bugcollect/v1/issues/${id}/events`, {
params: { ...rest, page: (page ?? 0) + 1 },
})
},
// Analytics events
events(appKey: string, params: {
eventName?: string
userId?: string
@ -155,11 +204,13 @@ export const bugCollectApi = {
// Webhooks
webhooks: {
list: (appKey: string) => client.get<{ data: BugCollectWebhook[] }>('/bugcollect/v1/webhooks', { params: { appKey } }),
create: (appKey: string, data: Omit<BugCollectWebhook, 'id' | 'createdAt' | 'updatedAt'>) =>
client.post<{ data: BugCollectWebhook }>('/bugcollect/v1/webhooks', data, { params: { appKey } }),
update: (id: string, data: Partial<Omit<BugCollectWebhook, 'id' | 'createdAt' | 'updatedAt'>>) =>
list: (appKey: string) =>
client.get<{ data: BugCollectWebhook[] }>('/bugcollect/v1/webhooks', { params: { appKey } }),
create: (data: BugCollectWebhookRequest) =>
client.post<{ data: BugCollectWebhook }>('/bugcollect/v1/webhooks', data),
update: (id: string | number, data: Partial<BugCollectWebhookRequest>) =>
client.put<{ data: BugCollectWebhook }>(`/bugcollect/v1/webhooks/${id}`, data),
delete: (id: string) => client.delete(`/bugcollect/v1/webhooks/${id}`),
delete: (id: string | number) =>
client.delete(`/bugcollect/v1/webhooks/${id}`),
},
}