fix: audit log pagination + useState for page/pageSize
All checks were successful
Deploy Admin Frontend / build-and-deploy (push) Successful in 6s

This commit is contained in:
WangDL 2026-05-22 11:21:05 +08:00
parent cf2dfc1351
commit 4292da4bf1

View File

@ -1,4 +1,4 @@
import { useMemo } from 'react' import { useMemo, useState } from 'react'
import { Row, Col, Typography } from 'antd' import { Row, Col, Typography } from 'antd'
import { useQuery } from '@tanstack/react-query' import { useQuery } from '@tanstack/react-query'
import ReactEChartsCore from 'echarts-for-react/esm/core' import ReactEChartsCore from 'echarts-for-react/esm/core'
@ -7,10 +7,7 @@ import { LineChart, BarChart } from 'echarts/charts'
import { GridComponent, TooltipComponent, TitleComponent, LegendComponent } from 'echarts/components' import { GridComponent, TooltipComponent, TitleComponent, LegendComponent } from 'echarts/components'
import { CanvasRenderer } from 'echarts/renderers' import { CanvasRenderer } from 'echarts/renderers'
import { import {
UserOutlined, UserOutlined, BookOutlined, CloudOutlined, FileOutlined,
BookOutlined,
CloudOutlined,
FileOutlined,
} from '@ant-design/icons' } from '@ant-design/icons'
import dayjs from 'dayjs' import dayjs from 'dayjs'
import MetricCard from '@/components/MetricCard' import MetricCard from '@/components/MetricCard'
@ -27,6 +24,9 @@ function formatStorage(bytes: number): string {
} }
export default function Dashboard() { export default function Dashboard() {
const [auditPage, setAuditPage] = useState(1)
const [auditPageSize, setAuditPageSize] = useState(10)
const { data: stats, isLoading: statsLoading } = useQuery({ const { data: stats, isLoading: statsLoading } = useQuery({
queryKey: ['dashboard', 'stats'], queryKey: ['dashboard', 'stats'],
queryFn: getDashboardStats, queryFn: getDashboardStats,
@ -34,8 +34,8 @@ export default function Dashboard() {
}) })
const { data: auditData, isLoading: auditLoading } = useQuery({ const { data: auditData, isLoading: auditLoading } = useQuery({
queryKey: ['dashboard', 'audit-logs'], queryKey: ['dashboard', 'audit-logs', auditPage, auditPageSize],
queryFn: () => getAuditLogs({ page: 1, limit: 10 }), queryFn: () => getAuditLogs({ page: auditPage, limit: auditPageSize }),
staleTime: 30_000, staleTime: 30_000,
}) })
@ -49,11 +49,9 @@ export default function Dashboard() {
}, },
yAxis: { type: 'value' as const, axisLabel: { fontSize: 11 } }, yAxis: { type: 'value' as const, axisLabel: { fontSize: 11 } },
series: [{ series: [{
name: '日活用户', name: '日活用户', type: 'line',
type: 'line',
data: stats?.userTrend.map((p) => p.value) || [], data: stats?.userTrend.map((p) => p.value) || [],
smooth: true, smooth: true, symbol: 'none',
symbol: 'none',
lineStyle: { color: '#1677ff', width: 2 }, lineStyle: { color: '#1677ff', width: 2 },
areaStyle: { color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ areaStyle: { color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: 'rgba(22,119,255,0.15)' }, { offset: 0, color: 'rgba(22,119,255,0.15)' },
@ -72,13 +70,11 @@ export default function Dashboard() {
}, },
yAxis: { type: 'value' as const, axisLabel: { fontSize: 11 } }, yAxis: { type: 'value' as const, axisLabel: { fontSize: 11 } },
series: [{ series: [{
name: 'AI 调用', name: 'AI 调用', type: 'bar',
type: 'bar',
data: stats?.aiCallTrend.map((p) => p.value) || [], data: stats?.aiCallTrend.map((p) => p.value) || [],
itemStyle: { itemStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: '#52c41a' }, { offset: 0, color: '#52c41a' }, { offset: 1, color: '#b7eb8f' },
{ offset: 1, color: '#b7eb8f' },
]), ]),
borderRadius: [4, 4, 0, 0], borderRadius: [4, 4, 0, 0],
}, },
@ -88,87 +84,43 @@ export default function Dashboard() {
return ( return (
<div style={{ padding: '0 0 24px' }}> <div style={{ padding: '0 0 24px' }}>
<Typography.Title level={5} style={{ margin: '0 0 16px' }}></Typography.Title> <Typography.Title level={5} style={{ margin: '0 0 16px' }}></Typography.Title>
<Row gutter={[16, 16]}> <Row gutter={[16, 16]}>
<Col xs={12} sm={12} lg={6}> <Col xs={12} sm={12} lg={6}>
<MetricCard <MetricCard title="总用户数" value={stats?.totalUsers} loading={statsLoading}
title="总用户数" prefix={<UserOutlined />} trend="up" trendValue={`+${stats?.newUsersToday ?? 0}`} trendLabel="今日新增" />
value={stats?.totalUsers}
loading={statsLoading}
prefix={<UserOutlined />}
trend="up"
trendValue={`+${stats?.newUsersToday ?? 0}`}
trendLabel="今日新增"
/>
</Col> </Col>
<Col xs={12} sm={12} lg={6}> <Col xs={12} sm={12} lg={6}>
<MetricCard <MetricCard title="知识库总数" value={stats?.totalKnowledgeBases} loading={statsLoading}
title="知识库总数" prefix={<BookOutlined />} trend="up" trendValue={`+${stats?.newKbsToday ?? 0}`} trendLabel="今日新增" />
value={stats?.totalKnowledgeBases}
loading={statsLoading}
prefix={<BookOutlined />}
trend="up"
trendValue={`+${stats?.newKbsToday ?? 0}`}
trendLabel="今日新增"
/>
</Col> </Col>
<Col xs={12} sm={12} lg={6}> <Col xs={12} sm={12} lg={6}>
<MetricCard <MetricCard title="今日 AI 调用" value={stats?.totalAiCallsToday} loading={statsLoading}
title="今日 AI 调用" prefix={<CloudOutlined />} />
value={stats?.totalAiCallsToday}
loading={statsLoading}
prefix={<CloudOutlined />}
/>
</Col> </Col>
<Col xs={12} sm={12} lg={6}> <Col xs={12} sm={12} lg={6}>
<MetricCard <MetricCard title="文件存储" value={stats ? formatStorage(stats.totalStorageBytes) : undefined}
title="文件存储" loading={statsLoading} prefix={<FileOutlined />} suffix={`${stats?.totalFiles ?? 0} 个文件`} />
value={stats ? formatStorage(stats.totalStorageBytes) : undefined}
loading={statsLoading}
prefix={<FileOutlined />}
suffix={`${stats?.totalFiles ?? 0} 个文件`}
/>
</Col> </Col>
</Row> </Row>
<Row gutter={[16, 16]} style={{ marginTop: 16 }}> <Row gutter={[16, 16]} style={{ marginTop: 16 }}>
<Col xs={24} lg={12}> <Col xs={24} lg={12}>
<EChartsChartContainer <EChartsChartContainer title="日活用户趋势(近 30 天)" loading={statsLoading} isEmpty={!stats?.userTrend?.length}>
title="日活用户趋势(近 30 天)" <ReactEChartsCore echarts={echarts} option={userTrendOption} style={{ height: 300 }} notMerge lazyUpdate />
loading={statsLoading}
isEmpty={!stats?.userTrend?.length}
>
<ReactEChartsCore
echarts={echarts}
option={userTrendOption}
style={{ height: 300 }}
notMerge
lazyUpdate
/>
</EChartsChartContainer> </EChartsChartContainer>
</Col> </Col>
<Col xs={24} lg={12}> <Col xs={24} lg={12}>
<EChartsChartContainer <EChartsChartContainer title="AI 调用趋势(近 30 天)" loading={statsLoading} isEmpty={!stats?.aiCallTrend?.length}>
title="AI 调用趋势(近 30 天)" <ReactEChartsCore echarts={echarts} option={aiCallTrendOption} style={{ height: 300 }} notMerge />
loading={statsLoading}
isEmpty={!stats?.aiCallTrend?.length}
>
<ReactEChartsCore
echarts={echarts}
option={aiCallTrendOption}
style={{ height: 300 }}
notMerge
/>
</EChartsChartContainer> </EChartsChartContainer>
</Col> </Col>
</Row> </Row>
<div style={{ marginTop: 16 }}> <div style={{ marginTop: 16 }}>
<AuditLogTable <AuditLogTable
headerTitle="最近操作日志" headerTitle="最近操作日志"
dataSource={auditData?.items || []} dataSource={auditData?.items || []}
loading={auditLoading} loading={auditLoading}
pagination={auditData ? { current: auditData.page, pageSize: auditData.limit, total: auditData.total } : undefined} pagination={auditData ? { current: auditData.page, pageSize: auditData.limit, total: auditData.total } : undefined}
onPageChange={(page, pageSize) => { setAuditPage(page); setAuditPageSize(pageSize) }}
/> />
</div> </div>
</div> </div>