import { useCallback, useEffect, useState } from 'react' import { Button, Card, Form, Input, Modal, Select, Space, Table, Tag, Typography, message } from 'antd' import type { ColumnsType } from 'antd/es/table' import { loginLogApi } from '@/lib/api' import { formatDate } from '@/lib/date' import type { LoginLog } from '@/types/system' type LoginLogSearch = { username?: string status?: boolean } export function LoginLogPage() { const [searchForm] = Form.useForm() const [rows, setRows] = useState([]) const [selectedRowKeys, setSelectedRowKeys] = useState([]) const [loading, setLoading] = useState(false) const [page, setPage] = useState(1) const [pageSize, setPageSize] = useState(10) const [total, setTotal] = useState(0) const reloadRows = useCallback(async () => { setLoading(true) try { const values = searchForm.getFieldsValue() const response = await loginLogApi.getLoginLogList({ page, pageSize, username: values.username, ...(typeof values.status === 'boolean' ? { status: values.status } : {}), }) setRows(response.data.list) setTotal(response.data.total) } finally { setLoading(false) } }, [page, pageSize, searchForm]) useEffect(() => { reloadRows() }, [reloadRows]) const refreshAfterDelete = (removedCount: number) => { setSelectedRowKeys([]) if (rows.length <= removedCount && page > 1) { setPage((current) => current - 1) return } reloadRows() } const runSearch = () => { if (page !== 1) { setPage(1) return } reloadRows() } const deleteRow = (record: LoginLog) => { Modal.confirm({ title: `删除登录日志 #${record.ID}`, content: '删除后无法恢复。', okText: '删除', okButtonProps: { danger: true }, onOk: async () => { await loginLogApi.deleteLoginLog(record.ID) message.success('登录日志已删除') refreshAfterDelete(1) }, }) } const deleteSelectedRows = () => { if (!selectedRowKeys.length) { return } Modal.confirm({ title: `批量删除 ${selectedRowKeys.length} 条登录日志`, content: '删除后无法恢复。', okText: '删除', okButtonProps: { danger: true }, onOk: async () => { await loginLogApi.deleteLoginLogByIds(selectedRowKeys.map((item) => Number(item))) message.success('登录日志已删除') refreshAfterDelete(selectedRowKeys.length) }, }) } const columns: ColumnsType = [ { title: 'ID', dataIndex: 'ID', width: 80, }, { title: '用户名', dataIndex: 'username', width: 160, }, { title: '登录 IP', dataIndex: 'ip', width: 160, }, { title: '状态', width: 110, render: (_, record) => {record.status ? '成功' : '失败'}, }, { title: '详情', render: (_, record) => record.errorMessage || (record.status ? '登录成功' : '-'), }, { title: '浏览器/设备', dataIndex: 'agent', ellipsis: true, }, { title: '登录时间', width: 180, render: (_, record) => formatDate(record.CreatedAt), }, { title: '操作', width: 100, fixed: 'right', render: (_, record) => ( ), }, ] return (
登录日志 当前页用于审计登录结果、失败原因和终端信息。