feat: 全站20个模板添加国际化(i18n)支持 - 简体中文/繁体中文/英文三语切换

- 所有18套前端模板 + 管理后台共20个HTML文件添加i18n引擎
- 前端JavaScript方案:I18N_LOCALES翻译字典 + data-i18n属性 + t()函数调用
- 语言切换器UI:下拉菜单选择,匹配各模板主题风格
- 语言持久化:localStorage存储 + URL参数覆盖 + 浏览器语言自动检测
- onLangChange回调:语言切换时动态重新渲染所有内容
- 支持语言:zh-CN(简体中文) / zh-TW(繁体中文) / en(English)
This commit is contained in:
2026-09-09 16:58:40 +08:00
parent 69c59f4fbd
commit a84129330e
20 changed files with 9343 additions and 3855 deletions

View File

@@ -152,6 +152,34 @@ section{position:relative}
.nav-toggle.open span:nth-child(2){opacity:0}
.nav-toggle.open span:nth-child(3){transform:translateY(-7px) rotate(-45deg)}
/* ============ 语言切换器 ============ */
.lang-switcher{position:relative;margin-left:8px}
.lang-btn{
display:flex;align-items:center;gap:6px;padding:8px 14px;border-radius:10px;
font-size:13px;font-weight:600;color:var(--text-muted);cursor:pointer;
background:rgba(255,255,255,0.05);border:1px solid var(--glass-border);
transition:all .25s var(--ease);
}
.lang-btn:hover{color:#fff;background:rgba(255,255,255,0.1);border-color:rgba(0,212,255,0.3)}
.lang-btn svg{width:16px;height:16px}
.lang-dropdown{
position:absolute;top:calc(100% + 8px);right:0;min-width:160px;
background:rgba(6,24,46,0.96);backdrop-filter:blur(20px);-webkit-backdrop-filter:blur(20px);
border:1px solid var(--glass-border);border-radius:var(--radius-sm);
box-shadow:0 12px 40px rgba(0,0,0,0.5);overflow:hidden;
opacity:0;transform:translateY(-8px);pointer-events:none;
transition:all .25s var(--ease);z-index:1001;
}
.lang-dropdown.open{opacity:1;transform:none;pointer-events:auto}
.lang-option{
display:flex;align-items:center;gap:10px;padding:12px 16px;
font-size:14px;color:var(--text-muted);cursor:pointer;transition:all .2s;
}
.lang-option:hover{background:rgba(0,212,255,0.1);color:#fff}
.lang-option.active{color:var(--secondary);font-weight:600}
.lang-option .check{width:16px;height:16px;opacity:0;transition:opacity .2s}
.lang-option.active .check{opacity:1}
/* ============ Hero ============ */
.hero{
min-height:100vh;display:flex;align-items:center;
@@ -464,6 +492,8 @@ section{position:relative}
.footer-top{grid-template-columns:1fr}
.about-card{padding:34px 26px}
.hero-actions .btn{flex:1;justify-content:center}
.lang-switcher{position:static;margin-left:0}
.lang-dropdown{right:auto;left:0}
}
</style>
</head>
@@ -473,7 +503,7 @@ section{position:relative}
<div class="loading-screen" id="loadingScreen">
<div class="loader">
<div class="loader-ring"></div>
<p>正在加载数据…</p>
<p data-i18n="loading">正在加载数据…</p>
</div>
</div>
@@ -484,16 +514,37 @@ section{position:relative}
<div class="logo-mark">
<svg viewBox="0 0 24 24" fill="none" stroke="#04101f" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"/></svg>
</div>
<div class="logo-text">Nexus<span>科技</span></div>
<div class="logo-text">Nexus<span data-i18n="logo_suffix">科技</span></div>
</div>
<div class="nav-links" id="navLinks">
<a href="#hero" onclick="closeNav()">首页</a>
<a href="#services" onclick="closeNav()">服务</a>
<a href="#news" onclick="closeNav()">新闻</a>
<a href="#team" onclick="closeNav()">团队</a>
<a href="#about" onclick="closeNav()">关于我们</a>
<a href="#contact" onclick="closeNav()">联系我们</a>
<a href="#contact" class="nav-cta" onclick="closeNav()">免费咨询</a>
<a href="#hero" onclick="closeNav()" data-i18n="nav_home">首页</a>
<a href="#services" onclick="closeNav()" data-i18n="nav_services">服务</a>
<a href="#news" onclick="closeNav()" data-i18n="nav_news">新闻</a>
<a href="#team" onclick="closeNav()" data-i18n="nav_team">团队</a>
<a href="#about" onclick="closeNav()" data-i18n="nav_about">关于我们</a>
<a href="#contact" onclick="closeNav()" data-i18n="nav_contact">联系我们</a>
<a href="#contact" class="nav-cta" onclick="closeNav()" data-i18n="nav_cta">免费咨询</a>
</div>
<div class="lang-switcher" id="langSwitcher">
<button class="lang-btn" id="langBtn" onclick="toggleLangDropdown()">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><path d="M2 12h20M12 2a15 15 0 0 1 0 20 15 15 0 0 1 0-20z"/></svg>
<span id="langLabel">中文</span>
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="width:12px;height:12px"><polyline points="6 9 12 15 18 9"/></polyline></svg>
</button>
<div class="lang-dropdown" id="langDropdown">
<div class="lang-option" data-lang="zh-CN" onclick="switchLang('zh-CN')">
<svg class="check" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"/></svg>
<span>简体中文</span>
</div>
<div class="lang-option" data-lang="zh-TW" onclick="switchLang('zh-TW')">
<svg class="check" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"/></svg>
<span>繁體中文</span>
</div>
<div class="lang-option" data-lang="en" onclick="switchLang('en')">
<svg class="check" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"/></svg>
<span>English</span>
</div>
</div>
</div>
<button class="nav-toggle" id="navToggle" aria-label="菜单">
<span></span><span></span><span></span>
@@ -507,23 +558,23 @@ section{position:relative}
<div class="hero-orb o1"></div>
<div class="hero-orb o2"></div>
<div class="hero-inner">
<div class="hero-badge reveal"><span class="dot"></span><span id="heroBadge">全球领先的智能科技企业</span></div>
<h1 class="reveal d1"><span id="heroTitle" class="grad">创新驱动 · 智领未来</span></h1>
<p class="lead reveal d2" id="heroDesc">正在加载企业简介…</p>
<div class="hero-badge reveal"><span class="dot"></span><span id="heroBadge" data-i18n="hero_badge">全球领先的智能科技企业</span></div>
<h1 class="reveal d1"><span id="heroTitle" class="grad" data-i18n="hero_title">创新驱动 · 智领未来</span></h1>
<p class="lead reveal d2" id="heroDesc" data-i18n="hero_desc">正在加载企业简介…</p>
<div class="hero-actions reveal d3">
<a href="#services" class="btn btn-primary">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14"/><path d="M12 5l7 7-7 7"/></svg>
探索我们的服务
<span data-i18n="hero_cta1">探索我们的服务</span>
</a>
<a href="#contact" class="btn btn-ghost">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><path d="M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72c.13.96.36 1.9.7 2.81a2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45c.91.34 1.85.57 2.81.7A2 2 0 0 1 22 16.92z"/></svg>
预约咨询
<span data-i18n="hero_cta2">预约咨询</span>
</a>
</div>
</div>
<div class="scroll-indicator">
<div class="mouse"></div>
<span>向下滚动</span>
<span data-i18n="scroll_hint">向下滚动</span>
</div>
</header>
@@ -531,9 +582,9 @@ section{position:relative}
<section class="section-pad" id="stats">
<div class="container">
<div class="section-head reveal">
<span class="eyebrow">DATA · 实力见证</span>
<h2 class="section-title">用数据说话</h2>
<p class="section-sub">十余年深耕,以技术与服务赢得全球客户信赖</p>
<span class="eyebrow" data-i18n="stats_eyebrow">DATA · 实力见证</span>
<h2 class="section-title" data-i18n="stats_title">用数据说话</h2>
<p class="section-sub" data-i18n="stats_sub">十余年深耕,以技术与服务赢得全球客户信赖</p>
</div>
<div class="stats-grid" id="statsGrid">
<div class="stat-card glass skeleton"></div>
@@ -548,9 +599,9 @@ section{position:relative}
<section class="section-pad" id="services">
<div class="container">
<div class="section-head reveal">
<span class="eyebrow">SOLUTIONS · 核心服务</span>
<h2 class="section-title">为企业数字化转型赋能</h2>
<p class="section-sub">从人工智能到云计算,提供端到端的一站式技术解决方案</p>
<span class="eyebrow" data-i18n="services_eyebrow">SOLUTIONS · 核心服务</span>
<h2 class="section-title" data-i18n="services_title">为企业数字化转型赋能</h2>
<p class="section-sub" data-i18n="services_sub">从人工智能到云计算,提供端到端的一站式技术解决方案</p>
</div>
<div class="services-grid" id="servicesGrid">
<div class="service-card glass skeleton"></div>
@@ -564,9 +615,9 @@ section{position:relative}
<section class="section-pad" id="news">
<div class="container">
<div class="section-head reveal">
<span class="eyebrow">NEWS · 新闻动态</span>
<h2 class="section-title">了解最新资讯</h2>
<p class="section-sub">关注 Nexus,掌握行业前沿与企业最新动态</p>
<span class="eyebrow" data-i18n="news_eyebrow">NEWS · 新闻动态</span>
<h2 class="section-title" data-i18n="news_title">了解最新资讯</h2>
<p class="section-sub" data-i18n="news_sub">关注 Nexus,掌握行业前沿与企业最新动态</p>
</div>
<div class="news-grid" id="newsGrid">
<div class="news-card glass skeleton"></div>
@@ -580,9 +631,9 @@ section{position:relative}
<section class="section-pad" id="team">
<div class="container">
<div class="section-head reveal">
<span class="eyebrow">TEAM · 核心团队</span>
<h2 class="section-title">汇聚行业顶尖人才</h2>
<p class="section-sub">富有远见与执行力的领导团队,引领企业持续创新</p>
<span class="eyebrow" data-i18n="team_eyebrow">TEAM · 核心团队</span>
<h2 class="section-title" data-i18n="team_title">汇聚行业顶尖人才</h2>
<p class="section-sub" data-i18n="team_sub">富有远见与执行力的领导团队,引领企业持续创新</p>
</div>
<div class="team-grid" id="teamGrid">
<div class="team-card glass skeleton"></div>
@@ -596,9 +647,9 @@ section{position:relative}
<section class="section-pad" id="about">
<div class="container">
<div class="section-head reveal">
<span class="eyebrow">ABOUT · 关于我们</span>
<h2 class="section-title">愿景与使命</h2>
<p class="section-sub">以技术为根基,以价值创造为导向</p>
<span class="eyebrow" data-i18n="about_eyebrow">ABOUT · 关于我们</span>
<h2 class="section-title" data-i18n="about_title">愿景与使命</h2>
<p class="section-sub" data-i18n="about_sub">以技术为根基,以价值创造为导向</p>
</div>
<div class="about-grid" id="aboutGrid">
<div class="about-card glass skeleton" style="height:280px"></div>
@@ -611,9 +662,9 @@ section{position:relative}
<section class="section-pad" id="contact">
<div class="container">
<div class="section-head reveal">
<span class="eyebrow">CONTACT · 联系我们</span>
<h2 class="section-title">开启合作之旅</h2>
<p class="section-sub">无论您有任何需求,我们随时为您提供专业支持</p>
<span class="eyebrow" data-i18n="contact_eyebrow">CONTACT · 联系我们</span>
<h2 class="section-title" data-i18n="contact_title">开启合作之旅</h2>
<p class="section-sub" data-i18n="contact_sub">无论您有任何需求,我们随时为您提供专业支持</p>
</div>
<div class="contact-wrap" id="contactWrap">
<div class="contact-info glass skeleton" style="height:340px"></div>
@@ -636,26 +687,26 @@ section{position:relative}
<div class="logo-mark">
<svg viewBox="0 0 24 24" fill="none" stroke="#04101f" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"/></svg>
</div>
<div class="logo-text" id="footerName">Nexus<span>科技</span></div>
<div class="logo-text" id="footerName">Nexus<span data-i18n="logo_suffix">科技</span></div>
</div>
<p id="footerDesc">创新驱动,智领未来。致力于用前沿技术赋能每一个行业。</p>
<p id="footerDesc" data-i18n="footer_desc">创新驱动,智领未来。致力于用前沿技术赋能每一个行业。</p>
</div>
<div class="footer-col">
<h4>快速导航</h4>
<a href="#hero">首页</a>
<a href="#services">核心服务</a>
<a href="#news">新闻动态</a>
<a href="#team">核心团队</a>
<h4 data-i18n="footer_nav_title">快速导航</h4>
<a href="#hero" data-i18n="nav_home">首页</a>
<a href="#services" data-i18n="footer_core_services">核心服务</a>
<a href="#news" data-i18n="footer_news">新闻动态</a>
<a href="#team" data-i18n="footer_team">核心团队</a>
</div>
<div class="footer-col">
<h4>关于我们</h4>
<a href="#about">企业愿景</a>
<a href="#about">企业使命</a>
<a href="#stats">企业实力</a>
<a href="#contact">联系我们</a>
<h4 data-i18n="nav_about">关于我们</h4>
<a href="#about" data-i18n="footer_vision">企业愿景</a>
<a href="#about" data-i18n="footer_mission">企业使命</a>
<a href="#stats" data-i18n="footer_strength">企业实力</a>
<a href="#contact" data-i18n="nav_contact">联系我们</a>
</div>
<div class="footer-col">
<h4>联系方式</h4>
<h4 data-i18n="footer_contact_title">联系方式</h4>
<a href="tel:" id="footPhone">400-888-9999</a>
<a href="mailto:" id="footEmail">contact@nexus-tech.com</a>
<a id="footAddr">上海市浦东新区</a>
@@ -665,10 +716,10 @@ section{position:relative}
<div class="footer-bottom">
<span id="copyRight">© 2026 Nexus 科技集团. 保留所有权利.</span>
<div class="footer-social">
<a href="#" aria-label="微信"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5z"/></svg></a>
<a href="#" aria-label="微博"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><path d="M8 14s1.5 2 4 2 4-2 4-2"/><line x1="9" y1="9" x2="9.01" y2="9"/><line x1="15" y1="9" x2="15.01" y2="9"/></svg></a>
<a href="#" aria-label="邮箱"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z"/><polyline points="22,6 12,13 2,6"/></svg></a>
<a href="#" aria-label="链接"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
<a href="#" aria-label="WeChat"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5z"/></svg></a>
<a href="#" aria-label="Weibo"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><path d="M8 14s1.5 2 4 2 4-2 4-2"/><line x1="9" y1="9" x2="9.01" y2="9"/><line x1="15" y1="9" x2="15.01" y2="9"/></svg></a>
<a href="#" aria-label="Email"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z"/><polyline points="22,6 12,13 2,6"/></svg></a>
<a href="#" aria-label="Link"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a>
</div>
</div>
</div>
@@ -680,28 +731,291 @@ section{position:relative}
</div>
<script>
/* =========================================================
i18n 国际化引擎
========================================================= */
const I18N_LOCALES = {
'zh-CN': {
loading: '正在加载数据…',
logo_suffix: '科技',
nav_home: '首页',
nav_services: '服务',
nav_news: '新闻',
nav_team: '团队',
nav_about: '关于我们',
nav_contact: '联系我们',
nav_cta: '免费咨询',
hero_badge: '全球领先的智能科技企业',
hero_title: '创新驱动 · 智领未来',
hero_desc: '正在加载企业简介…',
hero_cta1: '探索我们的服务',
hero_cta2: '预约咨询',
scroll_hint: '向下滚动',
stats_eyebrow: 'DATA · 实力见证',
stats_title: '用数据说话',
stats_sub: '十余年深耕,以技术与服务赢得全球客户信赖',
services_eyebrow: 'SOLUTIONS · 核心服务',
services_title: '为企业数字化转型赋能',
services_sub: '从人工智能到云计算,提供端到端的一站式技术解决方案',
news_eyebrow: 'NEWS · 新闻动态',
news_title: '了解最新资讯',
news_sub: '关注 Nexus,掌握行业前沿与企业最新动态',
team_eyebrow: 'TEAM · 核心团队',
team_title: '汇聚行业顶尖人才',
team_sub: '富有远见与执行力的领导团队,引领企业持续创新',
about_eyebrow: 'ABOUT · 关于我们',
about_title: '愿景与使命',
about_sub: '以技术为根基,以价值创造为导向',
contact_eyebrow: 'CONTACT · 联系我们',
contact_title: '开启合作之旅',
contact_sub: '无论您有任何需求,我们随时为您提供专业支持',
footer_desc: '创新驱动,智领未来。致力于用前沿技术赋能每一个行业。',
footer_nav_title: '快速导航',
footer_core_services: '核心服务',
footer_news: '新闻动态',
footer_team: '核心团队',
footer_vision: '企业愿景',
footer_mission: '企业使命',
footer_strength: '企业实力',
footer_contact_title: '联系方式',
contact_phone: '联系电话',
contact_email: '电子邮箱',
contact_address: '公司地址',
contact_website: '官方网站',
contact_card_phone: '电话',
contact_card_email: '邮箱',
contact_card_address: '地址',
contact_card_website: '网站',
contact_info_title: '随时与我们联系',
contact_info_desc: '无论您希望了解产品详情、寻求技术合作,还是加入我们,我们都期待您的来信。专业团队将在第一时间为您提供支持。',
about_vision: '企业愿景',
about_mission: '企业使命',
about_founded: '成立年份',
about_scale: '团队规模',
about_name: '企业名称',
about_official: '官方网站',
error_title: '数据加载失败',
error_desc: '无法连接到服务器,请稍后重试。',
error_reload: '重新加载',
error_network: '请检查网络连接后重试',
cat_product: '产品动态',
cat_company: '公司新闻',
cat_industry: '行业资讯',
empty_stats: '暂无统计数据',
empty_services: '暂无服务数据',
empty_news: '暂无新闻数据',
empty_team: '暂无团队数据',
copyright_suffix: '保留所有权利.'
},
'en': {
loading: 'Loading data…',
logo_suffix: 'Tech',
nav_home: 'Home',
nav_services: 'Services',
nav_news: 'News',
nav_team: 'Team',
nav_about: 'About',
nav_contact: 'Contact',
nav_cta: 'Free Consult',
hero_badge: 'World\'s Leading Smart Tech Enterprise',
hero_title: 'Innovation Drives the Future',
hero_desc: 'Loading company profile…',
hero_cta1: 'Explore Our Services',
hero_cta2: 'Book a Consultation',
scroll_hint: 'Scroll Down',
stats_eyebrow: 'DATA · Proven Results',
stats_title: 'Speaking with Data',
stats_sub: 'Over a decade of excellence, earning global trust through technology and service',
services_eyebrow: 'SOLUTIONS · Core Services',
services_title: 'Empowering Digital Transformation',
services_sub: 'End-to-end one-stop technology solutions from AI to cloud computing',
news_eyebrow: 'NEWS · Updates',
news_title: 'Latest News & Insights',
news_sub: 'Stay ahead with Nexus — industry trends and company updates',
team_eyebrow: 'TEAM · Our People',
team_title: 'Top Talent in the Industry',
team_sub: 'A visionary leadership team driving continuous innovation',
about_eyebrow: 'ABOUT · About Us',
about_title: 'Vision & Mission',
about_sub: 'Rooted in technology, driven by value creation',
contact_eyebrow: 'CONTACT · Reach Out',
contact_title: 'Start Your Journey with Us',
contact_sub: 'Whatever your needs, we\'re here to provide professional support',
footer_desc: 'Innovation drives the future. Empowering every industry with cutting-edge technology.',
footer_nav_title: 'Quick Links',
footer_core_services: 'Core Services',
footer_news: 'News',
footer_team: 'Our Team',
footer_vision: 'Vision',
footer_mission: 'Mission',
footer_strength: 'Strength',
footer_contact_title: 'Contact',
contact_phone: 'Phone',
contact_email: 'Email',
contact_address: 'Address',
contact_website: 'Website',
contact_card_phone: 'Phone',
contact_card_email: 'Email',
contact_card_address: 'Address',
contact_card_website: 'Website',
contact_info_title: 'Get in Touch',
contact_info_desc: 'Whether you want to learn about our products, explore technical partnerships, or join our team — we look forward to hearing from you. Our professional team will respond promptly.',
about_vision: 'Vision',
about_mission: 'Mission',
about_founded: 'Founded',
about_scale: 'Team Size',
about_name: 'Company',
about_official: 'Website',
error_title: 'Failed to Load Data',
error_desc: 'Unable to connect to the server. Please try again later.',
error_reload: 'Reload',
error_network: 'Please check your network connection and try again',
cat_product: 'Product',
cat_company: 'Company',
cat_industry: 'Industry',
empty_stats: 'No statistics available',
empty_services: 'No services available',
empty_news: 'No news available',
empty_team: 'No team data available',
copyright_suffix: 'All rights reserved.'
},
'zh-TW': {
loading: '正在載入資料…',
logo_suffix: '科技',
nav_home: '首頁',
nav_services: '服務',
nav_news: '新聞',
nav_team: '團隊',
nav_about: '關於我們',
nav_contact: '聯絡我們',
nav_cta: '免費諮詢',
hero_badge: '全球領先的智能科技企業',
hero_title: '創新驅動 · 智領未來',
hero_desc: '正在載入企業簡介…',
hero_cta1: '探索我們的服務',
hero_cta2: '預約諮詢',
scroll_hint: '向下捲動',
stats_eyebrow: 'DATA · 實力見證',
stats_title: '用數據說話',
stats_sub: '十餘年深耕,以技術與服務贏得全球客戶信賴',
services_eyebrow: 'SOLUTIONS · 核心服務',
services_title: '為企業數位化轉型賦能',
services_sub: '從人工智慧到雲端運算,提供端到端的一站式技術解決方案',
news_eyebrow: 'NEWS · 新聞動態',
news_title: '了解最新資訊',
news_sub: '關注 Nexus,掌握行業前沿與企業最新動態',
team_eyebrow: 'TEAM · 核心團隊',
team_title: '匯聚行業頂尖人才',
team_sub: '富有遠見與執行力的領導團隊,引領企業持續創新',
about_eyebrow: 'ABOUT · 關於我們',
about_title: '願景與使命',
about_sub: '以技術為根基,以價值創造為導向',
contact_eyebrow: 'CONTACT · 聯絡我們',
contact_title: '開啟合作之旅',
contact_sub: '無論您有任何需求,我們隨時為您提供專業支援',
footer_desc: '創新驅動,智領未來。致力於用前沿技術賦能每一個行業。',
footer_nav_title: '快速導航',
footer_core_services: '核心服務',
footer_news: '新聞動態',
footer_team: '核心團隊',
footer_vision: '企業願景',
footer_mission: '企業使命',
footer_strength: '企業實力',
footer_contact_title: '聯絡方式',
contact_phone: '聯絡電話',
contact_email: '電子信箱',
contact_address: '公司地址',
contact_website: '官方網站',
contact_card_phone: '電話',
contact_card_email: '信箱',
contact_card_address: '地址',
contact_card_website: '網站',
contact_info_title: '隨時與我們聯繫',
contact_info_desc: '無論您希望了解產品詳情、尋求技術合作,還是加入我們,我們都期待您的來信。專業團隊將在第一時間為您提供支援。',
about_vision: '企業願景',
about_mission: '企業使命',
about_founded: '成立年份',
about_scale: '團隊規模',
about_name: '企業名稱',
about_official: '官方網站',
error_title: '資料載入失敗',
error_desc: '無法連線到伺服器,請稍後重試。',
error_reload: '重新載入',
error_network: '請檢查網路連線後重試',
cat_product: '產品動態',
cat_company: '公司新聞',
cat_industry: '行業資訊',
empty_stats: '暫無統計資料',
empty_services: '暫無服務資料',
empty_news: '暫無新聞資料',
empty_team: '暫無團隊資料',
copyright_suffix: '保留所有權利.'
}
};
const LANG_LABELS = {'zh-CN':'中文','en':'EN','zh-TW':'繁中'};
let currentLang = (function(){
try{
var u=new URLSearchParams(location.search).get('lang');
if(u&&I18N_LOCALES[u]) return u;
}catch(e){}
try{var s=localStorage.getItem('lang');if(s&&I18N_LOCALES[s]) return s;}catch(e){}
var b=navigator.language||navigator.userLanguage||'';
if(b.startsWith('zh-TW')||b.startsWith('zh-Hant')) return 'zh-TW';
if(b.startsWith('zh')) return 'zh-CN';
return 'en';
})();
function t(key){return (I18N_LOCALES[currentLang]&&I18N_LOCALES[currentLang][key])||(I18N_LOCALES['zh-CN'][key])||key;}
function applyI18n(){
document.querySelectorAll('[data-i18n]').forEach(function(el){
var key=el.getAttribute('data-i18n');
el.textContent=t(key);
});
document.documentElement.lang=currentLang==='zh-TW'?'zh-TW':currentLang==='zh-CN'?'zh-CN':'en';
document.getElementById('langLabel').textContent=LANG_LABELS[currentLang]||currentLang;
document.querySelectorAll('.lang-option').forEach(function(opt){
opt.classList.toggle('active',opt.getAttribute('data-lang')===currentLang);
});
}
function switchLang(lang){
if(!I18N_LOCALES[lang]) return;
currentLang=lang;
try{localStorage.setItem('lang',lang);}catch(e){}
applyI18n();
if(typeof onLangChange==='function') onLangChange(lang);
document.getElementById('langDropdown').classList.remove('open');
}
function toggleLangDropdown(){
document.getElementById('langDropdown').classList.toggle('open');
}
document.addEventListener('click',function(e){
var sw=document.getElementById('langSwitcher');
if(sw&&!sw.contains(e.target)) document.getElementById('langDropdown').classList.remove('open');
});
/* =========================================================
SVG 图标库(纯 SVG,不使用 emoji)
========================================================= */
const ICONS = {
// 服务图标
ai:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><rect x="4" y="4" width="16" height="16" rx="3"/><circle cx="9" cy="9" r="1.4"/><circle cx="15" cy="9" r="1.4"/><circle cx="9" cy="15" r="1.4"/><circle cx="15" cy="15" r="1.4"/><path d="M9 9h6M9 15h6M12 4v16"/></svg>',
cloud:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M17.5 19a4.5 4.5 0 0 0 .5-9 6 6 0 0 0-11.5-1.5A4 4 0 0 0 6.5 19h11z"/><path d="M9 14l2 2 4-4"/></svg>',
iot:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="2.5"/><path d="M12 2v3M12 19v3M2 12h3M19 12h3M5 5l2 2M17 17l2 2M5 19l2-2M17 7l2-2"/></svg>',
data:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><ellipse cx="12" cy="5" rx="8" ry="3"/><path d="M4 5v6c0 1.7 3.6 3 8 3s8-1.3 8-3V5"/><path d="M4 11v6c0 1.7 3.6 3 8 3s8-1.3 8-3v-6"/></svg>',
security:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M12 2l8 4v6c0 5-3.5 8.5-8 10-4.5-1.5-8-5-8-10V6l8-4z"/><path d="M9 12l2 2 4-4"/></svg>',
consulting:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M9 18h6M10 21h4"/><path d="M12 2a7 7 0 0 0-4 12.7c.6.5 1 1.3 1 2.1V17h6v-.2c0-.8.4-1.6 1-2.1A7 7 0 0 0 12 2z"/></svg>',
// 统计图标
users:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M23 21v-2a4 4 0 0 0-3-3.87M16 3.13a4 4 0 0 1 0 7.75"/></svg>',
patent:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M9 2h6v4l2 2v3a4 4 0 0 1-4 4h-2a4 4 0 0 1-4-4V8l2-2V2z"/><path d="M12 15v6M9 21h6"/></svg>',
globe:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><path d="M2 12h20M12 2a15 15 0 0 1 0 20 15 15 0 0 1 0-20z"/></svg>',
revenue:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><line x1="12" y1="1" x2="12" y2="23"/><path d="M17 5H9.5a3.5 3.5 0 0 0 0 7h5a3.5 3.5 0 0 1 0 7H6"/></svg>',
// 联系图标
phone:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round"><path d="M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72c.13.96.36 1.9.7 2.81a2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45c.91.34 1.85.57 2.81.7A2 2 0 0 1 22 16.92z"/></svg>',
email:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round"><path d="M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z"/><polyline points="22,6 12,13 2,6"/></svg>',
location:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" 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"/><circle cx="12" cy="10" r="3"/></svg>',
website:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="2" y1="12" x2="22" y2="12"/><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/></svg>',
// 通用
check:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3.2" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"/></svg>',
calendar:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="4" width="18" height="18" rx="2"/><line x1="16" y1="2" x2="16" y2="6"/><line x1="8" y1="2" x2="8" y2="6"/><line x1="3" y1="10" x2="21" y2="10"/></svg>',
user:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"/><circle cx="12" cy="7" r="4"/></svg>',
@@ -721,7 +1035,6 @@ function safeParse(str, fallback){
}
function esc(s){return (s==null?'':String(s)).replace(/[&<>"']/g,m=>({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;'}[m]));}
function firstChar(str){return (str||'?').trim().charAt(0);}
// 头像渐变色板
const AVATAR_COLORS=[
'linear-gradient(135deg,#00D4FF,#0A4D8C)',
'linear-gradient(135deg,#7C5CFF,#3A8DFF)',
@@ -731,7 +1044,6 @@ const AVATAR_COLORS=[
'linear-gradient(135deg,#5CE1E6,#6C7BFF)'
];
function avatarColor(i){return AVATAR_COLORS[i%AVATAR_COLORS.length];}
// 解析数值与后缀(如 "5000+"-> {num:5000,suf:"+"}; "50亿+"->{num:50,suf:"亿+"})
function parseNum(v){
if(v==null) return {num:0,suf:''};
const s=String(v);
@@ -747,7 +1059,7 @@ function formatDate(d){
}catch(e){return '';}
}
function truncate(s,n){s=s||'';return s.length>n?s.slice(0,n)+'…':s;}
const CAT_LABEL={product:'产品动态',company:'公司新闻',industry:'行业资讯'};
const CAT_LABEL_KEY={product:'cat_product',company:'cat_company',industry:'cat_industry'};
/* =========================================================
导航交互
@@ -802,7 +1114,7 @@ function animateNum(el,num,suf,dur){
const isInt=Number.isInteger(num);
function tick(now){
let p=Math.min((now-start)/dur,1);
p=1-Math.pow(1-p,3); // easeOutCubic
p=1-Math.pow(1-p,3);
const cur=num*p;
el.textContent=(isInt?Math.round(cur):cur.toFixed(1))+suf;
if(p<1) requestAnimationFrame(tick);
@@ -832,14 +1144,13 @@ document.addEventListener('mousemove',e=>{
});
/* =========================================================
渲染函数
渲染函数(i18n-aware)
========================================================= */
function renderHero(company){
document.getElementById('heroTitle').textContent=company.slogan||'创新驱动 · 智领未来';
document.getElementById('heroTitle').textContent=company.slogan||t('hero_title');
document.getElementById('heroDesc').textContent=truncate(company.description,100);
document.getElementById('heroBadge').textContent=company.name||'全球领先的智能科技企业';
document.title=(company.name||'Nexus 科技集团')+(company.slogan?(' - '+company.slogan):'');
/* 企业 Logo 图片注入 */
document.getElementById('heroBadge').textContent=company.name||t('hero_badge');
document.title=(company.name||'Nexus '+t('logo_suffix'))+(company.slogan?(' - '+company.slogan):'');
if(company.logo){
document.querySelectorAll('.logo-mark').forEach(function(lm){
lm.style.position='relative';
@@ -852,96 +1163,96 @@ function renderHero(company){
function renderStats(company){
const stats=safeParse(company.stats,[]);
const grid=document.getElementById('statsGrid');
if(!stats.length){grid.innerHTML='<p style="grid-column:1/-1;text-align:center;color:var(--text-muted)">暂无统计数据</p>';return;}
if(!stats.length){grid.innerHTML='<p style="grid-column:1/-1;text-align:center;color:var(--text-muted)">'+t('empty_stats')+'</p>';return;}
grid.innerHTML=stats.map((s,i)=>{
const {num,suf}=parseNum(s.value);
return `<div class="stat-card glass reveal d${(i%4)+1}">
<div class="stat-icon">${icon(s.icon)}</div>
<div class="stat-value" data-num="${num}" data-suf="${esc(suf)}">0${suf}</div>
<div class="stat-label">${esc(s.label)}</div>
</div>`;
return '<div class="stat-card glass reveal d'+((i%4)+1)+'">'+
'<div class="stat-icon">'+icon(s.icon)+'</div>'+
'<div class="stat-value" data-num="'+num+'" data-suf="'+esc(suf)+'">0'+suf+'</div>'+
'<div class="stat-label">'+esc(s.label)+'</div>'+
'</div>';
}).join('');
// 重新观察并触发动画
grid.querySelectorAll('.reveal').forEach(el=>io.observe(el));
grid.querySelectorAll('.stat-value').forEach(el=>numIO.observe(el));
}
function renderServices(services){
const grid=document.getElementById('servicesGrid');
if(!services||!services.length){grid.innerHTML='<p style="grid-column:1/-1;text-align:center;color:var(--text-muted)">暂无服务数据</p>';return;}
if(!services||!services.length){grid.innerHTML='<p style="grid-column:1/-1;text-align:center;color:var(--text-muted)">'+t('empty_services')+'</p>';return;}
grid.innerHTML=services.map((sv,i)=>{
const feats=safeParse(sv.features,[]);
const featHtml=feats.map(f=>`<li><span class="chk">${icon('check')}</span><span>${esc(f)}</span></li>`).join('');
return `<div class="service-card glass reveal d${(i%3)+1}">
<div class="service-icon" style="position:relative;overflow:hidden">${icon(sv.icon)}${sv.image?`<img src="${esc(sv.image)}" alt="${esc(sv.title)}" style="position:absolute;inset:0;width:100%;height:100%;object-fit:cover" onerror="this.remove()">`:''}</div>
<h3>${esc(sv.title)}</h3>
<p class="desc">${esc(sv.description)}</p>
<ul class="features">${featHtml}</ul>
</div>`;
const featHtml=feats.map(f=>'<li><span class="chk">'+icon('check')+'</span><span>'+esc(f)+'</span></li>').join('');
return '<div class="service-card glass reveal d'+((i%3)+1)+'">'+
'<div class="service-icon" style="position:relative;overflow:hidden">'+icon(sv.icon)+(sv.image?'<img src="'+esc(sv.image)+'" alt="'+esc(sv.title)+'" style="position:absolute;inset:0;width:100%;height:100%;object-fit:cover" onerror="this.remove()">':'')+'</div>'+
'<h3>'+esc(sv.title)+'</h3>'+
'<p class="desc">'+esc(sv.description)+'</p>'+
'<ul class="features">'+featHtml+'</ul>'+
'</div>';
}).join('');
grid.querySelectorAll('.reveal').forEach(el=>io.observe(el));
}
function renderNews(news){
const grid=document.getElementById('newsGrid');
if(!news||!news.length){grid.innerHTML='<p style="grid-column:1/-1;text-align:center;color:var(--text-muted)">暂无新闻数据</p>';return;}
if(!news||!news.length){grid.innerHTML='<p style="grid-column:1/-1;text-align:center;color:var(--text-muted)">'+t('empty_news')+'</p>';return;}
grid.innerHTML=news.map((nw,i)=>{
const cat=CAT_LABEL[nw.category]||nw.category||'动态';
var catKey=CAT_LABEL_KEY[nw.category];
var cat=catKey?t(catKey):(nw.category||'');
const date=formatDate(nw.created_at);
return `<article class="news-card glass reveal d${(i%3)+1}">
<div class="news-thumb">
${nw.image?`<img src="${esc(nw.image)}" alt="${esc(nw.title)}" style="position:absolute;inset:0;width:100%;height:100%;object-fit:cover;z-index:0" onerror="this.style.display='none';this.nextElementSibling.style.display=''">`:''}
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" style="${nw.image?'display:none':''}"><path d="M4 22h16a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2H8a2 2 0 0 0-2 2v16a2 2 0 0 1-2 2zm0 0a2 2 0 0 1-2-2v-9c0-1.1.9-2 2-2h2"/><path d="M18 14h-8M15 18h-5M10 6h8v4h-8V6z"/></svg>
<span class="news-cat cat-${esc(nw.category)}">${esc(cat)}</span>
</div>
<div class="news-body">
<div class="news-meta">
<span>${icon('calendar')}${esc(date)}</span>
<span>${icon('user')}${esc(nw.author||'')}</span>
</div>
<h3>${esc(nw.title)}</h3>
<p class="summary">${esc(nw.summary)}</p>
</div>
</article>`;
return '<article class="news-card glass reveal d'+((i%3)+1)+'">'+
'<div class="news-thumb">'+
(nw.image?'<img src="'+esc(nw.image)+'" alt="'+esc(nw.title)+'" style="position:absolute;inset:0;width:100%;height:100%;object-fit:cover;z-index:0" onerror="this.style.display=\'none\';this.nextElementSibling.style.display=\'\'">':'')+
'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" style="'+(nw.image?'display:none':'')+'"><path d="M4 22h16a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2H8a2 2 0 0 0-2 2v16a2 2 0 0 1-2 2zm0 0a2 2 0 0 1-2-2v-9c0-1.1.9-2 2-2h2"/><path d="M18 14h-8M15 18h-5M10 6h8v4h-8V6z"/></svg>'+
'<span class="news-cat cat-'+esc(nw.category)+'">'+esc(cat)+'</span>'+
'</div>'+
'<div class="news-body">'+
'<div class="news-meta">'+
'<span>'+icon('calendar')+esc(date)+'</span>'+
'<span>'+icon('user')+esc(nw.author||'')+'</span>'+
'</div>'+
'<h3>'+esc(nw.title)+'</h3>'+
'<p class="summary">'+esc(nw.summary)+'</p>'+
'</div>'+
'</article>';
}).join('');
grid.querySelectorAll('.reveal').forEach(el=>io.observe(el));
}
function renderTeam(team){
const grid=document.getElementById('teamGrid');
if(!team||!team.length){grid.innerHTML='<p style="grid-column:1/-1;text-align:center;color:var(--text-muted)">暂无团队数据</p>';return;}
if(!team||!team.length){grid.innerHTML='<p style="grid-column:1/-1;text-align:center;color:var(--text-muted)">'+t('empty_team')+'</p>';return;}
grid.innerHTML=team.map((m,i)=>{
return `<div class="team-card glass reveal d${(i%3)+1}">
<div class="team-avatar" style="background:${avatarColor(i)};position:relative;overflow:hidden">${esc(firstChar(m.name))}${m.avatar?`<img src="${esc(m.avatar)}" alt="${esc(m.name)}" style="position:absolute;inset:0;width:100%;height:100%;border-radius:50%;object-fit:cover" onerror="this.remove()">`:''}</div>
<h3>${esc(m.name)}</h3>
<div class="team-role">${esc(m.position)}</div>
<p class="team-bio">${esc(m.bio)}</p>
</div>`;
return '<div class="team-card glass reveal d'+((i%3)+1)+'">'+
'<div class="team-avatar" style="background:'+avatarColor(i)+';position:relative;overflow:hidden">'+esc(firstChar(m.name))+(m.avatar?'<img src="'+esc(m.avatar)+'" alt="'+esc(m.name)+'" style="position:absolute;inset:0;width:100%;height:100%;border-radius:50%;object-fit:cover" onerror="this.remove()">':'')+'</div>'+
'<h3>'+esc(m.name)+'</h3>'+
'<div class="team-role">'+esc(m.position)+'</div>'+
'<p class="team-bio">'+esc(m.bio)+'</p>'+
'</div>';
}).join('');
grid.querySelectorAll('.reveal').forEach(el=>io.observe(el));
}
function renderAbout(company){
const grid=document.getElementById('aboutGrid');
grid.innerHTML=`
<div class="about-card glass reveal d1">
<span class="quote">"</span>
<h3><span class="tag">${icon('compass')}</span>企业愿景</h3>
<p>${esc(company.vision||'')}</p>
<div class="about-meta">
<div class="item"><b>${esc(company.founded_year||'—')}</b><span>成立年份</span></div>
<div class="item"><b>${esc(company.employee_count||'—')}</b><span>团队规模</span></div>
</div>
</div>
<div class="about-card glass reveal d2">
<span class="quote">"</span>
<h3><span class="tag">${icon('target')}</span>企业使命</h3>
<p>${esc(company.mission||'')}</p>
<div class="about-meta">
<div class="item"><b>${esc(company.name||'')}</b><span>企业名称</span></div>
<div class="item"><b>${esc(company.website||'')}</b><span>官方网站</span></div>
</div>
</div>`;
grid.innerHTML=
'<div class="about-card glass reveal d1">'+
'<span class="quote">"</span>'+
'<h3><span class="tag">'+icon('compass')+'</span>'+t('about_vision')+'</h3>'+
'<p>'+esc(company.vision||'')+'</p>'+
'<div class="about-meta">'+
'<div class="item"><b>'+esc(company.founded_year||'—')+'</b><span>'+t('about_founded')+'</span></div>'+
'<div class="item"><b>'+esc(company.employee_count||'—')+'</b><span>'+t('about_scale')+'</span></div>'+
'</div>'+
'</div>'+
'<div class="about-card glass reveal d2">'+
'<span class="quote">"</span>'+
'<h3><span class="tag">'+icon('target')+'</span>'+t('about_mission')+'</h3>'+
'<p>'+esc(company.mission||'')+'</p>'+
'<div class="about-meta">'+
'<div class="item"><b>'+esc(company.name||'')+'</b><span>'+t('about_name')+'</span></div>'+
'<div class="item"><b>'+esc(company.website||'')+'</b><span>'+t('about_official')+'</span></div>'+
'</div>'+
'</div>';
grid.querySelectorAll('.reveal').forEach(el=>io.observe(el));
}
@@ -949,58 +1260,58 @@ function renderContact(company){
const wrap=document.getElementById('contactWrap');
const site=company.website||'';
const siteHref=site?(site.startsWith('http')?site:'https://'+site):'#';
wrap.innerHTML=`
<div class="contact-info glass reveal d1">
<h3>随时与我们联系</h3>
<p>无论您希望了解产品详情、寻求技术合作,还是加入我们,我们都期待您的来信。专业团队将在第一时间为您提供支持。</p>
<div class="contact-items">
<div class="contact-item">
<div class="ic">${icon('phone')}</div>
<div><div class="lbl">联系电话</div><div class="val">${esc(company.phone||'—')}</div></div>
</div>
<div class="contact-item">
<div class="ic">${icon('email')}</div>
<div><div class="lbl">电子邮箱</div><div class="val">${esc(company.email||'—')}</div></div>
</div>
<div class="contact-item">
<div class="ic">${icon('location')}</div>
<div><div class="lbl">公司地址</div><div class="val">${esc(company.address||'—')}</div></div>
</div>
<div class="contact-item">
<div class="ic">${icon('website')}</div>
<div><div class="lbl">官方网站</div><div class="val">${esc(site||'—')}</div></div>
</div>
</div>
</div>
<div class="contact-cards">
<a href="tel:${esc(company.phone||'')}" class="contact-mini glass reveal d1">
<div class="ic">${icon('phone')}</div>
<div class="lbl">电话</div>
<div class="val">${esc(company.phone||'—')}</div>
</a>
<a href="mailto:${esc(company.email||'')}" class="contact-mini glass reveal d2">
<div class="ic">${icon('email')}</div>
<div class="lbl">邮箱</div>
<div class="val">${esc(company.email||'—')}</div>
</a>
<div class="contact-mini glass reveal d3">
<div class="ic">${icon('location')}</div>
<div class="lbl">地址</div>
<div class="val">${esc(company.address||'—')}</div>
</div>
<a href="${siteHref}" target="_blank" rel="noopener" class="contact-mini glass reveal d4">
<div class="ic">${icon('website')}</div>
<div class="lbl">网站</div>
<div class="val">${esc(site||'—')}</div>
</a>
</div>`;
wrap.innerHTML=
'<div class="contact-info glass reveal d1">'+
'<h3>'+t('contact_info_title')+'</h3>'+
'<p>'+t('contact_info_desc')+'</p>'+
'<div class="contact-items">'+
'<div class="contact-item">'+
'<div class="ic">'+icon('phone')+'</div>'+
'<div><div class="lbl">'+t('contact_phone')+'</div><div class="val">'+esc(company.phone||'—')+'</div></div>'+
'</div>'+
'<div class="contact-item">'+
'<div class="ic">'+icon('email')+'</div>'+
'<div><div class="lbl">'+t('contact_email')+'</div><div class="val">'+esc(company.email||'—')+'</div></div>'+
'</div>'+
'<div class="contact-item">'+
'<div class="ic">'+icon('location')+'</div>'+
'<div><div class="lbl">'+t('contact_address')+'</div><div class="val">'+esc(company.address||'—')+'</div></div>'+
'</div>'+
'<div class="contact-item">'+
'<div class="ic">'+icon('website')+'</div>'+
'<div><div class="lbl">'+t('contact_website')+'</div><div class="val">'+esc(site||'—')+'</div></div>'+
'</div>'+
'</div>'+
'</div>'+
'<div class="contact-cards">'+
'<a href="tel:'+esc(company.phone||'')+'" class="contact-mini glass reveal d1">'+
'<div class="ic">'+icon('phone')+'</div>'+
'<div class="lbl">'+t('contact_card_phone')+'</div>'+
'<div class="val">'+esc(company.phone||'—')+'</div>'+
'</a>'+
'<a href="mailto:'+esc(company.email||'')+'" class="contact-mini glass reveal d2">'+
'<div class="ic">'+icon('email')+'</div>'+
'<div class="lbl">'+t('contact_card_email')+'</div>'+
'<div class="val">'+esc(company.email||'—')+'</div>'+
'</a>'+
'<div class="contact-mini glass reveal d3">'+
'<div class="ic">'+icon('location')+'</div>'+
'<div class="lbl">'+t('contact_card_address')+'</div>'+
'<div class="val">'+esc(company.address||'—')+'</div>'+
'</div>'+
'<a href="'+siteHref+'" target="_blank" rel="noopener" class="contact-mini glass reveal d4">'+
'<div class="ic">'+icon('website')+'</div>'+
'<div class="lbl">'+t('contact_card_website')+'</div>'+
'<div class="val">'+esc(site||'—')+'</div>'+
'</a>'+
'</div>';
wrap.querySelectorAll('.reveal').forEach(el=>io.observe(el));
}
function renderFooter(company){
const name=company.name||'Nexus 科技集团';
const shortName=name.replace(/科技集团|科技|集团/g,'').trim()||'Nexus';
document.getElementById('footerName').innerHTML=esc(shortName)+'<span>科技</span>';
const name=company.name||('Nexus '+t('logo_suffix'));
const shortName=name.replace(/科技集團|科技|集團|科技集团|科技|集团/g,'').trim()||'Nexus';
document.getElementById('footerName').innerHTML=esc(shortName)+'<span>'+t('logo_suffix')+'</span>';
document.getElementById('footerDesc').textContent=truncate(company.description,80);
document.getElementById('footPhone').textContent=company.phone||'';
document.getElementById('footPhone').href='tel:'+(company.phone||'');
@@ -1012,62 +1323,81 @@ function renderFooter(company){
document.getElementById('footSite').href=site?(site.startsWith('http')?site:'https://'+site):'#';
const year=new Date().getFullYear();
const fy=company.founded_year||2010;
document.getElementById('copyRight').textContent='© '+fy+'-'+year+' '+name+'. 保留所有权利.';
document.getElementById('copyRight').textContent='\u00a9 '+fy+'-'+year+' '+name+'. '+t('copyright_suffix');
}
/* =========================================================
错误提示
========================================================= */
function showError(msg){
const html=`<div class="error-box">
<div class="ic"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="12"/><line x1="12" y1="16" x2="12.01" y2="16"/></svg></div>
<h3>数据加载失败</h3>
<p>${esc(msg||'无法连接到服务器,请稍后重试。')}</p>
<button class="btn btn-primary" onclick="location.reload()">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><polyline points="23 4 23 10 17 10"/><path d="M20.49 15a9 9 0 1 1-2.12-9.36L23 10"/></svg>
重新加载
</button>
</div>`;
['statsGrid','servicesGrid','newsGrid','teamGrid','aboutGrid','contactWrap'].forEach(id=>{
const el=document.getElementById(id);
var html='<div class="error-box">'+
'<div class="ic"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="12"/><line x1="12" y1="16" x2="12.01" y2="16"/></svg></div>'+
'<h3>'+t('error_title')+'</h3>'+
'<p>'+esc(msg||t('error_desc'))+'</p>'+
'<button class="btn btn-primary" onclick="location.reload()">'+
'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><polyline points="23 4 23 10 17 10"/><path d="M20.49 15a9 9 0 1 1-2.12-9.36L23 10"/></svg>'+
t('error_reload')+
'</button>'+
'</div>';
['statsGrid','servicesGrid','newsGrid','teamGrid','aboutGrid','contactWrap'].forEach(function(id){
var el=document.getElementById(id);
if(el) el.innerHTML=html;
});
document.getElementById('heroTitle').textContent='数据加载失败';
document.getElementById('heroDesc').textContent=msg||'请检查网络连接后重试';
document.getElementById('heroTitle').textContent=t('error_title');
document.getElementById('heroDesc').textContent=msg||t('error_network');
}
/* =========================================================
语言切换回调:重新渲染动态内容
========================================================= */
var lastData={};
function onLangChange(){
applyI18n();
if(lastData.company){
renderHero(lastData.company);
renderStats(lastData.company);
renderServices(lastData.services||[]);
renderNews(lastData.news||[]);
renderTeam(lastData.team||[]);
renderAbout(lastData.company);
renderContact(lastData.company);
renderFooter(lastData.company);
}
}
/* =========================================================
主流程:获取数据并渲染
========================================================= */
async function bootstrap(){
applyI18n();
try{
const res=await fetch('/api/v1/enterprise/all',{headers:{'Accept':'application/json'}});
if(!res.ok) throw new Error('服务器响应异常 ('+res.status+')');
if(!res.ok) throw new Error('Server error ('+res.status+')');
const json=await res.json();
if(json.code!==0) throw new Error(json.message||'接口返回错误');
if(json.code!==0) throw new Error(json.message||'API error');
const data=json.data||{};
const company=data.company||{};
const services=data.services||[];
const news=data.news||[];
const team=data.team||[];
lastData={
company:data.company||{},
services:data.services||[],
news:data.news||[],
team:data.team||[]
};
renderHero(company);
renderStats(company);
renderServices(services);
renderNews(news);
renderTeam(team);
renderAbout(company);
renderContact(company);
renderFooter(company);
renderHero(lastData.company);
renderStats(lastData.company);
renderServices(lastData.services);
renderNews(lastData.news);
renderTeam(lastData.team);
renderAbout(lastData.company);
renderContact(lastData.company);
renderFooter(lastData.company);
// 隐藏加载屏
setTimeout(()=>document.getElementById('loadingScreen').classList.add('hide'),300);
// 重新观察渐入元素(数据渲染后新增的)
setTimeout(observeReveals,50);
}catch(err){
console.error('[bootstrap]',err);
document.getElementById('loadingScreen').classList.add('hide');
showError(err.message||'网络请求失败');
showError(err.message||'Network error');
}
}