删除第一张风险监控地图(SecurityRiskMap)及相关代码

This commit is contained in:
gcw_yTjNWok9
2025-12-18 13:37:44 +08:00
parent bb17c69ba9
commit 7e6321a7b9
11 changed files with 2084 additions and 89 deletions

View File

@@ -0,0 +1,418 @@
<template>
<div class="threat-intel-map">
<div ref="chartDiv" class="map-chart"></div>
<!-- 左侧漏洞类型面板 -->
<div class="info-panel panel-left">
<div class="panel-title">🔍 漏洞类型分布</div>
<div class="vuln-list">
<div class="vuln-item" v-for="(item, index) in vulnTypes" :key="index">
<div class="vuln-header">
<span class="vuln-name">{{ item.name }}</span>
<span class="vuln-count">{{ item.count }}</span>
</div>
<div class="progress-bar">
<div class="progress-fill" :style="{ width: item.percentage + '%', background: item.color }"></div>
</div>
<div class="vuln-trend" :class="item.trend">
{{ item.trend === 'up' ? '↗' : item.trend === 'down' ? '↘' : '→' }} {{ item.change }}%
</div>
</div>
</div>
</div>
<!-- 右侧威胁情报排行 -->
<div class="info-panel panel-right">
<div class="panel-title">📊 威胁情报排行</div>
<div class="intel-ranking">
<div class="rank-item" v-for="(item, index) in intelRanking" :key="index">
<div class="rank-badge" :class="'rank-' + (index + 1)">{{ index + 1 }}</div>
<div class="rank-info">
<div class="rank-country">{{ item.country }}</div>
<div class="rank-threats">{{ item.threats.toLocaleString() }} 威胁</div>
</div>
<div class="rank-indicator" :style="{ background: item.riskLevel === 'high' ? '#ef4444' : item.riskLevel === 'medium' ? '#f59e0b' : '#10b981' }"></div>
</div>
</div>
</div>
</div>
</template>
<script setup>
import { ref, onMounted, onUnmounted } from 'vue'
import * as echarts from 'echarts'
// 响应式数据
const chartDiv = ref(null)
const myChart = ref(null)
// 漏洞类型数据
const vulnTypes = ref([
{ name: 'XSS 跨站脚本', count: 1247, percentage: 35, color: '#ef4444', trend: 'up', change: 12 },
{ name: 'SQL 注入', count: 892, percentage: 25, color: '#f97316', trend: 'down', change: 8 },
{ name: '缓冲区溢出', count: 634, percentage: 18, color: '#eab308', trend: 'up', change: 15 },
{ name: '输入验证', count: 445, percentage: 12, color: '#3b82f6', trend: 'stable', change: 2 },
{ name: '信息泄露', count: 356, percentage: 10, color: '#10b981', trend: 'down', change: 5 }
])
// 威胁情报排行
const intelRanking = ref([
{ country: 'United States', threats: 15420, riskLevel: 'high' },
{ country: 'China', threats: 12350, riskLevel: 'high' },
{ country: 'Russia', threats: 9870, riskLevel: 'high' },
{ country: 'Germany', threats: 6540, riskLevel: 'medium' },
{ country: 'Brazil', threats: 4320, riskLevel: 'medium' }
])
// 地理坐标映射 - 主要城市坐标
const geoCoordMap = {
'Beijing': [116.4074, 39.9042], // 北京
'Shanghai': [121.4737, 31.2304], // 上海
'Guangzhou': [113.2644, 23.1291], // 广州
'Shenzhen': [114.0579, 22.5431], // 深圳
'Washington': [-77.0369, 38.9072], // 华盛顿
'NewYork': [-74.0060, 40.7128], // 纽约
'Moscow': [37.6173, 55.7558], // 莫斯科
'Berlin': [13.4050, 52.5200], // 柏林
'Tokyo': [139.6917, 35.6895], // 东京
'London': [-0.1278, 51.5074], // 伦敦
'Paris': [2.3522, 48.8566], // 巴黎
'Sydney': [151.2093, -33.8688], // 悉尼
'Mumbai': [72.8777, 19.0760], // 孟买
'Dubai': [55.2708, 25.2048], // 迪拜
'Toronto': [-79.3832, 43.6532], // 多伦多
'SaoPaulo': [-46.6333, -23.5505], // 圣保罗
'Cairo': [31.2357, 30.0444], // 开罗
'Istanbul': [28.9784, 41.0082], // 伊斯坦布尔
'Tehran': [51.3890, 35.6892], // 德黑兰
'Riyadh': [46.6753, 24.7136] // 利雅得
}
import { loadWorldMap } from '@/utils/mapLoader'
// 初始化图表
const initChart = () => {
if (!chartDiv.value) return
// 地图热力数据
const mapData = [
{ name: 'China', value: 100 },
{ name: 'United States', value: 95 },
{ name: 'Russia', value: 80 },
{ name: 'Germany', value: 65 },
{ name: 'Brazil', value: 45 },
{ name: 'India', value: 55 },
{ name: 'Japan', value: 40 },
{ name: 'United Kingdom', value: 35 },
{ name: 'France', value: 30 },
{ name: 'Australia', value: 25 },
{ name: 'Canada', value: 35 },
{ name: 'Mexico', value: 20 },
{ name: 'Argentina', value: 15 },
{ name: 'South Africa', value: 18 },
{ name: 'Egypt', value: 22 },
{ name: 'Turkey', value: 28 },
{ name: 'Iran', value: 32 },
{ name: 'Saudi Arabia', value: 25 },
{ name: 'Kazakhstan', value: 12 },
{ name: 'Mongolia', value: 8 }
]
// 威胁情报节点
const intelNodes = [
{ name: '北京情报中心', value: [...geoCoordMap['Beijing'], 100] },
{ name: '上海监测点', value: [...geoCoordMap['Shanghai'], 85] },
{ name: '广州分析中心', value: [...geoCoordMap['Guangzhou'], 75] },
{ name: '深圳预警站', value: [...geoCoordMap['Shenzhen'], 70] },
{ name: '华盛顿情报站', value: [...geoCoordMap['Washington'], 90] },
{ name: '纽约监控点', value: [...geoCoordMap['NewYork'], 80] },
{ name: '莫斯科分析点', value: [...geoCoordMap['Moscow'], 85] },
{ name: '柏林预警中心', value: [...geoCoordMap['Berlin'], 65] },
{ name: '东京监测站', value: [...geoCoordMap['Tokyo'], 60] },
{ name: '伦敦情报点', value: [...geoCoordMap['London'], 55] }
]
const option = {
backgroundColor: 'transparent',
// 视觉映射组件
visualMap: {
min: 0,
max: 100,
left: '20',
bottom: '20',
text: ['高风险', '低风险'],
textStyle: { color: '#64748b', fontSize: 10 },
calculable: true,
inRange: {
color: ['#e0e7ff', '#c7d2fe', '#a5b4fc', '#818cf8', '#6366f1']
}
},
tooltip: {
trigger: 'item',
backgroundColor: 'rgba(255,255,255,0.95)',
borderColor: '#e2e8f0',
textStyle: { color: '#1f2937' },
formatter: function(params) {
if(params.seriesType === 'effectScatter') {
return `${params.marker} ${params.name}<br/>威胁指数: ${params.value[2]}`
}
if(!params.value) return params.name + ': 无数据'
return `${params.name}<br/>威胁等级: ${params.value}`
}
},
geo: {
map: 'world',
roam: true,
zoom: 1.2,
label: { show: false },
itemStyle: {
areaColor: '#f8fafc',
borderColor: '#e2e8f0',
borderWidth: 1
},
emphasis: {
label: { show: false },
itemStyle: {
areaColor: '#3b82f6',
shadowBlur: 10,
shadowColor: 'rgba(59, 130, 246, 0.3)'
}
}
},
series: [
// 地域威胁热力图
{
name: '威胁分布',
type: 'map',
geoIndex: 0,
data: mapData
},
// 情报节点
{
name: '情报节点',
type: 'effectScatter',
coordinateSystem: 'geo',
data: intelNodes,
symbolSize: function (val) {
return val[2] / 6
},
showEffectOn: 'render',
rippleEffect: {
brushType: 'stroke',
scale: 2.5
},
label: {
show: true,
formatter: '{b}',
position: 'right',
color: '#1f2937',
fontSize: 9,
textBorderColor: '#fff',
textBorderWidth: 1
},
itemStyle: {
color: '#f59e0b',
shadowBlur: 10,
shadowColor: '#f59e0b'
},
zlevel: 1
}
]
}
myChart.value = echarts.init(chartDiv.value)
myChart.value.setOption(option)
}
// 组件挂载
onMounted(async () => {
await loadWorldMap()
initChart()
window.addEventListener('resize', () => {
myChart.value && myChart.value.resize()
})
})
// 组件卸载
onUnmounted(() => {
if (myChart.value) {
myChart.value.dispose()
}
window.removeEventListener('resize', () => {
myChart.value && myChart.value.resize()
})
})
</script>
<style lang="scss" scoped>
.threat-intel-map {
position: relative;
width: 100%;
height: 100%;
background: linear-gradient(135deg, #f8fafc 0%, #e0e7ff 100%);
border-radius: 0.5rem;
overflow: hidden;
}
.map-chart {
width: 100%;
height: 100%;
}
/* 信息面板通用样式 */
.info-panel {
position: absolute;
top: 20px;
width: 260px;
background: rgba(255, 255, 255, 0.95);
backdrop-filter: blur(8px);
border: 1px solid rgba(59, 130, 246, 0.2);
border-radius: 0.5rem;
padding: 16px;
z-index: 10;
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1);
.panel-title {
font-size: 14px;
font-weight: 600;
color: #3b82f6;
margin-bottom: 12px;
border-bottom: 1px solid rgba(59, 130, 246, 0.2);
padding-bottom: 8px;
}
}
.panel-left { left: 20px; }
.panel-right { right: 20px; }
/* 漏洞类型列表 */
.vuln-list {
.vuln-item {
margin-bottom: 12px;
.vuln-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 4px;
.vuln-name {
font-size: 12px;
color: #374151;
font-weight: 500;
}
.vuln-count {
font-size: 11px;
color: #6b7280;
font-weight: 600;
}
}
.progress-bar {
height: 4px;
background: rgba(59, 130, 246, 0.1);
border-radius: 2px;
overflow: hidden;
margin-bottom: 4px;
.progress-fill {
height: 100%;
border-radius: 2px;
transition: width 1s ease;
}
}
.vuln-trend {
font-size: 10px;
font-weight: 600;
&.up { color: #ef4444; }
&.down { color: #10b981; }
&.stable { color: #6b7280; }
}
}
}
/* 威胁情报排行 */
.intel-ranking {
.rank-item {
display: flex;
align-items: center;
margin-bottom: 10px;
padding: 8px;
border-radius: 6px;
transition: background-color 0.2s;
&:hover {
background: rgba(59, 130, 246, 0.05);
}
.rank-badge {
width: 20px;
height: 20px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: 10px;
font-weight: 700;
color: white;
margin-right: 12px;
&.rank-1 { background: #ef4444; }
&.rank-2 { background: #f97316; }
&.rank-3 { background: #eab308; }
&.rank-4, &.rank-5 { background: #6b7280; }
}
.rank-info {
flex: 1;
.rank-country {
font-size: 12px;
font-weight: 600;
color: #1f2937;
margin-bottom: 2px;
}
.rank-threats {
font-size: 10px;
color: #6b7280;
}
}
.rank-indicator {
width: 8px;
height: 8px;
border-radius: 50%;
}
}
}
/* 响应式适配 */
@media (max-width: 768px) {
.info-panel {
width: 220px;
padding: 12px;
top: 15px;
}
.panel-left { left: 15px; }
.panel-right { right: 15px; }
}
</style>