<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>网络安全监控中心</title> <script src="https://cdn.tailwindcss.com"></script> <link href="https://cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.min.css" rel="stylesheet"> <script src="https://cdn.jsdelivr.net/npm/echarts@5.4.3/dist/echarts.min.js"></script> <!-- 配置Tailwind自定义颜色和字体 --> <script> tailwind.config = { theme: { extend: { colors: { primary: '#165DFF', secondary: '#0E2E8B', accent: '#FF6B35', danger: '#E63946', darkBlue: '#0A2463', lightBlue: '#3E92CC', cardBlue: '#1A3A6B' }, fontFamily: { sans: ['Inter', 'system-ui', 'sans-serif'], }, } } } </script> <style type="text/tailwindcss"> @layer utilities { .content-auto { content-visibility: auto; } .scrollbar-hide { -ms-overflow-style: none; scrollbar-width: none; } .scrollbar-hide::-webkit-scrollbar { display: none; } .text-shadow { text-shadow: 0 2px 4px rgba(0,0,0,0.1); } .bg-gradient-blue { background: linear-gradient(135deg, #0A2463 0%, #165DFF 100%); } .card-hover { transition: all 0.3s ease; } .card-hover:hover { transform: translateY(-3px); box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04); } } </style> </head> <body class="bg-gradient-to-br from-darkBlue to-primary min-h-screen text-gray-100 font-sans"> <!-- 顶部导航栏 --> <header class="bg-darkBlue/80 backdrop-blur-md border-b border-primary/30 sticky top-0 z-50"> <div class="container mx-auto px-4 py-3 flex items-center justify-between"> <div class="flex items-center space-x-3"> <i class="fa fa-shield text-2xl text-accent"></i> <h1 class="text-xl md:text-2xl font-bold text-shadow">网络安全监控中心</h1> </div> <div class="flex items-center space-x-4"> <div class="hidden md:flex items-center space-x-2 text-sm"> <span class="text-gray-300">当前时间:</span> <span id="current-time" class="font-medium"></span> </div> <button class="bg-primary/20 hover:bg-primary/40 transition-colors p-2 rounded-full"> <i class="fa fa-bell-o"></i> </button> <div class="h-8 w-8 rounded-full bg-accent flex items-center justify-center"> <span class="text-xs font-bold">AD</span> </div> </div> </div> </header> <!-- 主内容区 --> <main class="container mx-auto px-4 py-6"> <!-- 标签页导航 --> <div class="mb-8 flex justify-center"> <div class="inline-flex bg-secondary/30 p-1 rounded-lg"> <button class="tab-button active px-6 py-2 rounded-md bg-primary font-medium transition-all" data-tab="threat"> 威胁态势 </button> <button class="tab-button px-6 py-2 rounded-md hover:bg-primary/50 font-medium transition-all" data-tab="compromise"> 失陷态势 </button> <button class="tab-button px-6 py-2 rounded-md hover:bg-primary/50 font-medium transition-all" data-tab="apt"> APT情报 </button> </div> </div> <!-- 主要内容网格 --> <div class="grid grid-cols-1 lg:grid-cols-3 gap-6"> <!-- 左侧攻击事件列表 --> <div class="lg:col-span-1"> <div class="bg-cardBlue/60 backdrop-blur-sm rounded-xl shadow-lg overflow-hidden border border-primary/20"> <div class="p-4 border-b border-primary/20 flex justify-between items-center"> <h2 class="text-lg font-semibold">最近30日发生的网络攻击行为</h2> <span class="text-xs bg-accent/20 text-accent px-2 py-1 rounded-full">实时更新</span> </div> <div class="flex border-b border-primary/20"> <div class="w-1/3 py-2 px-4 bg-danger/80 text-center font-medium text-sm"> 攻击源地址 </div> <div class="w-2/3 py-2 px-4 bg-primary text-center font-medium text-sm"> 被攻击地址 </div> </div> <div class="max-h-[600px] overflow-y-auto scrollbar-hide"> <div id="attack-list" class="divide-y divide-primary/10"> <!-- 攻击事件项将通过JavaScript动态生成 --> </div> </div> </div> </div> <!-- 右侧世界地图 --> <div class="lg:col-span-2"> <div class="bg-cardBlue/60 backdrop-blur-sm rounded-xl shadow-lg overflow-hidden border border-primary/20 h-full flex flex-col"> <div class="p-4 border-b border-primary/20"> <h2 class="text-lg font-semibold">全球网络攻击分布</h2> </div> <div class="flex-1 p-4 relative"> <div class="absolute top-4 right-4 bg-darkBlue/70 backdrop-blur-sm rounded-lg p-3 shadow-lg border border-primary/20 z-10"> <div class="flex items-center space-x-2 mb-2"> <div class="w-3 h-3 rounded-full bg-accent"></div> <span class="text-sm">攻击路径</span> </div> <div class="flex items-center space-x-2 mb-2"> <div class="w-3 h-3 rounded-full bg-danger"></div> <span class="text-sm">攻击源</span> </div> <div class="flex items-center space-x-2"> <div class="w-3 h-3 rounded-full bg-primary"></div> <span class="text-sm">目标地址</span> </div> </div> <div class="h-full relative"> <!-- 地图容器 --> <div id="world-map" class="w-full h-full"></div> </div> </div> <!-- 统计数据卡片 --> <div class="grid grid-cols-2 md:grid-cols-4 gap-4 p-4 border-t border-primary/20"> <div class="bg-darkBlue/50 rounded-lg p-3 card-hover"> <div class="text-xs text-gray-300 mb-1">总攻击次数</div> <div class="text-2xl font-bold text-white">2,847</div> <div class="text-xs text-green-400 mt-1 flex items-center"> <i class="fa fa-arrow-up mr-1"></i> 12.5% </div> </div> <div class="bg-darkBlue/50 rounded-lg p-3 card-hover"> <div class="text-xs text-gray-300 mb-1">攻击源IP</div> <div class="text-2xl font-bold text-white">147</div> <div class="text-xs text-green-400 mt-1 flex items-center"> <i class="fa fa-arrow-up mr-1"></i> 3.2% </div> </div> <div class="bg-darkBlue/50 rounded-lg p-3 card-hover"> <div class="text-xs text-gray-300 mb-1">目标IP</div> <div class="text-2xl font-bold text-white">892</div> <div class="text-xs text-red-400 mt-1 flex items-center"> <i class="fa fa-arrow-down mr-1"></i> 2.1% </div> </div> <div class="bg-darkBlue/50 rounded-lg p-3 card-hover"> <div class="text-xs text-gray-300 mb-1">高危攻击</div> <div class="text-2xl font-bold text-white">346</div> <div class="text-xs text-green-400 mt-1 flex items-center"> <i class="fa fa-arrow-up mr-1"></i> 8.7% </div> </div> </div> </div> </div> </div> </main> <script> // 实时时间更新 function updateTime() { const now = new Date(); const options = { year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit', second: '2-digit' }; document.getElementById('current-time').textContent = now.toLocaleString('zh-CN', options); } setInterval(updateTime, 1000); updateTime(); // 标签页切换功能 const tabButtons = document.querySelectorAll('.tab-button'); tabButtons.forEach(button => { button.addEventListener('click', () => { // 移除所有活动状态 tabButtons.forEach(btn => btn.classList.remove('active', 'bg-primary')); tabButtons.forEach(btn => btn.classList.add('hover:bg-primary/50')); // 添加当前活动状态 button.classList.add('active', 'bg-primary'); button.classList.remove('hover:bg-primary/50'); // 这里可以添加不同标签页内容的切换逻辑 const tabName = button.getAttribute('data-tab'); console.log(`切换到${tabName}标签页`); }); }); // 攻击数据 const attackData = [ { source: "172.192.38.118", sourceCountry: "au", target: "121.***.**.69", targetCountry: "cn", severity: "high" }, { source: "172.192.38.118", sourceCountry: "au", target: "121.***.**.75", targetCountry: "cn", severity: "high" }, { source: "172.192.38.118", sourceCountry: "au", target: "121.***.**.76", targetCountry: "cn", severity: "medium" }, { source: "172.192.38.118", sourceCountry: "au", target: "121.***.**.77", targetCountry: "cn", severity: "high" }, { source: "172.192.38.118", sourceCountry: "au", target: "121.***.**.78", targetCountry: "cn", severity: "medium" }, { source: "172.192.38.118", sourceCountry: "au", target: "121.***.**.79", targetCountry: "cn", severity: "low" }, { source: "172.192.38.118", sourceCountry: "au", target: "121.***.**.80", targetCountry: "cn", severity: "medium" }, { source: "172.192.38.118", sourceCountry: "au", target: "121.***.**.81", targetCountry: "cn", severity: "high" }, { source: "172.192.38.118", sourceCountry: "au", target: "121.***.**.82", targetCountry: "cn", severity: "medium" }, { source: "47.***.30.140", sourceCountry: "us", target: "218.***.**.102", targetCountry: "cn", severity: "high" }, { source: "64.***.12.89", sourceCountry: "de", target: "117.***.**.56", targetCountry: "cn", severity: "low" }, { source: "89.***.45.22", sourceCountry: "uk", target: "202.***.**.91", targetCountry: "cn", severity: "medium" }, { source: "103.***.76.15", sourceCountry: "jp", target: "180.***.**.143", targetCountry: "cn", severity: "high" }, { source: "212.***.33.77", sourceCountry: "fr", target: "58.***.**.207", targetCountry: "cn", severity: "medium" }, ]; // 生成攻击列表 const attackList = document.getElementById('attack-list'); attackData.forEach(attack => { const attackItem = document.createElement('div'); attackItem.className = 'flex hover:bg-primary/10 transition-colors'; // 攻击源地址列 const sourceCol = document.createElement('div'); sourceCol.className = 'w-1/3 p-3'; sourceCol.innerHTML = ` <div class="flex items-center"> <img src="https://flagcdn.com/w80/${attack.sourceCountry}.png" alt="${attack.sourceCountry}国旗" class="w-5 h-3 mr-2 rounded"> <span class="text-sm truncate">${attack.source}</span> </div> `; // 目标地址列 const targetCol = document.createElement('div'); targetCol.className = 'w-2/3 p-3 flex items-center justify-between'; targetCol.innerHTML = ` <div class="flex items-center"> <img src="https://flagcdn.com/w80/${attack.targetCountry}.png" alt="${attack.targetCountry}国旗" class="w-5 h-3 mr-2 rounded"> <span class="text-sm truncate">${attack.target}</span> </div> <span class="text-xs px-2 py-0.5 rounded-full ${ attack.severity === 'high' ? 'bg-danger/80' : attack.severity === 'medium' ? 'bg-yellow-500/80' : 'bg-green-500/80' }"> ${attack.severity === 'high' ? '高危' : attack.severity === 'medium' ? '中危' : '低危'} </span> `; attackItem.appendChild(sourceCol); attackItem.appendChild(targetCol); attackList.appendChild(attackItem); }); // 国家经纬度数据 const countryCoordinates = { 'au': { name: '澳大利亚', lng: 133.7751, lat: -25.2744 }, 'cn': { name: '中国', lng: 104.1954, lat: 35.8617 }, 'us': { name: '美国', lng: -95.7129, lat: 37.0902 }, 'de': { name: '德国', lng: 10.4515, lat: 51.1657 }, 'uk': { name: '英国', lng: -3.4360, lat: 55.3781 }, 'jp': { name: '日本', lng: 138.2529, lat: 36.2048 }, 'fr': { name: '法国', lng: 2.2137, lat: 46.2276 } }; // 初始化地图 window.addEventListener('load', function() { // 创建地图实例 const chartDom = document.getElementById('world-map'); const myChart = echarts.init(chartDom); // 处理地图数据 function getAttackPaths() { return attackData.map(attack => { const source = countryCoordinates[attack.sourceCountry]; const target = countryCoordinates[attack.targetCountry]; return { source: { name: source.name, value: [source.lng, source.lat] }, target: { name: target.name, value: [target.lng, target.lat] } }; }); } function getUniqueSources() { const sources = {}; attackData.forEach(attack => { if (!sources[attack.sourceCountry]) { const country = countryCoordinates[attack.sourceCountry]; sources[attack.sourceCountry] = { name: country.name, value: [country.lng, country.lat] }; } }); return Object.values(sources); } function getUniqueTargets() { const targets = {}; attackData.forEach(attack => { if (!targets[attack.targetCountry]) { const country = countryCoordinates[attack.targetCountry]; targets[attack.targetCountry] = { name: country.name, value: [country.lng, country.lat] }; } }); return Object.values(targets); } // 注册世界地图 fetch('https://cdn.jsdelivr.net/npm/echarts/map/json/world.json') .then(response => response.json()) .then(worldJson => { echarts.registerMap('world', worldJson); // 设置地图配置 const option = { backgroundColor: 'transparent', tooltip: { trigger: 'item', formatter: function(params) { return `${params.name}<br/>攻击次数: ${getAttackCount(params.name)}`; } }, geo: { map: 'world', roam: true, // 开启缩放和平移 label: { show: false }, itemStyle: { areaColor: 'rgba(26, 58, 107, 0.6)', borderColor: 'rgba(22, 93, 255, 0.3)', borderWidth: 1 }, emphasis: { itemStyle: { areaColor: 'rgba(22, 93, 255, 0.5)' } } }, series: [ // 攻击路径 { name: '攻击路径', type: 'lines', zlevel: 2, effect: { show: true, period: 6, trailLength: 0.3, symbol: 'arrow', symbolSize: 6, color: '#FF6B35' }, lineStyle: { width: 2, color: '#FF6B35', curveness: 0.2, opacity: 0.7 }, data: getAttackPaths() }, // 攻击源点 { name: '攻击源', type: 'scatter', coordinateSystem: 'geo', zlevel: 3, symbol: 'circle', symbolSize: 10, itemStyle: { color: '#E63946', shadowBlur: 10, shadowColor: '#E63946' }, data: getUniqueSources() }, // 目标点 { name: '目标地址', type: 'scatter', coordinateSystem: 'geo', zlevel: 3, symbol: 'circle', symbolSize: 10, itemStyle: { color: '#165DFF', shadowBlur: 10, shadowColor: '#165DFF' }, data: getUniqueTargets() } ] }; // 计算每个国家的攻击次数 function getAttackCount(countryName) { let count = 0; attackData.forEach(attack => { if (countryCoordinates[attack.sourceCountry]?.name === countryName || countryCoordinates[attack.targetCountry]?.name === countryName) { count++; } }); return count; } // 设置配置并渲染地图 myChart.setOption(option); // 窗口大小变化时调整地图大小 window.addEventListener('resize', function() { myChart.resize(); }); }) .catch(error => { console.error('地图加载失败:', error); // 显示错误信息 const mapContainer = document.getElementById('world-map'); mapContainer.innerHTML = ` <div class="flex items-center justify-center h-full text-red-400"> <i class="fa fa-exclamation-triangle mr-2"></i> 地图加载失败,请检查网络连接 </div> `; }); }); </script> </body> </html>