Files
adminpage/src/pages/SystemLogs/index.tsx

219 lines
5.8 KiB
TypeScript
Raw Normal View History

import { useEffect, useState } from 'react'
import {
Table,
Card,
Select,
DatePicker,
Button,
Tag,
Typography,
Space,
Input,
} from 'antd'
import {
SearchOutlined,
ReloadOutlined,
InfoCircleOutlined,
WarningOutlined,
CloseCircleOutlined,
BugOutlined,
} from '@ant-design/icons'
import { getSystemLogs } from '@/api/admin'
import type { SystemLog } from '@/types/api'
import './index.css'
const { Title } = Typography
const { RangePicker } = DatePicker
const { Option } = Select
const SystemLogs = () => {
const [loading, setLoading] = useState(false)
const [logs, setLogs] = useState<SystemLog[]>([])
const [total, setTotal] = useState(0)
const [currentPage, setCurrentPage] = useState(1)
const [pageSize, setPageSize] = useState(20)
const [levelFilter, setLevelFilter] = useState<string>('')
const [moduleFilter, setModuleFilter] = useState<string>('')
const [dateRange, setDateRange] = useState<[string, string] | null>(null)
const fetchLogs = async (page = currentPage, size = pageSize) => {
setLoading(true)
try {
const params: any = {
page,
page_size: size,
}
if (levelFilter) {
params.level = levelFilter
}
if (moduleFilter) {
params.module = moduleFilter
}
if (dateRange) {
params.start_date = dateRange[0]
params.end_date = dateRange[1]
}
const res = await getSystemLogs(params)
if (res.data) {
setLogs(res.data.logs)
setTotal(res.data.total)
}
} catch (error) {
console.error('Failed to fetch logs:', error)
} finally {
setLoading(false)
}
}
useEffect(() => {
fetchLogs()
}, [])
const handleSearch = () => {
setCurrentPage(1)
fetchLogs(1, pageSize)
}
const getLevelTag = (level: string) => {
const levelMap: Record<string, { color: string; icon: React.ReactNode; text: string }> = {
info: { color: 'blue', icon: <InfoCircleOutlined />, text: '信息' },
warning: { color: 'orange', icon: <WarningOutlined />, text: '警告' },
error: { color: 'red', icon: <CloseCircleOutlined />, text: '错误' },
debug: { color: 'default', icon: <BugOutlined />, text: '调试' },
}
const config = levelMap[level] || { color: 'default', icon: null, text: level }
return (
<Tag color={config.color} icon={config.icon}>
{config.text}
</Tag>
)
}
const columns = [
{
title: '时间',
dataIndex: 'created_at',
key: 'created_at',
width: 180,
render: (text: string) => new Date(text).toLocaleString('zh-CN'),
},
{
title: '级别',
dataIndex: 'level',
key: 'level',
width: 100,
render: (level: string) => getLevelTag(level),
},
{
title: '模块',
dataIndex: 'module',
key: 'module',
width: 120,
render: (text: string) => <Tag>{text}</Tag>,
},
{
title: '消息',
dataIndex: 'message',
key: 'message',
ellipsis: true,
},
{
title: '用户ID',
dataIndex: 'user_id',
key: 'user_id',
width: 150,
render: (text: string) => text ? <Tag>{text?.substring(0, 8)}...</Tag> : '-',
},
{
title: 'IP地址',
dataIndex: 'ip',
key: 'ip',
width: 140,
render: (text: string) => text || '-',
},
]
return (
<div className="system-logs">
<div className="page-header">
<Title level={4}></Title>
</div>
<Card className="filter-card" bordered={false}>
<Space wrap>
<Select
placeholder="日志级别"
value={levelFilter || undefined}
onChange={setLevelFilter}
style={{ width: 120 }}
allowClear
>
<Option value="info"></Option>
<Option value="warning"></Option>
<Option value="error"></Option>
<Option value="debug"></Option>
</Select>
<Select
placeholder="模块"
value={moduleFilter || undefined}
onChange={setModuleFilter}
style={{ width: 150 }}
allowClear
>
<Option value="auth"></Option>
<Option value="order"></Option>
<Option value="file"></Option>
<Option value="print"></Option>
<Option value="pay"></Option>
<Option value="admin"></Option>
</Select>
<RangePicker
showTime
onChange={(dates) => {
if (dates) {
setDateRange([
dates[0]?.format('YYYY-MM-DD HH:mm:ss') || '',
dates[1]?.format('YYYY-MM-DD HH:mm:ss') || '',
])
} else {
setDateRange(null)
}
}}
/>
<Button type="primary" icon={<SearchOutlined />} onClick={handleSearch}>
</Button>
<Button icon={<ReloadOutlined />} onClick={() => fetchLogs()}>
</Button>
</Space>
</Card>
<Card className="table-card" bordered={false}>
<Table
columns={columns}
dataSource={logs}
rowKey="id"
loading={loading}
pagination={{
current: currentPage,
pageSize: pageSize,
total: total,
showSizeChanger: true,
showQuickJumper: true,
showTotal: (total) => `${total} 条记录`,
onChange: (page, size) => {
setCurrentPage(page)
setPageSize(size || 20)
fetchLogs(page, size || 20)
},
}}
/>
</Card>
</div>
)
}
export default SystemLogs