diff --git a/src/views/Jyh/Community/components/HarmonyEcoCharts.vue b/src/views/Jyh/Community/components/HarmonyEcoCharts.vue new file mode 100644 index 0000000..b9a06e9 --- /dev/null +++ b/src/views/Jyh/Community/components/HarmonyEcoCharts.vue @@ -0,0 +1,1288 @@ + + + + + HarmonyOS 鸿蒙生态数据可视化 + + + + + + + + 鸿蒙项目城市分布 + 鸿蒙优秀开源项目 + + + + + + + + + + + {{ (index % hmProjects.length) + 1 }} + + + {{ item.name }} + {{ item.desc }} + + + ★ {{ item.stars }} + + + + + + + + + + + + + 鸿蒙开发者城市分布 + 鸿蒙明星开发者贡献榜 + + + + + + + + + + + {{ item.name.charAt(0).toUpperCase() }} + + + + + {{ item.name }} + {{ item.employer }} + + + ++{{ item.added }} + / + --{{ item.deleted }} + + + + + + 总修改 + + {{ item.score }} + + + + + + + + + + + + + + + + + + 开源企业城市分布 + 开源企业贡献榜 + + + + + + + + + + + + {{ (index % hmEnterprises.length) + 1 }} + + + + + {{ item.name }} + {{ item.city }} + + {{ item.business }} + + + {{ item.remark }} + + + + + + + + + + + + + + 高校鸿蒙贡献分布 + 高校鸿蒙贡献榜 + + + + + + + + + + + + {{ (index % uniContributors.length) + 1 }} + + + + + + {{ item.authorName }} + {{ item.university }} + + + @{{ item.repo }} + {{ item.detailMessage }} + + + + + + 新增:+{{ item.additions }} + 减少:-{{ item.deletions }} + 修改:{{ item.changeNum }} + + {{ item.authorEmail }} + + + + + + + + + + + + + + + + diff --git a/src/views/Jyh/Community/StatsBar.vue b/src/views/Jyh/Community/components/StatsBar.vue similarity index 94% rename from src/views/Jyh/Community/StatsBar.vue rename to src/views/Jyh/Community/components/StatsBar.vue index 1760fe1..e053869 100644 --- a/src/views/Jyh/Community/StatsBar.vue +++ b/src/views/Jyh/Community/components/StatsBar.vue @@ -1,5 +1,10 @@ + + 1000W+ + 鸿蒙开发者 + + 150+ 开源企业 diff --git a/src/views/Jyh/Community/index.vue b/src/views/Jyh/Community/index.vue index 116b73a..e9ab071 100644 --- a/src/views/Jyh/Community/index.vue +++ b/src/views/Jyh/Community/index.vue @@ -19,6 +19,9 @@ + + + @@ -143,17 +146,13 @@ @mouseleave="resumeDeveloperScroll"> - - {{ name.charAt(0) }} - {{ name }} 核心贡献者 - @@ -184,7 +183,6 @@ - - - - - - HarmonyOS 鸿蒙生态数据可视化 - - - - - - 鸿蒙优质开源项目榜 - - - - - {{ index + 1 }} - - - {{ item.name }} - {{ item.desc }} - - - ★ {{ item.stars }} - - - - - - - - - 鸿蒙明星开发者贡献榜 - - - - - - - {{ item.name.charAt(0) }} - - - - {{ item.name }} - 核心贡献者 - - - - - - - 活跃 - - - - - - - - - - 鸿蒙开源企业贡献榜 - - - - - - - - - @@ -409,11 +307,11 @@ import { onMounted, ref, nextTick, watch, onUnmounted, computed } from 'vue'; import * as echarts from 'echarts'; import { usePageResize } from '@/utils/hooks/usePageResize'; -import StatsBar from './StatsBar.vue'; +import StatsBar from './components/StatsBar.vue'; +import HarmonyEcoCharts from './components/HarmonyEcoCharts.vue'; const { widthType } = usePageResize(); -// ================= 数据定义 ================= const githubProjects = ref([ { name: 'bootstrap', @@ -481,6 +379,7 @@ const excellentProjects = ref([ { 'name': 'RustSBI', 'desc': 'RISC-V 安全引导程序', 'org': '华中科技大学' }, { 'name': 'NextDenovo', 'desc': '长读长序列组装工具', 'org': '武汉希望组' } ]); + const chinaExcellentProjects = ref([ { 'name': 'Deepin 深度操作系统', @@ -534,11 +433,14 @@ const chinaExcellentProjects = ref([ } ]); -// 武汉知名社区数据 const wuhanCommunities = ref([ { name: '黄鹤开源社区', type: '核心生态', slogan: '国家级、城市级开源社区平台,武汉开源生态的核心枢纽' }, { name: '深度社区 (Deepin)', type: '操作系统', slogan: '全球最大桌面操作系统社区之一,全球用户超过 750 万' }, - { name: '极狐社区 (GitLab China)', type: 'DevOps', slogan: '全球第二大开源托管平台 GitLab 在汉设立的中国发行版及开发者社区' }, + { + name: '极狐社区 (GitLab China)', + type: 'DevOps', + slogan: '全球第二大开源托管平台 GitLab 在汉设立的中国发行版及开发者社区' + }, { name: '开源鸿蒙社区 (OpenHarmony)', type: '万物互联', slogan: '国家级生态创新中心,设有全国首个分委会' }, { name: 'PostgreSQL 中文社区', type: '数据库', slogan: '全球四大开源数据库之一的运营中心设在武汉' }, { name: '武汉大学开源社区', type: '学术社团', slogan: '老牌社团,涉及 Linux、嵌入式、深度学习等方向' }, @@ -550,6 +452,50 @@ const wuhanCommunities = ref([ { name: '湖北大学', type: '兴趣小组', slogan: '开源技术兴趣小组' } ]); +// 开发者名单 +const developerNames = ['白纯骢', '陆红旭', '慕冬亮', '张继德', '蒋周奇', '张天雄', '阮文俊', '李奇', '陈鹏轩', '杨帆']; + +// 图表数据 +const chartData = ref({ + cityProject: { + xAxis: ['北京', '上海', '深圳', '杭州', '广州', '成都', '武汉', '南京', '西安', '重庆'], + data: [757259, 678614, 343417, 315406, 177003, 168300, 120827, 111593, 58678, 56564] + }, + talent: { + xAxis: ['北京', '上海', '广州', '深圳', '成都', '杭州', '武汉', '南京', '郑州', '长沙'], + data: [2115924, 1591988, 1555240, 1163580, 894108, 830306, 791335, 733581, 553397, 487971] + }, + communityRank: { + xAxis: ['Deepin', 'OpenHarmony', 'MindSpore', 'IoTDB', 'GoFrame'], + data: [95, 92, 88, 76, 72] + }, + club: { + xAxis: ['成都', '北京', '上海', '武汉', '重庆', '深圳', '苏州', '杭州', '合肥', '青岛'], + data: [10, 7, 5, 4, 3, 2, 2, 2, 2, 2] + }, + policy: { + xAxis: ['江苏', '北京', '浙江', '广东', '上海', '湖北', '天津', '陕西', '河南', '云南'], + data: [11, 7, 3, 3, 3, 2, 2, 2, 2, 2] + }, + campus: { + xAxis: ['南京', '武汉', '北京', '长沙', '成都', '上海', '天津', '深圳', '济南', '广州'], + data: [20, 16, 16, 16, 11, 10, 8, 8, 7, 6] + }, + mirrors: { + xAxis: ['上海', '北京', '西安', '重庆', '济南', '南京', '武汉', '合肥', '香港', '长春', '成都', '深圳', '兰州', '哈尔滨', '南阳', '杭州'], + data: [4, 4, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] + } +}); + +// ================= 逻辑处理 ================= + +const isEmpty = ref({ + cityProject: false, talent: false, developer: false, communityRank: false, + club: false, policy: false, campus: false, mirrors: false +}); +const chartInstances = ref<{ [key: string]: echarts.ECharts | null }>({}); + +// 社区 Tab 切换 const activeCommunityTab = ref(0); const communityScrollRef = ref(null); let communityTimer: NodeJS.Timeout | null = null; @@ -570,7 +516,6 @@ const startCommunityScroll = () => { if (!container) return; const list = container.querySelector('.community-scroll-list') as HTMLElement; if (!list || list.scrollHeight <= container.clientHeight) return; - if (communityTimer) clearInterval(communityTimer); communityTimer = setInterval(() => { container.scrollTop += 1; @@ -582,16 +527,13 @@ const startCommunityScroll = () => { const pauseCommunityScroll = () => communityTimer && clearInterval(communityTimer); const resumeCommunityScroll = () => activeCommunityTab.value === 1 && startCommunityScroll(); +// 项目 Tab 切换 const currentProjectList = computed(() => { return activeTab.value === 0 ? chinaExcellentProjects.value : excellentProjects.value; }); -const switchTab = (index: number) => { - if (activeTab.value === 1) { - activeTab.value = 0; - } else { - activeTab.value = 1; - } +const switchTab = () => { + activeTab.value = activeTab.value === 1 ? 0 : 1; nextTick(() => { if (scrollContainer2.value) scrollContainer2.value.scrollTop = 0; pauseScroll(2); @@ -599,82 +541,21 @@ const switchTab = (index: number) => { }); }; -const chartData = ref({ - cityProject: { - xAxis: ['北京', '上海', '深圳', '杭州', '广州', '成都', '武汉', '南京', '西安', '重庆'], - data: [757259, 678614, 343417, 315406, 177003, 168300, 120827, 111593, 58678, 56564] - }, - talent: { - xAxis: ['北京', '上海', '广州', '深圳', '成都', '杭州', '武汉', '南京', '郑州', '长沙'], - data: [2115924, 1591988, 1555240, 1163580, 894108, 830306, 791335, 733581, 553397, 487971] - }, - communityRank: { - xAxis: ['Deepin', 'OpenHarmony', 'MindSpore', 'IoTDB', 'GoFrame'], - data: [95, 92, 88, 76, 72] - }, - club: { - xAxis: ['成都', '北京', '上海', '武汉','重庆', '深圳', '苏州', '杭州', '合肥', '青岛' ], - data: [10, 7, 5, 4, 3, 2, 2, 2, 2, 2] - }, - policy: { - xAxis: [ - '江苏', '北京', '浙江', '广东', '上海', '湖北', '天津', - '陕西', '河南', '云南' - // '黑龙江','安徽省', '重庆市', '宁夏回族自治区', '山东省', '湖南省' - ], - data: [11, 7, 3, 3, 3, 2, 2, 2, 2, 2 - // 2, 2, 1, 1, 1, 1 - ] - }, - campus: { - xAxis: [ - '南京', '武汉', '北京', '长沙', '成都', '上海', '天津', '深圳', - '济南', '广州' - // '呼和浩特', '长春', '吉林', '沈阳', '苏州', '青岛', - // '惠州', '合肥', '佛山', '南昌', '南充', '徐州', '西安', '郑州', - // '贵阳', '线上', '哈尔滨', '宜宾', '杭州', '太原', '大连', '银川', - // '西宁', '中山', '乐山', '内江', '泸州', '常德', '昌吉', '桂林', - // '福州', '常州', '库尔勒', '兰州', '温州', '鄂州', '乌鲁木齐', '日照', - // '无锡', '重庆', '东莞', '赣州' - ], - data: [ - 20, 16, 16, 16, 11, 10, 8, 8, 7, 6 - // 5, 4, 3, 3, 3, 3, - // 3, 3, 3, 3, 3, 2, 2, 2, - // 2, 2, 2, 2, 2, 2, 2, 1, - // 1, 1, 1, 1, 1, 1, 1, 1, - // 1, 1, 1, 1, 1, 1, 1, 1, - // 1, 1, 1, 1 - ] - }, - mirrors: { - xAxis: [ - '上海', '北京', '西安', '重庆', '济南', '南京', '武汉', '合肥', '香港', - '长春', '成都', '深圳', '兰州', '哈尔滨', '南阳', '杭州' - ], - data: [4, 4, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] - } -}); - -// 数据定义 -const developerNames = ['白纯骢', '陆红旭', '慕冬亮', '张继德', '蒋周奇', '张天雄', '阮文俊', '李奇', '陈鹏轩', '杨帆']; - -const developerScrollRef = ref(null); -let developerTimer: NodeJS.Timeout | null = null; - -// 自动生成头像背景色 +// 头像背景色 const getAvatarBg = (index: number) => { const colors = ['#6366f1', '#8b5cf6', '#ec4899', '#f43f5e', '#f59e0b', '#10b981', '#06b6d4', '#3b82f6']; return colors[index % colors.length]; }; -// 滚动逻辑 +// 开发者列表滚动 +const developerScrollRef = ref(null); +let developerTimer: NodeJS.Timeout | null = null; + const startDeveloperScroll = () => { const container = developerScrollRef.value; if (!container) return; const list = container.querySelector('.developer-list') as HTMLElement; if (!list || list.scrollHeight <= container.clientHeight) return; - if (developerTimer) clearInterval(developerTimer); developerTimer = setInterval(() => { container.scrollTop += 1; @@ -687,16 +568,9 @@ const startDeveloperScroll = () => { const pauseDeveloperScroll = () => developerTimer && clearInterval(developerTimer); const resumeDeveloperScroll = () => startDeveloperScroll(); -const isEmpty = ref({ - cityProject: false, talent: false, developer: false, communityRank: false, - club: false, policy: false, campus: false, mirrors: false -}); - -const chartInstances = ref<{ [key: string]: echarts.ECharts | null }>({}); +// 自动滚动 (通用项目列表) const scrollContainer1 = ref(null); const scrollContainer2 = ref(null); -const scrollContainer3 = ref(null); -const scrollContainer4 = ref(null); const scrollTimers: { [key: number]: NodeJS.Timeout | null } = { 1: null, 2: null }; const autoScroll = (key: number) => { @@ -721,10 +595,8 @@ const pauseScroll = (key: number) => { }; const resumeScroll = (key: number) => autoScroll(key); -// ================= 图表初始化================= - +// ================= 图表初始化 ================= const commonGrid = { left: '3%', right: '4%', bottom: '15px', top: '15%', containLabel: true }; -const colorPalette = ['#3b82f6', '#06b6d4', '#8b5cf6', '#ec4899', '#f59e0b']; // 蓝, 青, 紫, 粉, 橙 const initCityProjectChart = () => { const el = document.getElementById('cityProjectChart'); @@ -761,36 +633,7 @@ const initTalentChart = () => { yAxis: { type: 'value', name: '单位:人', splitLine: { lineStyle: { type: 'dashed', color: '#eee' } } }, series: [{ type: 'bar', data: chartData.value.talent.data, barWidth: '50%', - itemStyle: { borderRadius: [4, 4, 0, 0], color: '#F97316' } // 橙色 - }] - }); -}; - -const initDeveloperChart = () => { - const el = document.getElementById('developerChart'); - if (!el) return; - const myChart = echarts.init(el); - chartInstances.value.developer = myChart; - myChart.setOption({ - tooltip: { trigger: 'axis', valueFormatter: (value: any) => value + ' 贡献分' }, - grid: { left: '3%', right: '5%', bottom: '15px', top: '5%', containLabel: true }, - xAxis: { type: 'value', show: false }, // 隐藏x轴 - yAxis: { - type: 'category', - data: chartData.value.developer.yAxis.reverse(), - axisLine: { show: false }, - axisTick: { show: false }, - axisLabel: { color: '#333', fontWeight: 500 } - }, - series: [{ - type: 'bar', data: chartData.value.developer.data.reverse(), barWidth: 16, - itemStyle: { - color: new echarts.graphic.LinearGradient(1, 0, 0, 0, [{ offset: 0, color: '#7C3AED' }, { - offset: 1, - color: '#C4B5FD' - }]), borderRadius: [0, 8, 8, 0] - }, - label: { show: false } // **修改点:隐藏具体分数** + itemStyle: { borderRadius: [4, 4, 0, 0], color: '#F97316' } }] }); }; @@ -809,9 +652,7 @@ const initCommunityRankChart = () => { }, yAxis: { type: 'value', name: '单位:个', nameTextStyle: { color: '#999' } }, series: [{ - type: 'bar', - data: [69, 35, 31, 25, 18, 15, 12, 12], - barWidth: '40%', + type: 'bar', data: [69, 35, 31, 25, 18, 15, 12, 12], barWidth: '40%', itemStyle: { borderRadius: [4, 4, 0, 0], color: '#3b82f6' } }] }); @@ -828,8 +669,7 @@ const initClubChart = () => { xAxis: { type: 'category', data: chartData.value.club.xAxis, axisLabel: { color: '#666' } }, yAxis: { type: 'value', name: '单位:个', splitLine: { lineStyle: { type: 'dashed', color: '#eee' } } }, series: [{ - type: 'line', data: chartData.value.club.data, - smooth: true, symbolSize: 8, + type: 'line', data: chartData.value.club.data, smooth: true, symbolSize: 8, lineStyle: { width: 3, color: '#F59E0B' }, itemStyle: { color: '#F59E0B', borderColor: '#fff', borderWidth: 2 }, areaStyle: { opacity: 0.15, color: '#F59E0B' } @@ -849,7 +689,7 @@ const initPolicyChart = () => { yAxis: { type: 'value', name: '单位:条', splitLine: { lineStyle: { type: 'dashed', color: '#eee' } } }, series: [{ type: 'bar', data: chartData.value.policy.data, barWidth: '45%', - itemStyle: { borderRadius: [4, 4, 0, 0], color: '#2563EB' } // 蓝色 + itemStyle: { borderRadius: [4, 4, 0, 0], color: '#2563EB' } }] }); }; @@ -859,23 +699,19 @@ const initCampusChart = () => { if (!el) return; const myChart = echarts.init(el); chartInstances.value.campus = myChart; - // **修改点:去掉三角形pictorialBar,改为美观的圆角柱状图** myChart.setOption({ tooltip: { trigger: 'axis', valueFormatter: (value: any) => value + ' 场' }, grid: commonGrid, xAxis: { type: 'category', data: chartData.value.campus.xAxis, axisLabel: { color: '#666' } }, yAxis: { type: 'value', name: '单位:场次', splitLine: { lineStyle: { type: 'dashed', color: '#eee' } } }, series: [{ - type: 'bar', - data: chartData.value.campus.data, - barWidth: '35%', + type: 'bar', data: chartData.value.campus.data, barWidth: '35%', itemStyle: { - borderRadius: [8, 8, 0, 0], // 圆角 - // 活力洋红色渐变 - color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ - { offset: 0, color: '#EC4899' }, - { offset: 1, color: '#F472B6' } - ]) + borderRadius: [8, 8, 0, 0], + color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{ offset: 0, color: '#EC4899' }, { + offset: 1, + color: '#F472B6' + }]) } }] }); @@ -892,38 +728,22 @@ const initMirrorChart = () => { xAxis: { type: 'category', data: chartData.value.mirrors.xAxis, axisLabel: { color: '#666' } }, yAxis: { type: 'value', name: '单位:个', splitLine: { lineStyle: { type: 'dashed', color: '#eee' } } }, series: [{ - type: 'bar', data: chartData.value.mirrors.data, - barWidth: 30, + type: 'bar', data: chartData.value.mirrors.data, barWidth: 30, itemStyle: { borderRadius: [4, 4, 0, 0], - color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ - { offset: 0, color: '#0EA5E9' }, - { offset: 1, color: '#38BDF8' } - ]) + color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{ offset: 0, color: '#0EA5E9' }, { + offset: 1, + color: '#38BDF8' + }]) } }] }); }; -const initCharts = () => { - nextTick(() => { - initCityProjectChart(); - initTalentChart(); - initDeveloperChart(); - initCommunityRankChart(); - initClubChart(); - initPolicyChart(); - initCampusChart(); - initMirrorChart(); - }); -}; - const init = () => { nextTick(() => { initCityProjectChart(); - initHmEnterpriseChart(); initTalentChart(); - initDeveloperChart(); initCommunityRankChart(); initClubChart(); initPolicyChart(); @@ -932,108 +752,25 @@ const init = () => { autoScroll(1); autoScroll(2); - autoScroll(3); - autoScroll(4); startCommunityScroll(); startDeveloperScroll(); }); }; + const unInit = () => { Object.values(scrollTimers).forEach(t => t && clearInterval(t)); pauseDeveloperScroll(); pauseCommunityScroll(); }; - -// 1. 鸿蒙优秀开源项目 (突出核心技术组件) -const hmProjects = [ - { name: 'OpenHarmony/arkui_ace_engine', desc: 'ArkUI 声明式UI开发框架引擎' }, - { name: 'HarmonyOS/dist_softbus', desc: '极简协议分布式软总线技术' }, - { name: 'OpenHarmony/communication_netmanager', desc: '网络管理与连接调度子系统' }, - { name: 'ohos-standard/third_party_sqlite', desc: '适配于鸿蒙的高性能数据库组件' }, -]; - -// 2. 鸿蒙明星开发者贡献榜 (模拟活跃度分数) -const hmDevelopers = [ - { name: 'Harmony_Hacker', score: '3,210', avatar: 'https://api.dicebear.com/7.x/avataaars/svg?seed=Ark' }, - { name: 'BlueOS_Contributor', score: '2,850', avatar: 'https://api.dicebear.com/7.x/avataaars/svg?seed=Blue' }, - { name: 'OpenSource_Fanatic', score: '2,460', avatar: 'https://api.dicebear.com/7.x/avataaars/svg?seed=Fan' }, -]; - -// 3. 鸿蒙开源企业排行榜 (体现生态伙伴参与度) -const hmEnterprises = [ - { name: '华为技术', value: 100 }, - { name: '软通动力', value: 85 }, - { name: '拓维信息', value: 72 }, - { name: '润和软件', value: 65 }, - { name: '中软国际', value: 58 } -]; - -const initHmEnterpriseChart = () => { - const chartDom = document.getElementById('hmEnterpriseChart'); - if (!chartDom) return; - - const myChart = echarts.init(chartDom); - - const option = { - grid: { - left: '3%', - right: '12%', - bottom: '3%', - top: '5%', - containLabel: true - }, - xAxis: { - type: 'value', - show: false // 保持与政策图一致,不显示坐标轴 - }, - yAxis: { - type: 'category', - // 反转数据,让高分的排在上面 - data: hmEnterprises.map(item => item.name).reverse(), - axisLine: { show: false }, - axisTick: { show: false }, - axisLabel: { - color: '#64748b', - fontSize: 12 - } - }, - series: [ - { - type: 'bar', - data: hmEnterprises.map(item => item.value).reverse(), - barWidth: 16, - itemStyle: { - // 使用渐变色提升质感 - color: new echarts.graphic.LinearGradient(0, 0, 1, 0, [ - { offset: 0, color: '#3b82f6' }, - { offset: 1, color: '#60a5fa' } - ]), - borderRadius: [0, 8, 8, 0] // 右侧圆角 - }, - label: { - show: true, - position: 'right', - formatter: '{c}', // 直接显示数值 - color: '#1e293b', - fontWeight: 'bold' - } - } - ] - }; - - myChart.setOption(option); - - // 窗口缩放自适应 - window.addEventListener('resize', () => myChart.resize()); -}; - watch(widthType, () => { init(); }); + onMounted(() => { init(); }); + onUnmounted(() => { unInit(); }); @@ -1042,7 +779,6 @@ onUnmounted(() => {