<template>
  <div class="index-module__NV_5cW__container">
    <!-- 头部区域：标题、副标题、武汉核心数据统计 -->
    <div class="index-module__NV_5cW__header">
      <div class="index-module__NV_5cW__floatingElements">
        <div class="index-module__NV_5cW__floatingElement"></div>
        <div class="index-module__NV_5cW__floatingElement"></div>
        <div class="index-module__NV_5cW__floatingElement"></div>
      </div>
      <div class="index-module__NV_5cW__titleSection">
<!--        <div class="index-module__NV_5cW__titleContainer">-->
<!--          <h1 class="index-module__NV_5cW__title">开源生态与贡献价值全景</h1>-->
<!--        </div>-->
        <!--        <div class="index-module__NV_5cW__subtitle">-->
        <!--          <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none"-->
        <!--               stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"-->
        <!--               class="lucide lucide-users" aria-hidden="true">-->
        <!--            <path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"></path>-->
        <!--            <path d="M16 3.128a4 4 0 0 1 0 7.744"></path>-->
        <!--            <path d="M22 21v-2a4 4 0 0 0-3-3.87"></path>-->
        <!--            <circle cx="9" cy="7" r="4"></circle>-->
        <!--          </svg>-->
        <!--          <span>汇聚武汉开源力量，共建城市开源生态</span>-->
        <!--        </div>-->
                
        <!-- 武汉4项核心开源数据统计 -->
        <StatsGlass />
      </div>
    </div>

    <!-- 内容区域：ECharts图表模块 + 项目列表 -->
    <div class="index-module__NV_5cW__content">
      <!-- ECharts图表区域 -->
      <div class="index-module__NV_5cW__chartsSection">
<!--        <div class="index-module__NV_5cW__sectionHeader">-->
<!--          <h2 class="index-module__NV_5cW__sectionTitle">-->
<!--            <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none"-->
<!--              stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"-->
<!--              class="lucide lucide-chart-pie" aria-hidden="true">-->
<!--              <path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z"></path>-->
<!--              <circle cx="12" cy="10" r="3"></circle>-->
<!--            </svg>-->
<!--            <span>开源生态与贡献价值全景数据可视化</span>-->
<!--          </h2>-->
<!--        </div>-->

        <!-- 图表网格布局：新增多个模块 -->
        <div class="index-module__NV_5cW__chartsGrid">
          <!-- 1. 开源企业贡献榜-->
          <div class="index-module__NV_5cW__chartCard list-card">
            <div class="chartCard__header">
              <div class="title-with-stats">
                <h3 class="chartCard__title">全球开源企业贡献榜 TOP 30</h3>
                <div class="enterprise-stats" v-if="enterpriseFilter !== 'all'">
                  <span class="stat-badge">
                    平均分: {{ avgScore }}
                  </span>
                  <span class="stat-badge">
                    总仓库: {{ totalRepos }}
                  </span>
                </div>
              </div>
              <div class="enterprise-filter">
                <span :class="['filter-tag', { active: enterpriseFilter === 'all' }]"
                  @click="changeEnterpriseFilter('all')">
                  全部 ({{ allEnterprises.length }})
                </span>
                <span :class="['filter-tag', { active: enterpriseFilter === 'China' }]"
                  @click="changeEnterpriseFilter('China')">
                  🇨🇳 中国 ({{ chinaCount }})
                </span>
                <span :class="['filter-tag', { active: enterpriseFilter === 'USA' }]"
                  @click="changeEnterpriseFilter('USA')">
                  🇺🇸 美国 ({{ usaCount }})
                </span>
              </div>
            </div>
            <div class="chartCard__container list-container" ref="scrollContainer1" @mouseenter="pauseScroll(1)"
              @mouseleave="resumeScroll(1)">
              <div class="scroll-indicator">
                <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none"
                  stroke="currentColor" stroke-width="2">
                  <path d="M12 5v14M19 12l-7 7-7-7" />
                </svg>
                <span>悬停暂停滚动</span>
              </div>
              <div class="project-list enterprise-list">
                <div class="project-item enterprise-item" v-for="(item, index) in excellentProjects" :key="index"
                  :title="`${item.name}\n全球排名: #${item.rank}\n综合得分: ${item.score}\n仓库数: ${item.repos}\n开发者: ${item.devs}\n国家: ${item.country}`">
                  <span :class="['enterprise-rank', getRankClass(item.displayRank || item.rank)]">
                    {{ getRankText(item.displayRank || item.rank) }}
                  </span>
                  <div class="enterprise-info">
                    <span class="enterprise-name">{{ item.name }}</span>
                    <div class="enterprise-meta">
                      <span class="meta-item">{{ getCountryFlag(item.country) }}</span>
                      <span class="meta-item">{{ item.repos }} 仓库</span>
                      <span class="meta-item meta-devs">{{ formatDevs(item.devs) }} 开发者</span>
                    </div>
                  </div>
                  <div class="score-bar-container">
                    <div :class="['score-bar', getScoreBarClass(item.score)]"
                      :style="{ width: (30 + (item.score - 60) / 36 * 70) + '%' }">
                    </div>
                  </div>
                  <span :class="['enterprise-score', getScoreClass(item.score)]">
                    {{ item.score }}
                  </span>
                </div>
              </div>
            </div>
          </div>

          <!-- 2. 基础设施覆盖率（多层环形图）-->
          <InfrastructureCoverageChart />

          <!-- 3. 高校开源社团/俱乐部数量-->
          <UniversityClubStatsChart />

          <!-- 4. 社区治理健康度对比-->
          <CommunityGovernanceHealthChart />

          <!-- 5. 语言与技术竞争-->
          <div class="index-module__NV_5cW__chartCard">
            <div class="chartCard__header">
              <h3 class="chartCard__title">语言与技术竞争</h3>
              <div class="language-tab" @click="changeLanguageTab">
                <span :class="{ active: languageTab === 'mainstream' }">主流语言</span>
                <span :class="{ active: languageTab === 'emerging' }">新兴语言</span>
              </div>
            </div>
            <div class="chartCard__container">
              <div class="num-empty" v-if="isEmpty.languageTech"></div>
              <div v-else id="languageTechChart" class="chart"></div>
            </div>
          </div>

          <!-- 6. 明星开发者聚焦（列表）-->
          <div class="index-module__NV_5cW__chartCard list-card">
            <h3 class="chartCard__title">明星开发者聚焦</h3>
            <!-- 新增：ref + 鼠标事件 -->
            <div class="chartCard__container list-container developer-list-container" ref="scrollContainer2"
              @mouseenter="pauseScroll(2)" @mouseleave="resumeScroll(2)">
              <div class="project-list developer-list">
                <div class="project-item developer-item" v-for="(item, index) in excellentProjects2025" :key="index">
                  <div class="dev-avatar">
                    <img :src="item.avatar" :alt="item.name" class="avatar-img" @error="handleImageError" />
                  </div>
                  <span class="project-rank dev-rank">{{ item.desc }}</span>
                  <div class="project-info dev-info">
                    <span class="project-name dev-name">{{ item.name }}</span>
                    <span class="project-desc dev-location">📍 {{ item.org }}</span>
                  </div>
                  <span class="project-org dev-followers">
                    <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none"
                      stroke="currentColor" stroke-width="2">
                      <path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"></path>
                      <circle cx="9" cy="7" r="4"></circle>
                    </svg>
                    {{ formatFollowers(item.followers) }}
                  </span>
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>

      <!-- 开发者活力波形图 -->
      <VitalityWaveChart />
      <!-- 开源项目热力图 -->
      <div class="index-module__NV_5cW__vitalitySection heatmap-section">
        <div class="heatmap-header">
          <div class="title-row">
            <h3 class="vitality__title">
              <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none"
                stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
                <path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z">
                </path>
              </svg>
              <span>开源项目热力图</span>
            </h3>
            <div class="label-toggle" @click="toggleLabels">
              <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none"
                stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
                <path d="M12 2v20M2 12h20"></path>
              </svg>
              <span>{{ showAllLabels ? '隐藏标签' : '显示全部' }}</span>
            </div>
          </div>
          <div class="heatmap-stats">
            <div class="stat-item">
              <span class="stat-value">{{ heatmapData.length }}</span>
              <span class="stat-label">项目总数</span>
            </div>
            <div class="stat-divider"></div>
            <div class="stat-item">
              <span class="stat-value">{{ topProject.name }}</span>
              <span class="stat-label">领先项目</span>
            </div>
            <div class="stat-divider"></div>
            <div class="stat-item">
              <span class="stat-value">{{ totalDevs }}</span>
              <span class="stat-label">总开发者数</span>
            </div>
          </div>
        </div>
        <div class="vitality__container heatmap-container">
          <div class="heatmap-legend">
            <div class="legend-item">
              <div class="legend-icon bubble-small"></div>
              <span>少量开发者</span>
            </div>
            <div class="legend-item">
              <div class="legend-icon bubble-medium"></div>
              <span>中等规模</span>
            </div>
            <div class="legend-item">
              <div class="legend-icon bubble-large"></div>
              <span>大量开发者</span>
            </div>
          </div>
          <div id="heatmapChart" class="chart"></div>
        </div>
      </div>
      <!-- 中国开源人才密度地图 -->
      <div class="index-module__NV_5cW__vitalitySection map-section">
        <h3 class="vitality__title">
          <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none"
            stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
            <path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z"></path>
            <circle cx="12" cy="10" r="3"></circle>
          </svg>
          <span>🌍 中国开源人才密度地图</span>
        </h3>
        <TalentMapChart />
      </div>
    </div>
  </div>
</template>

<script lang="ts" setup>
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 CommunityGovernanceHealthChart from './components/CommunityGovernanceHealthChart.vue'
import VitalityWaveChart from './components/VitalityWaveChart.vue'
import StatsGlass from './components/StatsGlass.vue'
import { usePageResize } from '@/utils/hooks/usePageResize';

// 页面尺寸响应式
const { widthType } = usePageResize();

// 1. 全球开源企业贡献榜数据（来自 EnterpriseContributionRanking.vue）
const rawEnterpriseData = [
  { name: 'Microsoft', openrank: 177654.43, repos: 9211, devs: 14954, country: 'USA' },
  { name: 'Huawei', openrank: 108690.66, repos: 11407, devs: 16413, country: 'China' },
  { name: 'Google', openrank: 64156.6, repos: 3426, devs: 64115, country: 'USA' },
  { name: 'Amazon', openrank: 54776.3, repos: 7850, devs: 35802, country: 'USA' },
  { name: 'Meta', openrank: 34811.3, repos: 1410, devs: 31912, country: 'USA' },
  { name: 'RedHat', openrank: 28004.37, repos: 736, devs: 3626, country: 'USA' },
  { name: 'Mozilla', openrank: 27085.14, repos: 1792, devs: 17242, country: 'USA' },
  { name: 'Alibaba', openrank: 24744.15, repos: 5570, devs: 18661, country: 'China' },
  { name: 'IBM', openrank: 21165.28, repos: 626, devs: 5658, country: 'USA' },
  { name: 'Elastic', openrank: 21472.45, repos: 2437, devs: 17735, country: 'USA' },
  { name: 'Nabu Casa', openrank: 18499.45, repos: 101, devs: 27413, country: 'USA' },
  { name: 'Grafana Labs', openrank: 18237.03, repos: 756, devs: 10925, country: 'USA' },
  { name: 'Ant Group', openrank: 17916.45, repos: 1251, devs: 13760, country: 'China' },
  { name: 'DataDog', openrank: 17795.41, repos: 935, devs: 5401, country: 'USA' },
  { name: 'Intel', openrank: 17725.74, repos: 1046, devs: 6142, country: 'USA' },
  { name: 'HashiCorp', openrank: 17229.81, repos: 745, devs: 17068, country: 'USA' },
  { name: 'Hugging Face', openrank: 16909.25, repos: 277, devs: 15021, country: 'USA' },
  { name: 'NVIDIA', openrank: 16082.9, repos: 850, devs: 12362, country: 'USA' },
  { name: 'Baidu', openrank: 15695.3, repos: 408, devs: 9386, country: 'China' },
  { name: 'VMWare', openrank: 14627.44, repos: 634, devs: 11794, country: 'USA' },
  { name: 'Odoo', openrank: 12959.59, repos: 27, devs: 2678, country: 'Belgium' },
  { name: 'Dio Academia', openrank: 11231.13, repos: 169, devs: 24070, country: 'Portugal' },
  { name: 'Oracle', openrank: 10799.13, repos: 528, devs: 37959, country: 'USA' },
  { name: 'Yandex', openrank: 10025.79, repos: 283, devs: 10112, country: 'Germany' },
  { name: 'NextCloud', openrank: 10029.67, repos: 229, devs: 39516, country: 'Russia' },
  { name: 'ByteDance', openrank: 8310.37, repos: 652, devs: 5989, country: 'China' },
  { name: 'WordPress', openrank: 8267.62, repos: 176, devs: 777, country: 'USA' },
  { name: 'Vercel', openrank: 8214.69, repos: 170, devs: 13420, country: 'USA' },
  { name: 'LangChain', openrank: 8108.64, repos: 135, devs: 10099, country: 'USA' },
  { name: 'ConsenSys', openrank: 8071.43, repos: 640, devs: 4686, country: 'USA' }
];

// 计算综合得分并排序
const calculateEnterpriseScore = () => {
  const maxOpenrank = Math.max(...rawEnterpriseData.map(d => d.openrank));
  const maxRepos = Math.max(...rawEnterpriseData.map(d => d.repos));
  const maxDevs = Math.max(...rawEnterpriseData.map(d => d.devs));

  const scored = rawEnterpriseData.map(item => {
    const openrankScore = Math.sqrt(item.openrank / maxOpenrank) * 100;
    const reposScore = Math.sqrt(item.repos / maxRepos) * 100;
    const devsScore = Math.sqrt(item.devs / maxDevs) * 100;
    const compositeScore = openrankScore * 0.4 + reposScore * 0.25 + devsScore * 0.35;

    return { ...item, rawScore: compositeScore };
  });

  const sorted = scored.sort((a, b) => b.rawScore - a.rawScore);
  const maxScore = sorted[0].rawScore;
  const minScore = sorted[sorted.length - 1].rawScore;

  return sorted.map((item, index) => {
    let normalizedScore = ((item.rawScore - minScore) / (maxScore - minScore)) * 36 + 60;
    normalizedScore = Math.max(60, Math.min(96, normalizedScore - index * 0.15));

    return {
      rank: index + 1,
      name: item.name,
      score: Math.round(normalizedScore * 10) / 10,
      repos: item.repos,
      country: item.country,
      devs: item.devs
    };
  });
};

const allEnterprises = calculateEnterpriseScore();
const enterpriseFilter = ref<'all' | 'China' | 'USA'>('all');

// 计算各国企业数量
const chinaCount = computed(() => allEnterprises.filter(item => item.country === 'China').length);
const usaCount = computed(() => allEnterprises.filter(item => item.country === 'USA').length);

// 切换筛选并重启滚动
const changeEnterpriseFilter = (filter: 'all' | 'China' | 'USA') => {
  enterpriseFilter.value = filter;
  // 重启滚动
  nextTick(() => {
    pauseScroll(1);
    setTimeout(() => autoScroll(1), 100);
  });
};

// 计算筛选后的统计数据
const avgScore = computed(() => {
  if (enterpriseFilter.value === 'all') return 0;
  const filtered = excellentProjects.value;
  if (filtered.length === 0) return 0;
  const sum = filtered.reduce((acc, item) => acc + item.score, 0);
  return (sum / filtered.length).toFixed(1);
});

const totalRepos = computed(() => {
  if (enterpriseFilter.value === 'all') return 0;
  return excellentProjects.value.reduce((acc, item) => acc + item.repos, 0).toLocaleString();
});

// 根据筛选条件过滤企业数据
const excellentProjects = computed(() => {
  if (enterpriseFilter.value === 'all') {
    return allEnterprises;
  }
  const filtered = allEnterprises.filter(item => item.country === enterpriseFilter.value);
  // 重新计算排名
  return filtered.map((item, index) => ({
    ...item,
    displayRank: index + 1
  }));
});

// 2. 明星开发者数据（基于GitHub中国区Top开发者）
const excellentProjects2025 = ref([
  { name: '稚晖', desc: 'TOP 1', org: 'Shanghai', followers: 82738, avatar: 'https://github.com/peng-zhihui.png' },
  { name: 'Crypto Michael', desc: 'TOP 2', org: 'Beijing, China', followers: 37622, avatar: 'https://github.com/michaelliao.png' },
  { name: '代码家', desc: 'TOP 3', org: 'Beijing, China', followers: 24743, avatar: 'https://github.com/daimajia.png' },
  { name: 'Jackson Tian', desc: 'TOP 4', org: 'Hangzhou, China', followers: 21267, avatar: 'https://github.com/JacksonTian.png' },
  { name: '云风', desc: 'TOP 5', org: 'China', followers: 21192, avatar: 'https://github.com/cloudwu.png' },
  { name: 'Fengda Huang', desc: 'TOP 6', org: 'Shanghai / Hangzhou', followers: 20229, avatar: 'https://github.com/phodal.png' },
  { name: '程序员鱼皮', desc: 'TOP 7', org: 'Shanghai', followers: 18461, avatar: 'https://github.com/liyupi.png' },
  { name: 'Trinea', desc: 'TOP 8', org: 'HangZhou', followers: 17019, avatar: 'https://github.com/Trinea.png' },
  { name: 'lifesinger', desc: 'TOP 9', org: 'Hangzhou, China', followers: 15894, avatar: 'https://github.com/lifesinger.png' },
  { name: 'stormzhang', desc: 'TOP 10', org: 'Shanghai, China', followers: 15889, avatar: 'https://github.com/stormzhang.png' },
  { name: 'Wenli Zhang', desc: 'TOP 11', org: 'Shanghai, China', followers: 15680, avatar: 'https://github.com/Ovilia.png' },
  { name: 'Wei Wang', desc: 'TOP 12', org: 'Yokohama / China', followers: 15532, avatar: 'https://github.com/onevcat.png' },
  { name: 'astaxie', desc: 'TOP 13', org: 'Shanghai, China', followers: 15022, avatar: 'https://github.com/astaxie.png' },
  { name: '司徒正美', desc: 'TOP 14', org: 'China', followers: 14742, avatar: 'https://github.com/RubyLouvre.png' },
  { name: '云谦', desc: 'TOP 15', org: 'HangZhou, China', followers: 14466, avatar: 'https://github.com/sorrycc.png' },
  { name: 'cangdu', desc: 'TOP 16', org: 'Shanghai, China', followers: 13728, avatar: 'https://github.com/bailicangdu.png' },
  { name: 'Huang Haiguang', desc: 'TOP 17', org: 'Qingdao, China', followers: 13422, avatar: 'https://github.com/fengdu78.png' },
  { name: '花裤衩', desc: 'TOP 18', org: 'Shanghai, China', followers: 13236, avatar: 'https://github.com/PanJiaChen.png' },
  { name: '破娃酱', desc: 'TOP 19', org: 'China', followers: 13203, avatar: 'https://github.com/breakwa11.png' },
  { name: 'Draven', desc: 'TOP 20', org: 'Beijing, China', followers: 13094, avatar: 'https://github.com/draveness.png' }
]);

// 3. 图表数据定义
const chartData = ref({
  // 基础设施覆盖率（来自 InfrastructureCoverageRings.vue）
  infrastructure: [
    {
      name: '镜像站规模',
      value: 85,
      color: '#00F0FF',
      radius: ['70%', '80%']
    },
    {
      name: '代码托管平台规模',
      value: 90,
      color: '#FFAB00',
      radius: ['50%', '60%']
    },
    {
      name: '构建平台活跃度',
      value: 40,
      color: '#B20003',
      radius: ['30%', '40%']
    }
  ],


  // 语言与技术竞争（南丁格尔玫瑰图数据）
  languageTech: {
    // 主流语言数据（基于2025年数据，增长率为2024→2025的变化）
    mainstream: [
      { name: 'JavaScript', value: 61, growth: 0 },
      { name: 'Python', value: 57, growth: 0 },
      { name: 'HTML/CSS', value: 52, growth: 1.96 },
      { name: 'Java', value: 49, growth: 6.52 },
      { name: 'SQL', value: 47, growth: -2.08 },
      { name: 'Shell', value: 36, growth: 0 }
    ],
    // 新兴语言数据（基于2025年数据，增长率为2024→2025的变化）
    emerging: [
      { name: 'TypeScript', value: 42, growth: 13.51 },
      { name: 'C++', value: 25, growth: 0 },
      { name: 'C#', value: 21, growth: -4.55 },
      { name: 'Go', value: 20, growth: 11.11 },
      { name: 'Kotlin', value: 18, growth: 28.57 },
      { name: 'C', value: 18, growth: 0 }
    ]
  }
});





// 空数据标识
const isEmpty = ref({
  languageTech: false
});

// 语言图表Tab状态
const languageTab = ref<'mainstream' | 'emerging'>('mainstream');



// 开源项目热力图数据 [OpenRank, 活跃仓库数, 活跃开发者数, 项目名称, 所属组织]
const heatmapData = ref([
  [67538.71, 29433, 1409, 'OpenHarmony', 'Huawei'],
  [55000, 15000, 6000, 'Linux', 'Linux Foundation'],
  [60000, 8000, 7000, 'Android', 'Google'],
  [52000, 20000, 5500, 'Chromium', 'Google'],
  [38000, 16000, 4500, 'TensorFlow', 'Google'],
  [42000, 13000, 5000, 'React', 'Meta'],
  [45417.67, 18000, 8629, 'Azure', 'Microsoft'],
  [35000, 22000, 5000, 'Kubernetes', 'CNCF'],
  [21844.62, 12340, 57, 'LLM', '发芽工具'],
  [25241.13, 8000, 83, 'NixOS', '-'],
  [22961.09, 4500, 9377, 'openEuler', 'Huawei'],
  [17795.41, 2792, 975, 'DataDog', 'DataDog'],
  [25598.21, 2082, 282, '.Net', '操作系统'],
  [7405.46, 9639, 3, 'Expensify', 'Expensify'],
  [8862.2, 4625, 120, 'PaddlePaddle', 'Baidu'],
  [12959.59, 2363, 1, 'Odoo', 'Odoo'],
  [12326.76, 881, 179, 'Rust', 'Rust Foundation'],
  [6778.7, 400, 479, 'CloudHarmony', '企业应用']
]);

// 计算热力图统计数据
const topProject = computed(() => {
  const sorted = [...heatmapData.value].sort((a, b) => b[0] - a[0]);
  return { name: sorted[0][3], openrank: sorted[0][0] };
});

const totalDevs = computed(() => {
  const total = heatmapData.value.reduce((sum, item) => sum + item[2], 0);
  if (total >= 10000) {
    return (total / 10000).toFixed(1) + '万';
  }
  return total.toLocaleString();
});

// 标签显示控制（默认显示全部）
const showAllLabels = ref(true);

const toggleLabels = () => {
  showAllLabels.value = !showAllLabels.value;
  initHeatmapChart();
};

// 获取人才等级
const getTalentLevel = (density: number) => {
  if (density >= 500) return '🔥 核心枢纽';
  if (density >= 100) return '⭐ 重要聚集地';
  if (density >= 10) return '📈 潜力增长区';
  return '🌱 发展中区域';
};

// 图表实例存储（用于resize时销毁重绘）
const chartInstances = ref<{ [key: string]: echarts.ECharts | null }>({
  languageTechChart: null,
  heatmapChart: null
});

// ===================== 新增：列表自动滚动逻辑 =====================
// 1. 定义滚动容器的ref
const scrollContainer1 = ref<HTMLDivElement | null>(null); // 第一个列表容器
const scrollContainer2 = ref<HTMLDivElement | null>(null); // 第二个列表容器

// 2. 存储定时器（键：1/2，值：定时器ID）
const scrollTimers: { [key: number]: NodeJS.Timeout | null } = {
  1: null,
  2: null
};

// 3. 滚动配置
const scrollStep = 1; // 每次滚动的步长（像素，越小越流畅）
const scrollInterval = 20; // 滚动间隔（毫秒，越小越流畅）

// 4. 通用自动滚动函数
const autoScroll = (containerKey: number) => {
  // 获取对应容器
  const container = containerKey === 1 ? scrollContainer1.value : scrollContainer2.value;
  if (!container) return;

  // 获取列表内容元素（project-list）
  const projectList = container.querySelector('.project-list') as HTMLDivElement;
  if (!projectList) return;

  // 若内容高度 ≤ 容器高度，不执行滚动
  if (projectList.scrollHeight <= container.clientHeight) {
    // 清除现有定时器
    if (scrollTimers[containerKey]) {
      clearInterval(scrollTimers[containerKey]!);
      scrollTimers[containerKey] = null;
    }
    return;
  }

  // 清除现有定时器（避免重复）
  if (scrollTimers[containerKey]) {
    clearInterval(scrollTimers[containerKey]!);
  }

  // 启动定时器滚动
  scrollTimers[containerKey] = setInterval(() => {
    // 向下滚动步长
    container.scrollTop += scrollStep;

    // 滚动到底部时，重置为0（循环滚动）
    // 加1是为了兼容像素精度问题
    if (projectList.scrollHeight - container.scrollTop <= container.clientHeight + 1) {
      container.scrollTop = 0; // 直接重置（也可以用平滑滚动：container.scrollTo({ top: 0, behavior: 'smooth' })）
    }
  }, scrollInterval);
};

// 5. 暂停滚动
const pauseScroll = (containerKey: number) => {
  if (scrollTimers[containerKey]) {
    clearInterval(scrollTimers[containerKey]!);
    scrollTimers[containerKey] = null;
  }
};

// 6. 恢复滚动
const resumeScroll = (containerKey: number) => {
  autoScroll(containerKey);
};

// 7. 组件卸载时清除所有定时器
onUnmounted(() => {
  Object.keys(scrollTimers).forEach(key => {
    const k = Number(key);
    if (scrollTimers[k]) {
      clearInterval(scrollTimers[k]!);
      scrollTimers[k] = null;
    }
  });
});

// 8. 格式化粉丝数（82738 → 82.7K）
const formatFollowers = (num: number) => {
  if (num >= 1000) {
    return (num / 1000).toFixed(1) + 'K';
  }
  return num.toString();
};

// 9. 图片加载失败处理
const handleImageError = (e: Event) => {
  const target = e.target as HTMLImageElement;
  const name = target.alt;
  target.style.display = 'none';
  if (target.parentElement) {
    target.parentElement.innerHTML = `<span class="avatar-text">${name.slice(0, 1)}</span>`;
  }
};

// 10. 企业排名相关方法
const getRankClass = (rank: number) => {
  if (rank === 1) return 'gold';
  if (rank === 2) return 'silver';
  if (rank === 3) return 'bronze';
  return 'normal';
};

const getRankText = (rank: number) => {
  if (rank <= 3) return rank.toString();
  return rank.toString().padStart(2, '0');
};

const getScoreClass = (score: number) => {
  if (score >= 90) return 'score-blue';        // 90+ 蓝色
  if (score >= 80) return 'score-light-blue';  // 80-89 浅蓝色
  if (score >= 70) return 'score-green';       // 70-79 绿色
  return 'score-red';                          // 60-69 红色
};

const getScoreBarClass = (score: number) => {
  if (score >= 90) return 'bar-blue';          // 90+ 蓝色
  if (score >= 80) return 'bar-light-blue';    // 80-89 浅蓝色
  if (score >= 70) return 'bar-green';         // 70-79 绿色
  return 'bar-red';                            // 60-69 红色
};

const getCountryFlag = (country: string) => {
  const countryMap: { [key: string]: string } = {
    'China': '🇨🇳',
    'USA': '🇺🇸',
    'Belgium': '🇧🇪',
    'Portugal': '🇵🇹',
    'Germany': '🇩🇪',
    'Russia': '🇷🇺'
  };
  return countryMap[country] || country;
};

const formatDevs = (num: number) => {
  if (num >= 10000) {
    return (num / 1000).toFixed(1) + 'K';
  }
  if (num >= 1000) {
    return (num / 1000).toFixed(1) + 'K';
  }
  return num.toString();
};
// ===================== 新增结束 =====================

// 根据增长率动态生成颜色的函数
const getColorByGrowth = (growth: number, tab: string) => {
  const minGrowth = -5;
  const maxGrowth = tab === 'mainstream' ? 10 : 30;
  const normalized = Math.max(0, Math.min(1, (growth - minGrowth) / (maxGrowth - minGrowth)));

  const colorStops = [
    { pos: 0, color: '#0063D0' },
    { pos: 0.2, color: '#0081FF' },
    { pos: 0.4, color: '#00A0FF' },
    { pos: 0.6, color: '#00C0FF' },
    { pos: 0.8, color: '#00E0FF' },
    { pos: 1, color: '#00F2FF' }
  ];

  let startColor = colorStops[0].color;
  let endColor = colorStops[0].color;
  let localPos = 0;

  for (let i = 0; i < colorStops.length - 1; i++) {
    if (normalized >= colorStops[i].pos && normalized <= colorStops[i + 1].pos) {
      startColor = colorStops[i].color;
      endColor = colorStops[i + 1].color;
      localPos = (normalized - colorStops[i].pos) / (colorStops[i + 1].pos - colorStops[i].pos);
      break;
    }
  }

  const interpolateColor = (color1: string, color2: string, factor: number) => {
    const c1 = parseInt(color1.slice(1), 16);
    const c2 = parseInt(color2.slice(1), 16);
    const r1 = (c1 >> 16) & 0xff, g1 = (c1 >> 8) & 0xff, b1 = c1 & 0xff;
    const r2 = (c2 >> 16) & 0xff, g2 = (c2 >> 8) & 0xff, b2 = c2 & 0xff;
    const r = Math.round(r1 + (r2 - r1) * factor);
    const g = Math.round(g1 + (g2 - g1) * factor);
    const b = Math.round(b1 + (b2 - b1) * factor);
    return `#${((r << 16) | (g << 8) | b).toString(16).padStart(6, '0')}`;
  };

  const topColor = interpolateColor(startColor, endColor, localPos);

  return new echarts.graphic.LinearGradient(0, 0, 0, 1, [
    { offset: 0, color: topColor },
    { offset: 1, color: startColor }
  ]);
};

// 初始化语言与技术竞争（南丁格尔玫瑰图）
const initLanguageTechChart = () => {
  const el = document.getElementById('languageTechChart');
  if (!el) return;

  if (chartInstances.value.languageTechChart) {
    chartInstances.value.languageTechChart.dispose();
  }

  const myChart = echarts.init(el);
  chartInstances.value.languageTechChart = myChart;

  const currentData = languageTab.value === 'mainstream'
    ? chartData.value.languageTech.mainstream
    : chartData.value.languageTech.emerging;

  myChart.setOption({
    graphic: {
      elements: [
        // 中心发光圆
        {
          type: 'circle',
          z: 0,
          shape: { cx: '48%', cy: '54%', r: '21%' },
          style: {
            fill: {
              type: 'radial',
              x: 0.5,
              y: 0.5,
              r: 0.5,
              colorStops: [
                { offset: 0, color: 'rgba(59, 130, 246, 0.15)' },
                { offset: 0.7, color: 'rgba(59, 130, 246, 0.05)' },
                { offset: 1, color: 'rgba(59, 130, 246, 0)' }
              ]
            },
            stroke: 'rgba(59, 130, 246, 0.4)',
            lineWidth: 2,
            shadowBlur: 10,
            shadowColor: 'rgba(59, 130, 246, 0.3)'
          }
        },
        // 中间虚线圆
        {
          type: 'circle',
          z: 0,
          shape: { cx: '48%', cy: '54%', r: '50%' },
          style: {
            stroke: 'rgba(139, 92, 246, 0.2)',
            lineWidth: 1.5,
            lineDash: [8, 4]
          }
        },
        // 外层虚线圆
        {
          type: 'circle',
          z: 0,
          shape: { cx: '48%', cy: '54%', r: '80%' },
          style: {
            stroke: 'rgba(236, 72, 153, 0.15)',
            lineWidth: 1,
            lineDash: [5, 5]
          }
        },
        // 装饰性小圆点（12点钟方向）
        {
          type: 'circle',
          z: 1,
          shape: { cx: '48%', cy: '12%', r: 4 },
          style: {
            fill: '#3b82f6',
            shadowBlur: 8,
            shadowColor: 'rgba(59, 130, 246, 0.6)'
          }
        },
        // 装饰性小圆点（3点钟方向）
        {
          type: 'circle',
          z: 1,
          shape: { cx: '88%', cy: '54%', r: 3 },
          style: {
            fill: '#8b5cf6',
            shadowBlur: 6,
            shadowColor: 'rgba(139, 92, 246, 0.6)'
          }
        },
        // 装饰性小圆点（6点钟方向）
        {
          type: 'circle',
          z: 1,
          shape: { cx: '48%', cy: '96%', r: 3 },
          style: {
            fill: '#ec4899',
            shadowBlur: 6,
            shadowColor: 'rgba(236, 72, 153, 0.6)'
          }
        },
        // 装饰性小圆点（9点钟方向）
        {
          type: 'circle',
          z: 1,
          shape: { cx: '8%', cy: '54%', r: 3 },
          style: {
            fill: '#10b981',
            shadowBlur: 6,
            shadowColor: 'rgba(16, 185, 129, 0.6)'
          }
        }
      ]
    },
    tooltip: {
      trigger: 'item',
      backgroundColor: 'rgba(255, 255, 255, 0.95)',
      borderColor: '#3b82f6',
      borderWidth: 1,
      borderRadius: 6,
      padding: 10,
      textStyle: { color: '#333', fontSize: 13 },
      formatter: (params: any) => `
        <div style="line-height: 1.8;">
          <div style="font-weight: bold; color: #3b82f6;">${params.name}</div>
          <div>市场占比：<span style="color: #10b981;">${params.value}%</span></div>
          <div>增长率：<span style="color: #f59e0b;">${params.data.growth}%</span></div>
        </div>
      `
    },
    visualMap: {
      show: true,
      type: 'continuous',
      min: -5,
      max: languageTab.value === 'mainstream' ? 10 : 30,
      dimension: 2,
      orient: 'vertical',
      itemWidth: 14,
      itemHeight: 90,
      text: ['高增长', '低增长'],
      textStyle: { color: '#333', fontSize: 11, fontWeight: '600' },
      inRange: { color: ['#0063D0', '#00F2FF'] },
      right: '2%',
      top: '0%',
      borderColor: 'rgba(59, 130, 246, 0.3)',
      borderWidth: 2,
      backgroundColor: 'rgba(255, 255, 255, 0.95)',
      padding: 8,
      borderRadius: 8,
      shadowBlur: 10,
      shadowColor: 'rgba(0, 0, 0, 0.1)'
    },
    polar: {
      radius: ['25%', '78%'],
      center: ['48%', '54%'],
      axisLine: { show: false },
      splitLine: {
        show: true,
        lineStyle: { color: 'rgba(0,0,0,0.05)', type: 'dashed' }
      }
    },
    angleAxis: {
      type: 'category',
      data: currentData.map(item => item.name),
      axisLine: { show: false },
      axisTick: { show: false },
      axisLabel: {
        color: '#333',
        fontSize: 13,
        fontWeight: '500',
        margin: 18,
        rotate: 0
      }
    },
    radiusAxis: {
      type: 'value',
      min: 0,
      max: Math.max(...currentData.map(item => item.value)) * 1.1,
      axisLine: { show: false },
      axisTick: { show: false },
      axisLabel: { show: false },
      splitLine: {
        show: true,
        lineStyle: { color: 'rgba(0,0,0,0.08)', type: 'dashed' }
      }
    },
    series: [
      {
        name: '语言占比',
        type: 'bar',
        coordinateSystem: 'polar',
        data: currentData.map((item, index) => {
          const baseColor = getColorByGrowth(item.growth, languageTab.value);
          // 为每个花瓣添加独特的渐变效果
          const gradientColor = new echarts.graphic.LinearGradient(0, 0, 0, 1, [
            { offset: 0, color: baseColor.colorStops[0].color },
            { offset: 0.5, color: baseColor.colorStops[0].color },
            { offset: 1, color: baseColor.colorStops[1].color }
          ]);

          return {
            value: item.value,
            growth: item.growth,
            itemStyle: {
              color: gradientColor,
              borderRadius: [18, 18, 0, 0],
              borderWidth: 2,
              borderColor: 'rgba(255, 255, 255, 0.4)',
              shadowBlur: 12,
              shadowColor: 'rgba(59, 130, 246, 0.4)',
              opacity: 0.95
            }
          };
        }),
        barWidth: '35%',
        barGap: '-15%',
        label: {
          show: true,
          position: 'inside',
          color: '#FFFFFF',
          fontSize: 13,
          fontWeight: 'bold',
          formatter: '{c}%',
          distance: 5
        },
        emphasis: {
          itemStyle: {
            shadowBlur: 25,
            shadowColor: 'rgba(59, 130, 246, 0.8)',
            borderWidth: 3,
            borderColor: 'rgba(255, 255, 255, 0.6)',
            opacity: 1
          },
          label: {
            fontSize: 15,
            fontWeight: 'bold',
            color: '#FFFFFF',
            textShadowBlur: 4,
            textShadowColor: 'rgba(0, 0, 0, 0.5)'
          }
        },
        // 添加动画效果
        animationType: 'scale',
        animationEasing: 'elasticOut',
        animationDelay: (idx: number) => idx * 100
      }
    ]
  });
};

// 切换语言Tab
const changeLanguageTab = () => {
  languageTab.value = languageTab.value === 'mainstream' ? 'emerging' : 'mainstream';
  initLanguageTechChart();
};



// 初始化开源项目热力图
const initHeatmapChart = () => {
  const el = document.getElementById('heatmapChart');
  if (!el) return;

  if (chartInstances.value.heatmapChart) {
    chartInstances.value.heatmapChart.dispose();
  }

  const myChart = echarts.init(el);
  chartInstances.value.heatmapChart = myChart;

  myChart.setOption({
    tooltip: {
      trigger: 'item',
      backgroundColor: 'rgba(255, 255, 255, 0.98)',
      borderColor: '#3b82f6',
      borderWidth: 2,
      borderRadius: 10,
      padding: 18,
      textStyle: { color: '#333', fontSize: 13 },
      extraCssText: 'box-shadow: 0 8px 24px rgba(59, 130, 246, 0.25);',
      formatter: (params: any) => {
        const data = params.data.value;
        const name = data[3];
        const org = data[4];
        const openrank = data[0].toLocaleString();
        const repos = data[1].toLocaleString();
        const devs = data[2].toLocaleString();

        // 计算排名
        const sorted = [...heatmapData.value].sort((a, b) => b[0] - a[0]);
        const rank = sorted.findIndex(item => item[3] === name) + 1;

        return `
          <div style="line-height: 2.2;">
            <div style="display: flex; align-items: center; justify-content: space-between; margin-bottom: 10px;">
              <div style="font-weight: bold; color: #3b82f6; font-size: 16px;">${name}</div>
              <div style="background: linear-gradient(135deg, #3b82f6, #8b5cf6); color: #fff; padding: 2px 10px; border-radius: 12px; font-size: 11px; font-weight: 600;">TOP ${rank}</div>
            </div>
            <div style="border-bottom: 2px solid #3b82f6; margin-bottom: 10px; opacity: 0.3;"></div>
            <div style="display: flex; align-items: center; gap: 10px; margin-bottom: 6px;">
              <span style="display: inline-block; width: 10px; height: 10px; background: linear-gradient(135deg, #f59e0b, #fbbf24); border-radius: 50%; box-shadow: 0 2px 4px rgba(245, 158, 11, 0.3);"></span>
              <span style="color: #666; min-width: 80px;">所属组织</span>
              <span style="color: #f59e0b; font-weight: 700;">${org}</span>
            </div>
            <div style="display: flex; align-items: center; gap: 10px; margin-bottom: 6px;">
              <span style="display: inline-block; width: 10px; height: 10px; background: linear-gradient(135deg, #3b82f6, #60a5fa); border-radius: 50%; box-shadow: 0 2px 4px rgba(59, 130, 246, 0.3);"></span>
              <span style="color: #666; min-width: 80px;">OpenRank</span>
              <span style="color: #3b82f6; font-weight: 700; font-size: 14px;">${openrank}</span>
            </div>
            <div style="display: flex; align-items: center; gap: 10px; margin-bottom: 6px;">
              <span style="display: inline-block; width: 10px; height: 10px; background: linear-gradient(135deg, #8b5cf6, #a78bfa); border-radius: 50%; box-shadow: 0 2px 4px rgba(139, 92, 246, 0.3);"></span>
              <span style="color: #666; min-width: 80px;">活跃仓库</span>
              <span style="color: #8b5cf6; font-weight: 700; font-size: 14px;">${repos}</span>
            </div>
            <div style="display: flex; align-items: center; gap: 10px;">
              <span style="display: inline-block; width: 10px; height: 10px; background: linear-gradient(135deg, #10b981, #34d399); border-radius: 50%; box-shadow: 0 2px 4px rgba(16, 185, 129, 0.3);"></span>
              <span style="color: #666; min-width: 80px;">活跃开发者</span>
              <span style="color: #10b981; font-weight: 700; font-size: 14px;">${devs}</span>
            </div>
          </div>
        `;
      }
    },
    visualMap: {
      min: 0,
      max: 9000,
      dimension: 2,
      orient: 'vertical',
      right: '2%',
      top: 'center',
      itemWidth: 18,
      itemHeight: 140,
      text: ['🔥 热门', '❄️ 冷门'],
      calculable: true,
      inRange: {
        color: ['#FF4900', '#FFAB00', '#00B03E', '#00C0FF', '#00F0FF']
      },
      textStyle: {
        color: '#333',
        fontSize: 13,
        fontWeight: '600'
      },
      borderColor: 'rgba(59, 130, 246, 0.3)',
      borderWidth: 2,
      backgroundColor: 'rgba(255, 255, 255, 0.95)',
      padding: 12,
      borderRadius: 8,
      shadowBlur: 10,
      shadowColor: 'rgba(0, 0, 0, 0.1)'
    },
    grid: {
      top: '8%',
      left: '8%',
      right: '16%',
      bottom: '10%',
      containLabel: true
    },
    xAxis: {
      type: 'value',
      name: 'OpenRank 影响力指数',
      nameLocation: 'center',
      nameGap: 35,
      min: 1000,
      max: 70000,
      nameTextStyle: {
        color: '#3b82f6',
        fontSize: 14,
        fontWeight: '700'
      },
      axisLine: {
        lineStyle: {
          color: '#3b82f6',
          width: 2,
          shadowBlur: 4,
          shadowColor: 'rgba(59, 130, 246, 0.3)'
        }
      },
      axisLabel: {
        color: '#666',
        fontSize: 12,
        fontWeight: '600',
        formatter: (value: number) => {
          if (value >= 1000) {
            return (value / 1000).toFixed(0) + 'k';
          }
          return value;
        }
      },
      splitLine: {
        show: true,
        lineStyle: {
          color: 'rgba(59, 130, 246, 0.1)',
          type: 'dashed',
          width: 1
        }
      }
    },
    yAxis: {
      type: 'value',
      name: '活跃仓库数量',
      nameLocation: 'center',
      nameGap: 45,
      min: 0,
      max: 30000,
      nameTextStyle: {
        color: '#8b5cf6',
        fontSize: 14,
        fontWeight: '700'
      },
      axisLine: {
        lineStyle: {
          color: '#8b5cf6',
          width: 2,
          shadowBlur: 4,
          shadowColor: 'rgba(139, 92, 246, 0.3)'
        }
      },
      axisLabel: {
        color: '#666',
        fontSize: 12,
        fontWeight: '600',
        formatter: (value: number) => {
          if (value >= 1000) {
            return (value / 1000).toFixed(0) + 'k';
          }
          return value;
        }
      },
      splitLine: {
        show: true,
        lineStyle: {
          color: 'rgba(139, 92, 246, 0.1)',
          type: 'dashed',
          width: 1
        }
      }
    },
    series: [
      {
        name: '开源项目',
        type: 'scatter',
        data: heatmapData.value.map(item => ({
          value: item,
          name: item[3]
        })),
        symbolSize: (data: any) => {
          const devs = data[2];
          return Math.log(devs + 1) * 4 + 10;
        },
        itemStyle: {
          opacity: 0.9,
          shadowBlur: 15,
          shadowColor: 'rgba(59, 130, 246, 0.5)',
          borderWidth: 2.5,
          borderColor: 'rgba(255, 255, 255, 0.8)'
        },
        label: {
          show: true,
          formatter: (params: any) => {
            const openrank = params.value[0];
            const repos = params.value[1];
            const devs = params.value[2];

            // 如果开启显示全部，则显示所有标签
            if (showAllLabels.value) {
              return params.value[3];
            }

            // 否则只显示重要项目：OpenRank > 15000 或 开发者数 > 3000 或 仓库数 > 10000
            if (openrank > 15000 || devs > 3000 || repos > 10000) {
              return params.value[3];
            }
            return '';
          },
          position: (pos: any, params: any, dom: any, rect: any, size: any) => {
            // 智能定位：根据位置自动调整标签方向，避免重叠
            const x = pos[0];
            const y = pos[1];
            const viewWidth = size.viewSize[0];
            const viewHeight = size.viewSize[1];

            // 右上区域：标签在上方
            if (x > viewWidth * 0.6 && y < viewHeight * 0.4) {
              return 'top';
            }
            // 右下区域：标签在右侧
            if (x > viewWidth * 0.6 && y > viewHeight * 0.6) {
              return 'right';
            }
            // 左上区域：标签在左侧
            if (x < viewWidth * 0.4 && y < viewHeight * 0.4) {
              return 'left';
            }
            // 左下区域：标签在下方
            if (x < viewWidth * 0.4 && y > viewHeight * 0.6) {
              return 'bottom';
            }
            // 默认在上方
            return 'top';
          },
          color: '#1e293b',
          fontSize: 10,
          fontWeight: 'bold',
          backgroundColor: 'rgba(255, 255, 255, 0.95)',
          padding: [3, 7],
          borderRadius: 5,
          borderWidth: 1.5,
          borderColor: 'rgba(59, 130, 246, 0.4)',
          shadowBlur: 6,
          shadowColor: 'rgba(0, 0, 0, 0.1)',
          distance: 8
        },
        labelLayout: {
          // 标签避让配置
          hideOverlap: true,
          moveOverlap: 'shiftY',
          draggable: false
        },
        emphasis: {
          focus: 'self',
          itemStyle: {
            shadowBlur: 25,
            shadowColor: 'rgba(59, 130, 246, 0.9)',
            borderWidth: 4,
            borderColor: '#fff',
            opacity: 1
          },
          label: {
            show: true,
            fontSize: 12,
            fontWeight: 'bold',
            backgroundColor: 'rgba(59, 130, 246, 0.98)',
            color: '#fff',
            borderColor: '#3b82f6',
            borderWidth: 2,
            padding: [5, 9],
            shadowBlur: 10,
            shadowColor: 'rgba(59, 130, 246, 0.5)',
            distance: 10
          }
        },
        animationType: 'scale',
        animationEasing: 'elasticOut',
        animationDelay: (idx: number) => idx * 40
      }
    ]
  });
};

// 统一初始化图表
const initCharts = () => {
  // 空数据判断
  isEmpty.value = {
    languageTech: chartData.value.languageTech.mainstream.length === 0 && chartData.value.languageTech.emerging.length === 0
  };

  // 初始化各图表
  if (!isEmpty.value.languageTech) nextTick(() => initLanguageTechChart());
  nextTick(() => initHeatmapChart());
};

// 页面resize时重绘图表
watch(widthType, () => {
  initCharts();
  // 重新启动滚动（防止resize后滚动失效）
  autoScroll(1);
  autoScroll(2);
});

// 挂载时初始化
onMounted(() => {
  setTimeout(() => {
    initCharts();
    // 启动列表自动滚动
    autoScroll(1);
    autoScroll(2);
  }, 100);
});
</script>

<style lang="scss" scoped>
.index-module__NV_5cW__container {
  //background: linear-gradient(to bottom right, #faf5ff, #60a5fa);
  min-height: 100vh;
  padding: 2rem 1rem;
  position: relative;
  overflow-x: hidden;
  animation: fadeIn 0.6s ease-out;
}

@keyframes fadeIn {
  from {
    opacity: 0;
  }

  to {
    opacity: 1;
  }
}

.index-module__NV_5cW__header {
  width: 1400px;
  text-align: center;
  padding: 1rem;
  position: relative;
  margin: 0 auto 3rem;
}

.index-module__NV_5cW__floatingElements {
  pointer-events: none;
  opacity: 0.3;
  position: absolute;
  inset: 0;
  overflow: hidden;
}

.index-module__NV_5cW__floatingElement {
  background: linear-gradient(135deg, #3b82f60d, #9333ea0d);
  border-radius: 50%;
  width: 120px;
  height: 120px;
  animation: 30s linear infinite index-module__NV_5cW__float;
  position: absolute;
}

.index-module__NV_5cW__floatingElement:first-child {
  animation-delay: 0s;
  top: 10%;
  left: 10%;
}

.index-module__NV_5cW__floatingElement:nth-child(2) {
  animation-delay: -7s;
  top: 60%;
  right: 10%;
}

.index-module__NV_5cW__floatingElement:nth-child(3) {
  animation-delay: -14s;
  bottom: 20%;
  left: 50%;
}

@keyframes index-module__NV_5cW__float {
  0% {
    transform: translateY(0) rotate(0);
  }

  33% {
    transform: translateY(-20px) rotate(120deg);
  }

  66% {
    transform: translateY(10px) rotate(240deg);
  }

  to {
    transform: translateY(0) rotate(360deg);
  }
}

.index-module__NV_5cW__titleSection {
  color: #333;
  z-index: 2;
  flex-direction: column;
  align-items: center;
  gap: 1rem;
  display: flex;
  position: relative;
}

.index-module__NV_5cW__titleContainer {
  flex-wrap: wrap;
  justify-content: center;
  align-items: center;
  gap: 1rem;
  display: flex;
}

.index-module__NV_5cW__title {
  background: #333;
  -webkit-text-fill-color: transparent;
  letter-spacing: -0.02em;
  white-space: nowrap;
  -webkit-background-clip: text;
  background-clip: text;
  margin: 0;
  font-size: 2.8rem;
  font-weight: 700;
}

.index-module__NV_5cW__titleBadge {
  color: #fff;
  letter-spacing: 0.05em;
  white-space: nowrap;
  background: #60a5fa;
  border-radius: 1.5rem;
  padding: 0.4rem 1rem;
  font-size: 1rem;
  font-weight: 600;
  box-shadow: 0 2px 10px #3b82f64d;
}

.index-module__NV_5cW__subtitle {
  color: #666;
  text-align: center;
  align-items: center;
  gap: 0.5rem;
  max-width: 500px;
  font-size: 1.1rem;
  font-weight: 400;
  display: flex;
}

.index-module__NV_5cW__statsBar {
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
  background: #ffffff1a;
  border: 1px solid #fff3;
  border-radius: 1.5rem;
  align-items: center;
  gap: 1.5rem;
  width: fit-content;
  max-width: 90%;
  margin-top: 0.75rem;
  padding: 0.75rem 1.5rem;
  display: flex;
}

.index-module__NV_5cW__stat {
  flex-direction: column;
  align-items: center;
  gap: 0.25rem;
  display: flex;
}

.index-module__NV_5cW__statNumber {
  color: #60a5fa;
  font-size: 1.5rem;
  font-weight: 700;
}

.index-module__NV_5cW__statLabel {
  color: #333;
  font-size: 0.875rem;
  font-weight: 500;
}

.index-module__NV_5cW__statDivider {
  background: #fff3;
  width: 1px;
  height: 2rem;
}

.index-module__NV_5cW__content {
  max-width: 1400px;
  /* 加宽容器，适配更多图表 */
  margin: 0 auto;
  padding: 0 1rem;
}

/* 图表区域样式（适配示例的num-empty） */
.index-module__NV_5cW__chartsSection {
  margin-bottom: 3rem;
}

.index-module__NV_5cW__chartsGrid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(350px, 1fr));
  /* 调整列宽，适配列表 */
  gap: 1.5rem;
  padding: 0;
}

.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.5rem;
  box-shadow: 0 4px 16px #00000014;
  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.list-card {
  padding: 1.5rem;
}

.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__wide {
  grid-column: 1 / -1;
  /* 跨列显示 */
}

.chartCard__header {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  margin-bottom: 1rem;
  gap: 0.75rem;
}

.title-with-stats {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.5rem;
  width: 100%;
}

.chartCard__title {
  color: #333;
  font-size: 1.1rem;
  font-weight: 600;
  margin: 0;
  text-align: center;
  width: 100%;
}

.enterprise-stats {
  display: flex;
  gap: 0.5rem;
  align-items: center;
  animation: fadeInDown 0.5s ease-out;
}

@keyframes fadeInDown {
  from {
    opacity: 0;
    transform: translateY(-10px);
  }

  to {
    opacity: 1;
    transform: translateY(0);
  }
}

.stat-badge {
  padding: 0.25rem 0.75rem;
  background: linear-gradient(135deg, #eff6ff 0%, #dbeafe 100%);
  border: 1px solid rgba(59, 130, 246, 0.2);
  border-radius: 1rem;
  font-size: 0.75rem;
  font-weight: 600;
  color: #3b82f6;
  white-space: nowrap;
}

.language-tab {
  display: flex;
  gap: 0.5rem;
  background: linear-gradient(135deg, #f0f4ff, #faf5ff);
  border-radius: 1rem;
  padding: 0.3rem;
  cursor: pointer;
  user-select: none;
  box-shadow: 0 2px 8px rgba(59, 130, 246, 0.1);
  border: 1px solid rgba(59, 130, 246, 0.1);
  transition: all 0.3s;
}

.language-tab:hover {
  box-shadow: 0 4px 12px rgba(59, 130, 246, 0.15);
  border-color: rgba(59, 130, 246, 0.2);
}

.language-tab span {
  padding: 0.45rem 1.2rem;
  border-radius: 0.75rem;
  font-size: 0.875rem;
  font-weight: 600;
  color: #666;
  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
  position: relative;
  overflow: hidden;
}

.language-tab span::before {
  content: '';
  position: absolute;
  top: 50%;
  left: 50%;
  width: 0;
  height: 0;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.3);
  transform: translate(-50%, -50%);
  transition: width 0.6s, height 0.6s;
}

.language-tab span:hover::before {
  width: 100%;
  height: 100%;
}

.language-tab span.active {
  background: linear-gradient(135deg, #3b82f6, #8b5cf6);
  color: #fff;
  box-shadow: 0 4px 12px rgba(59, 130, 246, 0.4);
  transform: translateY(-1px);
}

.language-tab span.active::after {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background: linear-gradient(135deg, rgba(255, 255, 255, 0.2), transparent);
  border-radius: 0.75rem;
}

/* 企业筛选器样式 */
.enterprise-filter {
  display: flex;
  gap: 0.4rem;
  background: linear-gradient(135deg, #f0f4ff, #faf5ff);
  border-radius: 1rem;
  padding: 0.25rem;
  cursor: pointer;
  user-select: none;
  box-shadow: 0 2px 8px rgba(59, 130, 246, 0.1);
  border: 1px solid rgba(59, 130, 246, 0.1);
  transition: all 0.3s;
}

.enterprise-filter:hover {
  box-shadow: 0 4px 12px rgba(59, 130, 246, 0.15);
  border-color: rgba(59, 130, 246, 0.2);
}

.filter-tag {
  padding: 0.35rem 0.9rem;
  border-radius: 0.75rem;
  font-size: 0.8rem;
  font-weight: 600;
  color: #666;
  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
  position: relative;
  overflow: hidden;
  cursor: pointer;
}

.filter-tag::before {
  content: '';
  position: absolute;
  top: 50%;
  left: 50%;
  width: 0;
  height: 0;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.3);
  transform: translate(-50%, -50%);
  transition: width 0.6s, height 0.6s;
}

.filter-tag:hover::before {
  width: 100%;
  height: 100%;
}

.filter-tag.active {
  background: linear-gradient(135deg, #3b82f6, #8b5cf6);
  color: #fff;
  box-shadow: 0 4px 12px rgba(59, 130, 246, 0.4);
  transform: translateY(-1px);
}

.filter-tag.active::after {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background: linear-gradient(135deg, rgba(255, 255, 255, 0.2), transparent);
  border-radius: 0.75rem;
}

.chartCard__container {
  width: 100%;
  height: 390px;
  position: relative;
  overflow: hidden;
}

/* 为语言图表添加特殊背景 */
.chartCard__wide .chartCard__container {
  background: linear-gradient(135deg,
      rgba(59, 130, 246, 0.02) 0%,
      rgba(139, 92, 246, 0.02) 50%,
      rgba(236, 72, 153, 0.02) 100%);
  border-radius: 0.5rem;
}

/* 列表容器样式：隐藏原生滚动条（可选，视觉更美观） */
.list-container {
  height: auto;
  max-height: 300px;
  /* 限制列表高度，超出滚动 */
  overflow-y: auto;
  padding: 0 0.5rem;
  /* 隐藏滚动条 */
  scrollbar-width: none;
  /* Firefox */
  -ms-overflow-style: none;
  /* IE/Edge */
  position: relative;
}

/* 隐藏webkit内核浏览器的滚动条 */
.chartCard__container.list-container::-webkit-scrollbar {
  display: none;
}

/* 滚动指示器 */
.scroll-indicator {
  position: absolute;
  top: 0;
  right: 0;
  display: flex;
  align-items: center;
  gap: 0.25rem;
  padding: 0.25rem 0.5rem;
  background: rgba(59, 130, 246, 0.1);
  border-radius: 0 0 0 0.5rem;
  font-size: 0.7rem;
  color: #3b82f6;
  z-index: 10;
  animation: bounce 2s ease-in-out infinite;
}

@keyframes bounce {

  0%,
  100% {
    transform: translateY(0);
  }

  50% {
    transform: translateY(3px);
  }
}

.scroll-indicator svg {
  width: 12px;
  height: 12px;
}

/* 项目列表样式 */
.project-list {
  display: flex;
  flex-direction: column;
  gap: 0.8rem;
}

.project-item {
  display: flex;
  align-items: center;
  gap: 1rem;
  padding: 0.8rem;
  background: #f8f9fa;
  border-radius: 0.5rem;
  border-left: 3px solid #2951E0;
  transition: all 0.2s;
}

/* 鼠标悬停项目项时的样式（可选） */
.project-item:hover {
  background: #f0f4ff;
  transform: translateX(2px);
}

.project-rank {
  width: 24px;
  height: 24px;
  border-radius: 50%;
  background: #2951E0;
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 12px;
  font-weight: 600;
  flex-shrink: 0;
}

.project-info {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
}

.project-name {
  font-size: 14px;
  font-weight: 600;
  color: #333;
}

.project-desc {
  font-size: 12px;
  color: #666;
  font-style: italic;
}

.project-org {
  font-size: 12px;
  color: #888;
  flex-shrink: 0;
  white-space: nowrap;
  max-width: 150px;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* 企业列表特殊样式 */
.enterprise-list {
  gap: 0.6rem;
}

.enterprise-item {
  background: linear-gradient(135deg, #ffffff 0%, #f8f9fa 100%);
  border-left: 3px solid #3b82f6;
  padding: 0.75rem 1rem;
  gap: 0.75rem;
  align-items: center;
  position: relative;
  overflow: hidden;
  animation: slideInRight 0.3s ease-out backwards;
}

@keyframes slideInRight {
  from {
    opacity: 0;
    transform: translateX(-20px);
  }

  to {
    opacity: 1;
    transform: translateX(0);
  }
}

.enterprise-item:nth-child(1) {
  animation-delay: 0.05s;
}

.enterprise-item:nth-child(2) {
  animation-delay: 0.1s;
}

.enterprise-item:nth-child(3) {
  animation-delay: 0.15s;
}

.enterprise-item:nth-child(4) {
  animation-delay: 0.2s;
}

.enterprise-item:nth-child(5) {
  animation-delay: 0.25s;
}

.enterprise-item::before {
  content: '';
  position: absolute;
  top: 0;
  left: -100%;
  width: 100%;
  height: 100%;
  background: linear-gradient(90deg, transparent, rgba(59, 130, 246, 0.1), transparent);
  transition: left 0.5s;
}

.enterprise-item:hover::before {
  left: 100%;
}

.enterprise-item:hover {
  background: linear-gradient(135deg, #f0f4ff 0%, #eff6ff 100%);
  border-left-color: #2563eb;
  box-shadow: 0 2px 8px rgba(59, 130, 246, 0.15);
  transform: translateX(3px);
}

.enterprise-rank {
  width: 32px;
  height: 24px;
  border-radius: 6px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 13px;
  font-weight: 700;
  flex-shrink: 0;
  font-family: 'DIN Alternate', 'Arial', sans-serif;
}

.enterprise-rank.gold {
  background: linear-gradient(135deg, #FFD700 0%, #FFA500 100%);
  color: #2c3e50;
  box-shadow: 0 2px 8px rgba(255, 215, 0, 0.4);
}

.enterprise-rank.silver {
  background: linear-gradient(135deg, #E8E8E8 0%, #C0C0C0 100%);
  color: #2c3e50;
  box-shadow: 0 2px 6px rgba(192, 192, 192, 0.4);
}

.enterprise-rank.bronze {
  background: linear-gradient(135deg, #CD7F32 0%, #B8733C 100%);
  color: #fff;
  box-shadow: 0 2px 6px rgba(205, 127, 50, 0.4);
}

.enterprise-rank.normal {
  background: linear-gradient(135deg, #3b82f6 0%, #2563eb 100%);
  color: #fff;
}

.enterprise-info {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  min-width: 0;
}

.enterprise-name {
  font-size: 14px;
  font-weight: 700;
  color: #1e293b;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.enterprise-meta {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-size: 11px;
  color: #64748b;
}

.meta-item {
  display: flex;
  align-items: center;
  gap: 2px;
}

.meta-devs {
  color: #8b5cf6;
  font-weight: 600;
}

.score-bar-container {
  width: 80px;
  height: 6px;
  background: rgba(0, 0, 0, 0.08);
  border-radius: 3px;
  overflow: hidden;
  flex-shrink: 0;
}

.score-bar {
  height: 100%;
  border-radius: 3px;
  transition: width 0.5s ease-out;
}

.score-bar.bar-blue {
  background: linear-gradient(90deg, #2563eb 0%, #3b82f6 100%);
  box-shadow: 0 0 4px rgba(37, 99, 235, 0.5);
}

.score-bar.bar-light-blue {
  background: linear-gradient(90deg, #60a5fa 0%, #93c5fd 100%);
  box-shadow: 0 0 4px rgba(96, 165, 250, 0.4);
}

.score-bar.bar-green {
  background: linear-gradient(90deg, #10b981 0%, #34d399 100%);
  box-shadow: 0 0 4px rgba(16, 185, 129, 0.4);
}

.score-bar.bar-red {
  background: linear-gradient(90deg, #ef4444 0%, #f87171 100%);
  box-shadow: 0 0 4px rgba(239, 68, 68, 0.4);
}

.enterprise-score {
  font-family: 'DIN Alternate', 'Arial', sans-serif;
  font-size: 15px;
  font-weight: 700;
  width: 40px;
  text-align: right;
  flex-shrink: 0;
}

.enterprise-score.score-blue {
  color: #2563eb;
  text-shadow: 0 0 8px rgba(37, 99, 235, 0.3);
}

.enterprise-score.score-light-blue {
  color: #60a5fa;
  text-shadow: 0 0 6px rgba(96, 165, 250, 0.3);
}

.enterprise-score.score-green {
  color: #10b981;
  text-shadow: 0 0 6px rgba(16, 185, 129, 0.2);
}

.enterprise-score.score-red {
  color: #ef4444;
  text-shadow: 0 0 6px rgba(239, 68, 68, 0.3);
}

/* 明星开发者特殊样式 */
.developer-list-container {
  max-height: 400px;
  margin-top: 20px;
}

.developer-item {
  background: linear-gradient(135deg, #f8f9fa 0%, #ffffff 100%);
  border-left: 3px solid #3b82f6;
  padding: 0.75rem 1rem;
  gap: 0.75rem;
}

.developer-item:hover {
  background: linear-gradient(135deg, #eff6ff 0%, #f0f4ff 100%);
  border-left-color: #8b5cf6;
  box-shadow: 0 2px 8px rgba(59, 130, 246, 0.15);
}

.dev-avatar {
  width: 42px;
  height: 42px;
  border-radius: 50%;
  background: linear-gradient(135deg, #3b82f6 0%, #8b5cf6 100%);
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 2px 8px rgba(59, 130, 246, 0.3);
  overflow: hidden;
  flex-shrink: 0;
}

.avatar-img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.avatar-text {
  font-size: 16px;
  font-weight: bold;
  color: #fff;
}

.dev-rank {
  width: auto;
  height: auto;
  border-radius: 12px;
  background: linear-gradient(135deg, #ec4899 0%, #f59e0b 100%);
  padding: 3px 10px;
  font-size: 11px;
  font-weight: 700;
  box-shadow: 0 2px 6px rgba(236, 72, 153, 0.3);
}

.dev-info {
  flex: 1;
  gap: 0.3rem;
}

.dev-name {
  font-size: 15px;
  font-weight: 700;
  color: #1e293b;
}

.dev-location {
  font-size: 11px;
  color: #64748b;
  font-style: normal;
}

.dev-followers {
  display: flex;
  align-items: center;
  gap: 4px;
  padding: 4px 10px;
  border-radius: 12px;
  background: rgba(59, 130, 246, 0.1);
  border: 1px solid rgba(59, 130, 246, 0.2);
  color: #3b82f6;
  font-size: 12px;
  font-weight: 600;
  white-space: nowrap;
  max-width: none;
}

.dev-followers svg {
  flex-shrink: 0;
}

/* 与示例一致的空数据样式 */
.num-empty {
  height: 10px;
  border-top: 2px solid #2951E0;
  width: 100%;
  background: linear-gradient(180deg, rgba(41, 81, 224, 0.12) 0%, rgba(41, 81, 224, 0.04) 100%);
  position: absolute;
  top: 50%;
  left: 0;
  transform: translateY(-50%);
  animation: pulse 1.5s ease-in-out infinite;
}

@keyframes pulse {

  0%,
  100% {
    opacity: 1;
  }

  50% {
    opacity: 0.5;
  }
}

.chart {
  width: 100%;
  height: 100%;
}

.index-module__NV_5cW__sectionHeader {
  flex-wrap: wrap;
  justify-content: center;
  align-items: center;
  gap: 1rem;
  margin-bottom: 2rem;
  display: flex;
  position: relative;
}

.index-module__NV_5cW__sectionTitle {
  color: #333;
  text-align: center;
  justify-content: center;
  align-items: center;
  gap: 0.75rem;
  width: 100%;
  margin: 0;
  font-size: 1.5rem;
  font-weight: 600;
  display: flex;
}

.index-module__NV_5cW__vitalitySection {
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
  background: #ffffffe6;
  border: 1px solid #ffffff4d;
  border-radius: 1.5rem;
  margin-bottom: 2rem;
  padding: 2rem;
  box-shadow: 0 8px 24px #00000014;
  transition: all 0.3s;
}

.index-module__NV_5cW__vitalitySection:hover {
  border-color: #3b82f64d;
  transform: translateY(-2px);
  box-shadow: 0 12px 32px #0000001f;
}

.vitality__title {
  color: #333;
  font-size: 1.5rem;
  font-weight: 600;
  margin: 0 0 1.5rem 0;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.75rem;
  position: relative;
}

.vitality__title::before {
  content: '';
  position: absolute;
  bottom: -8px;
  left: 50%;
  transform: translateX(-50%);
  width: 60px;
  height: 3px;
  background: linear-gradient(90deg, #10b981, #f59e0b);
  border-radius: 2px;
}

.vitality__title svg {
  color: #10b981;
  animation: pulse 2s ease-in-out infinite;
}

@keyframes pulse {

  0%,
  100% {
    transform: scale(1);
  }

  50% {
    transform: scale(1.1);
  }
}

.vitality__container {
  width: 100%;
  height: 400px;
  position: relative;
  background: linear-gradient(135deg,
      rgba(16, 185, 129, 0.02) 0%,
      rgba(245, 158, 11, 0.02) 100%);
  border-radius: 0.75rem;
  padding: 1rem;
}

/* 地图区域样式（科技蓝风格） */
.map-section {
  position: relative;
  overflow: hidden;
  border: 2px solid rgba(0, 192, 255, 0.1);
  box-shadow: 0 4px 16px rgba(0, 192, 255, 0.1);
}

.map-section::before {
  content: '';
  position: absolute;
  top: -30%;
  left: -30%;
  width: 100%;
  height: 100%;
  background: radial-gradient(circle, rgba(0, 192, 255, 0.1) 0%, transparent 70%);
  animation: rotate 30s linear infinite;
  pointer-events: none;
}

/* 热力图特殊样式 */
.heatmap-section {
  position: relative;
  overflow: hidden;
}

.heatmap-section::before {
  content: '';
  position: absolute;
  top: -50%;
  right: -50%;
  width: 100%;
  height: 100%;
  background: radial-gradient(circle, rgba(59, 130, 246, 0.1) 0%, transparent 70%);
  animation: rotate 20s linear infinite;
  pointer-events: none;
}

@keyframes rotate {
  from {
    transform: rotate(0deg);
  }

  to {
    transform: rotate(360deg);
  }
}

.heatmap-header {
  display: flex;
  flex-direction: column;
  gap: 1.5rem;
  margin-bottom: 1.5rem;
}

.title-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
}

.label-toggle {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.5rem 1rem;
  background: linear-gradient(135deg, rgba(59, 130, 246, 0.1), rgba(139, 92, 246, 0.1));
  border: 2px solid rgba(59, 130, 246, 0.3);
  border-radius: 1.5rem;
  cursor: pointer;
  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
  user-select: none;
  font-size: 0.85rem;
  font-weight: 600;
  color: #3b82f6;
}

.label-toggle:hover {
  background: linear-gradient(135deg, rgba(59, 130, 246, 0.2), rgba(139, 92, 246, 0.2));
  border-color: rgba(59, 130, 246, 0.5);
  transform: translateY(-2px);
  box-shadow: 0 4px 12px rgba(59, 130, 246, 0.3);
}

.label-toggle:active {
  transform: translateY(0);
}

.label-toggle svg {
  width: 16px;
  height: 16px;
  transition: transform 0.3s;
}

.label-toggle:hover svg {
  transform: rotate(90deg);
}

.heatmap-stats {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 2rem;
  padding: 1rem 2rem;
  background: linear-gradient(135deg,
      rgba(255, 255, 255, 0.9) 0%,
      rgba(255, 255, 255, 0.7) 100%);
  border-radius: 1rem;
  border: 2px solid rgba(59, 130, 246, 0.2);
  box-shadow: 0 4px 12px rgba(59, 130, 246, 0.1);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
}

.stat-item {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.3rem;
}

.stat-value {
  font-size: 1.3rem;
  font-weight: 700;
  background: linear-gradient(135deg, #3b82f6, #8b5cf6);
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  background-clip: text;
}

.stat-label {
  font-size: 0.8rem;
  color: #666;
  font-weight: 500;
}

.stat-divider {
  width: 2px;
  height: 2.5rem;
  background: linear-gradient(to bottom,
      transparent 0%,
      rgba(59, 130, 246, 0.3) 50%,
      transparent 100%);
}

.heatmap-container {
  background: linear-gradient(135deg,
      rgba(59, 130, 246, 0.02) 0%,
      rgba(139, 92, 246, 0.02) 50%,
      rgba(236, 72, 153, 0.02) 100%);
  border: 1px solid rgba(59, 130, 246, 0.1);
  position: relative;
}

.heatmap-legend {
  position: absolute;
  top: 1rem;
  left: 1rem;
  display: flex;
  gap: 1.5rem;
  padding: 0.75rem 1.25rem;
  background: rgba(255, 255, 255, 0.95);
  border-radius: 1rem;
  border: 2px solid rgba(59, 130, 246, 0.2);
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
  z-index: 10;
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
}

.legend-item {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-size: 0.8rem;
  color: #666;
  font-weight: 600;
}

.legend-icon {
  border-radius: 50%;
  border: 2px solid rgba(255, 255, 255, 0.8);
  box-shadow: 0 2px 6px rgba(59, 130, 246, 0.3);
}

.bubble-small {
  width: 12px;
  height: 12px;
  background: linear-gradient(135deg, #FF4900, #FFAB00);
}

.bubble-medium {
  width: 18px;
  height: 18px;
  background: linear-gradient(135deg, #00B03E, #00C0FF);
}

.bubble-large {
  width: 24px;
  height: 24px;
  background: linear-gradient(135deg, #00C0FF, #00F0FF);
}

.index-module__NV_5cW__actionSection {
  text-align: center;
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
  background: #ffffffe6;
  border: 1px solid #ffffff4d;
  border-radius: 1.5rem;
  margin: 0;
  padding: 2.5rem 2rem;
  position: relative;
  overflow: hidden;
  box-shadow: 0 8px 24px #00000014;
}

.index-module__NV_5cW__actionBackground {
  z-index: 1;
  background: linear-gradient(135deg, #3b82f60d 0%, #9333ea0d 100%);
  position: absolute;
  inset: 0;
}

.index-module__NV_5cW__actionContent {
  z-index: 2;
  max-width: 600px;
  margin: 0 auto;
  position: relative;
}

.index-module__NV_5cW__actionIcon {
  color: #fff;
  background: linear-gradient(135deg, #3b82f6, #8b5cf6);
  border-radius: 50%;
  justify-content: center;
  align-items: center;
  width: 3rem;
  height: 3rem;
  margin: 0 auto 1.5rem;
  display: flex;
  box-shadow: 0 4px 12px #3b82f633;
}

.index-module__NV_5cW__actionTitle {
  background: linear-gradient(135deg, #1e293b 0%, #3b82f6 100%);
  -webkit-text-fill-color: transparent;
  -webkit-background-clip: text;
  background-clip: text;
  margin-bottom: 1rem;
  font-size: 2rem;
  font-weight: 700;
  line-height: 1.2;
}

.index-module__NV_5cW__actionDescription {
  color: #64748b;
  margin-bottom: 2rem;
  font-size: 1rem;
  font-weight: 400;
  line-height: 1.5;
}

.index-module__NV_5cW__actionFeatures {
  flex-wrap: wrap;
  justify-content: center;
  gap: 1.5rem;
  margin-bottom: 2rem;
  display: flex;
}

.index-module__NV_5cW__feature {
  color: #3b82f6;
  background: #3b82f614;
  border: 1px solid #3b82f626;
  border-radius: 1.5rem;
  align-items: center;
  gap: 0.4rem;
  padding: 0.5rem 1rem;
  font-size: 0.85rem;
  font-weight: 500;
  display: flex;
}

.index-module__NV_5cW__createButton {
  background: linear-gradient(135deg, #3b82f6 0%, #8b5cf6 100%);
  border: none;
  border-radius: 1.5rem;
  align-items: center;
  gap: 0.5rem;
  height: auto;
  margin: 0 auto;
  padding: 0.75rem 2rem;
  font-size: 1rem;
  font-weight: 600;
  transition: all 0.3s;
  display: flex;
  box-shadow: 0 4px 12px #3b82f64d;
}

.index-module__NV_5cW__createButton:hover {
  background: linear-gradient(135deg, #2563eb 0%, #7c3aed 100%);
  transform: translateY(-2px);
  box-shadow: 0 6px 18px #3b82f666;
}

/* 响应式适配 */
@media (max-width: 768px) {
  .index-module__NV_5cW__titleContainer {
    text-align: center;
    flex-direction: column;
    gap: 0.5rem;
  }

  .index-module__NV_5cW__title {
    font-size: 2.5rem;
  }

  .index-module__NV_5cW__titleBadge {
    padding: 0.4rem 1.2rem;
    font-size: 1rem;
  }

  .index-module__NV_5cW__container {
    padding: 1rem;
  }

  .index-module__NV_5cW__header {
    margin-bottom: 2rem;
    padding: 1.5rem 1rem;
  }

  .index-module__NV_5cW__statsBar {
    flex-wrap: nowrap;
    justify-content: space-between;
    gap: 0.8rem;
    width: 100%;
    max-width: 100%;
    padding: 0.8rem 1.2rem;
  }

  .index-module__NV_5cW__stat {
    text-align: center;
    flex: 1;
    min-width: 60px;
  }

  .index-module__NV_5cW__statNumber {
    font-size: 1.1rem;
  }

  .index-module__NV_5cW__statLabel {
    white-space: nowrap;
    font-size: 0.7rem;
  }

  .index-module__NV_5cW__statDivider {
    width: 1px;
    height: 1.2rem;
  }

  .index-module__NV_5cW__sectionTitle {
    text-align: left;
    flex: 1;
    justify-content: flex-start;
    gap: 0.5rem;
    font-size: 1.3rem;
  }

  .index-module__NV_5cW__actionSection {
    border-radius: 1rem;
    margin: 0;
    padding: 2rem 1.5rem;
  }

  .index-module__NV_5cW__actionTitle {
    font-size: 1.6rem;
  }

  .index-module__NV_5cW__actionFeatures {
    flex-direction: column;
    align-items: center;
    gap: 1rem;
  }

  .index-module__NV_5cW__createButton {
    padding: 0.65rem 1.5rem;
    font-size: 0.95rem;
  }

  .chartCard__container {
    height: 250px;
  }

  .vitality__container {
    height: 300px;
  }

  .heatmap-stats {
    flex-wrap: wrap;
    gap: 1rem;
    padding: 0.8rem 1rem;
  }

  .stat-item {
    flex: 1;
    min-width: 80px;
  }

  .stat-value {
    font-size: 1.1rem;
  }

  .stat-label {
    font-size: 0.7rem;
  }

  .stat-divider {
    height: 2rem;
  }

  .title-row {
    flex-direction: column;
    align-items: flex-start;
  }

  .label-toggle {
    padding: 0.4rem 0.8rem;
    font-size: 0.75rem;
  }

  .heatmap-legend {
    flex-direction: column;
    gap: 0.75rem;
    padding: 0.6rem 0.9rem;
    top: 0.5rem;
    left: 0.5rem;
  }

  .legend-item {
    font-size: 0.7rem;
  }

  .bubble-small {
    width: 10px;
    height: 10px;
  }

  .bubble-medium {
    width: 14px;
    height: 14px;
  }

  .bubble-large {
    width: 18px;
    height: 18px;
  }

  /* 地图移动端适配 */
  .map-container {
    flex-direction: column;
    gap: 1rem;
  }

  .map-container .chart {
    min-height: 350px;
  }

  .map-rank-panel {
    width: 100%;
  }

  .rank-item {
    padding: 0.6rem 0.8rem;
    gap: 0.5rem;
  }

  .rank-num {
    width: 28px;
    height: 28px;
    font-size: 12px;
  }

  .rank-name {
    font-size: 13px;
  }

  .rank-score {
    font-size: 13px;
  }

  /* 移动端列表样式调整 */
  .project-item {
    flex-wrap: wrap;
    gap: 0.5rem;
  }

  .project-org {
    width: 100%;
    max-width: 100%;
    margin-top: 0.2rem;
  }

  /* 企业列表移动端调整 */
  .enterprise-item {
    padding: 0.6rem 0.8rem;
    gap: 0.5rem;
  }

  .enterprise-rank {
    width: 28px;
    height: 22px;
    font-size: 12px;
  }

  .enterprise-name {
    font-size: 13px;
  }

  .enterprise-meta {
    font-size: 10px;
  }

  .score-bar-container {
    width: 60px;
  }

  .enterprise-score {
    font-size: 13px;
    width: 35px;
  }
}

@media (max-width: 480px) {
  .index-module__NV_5cW__title {
    font-size: 1.8rem;
  }

  .index-module__NV_5cW__actionSection {
    padding: 1.5rem 1rem;
  }

  .index-module__NV_5cW__statsBar {
    gap: 0.6rem;
    padding: 0.6rem 0.8rem;
  }

  .index-module__NV_5cW__statNumber {
    font-size: 1rem;
  }

  .index-module__NV_5cW__statLabel {
    font-size: 0.65rem;
  }

  .index-module__NV_5cW__sectionTitle {
    gap: 0.4rem;
    font-size: 1.2rem;
  }

  .chartCard__container {
    height: 200px;
  }

  .vitality__container {
    height: 250px;
  }

  .heatmap-stats {
    gap: 0.6rem;
    padding: 0.6rem 0.8rem;
  }

  .stat-value {
    font-size: 1rem;
  }

  .stat-label {
    font-size: 0.65rem;
  }

  .heatmap-legend {
    gap: 0.5rem;
    padding: 0.5rem 0.7rem;
  }

  .legend-item {
    font-size: 0.65rem;
    gap: 0.3rem;
  }

  .vitality__title {
    font-size: 1.2rem;
  }

  .index-module__NV_5cW__chartsGrid {
    grid-template-columns: 1fr;
  }

  /* 地图小屏适配 */
  .map-container .chart {
    min-height: 300px;
    padding: 0.5rem;
  }

  .map-rank-panel {
    padding: 1rem;
  }

  .panel-title {
    font-size: 1rem;
    padding-bottom: 0.75rem;
  }

  .rank-item {
    padding: 0.5rem 0.6rem;
  }

  .rank-num {
    width: 26px;
    height: 26px;
    font-size: 11px;
  }

  .rank-name {
    font-size: 12px;
  }

  .rank-score {
    fo

    /* 小屏列表高度调整 */
    .chartCard__container.list-container {
      max-height: 300px;
    }

    /* 企业列表小屏调整 */
    .enterprise-item {
      padding: 0.5rem 0.6rem;
    }

    .enterprise-rank {
      width: 26px;
      height: 20px;
      font-size: 11px;
    }

    .enterprise-name {
      font-size: 12px;
    }

    .score-bar-container {
      width: 50px;
      height: 5px;
    }

    .enterprise-score {
      font-size: 12px;
      width: 32px;
    }
  }
}

.stats-glass-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;

  /* 布局控制：撑满容器并增加内边距 */
  width: 100%;
  padding: 2rem 4rem;
  //margin: 2rem 0;

  /* 深色玻璃拟态背景 */
  background: rgba(255, 255, 255, 0.02);
  backdrop-filter: blur(20px);
  -webkit-backdrop-filter: blur(20px);

  /* 极细微的边框勾勒 */
  border-radius: 1rem;
  border: 1px solid rgba(255, 255, 255, 0.08);

  /* 外阴影与内发光，增加悬浮感 */
  box-shadow: 0 20px 50px rgba(0, 0, 0, 0.3),
  inset 0 0 20px rgba(255, 255, 255, 0.02);

  transition: all 0.5s cubic-bezier(0.4, 0, 0.2, 1);

  &:hover {
    border-color: rgba(56, 189, 248, 0.4);
    background: rgba(255, 255, 255, 0.04);
    transform: translateY(-2px);
  }
}

.stat-node {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.75rem;
  transition: transform 0.3s ease;

  &:hover {
    transform: scale(1.05);
    .stat-value {
      text-shadow: 0 0 25px rgba(56, 189, 248, 0.8);
    }
  }
}

.stat-value {
  /* 科技感亮蓝渐变 */
  font-family: "PingFang SC", "Microsoft YaHei", sans-serif;
  font-size: 2.25rem;
  font-weight: 800;
  background: linear-gradient(180deg, #fff 0%, #38bdf8 100%);
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;

  /* 基础发光效果 */
  filter: drop-shadow(0 0 10px rgba(56, 189, 248, 0.3));
  letter-spacing: -1px;
}

.stat-desc {
  /* 在黑底上使用半透明白色，更有高级感 */
  color: rgba(255, 255, 255, 0.6);
  font-size: 0.875rem;
  font-weight: 500;
  letter-spacing: 0.1rem;
  text-transform: uppercase;
}

.stat-separator {
  /* 渐隐分割线 */
  width: 1px;
  height: 3rem;
  background: linear-gradient(
      to bottom,
      rgba(255, 255, 255, 0),
      rgba(255, 255, 255, 0.2),
      rgba(255, 255, 255, 0)
  );
  margin: 0 1rem;
}

/* 响应式适配 */
@media (max-width: 1024px) {
  .stats-glass-bar {
    padding: 2rem;
  }
  .stat-value {
    font-size: 1.75rem;
  }
}

@media (max-width: 768px) {
  .stats-glass-bar {
    flex-direction: column;
    gap: 2rem;
  }
  .stat-separator {
    width: 50%;
    height: 1px;
    background: linear-gradient(to right, transparent, rgba(255,255,255,0.2), transparent);
  }
}
</style>
