feat: 添加访问日志分页功能,优化相关接口和前端组件

This commit is contained in:
ryan
2026-03-14 23:18:49 +08:00
parent b7d38590ba
commit 8d406f5ade
8 changed files with 184 additions and 23 deletions
@@ -1,11 +1,15 @@
import { apiRequest } from '@/lib/api/client';
import type { AccessLogItem } from '@/features/access-logs/types';
import type { AccessLogList } from '@/features/access-logs/types';
export function getAccessLogs(nodeId?: string) {
export function getAccessLogs(page: number, nodeId?: string, pageSize = 50) {
const normalizedNodeId = nodeId?.trim();
const query = normalizedNodeId
? `?node_id=${encodeURIComponent(normalizedNodeId)}`
: '';
return apiRequest<AccessLogItem[]>(`/access-logs/${query}`);
const searchParams = new URLSearchParams({
p: String(Math.max(page, 0)),
page_size: String(pageSize),
});
if (normalizedNodeId) {
searchParams.set('node_id', normalizedNodeId);
}
return apiRequest<AccessLogList>(`/access-logs/?${searchParams.toString()}`);
}
@@ -54,13 +54,16 @@ export function AccessLogsPage() {
const queryClient = useQueryClient();
const [nodeFilterInput, setNodeFilterInput] = useState('');
const [nodeFilter, setNodeFilter] = useState('');
const [page, setPage] = useState(0);
const logsQuery = useQuery({
queryKey: accessLogsQueryKey(nodeFilter),
queryFn: () => getAccessLogs(nodeFilter),
queryKey: [...accessLogsQueryKey(nodeFilter), page],
queryFn: () => getAccessLogs(page, nodeFilter),
});
const logs = useMemo(() => logsQuery.data ?? [], [logsQuery.data]);
const logs = useMemo(() => logsQuery.data?.items ?? [], [logsQuery.data]);
const hasMore = logsQuery.data?.has_more ?? false;
const pageSize = logsQuery.data?.page_size ?? 50;
const summary = useMemo(() => buildSummary(logs), [logs]);
return (
@@ -126,7 +129,10 @@ export function AccessLogsPage() {
<div className="flex flex-wrap gap-2">
<PrimaryButton
type="button"
onClick={() => setNodeFilter(nodeFilterInput.trim())}
onClick={() => {
setNodeFilter(nodeFilterInput.trim());
setPage(0);
}}
>
筛选
</PrimaryButton>
@@ -135,6 +141,7 @@ export function AccessLogsPage() {
onClick={() => {
setNodeFilter('');
setNodeFilterInput('');
setPage(0);
}}
>
清空
@@ -209,6 +216,27 @@ export function AccessLogsPage() {
</table>
</div>
)}
<div className="flex flex-col gap-3 border-t border-[var(--border-default)] pt-4 sm:flex-row sm:items-center sm:justify-between">
<p className="text-sm text-[var(--foreground-secondary)]">
第 {page + 1} 页,每页 {pageSize} 条。
</p>
<div className="flex gap-2">
<SecondaryButton
type="button"
disabled={page === 0 || logsQuery.isLoading}
onClick={() => setPage((value) => Math.max(value - 1, 0))}
>
上一页
</SecondaryButton>
<SecondaryButton
type="button"
disabled={!hasMore || logsQuery.isLoading}
onClick={() => setPage((value) => value + 1)}
>
下一页
</SecondaryButton>
</div>
</div>
</div>
</AppCard>
</div>
@@ -8,3 +8,10 @@ export interface AccessLogItem {
path: string;
status_code: number;
}
export interface AccessLogList {
items: AccessLogItem[];
page: number;
page_size: number;
has_more: boolean;
}
@@ -733,10 +733,9 @@ export function NodeDetailPage({ nodeId }: { nodeId: string }) {
/>
</div>
<div className="grid gap-6 xl:grid-cols-[1.1fr_1.1fr_0.8fr]">
<div className="grid gap-6 xl:grid-cols-3">
<AppCard
title="系统画像"
description="展示节点当前上报的主机事实信息,便于快速识别机器环境。"
title="系统信息"
>
{observabilityQuery.isLoading ? (
<LoadingState />