为错误报告列表增加分页
扩展管理员列表契约支持 offset、total 和 hasMore 后台页面增加页码状态、上一页和下一页操作
This commit is contained in:
@@ -280,6 +280,7 @@ export function listAdminErrorReports(
|
||||
fingerprint?: string;
|
||||
source?: string;
|
||||
limit?: number;
|
||||
offset?: number;
|
||||
} = {},
|
||||
) {
|
||||
return request<AdminErrorReportListResponse>(
|
||||
@@ -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}` : '';
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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<AdminErrorReportEntry[]>([]);
|
||||
@@ -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) {
|
||||
状态{' '}
|
||||
<select
|
||||
value={filterStatus}
|
||||
onChange={(event) => setFilterStatus(event.target.value)}
|
||||
onChange={(event) => {
|
||||
setFilterStatus(event.target.value);
|
||||
setPageOffset(0);
|
||||
}}
|
||||
>
|
||||
<option value="">全部</option>
|
||||
{ADMIN_ERROR_REPORT_STATUSES.map((value) => (
|
||||
@@ -162,6 +173,33 @@ export function AdminErrorReportsPage({ token, onUnauthorized }: Props) {
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div className="admin-detail-modal__actions" aria-label="错误报告分页">
|
||||
<span>
|
||||
{pageInfo.total === 0
|
||||
? '暂无报告'
|
||||
: `第 ${pageOffset + 1}-${Math.min(pageOffset + reports.length, pageInfo.total)} 条,共 ${pageInfo.total} 条`}
|
||||
</span>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() =>
|
||||
setPageOffset((offset) =>
|
||||
Math.max(0, offset - ERROR_REPORT_PAGE_SIZE),
|
||||
)
|
||||
}
|
||||
disabled={pageOffset === 0}
|
||||
>
|
||||
上一页
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() =>
|
||||
setPageOffset((offset) => offset + ERROR_REPORT_PAGE_SIZE)
|
||||
}
|
||||
disabled={!pageInfo.hasMore}
|
||||
>
|
||||
下一页
|
||||
</button>
|
||||
</div>
|
||||
{selected ? (
|
||||
<div
|
||||
className="admin-detail-modal"
|
||||
|
||||
Reference in New Issue
Block a user