Files
SMANAGE/TempLate/FTP/map.html
T
2026-06-16 11:55:14 +08:00

842 lines
42 KiB
HTML

<!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/chart.js@4.4.8/dist/chart.umd.min.js"></script>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet">
<!-- Tailwind配置 -->
<script>
tailwind.config = {
theme: {
extend: {
colors: {
primary: '#165DFF',
secondary: '#36CFC9',
danger: '#FF4D4F',
warning: '#FF7D00',
success: '#52C41A',
dark: '#1D2129',
'dark-light': '#272E3B',
'dark-lighter': '#374151',
'light-gray': '#F2F3F5',
'gray-medium': '#86909C',
},
fontFamily: {
inter: ['Inter', 'sans-serif'],
},
}
}
}
</script>
<style type="text/tailwindcss">
@layer utilities {
.content-auto {
content-visibility: auto;
}
.text-shadow {
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
.text-shadow-lg {
text-shadow: 0 4px 8px rgba(0, 0, 0, 0.12), 0 2px 4px rgba(0, 0, 0, 0.08);
}
.glow {
box-shadow: 0 0 15px rgba(22, 93, 255, 0.5);
}
.pulse {
animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
}
.grid-dots {
background-image: radial-gradient(rgba(255, 255, 255, 0.1) 1px, transparent 1px);
background-size: 20px 20px;
}
.gradient-bg {
background: linear-gradient(135deg, #1D2129 0%, #272E3B 100%);
}
.attack-line {
stroke-dasharray: 1000;
stroke-dashoffset: 1000;
animation: dash 3s linear forwards;
}
@keyframes dash {
to {
stroke-dashoffset: 0;
}
}
@keyframes pulse {
0%, 100% {
opacity: 1;
}
50% {
opacity: 0.5;
}
}
}
</style>
</head>
<body class="font-inter bg-dark text-white min-h-screen grid-dots overflow-hidden">
<!-- 顶部导航栏 -->
<header class="bg-dark-light/80 backdrop-blur-md border-b border-dark-lighter z-50">
<div class="container mx-auto px-4 py-3 flex justify-between items-center">
<div class="flex items-center space-x-2">
<div class="h-8 w-8 rounded-lg bg-gradient-to-br from-primary to-secondary flex items-center justify-center">
<i class="fa fa-shield text-white"></i>
</div>
<h1 class="text-xl font-bold bg-gradient-to-r from-white to-gray-300 bg-clip-text text-transparent">全球攻防态势监控平台</h1>
</div>
<div class="flex items-center space-x-6">
<div class="flex items-center space-x-2">
<div class="h-2 w-2 rounded-full bg-success animate-pulse"></div>
<span class="text-sm text-gray-300">系统运行中</span>
</div>
<div class="flex items-center space-x-4">
<button class="text-gray-300 hover:text-white transition-colors">
<i class="fa fa-refresh"></i>
</button>
<button class="text-gray-300 hover:text-white transition-colors">
<i class="fa fa-question-circle"></i>
</button>
<button class="text-gray-300 hover:text-white transition-colors">
<i class="fa fa-user-circle"></i>
</button>
</div>
</div>
</div>
</header>
<!-- 主内容区 -->
<main class="container mx-auto px-4 py-4 flex flex-col lg:flex-row gap-4 h-[calc(100vh-80px)]">
<!-- 左侧控制面板 -->
<div class="w-full lg:w-1/5 flex flex-col gap-4">
<!-- 服务器信息卡片 -->
<div class="bg-dark-light/50 backdrop-blur-md rounded-xl p-4 border border-dark-lighter shadow-lg">
<div class="flex justify-between items-center mb-3">
<h2 class="text-lg font-semibold">服务器信息</h2>
<span class="px-2 py-1 bg-primary/20 text-primary text-xs rounded-full">在线</span>
</div>
<div class="space-y-3">
<div class="flex justify-between">
<span class="text-gray-400 text-sm">位置</span>
<span class="text-white">天津</span>
</div>
<div class="flex justify-between">
<span class="text-gray-400 text-sm">IP地址</span>
<span class="text-white">121.58.245.100</span>
</div>
<div class="flex justify-between">
<span class="text-gray-400 text-sm">系统负载</span>
<div class="flex items-center space-x-2">
<div class="w-20 bg-dark-lighter rounded-full h-2">
<div class="bg-success h-2 rounded-full" style="width: 35%"></div>
</div>
<span class="text-white">35%</span>
</div>
</div>
<div class="flex justify-between">
<span class="text-gray-400 text-sm">响应时间</span>
<span class="text-white">24ms</span>
</div>
</div>
</div>
<!-- 攻击统计卡片 -->
<div class="bg-dark-light/50 backdrop-blur-md rounded-xl p-4 border border-dark-lighter shadow-lg">
<h2 class="text-lg font-semibold mb-3">攻击统计</h2>
<div class="grid grid-cols-2 gap-3">
<div class="bg-dark-lighter/50 rounded-lg p-3">
<p class="text-gray-400 text-sm">今日攻击</p>
<p class="text-2xl font-bold text-danger">2,583</p>
<p class="text-xs text-warning mt-1"><i class="fa fa-arrow-up"></i> 12.5%</p>
</div>
<div class="bg-dark-lighter/50 rounded-lg p-3">
<p class="text-gray-400 text-sm">防护成功率</p>
<p class="text-2xl font-bold text-success">99.8%</p>
<p class="text-xs text-success mt-1"><i class="fa fa-arrow-up"></i> 0.3%</p>
</div>
<div class="bg-dark-lighter/50 rounded-lg p-3">
<p class="text-gray-400 text-sm">活跃攻击源</p>
<p class="text-2xl font-bold text-warning">128</p>
<p class="text-xs text-danger mt-1"><i class="fa fa-arrow-up"></i> 8.2%</p>
</div>
<div class="bg-dark-lighter/50 rounded-lg p-3">
<p class="text-gray-400 text-sm">流量峰值</p>
<p class="text-2xl font-bold text-primary">42.6 Gbps</p>
<p class="text-xs text-gray-400 mt-1"><i class="fa fa-minus"></i> 0.0%</p>
</div>
</div>
</div>
<!-- 攻击类型分布 -->
<div class="bg-dark-light/50 backdrop-blur-md rounded-xl p-4 border border-dark-lighter shadow-lg flex-grow">
<h2 class="text-lg font-semibold mb-3">攻击类型分布</h2>
<div class="h-48">
<canvas id="attackTypesChart"></canvas>
</div>
</div>
<!-- 最近攻击记录 -->
<div class="bg-dark-light/50 backdrop-blur-md rounded-xl p-4 border border-dark-lighter shadow-lg flex-grow">
<h2 class="text-lg font-semibold mb-3">最近攻击记录</h2>
<div class="space-y-2 max-h-60 overflow-y-auto pr-1">
<div class="bg-dark-lighter/30 rounded-lg p-2 flex justify-between items-center">
<div>
<p class="text-sm font-medium">182.168.123.45</p>
<p class="text-xs text-gray-400">DDOS攻击 · 3分钟前</p>
</div>
<span class="px-2 py-1 bg-danger/20 text-danger text-xs rounded-full">高风险</span>
</div>
<div class="bg-dark-lighter/30 rounded-lg p-2 flex justify-between items-center">
<div>
<p class="text-sm font-medium">203.0.113.78</p>
<p class="text-xs text-gray-400">SQL注入 · 15分钟前</p>
</div>
<span class="px-2 py-1 bg-warning/20 text-warning text-xs rounded-full">中风险</span>
</div>
<div class="bg-dark-lighter/30 rounded-lg p-2 flex justify-between items-center">
<div>
<p class="text-sm font-medium">54.176.101.202</p>
<p class="text-xs text-gray-400">XSS攻击 · 28分钟前</p>
</div>
<span class="px-2 py-1 bg-warning/20 text-warning text-xs rounded-full">中风险</span>
</div>
<div class="bg-dark-lighter/30 rounded-lg p-2 flex justify-between items-center">
<div>
<p class="text-sm font-medium">192.168.1.100</p>
<p class="text-xs text-gray-400">暴力破解 · 42分钟前</p>
</div>
<span class="px-2 py-1 bg-warning/20 text-warning text-xs rounded-full">中风险</span>
</div>
<div class="bg-dark-lighter/30 rounded-lg p-2 flex justify-between items-center">
<div>
<p class="text-sm font-medium">104.236.209.25</p>
<p class="text-xs text-gray-400">端口扫描 · 1小时前</p>
</div>
<span class="px-2 py-1 bg-gray-medium/20 text-gray-medium text-xs rounded-full">低风险</span>
</div>
</div>
</div>
</div>
<!-- 中间地图区域 -->
<div class="w-full lg:w-3/5 flex flex-col gap-4">
<div class="bg-dark-light/50 backdrop-blur-md rounded-xl p-4 border border-dark-lighter shadow-lg flex-grow relative overflow-hidden">
<div class="flex justify-between items-center mb-3">
<h2 class="text-lg font-semibold">全球攻击态势</h2>
<div class="flex space-x-2">
<button class="px-3 py-1 bg-primary/20 text-primary text-sm rounded-lg hover:bg-primary/30 transition-colors">
<i class="fa fa-play mr-1"></i>实时
</button>
<button class="px-3 py-1 bg-dark-lighter text-gray-300 text-sm rounded-lg hover:bg-dark-lighter/70 transition-colors">
<i class="fa fa-history mr-1"></i>历史
</button>
</div>
</div>
<!-- 地图容器 -->
<div id="map-container" class="w-full h-[calc(100%-40px)] rounded-lg overflow-hidden relative">
<!-- 瓦片地图将在这里通过JS加载 -->
<div id="map" class="w-full h-full relative">
<!-- 地图加载指示器 -->
<div id="map-loading" class="absolute inset-0 flex items-center justify-center bg-dark-light/80 z-10">
<div class="flex flex-col items-center">
<div class="w-12 h-12 border-4 border-primary border-t-transparent rounded-full animate-spin"></div>
<p class="mt-2 text-gray-300">加载地图数据...</p>
</div>
</div>
<!-- 服务器位置标记 -->
<div id="server-marker" class="absolute" style="left: 75%; top: 45%; transform: translate(-50%, -50%);">
<div class="w-4 h-4 rounded-full bg-primary shadow-lg glow pulse"></div>
<div class="absolute -inset-1 bg-primary/20 rounded-full animate-ping"></div>
<div class="absolute -inset-3 bg-primary/10 rounded-full animate-ping" style="animation-delay: 1s;"></div>
</div>
<!-- 攻击线路将通过JS动态添加 -->
<svg id="attack-lines" class="absolute inset-0 w-full h-full pointer-events-none"></svg>
<!-- 攻击信息卡片将通过JS动态添加 -->
<div id="attack-info-card" class="hidden absolute bg-dark-light/90 backdrop-blur-md rounded-lg p-3 shadow-xl border border-dark-lighter min-w-[200px] z-20">
<div class="flex justify-between items-start mb-2">
<h3 class="font-semibold text-white">攻击详情</h3>
<span id="attack-severity" class="px-2 py-0.5 bg-danger/20 text-danger text-xs rounded-full">高风险</span>
</div>
<div class="space-y-1 text-sm">
<div class="flex justify-between">
<span class="text-gray-400">源IP:</span>
<span id="attack-ip" class="text-white">182.168.123.45</span>
</div>
<div class="flex justify-between">
<span class="text-gray-400">地区:</span>
<span id="attack-region" class="text-white">美国</span>
</div>
<div class="flex justify-between">
<span class="text-gray-400">攻击类型:</span>
<span id="attack-type" class="text-white">DDOS</span>
</div>
<div class="flex justify-between">
<span class="text-gray-400">攻击次数:</span>
<span id="attack-count" class="text-white">245</span>
</div>
<div class="flex justify-between">
<span class="text-gray-400">首次检测:</span>
<span id="attack-first-detected" class="text-white">2023-05-15 14:30</span>
</div>
</div>
<div class="mt-3 pt-2 border-t border-dark-lighter">
<button class="w-full py-1.5 bg-danger/20 text-danger text-sm rounded-lg hover:bg-danger/30 transition-colors">
<i class="fa fa-shield mr-1"></i>加强防护
</button>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- 右侧数据面板 -->
<div class="w-full lg:w-1/5 flex flex-col gap-4">
<!-- 攻击趋势 -->
<div class="bg-dark-light/50 backdrop-blur-md rounded-xl p-4 border border-dark-lighter shadow-lg">
<h2 class="text-lg font-semibold mb-3">攻击趋势</h2>
<div class="h-48">
<canvas id="attackTrendChart"></canvas>
</div>
</div>
<!-- 攻击源分布 -->
<div class="bg-dark-light/50 backdrop-blur-md rounded-xl p-4 border border-dark-lighter shadow-lg">
<h2 class="text-lg font-semibold mb-3">攻击源分布</h2>
<div class="space-y-3">
<div>
<div class="flex justify-between mb-1">
<span class="text-sm text-gray-300">美国</span>
<span class="text-sm font-medium">32%</span>
</div>
<div class="w-full bg-dark-lighter rounded-full h-2">
<div class="bg-danger h-2 rounded-full" style="width: 32%"></div>
</div>
</div>
<div>
<div class="flex justify-between mb-1">
<span class="text-sm text-gray-300">俄罗斯</span>
<span class="text-sm font-medium">24%</span>
</div>
<div class="w-full bg-dark-lighter rounded-full h-2">
<div class="bg-warning h-2 rounded-full" style="width: 24%"></div>
</div>
</div>
<div>
<div class="flex justify-between mb-1">
<span class="text-sm text-gray-300">中国</span>
<span class="text-sm font-medium">18%</span>
</div>
<div class="w-full bg-dark-lighter rounded-full h-2">
<div class="bg-primary h-2 rounded-full" style="width: 18%"></div>
</div>
</div>
<div>
<div class="flex justify-between mb-1">
<span class="text-sm text-gray-300">印度</span>
<span class="text-sm font-medium">12%</span>
</div>
<div class="w-full bg-dark-lighter rounded-full h-2">
<div class="bg-secondary h-2 rounded-full" style="width: 12%"></div>
</div>
</div>
<div>
<div class="flex justify-between mb-1">
<span class="text-sm text-gray-300">其他</span>
<span class="text-sm font-medium">14%</span>
</div>
<div class="w-full bg-dark-lighter rounded-full h-2">
<div class="bg-gray-medium h-2 rounded-full" style="width: 14%"></div>
</div>
</div>
</div>
</div>
<!-- 防护效果 -->
<div class="bg-dark-light/50 backdrop-blur-md rounded-xl p-4 border border-dark-lighter shadow-lg">
<h2 class="text-lg font-semibold mb-3">防护效果</h2>
<div class="grid grid-cols-2 gap-3">
<div class="bg-dark-lighter/50 rounded-lg p-3 text-center">
<div class="text-2xl font-bold text-success mb-1">99.8%</div>
<p class="text-xs text-gray-400">拦截成功率</p>
</div>
<div class="bg-dark-lighter/50 rounded-lg p-3 text-center">
<div class="text-2xl font-bold text-danger mb-1">0.2%</div>
<p class="text-xs text-gray-400">漏报率</p>
</div>
</div>
</div>
<!-- 系统状态 -->
<div class="bg-dark-light/50 backdrop-blur-md rounded-xl p-4 border border-dark-lighter shadow-lg flex-grow">
<h2 class="text-lg font-semibold mb-3">系统状态</h2>
<div class="space-y-3">
<div class="flex items-center justify-between">
<div class="flex items-center">
<div class="w-2 h-2 rounded-full bg-success mr-2"></div>
<span class="text-sm">Web应用防火墙</span>
</div>
<span class="text-xs text-gray-400">正常</span>
</div>
<div class="flex items-center justify-between">
<div class="flex items-center">
<div class="w-2 h-2 rounded-full bg-success mr-2"></div>
<span class="text-sm">入侵检测系统</span>
</div>
<span class="text-xs text-gray-400">正常</span>
</div>
<div class="flex items-center justify-between">
<div class="flex items-center">
<div class="w-2 h-2 rounded-full bg-success mr-2"></div>
<span class="text-sm">流量清洗系统</span>
</div>
<span class="text-xs text-gray-400">正常</span>
</div>
<div class="flex items-center justify-between">
<div class="flex items-center">
<div class="w-2 h-2 rounded-full bg-warning mr-2"></div>
<span class="text-sm">威胁情报更新</span>
</div>
<span class="text-xs text-gray-400">延迟</span>
</div>
<div class="flex items-center justify-between">
<div class="flex items-center">
<div class="w-2 h-2 rounded-full bg-success mr-2"></div>
<span class="text-sm">日志分析系统</span>
</div>
<span class="text-xs text-gray-400">正常</span>
</div>
</div>
</div>
<!-- 操作按钮 -->
<div class="bg-dark-light/50 backdrop-blur-md rounded-xl p-4 border border-dark-lighter shadow-lg">
<div class="space-y-3">
<button class="w-full py-2 bg-primary rounded-lg hover:bg-primary/90 transition-colors flex items-center justify-center">
<i class="fa fa-refresh mr-2"></i>刷新数据
</button>
<button class="w-full py-2 bg-dark-lighter text-gray-300 rounded-lg hover:bg-dark-lighter/70 transition-colors flex items-center justify-center">
<i class="fa fa-history mr-2"></i>历史记录
</button>
<button class="w-full py-2 bg-dark-lighter text-gray-300 rounded-lg hover:bg-dark-lighter/70 transition-colors flex items-center justify-center">
<i class="fa fa-cog mr-2"></i>系统设置
</button>
</div>
</div>
</div>
</main>
<!-- API调用示例区域 -->
<div class="fixed bottom-4 right-4 bg-dark-light/80 backdrop-blur-md rounded-lg p-4 border border-dark-lighter shadow-lg z-50">
<h3 class="text-sm font-semibold mb-2">API调用示例</h3>
<div class="space-y-2">
<div class="flex items-center space-x-2">
<input type="text" id="api-region" placeholder="地区编号" class="px-3 py-1 bg-dark-lighter rounded-lg text-sm w-24 focus:outline-none focus:ring-1 focus:ring-primary">
<input type="text" id="api-count" placeholder="攻击数量" class="px-3 py-1 bg-dark-lighter rounded-lg text-sm w-24 focus:outline-none focus:ring-1 focus:ring-primary">
<select id="api-type" class="px-3 py-1 bg-dark-lighter rounded-lg text-sm w-32 focus:outline-none focus:ring-1 focus:ring-primary">
<option value="ddos">DDOS</option>
<option value="sql">SQL注入</option>
<option value="xss">XSS攻击</option>
<option value="brute">暴力破解</option>
<option value="scan">端口扫描</option>
</select>
</div>
<button id="api-simulate" class="w-full py-1.5 bg-primary/20 text-primary text-sm rounded-lg hover:bg-primary/30 transition-colors">
模拟攻击
</button>
</div>
</div>
<script>
// 全球各地区坐标映射(示例数据)
const regionCoordinates = {
"US": { name: "美国", x: 20, y: 40, ip: "182.168.123.45" },
"RU": { name: "俄罗斯", x: 70, y: 30, ip: "203.0.113.78" },
"CN": { name: "中国", x: 85, y: 45, ip: "54.176.101.202" },
"IN": { name: "印度", x: 75, y: 55, ip: "192.168.1.100" },
"DE": { name: "德国", x: 50, y: 35, ip: "104.236.209.25" },
"JP": { name: "日本", x: 90, y: 40, ip: "172.16.254.1" },
"BR": { name: "巴西", x: 30, y: 70, ip: "198.51.100.1" },
"UK": { name: "英国", x: 48, y: 32, ip: "203.0.113.25" },
"AU": { name: "澳大利亚", x: 90, y: 75, ip: "192.0.2.1" },
"FR": { name: "法国", x: 50, y: 35, ip: "198.51.100.25" }
};
// 攻击类型配置
const attackTypes = {
"ddos": { name: "DDOS", color: "#FF4D4F", severity: "高风险" },
"sql": { name: "SQL注入", color: "#FF7D00", severity: "中风险" },
"xss": { name: "XSS攻击", color: "#FF7D00", severity: "中风险" },
"brute": { name: "暴力破解", color: "#FF7D00", severity: "中风险" },
"scan": { name: "端口扫描", color: "#86909C", severity: "低风险" }
};
// 服务器位置
const serverPosition = { x: 75, y: 45 };
// 地图元素
const mapContainer = document.getElementById('map-container');
const mapElement = document.getElementById('map');
const attackLines = document.getElementById('attack-lines');
const attackInfoCard = document.getElementById('attack-info-card');
const mapLoading = document.getElementById('map-loading');
// 初始化地图
function initMap() {
// 模拟地图加载
setTimeout(() => {
// 创建地图瓦片
const mapWidth = mapElement.offsetWidth;
const mapHeight = mapElement.offsetHeight;
// 使用BBBike extracts的瓦片地图
const tileSize = 256;
const zoom = 2;
const tilesX = Math.ceil(mapWidth / tileSize) + 2;
const tilesY = Math.ceil(mapHeight / tileSize) + 2;
// 这里应该使用真实的瓦片地图URL,例如OpenStreetMap或BBBike extracts
// 为了演示,我们使用模拟的瓦片
for (let x = 0; x < tilesX; x++) {
for (let y = 0; y < tilesY; y++) {
const tile = document.createElement('div');
tile.className = 'absolute w-[256px] h-[256px] opacity-80';
tile.style.left = `${x * tileSize - 256}px`;
tile.style.top = `${y * tileSize - 256}px`;
// 使用BBBike extracts的瓦片地图
// 注意:实际使用时需要替换为有效的瓦片服务器URL
tile.style.backgroundImage = `url(https://tile.openstreetmap.org/${zoom}/${x}/${y}.png)`;
tile.style.backgroundSize = 'cover';
tile.style.filter = 'brightness(0.5)';
mapElement.appendChild(tile);
}
}
// 隐藏加载指示器
mapLoading.classList.add('hidden');
// 模拟一些初始攻击线路
simulateInitialAttacks();
}, 1500);
}
// 模拟初始攻击
function simulateInitialAttacks() {
const regions = Object.keys(regionCoordinates);
const attackTypes = Object.keys(attackTypes);
// 随机生成3-5条初始攻击线路
const attackCount = Math.floor(Math.random() * 3) + 3;
for (let i = 0; i < attackCount; i++) {
const randomRegion = regions[Math.floor(Math.random() * regions.length)];
const randomType = attackTypes[Math.floor(Math.random() * attackTypes.length)];
const count = Math.floor(Math.random() * 300) + 50;
setTimeout(() => {
addAttackLine(randomRegion, count, randomType);
}, i * 1000);
}
}
// 添加攻击线路
function addAttackLine(regionCode, count, type) {
const region = regionCoordinates[regionCode];
const attackType = attackTypes[type];
if (!region || !attackType) {
console.error("无效的地区或攻击类型");
return;
}
// 计算攻击强度(基于攻击数量)
const maxCount = 500;
const intensity = Math.min(count / maxCount, 1);
// 创建SVG路径
const path = document.createElementNS("http://www.w3.org/2000/svg", "path");
// 计算路径
const mapWidth = mapElement.offsetWidth;
const mapHeight = mapElement.offsetHeight;
const startX = (region.x / 100) * mapWidth;
const startY = (region.y / 100) * mapHeight;
const endX = (serverPosition.x / 100) * mapWidth;
const endY = (serverPosition.y / 100) * mapHeight;
// 添加曲线效果
const controlX = (startX + endX) / 2 + (Math.random() - 0.5) * 100;
const controlY = (startY + endY) / 2 + (Math.random() - 0.5) * 100;
// 创建渐变
const gradientId = `gradient-${Date.now()}`;
const defs = document.createElementNS("http://www.w3.org/2000/svg", "defs");
const linearGradient = document.createElementNS("http://www.w3.org/2000/svg", "linearGradient");
linearGradient.setAttribute("id", gradientId);
linearGradient.setAttribute("x1", "0%");
linearGradient.setAttribute("y1", "0%");
linearGradient.setAttribute("x2", "100%");
linearGradient.setAttribute("y2", "0%");
const stop1 = document.createElementNS("http://www.w3.org/2000/svg", "stop");
stop1.setAttribute("offset", "0%");
stop1.setAttribute("stop-color", attackType.color);
stop1.setAttribute("stop-opacity", intensity);
const stop2 = document.createElementNS("http://www.w3.org/2000/svg", "stop");
stop2.setAttribute("offset", "100%");
stop2.setAttribute("stop-color", attackType.color);
stop2.setAttribute("stop-opacity", 0);
linearGradient.appendChild(stop1);
linearGradient.appendChild(stop2);
defs.appendChild(linearGradient);
// 设置路径
path.setAttribute("d", `M ${startX},${startY} Q ${controlX},${controlY} ${endX},${endY}`);
path.setAttribute("stroke", `url(#${gradientId})`);
path.setAttribute("stroke-width", 2);
path.setAttribute("fill", "none");
path.setAttribute("class", "attack-line");
path.setAttribute("data-region", regionCode);
path.setAttribute("data-count", count);
path.setAttribute("data-type", type);
// 添加到SVG
attackLines.appendChild(defs);
attackLines.appendChild(path);
// 添加攻击源标记
const attackMarker = document.createElement('div');
attackMarker.className = 'absolute w-2 h-2 rounded-full bg-danger shadow-lg animate-pulse';
attackMarker.style.left = `${startX - 1}px`;
attackMarker.style.top = `${startY - 1}px`;
attackMarker.setAttribute("data-path-id", attackLines.children.length - 1);
mapElement.appendChild(attackMarker);
// 添加点击事件
path.addEventListener('mouseover', () => showAttackInfo(region, count, attackType, startX, startY));
path.addEventListener('mouseout', () => hideAttackInfo());
// 清理旧的攻击线(保留最近的10条)
cleanupOldAttacks();
}
// 显示攻击信息卡片
function showAttackInfo(region, count, attackType, x, y) {
// 更新卡片内容
document.getElementById('attack-ip').textContent = region.ip;
document.getElementById('attack-region').textContent = region.name;
document.getElementById('attack-type').textContent = attackType.name;
document.getElementById('attack-count').textContent = count;
document.getElementById('attack-severity').textContent = attackType.severity;
document.getElementById('attack-severity').className = `px-2 py-0.5 ${
attackType.severity === '高风险' ? 'bg-danger/20 text-danger' :
attackType.severity === '中风险' ? 'bg-warning/20 text-warning' :
'bg-gray-medium/20 text-gray-medium'
} text-xs rounded-full`;
// 设置当前时间
const now = new Date();
const timeString = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}-${String(now.getDate()).padStart(2, '0')} ${String(now.getHours()).padStart(2, '0')}:${String(now.getMinutes()).padStart(2, '0')}`;
document.getElementById('attack-first-detected').textContent = timeString;
// 定位卡片
const cardWidth = attackInfoCard.offsetWidth;
const cardHeight = attackInfoCard.offsetHeight;
const mapWidth = mapElement.offsetWidth;
const mapHeight = mapElement.offsetHeight;
// 确保卡片在地图内显示
let left = x + 20;
let top = y - cardHeight / 2;
if (left + cardWidth > mapWidth) {
left = x - cardWidth - 20;
}
if (top < 0) {
top = 0;
} else if (top + cardHeight > mapHeight) {
top = mapHeight - cardHeight;
}
attackInfoCard.style.left = `${left}px`;
attackInfoCard.style.top = `${top}px`;
// 显示卡片
attackInfoCard.classList.remove('hidden');
}
// 隐藏攻击信息卡片
function hideAttackInfo() {
attackInfoCard.classList.add('hidden');
}
// 清理旧的攻击线路
function cleanupOldAttacks() {
// 保留最近的10条攻击线路
const paths = attackLines.querySelectorAll('path');
if (paths.length > 10) {
const countToRemove = paths.length - 10;
for (let i = 0; i < countToRemove; i++) {
attackLines.removeChild(paths[i]);
}
// 清理对应的标记
const markers = mapElement.querySelectorAll('.animate-pulse');
if (markers.length > 10) {
const markersToRemove = markers.length - 10;
for (let i = 0; i < markersToRemove; i++) {
mapElement.removeChild(markers[i]);
}
}
}
}
// 初始化图表
function initCharts() {
// 攻击类型分布图表
const attackTypesCtx = document.getElementById('attackTypesChart').getContext('2d');
new Chart(attackTypesCtx, {
type: 'doughnut',
data: {
labels: ['DDOS', 'SQL注入', 'XSS攻击', '暴力破解', '端口扫描'],
datasets: [{
data: [35, 25, 15, 10, 15],
backgroundColor: [
'#FF4D4F',
'#FF7D00',
'#36CFC9',
'#165DFF',
'#86909C'
],
borderWidth: 0,
cutout: '70%'
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
position: 'bottom',
labels: {
color: '#F2F3F5',
font: {
size: 10
},
padding: 10
}
}
}
}
});
// 攻击趋势图表
const attackTrendCtx = document.getElementById('attackTrendChart').getContext('2d');
new Chart(attackTrendCtx, {
type: 'line',
data: {
labels: ['00:00', '04:00', '08:00', '12:00', '16:00', '20:00'],
datasets: [{
label: '攻击次数',
data: [120, 90, 180, 150, 200, 170],
borderColor: '#165DFF',
backgroundColor: 'rgba(22, 93, 255, 0.1)',
fill: true,
tension: 0.4,
borderWidth: 2
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
scales: {
y: {
beginAtZero: true,
grid: {
color: 'rgba(255, 255, 255, 0.05)'
},
ticks: {
color: '#86909C',
font: {
size: 10
}
}
},
x: {
grid: {
display: false
},
ticks: {
color: '#86909C',
font: {
size: 10
}
}
}
},
plugins: {
legend: {
display: false
}
}
}
});
}
// 初始化事件监听
function initEventListeners() {
// API模拟按钮
document.getElementById('api-simulate').addEventListener('click', () => {
const regionCode = document.getElementById('api-region').value;
const count = parseInt(document.getElementById('api-count').value);
const type = document.getElementById('api-type').value;
if (!regionCode || isNaN(count) || count <= 0) {
alert('请输入有效的地区编号和攻击数量');
return;
}
if (regionCoordinates[regionCode]) {
addAttackLine(regionCode, count, type);
} else {
alert('无效的地区编号');
}
});
// 窗口大小变化时重新计算地图尺寸
window.addEventListener('resize', () => {
// 简单处理:刷新页面
// 实际应用中应更优雅地处理地图重绘
if (mapElement.children.length > 0) {
mapElement.innerHTML = '';
attackLines.innerHTML = '';
initMap();
}
});
}
// 页面加载完成后初始化
window.addEventListener('DOMContentLoaded', () => {
initMap();
initCharts();
initEventListeners();
});
</script>
</body>
</html>