diff --git a/src/views/Jyh/security/index.vue b/src/views/Jyh/security/index.vue
index 0edc961..494b93c 100644
--- a/src/views/Jyh/security/index.vue
+++ b/src/views/Jyh/security/index.vue
@@ -160,13 +160,40 @@
-
+
+
+
@@ -374,9 +401,25 @@ const chartData = ref({
industryColorPalette: [
'#00f0ff', '#00b03e', '#ffeb00', '#ffab00',
'#ff5100', '#c0232a', '#a262f2', '#379bff'
- ]
+ ],
+ // CVE图表数据
+ cveData: {
+ // 全球CVE:2024年实际数据(基于Excel数据)
+ global: {
+ cveCount: [98402, 418, 7025, 3711, 5115, 3228, 3044, 2957, 2592, 1455, 4826, 4661],
+ acceleration: [0, -99.58, 1580.62, -47.17, 37.83, -36.89, -5.70, -2.86, -12.34, -43.87, 231.68, -3.42] // 环比增长率(%)
+ },
+ // 中国区域CVE:2024年数据(约占全球30%)
+ regional: {
+ 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] // 环比增长率(%)
+ }
+ }
});
+// 视图切换状态变量(global: 全球, regional: 区域)
+const cveView = ref('global');
+
// 空数据标识
const isEmpty = ref({
university: false,
@@ -385,7 +428,8 @@ const isEmpty = ref({
developer: false,
languageTech: false,
highRiskComponent: false,
- industryDistribution: false
+ industryDistribution: false,
+ cveData: false
});
// 图表实例存储(用于resize时销毁重绘)
@@ -396,7 +440,8 @@ const chartInstances = ref<{ [key: string]: echarts.ECharts | null }>({
developerChart: null,
languageTechChart: null,
highRiskComponentRank: null,
- cweAttackSurfaceRadar: null
+ cweAttackSurfaceRadar: null,
+ CVEChart: null
});
// ===================== 新增:列表自动滚动逻辑 =====================
@@ -475,6 +520,145 @@ onUnmounted(() => {
}
});
});
+
+// CVE视图切换方法
+const switchCveView = (view: 'global' | 'regional') => {
+ cveView.value = view;
+ nextTick(() => {
+ initCVEChart();
+ });
+};
+
+// 初始化CVE图表(柱状图+折线图)
+const initCVEChart = () => {
+ const el = document.getElementById('CVEChart');
+ if (!el) return;
+
+ if (chartInstances.value.CVEChart) {
+ chartInstances.value.CVEChart.dispose();
+ }
+
+ const myChart = echarts.init(el);
+ chartInstances.value.CVEChart = myChart;
+
+ // 获取当前视图的数据
+ const currentData = chartData.value.cveData[cveView.value === 'global' ? 'global' : 'regional'];
+ const cveCount = currentData.cveCount;
+ const acceleration = currentData.acceleration;
+
+ // 月份数据
+ const months = ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'];
+
+ myChart.setOption({
+ tooltip: {
+ trigger: 'axis',
+ axisPointer: {
+ type: 'cross',
+ crossStyle: {
+ color: '#999'
+ }
+ },
+ formatter: (params: any) => {
+ let res = `${params[0].name}
`;
+ params.forEach((p: any) => {
+ if (p.seriesName === 'CVE数量') {
+ res += `${p.marker}${p.seriesName}: ${p.value}
`;
+ } else {
+ res += `${p.marker}${p.seriesName}: ${p.value}%
`;
+ }
+ });
+ return res;
+ }
+ },
+ legend: {
+ top: 0,
+ textStyle: { fontSize: 12 },
+ data: ['CVE数量', '环比增长率']
+ },
+ grid: { left: '3%', right: '4%', bottom: '3%', top: '15%', containLabel: true },
+ xAxis: [
+ {
+ type: 'category',
+ data: months,
+ axisPointer: {
+ type: 'shadow'
+ },
+ axisLabel: { fontSize: 12 }
+ }
+ ],
+ yAxis: [
+ {
+ type: 'value',
+ name: 'CVE数量',
+ nameTextStyle: { fontSize: 12, color: '#333' },
+ axisLabel: { fontSize: 12, color: '#666' },
+ position: 'left',
+ splitLine: {
+ show: true,
+ lineStyle: {
+ type: 'dashed'
+ }
+ }
+ },
+ {
+ type: 'value',
+ name: '环比增长率(%)',
+ nameTextStyle: { fontSize: 12, color: '#333' },
+ axisLabel: { fontSize: 12, color: '#666' },
+ position: 'right',
+ splitLine: {
+ show: false
+ }
+ }
+ ],
+ series: [
+ {
+ name: 'CVE数量',
+ type: 'bar',
+ data: cveCount,
+ itemStyle: {
+ color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
+ { offset: 0, color: '#3b82f6' },
+ { offset: 1, color: '#60a5fa' }
+ ])
+ },
+ barWidth: 20,
+ label: {
+ show: true,
+ position: 'top',
+ formatter: '{c}',
+ fontSize: 10,
+ color: '#333'
+ }
+ },
+ {
+ name: '环比增长率',
+ type: 'line',
+ yAxisIndex: 1,
+ data: acceleration,
+ itemStyle: {
+ color: '#ef4444',
+ borderWidth: 2
+ },
+ lineStyle: {
+ width: 2,
+ color: '#ef4444'
+ },
+ symbol: 'circle',
+ symbolSize: 6,
+ smooth: true,
+ label: {
+ show: true,
+ position: 'top',
+ formatter: (params: any) => `${params.value}%`,
+ fontSize: 10,
+ color: '#333'
+ }
+ }
+ ]
+ });
+};
+
// ===================== 新增结束 =====================
// 初始化高校参与分布饼图
@@ -870,7 +1054,9 @@ const initCharts = () => {
developer: chartData.value.developer.data.every(item => item === 0),
languageTech: chartData.value.languageTech.series.every(s => s.data.every(d => d === 0)),
highRiskComponent: chartData.value.highRiskComponent.length === 0,
- industryDistribution: chartData.value.industryDistribution.length === 0
+ industryDistribution: chartData.value.industryDistribution.length === 0,
+ cveData: chartData.value.cveData.global.cveCount.every(item => item === 0) &&
+ chartData.value.cveData.regional.cveCount.every(item => item === 0)
};
// 初始化各图表
@@ -881,6 +1067,7 @@ const initCharts = () => {
if (!isEmpty.value.languageTech) nextTick(() => initLanguageTechChart());
if (!isEmpty.value.highRiskComponent) nextTick(() => initHighRiskComponentChart());
if (!isEmpty.value.industryDistribution) nextTick(() => initIndustryDistributionChart());
+ if (!isEmpty.value.cveData) nextTick(() => initCVEChart());
};
// 页面resize时重绘图表
@@ -1489,4 +1676,42 @@ onMounted(() => {
max-height: 300px;
}
}
+
+/* 图表卡片头部样式 */
+.chartCard__header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-bottom: 10px;
+}
+
+/* 图表操作按钮样式 */
+.chartCard__actions {
+ display: flex;
+ gap: 8px;
+}
+
+.chartCard__actionBtn {
+ padding: 4px 12px;
+ border: 1px solid #d1d5db;
+ background-color: #f9fafb;
+ border-radius: 4px;
+ font-size: 12px;
+ cursor: pointer;
+ transition: all 0.2s;
+}
+
+.chartCard__actionBtn:hover {
+ background-color: #f3f4f6;
+}
+
+.chartCard__actionBtn--active {
+ background-color: #3b82f6;
+ color: white;
+ border-color: #3b82f6;
+}
+
+.chartCard__actionBtn--active:hover {
+ background-color: #2563eb;
+}
\ No newline at end of file