diff --git a/src/main.jsx b/src/main.jsx index c82cad6..1725dc5 100644 --- a/src/main.jsx +++ b/src/main.jsx @@ -52,6 +52,7 @@ import ProductsDetail from '@/views/products/Detail'; import ProductsAudit from '@/views/products/Audit'; import ImageViewer from '@/views/ImageViewer'; import CustomerImageViewer from '@/views/CustomerImageViewer'; +import AkamaiLog from '@/views/AkamaiLog'; import PickYear from './views/products/PickYear' import { BUILD_VERSION, PERM_ACCOUNT_MANAGEMENT, PERM_ROLE_NEW, @@ -122,6 +123,7 @@ const initRouter = async () => { { path: '/logout', element: }, { path: '/image-viewer/:GRI_SN/:GRI_No', element: }, { path: '/customer-image/:key', element: }, + { path: '/akamai-log', element: }, ] } ]) diff --git a/src/views/AkamaiLog.jsx b/src/views/AkamaiLog.jsx new file mode 100644 index 0000000..4af5dfc --- /dev/null +++ b/src/views/AkamaiLog.jsx @@ -0,0 +1,141 @@ +import React, { useState, useEffect } from 'react'; +import { Input, Button, Card, Typography, Space, Alert, Spin, Table, Tag } from 'antd'; +import { useSearchParams } from 'react-router-dom'; +import { postJSON } from "@haina/utils-request"; + +const { Title, Text } = Typography; + +const AkamaiLog = () => { + const [searchParams] = useSearchParams(); + const ip = searchParams.get('ip'); + const [log, setLog] = useState([]);// 日志数据 + const [loading, setLoading] = useState(false);// 加载状态 + const [error, setError] = useState('');// 错误信息 + + // 静态资源扩展名过滤 + const STATIC_EXTENSIONS = [ + '.jpg', '.jpeg', '.png', '.gif', '.bmp', '.webp', '.svg', '.ico', + '.css', '.scss', '.less', + '.js', '.jsx', '.ts', '.tsx', '.map', + '.woff', '.woff2', '.ttf', '.eot', '.otf', + '.mp4', '.mp3', '.avi', '.mov', '.flv', '.webm', '.m3u8', + '.pdf', '.doc', '.docx', '.xls', '.xlsx', '.ppt', '.pptx', + '.zip', '.tar', '.gz', '.rar', '.7z', '.xml', '.json', '.txt', + '.php' + ]; + + // URL路径过滤 + const FILTER_URLS = [ + '/api/', '/admin/', '/wp-admin/', + 'robots.txt', 'sitemap.xml', '/404', '/.well-known/' + ]; + + // 过滤日志数据 + const filterLogData = (data) => { + if (!Array.isArray(data)) return []; + return data.filter(item => { + if (!item.request_path) return true; + + const fullUrl = `${item.request_host || ''}${item.request_path}`; + const requestPath = item.request_path.toLowerCase(); + const hasStaticExtension = STATIC_EXTENSIONS.some(ext => + requestPath.endsWith(ext) + ); + const hasFilteredUrl = FILTER_URLS.some(url => + fullUrl.includes(url) || requestPath.includes(url) + ); + return !hasStaticExtension && !hasFilteredUrl; + }); + }; + + useEffect(() => { + const fetchLog = async () => { + if (!ip) { + setError('未获取到 IP 地址'); + return; + } + setLoading(true); + setError(''); + try { + const res = await postJSON(`http://202.103.69.110:8010/webhook/60601af9-dbd7-4b01-8718-a1c05018b4be`, + { ip: ip } + ); + // console.log('日志数据:', res); + const filteredData = filterLogData(res); + setLog(filteredData); + } catch (err) { + console.error('请求日志失败:', err); + setError('日志加载失败,请稍后重试'); + } finally { + setLoading(false); + } + }; + fetchLog(); + }, [ip]); + + // 表格列配置 + const columns = [ + { + title: '来源地址', + dataIndex: 'referer', + key: 'referer', + width: 250, + }, + // { + // title: '流量(bytes)', + // dataIndex: 'bytes', + // key: 'bytes', + // width: 100, + // }, + { + title: '请求路径', + key: 'request_path', + width: 300, + render: (_, record) => { + return record.request_host + '/' + record.request_path + (record.query_str !== '-' ? '?' + record.query_str : ''); + }, + }, + { + title: '请求方法', + dataIndex: 'request_method', + key: 'request_method', + width: 80, + render: (method) => {method}, + }, + { + title: '状态码', + dataIndex: 'status_code', + key: 'status_code', + width: 80, + }, + { + title: '请求时间', + dataIndex: 'request_time', + key: 'request_time', + width: 180, + }, + ]; + + return ( +
+ Akamai 日志查询 + {error && } + + 当前查询 IP: + {ip || '未获取到ip'} + + + + + + ); +}; + +export default AkamaiLog; \ No newline at end of file