From d9a7260996ee9e505a6481ec39e6bb0d581395bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E5=BE=B7=E5=AE=87?= Date: Tue, 1 Sep 2026 16:28:41 +0800 Subject: [PATCH] =?UTF-8?q?=E4=B8=BA=E9=94=99=E8=AF=AF=E6=8A=A5=E5=91=8A?= =?UTF-8?q?=E5=88=97=E8=A1=A8=E5=A2=9E=E5=8A=A0=E5=88=86=E9=A1=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 扩展管理员列表契约支持 offset、total 和 hasMore 后台页面增加页码状态、上一页和下一页操作 --- apps/admin-web/src/api/adminApiClient.ts | 5 +++ apps/admin-web/src/api/adminApiTypes.ts | 4 ++ .../src/pages/AdminErrorReportsPage.tsx | 44 +++++++++++++++++-- 3 files changed, 50 insertions(+), 3 deletions(-) diff --git a/apps/admin-web/src/api/adminApiClient.ts b/apps/admin-web/src/api/adminApiClient.ts index 5155a2470..6673b98be 100644 --- a/apps/admin-web/src/api/adminApiClient.ts +++ b/apps/admin-web/src/api/adminApiClient.ts @@ -280,6 +280,7 @@ export function listAdminErrorReports( fingerprint?: string; source?: string; limit?: number; + offset?: number; } = {}, ) { return request( @@ -866,6 +867,7 @@ function buildErrorReportQueryString(query: { fingerprint?: string; source?: string; limit?: number; + offset?: number; }) { const params = new URLSearchParams(); appendQueryParam(params, 'status', query.status); @@ -874,6 +876,9 @@ function buildErrorReportQueryString(query: { if (typeof query.limit === 'number' && Number.isFinite(query.limit)) { params.set('limit', String(query.limit)); } + if (typeof query.offset === 'number' && Number.isFinite(query.offset)) { + params.set('offset', String(query.offset)); + } const queryString = params.toString(); return queryString ? `?${queryString}` : ''; } diff --git a/apps/admin-web/src/api/adminApiTypes.ts b/apps/admin-web/src/api/adminApiTypes.ts index c2f9b3b52..b911a6e8b 100644 --- a/apps/admin-web/src/api/adminApiTypes.ts +++ b/apps/admin-web/src/api/adminApiTypes.ts @@ -116,6 +116,10 @@ export interface AdminErrorReportEntry { export interface AdminErrorReportListResponse { reports: AdminErrorReportEntry[]; + total: number; + offset: number; + limit: number; + hasMore: boolean; } export interface AdminErrorReportDetail extends AdminErrorReportEntry { diff --git a/apps/admin-web/src/pages/AdminErrorReportsPage.tsx b/apps/admin-web/src/pages/AdminErrorReportsPage.tsx index 0ac7f508c..4c2f323e8 100644 --- a/apps/admin-web/src/pages/AdminErrorReportsPage.tsx +++ b/apps/admin-web/src/pages/AdminErrorReportsPage.tsx @@ -16,6 +16,7 @@ import type { type Props = { token: string; onUnauthorized: (message?: string) => void }; const ADMIN_ERROR_REPORT_STATUSES = ['new', 'in-progress', 'resolved'] as const; +const ERROR_REPORT_PAGE_SIZE = 50; export function AdminErrorReportsPage({ token, onUnauthorized }: Props) { const [reports, setReports] = useState([]); @@ -23,6 +24,8 @@ export function AdminErrorReportsPage({ token, onUnauthorized }: Props) { const [status, setStatus] = useState(''); const [busy, setBusy] = useState(false); const [filterStatus, setFilterStatus] = useState(''); + const [pageOffset, setPageOffset] = useState(0); + const [pageInfo, setPageInfo] = useState({ total: 0, hasMore: false }); const openReportRequestId = useRef(0); const loadRequestId = useRef(0); @@ -32,15 +35,20 @@ export function AdminErrorReportsPage({ token, onUnauthorized }: Props) { try { const response = await listAdminErrorReports(token, { status: filterStatus || undefined, + limit: ERROR_REPORT_PAGE_SIZE, + offset: pageOffset, }); - if (requestId === loadRequestId.current) setReports(response.reports); + if (requestId === loadRequestId.current) { + setReports(response.reports); + setPageInfo({ total: response.total, hasMore: response.hasMore }); + } } catch (error) { if (requestId !== loadRequestId.current) return; if (isAdminApiError(error) && error.status === 401) return onUnauthorized(); setStatus(formatAdminApiError(error)); } - }, [filterStatus, onUnauthorized, token]); + }, [filterStatus, onUnauthorized, pageOffset, token]); useEffect(() => { void load(); @@ -109,7 +117,10 @@ export function AdminErrorReportsPage({ token, onUnauthorized }: Props) { 状态{' '}