diff --git a/src/views/Jyh/security/index.vue b/src/views/Jyh/security/index.vue index 396e44a..9fe76df 100644 --- a/src/views/Jyh/security/index.vue +++ b/src/views/Jyh/security/index.vue @@ -148,6 +148,15 @@
+ + +
+

编程语言安全态势

+
+
+
+
+
@@ -504,6 +513,37 @@ const chartData = ref({ cveCount: [29521, 125, 2108, 1113, 1535, 968, 913, 887, 778, 437, 1448, 1398], acceleration: [0, -99.58, 1580.62, -47.17, 37.83, -36.89, -5.70, -2.86, -12.34, -43.87, 231.68, -3.42] // 环比增长率(%) } + }, + + // 气泡图数据 + // 基于真实数据:[代码活跃度(X), 漏洞密度(Y), 漏洞总数(Size), 语言名称(Name)] + // 活跃度基于新增项目数量,漏洞密度基于CWE分布统计 + scatterData: [ + [95, 75, 450, 'JavaScript'], // 最高活跃度:9,345,046个项目 + [90, 70, 380, 'Python'], // 高活跃度:9,261,587个项目 + [85, 65, 320, 'TypeScript'], // 高增长:78.1%增长率 + [75, 80, 420, 'Java'], // 传统强势:3,520,215个项目 + [45, 60, 280, 'C++'], // 中等活跃:1,701,552个项目 + [40, 55, 250, 'C#'], // 中等活跃:1,478,463个项目 + [35, 45, 180, 'PHP'], // 传统Web语言 + [25, 25, 80, 'Go'], // 新兴语言,低漏洞密度 + [15, 20, 45, 'Rust'], // 安全性较好的新语言 + [60, 50, 200, 'Shell'], // 脚本语言 + ], + // 四象限分割点 + midX: 50, + midY: 50, + + // 四象限颜色定义 + quadrantColors: { + // [高密度, 低活跃度] - 极高风险 + Q1: '#BF232A', + // [高密度, 高活跃度] - 高风险,需密切关注 + Q2: '#FF4900', + // [低密度, 低活跃度] - 低风险,但维护成本高 + Q3: '#00B43E', + // [低密度, 高活跃度] - 健康生态 + Q4: '#0063D0' } }); @@ -1200,6 +1240,77 @@ const initVulnerabilitySeverityChart = () => { }); }; +// 初始化气泡图 +const initScatterChart = () => { + const el = document.getElementById('scatterChart'); + if (!el) return; + + if (chartInstances.value.scatterChart) { + chartInstances.value.scatterChart.dispose(); + } + + const myChart = echarts.init(el); + chartInstances.value.scatterChart = myChart; + + // 数据处理 + const data = chartData.value.scatterData.map(item => ({ + value: [item[0], item[1], item[2]], + name: item[3] + })); + + // 计算四象限颜色 + const getColor = (x: number, y: number) => { + if (x < chartData.value.midX && y >= chartData.value.midY) return chartData.value.quadrantColors.Q1; // 高密度, 低活跃度 - 极高风险 + if (x >= chartData.value.midX && y >= chartData.value.midY) return chartData.value.quadrantColors.Q2; // 高密度, 高活跃度 - 高风险 + if (x < chartData.value.midX && y < chartData.value.midY) return chartData.value.quadrantColors.Q3; // 低密度, 低活跃度 - 低风险 + return chartData.value.quadrantColors.Q4; // 低密度, 高活跃度 - 健康生态 + }; + + myChart.setOption({ + tooltip: { + trigger: 'item', + formatter: (params: any) => { + return ` +
${params.data.name}
+
代码活跃度: ${params.data.value[0]}
+
漏洞密度: ${params.data.value[1]}
+
漏洞总数: ${params.data.value[2]}
+ `; + } + }, + grid: { left: '3%', right: '4%', bottom: '3%', top: '15%', containLabel: true }, + xAxis: { + type: 'value', + name: '代码活跃度', + nameTextStyle: { fontSize: 12 }, + axisLabel: { fontSize: 12 }, + splitLine: { show: true } + }, + yAxis: { + type: 'value', + name: '漏洞密度', + nameTextStyle: { fontSize: 12 }, + axisLabel: { fontSize: 12 }, + splitLine: { show: true } + }, + series: [{ + type: 'scatter', + data: data, + symbolSize: (val: any) => val[2] / 2, // 根据漏洞总数调整气泡大小 + itemStyle: { + color: (params: any) => getColor(params.value[0], params.value[1]) + }, + label: { + show: true, + formatter: (params: any) => params.data.name, + position: 'inside', + fontSize: 10, + color: '#fff' + } + }] + }); +}; + // 初始化武汉市语言与技术竞争趋势(折线图) const initLanguageTechChart = () => { const el = document.getElementById('languageTechChart'); @@ -1275,7 +1386,8 @@ const initCharts = () => { cveData: chartData.value.cveData.global.cveCount.every(item => item === 0) && chartData.value.cveData.regional.cveCount.every(item => item === 0), languageTrend: chartData.value.languageTrend.series.every(s => s.data.every(d => d === 0)), - vulnerabilitySeverity: chartData.value.vulnerabilitySeverity.series.every(s => s.data.every(d => d === 0)) + vulnerabilitySeverity: chartData.value.vulnerabilitySeverity.series.every(s => s.data.every(d => d === 0)), + scatterData: chartData.value.scatterData.length === 0 }; // 初始化各图表 @@ -1289,6 +1401,7 @@ const initCharts = () => { if (!isEmpty.value.cveData) nextTick(() => initCVEChart()); if (!isEmpty.value.languageTrend) nextTick(() => initLanguageTrendChart()); if (!isEmpty.value.vulnerabilitySeverity) nextTick(() => initVulnerabilitySeverityChart()); + if (!isEmpty.value.scatterData) nextTick(() => initScatterChart()); }; // 页面resize时重绘图表