diff --git a/src/views/Jyh/ecosystem/components/UniversityClubStatsChart.vue b/src/views/Jyh/ecosystem/components/UniversityClubStatsChart.vue
new file mode 100644
index 0000000..8a30ffa
--- /dev/null
+++ b/src/views/Jyh/ecosystem/components/UniversityClubStatsChart.vue
@@ -0,0 +1,364 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/views/Jyh/ecosystem/index.vue b/src/views/Jyh/ecosystem/index.vue
index 76e546f..ff5232a 100644
--- a/src/views/Jyh/ecosystem/index.vue
+++ b/src/views/Jyh/ecosystem/index.vue
@@ -134,13 +134,7 @@
-
@@ -286,6 +280,7 @@ import { onMounted, ref, nextTick, watch, onUnmounted, computed } from 'vue';
import * as echarts from 'echarts';
import TalentMapChart from './TalentMapChart.vue'
import InfrastructureCoverageChart from './components/InfrastructureCoverageChart.vue'
+import UniversityClubStatsChart from './components/UniversityClubStatsChart.vue'
import { usePageResize } from '@/utils/hooks/usePageResize';
// 页面尺寸响应式
@@ -538,42 +533,12 @@ const chartData = ref({
}
});
-// 处理高校社团数据
-const processUniversityClubsData = () => {
- const counts: { [key: string]: { count: number; clubs: string[] } } = {};
- chartData.value.universityClubs.forEach(item => {
- if (!counts[item.university]) {
- counts[item.university] = { count: 0, clubs: [] };
- }
- counts[item.university].count++;
- counts[item.university].clubs.push(item.club);
- });
- // 转换为数组并排序
- const sorted = Object.entries(counts)
- .map(([name, data]) => ({
- name,
- value: data.count,
- clubs: data.clubs
- }))
- .sort((a, b) => b.value - a.value);
- return {
- universities: sorted.slice(0, 10).map(item => item.name), // 取前10名,避免X轴过挤
- values: sorted.slice(0, 10).map(item => item.value),
- details: sorted.slice(0, 10).reduce((acc, item) => {
- acc[item.name] = item.clubs;
- return acc;
- }, {} as { [key: string]: string[] })
- };
-};
-
-const communityData = computed(() => processUniversityClubsData());
// 空数据标识
const isEmpty = ref({
- community: false,
communityHealth: false,
languageTech: false
});
@@ -642,7 +607,6 @@ const getTalentLevel = (density: number) => {
// 图表实例存储(用于resize时销毁重绘)
const chartInstances = ref<{ [key: string]: echarts.ECharts | null }>({
- communityChart: null,
communityHealthChart: null,
languageTechChart: null,
vitalityChart: null,
@@ -796,131 +760,7 @@ const formatDevs = (num: number) => {
-// 初始化高校开源社团/俱乐部数量图表(纵向柱状图)
-const initCommunityChart = () => {
- const el = document.getElementById('communityChart');
- if (!el) return;
- if (chartInstances.value.communityChart) {
- chartInstances.value.communityChart.dispose();
- }
-
- const myChart = echarts.init(el);
- chartInstances.value.communityChart = myChart;
-
- const data = communityData.value;
-
- myChart.setOption({
- tooltip: {
- trigger: 'axis',
- axisPointer: { type: 'shadow' },
- backgroundColor: 'rgba(255, 255, 255, 0.95)',
- borderColor: '#3b82f6',
- borderWidth: 1,
- borderRadius: 6,
- padding: 12,
- textStyle: { color: '#333', fontSize: 13 },
- formatter: (params: any) => {
- const name = params[0].name;
- const value = params[0].value;
- const clubs = data.details[name] || [];
-
- const clubsHtml = clubs.map(c => `• ${c}`).join('
');
-
- return `
-
-
${name}
-
社团数量: ${value} 个
-
- ${clubsHtml}
-
-
- `;
- }
- },
- grid: {
- left: '10%',
- right: '10%',
- bottom: '5%',
- top: '20%',
- containLabel: true
- },
- xAxis: {
- type: 'category',
- data: data.universities,
- axisLabel: {
- fontSize: 10,
- rotate: 45,
- interval: 0,
- color: '#666',
- margin: 15
- },
- axisTick: {
- alignWithLabel: true,
- length: 5
- },
- axisLine: {
- lineStyle: { color: '#e5e7eb', width: 2 }
- }
- },
- yAxis: {
- type: 'value',
- name: '社团数量',
- nameTextStyle: { fontSize: 12, color: '#666' },
- axisLabel: { fontSize: 12, color: '#666' },
- minInterval: 1,
- splitLine: {
- lineStyle: { color: 'rgba(0, 0, 0, 0.06)', type: 'dashed' }
- }
- },
- series: [
- {
- name: '社团数量',
- type: 'bar',
- data: data.values,
- barWidth: '60%',
- barCategoryGap: '30%',
- itemStyle: {
- color: (params: any) => {
- // 根据排名使用不同颜色
- const colors = [
- ['#3b82f6', '#60a5fa'], // 蓝色
- ['#8b5cf6', '#a78bfa'], // 紫色
- ['#ec4899', '#f472b6'], // 粉色
- ['#10b981', '#34d399'], // 绿色
- ['#f59e0b', '#fbbf24'] // 橙色
- ];
- const colorPair = colors[params.dataIndex % colors.length];
- return new echarts.graphic.LinearGradient(0, 1, 0, 0, [
- { offset: 0, color: colorPair[1] },
- { offset: 1, color: colorPair[0] }
- ]);
- },
- borderRadius: [4, 4, 0, 0],
- shadowBlur: 8,
- shadowColor: 'rgba(59, 130, 246, 0.3)'
- },
- label: {
- show: true,
- position: 'top',
- formatter: '{c}',
- fontSize: 11,
- color: '#3b82f6',
- fontWeight: 'bold'
- },
- emphasis: {
- itemStyle: {
- shadowBlur: 15,
- shadowColor: 'rgba(59, 130, 246, 0.6)'
- }
- }
- }
- ],
- animationDuration: 1000,
- animationEasing: 'cubicOut',
- animationDelay: (idx: number) => idx * 50
- });
-};
// 初始化社区治理健康度对比(纵向柱状图)
const initCommunityHealthChart = () => {
@@ -1928,13 +1768,11 @@ const initHeatmapChart = () => {
const initCharts = () => {
// 空数据判断
isEmpty.value = {
- community: chartData.value.universityClubs.length === 0,
communityHealth: chartData.value.communityHealth.github.every(item => item === 0),
languageTech: chartData.value.languageTech.mainstream.length === 0 && chartData.value.languageTech.emerging.length === 0
};
// 初始化各图表
- if (!isEmpty.value.community) nextTick(() => initCommunityChart());
if (!isEmpty.value.communityHealth) nextTick(() => initCommunityHealthChart());
if (!isEmpty.value.languageTech) nextTick(() => initLanguageTechChart());
nextTick(() => initVitalityChart());