从0到1:用 Qwen3-Coder 和 高德MCP 助力数字文旅建造——国庆山西游

14,998 阅读33分钟

在这里插入图片描述

从0到1:用 Qwen3-Coder 和 高德MCP 助力数字文旅建造——国庆山西游

1. 背景

“技术不是替代旅行,而是让旅途更有把握,让每一次选择更符合你的期待。”

随着大模型与地图服务能力的成熟,围绕旅游场景的“智能行程助理”成为低门槛、强体验的实践方向。Qwen3-Coder 负责理解需求、生成代码与自动化操作,高德MCP 则作为地理数据能力的桥梁,承接地理编码、路径规划、天气与POI等服务。本文以“国庆山西游”原型为例,提供从0到1的构建路径,帮助读者快速完成一个可本地运行、无需外部依赖的演示级系统。

2.效果展示

首页展示:

在这里插入图片描述

地图导览:

在这里插入图片描述

行程规划:

在这里插入图片描述

天气查询: 在这里插入图片描述

3. 相关介绍

3.1 数字文旅

数字文旅强调以数据与智能驱动旅行全流程,包括目的地信息聚合、行程生成、动态调整与复盘沉淀。目标不只是“把信息摆齐”,而是通过算法与工具让决策更高效、体验更顺滑。

3.2 Qwen3-Coder

  • Qwen3-Coder-Plus:作为“理解-生成-优化”的智能中枢,擅长在复杂需求中做任务拆解与自动化拼装。
  • Qwen-Code CLI:面向开发/办公的命令行“驾驶舱”,用自然语言与模型对话,驱动任务执行,降低实施门槛。

3.3 高德MCP

高德MCP将高德开放平台能力以 MCP 协议方式提供,统一了模型侧的调用姿势,实现地点搜索、地理编码、路线规划、天气与POI检索等,便于与大模型工作流拼装。

4.分步指南(超详细)

4.1 第一步 激活Qwen3-Coder

(1)获取 API Key:访问阿里云百炼平台(bailian.console.aliyun.com/?tab=app#/a…) 或魔搭平台(modelscope.cn/models) 来开通服务和获取 API Key。(以阿里云百炼平台为例)

在这里插入图片描述

(2)安装Node.js 版本:必须安装 Node.js 20 或更高版本。

访问Node.js — Download Node.js® 官方网站的下载页面,选择平台为 Windows 并选择下载并安装(推荐 LTS 版本)

**安装验证:**安装完成后,打开命令提示符(CMD)并运行以下命令,以确认 Node.js 和 npm(Node.js 包管理器)已成功安装。

node -v
npm -v

在这里插入图片描述

(3)安装Qwen-Code

打开命令提示符(CMD)并运行以下命令:

npm install -g @qwen-code/qwen-code

安装完成后,通过以下命令验证安装是否成功:

qwen --version

在这里插入图片描述

(4)系统级环境变量:打开命令提示符(CMD)并运行以下命令

setx OPENAI_API_KEY "YOUR_API_KEY_HERE"
setx OPENAI_BASE_URL "YOUR_REGIONAL_BASE_URL"
setx OPENAI_MODEL "qwen3-coder-plus"

中国内地用户:
OPENAI_BASE_URL=https://dashscope.aliyuncs.com/compatible-mode/v1
国际用户:
OPENAI_BASE_URL=https://dashscope-intl.aliyuncs.com/compatible-mode/v1

在这里插入图片描述

(5)启动Qwen3-Coder:

打开命令提示符(CMD)并运行以下命令(先到指定文件夹,再启动):

cd 路径
qwen

在这里插入图片描述

4.2 第二步 配置高德MCP

(1)访问高德开放平台获取你自己的API密钥。

在这里插入图片描述

(2)根据以下配置MCP:

{
  "mcpServers": {
    "gaode": {
      "command": "cmd",
      "args": [
        "/c",
        "npx",
        "@wopal/mcp-gaode-maps"
      ],
      "env": {
        "GAODE_API_KEY": "您的高德地图API密钥"
      }
    }
  }
}

4.3 实战开发数字文旅——构建国庆山西游

我们以“5日游:大同—太原—平遥”为主线,组合规划、路线、天气与POI功能,产出可运行原型页面。

以下为用于驱动 Qwen3-Coder 的首轮提示词(内含示例 Key 字段,按需替换):

我想设计一个项目用高德MCP 助力数字文旅建造——国庆山西游:
背景需求:
- 国庆的来临,欢迎大家来山西游
要求:
- 帮我规划一条山西5日游路线,包括大同,太原,平遥等,并提供可视化地图,考虑交通时间和各景点的游览时长
- 请查询各个风景区的开放时间、门票价格
- 请推荐各个风景区附近评分最高的餐厅
- 请查询山西那5日的天气情况,并给出适合的旅游活动建议
- 每个对方加入可以直接位置导航

界面与体验要求:
- 可视化地图使用内嵌,并且展示各景点之间的顺序以及路线,"GAODE_API_KEY": "示例 Key "
- 卡通风格:界面色彩明亮,字体圆润可爱,符合大众审美。
- 在网站最下面:山西国庆5日游旅行助手 © 2025 制作者:LucianaiB
- 无需联网,纯本地运行(HTML + CSS + JS 单文件)

技术要求:
- 使用 HTML、CSS、JavaScript 单文件实现
- 调用高德MCP作为地点路线支持
- 不依赖任何外部库或服务器
请提供一个开箱即用的解决方案,包含全部代码和使用指南。

提示词投喂与结果观察:

在这里插入图片描述

开始漫长的测试与优化中...

在这里插入图片描述

效果展示:

在这里插入图片描述

5.全文总结

5.1 用户旅程与交互流

journey
  title 山西5日游用户旅程
  section 出行前
    搜集目的地信息: 3: 游客
    生成初版行程: 4: Qwen3-Coder
  section 出行中
    路线导航与换乘: 4: 高德MCP
    附近餐饮推荐: 3: 高德MCP
    天气联动调整: 3: 系统
  section 出行后
    评价与复盘: 2: 游客
    数据沉淀与优化: 4: 系统

5.2模块职责与数据流(对照表)

模块/组件主要职责关键输入关键输出典型风险
Qwen3-Coder需求理解、代码/文案生成、任务分解自然语言、上下文、示例HTML/JS片段、提示词、脚本幻觉、指令不明确
高德MCP地理编码/路径/天气/POI经纬度、关键词、API Key路线polyline、POI列表、天气数据配额、鉴权失败
前端页面地图渲染、交互、可视化API响应、行程数据标注、连线、行程卡片兼容性、性能
配置与密钥环境变量、安全管理OPENAI_*、GAODE_API_KEY安全调用上下文泄露、误配

5.3 总结

本原型以“国庆山西游”为故事线,目标是用尽量少的工程成本,验证“一套大模型+地图服务”的可行性与可用性。Qwen3-Coder 在这里承担了两个关键角色:其一是把自然语言需求转为可执行方案(例如拆出页面结构、脚本逻辑与接口参数),其二是在多轮调试中快速重构与迁移,实现“人—机共创”的高效闭环。高德MCP 则起到“能力联通器”的作用,向上以统一的 MCP 协议与模型对接,向下聚合地理编码、路径规划、天气与 POI 等核心能力,使得我们不必在各种零碎 SDK 之间反复切换。二者结合的结果,是把传统需要多人协作、分工较细的工作流,压缩为一人可控的小闭环,尤其适合中小团队或教学与演示场景。

从实施路径看,本文遵循“先能跑、再好看、最后稳”的节奏:先保证 API Key、MCP 适配与页面基础能力可运行;随后完善地图可视化与行程结构化表达;再通过日志回放与抽样核验,逐步抬高准确性与稳定性。为了避免“好看不耐用”,我们引入了量化评测指标,分别从准确性、响应速度、成本效益、易用性与稳定性给出权重与打分标准,鼓励在后续版本中进行 A/B 对比与数据驱动的优化。风险方面,重点提示密钥管理(统一走环境变量)、调用配额(限流与重试)与隐私定位(授权与最小化采集)等问题,确保方案不仅“能演示”,也具备延展到生产级的基本素养。

更重要的是,可复用性。本文提供的提示词框架、模块职责对照与旅程图,可以直接迁移到其他目的地或主题(例如“研学游”“亲子游”“红色文化游”),仅需替换城市与兴趣点,即可组合新的原型。倘若后续接入更多数据源(如票务、住宿与评价),或引入前端组件库与服务端缓存,整体体验还可以在不改动核心架构的前提下平滑进化。综上,这套“Qwen3-Coder + 高德MCP”的组合为数字文旅提供了一条具备性价比与可复制性的落地路径:既能快速亮相,也能循序渐进地走向成熟。

“把复杂留给系统,把选择还给用户。”

“不是要替你做决定,而是把更好的选项摆在你面前。”

6.完整代码

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>山西5日游旅行助手 - 发现三晋之美</title>
    <script src="https://webapi.amap.com/maps?v=2.0&key=fdda8428fc9485f355b24b1c76f6f147"></script>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }

        body {
            font-family: 'Microsoft YaHei', '微软雅黑', Arial, sans-serif;
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            min-height: auto;
            color: #333;
            overflow-x: hidden;
        }

        /* 🎨 动态渐变背景动画 */
        body::before {
            content: '';
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background: linear-gradient(45deg, #667eea, #764ba2, #f093fb, #f5576c, #4facfe, #00f2fe);
            background-size: 400% 400%;
            animation: gradientShift 15s ease infinite;
            z-index: -2;
        }

        @keyframes gradientShift {
            0% { background-position: 0% 50%; }
            50% { background-position: 100% 50%; }
            100% { background-position: 0% 50%; }
        }

        /* 🌟 鼠标跟随光晕效果 */
        .cursor-glow {
            position: fixed;
            width: 20px;
            height: 20px;
            background: radial-gradient(circle, rgba(255,255,255,0.8) 0%, rgba(255,255,255,0.2) 50%, transparent 100%);
            border-radius: 50%;
            pointer-events: none;
            z-index: 9999;
            transition: transform 0.1s ease;
            mix-blend-mode: screen;
        }

        /* ✨ 页面切换动画 */
        .page-transition {
            opacity: 0;
            transform: translateY(30px);
            transition: all 0.6s cubic-bezier(0.4, 0, 0.2, 1);
        }

        .page-transition.active {
            opacity: 1;
            transform: translateY(0);
        }

        .fade-in {
            animation: fadeIn 0.8s ease-out forwards;
        }

        @keyframes fadeIn {
            from {
                opacity: 0;
                transform: translateY(20px);
            }
            to {
                opacity: 1;
                transform: translateY(0);
            }
        }

        /* 🎯 按钮波纹效果 */
        .ripple-effect {
            position: relative;
            overflow: hidden;
        }

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

        .ripple-effect:active::before {
            width: 300px;
            height: 300px;
        }

        /* 💫 卡片悬浮3D效果 */
        .card-3d {
            transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
            transform-style: preserve-3d;
        }

        .card-3d:hover {
            transform: translateY(-10px) rotateX(5deg) rotateY(5deg);
            box-shadow: 0 20px 40px rgba(0,0,0,0.2);
        }

        /* 💓 心跳动画 */
        .heartbeat {
            animation: heartbeat 2s ease-in-out infinite;
        }

        @keyframes heartbeat {
            0%, 100% { transform: scale(1); }
            14% { transform: scale(1.1); }
            28% { transform: scale(1); }
            42% { transform: scale(1.1); }
            70% { transform: scale(1); }
        }

        /* ⌨️ 打字机效果 */
        .typewriter {
            overflow: hidden;
            border-right: 2px solid rgba(255,255,255,0.75);
            white-space: nowrap;
            animation: typing 3.5s steps(40, end), blink-caret 0.75s step-end infinite;
        }

        @keyframes typing {
            from { width: 0; }
            to { width: 100%; }
        }

        @keyframes blink-caret {
            from, to { border-color: transparent; }
            50% { border-color: rgba(255,255,255,0.75); }
        }

        /* 🔢 数字计数动画 */
        .counter {
            transition: all 0.3s ease;
        }

        /* 📱 触摸手势支持 */
        .swipe-container {
            touch-action: pan-x;
            position: relative;
        }

        /* 🎪 元素依次出现动画 */
        .stagger-animation {
            opacity: 0;
            transform: translateY(30px);
            animation: staggerIn 0.6s ease-out forwards;
        }

        .stagger-animation:nth-child(1) { animation-delay: 0.1s; }
        .stagger-animation:nth-child(2) { animation-delay: 0.2s; }
        .stagger-animation:nth-child(3) { animation-delay: 0.3s; }
        .stagger-animation:nth-child(4) { animation-delay: 0.4s; }
        .stagger-animation:nth-child(5) { animation-delay: 0.5s; }

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

        /* 🌊 滚动隐藏导航栏 */
        .header {
            transition: transform 0.3s ease-in-out;
        }

        .header.hidden {
            transform: translateY(-100%);
        }

        /* 🎨 增强现有动画 */
        .nav-item {
            position: relative;
            overflow: hidden;
        }

        .nav-item::after {
            content: '';
            position: absolute;
            bottom: 0;
            left: -100%;
            width: 100%;
            height: 2px;
            background: linear-gradient(90deg, transparent, rgba(255,255,255,0.8), transparent);
            transition: left 0.5s ease;
        }

        .nav-item:hover::after {
            left: 100%;
        }

        /* 🎭 按钮增强动画 */
        .enhanced-button {
            position: relative;
            overflow: hidden;
            transform: perspective(1px) translateZ(0);
            transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
        }

        .enhanced-button:hover {
            transform: scale(1.05) translateZ(0);
            box-shadow: 0 10px 30px rgba(0,0,0,0.2);
        }

        .enhanced-button:active {
            transform: scale(0.98) translateZ(0);
        }

        /* 🌈 彩虹边框动画 */
        .rainbow-border {
            position: relative;
            background: linear-gradient(45deg, #ff0000, #ff7300, #fffb00, #48ff00, #00ffd5, #002bff, #7a00ff, #ff00c8, #ff0000);
            background-size: 400%;
            border-radius: 15px;
            padding: 2px;
            animation: rainbow 3s linear infinite;
        }

        @keyframes rainbow {
            0% { background-position: 0% 50%; }
            100% { background-position: 400% 50%; }
        }

        .rainbow-border > * {
            background: white;
            border-radius: 13px;
        }

        /* 🎪 旋转加载动画增强 */
        .loading-enhanced {
            position: relative;
            width: 60px;
            height: 60px;
        }

        .loading-enhanced::before,
        .loading-enhanced::after {
            content: '';
            position: absolute;
            border-radius: 50%;
            animation: spin 1.5s linear infinite;
        }

        .loading-enhanced::before {
            width: 60px;
            height: 60px;
            border: 3px solid transparent;
            border-top: 3px solid var(--primary-orange);
            border-right: 3px solid var(--primary-blue);
        }

        .loading-enhanced::after {
            width: 40px;
            height: 40px;
            top: 10px;
            left: 10px;
            border: 3px solid transparent;
            border-bottom: 3px solid var(--accent-yellow);
            border-left: 3px solid var(--accent-pink);
            animation-direction: reverse;
            animation-duration: 1s;
        }

        /* 🎨 滑动切换动画 */
        .slide-left {
            animation: slideLeft 0.5s ease-out;
        }

        .slide-right {
            animation: slideRight 0.5s ease-out;
        }

        @keyframes slideLeft {
            from { transform: translateX(100%); opacity: 0; }
            to { transform: translateX(0); opacity: 1; }
        }

        @keyframes slideRight {
            from { transform: translateX(-100%); opacity: 0; }
            to { transform: translateX(0); opacity: 1; }
        }

        /* 🌟 粒子效果背景 */
        .particles {
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            pointer-events: none;
            z-index: -1;
        }

        .particle {
            position: absolute;
            width: 4px;
            height: 4px;
            background: rgba(255, 255, 255, 0.5);
            border-radius: 50%;
            animation: float 6s ease-in-out infinite;
        }

        .particle:nth-child(odd) {
            animation-delay: -2s;
            animation-duration: 8s;
        }

        .particle:nth-child(even) {
            animation-delay: -4s;
            animation-duration: 10s;
        }

        @keyframes float {
            0%, 100% {
                transform: translateY(0px) rotate(0deg);
                opacity: 0;
            }
            10%, 90% {
                opacity: 1;
            }
            50% {
                transform: translateY(-100px) rotate(180deg);
            }
        }

        /* 卡通风格主题色彩 */
        :root {
            --primary-orange: #FF6B35;
            --primary-blue: #4ECDC4;
            --accent-yellow: #FFE66D;
            --accent-pink: #FF8B94;
            --accent-green: #95E1D3;
            --bg-white: #FFFFFF;
            --text-dark: #2C3E50;
            --text-light: #7F8C8D;
        }

        /* 顶部导航栏 */
        .header {
            background: linear-gradient(90deg, var(--primary-orange), var(--primary-blue));
            padding: 15px 0;
            box-shadow: 0 4px 20px rgba(0,0,0,0.1);
            position: relative;
            overflow: hidden;
        }

        .header::before {
            content: '';
            position: absolute;
            top: -50%;
            left: -50%;
            width: 200%;
            height: 200%;
            background: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"><circle cx="20" cy="20" r="2" fill="rgba(255,255,255,0.1)"/><circle cx="80" cy="40" r="1.5" fill="rgba(255,255,255,0.1)"/><circle cx="40" cy="80" r="1" fill="rgba(255,255,255,0.1)"/></svg>');
            animation: float 20s infinite linear;
        }

        @keyframes float {
            0% { transform: translate(-50%, -50%) rotate(0deg); }
            100% { transform: translate(-50%, -50%) rotate(360deg); }
        }

        .nav-container {
            max-width: 1200px;
            margin: 0 auto;
            display: flex;
            justify-content: space-between;
            align-items: center;
            padding: 0 20px;
            position: relative;
            z-index: 2;
        }

        .logo {
            display: flex;
            align-items: center;
            color: white;
            font-size: 24px;
            font-weight: bold;
            text-decoration: none;
        }

        .logo::before {
            content: '🏯';
            font-size: 32px;
            margin-right: 10px;
            animation: bounce 2s infinite;
        }

        @keyframes bounce {
            0%, 20%, 50%, 80%, 100% { transform: translateY(0); }
            40% { transform: translateY(-10px); }
            60% { transform: translateY(-5px); }
        }

        .nav-menu {
            display: flex;
            gap: 20px;
            list-style: none;
        }

        .nav-item {
            background: rgba(255,255,255,0.2);
            border-radius: 25px;
            padding: 10px 20px;
            cursor: pointer;
            transition: all 0.3s ease;
            color: white;
            font-weight: 500;
            backdrop-filter: blur(10px);
        }

        .nav-item:hover {
            background: rgba(255,255,255,0.3);
            transform: translateY(-2px);
            box-shadow: 0 5px 15px rgba(0,0,0,0.2);
        }

        /* 主要内容区域 */
        .main-container {
            max-width: 1200px;
            margin: 0 auto;
            padding: 20px;
            display: grid;
            grid-template-columns: 300px 1fr;
            gap: 20px;
            min-height: auto;
        }

        /* 侧边栏 */
        .sidebar {
            background: var(--bg-white);
            border-radius: 20px;
            padding: 25px;
            box-shadow: 0 10px 30px rgba(0,0,0,0.1);
            height: fit-content;
            position: sticky;
            top: 20px;
        }

        .sidebar-title {
            color: var(--primary-orange);
            font-size: 20px;
            font-weight: bold;
            margin-bottom: 20px;
            display: flex;
            align-items: center;
        }

        .sidebar-title::before {
            content: '🗺️';
            margin-right: 8px;
            font-size: 24px;
        }

        .route-days {
            display: flex;
            flex-direction: column;
            gap: 12px;
        }

        .day-button {
            background: linear-gradient(135deg, var(--accent-yellow), var(--accent-pink));
            border: none;
            border-radius: 15px;
            padding: 15px;
            cursor: pointer;
            transition: all 0.3s ease;
            color: var(--text-dark);
            font-weight: 600;
            font-size: 14px;
            position: relative;
            overflow: hidden;
        }

        .day-button:hover {
            transform: translateY(-3px);
            box-shadow: 0 8px 25px rgba(0,0,0,0.15);
        }

        .day-button.active {
            background: linear-gradient(135deg, var(--primary-orange), var(--primary-blue));
            color: white;
        }

        .day-button::before {
            content: '';
            position: absolute;
            top: 0;
            left: -100%;
            width: 100%;
            height: 100%;
            background: linear-gradient(90deg, transparent, rgba(255,255,255,0.3), transparent);
            transition: left 0.5s;
        }

        .day-button:hover::before {
            left: 100%;
        }

        /* 功能按钮区域 */
        .function-buttons {
            margin-top: 25px;
            display: flex;
            flex-direction: column;
            gap: 12px;
        }

        .function-btn {
            background: var(--bg-white);
            border: 2px solid var(--primary-blue);
            border-radius: 12px;
            padding: 12px 16px;
            cursor: pointer;
            transition: all 0.3s ease;
            color: var(--primary-blue);
            font-weight: 500;
            display: flex;
            align-items: center;
            justify-content: center;
            gap: 8px;
        }

        .function-btn:hover {
            background: var(--primary-blue);
            color: white;
            transform: scale(1.05);
        }

        /* 主内容区域 */
        .content-area {
            background: var(--bg-white);
            min-height: auto;
            height: fit-content;
            padding: 0;
            margin: 0;
            min-height: auto;
            padding: 0;
            margin: 0;
            border-radius: 20px;
            overflow: hidden;
            box-shadow: 0 10px 30px rgba(0,0,0,0.1);
            position: relative;
        }

        /* 欢迎页面 */
        .welcome-section {
            padding: 40px;
            height: fit-content;
            min-height: auto;
            margin-bottom: 0;
            height: fit-content;
            min-height: auto;
            text-align: center;
            background: linear-gradient(135deg, var(--accent-yellow), var(--accent-pink));
            color: var(--text-dark);
        }

        .welcome-title {
            font-size: 36px;
            font-weight: bold;
            margin-bottom: 20px;
            text-shadow: 2px 2px 4px rgba(0,0,0,0.1);
        }

        .welcome-subtitle {
            font-size: 18px;
            margin-bottom: 30px;
            opacity: 0.8;
        }

        .start-journey-btn {
            background: var(--primary-orange);
            color: white;
            border: none;
            padding: 15px 30px;
            border-radius: 25px;
            font-size: 18px;
            font-weight: bold;
            cursor: pointer;
            transition: all 0.3s ease;
            box-shadow: 0 5px 15px rgba(255,107,53,0.3);
        }

        .start-journey-btn:hover {
            transform: translateY(-3px);
            box-shadow: 0 8px 25px rgba(255,107,53,0.4);
        }

        /* 地图区域 */
        .map-section {
            display: none;
            height: 600px;
            position: relative;
        }

        #map-container {
            width: 100%;
            height: 100%;
            border-radius: 0 0 20px 20px;
        }

        /* 路线详情区域 */
        .route-section {
            display: none;
            padding: 30px;
        }

        .panel-title {
            color: var(--primary-orange);
            font-size: 24px;
            font-weight: bold;
            margin-bottom: 25px;
            display: flex;
            align-items: center;
        }

        .panel-title::before {
            content: '📍';
            margin-right: 10px;
            font-size: 28px;
        }

        .route-timeline {
            display: flex;
            flex-direction: column;
            gap: 20px;
        }

        .timeline-item {
            background: linear-gradient(135deg, #f8f9fa, #e9ecef);
            border-radius: 15px;
            padding: 20px;
            position: relative;
            border-left: 5px solid var(--primary-blue);
            transition: all 0.3s ease;
        }

        .timeline-item:hover {
            transform: translateX(5px);
            box-shadow: 0 5px 20px rgba(0,0,0,0.1);
        }

        .timeline-day {
            background: var(--primary-orange);
            color: white;
            padding: 5px 15px;
            border-radius: 20px;
            font-weight: bold;
            display: inline-block;
            margin-bottom: 15px;
        }

        .timeline-content h3 {
            color: var(--text-dark);
            margin-bottom: 10px;
        }

        .timeline-attractions {
            display: flex;
            flex-wrap: wrap;
            gap: 10px;
            margin-top: 15px;
        }

        .attraction-tag {
            background: var(--accent-yellow);
            color: var(--text-dark);
            padding: 5px 12px;
            border-radius: 15px;
            font-size: 12px;
            font-weight: 500;
        }

        /* 天气区域 */
        .weather-section {
            display: none;
            padding: 30px;
        }

        .weather-cards {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
            gap: 20px;
            margin-top: 20px;
        }

        .weather-card {
            background: linear-gradient(135deg, var(--primary-blue), var(--accent-green));
            color: white;
            padding: 20px;
            border-radius: 15px;
            text-align: center;
            box-shadow: 0 5px 15px rgba(0,0,0,0.1);
        }

        .weather-city {
            font-size: 18px;
            font-weight: bold;
            margin-bottom: 10px;
        }

        .weather-temp {
            font-size: 32px;
            font-weight: bold;
            margin: 10px 0;
        }

        .weather-desc {
        .weather-desc {
            opacity: 0.9;
            font-size: 14px;
        }

        .weather-icon {
            font-size: 48px;
            margin: 10px 0;
            animation: float 3s ease-in-out infinite;
        }

        @keyframes float {
            0%, 100% { transform: translateY(0px); }
            50% { transform: translateY(-5px); }
        }

        .weather-range {
            font-size: 14px;
            opacity: 0.8;
            margin-bottom: 12px;
        }

        .weather-details {
            display: grid;
            gap: 8px;
            margin-top: 15px;
        }

        .weather-detail-item {
            display: flex;
            justify-content: space-between;
            align-items: center;
            font-size: 13px;
            opacity: 0.9;
            padding: 6px 12px;
            background: rgba(255,255,255,0.15);
            border-radius: 8px;
            backdrop-filter: blur(10px);
        }

        .weather-detail-item span:last-child {
            font-weight: bold;
        }

        .forecast-item {
            display: flex;
            align-items: center;
            justify-content: space-between;
            padding: 12px 0;
            border-bottom: 1px solid #eee;
        }

        .forecast-item:last-child {
            border-bottom: none;
        }

        .forecast-date {
            font-weight: bold;
            color: var(--text-dark);
            min-width: 80px;
        }

        .forecast-weather {
            display: flex;
            align-items: center;
            gap: 10px;
            flex: 1;
            justify-content: center;
        }

        .forecast-icon {
            font-size: 24px;
        }

        .forecast-desc {
            color: var(--text-light);
            font-size: 14px;
        }

        .forecast-temp {
            font-weight: bold;
            color: var(--primary-orange);
            min-width: 80px;
            text-align: right;
        }
        }

        .weather-details {
            display: grid;
            grid-template-columns: repeat(3, 1fr);
            gap: 8px;
            margin-top: 12px;
            position: relative;
            z-index: 2;
        }

        .weather-detail-item {
            background: rgba(255,255,255,0.2);
            padding: 8px;
            border-radius: 8px;
            text-align: center;
            font-size: 12px;
        }

        .weather-detail-label {
            opacity: 0.8;
            margin-bottom: 4px;
        }

        .weather-detail-value {
            font-weight: bold;
        }

        /* 5日预报样式 */
        .forecast-container {
            margin-top: 25px;
            background: #f8f9fa;
            padding: 20px;
            border-radius: 15px;
        }

        .forecast-title {
            color: var(--primary-orange);
            font-size: 18px;
            font-weight: bold;
            margin-bottom: 15px;
            display: flex;
            align-items: center;
        }

        .forecast-title::before {
            content: '📅';
            margin-right: 8px;
        }

        .forecast-grid {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
            gap: 12px;
        }

        .forecast-item {
            background: white;
            padding: 15px;
            border-radius: 12px;
            text-align: center;
            box-shadow: 0 2px 8px rgba(0,0,0,0.1);
            transition: transform 0.2s ease;
        }

        .forecast-item:hover {
            transform: translateY(-2px);
        }

        .forecast-date {
            font-weight: bold;
            color: var(--text-dark);
            margin-bottom: 8px;
            font-size: 14px;
        }

        .forecast-icon {
            font-size: 24px;
            margin: 8px 0;
        }

        .forecast-desc {
            font-size: 12px;
            color: var(--text-light);
            margin-bottom: 8px;
        }

        .forecast-temp {
            font-weight: bold;
            color: var(--primary-blue);
            font-size: 13px;
        }

        /* 旅游指数样式 */
        .travel-index-container {
            margin-top: 25px;
            background: linear-gradient(135deg, #e3f2fd, #f3e5f5);
            padding: 20px;
            border-radius: 15px;
        }

        .travel-index-title {
            color: var(--primary-blue);
            font-size: 18px;
            font-weight: bold;
            margin-bottom: 15px;
            display: flex;
            align-items: center;
        }

        .travel-index-title::before {
            content: '🎯';
            margin-right: 8px;
        }

        .travel-index-grid {
            display: grid;
            gap: 10px;
        }

        .travel-index-item {
            background: white;
            padding: 12px 15px;
            border-radius: 10px;
            display: flex;
            justify-content: space-between;
            align-items: center;
            font-size: 14px;
        }

        /* 天气预警样式 */
        .weather-alerts {
            margin-top: 25px;
            background: linear-gradient(135deg, #fff3e0, #fce4ec);
            padding: 20px;
            border-radius: 15px;
            border-left: 4px solid #ff9800;
        }

        .alert-title {
            color: #ff9800;
            font-size: 16px;
            font-weight: bold;
            margin-bottom: 12px;
            display: flex;
            align-items: center;
        }

        .alert-title::before {
            content: '⚠️';
            margin-right: 8px;
        }

        .alert-content {
            color: var(--text-dark);
            line-height: 1.5;
            font-size: 14px;
        }

        /* 天气更新时间 */
        .weather-update {
            text-align: center;
            margin-top: 20px;
            color: var(--text-light);
            font-size: 12px;
        }

        .refresh-weather-btn {
            background: var(--primary-blue);
            color: white;
            border: none;
            padding: 8px 16px;
            border-radius: 20px;
            font-size: 12px;
            cursor: pointer;
            margin-left: 10px;
            transition: all 0.3s ease;
        }

        .refresh-weather-btn:hover {
            background: var(--primary-orange);
            transform: scale(1.05);
        }

        /* 响应式设计 */
        @media (max-width: 768px) {
            .main-container {
                grid-template-columns: 1fr;
                gap: 15px;
                padding: 15px;
            }

            .sidebar {
                position: static;
                order: 2;
            }

            .nav-menu {
                display: none;
            }

            .welcome-title {
                font-size: 28px;
            }

            .map-section {
                height: 400px;
            }
        }

        /* 加载动画 */
        .loading {
            display: flex;
            justify-content: center;
            align-items: center;
            height: 200px;
        }

        .loading::after {
            content: '';
            width: 40px;
            height: 40px;
            border: 4px solid var(--accent-yellow);
            border-top: 4px solid var(--primary-orange);
            border-radius: 50%;
            animation: spin 1s linear infinite;
        }

        @keyframes spin {
            0% { transform: rotate(0deg); }
            100% { transform: rotate(360deg); }
        }
        /* 浮动按钮样式 */
        .floating-buttons {
            position: fixed;
            bottom: 20px;
            right: 20px;
            display: flex;
            flex-direction: column;
            gap: 10px;
            z-index: 1000;
        }

        .floating-btn {
            width: 50px;
            height: 50px;
            border-radius: 50%;
            border: none;
            background: rgba(255, 255, 255, 0.9);
            backdrop-filter: blur(10px);
            box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1);
            cursor: pointer;
            font-size: 20px;
            display: flex;
            align-items: center;
            justify-content: center;
            transition: all 0.3s ease;
        }

        .floating-btn:hover {
            transform: translateY(-2px);
            box-shadow: 0 6px 20px rgba(0, 0, 0, 0.15);
            background: rgba(255, 255, 255, 1);
        }
    </style>
</head>
<body>
    <!-- 顶部导航栏 -->
    <header class="header">
        <div class="nav-container">
            <a href="#" class="logo">山西5日游助手</a>
            <nav class="nav-menu">
                <div class="nav-item" data-section="welcome">首页</div>
                <div class="nav-item" data-section="map">地图导览</div>
                <div class="nav-item" data-section="route">行程规划</div>
                <div class="nav-item" data-section="weather">天气查询</div>
            </nav>
        </div>
    </header>

    <!-- 主要内容区域 -->
    <main class="main-container">
        <!-- 侧边栏 -->
        <aside class="sidebar">
            <div class="sidebar-title">5日游行程</div>
            <div class="route-days">
                <button class="day-button" data-day="1">
                    第1天 - 太原市区游<br>
                    <small>晋祠 → 山西博物院 → 柳巷</small>
                </button>
                <button class="day-button" data-day="2">
                    第2天 - 太原-平遥<br>
                    <small>乔家大院 → 平遥古城</small>
                </button>
                <button class="day-button" data-day="3">
                    第3天 - 平遥古城<br>
                    <small>古城墙 → 日升昌 → 县衙</small>
                </button>
                <button class="day-button" data-day="4">
                    第4天 - 平遥-大同<br>
                    <small>王家大院 → 云冈石窟</small>
                </button>
                <button class="day-button" data-day="5">
                    第5天 - 大同-返程<br>
                    <small>悬空寺 → 华严寺</small>
                </button>
            </div>
            
            <div class="function-buttons">
            </div>
        </aside>

        <!-- 主内容区域 -->
        <section class="content-area">
            <!-- 欢迎页面 -->
            <div id="welcome" class="welcome-section">
                <h1 class="welcome-title">🏯 探索三晋文化之旅</h1>
                <p class="welcome-subtitle">
                    精心规划的山西5日游路线,带您领略千年古韵与现代魅力
                </p>
                <button class="start-journey-btn" data-section="map">
                    🚀 开始我的山西之旅
                </button>
                
                <div style="margin-top: 40px; margin-bottom: 0; display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 20px;">
                    <div style="background: rgba(255,255,255,0.9); padding: 20px; border-radius: 15px;">
                        <h3 style="color: var(--primary-orange); margin-bottom: 10px;">🏛️ 历史文化</h3>
                        <p>探访晋祠、平遥古城等千年古迹</p>
                    </div>
                    <div style="background: rgba(255,255,255,0.9); padding: 20px; border-radius: 15px;">
                        <h3 style="color: var(--primary-blue); margin-bottom: 10px;">🎨 石窟艺术</h3>
                        <p>欣赏云冈石窟的佛教艺术瑰宝</p>
                    </div>
                    <div style="background: rgba(255,255,255,0.9); padding: 20px; border-radius: 15px;">
                        <h3 style="color: var(--accent-pink); margin-bottom: 10px;">🍜 特色美食</h3>
                        <p>品尝刀削面、平遥牛肉等地道美味</p>
                    </div>
                </div>
            </div>

            <!-- 地图区域 -->
            <div id="map" class="map-section">
                <div id="map-container"></div>
            </div>

            <!-- 路线详情区域 -->
            <div id="route" class="route-section">
                <div class="panel-title">山西5日游完整行程</div>
                <div id="route-content" class="route-timeline">
                    <!-- 路线内容将通过JavaScript动态生成 -->
                </div>
            </div>

        <!-- 天气区域 -->
        <div id="weather" class="weather-section">
            <div class="panel-title">🌤️ 各城市天气预报</div>
            
            <!-- 天气更新时间 -->
            <div style="text-align: center; margin-bottom: 20px; color: var(--text-light); font-size: 14px;">
                <span id="weather-update-time">最后更新: --</span>
                <button onclick="updateWeather()" style="margin-left: 15px; background: var(--primary-blue); color: white; border: none; padding: 5px 12px; border-radius: 8px; cursor: pointer; font-size: 12px;">🔄 刷新</button>
            </div>

            <div class="weather-cards">
                <div class="weather-card" data-city="taiyuan">
                    <div class="weather-city">太原</div>
                    <div class="weather-icon">☀️</div>
                    <div class="weather-temp">22°C</div>
                    <div class="weather-range">15°C ~ 25°C</div>
                    <div class="weather-desc">晴转多云 适宜出行</div>
                    <div class="weather-details">
                        <div class="weather-detail-item">
                            <span>💨 风力</span>
                            <span class="wind-level">2级</span>
                        </div>
                        <div class="weather-detail-item">
                            <span>💧 湿度</span>
                            <span class="humidity">65%</span>
                        </div>
                        <div class="weather-detail-item">
                            <span>👁️ 能见度</span>
                            <span class="visibility">15km</span>
                        </div>
                    </div>
                </div>
                
                <div class="weather-card" data-city="pingyao">
                    <div class="weather-city">平遥</div>
                    <div class="weather-icon"></div>
                    <div class="weather-temp">20°C</div>
                    <div class="weather-range">13°C ~ 23°C</div>
                    <div class="weather-desc">多云 微风</div>
                    <div class="weather-details">
                        <div class="weather-detail-item">
                            <span>💨 风力</span>
                            <span class="wind-level">1级</span>
                        </div>
                        <div class="weather-detail-item">
                            <span>💧 湿度</span>
                            <span class="humidity">58%</span>
                        </div>
                        <div class="weather-detail-item">
                            <span>👁️ 能见度</span>
                            <span class="visibility">12km</span>
                        </div>
                    </div>
                </div>
                
                <div class="weather-card" data-city="datong">
                    <div class="weather-city">大同</div>
                    <div class="weather-icon">🌤️</div>
                    <div class="weather-temp">18°C</div>
                    <div class="weather-range">10°C ~ 21°C</div>
                    <div class="weather-desc">晴朗 空气清新</div>
                    <div class="weather-details">
                        <div class="weather-detail-item">
                            <span>💨 风力</span>
                            <span class="wind-level">3级</span>
                        </div>
                        <div class="weather-detail-item">
                            <span>💧 湿度</span>
                            <span class="humidity">45%</span>
                        </div>
                        <div class="weather-detail-item">
                            <span>👁️ 能见度</span>
                            <span class="visibility">20km</span>
                        </div>
                    </div>
                </div>
            </div>

            <!-- 5日天气预报 -->
            <div style="margin-top: 30px;">
                <h3 style="color: var(--primary-orange); margin-bottom: 20px; display: flex; align-items: center;">
                    <span style="margin-right: 8px;">📅</span>
                    5日天气趋势
                </h3>
                <div id="weather-forecast" style="background: white; border-radius: 15px; padding: 20px; box-shadow: 0 4px 15px rgba(0,0,0,0.08);">
                    <!-- 5日预报内容将通过JavaScript生成 -->
                </div>
            </div>
            
            <!-- 穿衣建议和旅游指数 -->
            <div style="margin-top: 30px; display: grid; grid-template-columns: 1fr 1fr; gap: 20px;">
                <div style="background: linear-gradient(135deg, #fff, #f8f9fa); padding: 20px; border-radius: 15px; border-left: 4px solid var(--primary-orange);">
                    <h3 style="color: var(--primary-orange); margin-bottom: 15px; display: flex; align-items: center;">
                        <span style="margin-right: 8px;">🧥</span>
                        穿衣建议
                    </h3>
                    <div id="clothing-advice" style="line-height: 1.6; color: var(--text-dark);">
                        山西秋季昼夜温差较大,建议携带薄外套。白天可穿长袖衬衫,晚上需要加件外套保暖。
                        舒适的运动鞋是必备,因为会有较多步行游览。
                    </div>
                </div>
                
                <div style="background: linear-gradient(135deg, #fff, #f8f9fa); padding: 20px; border-radius: 15px; border-left: 4px solid var(--primary-blue);">
                    <h3 style="color: var(--primary-blue); margin-bottom: 15px; display: flex; align-items: center;">
                        <span style="margin-right: 8px;">🎯</span>
                        旅游指数
                    </h3>
                    <div id="travel-index" style="display: grid; gap: 10px;">
                        <div style="display: flex; justify-content: space-between; align-items: center;">
                            <span>🚶 舒适度指数</span>
                            <span style="background: #4CAF50; color: white; padding: 2px 8px; border-radius: 12px; font-size: 12px;"></span>
                        </div>
                        <div style="display: flex; justify-content: space-between; align-items: center;">
                            <span>📸 拍照指数</span>
                            <span style="background: #2196F3; color: white; padding: 2px 8px; border-radius: 12px; font-size: 12px;"></span>
                        </div>
                        <div style="display: flex; justify-content: space-between; align-items: center;">
                            <span>🌬️ 空气质量</span>
                            <span style="background: #4CAF50; color: white; padding: 2px 8px; border-radius: 12px; font-size: 12px;"></span>
                        </div>
                    </div>
                </div>
            </div>

            <!-- 天气预警 -->
            <div id="weather-alerts" style="margin-top: 20px; display: none;">
                <div style="background: linear-gradient(135deg, #fff3cd, #ffeaa7); padding: 15px; border-radius: 12px; border-left: 4px solid #f39c12;">
                    <h4 style="color: #d68910; margin: 0 0 10px 0; display: flex; align-items: center;">
                        <span style="margin-right: 8px;">⚠️</span>
                        天气预警
                    </h4>
                    <div id="alert-content" style="color: #7d6608; font-size: 14px; line-height: 1.5;"></div>
                </div>
            </div>
        </div>
        </section>
    </main>

    <script>
        // 全局变量
        let map = null;
        let markers = [];
        let polylines = [];
        let currentDay = 0;

        // 山西5日游完整路线数据
        const travelRoute = [
            {
                day: 1,
                city: "太原",
                title: "太原市区游",
                attractions: [
                    {
                        name: "晋祠",
                        location: [112.434468, 37.708991],
                        openTime: "08:00-18:00",
                        price: "80元",
                        duration: "2-3小时",
                        description: "中国现存最早的皇家园林,三晋文化的发源地",
                        visitTime: "09:00-12:00"
                    },
                    {
                        name: "山西博物院",
                        location: [112.563958, 37.857014],
                        openTime: "09:00-17:00",
                        price: "免费",
                        duration: "2-3小时",
                        description: "了解山西历史文化的最佳场所",
                        visitTime: "14:00-17:00"
                    },
                    {
                        name: "柳巷商业街",
                        location: [112.565308, 37.857014],
                        openTime: "全天开放",
                        price: "免费",
                        duration: "1-2小时",
                        description: "太原最繁华的商业街,品尝当地美食",
                        visitTime: "18:00-20:00"
                    }
                ],
                accommodation: "太原市区酒店",
                transport: "市内公交/地铁"
            },
            {
                day: 2,
                city: "太原-平遥",
                title: "太原-平遥",
                attractions: [
                    {
                        name: "乔家大院",
                        location: [112.232593, 37.386844],
                        openTime: "08:00-18:30",
                        price: "138元",
                        duration: "2-3小时",
                        description: "清代北方民居建筑的典型代表",
                        visitTime: "10:00-13:00"
                    },
                    {
                        name: "平遥古城",
                        location: [112.190369, 37.195001],
                        openTime: "全天开放",
                        price: "125元",
                        duration: "半天",
                        description: "保存最完整的明清古城之一",
                        visitTime: "15:00-18:00"
                    }
                ],
                accommodation: "平遥古城内客栈",
                transport: "高铁/大巴 (约2小时)"
            },
            {
                day: 3,
                city: "平遥",
                title: "平遥古城深度游",
                attractions: [
                    {
                        name: "平遥古城墙",
                        location: [112.190369, 37.195001],
                        openTime: "08:00-18:00",
                        price: "包含在古城票内",
                        duration: "1-2小时",
                        description: "明代古城墙,俯瞰古城全貌",
                        visitTime: "08:30-10:30"
                    },
                    {
                        name: "日升昌票号",
                        location: [112.189369, 37.194001],
                        openTime: "08:00-18:00",
                        price: "包含在古城票内",
                        duration: "1小时",
                        description: "中国第一家票号,了解古代金融业",
                        visitTime: "11:00-12:00"
                    },
                    {
                        name: "县衙署",
                        location: [112.191369, 37.196001],
                        openTime: "08:00-18:00",
                        price: "包含在古城票内",
                        duration: "1小时",
                        description: "明清县衙建筑群,体验古代官府文化",
                        visitTime: "14:00-15:00"
                    }
                ],
                accommodation: "平遥古城内客栈",
                transport: "步行游览"
            },
            {
                day: 4,
                city: "平遥-大同",
                title: "平遥-大同",
                attractions: [
                    {
                        name: "王家大院",
                        location: [111.833333, 37.133333],
                        openTime: "08:00-18:30",
                        price: "66元",
                        duration: "2-3小时",
                        description: "被誉为'华夏民居第一宅'",
                        visitTime: "09:00-12:00"
                    },
                    {
                        name: "云冈石窟",
                        location: [113.132415, 40.109589],
                        openTime: "08:30-17:30",
                        price: "120元",
                        duration: "3-4小时",
                        description: "中国四大石窟之一,世界文化遗产",
                        visitTime: "15:00-18:00"
                    }
                ],
                accommodation: "大同市区酒店",
                transport: "高铁 (约3小时)"
            },
            {
                day: 5,
                city: "大同",
                title: "大同-返程",
                attractions: [
                    {
                        name: "悬空寺",
                        location: [113.718468, 39.665325],
                        openTime: "08:00-18:00",
                        price: "130元",
                        duration: "2小时",
                        description: "建在悬崖峭壁上的千年古寺",
                        visitTime: "09:00-11:00"
                    },
                    {
                        name: "华严寺",
                        location: [113.295415, 40.076589],
                        openTime: "08:00-18:00",
                        price: "65元",
                        duration: "1-2小时",
                        description: "辽金时期佛教建筑精品",
                        visitTime: "13:00-15:00"
                    }
                ],
                accommodation: "返程",
                transport: "高铁/飞机返程"
            }
        ];

        // 餐厅推荐数据
        const restaurants = {
            taiyuan: [
                { name: "老太原面馆", rating: 4.8, cuisine: "面食", distance: "500m", price: "人均30元" },
                { name: "认一力饭庄", rating: 4.7, cuisine: "晋菜", distance: "800m", price: "人均80元" },
                { name: "六味斋", rating: 4.6, cuisine: "熟食", distance: "300m", price: "人均25元" }
            ],
            pingyao: [
                { name: "德居源", rating: 4.9, cuisine: "晋菜", distance: "200m", price: "人均60元" },
                { name: "天元奎饭店", rating: 4.7, cuisine: "传统菜", distance: "150m", price: "人均45元" },
                { name: "洪武记饭店", rating: 4.8, cuisine: "平遥牛肉", distance: "100m", price: "人均35元" }
            ],
            datong: [
                { name: "凤临阁", rating: 4.8, cuisine: "大同菜", distance: "600m", price: "人均70元" },
                { name: "老大同刀削面", rating: 4.6, cuisine: "面食", distance: "400m", price: "人均20元" },
                { name: "同和居", rating: 4.7, cuisine: "传统菜", distance: "500m", price: "人均50元" }
            ]
        };

        // 🎨 动画效果管理器
        class AnimationManager {
            constructor() {
                this.currentPage = 0;
                this.totalPages = 4;
                this.isAnimating = false;
                this.touchStartX = 0;
                this.touchEndX = 0;
                this.lastScrollY = 0;
                this.init();
            }

            init() {
                this.createCursorGlow();
                this.createParticles();
                this.setupKeyboardShortcuts();
                this.setupTouchGestures();
                this.setupScrollHideNav();
                this.addRippleEffects();
                this.startTypewriterEffect();
                this.enhanceButtons();
                this.addStaggerAnimations();
            }

            // 🌟 创建鼠标跟随光晕
            createCursorGlow() {
                const glow = document.createElement('div');
                glow.className = 'cursor-glow';
                document.body.appendChild(glow);

                document.addEventListener('mousemove', (e) => {
                    glow.style.left = e.clientX - 10 + 'px';
                    glow.style.top = e.clientY - 10 + 'px';
                });

                document.addEventListener('mousedown', () => {
                    glow.style.transform = 'scale(1.5)';
                });

                document.addEventListener('mouseup', () => {
                    glow.style.transform = 'scale(1)';
                });
            }

            // ✨ 创建粒子效果
            createParticles() {
                const particlesContainer = document.createElement('div');
                particlesContainer.className = 'particles';
                document.body.appendChild(particlesContainer);

                for (let i = 0; i < 50; i++) {
                    const particle = document.createElement('div');
                    particle.className = 'particle';
                    particle.style.left = Math.random() * 100 + '%';
                    particle.style.top = Math.random() * 100 + '%';
                    particle.style.animationDelay = Math.random() * 6 + 's';
                    particlesContainer.appendChild(particle);
                }
            }

            // ⌨️ 键盘快捷键
            setupKeyboardShortcuts() {
                document.addEventListener('keydown', (e) => {
                    if (this.isAnimating) return;

                    switch(e.key) {
                        case '1':
                            this.switchToPage('welcome');
                            break;
   
            });
        }
        
        // 完善的美食推荐功能
        function showFoodRecommendations() {
            // 创建美食推荐弹窗
      ✅ 美食推荐功能初始化完成');
        });
    </script>
</body>
</html>