import { useState } from 'react' import { useQuery } from '@tanstack/react-query' import { ScrollText, Search, Filter } from 'lucide-react' import api from '../lib/api' import Card from '../components/ui/Card' import Button from '../components/ui/Button' import EmptyState from '../components/ui/EmptyState' import Pagination from '../components/ui/Pagination' const ACTION_LABELS: Record = { CREATE: '创建', UPDATE: '更新', DELETE: '删除', CORRECT: '更正', CREATE_EMPLOYEE: '创建员工', UPDATE_EMPLOYEE: '更新员工', DELETE_EMPLOYEE: '删除员工', IMPORT_EMPLOYEES: '导入员工', BATCH_RENEW: '批量续签', ADD_CONTRACT: '添加合同', CREATE_CONTRACT: '创建合同', SIGN_CONTRACT: '签署合同', TERMINATE: '解聘', CREATE_TERMINATION: '创建解聘记录', APPROVE_TERMINATION: '审批解聘', REJECT_TERMINATION: '驳回解聘', EXECUTE_TERMINATION: '执行解聘', CANCEL_TERMINATION: '撤销解聘', SUBMIT_TERMINATION: '提交解聘审批', CREATE_DRAFT: '创建草稿', REHIRE: '重新入职', PAYROLL_GENERATE: '生成工资条', PAYROLL_ARCHIVE: '归档发薪批次', PAYROLL_PUBLISH: '发布工资条', EXPORT_PAYROLL: '导出薪税', AI_CHAT: 'AI 对话', AI_REVIEW: 'AI 审查', UPDATE_SETTINGS: '更新设置', POLICY_ADVANCE: '制度流程推进', POLICY_PUBLISH: '制度发布', EVIDENCE_CREATE: '创建证据链', ATTENDANCE_CONFIRM: '考勤确认', } const ENTITY_LABELS: Record = { EMPLOYEE: '员工', CONTRACT: '合同', TERMINATION: '解聘', TERMINATION_RECORD: '解聘记录', PAYROLL: '薪税', PAYSLIP: '工资条', SETTINGS: '设置', POLICY: '制度', POLICY_DOCUMENT: '制度文件', EVIDENCE: '证据链', AI: 'AI', ATTENDANCE: '考勤', DISCIPLINARY: '违纪', EmployeeSocialInsRecord: '社保记录', EmployeeHousingFundRecord: '公积金记录', SocialMonthlyProcess: '社保月度流程', RetirementPolicy: '退休政策', NotificationSetting: '通知设置', } /** * 系统操作日志页面 */ export default function AuditLog() { const [page, setPage] = useState(1) const [pageSize, setPageSize] = useState(20) const [action, setAction] = useState('') const [entity, setEntity] = useState('') const [dateFrom, setDateFrom] = useState('') const [dateTo, setDateTo] = useState('') const { data, isLoading } = useQuery({ queryKey: ['audit-logs', page, pageSize, action, entity, dateFrom, dateTo], queryFn: async () => { const params = new URLSearchParams({ page: String(page), pageSize: String(pageSize) }) if (action) params.set('action', action) if (entity) params.set('entity', entity) if (dateFrom) params.set('dateFrom', dateFrom) if (dateTo) params.set('dateTo', dateTo) const res = await api.get(`/audit?${params}`) as any return res.data }, }) const { data: stats } = useQuery({ queryKey: ['audit-stats'], queryFn: async () => { const res = await api.get('/audit/stats') as any return res.data }, }) return (

系统操作日志

记录所有关键操作,保留6个月以上

{/* 统计概览 */} {stats && stats.length > 0 && (
操作类型分布
{stats.slice(0, 10).map((s: any) => (
{ACTION_LABELS[s.action] || s.action} {s._count.action}
))}
)} {/* 筛选栏 */}
{ setDateFrom(e.target.value); setPage(1) }} className="block mt-1 px-2 py-1.5 text-sm border rounded-lg focus:outline-none focus:ring-1 focus:ring-primary" />
{ setDateTo(e.target.value); setPage(1) }} className="block mt-1 px-2 py-1.5 text-sm border rounded-lg focus:outline-none focus:ring-1 focus:ring-primary" />
{(action || entity || dateFrom || dateTo) && ( )}
{/* 日志列表 */} {isLoading ? (
加载中...
) : !data?.items || data.items.length === 0 ? ( ) : ( <>
{data.items.map((log: any) => (
{ACTION_LABELS[log.action] || log.action} {ENTITY_LABELS[log.entity] || log.entity}
{log.detail && (
{typeof log.detail === 'object' ? JSON.stringify(log.detail).slice(0, 100) : String(log.detail).slice(0, 100)}
)}
{new Date(log.createdAt).toLocaleString('zh-CN', { month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit' })}
{log.ip &&
{log.ip}
}
))}
{ setPageSize(s); setPage(1) }} /> )}
) }