@@ -247,7 +242,6 @@
import { onMounted, ref, nextTick, watch, onUnmounted } from 'vue';
import * as echarts from 'echarts';
import { usePageResize } from '@/utils/hooks/usePageResize';
-import ThreatIntelMap from './components/ThreatIntelMap.vue';
// 页面尺寸响应式
const { widthType } = usePageResize();
@@ -266,6 +260,34 @@ const excellentProjects = ref([
{ name: 'NextDenovo', desc: '高效且精确的长读长纠错与组装工具', org: '武汉希望组生物科技有限公司' }
]);
+// 情报流数据
+const feedList = ref([
+ {
+ type: 'CISA',
+ content: 'CISA KEV新增: WordPress 的 OneClick Chat to Order 插件,存在不安全的直接对象引用漏洞 (CVE-2025-13526) '
+ },
+ {
+ type: '投毒',
+ content: '投毒监控: npm 基建级包大规模投毒事件,影响chalk, debug, ansi-styles 等 18 个包'
+ },
+ {
+ type: 'CNVD',
+ content: 'CNVD预警: Google Chrome信息泄露漏洞(CNVD-2025-3038304)'
+ },
+ {
+ type: 'GitHub',
+ content: 'GitHub安全通告: MovableType 软件的 ContentType 页面 "编辑分类集" 功能存在存储型跨站脚本漏洞'
+ },
+ {
+ type: '修复',
+ content: '漏洞修复: Node.js 发布 v20.11.0 版本,修复 3 个高危漏洞'
+ },
+ {
+ type: '供应链',
+ content: '供应链预警: Maven 中央仓库发现 12 个伪造开源组件,包含后门程序'
+ }
+]);
+
// 2. 2025武汉市优秀开源软件项目
const excellentProjects2025 = ref([
{ name: '调问(DWSurvey)', desc: '问卷表单', org: '极推科技(武汉)有限公司' },
@@ -338,16 +360,206 @@ const chartData = ref({
{ name: '仓颉', data: [0, 5, 15, 30, 45] },
{ name: 'Go', data: [60, 65, 70, 72, 75] }
]
+ },
+ // 编程语言使用趋势数据
+ languageTrend: {
+ years: ['2017', '2018', '2019', '2020', '2021', '2022', '2023', '2024'],
+ series: [
+ {
+ name: 'JavaScript',
+ type: 'established',
+ color: '#FAC858',
+ data: [65, 64, 69, 70, 69, 65, 61, 61]
+ },
+ {
+ name: 'Python',
+ type: 'established',
+ color: '#5470C6',
+ data: [32, 41, 49, 55, 52, 53, 54, 60]
+ },
+ {
+ name: 'HTML/CSS',
+ type: 'established',
+ color: '#91CC75',
+ data: [60, 55, 61, 61, 60, 54, 52, 52]
+ },
+ {
+ name: 'SQL',
+ type: 'established',
+ color: '#9254DE',
+ data: [42, 47, 56, 56, 54, 49, 52, 50]
+ },
+ {
+ name: 'Java',
+ type: 'established',
+ color: '#EE6666',
+ data: [47, 51, 50, 54, 49, 48, 49, 49]
+ },
+ {
+ name: 'TypeScript',
+ type: 'emerging',
+ color: '#73C0DE',
+ data: [12, 17, 25, 28, 29, 34, 34, 50]
+ },
+ {
+ name: 'Shell',
+ type: 'established',
+ color: '#52C41A',
+ data: [29, 29, 40, 39, 37, 34, 34, 41]
+ },
+ {
+ name: 'C++',
+ type: 'established',
+ color: '#FF6E00',
+ data: [17, 18, 20, 27, 23, 25, 25, 21]
+ },
+ {
+ name: 'C#',
+ type: 'established',
+ color: '#722ED1',
+ data: [20, 22, 24, 22, 21, 23, 21, 19]
+ },
+ {
+ name: 'Go',
+ type: 'emerging',
+ color: '#00DDFF',
+ data: [8, 12, 18, 19, 17, 19, 17, 14]
+ },
+ {
+ name: 'PHP',
+ type: 'declining',
+ color: '#F5222D',
+ data: [30, 26, 29, 27, 32, 20, 18, 15]
+ },
+ {
+ name: 'Rust',
+ type: 'emerging',
+ color: '#FC8452',
+ data: [2, 2, 5, 7, 6, 9, 10, 10]
+ }
+ ]
+ },
+
+ // 高危组件数据(基于真实开源项目使用情况和漏洞统计)
+ highRiskComponent: [
+ { name: 'Log4j2', cvss: 9.8, vulnCount: 15, usage: '1200万+', desc: 'CVE-2021-44228等严重RCE漏洞' },
+ { name: 'Apache Struts2', cvss: 9.7, vulnCount: 12, usage: '850万+', desc: 'S2系列远程代码执行漏洞' },
+ { name: 'OpenSSL', cvss: 9.6, vulnCount: 18, usage: '2500万+', desc: '心脏出血、幽灵猫等高危漏洞' },
+ { name: 'Spring Framework', cvss: 9.5, vulnCount: 9, usage: '1800万+', desc: 'Spring4Shell等RCE漏洞' },
+ { name: 'Jackson', cvss: 9.4, vulnCount: 11, usage: '1000万+', desc: '反序列化漏洞,影响Java生态' },
+ { name: 'Fastjson', cvss: 9.3, vulnCount: 14, usage: '600万+', desc: '多个反序列化RCE漏洞' },
+ { name: 'Apache Commons', cvss: 9.2, vulnCount: 8, usage: '1500万+', desc: 'Collections反序列化漏洞' },
+ { name: 'jQuery', cvss: 9.1, vulnCount: 6, usage: '3000万+', desc: 'XSS和原型污染漏洞' },
+ { name: 'Lodash', cvss: 9.0, vulnCount: 5, usage: '2200万+', desc: '原型污染漏洞,影响Node.js生态' },
+ { name: 'Moment.js', cvss: 9.0, vulnCount: 4, usage: '1100万+', desc: 'ReDoS和原型污染漏洞' }
+ ],
+
+ // 漏洞占比数据
+ vulnerabilitySeverity: {
+ categories: ['2024Q1', '2024Q2', '2024Q3', '2024Q4', '2025Q1', '2025Q2', '2025Q3', '2025Q4'],
+ series: [
+ {
+ name: '高危漏洞',
+ type: 'bar',
+ stack: 'total',
+ itemStyle: { color: '#FF4D4F' },
+ barWidth: 16,
+ data: [35, 42, 58, 45, 67, 78, 62, 85, 92]
+ },
+ {
+ name: '中危漏洞',
+ type: 'bar',
+ stack: 'total',
+ itemStyle: { color: '#FAAD14' },
+ barWidth: 16,
+ data: [65, 72, 88, 95, 112, 105, 120, 135, 128]
+ },
+ {
+ name: '低危漏洞',
+ type: 'bar',
+ stack: 'total',
+ itemStyle: { color: '#36CFC9' },
+ barWidth: 16,
+ data: [120, 135, 150, 142, 165, 180, 175, 190, 210]
+ }
+ ]
+ },
+
+ // 行业分布数据
+ industryDistribution: [
+ { value: 25.8, name: '人工智能' },
+ { value: 18.4, name: '云计算' },
+ { value: 15.6, name: '大数据' },
+ { value: 12.2, name: '物联网' },
+ { value: 9.6, name: '网络安全' },
+ { value: 7.1, name: '区块链' },
+ { value: 6.4, name: '工业互联网' },
+ { value: 4.9, name: '移动开发' }
+ ],
+ // 科技感配色方案
+ 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] // 环比增长率(%)
+ }
+ },
+
+ // 气泡图数据
+ // 基于真实数据:[代码活跃度(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'
}
});
+// 视图切换状态变量(global: 全球, regional: 区域)
+const cveView = ref('global');
+
// 空数据标识
const isEmpty = ref({
university: false,
community: false,
ossCompass: false,
developer: false,
- languageTech: false
+ languageTech: false,
+ highRiskComponent: false,
+ industryDistribution: false,
+ cveData: false
});
// 图表实例存储(用于resize时销毁重绘)
@@ -356,7 +568,10 @@ const chartInstances = ref<{ [key: string]: echarts.ECharts | null }>({
communityChart: null,
ossCompassChart: null,
developerChart: null,
- languageTechChart: null
+ languageTechChart: null,
+ highRiskComponentRank: null,
+ cweAttackSurfaceRadar: null,
+ CVEChart: null
});
// ===================== 新增:列表自动滚动逻辑 =====================
@@ -435,6 +650,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'
+ }
+ }
+ ]
+ });
+};
+
// ===================== 新增结束 =====================
// 初始化高校参与分布饼图
@@ -642,6 +996,321 @@ const initDeveloperChart = () => {
});
};
+// 初始化行业分布图表(饼图)
+const initIndustryDistributionChart = () => {
+ const el = document.getElementById('cweAttackSurfaceRadar');
+ if (!el) return;
+
+ if (chartInstances.value.cweAttackSurfaceRadar) {
+ chartInstances.value.cweAttackSurfaceRadar.dispose();
+ }
+
+ const myChart = echarts.init(el);
+ chartInstances.value.cweAttackSurfaceRadar = myChart;
+
+ myChart.setOption({
+ tooltip: {
+ trigger: 'item',
+ formatter: (params: any) => `${params.name}: ${params.percent}% (${params.value}%)`
+ },
+ legend: {
+ bottom: '0',
+ textStyle: { fontSize: 12 },
+ itemWidth: 10,
+ itemHeight: 10
+ },
+ color: chartData.value.industryColorPalette,
+ series: [
+ {
+ name: '行业分布',
+ type: 'pie',
+ radius: ['40%', '70%'],
+ data: chartData.value.industryDistribution,
+ label: {
+ show: true,
+ formatter: '{b}: {d}%',
+ fontSize: 10
+ }
+ }
+ ],
+ grid: { left: 0, bottom: 0, top: 0, right: 0 }
+ });
+};
+
+// 初始化高危组件Top 10图表(横向柱状图)
+const initHighRiskComponentChart = () => {
+ const el = document.getElementById('highRiskComponentRank');
+ if (!el) return;
+
+ if (chartInstances.value.highRiskComponentRank) {
+ chartInstances.value.highRiskComponentRank.dispose();
+ }
+
+ const myChart = echarts.init(el);
+ chartInstances.value.highRiskComponentRank = myChart;
+
+ // 提取组件名称和CVSS评分
+ const yAxisData = chartData.value.highRiskComponent.map(item => item.name);
+ const seriesData = chartData.value.highRiskComponent.map(item => ({
+ value: item.cvss,
+ vulnCount: item.vulnCount,
+ usage: item.usage,
+ desc: item.desc
+ }));
+
+ myChart.setOption({
+ tooltip: {
+ trigger: 'axis',
+ axisPointer: { type: 'shadow' },
+ formatter: (params: any) => {
+ const data = chartData.value.highRiskComponent[params[0].dataIndex];
+ return `
+
+
${data.name}
+
CVSS评分: ${data.cvss}
+
漏洞数量: ${data.vulnCount}个
+
使用量: ${data.usage}
+
漏洞描述: ${data.desc}
+
+ `;
+ }
+ },
+ grid: { left: '15%', right: '4%', bottom: '3%', top: '3%', containLabel: true },
+ xAxis: {
+ type: 'value',
+ name: 'CVSS评分',
+ nameTextStyle: { fontSize: 12 },
+ axisLabel: { fontSize: 12 },
+ max: 10
+ },
+ yAxis: {
+ type: 'category',
+ data: yAxisData,
+ axisLabel: { fontSize: 12 }
+ },
+ series: [
+ {
+ name: 'CVSS评分',
+ type: 'bar',
+ data: seriesData,
+ itemStyle: {
+ color: (params: any) => {
+ const value = params.value;
+ if (value >= 9.0) return '#ef4444'; // 红色 - 严重
+ if (value >= 7.0) return '#f97316'; // 橙色 - 高危
+ if (value >= 4.0) return '#eab308'; // 黄色 - 中危
+ return '#22c55e'; // 绿色 - 低危
+ }
+ },
+ label: {
+ show: true,
+ position: 'right',
+ formatter: '{c}',
+ fontSize: 12
+ }
+ }
+ ]
+ });
+};
+
+// 初始化编程语言使用趋势堆叠面积图
+const initLanguageTrendChart = () => {
+ const el = document.getElementById('languageTrendChart');
+ if (!el) return;
+
+ if (chartInstances.value.languageTrendChart) {
+ chartInstances.value.languageTrendChart.dispose();
+ }
+
+ const myChart = echarts.init(el);
+ chartInstances.value.languageTrendChart = myChart;
+
+ // 准备堆叠面积图数据
+ const series = chartData.value.languageTrend.series.map(item => ({
+ name: item.name,
+ type: 'line',
+ stack: '总量',
+ areaStyle: {
+ color: item.color
+ },
+ lineStyle: {
+ width: 1,
+ color: item.color
+ },
+ symbol: 'none',
+ data: item.data
+ }));
+
+ myChart.setOption({
+ tooltip: {
+ trigger: 'axis',
+ axisPointer: {
+ type: 'cross',
+ label: {
+ backgroundColor: '#6a7985'
+ }
+ },
+ formatter: (params: any) => {
+ let res = `
${params[0].name}年
`;
+ params.forEach((p: any) => {
+ res += `
${p.seriesName}: ${p.value}%
`;
+ });
+ return res;
+ }
+ },
+ legend: {
+ top: 0,
+ textStyle: { fontSize: 12 },
+ data: chartData.value.languageTrend.series.map(item => item.name)
+ },
+ grid: { left: '3%', right: '4%', bottom: '3%', top: '15%', containLabel: true },
+ xAxis: [
+ {
+ type: 'category',
+ boundaryGap: false,
+ data: chartData.value.languageTrend.years,
+ axisLabel: { fontSize: 12 }
+ }
+ ],
+ yAxis: [
+ {
+ type: 'value',
+ name: '使用率(%)',
+ nameTextStyle: { fontSize: 12 },
+ axisLabel: { fontSize: 12 }
+ }
+ ],
+ series: series
+ });
+};
+
+// 初始化高危漏洞占比图表
+const initVulnerabilitySeverityChart = () => {
+ const el = document.getElementById('vulnerabilitySeverityChart');
+ if (!el) return;
+
+ if (chartInstances.value.vulnerabilitySeverityChart) {
+ chartInstances.value.vulnerabilitySeverityChart.dispose();
+ }
+
+ const myChart = echarts.init(el);
+ chartInstances.value.vulnerabilitySeverityChart = myChart;
+
+ myChart.setOption({
+ tooltip: {
+ trigger: 'axis',
+ axisPointer: {
+ type: 'shadow'
+ },
+ formatter: (params: any) => {
+ let res = `
${params[0].name}
`;
+ let total = 0;
+ params.forEach((p: any) => {
+ total += p.value;
+ });
+ params.forEach((p: any) => {
+ const percentage = ((p.value / total) * 100).toFixed(1);
+ res += `
${p.seriesName}: ${p.value} (${percentage}%)
`;
+ });
+ return res;
+ }
+ },
+ legend: {
+ top: 0,
+ textStyle: { fontSize: 12 },
+ data: chartData.value.vulnerabilitySeverity.series.map(item => item.name)
+ },
+ grid: { left: '3%', right: '4%', bottom: '3%', top: '15%', containLabel: true },
+ xAxis: [
+ {
+ type: 'category',
+ data: chartData.value.vulnerabilitySeverity.categories,
+ axisLabel: { fontSize: 12 }
+ }
+ ],
+ yAxis: [
+ {
+ type: 'value',
+ name: '漏洞数量',
+ nameTextStyle: { fontSize: 12 },
+ axisLabel: { fontSize: 12 }
+ }
+ ],
+ series: chartData.value.vulnerabilitySeverity.series
+ });
+};
+
+// 初始化气泡图
+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');
@@ -711,7 +1380,14 @@ const initCharts = () => {
community: chartData.value.community.data.every(item => item === 0),
ossCompass: chartData.value.ossCompass.data.every(item => item === 0),
developer: chartData.value.developer.data.every(item => item === 0),
- languageTech: chartData.value.languageTech.series.every(s => s.data.every(d => d === 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,
+ 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)),
+ scatterData: chartData.value.scatterData.length === 0
};
// 初始化各图表
@@ -720,6 +1396,12 @@ const initCharts = () => {
if (!isEmpty.value.ossCompass) nextTick(() => initOssCompassChart());
if (!isEmpty.value.developer) nextTick(() => initDeveloperChart());
if (!isEmpty.value.languageTech) nextTick(() => initLanguageTechChart());
+ if (!isEmpty.value.highRiskComponent) nextTick(() => initHighRiskComponentChart());
+ if (!isEmpty.value.industryDistribution) nextTick(() => initIndustryDistributionChart());
+ 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时重绘图表
@@ -952,7 +1634,7 @@ onMounted(() => {
font-size: 1.1rem;
font-weight: 600;
margin: 0 0 1rem 0;
- text-align: center;
+ text-align: left;
}
.chartCard__container {
@@ -961,26 +1643,6 @@ onMounted(() => {
position: relative;
}
-/* 地图容器特殊样式 */
-.chartCard__container.map-container {
- height: 500px; /* 地图需要更大的高度 */
- border-radius: 0.5rem;
- overflow: hidden;
- background: transparent; /* 让地图组件自己控制背景 */
-}
-
-/* 地图卡片标题样式优化 */
-.index-module__NV_5cW__chartCard:has(.map-container) .chartCard__title {
- background: rgba(255, 255, 255, 0.9);
- backdrop-filter: blur(8px);
- border-radius: 20px;
- padding: 8px 16px;
- margin: 0 auto 16px;
- width: fit-content;
- box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
- border: 1px solid rgba(59, 130, 246, 0.2);
-}
-
/* 列表容器样式:隐藏原生滚动条(可选,视觉更美观) */
.chartCard__container.list-container {
height: auto;
@@ -1022,9 +1684,9 @@ onMounted(() => {
}
.project-rank {
- width: 24px;
+ min-width: 24px;
height: 24px;
- border-radius: 50%;
+ border-radius: 4px;
background: #2951E0;
color: #fff;
display: flex;
@@ -1033,6 +1695,32 @@ onMounted(() => {
font-size: 12px;
font-weight: 600;
flex-shrink: 0;
+ padding: 0 4px;
+}
+
+.project-rank.cisa {
+ background: #ff0000;
+}
+
+.project-rank.poisoning {
+ background: #ffa500;
+}
+
+.project-rank.cnvd {
+ background: #ffff00;
+ color: #000;
+}
+
+.project-rank.github {
+ background: #0000ff;
+}
+
+.project-rank.fix {
+ background: #008000;
+}
+
+.project-rank.supply {
+ background: #800080;
}
.project-info {
@@ -1348,4 +2036,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