态势感知平台-开源生态与贡献价值全景基础设施覆盖率组件抽离
This commit is contained in:
@@ -0,0 +1,330 @@
|
|||||||
|
<template>
|
||||||
|
<div class="index-module__NV_5cW__chartCard">
|
||||||
|
<h3 class="chartCard__title">基础设施覆盖率</h3>
|
||||||
|
<div class="chartCard__container">
|
||||||
|
<div class="num-empty" v-if="isEmpty"></div>
|
||||||
|
<div v-else id="infrastructureChart" class="chart"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { onMounted, ref, nextTick, watch, onUnmounted, computed } from 'vue';
|
||||||
|
import * as echarts from 'echarts';
|
||||||
|
import { usePageResize } from '@/utils/hooks/usePageResize';
|
||||||
|
|
||||||
|
// 不再接收外部数据,组件内部管理数据
|
||||||
|
const infrastructureData = ref([
|
||||||
|
{
|
||||||
|
name: '镜像站规模',
|
||||||
|
value: 85,
|
||||||
|
color: '#00F0FF',
|
||||||
|
radius: ['70%', '80%']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '代码托管平台规模',
|
||||||
|
value: 90,
|
||||||
|
color: '#FFAB00',
|
||||||
|
radius: ['50%', '60%']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '构建平台活跃度',
|
||||||
|
value: 40,
|
||||||
|
color: '#B20003',
|
||||||
|
radius: ['30%', '40%']
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
|
||||||
|
// 未来用于API调用的方法
|
||||||
|
const fetchDataFromApi = async () => {
|
||||||
|
try {
|
||||||
|
// 这里是预留的API调用位置,例如:
|
||||||
|
// const response = await fetch('/api/infrastructure-data');
|
||||||
|
// const apiData = await response.json();
|
||||||
|
// infrastructureData.value = apiData;
|
||||||
|
|
||||||
|
// 暂时保留默认数据,实际使用时替换为API返回的数据
|
||||||
|
console.log('Fetching infrastructure data from API...');
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to fetch infrastructure data:', error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 组件挂载时获取数据
|
||||||
|
onMounted(() => {
|
||||||
|
fetchDataFromApi();
|
||||||
|
});
|
||||||
|
|
||||||
|
// 页面尺寸响应式
|
||||||
|
const { widthType } = usePageResize();
|
||||||
|
|
||||||
|
// 空数据标识
|
||||||
|
const isEmpty = computed(() => {
|
||||||
|
return infrastructureData.value.length === 0;
|
||||||
|
});
|
||||||
|
|
||||||
|
// 图表实例存储(用于resize时销毁重绘)
|
||||||
|
const chartInstances = ref<{ [key: string]: echarts.ECharts | null }>({
|
||||||
|
infrastructureChart: null
|
||||||
|
});
|
||||||
|
|
||||||
|
// 初始化基础设施覆盖率图表(多层环形图)
|
||||||
|
const initInfrastructureChart = () => {
|
||||||
|
const el = document.getElementById('infrastructureChart');
|
||||||
|
if (!el) return;
|
||||||
|
|
||||||
|
if (chartInstances.value.infrastructureChart) {
|
||||||
|
chartInstances.value.infrastructureChart.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
const myChart = echarts.init(el);
|
||||||
|
chartInstances.value.infrastructureChart = myChart;
|
||||||
|
|
||||||
|
const seriesData: any[] = [];
|
||||||
|
const center = ['50%', '50%'];
|
||||||
|
|
||||||
|
infrastructureData.value.forEach(item => {
|
||||||
|
const completeValue = item.value;
|
||||||
|
const remainingValue = 100 - item.value;
|
||||||
|
|
||||||
|
seriesData.push({
|
||||||
|
name: item.name,
|
||||||
|
type: 'pie',
|
||||||
|
radius: item.radius,
|
||||||
|
center: center,
|
||||||
|
avoidLabelOverlap: false,
|
||||||
|
startAngle: 90,
|
||||||
|
hoverAnimation: true,
|
||||||
|
label: {
|
||||||
|
show: false
|
||||||
|
},
|
||||||
|
labelLine: {
|
||||||
|
show: false
|
||||||
|
},
|
||||||
|
emphasis: {
|
||||||
|
scale: true,
|
||||||
|
scaleSize: 5
|
||||||
|
},
|
||||||
|
data: [
|
||||||
|
{
|
||||||
|
value: completeValue,
|
||||||
|
name: item.name,
|
||||||
|
itemStyle: {
|
||||||
|
color: new echarts.graphic.LinearGradient(
|
||||||
|
0, 0, 0, 1,
|
||||||
|
[
|
||||||
|
{ offset: 0, color: item.color },
|
||||||
|
{ offset: 1, color: item.color + '80' }
|
||||||
|
]
|
||||||
|
),
|
||||||
|
shadowBlur: 10,
|
||||||
|
shadowColor: item.color + '40'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: remainingValue,
|
||||||
|
name: '未覆盖',
|
||||||
|
itemStyle: {
|
||||||
|
color: 'rgba(255, 255, 255, 0.08)'
|
||||||
|
},
|
||||||
|
tooltip: {
|
||||||
|
show: false
|
||||||
|
},
|
||||||
|
emphasis: {
|
||||||
|
disabled: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// 计算平均覆盖率
|
||||||
|
const avgCoverage = Math.round(
|
||||||
|
infrastructureData.value.reduce((sum, d) => sum + d.value, 0) /
|
||||||
|
infrastructureData.value.length
|
||||||
|
);
|
||||||
|
|
||||||
|
myChart.setOption({
|
||||||
|
tooltip: {
|
||||||
|
trigger: 'item',
|
||||||
|
backgroundColor: 'rgba(255, 255, 255, 0.95)',
|
||||||
|
borderColor: '#3b82f6',
|
||||||
|
borderWidth: 1,
|
||||||
|
borderRadius: 6,
|
||||||
|
padding: 12,
|
||||||
|
textStyle: { color: '#333', fontSize: 13 },
|
||||||
|
formatter: (params: any) => {
|
||||||
|
if (params.name === '未覆盖') return '';
|
||||||
|
const remaining = 100 - params.value;
|
||||||
|
return `
|
||||||
|
<div style="line-height: 2;">
|
||||||
|
<div style="font-weight: bold; color: #3b82f6; margin-bottom: 6px; border-bottom: 2px solid #3b82f6; padding-bottom: 4px;">${params.name}</div>
|
||||||
|
<div style="display: flex; align-items: center; gap: 8px;">
|
||||||
|
<span style="display: inline-block; width: 8px; height: 8px; background: #10b981; border-radius: 50%;"></span>
|
||||||
|
已覆盖:<span style="color: #10b981; font-weight: 700; font-size: 15px;">${params.value}%</span>
|
||||||
|
</div>
|
||||||
|
<div style="display: flex; align-items: center; gap: 8px;">
|
||||||
|
<span style="display: inline-block; width: 8px; height: 8px; background: #ef4444; border-radius: 50%;"></span>
|
||||||
|
未覆盖:<span style="color: #ef4444; font-weight: 700; font-size: 15px;">${remaining}%</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
legend: {
|
||||||
|
data: infrastructureData.value.map(d => d.name),
|
||||||
|
orient: 'vertical',
|
||||||
|
right: '5%',
|
||||||
|
top: 'center',
|
||||||
|
itemWidth: 12, // 图例方块宽度
|
||||||
|
itemHeight: 12, // 图例方块高度
|
||||||
|
itemGap: 15, // 图例项之间的间距
|
||||||
|
icon: 'circle', // 图例形状:'circle'圆形, 'rect'方形, 'roundRect'圆角方形
|
||||||
|
textStyle: {
|
||||||
|
color: '#333',
|
||||||
|
fontSize: 12,
|
||||||
|
padding: [0, 0, 0, 8] // 文字与图标的间距
|
||||||
|
}
|
||||||
|
},
|
||||||
|
graphic: [
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
left: 'center',
|
||||||
|
top: '45%',
|
||||||
|
style: {
|
||||||
|
text: '总覆盖度',
|
||||||
|
fill: '#666',
|
||||||
|
fontSize: 13,
|
||||||
|
fontWeight: '500'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
left: 'center',
|
||||||
|
top: '52%',
|
||||||
|
style: {
|
||||||
|
text: `${avgCoverage}%`,
|
||||||
|
fill: '#3b82f6',
|
||||||
|
fontSize: 28,
|
||||||
|
fontWeight: 'bold'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
series: seriesData,
|
||||||
|
animationDuration: 1000,
|
||||||
|
animationEasing: 'cubicOut',
|
||||||
|
animationDelay: (idx: number) => idx * 100
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// 监听数据变化,重新渲染图表
|
||||||
|
watch(infrastructureData, () => {
|
||||||
|
if (!isEmpty.value) {
|
||||||
|
nextTick(() => {
|
||||||
|
initInfrastructureChart();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, { deep: true });
|
||||||
|
|
||||||
|
// 页面resize时重绘图表
|
||||||
|
watch(widthType, () => {
|
||||||
|
nextTick(() => {
|
||||||
|
if (!isEmpty.value) {
|
||||||
|
initInfrastructureChart();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// 挂载时初始化
|
||||||
|
onMounted(() => {
|
||||||
|
setTimeout(() => {
|
||||||
|
if (!isEmpty.value) {
|
||||||
|
initInfrastructureChart();
|
||||||
|
}
|
||||||
|
}, 100);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 组件卸载时销毁图表实例
|
||||||
|
onUnmounted(() => {
|
||||||
|
if (chartInstances.value.infrastructureChart) {
|
||||||
|
chartInstances.value.infrastructureChart.dispose();
|
||||||
|
chartInstances.value.infrastructureChart = null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
/* 基础设施覆盖率图表卡片样式 - 从主页面复制 */
|
||||||
|
.index-module__NV_5cW__chartCard {
|
||||||
|
-webkit-backdrop-filter: blur(10px);
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
|
background: #ffffffe6;
|
||||||
|
border: 1px solid #ffffff4d;
|
||||||
|
border-radius: 1rem;
|
||||||
|
padding: 1.25rem;
|
||||||
|
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.index-module__NV_5cW__chartCard::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: -100%;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background: linear-gradient(90deg, transparent, rgba(59, 130, 246, 0.05), transparent);
|
||||||
|
transition: left 0.6s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.index-module__NV_5cW__chartCard:hover::before {
|
||||||
|
left: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.index-module__NV_5cW__chartCard:hover {
|
||||||
|
border-color: #3b82f64d;
|
||||||
|
transform: translateY(-4px);
|
||||||
|
box-shadow: 0 8px 24px #0000001f;
|
||||||
|
}
|
||||||
|
|
||||||
|
.index-module__NV_5cW__chartCard:hover .chartCard__title {
|
||||||
|
color: #3b82f6;
|
||||||
|
transform: scale(1.02);
|
||||||
|
transition: all 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 标题样式 - 从主页面复制 */
|
||||||
|
.chartCard__title {
|
||||||
|
color: #333;
|
||||||
|
font-size: 1.1rem;
|
||||||
|
font-weight: 600;
|
||||||
|
margin: 0;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 容器样式 - 从主页面复制 */
|
||||||
|
.chartCard__container {
|
||||||
|
width: 100%;
|
||||||
|
height: 390px;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 空数据显示样式 - 从主页面复制 */
|
||||||
|
.num-empty {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 图表容器样式 */
|
||||||
|
.chart {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -131,13 +131,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 2. 基础设施覆盖率(多层环形图)-->
|
<!-- 2. 基础设施覆盖率(多层环形图)-->
|
||||||
<div class="index-module__NV_5cW__chartCard">
|
<InfrastructureCoverageChart />
|
||||||
<h3 class="chartCard__title">基础设施覆盖率</h3>
|
|
||||||
<div class="chartCard__container">
|
|
||||||
<div class="num-empty" v-if="isEmpty.infrastructure"></div>
|
|
||||||
<div v-else id="infrastructureChart" class="chart"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 3. 高校开源社团/俱乐部数量-->
|
<!-- 3. 高校开源社团/俱乐部数量-->
|
||||||
<div class="index-module__NV_5cW__chartCard">
|
<div class="index-module__NV_5cW__chartCard">
|
||||||
@@ -291,6 +285,7 @@
|
|||||||
import { onMounted, ref, nextTick, watch, onUnmounted, computed } from 'vue';
|
import { onMounted, ref, nextTick, watch, onUnmounted, computed } from 'vue';
|
||||||
import * as echarts from 'echarts';
|
import * as echarts from 'echarts';
|
||||||
import TalentMapChart from './TalentMapChart.vue'
|
import TalentMapChart from './TalentMapChart.vue'
|
||||||
|
import InfrastructureCoverageChart from './components/InfrastructureCoverageChart.vue'
|
||||||
import { usePageResize } from '@/utils/hooks/usePageResize';
|
import { usePageResize } from '@/utils/hooks/usePageResize';
|
||||||
|
|
||||||
// 页面尺寸响应式
|
// 页面尺寸响应式
|
||||||
@@ -578,7 +573,6 @@ const communityData = computed(() => processUniversityClubsData());
|
|||||||
|
|
||||||
// 空数据标识
|
// 空数据标识
|
||||||
const isEmpty = ref({
|
const isEmpty = ref({
|
||||||
infrastructure: false,
|
|
||||||
community: false,
|
community: false,
|
||||||
communityHealth: false,
|
communityHealth: false,
|
||||||
languageTech: false
|
languageTech: false
|
||||||
@@ -648,7 +642,6 @@ const getTalentLevel = (density: number) => {
|
|||||||
|
|
||||||
// 图表实例存储(用于resize时销毁重绘)
|
// 图表实例存储(用于resize时销毁重绘)
|
||||||
const chartInstances = ref<{ [key: string]: echarts.ECharts | null }>({
|
const chartInstances = ref<{ [key: string]: echarts.ECharts | null }>({
|
||||||
infrastructureChart: null,
|
|
||||||
communityChart: null,
|
communityChart: null,
|
||||||
communityHealthChart: null,
|
communityHealthChart: null,
|
||||||
languageTechChart: null,
|
languageTechChart: null,
|
||||||
@@ -801,154 +794,7 @@ const formatDevs = (num: number) => {
|
|||||||
};
|
};
|
||||||
// ===================== 新增结束 =====================
|
// ===================== 新增结束 =====================
|
||||||
|
|
||||||
// 初始化基础设施覆盖率图表(多层环形图)
|
|
||||||
const initInfrastructureChart = () => {
|
|
||||||
const el = document.getElementById('infrastructureChart');
|
|
||||||
if (!el) return;
|
|
||||||
|
|
||||||
if (chartInstances.value.infrastructureChart) {
|
|
||||||
chartInstances.value.infrastructureChart.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
const myChart = echarts.init(el);
|
|
||||||
chartInstances.value.infrastructureChart = myChart;
|
|
||||||
|
|
||||||
const seriesData: any[] = [];
|
|
||||||
const center = ['50%', '50%'];
|
|
||||||
|
|
||||||
chartData.value.infrastructure.forEach(item => {
|
|
||||||
const completeValue = item.value;
|
|
||||||
const remainingValue = 100 - item.value;
|
|
||||||
|
|
||||||
seriesData.push({
|
|
||||||
name: item.name,
|
|
||||||
type: 'pie',
|
|
||||||
radius: item.radius,
|
|
||||||
center: center,
|
|
||||||
avoidLabelOverlap: false,
|
|
||||||
startAngle: 90,
|
|
||||||
hoverAnimation: true,
|
|
||||||
label: {
|
|
||||||
show: false
|
|
||||||
},
|
|
||||||
labelLine: {
|
|
||||||
show: false
|
|
||||||
},
|
|
||||||
emphasis: {
|
|
||||||
scale: true,
|
|
||||||
scaleSize: 5
|
|
||||||
},
|
|
||||||
data: [
|
|
||||||
{
|
|
||||||
value: completeValue,
|
|
||||||
name: item.name,
|
|
||||||
itemStyle: {
|
|
||||||
color: new echarts.graphic.LinearGradient(
|
|
||||||
0, 0, 0, 1,
|
|
||||||
[
|
|
||||||
{ offset: 0, color: item.color },
|
|
||||||
{ offset: 1, color: item.color + '80' }
|
|
||||||
]
|
|
||||||
),
|
|
||||||
shadowBlur: 10,
|
|
||||||
shadowColor: item.color + '40'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: remainingValue,
|
|
||||||
name: '未覆盖',
|
|
||||||
itemStyle: {
|
|
||||||
color: 'rgba(255, 255, 255, 0.08)'
|
|
||||||
},
|
|
||||||
tooltip: {
|
|
||||||
show: false
|
|
||||||
},
|
|
||||||
emphasis: {
|
|
||||||
disabled: true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// 计算平均覆盖率
|
|
||||||
const avgCoverage = Math.round(
|
|
||||||
chartData.value.infrastructure.reduce((sum, d) => sum + d.value, 0) /
|
|
||||||
chartData.value.infrastructure.length
|
|
||||||
);
|
|
||||||
|
|
||||||
myChart.setOption({
|
|
||||||
tooltip: {
|
|
||||||
trigger: 'item',
|
|
||||||
backgroundColor: 'rgba(255, 255, 255, 0.95)',
|
|
||||||
borderColor: '#3b82f6',
|
|
||||||
borderWidth: 1,
|
|
||||||
borderRadius: 6,
|
|
||||||
padding: 12,
|
|
||||||
textStyle: { color: '#333', fontSize: 13 },
|
|
||||||
formatter: (params: any) => {
|
|
||||||
if (params.name === '未覆盖') return '';
|
|
||||||
const remaining = 100 - params.value;
|
|
||||||
return `
|
|
||||||
<div style="line-height: 2;">
|
|
||||||
<div style="font-weight: bold; color: #3b82f6; margin-bottom: 6px; border-bottom: 2px solid #3b82f6; padding-bottom: 4px;">${params.name}</div>
|
|
||||||
<div style="display: flex; align-items: center; gap: 8px;">
|
|
||||||
<span style="display: inline-block; width: 8px; height: 8px; background: #10b981; border-radius: 50%;"></span>
|
|
||||||
已覆盖:<span style="color: #10b981; font-weight: 700; font-size: 15px;">${params.value}%</span>
|
|
||||||
</div>
|
|
||||||
<div style="display: flex; align-items: center; gap: 8px;">
|
|
||||||
<span style="display: inline-block; width: 8px; height: 8px; background: #ef4444; border-radius: 50%;"></span>
|
|
||||||
未覆盖:<span style="color: #ef4444; font-weight: 700; font-size: 15px;">${remaining}%</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
legend: {
|
|
||||||
data: chartData.value.infrastructure.map(d => d.name),
|
|
||||||
orient: 'vertical',
|
|
||||||
right: '5%',
|
|
||||||
top: 'center',
|
|
||||||
itemWidth: 12, // 图例方块宽度
|
|
||||||
itemHeight: 12, // 图例方块高度
|
|
||||||
itemGap: 15, // 图例项之间的间距
|
|
||||||
icon: 'circle', // 图例形状:'circle'圆形, 'rect'方形, 'roundRect'圆角方形
|
|
||||||
textStyle: {
|
|
||||||
color: '#333',
|
|
||||||
fontSize: 12,
|
|
||||||
padding: [0, 0, 0, 8] // 文字与图标的间距
|
|
||||||
}
|
|
||||||
},
|
|
||||||
graphic: [
|
|
||||||
{
|
|
||||||
type: 'text',
|
|
||||||
left: 'center',
|
|
||||||
top: '45%',
|
|
||||||
style: {
|
|
||||||
text: '总覆盖度',
|
|
||||||
fill: '#666',
|
|
||||||
fontSize: 13,
|
|
||||||
fontWeight: '500'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'text',
|
|
||||||
left: 'center',
|
|
||||||
top: '52%',
|
|
||||||
style: {
|
|
||||||
text: `${avgCoverage}%`,
|
|
||||||
fill: '#3b82f6',
|
|
||||||
fontSize: 28,
|
|
||||||
fontWeight: 'bold'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
series: seriesData,
|
|
||||||
animationDuration: 1000,
|
|
||||||
animationEasing: 'cubicOut',
|
|
||||||
animationDelay: (idx: number) => idx * 100
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// 初始化高校开源社团/俱乐部数量图表(纵向柱状图)
|
// 初始化高校开源社团/俱乐部数量图表(纵向柱状图)
|
||||||
const initCommunityChart = () => {
|
const initCommunityChart = () => {
|
||||||
@@ -2082,14 +1928,12 @@ const initHeatmapChart = () => {
|
|||||||
const initCharts = () => {
|
const initCharts = () => {
|
||||||
// 空数据判断
|
// 空数据判断
|
||||||
isEmpty.value = {
|
isEmpty.value = {
|
||||||
infrastructure: chartData.value.infrastructure.length === 0,
|
|
||||||
community: chartData.value.universityClubs.length === 0,
|
community: chartData.value.universityClubs.length === 0,
|
||||||
communityHealth: chartData.value.communityHealth.github.every(item => item === 0),
|
communityHealth: chartData.value.communityHealth.github.every(item => item === 0),
|
||||||
languageTech: chartData.value.languageTech.mainstream.length === 0 && chartData.value.languageTech.emerging.length === 0
|
languageTech: chartData.value.languageTech.mainstream.length === 0 && chartData.value.languageTech.emerging.length === 0
|
||||||
};
|
};
|
||||||
|
|
||||||
// 初始化各图表
|
// 初始化各图表
|
||||||
if (!isEmpty.value.infrastructure) nextTick(() => initInfrastructureChart());
|
|
||||||
if (!isEmpty.value.community) nextTick(() => initCommunityChart());
|
if (!isEmpty.value.community) nextTick(() => initCommunityChart());
|
||||||
if (!isEmpty.value.communityHealth) nextTick(() => initCommunityHealthChart());
|
if (!isEmpty.value.communityHealth) nextTick(() => initCommunityHealthChart());
|
||||||
if (!isEmpty.value.languageTech) nextTick(() => initLanguageTechChart());
|
if (!isEmpty.value.languageTech) nextTick(() => initLanguageTechChart());
|
||||||
|
|||||||
@@ -94,8 +94,6 @@ const excellentProjects = ref([
|
|||||||
{ name: 'NextDenovo', desc: '高效且精确的长读长纠错与组装工具', org: '武汉希望组生物科技有限公司' }
|
{ name: 'NextDenovo', desc: '高效且精确的长读长纠错与组装工具', org: '武汉希望组生物科技有限公司' }
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// 2. 2025武汉市优秀开源软件项目
|
// 2. 2025武汉市优秀开源软件项目
|
||||||
const excellentProjects2025 = ref([
|
const excellentProjects2025 = ref([
|
||||||
{ name: '调问(DWSurvey)', desc: '问卷表单', org: '极推科技(武汉)有限公司' },
|
{ name: '调问(DWSurvey)', desc: '问卷表单', org: '极推科技(武汉)有限公司' },
|
||||||
@@ -170,10 +168,8 @@ const chartData = ref({
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
// 空数据标识
|
// 空数据标识
|
||||||
const isEmpty = ref({
|
const isEmpty = ref({
|
||||||
university: false,
|
university: false,
|
||||||
@@ -193,10 +189,6 @@ const chartInstances = ref<{ [key: string]: echarts.ECharts | null }>({
|
|||||||
cweAttackSurfaceRadar: null
|
cweAttackSurfaceRadar: null
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// ===================== 新增结束 =====================
|
// ===================== 新增结束 =====================
|
||||||
|
|
||||||
// 初始化高校参与分布饼图
|
// 初始化高校参与分布饼图
|
||||||
@@ -404,12 +396,6 @@ const initDeveloperChart = () => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// 初始化武汉市语言与技术竞争趋势(折线图)
|
// 初始化武汉市语言与技术竞争趋势(折线图)
|
||||||
const initLanguageTechChart = () => {
|
const initLanguageTechChart = () => {
|
||||||
const el = document.getElementById('languageTechChart');
|
const el = document.getElementById('languageTechChart');
|
||||||
@@ -480,8 +466,6 @@ const initCharts = () => {
|
|||||||
ossCompass: chartData.value.ossCompass.data.every(item => item === 0),
|
ossCompass: chartData.value.ossCompass.data.every(item => item === 0),
|
||||||
developer: chartData.value.developer.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)),
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// 初始化各图表
|
// 初始化各图表
|
||||||
@@ -490,7 +474,6 @@ const initCharts = () => {
|
|||||||
if (!isEmpty.value.ossCompass) nextTick(() => initOssCompassChart());
|
if (!isEmpty.value.ossCompass) nextTick(() => initOssCompassChart());
|
||||||
if (!isEmpty.value.developer) nextTick(() => initDeveloperChart());
|
if (!isEmpty.value.developer) nextTick(() => initDeveloperChart());
|
||||||
if (!isEmpty.value.languageTech) nextTick(() => initLanguageTechChart());
|
if (!isEmpty.value.languageTech) nextTick(() => initLanguageTechChart());
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// 页面resize时重绘图表
|
// 页面resize时重绘图表
|
||||||
|
|||||||
Reference in New Issue
Block a user