842 lines
42 KiB
HTML
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> |