当前位置: 首页 > news >正文

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

在这里插入图片描述

从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:访问阿里云百炼平台(https://bailian.console.aliyun.com/?tab=app#/app-market/newTemplate) 或魔搭平台(https://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 用户旅程与交互流

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

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;case '2':this.switchToPage('map');break;case '3':this.switchToPage('route');break;case '4':this.switchToPage('weather');break;case 'Escape':this.switchToPage('welcome');break;case 'ArrowLeft':this.previousPage();break;case 'ArrowRight':this.nextPage();break;}});}// 📱 触摸手势支持setupTouchGestures() {const container = document.querySelector('.content-area');if (!container) return;container.addEventListener('touchstart', (e) => {this.touchStartX = e.changedTouches[0].screenX;}, { passive: true });container.addEventListener('touchend', (e) => {this.touchEndX = e.changedTouches[0].screenX;this.handleSwipe();}, { passive: true });}handleSwipe() {const swipeThreshold = 50;const diff = this.touchStartX - this.touchEndX;if (Math.abs(diff) > swipeThreshold) {if (diff > 0) {this.nextPage(); // 向左滑动,下一页} else {this.previousPage(); // 向右滑动,上一页}}}// 🌊 滚动隐藏导航栏setupScrollHideNav() {window.addEventListener('scroll', () => {const currentScrollY = window.scrollY;const header = document.querySelector('.header');if (currentScrollY > this.lastScrollY && currentScrollY > 100) {header.classList.add('hidden');} else {header.classList.remove('hidden');}this.lastScrollY = currentScrollY;});}// 🎯 添加波纹效果addRippleEffects() {const buttons = document.querySelectorAll('.day-button, .function-btn, .start-journey-btn, .nav-item');buttons.forEach(button => {button.classList.add('ripple-effect');});}// ⌨️ 打字机效果startTypewriterEffect() {const title = document.querySelector('.welcome-title');if (title) {title.classList.add('typewriter');}}// 🎨 增强按钮效果enhanceButtons() {const buttons = document.querySelectorAll('.day-button, .function-btn, .start-journey-btn');buttons.forEach(button => {button.classList.add('enhanced-button');// 添加心跳动画给重要按钮if (button.classList.contains('start-journey-btn')) {button.classList.add('heartbeat');}});// 添加3D卡片效果const cards = document.querySelectorAll('.weather-card, .timeline-item, .sidebar');cards.forEach(card => {card.classList.add('card-3d');});}// 🎪 添加渐进式加载动画addStaggerAnimations() {const elements = document.querySelectorAll('.route-days .day-button');elements.forEach((el, index) => {el.classList.add('stagger-animation');el.style.animationDelay = (index * 0.1) + 's';});}// 📄 页面切换动画switchToPage(page) {if (this.isAnimating) return;this.isAnimating = true;const currentSection = document.querySelector('.welcome-section[style*="block"], .map-section[style*="block"], .route-section[style*="block"], .weather-section[style*="block"]');const targetSection = document.getElementById(page);if (currentSection) {currentSection.style.animation = 'fadeOut 0.3s ease-out forwards';setTimeout(() => {currentSection.style.display = 'none';currentSection.style.animation = '';if (targetSection) {targetSection.style.display = 'block';targetSection.classList.add('fade-in');setTimeout(() => {targetSection.classList.remove('fade-in');this.isAnimating = false;}, 800);}}, 300);} else {showSection(page);this.isAnimating = false;}}nextPage() {const pages = ['welcome', 'map', 'route', 'weather'];this.currentPage = (this.currentPage + 1) % pages.length;this.switchToPage(pages[this.currentPage]);}previousPage() {const pages = ['welcome', 'map', 'route', 'weather'];this.currentPage = (this.currentPage - 1 + pages.length) % pages.length;this.switchToPage(pages[this.currentPage]);}// 🔢 数字计数动画animateCounter(element, start, end, duration = 2000) {const startTime = performance.now();const startValue = parseInt(start);const endValue = parseInt(end);const difference = endValue - startValue;const animate = (currentTime) => {const elapsed = currentTime - startTime;const progress = Math.min(elapsed / duration, 1);const easeOutQuart = 1 - Math.pow(1 - progress, 4);const currentValue = Math.round(startValue + (difference * easeOutQuart));element.textContent = currentValue + '°C';if (progress < 1) {requestAnimationFrame(animate);}};requestAnimationFrame(animate);}}// 🎨 创建动画管理器实例let animationManager;// 初始化页面document.addEventListener('DOMContentLoaded', function() {console.log('页面加载完成,开始初始化...');// 初始化动画管理器animationManager = new AnimationManager();showSection('welcome');generateRouteContent();setupEventListeners();// 添加页面加载完成的淡入效果document.body.style.opacity = '0';setTimeout(() => {document.body.style.transition = 'opacity 1s ease-in-out';document.body.style.opacity = '1';}, 100);});// 设置事件监听器function setupEventListeners() {console.log('设置事件监听器...');// 导航菜单事件document.querySelectorAll('.nav-item').forEach(item => {item.addEventListener('click', function() {const section = this.getAttribute('data-section');showSection(section);console.log('导航点击:', section);showSection(section);});});// 功能按钮事件document.querySelectorAll('.function-btn').forEach(btn => {btn.addEventListener('click', function() {const action = this.getAttribute('data-action');console.log('功能按钮点击:', action);switch(action) {case 'map':showSection('map');break;case 'food':showAttractions();break;case 'weather':showSection('weather');break;case 'route':showAllRoute();break;}});});// 天数按钮事件document.querySelectorAll('.day-button').forEach(btn => {btn.addEventListener('click', function() {const day = parseInt(this.getAttribute('data-day'));console.log('天数按钮点击:', day);showRouteDetail(day);});});// 开始旅程按钮事件document.querySelector('.start-journey-btn').addEventListener('click', function() {const section = this.getAttribute('data-section');showSection(section);});console.log('所有事件监听器设置完成');}// 显示不同区域function showSection(section) {console.log('切换到区域:', section);// 隐藏所有区域document.querySelectorAll('.welcome-section, .map-section, .route-section, .weather-section').forEach(el => {el.style.display = 'none';});// 特殊处理美食推荐页面if (section === 'food') {showFoodSection();return;}// 显示对应区域const sectionElement = document.getElementById(section);if (sectionElement) {sectionElement.style.display = 'block';}// 特殊处理美食推荐页面if (section === 'food') {showFoodSection();return;}// 特殊处理美食推荐页面if (section === 'food') {showFoodSection();return;}// 隐藏所有区域document.querySelectorAll('.welcome-section, .map-section, .route-section, .weather-section').forEach(el => {el.style.display = 'none';});// 显示指定区域const sectionToShow = document.getElementById(section);if (sectionToShow) {sectionToShow.style.display = 'block';console.log('成功显示区域:', section);} else {console.error('找不到区域:', section);return;}// 特殊处理if (section === 'map') {console.log('准备初始化地图...');// 确保地图容器已显示后再初始化setTimeout(() => {if (typeof AMap !== 'undefined') {initMap();} else {console.log('AMap未加载,等待加载完成...');waitForAMap(() => initMap());}}, 200);} else if (section === 'route') {generateRouteContent();} else if (section === 'weather') {updateWeather();}}// 地图初始化重试计数let mapInitRetryCount = 0;const maxRetries = 5;// 初始化高德地图function initMap() {console.log('开始初始化地图,尝试次数:', mapInitRetryCount + 1);try {if (map) {map.destroy();map = null;}// 检查AMap是否已加载if (typeof AMap === 'undefined') {console.log('AMap未定义,等待加载...');document.getElementById('map-container').innerHTML = '<div style="display: flex; flex-direction: column; align-items: center; justify-content: center; height: 100%; color: #666; font-size: 16px; gap: 10px;">' +'<div class="loading"></div>' +'<div>🗺️ 地图API加载中,请稍候...</div>' +'</div>';// 重试机制if (mapInitRetryCount < maxRetries) {mapInitRetryCount++;setTimeout(() => initMap(), 2000);} else {showMapError('地图API加载超时,请检查网络连接');}return;}console.log('AMap已加载,开始创建地图实例');// 创建地图实例map = new AMap.Map('map-container', {zoom: 7,center: [112.549248, 37.857014],mapStyle: 'amap://styles/normal',resizeEnable: true,rotateEnable: true,pitchEnable: true,zoomEnable: true,dragEnable: true});// 监听地图加载完成事件map.on('complete', function() {console.log('地图加载完成');// 添加地图控件try {map.addControl(new AMap.Scale({position: 'LB'}));map.addControl(new AMap.ToolBar({position: 'RT'}));console.log('地图控件添加成功');} catch (e) {console.warn('地图控件添加失败:', e);}// 清除之前的标记clearMapMarkers();// 添加景点标记addAllAttractions();// 绘制路线drawCompleteRoute();console.log('✅ 地图初始化完全成功');mapInitRetryCount = 0; // 重置重试计数});// 监听地图加载错误map.on('error', function(e) {console.error('地图加载错误:', e);showMapError('地图加载出错: ' + (e.message || '未知错误'));});} catch (error) {console.error('地图初始化异常:', error);if (mapInitRetryCount < maxRetries) {mapInitRetryCount++;console.log('重试地图初始化,第', mapInitRetryCount, '次');setTimeout(() => initMap(), 1000);} else {showMapError('地图初始化失败: ' + error.message);}}}// 显示地图错误信息function showMapError(message) {document.getElementById('map-container').innerHTML = '<div style="display: flex; flex-direction: column; align-items: center; justify-content: center; height: 100%; color: #e74c3c; font-size: 16px; gap: 15px; padding: 20px; text-align: center;">' +'<div style="font-size: 48px;">❌</div>' +'<div style="font-weight: bold;">地图加载失败</div>' +'<div style="font-size: 14px; color: #666; line-height: 1.5;">' + message + '</div>' +'<button onclick="retryMapInit()" style="background: var(--primary-orange); color: white; border: none; padding: 10px 20px; border-radius: 8px; cursor: pointer; font-size: 14px;">🔄 重新加载</button>' +'</div>';}// 重新初始化地图function retryMapInit() {mapInitRetryCount = 0;initMap();}// 等待AMap加载的函数function waitForAMap(callback, timeout = 10000) {const startTime = Date.now();function check() {if (typeof AMap !== 'undefined') {callback();} else if (Date.now() - startTime < timeout) {setTimeout(check, 100);} else {showMapError('地图API加载超时,请检查网络连接或API密钥');}}check();}// 清除地图标记function clearMapMarkers() {if (map) {markers.forEach(marker => map.remove(marker));polylines.forEach(polyline => map.remove(polyline));}markers = [];polylines = [];}// 添加景点标记function addAllAttractions() {const colors = ['#FF6B35', '#4ECDC4', '#FFE66D', '#FF8B94', '#95E1D3'];travelRoute.forEach((dayRoute, dayIndex) => {dayRoute.attractions.forEach(attraction => {const marker = new AMap.Marker({position: attraction.location,title: attraction.name,icon: new AMap.Icon({size: new AMap.Size(32, 32),image: `data:image/svg+xml;base64,${btoa(` <svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32"> <circle cx="16" cy="16" r="14" fill="${colors[dayIndex]}" stroke="white" stroke-width="2"/> <text x="16" y="20" text-anchor="middle" fill="white" font-size="12" font-weight="bold">${dayIndex + 1}</text> </svg> `)}`,imageSize: new AMap.Size(32, 32)})});const infoWindow = new AMap.InfoWindow({content: `<div style="padding: 15px; min-width: 250px; font-family: 'Microsoft YaHei';"><h3 style="color: ${colors[dayIndex]}; margin: 0 0 12px 0; font-size: 16px;">${attraction.name}</h3><div style="display: grid; gap: 8px; font-size: 13px;"><p style="margin: 0;"><strong>🕒 开放时间:</strong> ${attraction.openTime}</p><p style="margin: 0;"><strong>💰 门票价格:</strong> ${attraction.price}</p><p style="margin: 0;"><strong>⏱️ 建议游览:</strong> ${attraction.duration}</p><p style="margin: 0;"><strong>📅 推荐时间:</strong> ${attraction.visitTime}</p><p style="margin: 8px 0 0 0; color: #666; font-size: 12px; line-height: 1.4;">${attraction.description}</p></div></div>`,offset: new AMap.Pixel(0, -30)});marker.on('click', () => infoWindow.open(map, marker.getPosition()));markers.push(marker);map.add(marker);});});}// 绘制路线function drawCompleteRoute() {const colors = ['#FF6B35', '#4ECDC4', '#FFE66D', '#FF8B94', '#95E1D3'];// 绘制每天内部的路线travelRoute.forEach((dayRoute, dayIndex) => {if (dayRoute.attractions.length > 1) {const path = dayRoute.attractions.map(attr => attr.location);const polyline = new AMap.Polyline({path: path,strokeColor: colors[dayIndex],strokeWeight: 4,strokeOpacity: 0.8,strokeStyle: 'solid'});polylines.push(polyline);map.add(polyline);}});// 连接不同天的路线for (let i = 0; i < travelRoute.length - 1; i++) {const currentDay = travelRoute[i];const nextDay = travelRoute[i + 1];if (currentDay.attractions.length > 0 && nextDay.attractions.length > 0) {const lastAttraction = currentDay.attractions[currentDay.attractions.length - 1];const firstAttraction = nextDay.attractions[0];const connectLine = new AMap.Polyline({path: [lastAttraction.location, firstAttraction.location],strokeColor: '#999999',strokeWeight: 2,strokeOpacity: 0.6,strokeStyle: 'dashed'});polylines.push(connectLine);map.add(connectLine);}}}// 显示路线详情function showRouteDetail(day) {console.log('显示第', day, '天路线详情');document.querySelectorAll('.day-button').forEach(btn => btn.classList.remove('active'));const clickedButton = document.querySelector(`[data-day="${day}"]`);if (clickedButton) clickedButton.classList.add('active');currentDay = day;showSection('route');generateDayRouteContent(day);// 如果地图已初始化,聚焦到该天的景点if (map && travelRoute[day - 1]) {const dayRoute = travelRoute[day - 1];if (dayRoute.attractions.length > 0) {const firstAttraction = dayRoute.attractions[0];map.setCenter(firstAttraction.location);map.setZoom(12);}}}// 生成路线内容function generateRouteContent() {const routeContent = document.getElementById('route-content');if (!routeContent) return;let html = '';travelRoute.forEach(dayRoute => {html += `<div class="timeline-item"><div class="timeline-day">第${dayRoute.day}天</div><div class="timeline-content"><h3>${dayRoute.title}</h3><p><strong>🏨 住宿:</strong> ${dayRoute.accommodation}</p><p><strong>🚗 交通:</strong> ${dayRoute.transport}</p><div class="timeline-attractions">${dayRoute.attractions.map(attr => `<span class="attraction-tag">${attr.name}</span>`).join('')}</div></div></div>`;});routeContent.innerHTML = html;}// 生成单天详细内容function generateDayRouteContent(day) {const dayRoute = travelRoute[day - 1];if (!dayRoute) return;const routeContent = document.getElementById('route-content');if (!routeContent) return;let html = `<div class="timeline-item" style="border-left: 5px solid var(--primary-orange); background: linear-gradient(135deg, #fff, #f8f9fa);"><div class="timeline-day">第${dayRoute.day}天 - ${dayRoute.title}</div><div class="timeline-content"><p style="color: var(--text-light); margin-bottom: 20px;"><strong>🏨 住宿:</strong> ${dayRoute.accommodation} | <strong>🚗 交通:</strong> ${dayRoute.transport}</p></div></div>`;dayRoute.attractions.forEach((attraction, index) => {html += `<div class="timeline-item" style="margin-left: 20px; border-left: 3px solid var(--primary-blue);"><div style="display: flex; justify-content: space-between; align-items: flex-start; margin-bottom: 12px;"><h3 style="color: var(--primary-blue); margin: 0; font-size: 18px;">${attraction.name}</h3><span style="background: var(--accent-yellow); color: var(--text-dark); padding: 6px 12px; border-radius: 12px; font-size: 12px; font-weight: bold; white-space: nowrap;">${attraction.visitTime}</span></div><p style="margin: 8px 0 15px 0; color: var(--text-dark); line-height: 1.5;">${attraction.description}</p><div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); gap: 10px;"><div style="background: #f1f3f4; padding: 12px; border-radius: 10px; text-align: center;"><div style="font-size: 11px; color: var(--text-light); margin-bottom: 4px;">🕒 开放时间</div><div style="font-weight: bold; font-size: 13px;">${attraction.openTime}</div></div><div style="background: #f1f3f4; padding: 12px; border-radius: 10px; text-align: center;"><div style="font-size: 11px; color: var(--text-light); margin-bottom: 4px;">💰 门票价格</div><div style="font-weight: bold; font-size: 13px; color: var(--primary-orange);">${attraction.price}</div></div><div style="background: #f1f3f4; padding: 12px; border-radius: 10px; text-align: center;"><div style="font-size: 11px; color: var(--text-light); margin-bottom: 4px;">⏱️ 建议游览</div><div style="font-weight: bold; font-size: 13px;">${attraction.duration}</div></div></div></div>`;});routeContent.innerHTML = html;}// 显示美食推荐function showAttractions() {const cities = ['taiyuan', 'pingyao', 'datong'];const cityNames = ['太原', '平遥', '大同'];let html = '<div class="panel-title">🍜 美食推荐</div>';cities.forEach((city, index) => {html += `<div style="margin-bottom: 35px;"><h3 style="color: var(--primary-orange); margin-bottom: 20px; font-size: 20px; display: flex; align-items: center;"><span style="margin-right: 8px;">🏙️</span>${cityNames[index]}美食推荐</h3><div style="display: grid; gap: 18px;">`;restaurants[city].forEach(restaurant => {html += `<div style="background: linear-gradient(135deg, #fff, #f8f9fa); padding: 25px; border-radius: 18px; border-left: 4px solid var(--primary-blue); box-shadow: 0 4px 15px rgba(0,0,0,0.08); transition: transform 0.3s ease;" onmouseover="this.style.transform='translateY(-2px)'" onmouseout="this.style.transform='translateY(0)'"><div style="display: flex; justify-content: space-between; align-items: flex-start; margin-bottom: 12px;"><h4 style="margin: 0; color: var(--text-dark); font-size: 16px;">${restaurant.name}</h4><div style="display: flex; align-items: center; gap: 6px; background: rgba(255,165,0,0.1); padding: 4px 8px; border-radius: 8px;"><span style="color: #ffa500; font-size: 14px;">⭐</span><span style="font-weight: bold; color: var(--primary-orange); font-size: 14px;">${restaurant.rating}</span></div></div><div style="display: flex; gap: 20px; font-size: 14px; color: var(--text-light);"><span style="display: flex; align-items: center; gap: 4px;">🍽️ ${restaurant.cuisine}</span><span style="display: flex; align-items: center; gap: 4px;">📍 ${restaurant.distance}</span><span style="display: flex; align-items: center; gap: 4px;">💰 ${restaurant.price}</span></div></div>`;});html += '</div></div>';});document.getElementById('route-content').innerHTML = html;showSection('route');}// 显示完整路线function showAllRoute() {showSection('route');generateRouteContent();}// 🎨 增强的动画效果函数function addAdvancedAnimations() {// 添加右下角浮动按钮const floatingButtons = `<div class="floating-buttons"><button class="floating-btn" data-section="map" title="查看地图" onclick="showSection('map')">🗺️</button><button class="floating-btn" data-section="weather" title="天气预报" onclick="showSection('weather')">🌤️</button><button class="floating-btn" data-section="route" title="完整路线" onclick="showSection('itinerary')">📍</button></div>`;document.body.insertAdjacentHTML('beforeend', floatingButtons);// 为浮动按钮添加点击事件document.querySelectorAll('.floating-btn').forEach(btn => {btn.addEventListener('click', function() {const section = this.getAttribute('data-section');const action = this.getAttribute('data-action');if (section) {showSection(section);} else if (action === 'food') {showFoodSection();}});});// 🌈 为重要元素添加彩虹边框(更低调的样式)const importantElements = document.querySelectorAll('.start-journey-btn');importantElements.forEach(el => {// 移除过于显眼的彩虹边框和心跳动画el.classList.remove('heartbeat');el.style.animation = 'none';});// 💫 添加悬浮动画到天气卡片const weatherCards = document.querySelectorAll('.weather-card');weatherCards.forEach((card, index) => {card.style.animationDelay = (index * 0.2) + 's';card.classList.add('stagger-animation');// 添加温度数字动画const tempElement = card.querySelector('.weather-temp');if (tempElement) {tempElement.addEventListener('mouseenter', () => {const currentTemp = parseInt(tempElement.textContent);animationManager.animateCounter(tempElement, currentTemp - 5, currentTemp, 1000);});}});// 🎪 为导航项添加更多动画效果const navItems = document.querySelectorAll('.nav-item');navItems.forEach((item, index) => {item.addEventListener('mouseenter', () => {item.style.transform = 'translateY(-2px) scale(1.05)';item.style.boxShadow = '0 8px 25px rgba(0,0,0,0.2)';});item.addEventListener('mouseleave', () => {item.style.transform = 'translateY(0) scale(1)';item.style.boxShadow = '0 5px 15px rgba(0,0,0,0.2)';});});// 🎯 为功能按钮添加点击反馈const functionBtns = document.querySelectorAll('.function-btn');functionBtns.forEach(btn => {btn.addEventListener('click', () => {btn.style.transform = 'scale(0.95)';setTimeout(() => {btn.style.transform = 'scale(1.05)';setTimeout(() => {btn.style.transform = 'scale(1)';}, 150);}, 100);});});// 🌟 为时间轴项目添加滑入动画const timelineItems = document.querySelectorAll('.timeline-item');const observerOptions = {threshold: 0.1,rootMargin: '0px 0px -50px 0px'};const observer = new IntersectionObserver((entries) => {entries.forEach(entry => {if (entry.isIntersecting) {entry.target.style.animation = 'slideInFromLeft 0.6s ease-out forwards';entry.target.style.opacity = '1';}});}, observerOptions);timelineItems.forEach(item => {item.style.opacity = '0';observer.observe(item);});}// 🎨 添加滑入动画样式const slideInAnimation = `@keyframes slideInFromLeft {from {transform: translateX(-50px);opacity: 0;}to {transform: translateX(0);opacity: 1;}}@keyframes fadeOut {from {transform: translateY(0);opacity: 1;}to {transform: translateY(-20px);opacity: 0;}}`;// 动态添加样式const styleSheet = document.createElement('style');styleSheet.textContent = slideInAnimation;document.head.appendChild(styleSheet);// 更新天气// 天气数据模拟const weatherIcons = {sunny: '☀️',cloudy: '⛅',partlyCloudy: '🌤️',rainy: '🌧️',snowy: '❄️',foggy: '🌫️'};const weatherConditions = [{ condition: 'sunny', desc: '晴朗', icon: '☀️' },{ condition: 'cloudy', desc: '多云', icon: '⛅' },{ condition: 'partlyCloudy', desc: '晴转多云', icon: '🌤️' },{ condition: 'rainy', desc: '小雨', icon: '🌧️' },{ condition: 'foggy', desc: '雾霾', icon: '🌫️' }];// 🌤️ 增强的天气更新函数function updateWeather() {console.log('🌤️ 更新天气信息...');const cities = ['taiyuan', 'pingyao', 'datong'];const cityNames = ['太原', '平遥', '大同'];// 添加加载动画const weatherSection = document.getElementById('weather');if (weatherSection && weatherSection.style.display === 'block') {const loadingDiv = document.createElement('div');loadingDiv.className = 'loading-enhanced';loadingDiv.style.position = 'fixed';loadingDiv.style.top = '50%';loadingDiv.style.left = '50%';loadingDiv.style.transform = 'translate(-50%, -50%)';loadingDiv.style.zIndex = '9999';document.body.appendChild(loadingDiv);setTimeout(() => {document.body.removeChild(loadingDiv);}, 1500);}// 更新当前天气(带动画)document.querySelectorAll('.weather-card').forEach((card, index) => {const cityData = generateWeatherData(cities[index]);// 温度更新动画const tempElement = card.querySelector('.weather-temp');if (tempElement) {const oldTemp = parseInt(tempElement.textContent) || cityData.temp;animationManager.animateCounter(tempElement, oldTemp, cityData.temp, 1500);}// 其他元素的淡入更新setTimeout(() => {const rangeElement = card.querySelector('.weather-range');if (rangeElement) {rangeElement.style.opacity = '0';setTimeout(() => {rangeElement.textContent = `${cityData.minTemp}°C ~ ${cityData.maxTemp}°C`;rangeElement.style.transition = 'opacity 0.5s ease';rangeElement.style.opacity = '1';}, 200);}const descElement = card.querySelector('.weather-desc');if (descElement) {descElement.style.opacity = '0';setTimeout(() => {descElement.textContent = cityData.desc + ' 适宜出行';descElement.style.transition = 'opacity 0.5s ease';descElement.style.opacity = '1';}, 400);}const iconElement = card.querySelector('.weather-icon');if (iconElement) {iconElement.style.transform = 'scale(0)';setTimeout(() => {iconElement.textContent = cityData.icon;iconElement.style.transition = 'transform 0.5s cubic-bezier(0.68, -0.55, 0.265, 1.55)';iconElement.style.transform = 'scale(1)';}, 600);}}, index * 200);// 更新详细信息const windElement = card.querySelector('.wind-level');if (windElement) windElement.textContent = cityData.windLevel + '级';const humidityElement = card.querySelector('.humidity');if (humidityElement) humidityElement.textContent = cityData.humidity + '%';const visibilityElement = card.querySelector('.visibility');if (visibilityElement) visibilityElement.textContent = cityData.visibility + 'km';});// 更新5日预报generate5DayForecast();// 更新穿衣建议updateClothingAdvice();// 更新旅游指数updateTravelIndex();// 更新时间戳(带打字机效果)const now = new Date();const timeString = now.toLocaleString('zh-CN', {month: '2-digit',day: '2-digit',hour: '2-digit',minute: '2-digit'});const updateTimeElement = document.getElementById('weather-update-time');if (updateTimeElement) {updateTimeElement.style.opacity = '0';setTimeout(() => {updateTimeElement.textContent = `最后更新: ${timeString}`;updateTimeElement.style.transition = 'opacity 0.5s ease';updateTimeElement.style.opacity = '1';}, 800);}// 检查天气预警checkWeatherAlerts();console.log('✅ 天气信息更新完成');}// 生成天气数据function generateWeatherData(city) {const baseTemp = city === 'taiyuan' ? 20 : city === 'pingyao' ? 18 : 16;const condition = weatherConditions[Math.floor(Math.random() * weatherConditions.length)];const temp = baseTemp + Math.floor(Math.random() * 8) - 2;const minTemp = temp - Math.floor(Math.random() * 5) - 3;const maxTemp = temp + Math.floor(Math.random() * 5) + 2;return {temp: temp,minTemp: minTemp,maxTemp: maxTemp,desc: condition.desc,icon: condition.icon,windLevel: Math.floor(Math.random() * 4) + 1,humidity: Math.floor(Math.random() * 30) + 45,visibility: Math.floor(Math.random() * 10) + 10,condition: condition.condition};}// 生成5日天气预报// 国庆5日天气预报数据const nationalDayWeather = [{date: '10月1日',day: '国庆节',taiyuan: { icon: '☀️', desc: '晴朗', temp: 22, minTemp: 12, maxTemp: 24, wind: '北风2级', humidity: 45 },pingyao: { icon: '🌤️', desc: '晴转多云', temp: 20, minTemp: 10, maxTemp: 22, wind: '东北风2级', humidity: 50 },datong: { icon: '☀️', desc: '晴朗', temp: 18, minTemp: 8, maxTemp: 20, wind: '北风3级', humidity: 40 }},{date: '10月2日',day: '国庆假期',taiyuan: { icon: '⛅', desc: '多云', temp: 21, minTemp: 11, maxTemp: 23, wind: '东风2级', humidity: 55 },pingyao: { icon: '⛅', desc: '多云', temp: 19, minTemp: 9, maxTemp: 21, wind: '东风2级', humidity: 58 },datong: { icon: '🌤️', desc: '晴转多云', temp: 17, minTemp: 7, maxTemp: 19, wind: '东北风2级', humidity: 48 }},{date: '10月3日',day: '国庆假期',taiyuan: { icon: '🌤️', desc: '晴转多云', temp: 23, minTemp: 13, maxTemp: 25, wind: '南风2级', humidity: 50 },pingyao: { icon: '☀️', desc: '晴朗', temp: 21, minTemp: 11, maxTemp: 23, wind: '南风2级', humidity: 45 },datong: { icon: '⛅', desc: '多云', temp: 19, minTemp: 9, maxTemp: 21, wind: '南风2级', humidity: 52 }},{date: '10月4日',day: '国庆假期',taiyuan: { icon: '☀️', desc: '晴朗', temp: 24, minTemp: 14, maxTemp: 26, wind: '西南风2级', humidity: 42 },pingyao: { icon: '☀️', desc: '晴朗', temp: 22, minTemp: 12, maxTemp: 24, wind: '西南风2级', humidity: 40 },datong: { icon: '🌤️', desc: '晴转多云', temp: 20, minTemp: 10, maxTemp: 22, wind: '西风2级', humidity: 46 }},{date: '10月5日',day: '国庆假期',taiyuan: { icon: '⛅', desc: '多云转晴', temp: 22, minTemp: 12, maxTemp: 24, wind: '北风2级', humidity: 48 },pingyao: { icon: '⛅', desc: '多云', temp: 20, minTemp: 10, maxTemp: 22, wind: '北风2级', humidity: 52 },datong: { icon: '☀️', desc: '晴朗', temp: 18, minTemp: 8, maxTemp: 20, wind: '北风3级', humidity: 44 }}];// 生成国庆5日天气预报function generate5DayForecast() {const forecastContainer = document.getElementById('weather-forecast');if (!forecastContainer) return;let html = '';nationalDayWeather.forEach((dayWeather, index) => {html += `<div class="forecast-day-container" style="margin-bottom: 25px;"><div class="forecast-day-header" style="background: linear-gradient(135deg, var(--primary-orange), var(--primary-blue)); color: white; padding: 15px; border-radius: 12px 12px 0 0; text-align: center;"><h4 style="margin: 0; font-size: 16px;">${dayWeather.date} (${dayWeather.day})</h4></div><div class="forecast-cities" style="display: grid; grid-template-columns: repeat(3, 1fr); gap: 0; background: white; border-radius: 0 0 12px 12px; overflow: hidden; box-shadow: 0 4px 15px rgba(0,0,0,0.1);"><div class="city-forecast" style="padding: 20px; border-right: 1px solid #eee; text-align: center;"><div style="font-weight: bold; color: var(--primary-orange); margin-bottom: 10px;">太原</div><div style="font-size: 32px; margin: 8px 0;">${dayWeather.taiyuan.icon}</div><div style="color: var(--text-dark); margin-bottom: 8px;">${dayWeather.taiyuan.desc}</div><div style="font-size: 18px; font-weight: bold; color: var(--primary-blue); margin-bottom: 8px;">${dayWeather.taiyuan.temp}°C</div><div style="font-size: 12px; color: var(--text-light);">${dayWeather.taiyuan.minTemp}°C ~ ${dayWeather.taiyuan.maxTemp}°C</div><div style="font-size: 11px; color: var(--text-light); margin-top: 5px;">${dayWeather.taiyuan.wind} | 湿度${dayWeather.taiyuan.humidity}%</div></div><div class="city-forecast" style="padding: 20px; border-right: 1px solid #eee; text-align: center;"><div style="font-weight: bold; color: var(--primary-orange); margin-bottom: 10px;">平遥</div><div style="font-size: 32px; margin: 8px 0;">${dayWeather.pingyao.icon}</div><div style="color: var(--text-dark); margin-bottom: 8px;">${dayWeather.pingyao.desc}</div><div style="font-size: 18px; font-weight: bold; color: var(--primary-blue); margin-bottom: 8px;">${dayWeather.pingyao.temp}°C</div><div style="font-size: 12px; color: var(--text-light);">${dayWeather.pingyao.minTemp}°C ~ ${dayWeather.pingyao.maxTemp}°C</div><div style="font-size: 11px; color: var(--text-light); margin-top: 5px;">${dayWeather.pingyao.wind} | 湿度${dayWeather.pingyao.humidity}%</div></div><div class="city-forecast" style="padding: 20px; text-align: center;"><div style="font-weight: bold; color: var(--primary-orange); margin-bottom: 10px;">大同</div><div style="font-size: 32px; margin: 8px 0;">${dayWeather.datong.icon}</div><div style="color: var(--text-dark); margin-bottom: 8px;">${dayWeather.datong.desc}</div><div style="font-size: 18px; font-weight: bold; color: var(--primary-blue); margin-bottom: 8px;">${dayWeather.datong.temp}°C</div><div style="font-size: 12px; color: var(--text-light);">${dayWeather.datong.minTemp}°C ~ ${dayWeather.datong.maxTemp}°C</div><div style="font-size: 11px; color: var(--text-light); margin-top: 5px;">${dayWeather.datong.wind} | 湿度${dayWeather.datong.humidity}%</div></div></div></div>`;});forecastContainer.innerHTML = html;}// 更新穿衣建议function updateClothingAdvice() {const adviceElement = document.getElementById('clothing-advice');if (!adviceElement) return;const avgTemp = 19; // 平均温度let advice = '';if (avgTemp >= 25) {advice = '天气较热,建议穿轻薄的短袖衣物,注意防晒。携带遮阳帽和太阳镜,多补充水分。';} else if (avgTemp >= 20) {advice = '天气温和,建议穿长袖衬衫或薄外套。早晚温差较大,可准备一件薄外套备用。';} else if (avgTemp >= 15) {advice = '天气偏凉,建议穿长袖衣物配薄外套。山西秋季昼夜温差大,晚上需要加件外套保暖。';} else if (avgTemp >= 10) {advice = '天气较冷,建议穿厚外套或轻薄羽绒服。注意保暖,特别是在户外景点游览时。';} else {advice = '天气寒冷,建议穿厚重的冬装,包括羽绒服、毛衣等。注意头部和手脚保暖。';}advice += ' 舒适的运动鞋是必备,因为会有较多步行游览。';adviceElement.textContent = advice;}// 更新旅游指数function updateTravelIndex() {const indexElement = document.getElementById('travel-index');if (!indexElement) return;// 根据天气条件计算指数const avgTemp = 19;const humidity = 55;const visibility = 15;// 舒适度指数let comfortLevel = avgTemp >= 15 && avgTemp <= 25 && humidity <= 70 ? '优' : avgTemp >= 10 && avgTemp <= 30 && humidity <= 80 ? '良' : '一般';let comfortColor = comfortLevel === '优' ? '#4CAF50' : comfortLevel === '良' ? '#2196F3' : '#FF9800';// 拍照指数let photoLevel = visibility >= 15 ? '优' : visibility >= 10 ? '良' : '一般';let photoColor = photoLevel === '优' ? '#4CAF50' : photoLevel === '良' ? '#2196F3' : '#FF9800';// 空气质量let airLevel = visibility >= 15 ? '优' : visibility >= 10 ? '良' : '轻度污染';let airColor = airLevel === '优' ? '#4CAF50' : airLevel === '良' ? '#2196F3' : '#FF9800';indexElement.innerHTML = `<div style="display: flex; justify-content: space-between; align-items: center;"><span>🚶 舒适度指数</span><span style="background: ${comfortColor}; color: white; padding: 2px 8px; border-radius: 12px; font-size: 12px;">${comfortLevel}</span></div><div style="display: flex; justify-content: space-between; align-items: center;"><span>📸 拍照指数</span><span style="background: ${photoColor}; color: white; padding: 2px 8px; border-radius: 12px; font-size: 12px;">${photoLevel}</span></div><div style="display: flex; justify-content: space-between; align-items: center;"><span>🌬️ 空气质量</span><span style="background: ${airColor}; color: white; padding: 2px 8px; border-radius: 12px; font-size: 12px;">${airLevel}</span></div>`;}// 检查天气预警function checkWeatherAlerts() {const alertsElement = document.getElementById('weather-alerts');const alertContent = document.getElementById('alert-content');if (!alertsElement || !alertContent) return;// 模拟天气预警检查const hasAlert = Math.random() < 0.3; // 30% 概率有预警if (hasAlert) {const alerts = ['大风蓝色预警:预计今日下午到夜间,部分地区有4-5级偏北风,阵风6-7级,请注意防范。','霜冻黄色预警:预计明晨最低气温将降至2°C以下,请注意添衣保暖。','大雾黄色预警:预计今夜到明晨有雾,能见度不足500米,请注意交通安全。'];const randomAlert = alerts[Math.floor(Math.random() * alerts.length)];alertContent.textContent = randomAlert;alertsElement.style.display = 'block';} else {alertsElement.style.display = 'none';}}// 定时更新天气setTimeout(updateWeather, 2000);setInterval(updateWeather, 30 * 60 * 1000);// 添加全局错误处理window.addEventListener('error', function(e) {console.error('JavaScript错误:', e.error);});// 🎨 增强现有函数的动画效果const originalShowSection = showSection;showSection = function(section) {console.log('🎬 切换到区域:', section, '(带动画效果)');// 如果动画管理器存在,使用动画切换if (animationManager && !animationManager.isAnimating) {animationManager.switchToPage(section);return;}// 否则使用原始函数originalShowSection(section);};// 🎯 增强按钮点击效果const originalSetupEventListeners = setupEventListeners;setupEventListeners = function() {originalSetupEventListeners();// 为所有按钮添加点击反馈效果document.querySelectorAll('button, .nav-item, .day-button').forEach(element => {element.addEventListener('click', function(e) {// 创建点击波纹效果const ripple = document.createElement('span');const rect = this.getBoundingClientRect();const size = Math.max(rect.width, rect.height);const x = e.clientX - rect.left - size / 2;const y = e.clientY - rect.top - size / 2;ripple.style.cssText = `position: absolute;width: ${size}px;height: ${size}px;left: ${x}px;top: ${y}px;background: rgba(255, 255, 255, 0.6);border-radius: 50%;transform: scale(0);animation: ripple-animation 0.6s linear;pointer-events: none;z-index: 1000;`;this.style.position = 'relative';this.style.overflow = 'hidden';this.appendChild(ripple);setTimeout(() => {if (ripple.parentNode) {ripple.parentNode.removeChild(ripple);}}, 600);});});// 添加键盘提示const keyboardHint = document.createElement('div');keyboardHint.innerHTML = `<div style="position: fixed; bottom: 20px; right: 20px; background: rgba(0,0,0,0.8); color: white; padding: 15px; border-radius: 10px; font-size: 12px; z-index: 1000; backdrop-filter: blur(10px);"><div style="margin-bottom: 8px; font-weight: bold;">⌨️ 快捷键</div><div>1-4: 切换页面</div><div>ESC: 返回首页</div><div>←→: 上下页面</div><div style="margin-top: 8px; font-size: 10px; opacity: 0.7;">📱 支持左右滑动</div></div>`;document.body.appendChild(keyboardHint);// 3秒后自动隐藏提示setTimeout(() => {keyboardHint.style.transition = 'opacity 1s ease';keyboardHint.style.opacity = '0';setTimeout(() => {if (keyboardHint.parentNode) {keyboardHint.parentNode.removeChild(keyboardHint);}}, 1000);}, 3000);};// 🎪 添加波纹动画样式const rippleStyle = document.createElement('style');rippleStyle.textContent = `@keyframes ripple-animation {to {transform: scale(4);opacity: 0;}}/* 🎨 性能优化:暂停不可见动画 */.particles {animation-play-state: running;}body.page-hidden .particles {animation-play-state: paused;}/* 📱 移动端优化 */@media (max-width: 768px) {.cursor-glow {display: none;}.particles .particle {animation-duration: 12s;}.card-3d:hover {transform: translateY(-5px);}}/* 🎯 无障碍支持 */@media (prefers-reduced-motion: reduce) {* {animation-duration: 0.01ms !important;animation-iteration-count: 1 !important;transition-duration: 0.01ms !important;}.typewriter {animation: none;border-right: none;}.particles {display: none;}}`;document.head.appendChild(rippleStyle);// 🎨 页面可见性API优化性能document.addEventListener('visibilitychange', function() {if (document.hidden) {document.body.classList.add('page-hidden');} else {document.body.classList.remove('page-hidden');}});// 🌟 添加页面加载进度条function showLoadingProgress() {const progressBar = document.createElement('div');progressBar.style.cssText = `position: fixed;top: 0;left: 0;width: 0%;height: 3px;background: linear-gradient(90deg, var(--primary-orange), var(--primary-blue));z-index: 10000;transition: width 0.3s ease;`;document.body.appendChild(progressBar);let progress = 0;const interval = setInterval(() => {progress += Math.random() * 15;if (progress >= 100) {progress = 100;clearInterval(interval);setTimeout(() => {progressBar.style.opacity = '0';setTimeout(() => {if (progressBar.parentNode) {progressBar.parentNode.removeChild(progressBar);}}, 300);}, 200);}progressBar.style.width = progress + '%';}, 100);}// 页面完全加载后的最终检查window.addEventListener('load', function() {console.log('🎉 山西5日游旅行助手加载完成!');console.log('📊 数据统计:');console.log('- 路线天数:', travelRoute.length);console.log('- 景点总数:', travelRoute.reduce((total, day) => total + day.attractions.length, 0));console.log('- 餐厅推荐:', Object.values(restaurants).reduce((total, city) => total + city.length, 0));console.log('✨ 动画效果已启用:');console.log('  - 页面切换动画 ✓');console.log('  - 按钮波纹效果 ✓');console.log('  - 鼠标跟随光晕 ✓');console.log('  - 动态渐变背景 ✓');console.log('  - 数字计数动画 ✓');console.log('  - 键盘快捷键支持 ✓');console.log('  - 触摸手势支持 ✓');console.log('  - 滚动隐藏导航 ✓');console.log('✅ 所有功能已就绪,可以开始使用!');// 启动高级动画效果setTimeout(() => {addAdvancedAnimations();}, 1000);// 显示欢迎消息setTimeout(() => {const welcomeToast = document.createElement('div');welcomeToast.style.cssText = `position: fixed;top: 100px;right: 20px;background: linear-gradient(135deg, var(--primary-orange), var(--primary-blue));color: white;padding: 15px 20px;border-radius: 10px;box-shadow: 0 10px 30px rgba(0,0,0,0.2);z-index: 10000;transform: translateX(400px);transition: transform 0.5s cubic-bezier(0.68, -0.55, 0.265, 1.55);`;welcomeToast.innerHTML = `<div style="font-weight: bold; margin-bottom: 5px;">🎉 欢迎使用山西旅行助手!</div><div style="font-size: 12px; opacity: 0.9;">所有动画效果已启用,尽情探索吧!</div>`;document.body.appendChild(welcomeToast);setTimeout(() => {welcomeToast.style.transform = 'translateX(0)';}, 100);setTimeout(() => {welcomeToast.style.transform = 'translateX(400px)';setTimeout(() => {if (welcomeToast.parentNode) {welcomeToast.parentNode.removeChild(welcomeToast);}}, 500);}, 4000);}, 2000);});// 🚀 启动加载进度条showLoadingProgress();</script><script>// 修复浮动按钮功能的JavaScript代码document.addEventListener('DOMContentLoaded', function() {// 添加浮动按钮样式const style = document.createElement('style');style.textContent = `/* 浮动按钮样式 */.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);}/* 让首页样式更低调 */.start-journey-btn {animation: none !important;box-shadow: 0 2px 8px rgba(255, 107, 107, 0.2) !important;}.start-journey-btn:hover {box-shadow: 0 4px 12px rgba(255, 107, 107, 0.3) !important;transform: translateY(-1px) !important;}.rainbow-border {display: none !important;}/* 美食推荐弹窗动画 *//* 美食推荐弹窗动画 */@keyframes fadeIn {from { opacity: 0; transform: scale(0.9); }to { opacity: 1; transform: scale(1); }}@keyframes fadeInUp {from { opacity: 0; transform: translateY(20px); }to { opacity: 1; transform: translateY(0); }}@keyframes slideInRight {from { transform: translateX(100%); opacity: 0; }to { transform: translateX(0); opacity: 1; }}@keyframes slideOutRight {from { transform: translateX(0); opacity: 1; }to { transform: translateX(100%); opacity: 0; }}/* 美食筛选按钮样式 */.food-filter-btn:hover {background: var(--primary-orange) !important;color: white !important;transform: translateY(-2px);box-shadow: 0 4px 12px rgba(255, 107, 107, 0.3);}.food-filter-btn.active {background: var(--primary-orange) !important;color: white !important;}/* 美食卡片悬停效果 */.food-card-item {transition: all 0.3s ease;}.food-card-item:hover {transform: translateY(-5px);box-shadow: 0 8px 25px rgba(0,0,0,0.15);}/* 评分星星悬停效果 */.food-rating span:hover {transform: scale(1.2);transition: transform 0.2s ease;}/* 收藏按钮悬停效果 */button[onclick*="toggleFoodFavorite"]:hover {transform: scale(1.2);transition: transform 0.2s ease;}@keyframes slideUp {from { transform: translateY(50px); opacity: 0; }to { transform: translateY(0); opacity: 1; }}`;document.head.appendChild(style);// 添加浮动按钮HTMLconst floatingButtons = document.createElement('div');floatingButtons.className = 'floating-buttons';floatingButtons.innerHTML = `<button class="floating-btn" data-section="map" title="查看地图">🗺️</button><button class="floating-btn" data-section="weather" title="天气预报">🌤️</button><button class="floating-btn" data-section="route" title="完整路线">📍</button>`;document.body.appendChild(floatingButtons);// 为浮动按钮添加点击事件document.querySelectorAll('.floating-btn').forEach(btn => {btn.addEventListener('click', function() {const section = this.getAttribute('data-section');const action = this.getAttribute('data-action');// 添加点击反馈this.style.transform = 'scale(0.9)';setTimeout(() => {this.style.transform = '';}, 150);if (section) {// 调用现有的showSection函数if (typeof showSection === 'function') {showSection(section);} else {// 如果showSection不存在,手动切换document.querySelectorAll('.section').forEach(s => s.style.display = 'none');const pageSection = document.getElementById(section);if (pageSection) {pageSection.style.display = 'block';}}} else if (action === 'food') {// 美食推荐功能showSection('food');}});});// 移除过于显眼的动画效果setTimeout(() => {const startBtn = document.querySelector('.start-journey-btn');if (startBtn) {startBtn.classList.remove('heartbeat');startBtn.style.animation = 'none';}// 移除彩虹边框const rainbowBorders = document.querySelectorAll('.rainbow-border');rainbowBorders.forEach(border => {const child = border.firstElementChild;if (child) {border.parentNode.insertBefore(child, border);border.remove();}});}, 100);// 优化地图加载性能const originalInitMap = window.initMap;if (originalInitMap) {window.initMap = function() {// 添加防抖处理if (window.mapInitTimeout) {clearTimeout(window.mapInitTimeout);}window.mapInitTimeout = setTimeout(() => {originalInitMap.call(this);}, 100);};}});// 完整的美食推荐功能function showFoodMessage() {showFoodSection();}// 显示美食推荐页面function showFoodSection() {// 隐藏所有其他区域document.querySelectorAll('.section').forEach(section => {section.style.display = 'none';});// 显示美食推荐区域let foodSection = document.getElementById('food-section');if (!foodSection) {foodSection = createFoodSection();document.querySelector('.container').appendChild(foodSection);}foodSection.style.display = 'block';// 更新导航状态document.querySelectorAll('.nav-item').forEach(item => {item.classList.remove('active');});}// 创建美食推荐区域function createFoodSection() {const foodSection = document.createElement('div');foodSection.id = 'food-section';foodSection.className = 'section';foodSection.style.display = 'none';const foodData = {taiyuan: {name: '太原',foods: [{ name: '刀削面', desc: '山西最著名的面食,面条粗细不均,口感筋道', price: '15-25元', location: '老太原面馆' },{ name: '过油肉', desc: '山西传统名菜,肉质鲜嫩,色泽金黄', price: '35-45元', location: '晋菜馆' },{ name: '头脑', desc: '太原特色早餐,营养丰富的羊肉汤', price: '20-30元', location: '清和元' },{ name: '羊杂割', desc: '山西传统小吃,汤鲜味美', price: '18-28元', location: '老字号羊杂店' }]},pingyao: {name: '平遥',foods: [{ name: '平遥牛肉', desc: '中华老字号,色泽红润,香味浓郁', price: '50-80元/斤', location: '冠云牛肉店' },{ name: '碗托', desc: '平遥特色小吃,口感爽滑', price: '8-12元', location: '古城内小摊' },{ name: '莜面栲栳栳', desc: '山西特色面食,形似蜂窝', price: '25-35元', location: '德居源' },{ name: '平遥豆腐脑', desc: '嫩滑香甜,配菜丰富', price: '10-15元', location: '早餐摊点' }]},datong: {name: '大同',foods: [{ name: '大同刀削面', desc: '大同版本的刀削面,汤头更浓郁', price: '18-28元', location: '老大同面馆' },{ name: '浑源凉粉', desc: '大同特色凉粉,清爽解腻', price: '12-18元', location: '浑源凉粉店' },{ name: '大同烧麦', desc: '皮薄馅大,鲜美可口', price: '20-30元', location: '老字号烧麦店' },{ name: '油炸糕', desc: '外酥内软,香甜可口', price: '5-8元/个', location: '街边小摊' }]}};foodSection.innerHTML = `<div class="panel-title">🍜 山西美食推荐</div><!-- 美食筛选按钮 --><div class="food-filters" style="display: flex; justify-content: center; gap: 10px; margin-bottom: 20px; flex-wrap: wrap;"><button class="food-filter-btn active" data-filter="all" style="padding: 8px 16px; border: 2px solid var(--primary-orange); background: var(--primary-orange); color: white; border-radius: 20px; cursor: pointer; font-size: 14px; transition: all 0.3s;">全部</button><button class="food-filter-btn" data-filter="noodles" style="padding: 8px 16px; border: 2px solid var(--primary-orange); background: transparent; color: var(--primary-orange); border-radius: 20px; cursor: pointer; font-size: 14px; transition: all 0.3s;">面食类</button><button class="food-filter-btn" data-filter="meat" style="padding: 8px 16px; border: 2px solid var(--primary-orange); background: transparent; color: var(--primary-orange); border-radius: 20px; cursor: pointer; font-size: 14px; transition: all 0.3s;">肉食类</button><button class="food-filter-btn" data-filter="snacks" style="padding: 8px 16px; border: 2px solid var(--primary-orange); background: transparent; color: var(--primary-orange); border-radius: 20px; cursor: pointer; font-size: 14px; transition: all 0.3s;">小食类</button><button class="food-filter-btn" data-filter="specialty" style="padding: 8px 16px; border: 2px solid var(--primary-orange); background: transparent; color: var(--primary-orange); border-radius: 20px; cursor: pointer; font-size: 14px; transition: all 0.3s;">特产类</button></div><div class="food-intro" style="background: rgba(255,255,255,0.9); padding: 20px; border-radius: 15px; margin-bottom: 20px; text-align: center;"><h3 style="color: var(--accent-pink); margin-bottom: 15px;">🎯 美食攻略</h3><p style="color: #666; line-height: 1.6; margin: 0;">山西素有"面食之乡"的美誉,这里的美食文化源远流长。从太原的刀削面到平遥的牛肉,每一道菜都承载着深厚的历史文化底蕴。让我们一起品味三晋大地的经典美味!</p></div><div class="food-cities">${Object.entries(foodData).map(([cityKey, cityData]) => ` <div class="food-city-card" style="background: rgba(255,255,255,0.95); border-radius: 20px; padding: 25px; margin-bottom: 25px; box-shadow: 0 8px 32px rgba(0,0,0,0.1);"> <h3 style="color: var(--primary-blue); margin-bottom: 20px; font-size: 24px; text-align: center;"> 🏙️ ${cityData.name}特色美食 </h3> <div class="food-grid" style="display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 15px;"> ${cityData.foods.map(food => ` <div class="food-item" style=" background: linear-gradient(135deg, #f8f9ff, #fff); border: 2px solid #e8f2ff; border-radius: 15px; padding: 20px; transition: all 0.3s ease; cursor: pointer; " onmouseover="this.style.transform='translateY(-5px)'; this.style.boxShadow='0 10px 30px rgba(0,0,0,0.15)'" onmouseout="this.style.transform=''; this.style.boxShadow=''"> <h4 style="color: var(--accent-pink); margin: 0 0 10px 0; font-size: 18px;">🍽️ ${food.name}</h4> <p style="color: #666; font-size: 14px; line-height: 1.5; margin: 0 0 10px 0;">${food.desc}</p> <div style="display: flex; justify-content: space-between; align-items: center; margin-top: 15px;"> <span style="background: var(--primary-orange); color: white; padding: 4px 12px; border-radius: 20px; font-size: 12px; font-weight: 600;">💰 ${food.price}</span> <span style="color: var(--primary-blue); font-size: 12px;">📍 ${food.location}</span> </div> </div> `).join('')} </div> </div> `).join('')}</div><div class="food-tips" style="background: linear-gradient(135deg, #fff8e1, #fff3c4); border-radius: 15px; padding: 20px; margin-top: 20px; border-left: 5px solid var(--primary-orange);"><h4 style="color: var(--primary-orange); margin: 0 0 15px 0; font-size: 18px;">💡 美食小贴士</h4><ul style="color: #666; line-height: 1.8; margin: 0; padding-left: 20px;"><li>建议在当地老字号餐厅品尝正宗美食</li><li>山西面食种类繁多,可以多尝试几种</li><li>平遥牛肉可以买一些作为特产带回家</li><li>用餐时间避开高峰期,体验更佳</li><li>可以向当地人询问隐藏的美食小店</li></ul></div>`;return foodSection;}// 显示美食推荐页面function showFoodSection() {// 隐藏所有其他区域document.querySelectorAll('.section').forEach(section => {section.style.display = 'none';});// 显示美食推荐区域let foodSection = document.getElementById('food-section');if (!foodSection) {foodSection = createFoodSection();document.querySelector('.container').appendChild(foodSection);}foodSection.style.display = 'block';// 更新导航状态document.querySelectorAll('.nav-item').forEach(item => {item.classList.remove('active');});}// 创建美食推荐区域function createFoodSection() {const foodSection = document.createElement('div');foodSection.id = 'food-section';foodSection.className = 'section';foodSection.style.display = 'none';const foodData = {taiyuan: {name: '太原',foods: [{ name: '刀削面', desc: '山西最著名的面食,面条粗细不均,口感筋道', price: '15-25元', location: '老太原面馆' },{ name: '过油肉', desc: '山西传统名菜,肉质鲜嫩,色泽金黄', price: '35-45元', location: '晋菜馆' },{ name: '头脑', desc: '太原特色早餐,营养丰富的羊肉汤', price: '20-30元', location: '清和元' },{ name: '羊杂割', desc: '山西传统小吃,汤鲜味美', price: '18-28元', location: '老字号羊杂店' }]},pingyao: {name: '平遥',foods: [{ name: '平遥牛肉', desc: '中华老字号,色泽红润,香味浓郁', price: '50-80元/斤', location: '冠云牛肉店' },{ name: '碗托', desc: '平遥特色小吃,口感爽滑', price: '8-12元', location: '古城内小摊' },{ name: '莜面栲栳栳', desc: '山西特色面食,形似蜂窝', price: '25-35元', location: '德居源' },{ name: '平遥豆腐脑', desc: '嫩滑香甜,配菜丰富', price: '10-15元', location: '早餐摊点' }]},datong: {name: '大同',foods: [{ name: '大同刀削面', desc: '大同版本的刀削面,汤头更浓郁', price: '18-28元', location: '老大同面馆' },{ name: '浑源凉粉', desc: '大同特色凉粉,清爽解腻', price: '12-18元', location: '浑源凉粉店' },{ name: '大同烧麦', desc: '皮薄馅大,鲜美可口', price: '20-30元', location: '老字号烧麦店' },{ name: '油炸糕', desc: '外酥内软,香甜可口', price: '5-8元/个', location: '街边小摊' }]}};foodSection.innerHTML = `<div class="panel-title">🍜 山西美食推荐</div><div class="food-intro" style="background: rgba(255,255,255,0.9); padding: 20px; border-radius: 15px; margin-bottom: 20px; text-align: center;"><h3 style="color: var(--accent-pink); margin-bottom: 15px;">🎯 美食攻略</h3><p style="color: #666; line-height: 1.6; margin: 0;">山西素有"面食之乡"的美誉,这里的美食文化源远流长。从太原的刀削面到平遥的牛肉,每一道菜都承载着深厚的历史文化底蕴。让我们一起品味三晋大地的经典美味!</p></div><div class="food-cities">${Object.entries(foodData).map(([cityKey, cityData]) => ` <div class="food-city-card" style="background: rgba(255,255,255,0.95); border-radius: 20px; padding: 25px; margin-bottom: 25px; box-shadow: 0 8px 32px rgba(0,0,0,0.1);"> <h3 style="color: var(--primary-blue); margin-bottom: 20px; font-size: 24px; text-align: center;"> 🏙️ ${cityData.name}特色美食 </h3> <div class="food-grid" style="display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 15px;"> ${cityData.foods.map(food => ` <div class="food-item" style=" background: linear-gradient(135deg, #f8f9ff, #fff); border: 2px solid #e8f2ff; border-radius: 15px; padding: 20px; transition: all 0.3s ease; cursor: pointer; " onmouseover="this.style.transform='translateY(-5px)'; this.style.boxShadow='0 10px 30px rgba(0,0,0,0.15)'" onmouseout="this.style.transform=''; this.style.boxShadow=''"> <h4 style="color: var(--accent-pink); margin: 0 0 10px 0; font-size: 18px;">🍽️ ${food.name}</h4> <p style="color: #666; font-size: 14px; line-height: 1.5; margin: 0 0 10px 0;">${food.desc}</p> <div style="display: flex; justify-content: space-between; align-items: center; margin-top: 15px;"> <span style="background: var(--primary-orange); color: white; padding: 4px 12px; border-radius: 20px; font-size: 12px; font-weight: 600;">💰 ${food.price}</span> <span style="color: var(--primary-blue); font-size: 12px;">📍 ${food.location}</span> </div> </div> `).join('')} </div> </div> `).join('')}</div><div class="food-tips" style="background: linear-gradient(135deg, #fff8e1, #fff3c4); border-radius: 15px; padding: 20px; margin-top: 20px; border-left: 5px solid var(--primary-orange);"><h4 style="color: var(--primary-orange); margin: 0 0 15px 0; font-size: 18px;">💡 美食小贴士</h4><ul style="color: #666; line-height: 1.8; margin: 0; padding-left: 20px;"><li>建议在当地老字号餐厅品尝正宗美食</li><li>山西面食种类繁多,可以多尝试几种</li><li>平遥牛肉可以买一些作为特产带回家</li><li>用餐时间避开高峰期,体验更佳</li><li>可以向当地人询问隐藏的美食小店</li></ul></div>`;return foodSection;}// 完善的美食推荐功能// 美食收藏功能function toggleFoodFavorite(foodName, element) {let favorites = JSON.parse(localStorage.getItem('foodFavorites') || '[]');if (favorites.includes(foodName)) {// 取消收藏favorites = favorites.filter(name => name !== foodName);element.innerHTML = '🤍';element.title = '添加到收藏';showToast('已取消收藏 ' + foodName, 'info');} else {// 添加收藏favorites.push(foodName);element.innerHTML = '❤️';element.title = '取消收藏';showToast('已收藏 ' + foodName, 'success');}localStorage.setItem('foodFavorites', JSON.stringify(favorites));}// 美食评分功能function rateFoodItem(element, rating) {const ratingContainer = element.parentElement;const stars = ratingContainer.querySelectorAll('span');// 更新星星显示stars.forEach((star, index) => {if (index < rating) {star.style.color = '#ffc107';star.innerHTML = '⭐';} else {star.style.color = '#ddd';star.innerHTML = '☆';}});// 保存评分到本地存储const foodCard = element.closest('.food-card-item');const foodName = foodCard.querySelector('h3').textContent;let ratings = JSON.parse(localStorage.getItem('foodRatings') || '{}');ratings[foodName] = rating;localStorage.setItem('foodRatings', JSON.stringify(ratings));showToast(`已为 ${foodName} 评分 ${rating}`, 'success');}// 初始化美食筛选功能function initFoodFilters() {const filterButtons = document.querySelectorAll('.food-filter-btn');filterButtons.forEach(btn => {btn.addEventListener('click', function() {// 移除所有按钮的激活状态filterButtons.forEach(b => {b.classList.remove('active');b.style.background = 'transparent';b.style.color = 'var(--primary-orange)';});// 激活当前按钮this.classList.add('active');this.style.background = 'var(--primary-orange)';this.style.color = 'white';const filterType = this.dataset.filter;filterFoodCards(filterType);});});}// 筛选美食卡片function filterFoodCards(filterType) {const foodCards = document.querySelectorAll('.food-card-item');foodCards.forEach(card => {const tags = card.querySelectorAll('span');let shouldShow = filterType === 'all';if (!shouldShow) {tags.forEach(tag => {const tagText = tag.textContent;if ((filterType === 'noodles' && tagText.includes('面食类')) ||(filterType === 'meat' && tagText.includes('肉食类')) ||(filterType === 'snacks' && tagText.includes('小食类')) ||(filterType === 'specialty' && tagText.includes('特产类'))) {shouldShow = true;}});}if (shouldShow) {card.style.display = 'flex';card.style.animation = 'fadeInUp 0.5s ease-out';} else {card.style.display = 'none';}});}// 显示提示消息function showToast(message, type = 'info') {const toast = document.createElement('div');toast.className = `toast toast-${type}`;toast.style.cssText = `position: fixed;top: 20px;right: 20px;background: ${type === 'success' ? '#4CAF50' : type === 'info' ? '#2196F3' : '#ff9800'};color: white;padding: 12px 20px;border-radius: 8px;box-shadow: 0 4px 12px rgba(0,0,0,0.15);z-index: 10000;font-size: 14px;animation: slideInRight 0.3s ease-out;max-width: 300px;`;toast.textContent = message;document.body.appendChild(toast);setTimeout(() => {toast.style.animation = 'slideOutRight 0.3s ease-out';setTimeout(() => {if (document.body.contains(toast)) {document.body.removeChild(toast);}}, 300);}, 2000);}// 加载用户的收藏和评分function loadUserPreferences() {const favorites = JSON.parse(localStorage.getItem('foodFavorites') || '[]');const ratings = JSON.parse(localStorage.getItem('foodRatings') || '{}');// 恢复收藏状态document.querySelectorAll('[onclick*="toggleFoodFavorite"]').forEach(btn => {const foodName = btn.getAttribute('onclick').match(/'([^']+)'/)[1];if (favorites.includes(foodName)) {btn.innerHTML = '❤️';btn.title = '取消收藏';}});// 恢复评分状态Object.keys(ratings).forEach(foodName => {const rating = ratings[foodName];const foodCards = document.querySelectorAll('.food-card-item');foodCards.forEach(card => {const cardTitle = card.querySelector('h3').textContent;if (cardTitle === foodName) {const stars = card.querySelectorAll('.food-rating span');stars.forEach((star, index) => {if (index < rating) {star.style.color = '#ffc107';star.innerHTML = '⭐';} else {star.style.color = '#ddd';star.innerHTML = '☆';}});}});});}// 完善的美食推荐功能function showFoodRecommendations() {// 创建美食推荐弹窗const foodModal = document.createElement('div');foodModal.style.cssText = `position: fixed;top: 0;left: 0;width: 100%;height: 100%;background: rgba(0, 0, 0, 0.7);z-index: 10000;display: flex;align-items: center;justify-content: center;backdrop-filter: blur(5px);animation: fadeIn 0.3s ease;`;const foodContent = document.createElement('div');foodContent.style.cssText = `background: white;border-radius: 15px;padding: 30px;max-width: 650px;max-height: 85vh;overflow-y: auto;box-shadow: 0 20px 40px rgba(0, 0, 0, 0.3);position: relative;animation: slideUp 0.4s ease;margin: 20px;`;foodContent.innerHTML = `<div style="text-align: center; margin-bottom: 25px;"><h2 style="color: #333; margin: 0 0 10px 0; font-size: 28px; font-weight: 600;">🍜 山西美食推荐</h2><p style="color: #666; margin: 0; font-size: 16px;">品味三晋大地的经典美味</p></div><div style="display: grid; gap: 20px;"><div class="food-item" style="display: flex; gap: 15px; padding: 20px; border-radius: 12px; background: linear-gradient(135deg, #fff5f5, #fff0f0); border: 1px solid #ffe0e0; transition: all 0.3s ease; cursor: pointer;"><div style="font-size: 50px; flex-shrink: 0; filter: drop-shadow(2px 2px 4px rgba(0,0,0,0.1));">🍜</div><div style="flex: 1;"><div style="display: flex; justify-content: space-between; align-items: flex-start; margin-bottom: 8px;"><h3 style="margin: 0; color: #d32f2f; font-size: 20px; font-weight: 600;">刀削面</h3><div style="display: flex; gap: 8px; align-items: center;"><div class="food-rating" style="display: flex; gap: 2px;"><span style="color: #ffc107; cursor: pointer;" onclick="rateFoodItem(this, 1)">⭐</span><span style="color: #ffc107; cursor: pointer;" onclick="rateFoodItem(this, 2)">⭐</span><span style="color: #ffc107; cursor: pointer;" onclick="rateFoodItem(this, 3)">⭐</span><span style="color: #ffc107; cursor: pointer;" onclick="rateFoodItem(this, 4)">⭐</span><span style="color: #ffc107; cursor: pointer;" onclick="rateFoodItem(this, 5)">⭐</span></div><button style="background: none; border: none; font-size: 18px; cursor: pointer;" onclick="toggleFoodFavorite('刀削面', this)" title="添加到收藏">🤍</button></div></div><p style="margin: 0 0 12px 0; color: #555; font-size: 15px; line-height: 1.5;">山西最著名的面食,面条粗细不均,三角形状,口感筋道爽滑。师傅手持特制刀具,将面团削成面条直接入锅,技艺精湛。</p><div style="display: flex; gap: 15px; font-size: 13px;"><span style="background: #e3f2fd; color: #1976d2; padding: 4px 8px; border-radius: 12px;">💰 15-25元</span><span style="background: #f3e5f5; color: #7b1fa2; padding: 4px 8px; border-radius: 12px;">📍 老太原面馆</span><span style="background: #e8f5e8; color: #2e7d32; padding: 4px 8px; border-radius: 12px;">🍜 面食类</span></div></div></div><div class="food-item" style="display: flex; gap: 15px; padding: 20px; border-radius: 12px; background: linear-gradient(135deg, #fff8e1, #fff3c4); border: 1px solid #ffecb3; transition: all 0.3s ease; cursor: pointer;"><div style="font-size: 50px; flex-shrink: 0; filter: drop-shadow(2px 2px 4px rgba(0,0,0,0.1));">🥩</div><div style="flex: 1;"><div style="display: flex; justify-content: space-between; align-items: flex-start; margin-bottom: 8px;"><h3 style="margin: 0; color: #f57c00; font-size: 20px; font-weight: 600;">过油肉</h3><div style="display: flex; gap: 8px; align-items: center;"><div class="food-rating" style="display: flex; gap: 2px;"><span style="color: #ffc107; cursor: pointer;" onclick="rateFoodItem(this, 1)">⭐</span><span style="color: #ffc107; cursor: pointer;" onclick="rateFoodItem(this, 2)">⭐</span><span style="color: #ffc107; cursor: pointer;" onclick="rateFoodItem(this, 3)">⭐</span><span style="color: #ffc107; cursor: pointer;" onclick="rateFoodItem(this, 4)">⭐</span><span style="color: #ffc107; cursor: pointer;" onclick="rateFoodItem(this, 5)">⭐</span></div><button style="background: none; border: none; font-size: 18px; cursor: pointer;" onclick="toggleFoodFavorite('过油肉', this)" title="添加到收藏">🤍</button></div></div><p style="margin: 0 0 12px 0; color: #555; font-size: 15px; line-height: 1.5;">山西传统名菜,选用优质猪肉片,配以青椒、木耳等,经过油炸后炒制,肉片鲜嫩,酸甜适中,是山西人的家常菜。</p><div style="display: flex; gap: 15px; font-size: 13px;"><span style="background: #e3f2fd; color: #1976d2; padding: 4px 8px; border-radius: 12px;">💰 35-45元</span><span style="background: #f3e5f5; color: #7b1fa2; padding: 4px 8px; border-radius: 12px;">📍 晋菜馆</span><span style="background: #fff3e0; color: #f57c00; padding: 4px 8px; border-radius: 12px;">🥩 肉食类</span></div></div></div><div class="food-item" style="display: flex; gap: 15px; padding: 20px; border-radius: 12px; background: linear-gradient(135deg, #f3e5f5, #e1bee7); border: 1px solid #ce93d8; transition: all 0.3s ease; cursor: pointer;"><div style="font-size: 50px; flex-shrink: 0; filter: drop-shadow(2px 2px 4px rgba(0,0,0,0.1));">🥩</div><div style="flex: 1;"><div style="display: flex; justify-content: space-between; align-items: flex-start; margin-bottom: 8px;"><h3 style="margin: 0; color: #7b1fa2; font-size: 20px; font-weight: 600;">平遥牛肉</h3><div style="display: flex; gap: 8px; align-items: center;"><div class="food-rating" style="display: flex; gap: 2px;"><span style="color: #ffc107; cursor: pointer;" onclick="rateFoodItem(this, 1)">⭐</span><span style="color: #ffc107; cursor: pointer;" onclick="rateFoodItem(this, 2)">⭐</span><span style="color: #ffc107; cursor: pointer;" onclick="rateFoodItem(this, 3)">⭐</span><span style="color: #ffc107; cursor: pointer;" onclick="rateFoodItem(this, 4)">⭐</span><span style="color: #ffc107; cursor: pointer;" onclick="rateFoodItem(this, 5)">⭐</span></div><button style="background: none; border: none; font-size: 18px; cursor: pointer;" onclick="toggleFoodFavorite('平遥牛肉', this)" title="添加到收藏">🤍</button></div></div><p style="margin: 0 0 12px 0; color: #555; font-size: 15px; line-height: 1.5;">平遥古城特产,选用优质黄牛肉,采用传统工艺腌制风干,色泽红润,肉质鲜美,是绝佳的旅游纪念品和下酒菜。</p><div style="display: flex; gap: 15px; font-size: 13px;"><span style="background: #e3f2fd; color: #1976d2; padding: 4px 8px; border-radius: 12px;">💰 50-80元/斤</span><span style="background: #f3e5f5; color: #7b1fa2; padding: 4px 8px; border-radius: 12px;">📍 冠云牛肉店</span><span style="background: #fce4ec; color: #c2185b; padding: 4px 8px; border-radius: 12px;">🎁 特产类</span></div></div></div><div class="food-item" style="display: flex; gap: 15px; padding: 20px; border-radius: 12px; background: linear-gradient(135deg, #e8f5e8, #c8e6c9); border: 1px solid #a5d6a7; transition: all 0.3s ease; cursor: pointer;"><div style="font-size: 50px; flex-shrink: 0; filter: drop-shadow(2px 2px 4px rgba(0,0,0,0.1));">🍲</div><div style="flex: 1;"><div style="display: flex; justify-content: space-between; align-items: flex-start; margin-bottom: 8px;"><h3 style="margin: 0; color: #ef6c00; font-size: 20px; font-weight: 600;">山西老陈醋</h3><div style="display: flex; gap: 8px; align-items: center;"><div class="food-rating" style="display: flex; gap: 2px;"><span style="color: #ffc107; cursor: pointer;" onclick="rateFoodItem(this, 1)">⭐</span><span style="color: #ffc107; cursor: pointer;" onclick="rateFoodItem(this, 2)">⭐</span><span style="color: #ffc107; cursor: pointer;" onclick="rateFoodItem(this, 3)">⭐</span><span style="color: #ffc107; cursor: pointer;" onclick="rateFoodItem(this, 4)">⭐</span><span style="color: #ffc107; cursor: pointer;" onclick="rateFoodItem(this, 5)">⭐</span></div><button style="background: none; border: none; font-size: 18px; cursor: pointer;" onclick="toggleFoodFavorite('山西老陈醋', this)" title="添加到收藏">🤍</button></div></div><p style="margin: 0 0 12px 0; color: #555; font-size: 15px; line-height: 1.5;">中国四大名醋之首,采用传统工艺酿造,酸味纯正,香气浓郁,具有开胃消食的功效,是山西人餐桌必备调料。</p><div style="display: flex; gap: 15px; font-size: 13px;"><span style="background: #e3f2fd; color: #1976d2; padding: 4px 8px; border-radius: 12px;">💰 20-50元/瓶</span><span style="background: #f3e5f5; color: #7b1fa2; padding: 4px 8px; border-radius: 12px;">📍 东湖醋园</span><span style="background: #fce4ec; color: #c2185b; padding: 4px 8px; border-radius: 12px;">🎁 特产类</span></div></div></div><div class="food-item" style="display: flex; gap: 15px; padding: 20px; border-radius: 12px; background: linear-gradient(135deg, #e3f2fd, #bbdefb); border: 1px solid #90caf9; transition: all 0.3s ease; cursor: pointer;"><div style="font-size: 50px; flex-shrink: 0; filter: drop-shadow(2px 2px 4px rgba(0,0,0,0.1));">🥟</div><div style="flex: 1;"><h3 style="margin: 0 0 8px 0; color: #1976d2; font-size: 20px; font-weight: 600;">莜面栲栳栳</h3><p style="margin: 0 0 12px 0; color: #555; font-size: 15px; line-height: 1.5;">忻州特色面食,用莜面制作,形似蜂窝,需要特殊技巧搓制。蘸料丰富多样,口感独特,营养价值高。</p><div style="display: flex; gap: 15px; font-size: 13px;"><span style="color: #ff6b6b; background: rgba(255,107,107,0.1); padding: 4px 8px; border-radius: 12px;">📍 忻州、五台山周边</span><span style="color: #4caf50; background: rgba(76,175,80,0.1); padding: 4px 8px; border-radius: 12px;">💰 18-28元</span></div></div></div><div class="food-item" style="display: flex; gap: 15px; padding: 20px; border-radius: 12px; background: linear-gradient(135deg, #fff3e0, #ffe0b2); border: 1px solid #ffcc02; transition: all 0.3s ease; cursor: pointer;"><div style="font-size: 50px; flex-shrink: 0; filter: drop-shadow(2px 2px 4px rgba(0,0,0,0.1));">🍯</div><div style="flex: 1;"><h3 style="margin: 0 0 8px 0; color: #ef6c00; font-size: 20px; font-weight: 600;">山西老陈醋</h3><p style="margin: 0 0 12px 0; color: #555; font-size: 15px; line-height: 1.5;">中国四大名醋之首,采用传统工艺酿造,酸味纯正,香气浓郁,具有开胃消食的功效,是山西人餐桌必备调料。</p><div style="display: flex; gap: 15px; font-size: 13px;"><span style="color: #ff6b6b; background: rgba(255,107,107,0.1); padding: 4px 8px; border-radius: 12px;">📍 东湖、水塔、紫林品牌</span><span style="color: #4caf50; background: rgba(76,175,80,0.1); padding: 4px 8px; border-radius: 12px;">💰 15-50元/瓶</span></div></div></div></div><div style="margin-top: 30px; padding-top: 25px; border-top: 2px solid #f0f0f0; text-align: center;"><div style="margin-bottom: 20px;"><h4 style="color: #333; margin: 0 0 10px 0; font-size: 16px;">🎯 美食攻略小贴士</h4><p style="color: #666; font-size: 14px; line-height: 1.5; margin: 0;">• 建议上午品尝太原头脑,下午体验刀削面<br>• 平遥牛肉可作为伴手礼带回家<br>• 山西老陈醋搭配任何面食都很棒</p></div><button onclick="this.closest('.food-modal').remove()" style="background: linear-gradient(135deg, #ff6b6b, #ff8e8e);color: white;border: none;padding: 15px 40px;border-radius: 30px;cursor: pointer;font-size: 16px;font-weight: 600;transition: all 0.3s ease;box-shadow: 0 6px 20px rgba(255, 107, 107, 0.3);letter-spacing: 1px;" onmouseover="this.style.transform='translateY(-3px)'; this.style.boxShadow='0 8px 25px rgba(255, 107, 107, 0.4)'" onmouseout="this.style.transform=''; this.style.boxShadow='0 6px 20px rgba(255, 107, 107, 0.3)'">关闭美食推荐</button></div>`;foodModal.className = 'food-modal';foodModal.appendChild(foodContent);document.body.appendChild(foodModal);// 点击背景关闭foodModal.addEventListener('click', function(e) {if (e.target === foodModal) {foodModal.style.animation = 'fadeIn 0.3s ease reverse';setTimeout(() => foodModal.remove(), 300);}});// 添加食物项目悬停效果setTimeout(() => {const foodItems = foodModal.querySelectorAll('.food-item');foodItems.forEach(item => {item.addEventListener('mouseenter', function() {this.style.transform = 'translateY(-5px) scale(1.02)';this.style.boxShadow = '0 10px 30px rgba(0, 0, 0, 0.15)';});item.addEventListener('mouseleave', function() {this.style.transform = '';this.style.boxShadow = '';});});}, 100);// 阻止滚动穿透document.body.style.overflow = 'hidden';foodModal.addEventListener('remove', () => {document.body.style.overflow = '';});}// 重新定义美食推荐功能,覆盖之前的重复定义window.showFoodSection = function() {// 隐藏所有其他区域document.querySelectorAll('.section').forEach(section => {section.style.display = 'none';});// 创建美食推荐页面内容const mainContent = document.querySelector('.container-fluid');let foodSection = document.getElementById('food-section');if (!foodSection) {foodSection = document.createElement('div');foodSection.id = 'food-section';foodSection.className = 'section';foodSection.innerHTML = `<div class="row"><div class="col-12"><h2 class="text-center mb-4">山西特色美食推荐</h2><!-- 美食筛选 --><div class="row mb-4"><div class="col-md-6"><select class="form-select" id="foodTypeFilter"><option value="">全部美食</option><option value="面食">面食</option><option value="肉类">肉类</option><option value="小吃">小吃</option><option value="汤品">汤品</option></select></div><div class="col-md-6"><input type="text" class="form-control" id="foodSearch" placeholder="搜索美食..."></div></div><!-- 美食列表 --><div class="row" id="foodList"><div class="col-md-6 col-lg-4 mb-4" data-type="面食"><div class="card h-100"><img src="https://via.placeholder.com/300x200?text=刀削面" class="card-img-top" alt="刀削面"><div class="card-body"><h5 class="card-title">刀削面</h5><p class="card-text">山西最著名的面食,面条粗细不均,口感筋道,配以各种浇头。</p><div class="d-flex justify-content-between align-items-center"><span class="badge bg-primary">面食</span><div class="rating"><span class="text-warning">★★★★★</span><small class="text-muted">(4.8)</small></div></div></div></div></div><div class="col-md-6 col-lg-4 mb-4" data-type="肉类"><div class="card h-100"><img src="https://via.placeholder.com/300x200?text=过油肉" class="card-img-top" alt="过油肉"><div class="card-body"><h5 class="card-title">过油肉</h5><p class="card-text">山西传统名菜,肉片嫩滑,配菜丰富,口味鲜美。</p><div class="d-flex justify-content-between align-items-center"><span class="badge bg-success">肉类</span><div class="rating"><span class="text-warning">★★★★☆</span><small class="text-muted">(4.6)</small></div></div></div></div></div><div class="col-md-6 col-lg-4 mb-4" data-type="小吃"><div class="card h-100"><img src="https://via.placeholder.com/300x200?text=平遥牛肉" class="card-img-top" alt="平遥牛肉"><div class="card-body"><h5 class="card-title">平遥牛肉</h5><p class="card-text">平遥古城特产,色泽红润,肉质鲜嫩,是著名的地方小吃。</p><div class="d-flex justify-content-between align-items-center"><span class="badge bg-info">小吃</span><div class="rating"><span class="text-warning">★★★★☆</span><small class="text-muted">(4.5)</small></div></div></div></div></div><div class="col-md-6 col-lg-4 mb-4" data-type="面食"><div class="card h-100"><img src="https://via.placeholder.com/300x200?text=猫耳朵" class="card-img-top" alt="猫耳朵"><div class="card-body"><h5 class="card-title">猫耳朵</h5><p class="card-text">形似猫耳的面食,口感Q弹,是山西特色面食之一。</p><div class="d-flex justify-content-between align-items-center"><span class="badge bg-primary">面食</span><div class="rating"><span class="text-warning">★★★★☆</span><small class="text-muted">(4.4)</small></div></div></div></div></div><div class="col-md-6 col-lg-4 mb-4" data-type="汤品"><div class="card h-100"><img src="https://via.placeholder.com/300x200?text=羊杂割" class="card-img-top" alt="羊杂割"><div class="card-body"><h5 class="card-title">羊杂割</h5><p class="card-text">山西传统汤品,营养丰富,味道鲜美,是冬日暖身佳品。</p><div class="d-flex justify-content-between align-items-center"><span class="badge bg-warning">汤品</span><div class="rating"><span class="text-warning">★★★★☆</span><small class="text-muted">(4.3)</small></div></div></div></div></div><div class="col-md-6 col-lg-4 mb-4" data-type="小吃"><div class="card h-100"><img src="https://via.placeholder.com/300x200?text=太原头脑" class="card-img-top" alt="太原头脑"><div class="card-body"><h5 class="card-title">太原头脑</h5><p class="card-text">太原特色小吃,由羊肉、藕根、山药等熬制而成,营养丰富。</p><div class="d-flex justify-content-between align-items-center"><span class="badge bg-info">小吃</span><div class="rating"><span class="text-warning">★★★★☆</span><small class="text-muted">(4.2)</small></div></div></div></div></div></div></div></div>`;mainContent.appendChild(foodSection);}// 显示美食推荐页面foodSection.style.display = 'block';// 添加筛选功能const typeFilter = document.getElementById('foodTypeFilter');const searchInput = document.getElementById('foodSearch');function filterFood() {const selectedType = typeFilter.value;const searchTerm = searchInput.value.toLowerCase();const foodItems = document.querySelectorAll('#foodList .col-md-6');foodItems.forEach(item => {const type = item.getAttribute('data-type');const title = item.querySelector('.card-title').textContent.toLowerCase();const description = item.querySelector('.card-text').textContent.toLowerCase();const typeMatch = !selectedType || type === selectedType;const searchMatch = !searchTerm || title.includes(searchTerm) || description.includes(searchTerm);if (typeMatch && searchMatch) {item.style.display = 'block';} else {item.style.display = 'none';}});}if (typeFilter && searchInput) {typeFilter.addEventListener('change', filterFood);searchInput.addEventListener('input', filterFood);}}// 强制覆盖所有重复的函数定义window.showFoodSection = function() {console.log('执行美食推荐功能...');// 隐藏所有其他区域document.querySelectorAll('.section').forEach(section => {section.style.display = 'none';});// 隐藏首页内容const homeSection = document.getElementById('home');if (homeSection) homeSection.style.display = 'none';// 创建美食推荐页面内容const mainContent = document.querySelector('.container-fluid');let foodSection = document.getElementById('food-section');if (!foodSection) {foodSection = document.createElement('div');foodSection.id = 'food-section';foodSection.className = 'section';foodSection.style.display = 'block';foodSection.innerHTML = `<div class="row"><div class="col-12"><h2 class="text-center mb-4" style="color: #d4a574;">🍜 山西特色美食推荐</h2><!-- 美食筛选 --><div class="row mb-4"><div class="col-md-6"><select class="form-select" id="foodTypeFilter"><option value="">全部美食</option><option value="面食">面食</option><option value="肉类">肉类</option><option value="小吃">小吃</option><option value="汤品">汤品</option></select></div><div class="col-md-6"><input type="text" class="form-control" id="foodSearch" placeholder="搜索美食..."></div></div><!-- 美食列表 --><div class="row" id="foodList"><div class="col-md-6 col-lg-4 mb-4" data-type="面食"><div class="card h-100 shadow-sm"><img src="https://via.placeholder.com/300x200/d4a574/ffffff?text=刀削面" class="card-img-top" alt="刀削面"><div class="card-body"><h5 class="card-title">刀削面</h5><p class="card-text">山西最著名的面食,面条粗细不均,口感筋道,配以各种浇头。</p><div class="d-flex justify-content-between align-items-center"><span class="badge bg-primary">面食</span><div class="rating"><span class="text-warning">★★★★★</span><small class="text-muted">(4.8)</small></div></div></div></div></div><div class="col-md-6 col-lg-4 mb-4" data-type="肉类"><div class="card h-100 shadow-sm"><img src="https://via.placeholder.com/300x200/d4a574/ffffff?text=过油肉" class="card-img-top" alt="过油肉"><div class="card-body"><h5 class="card-title">过油肉</h5><p class="card-text">山西传统名菜,肉片嫩滑,配菜丰富,口味鲜美。</p><div class="d-flex justify-content-between align-items-center"><span class="badge bg-success">肉类</span><div class="rating"><span class="text-warning">★★★★☆</span><small class="text-muted">(4.6)</small></div></div></div></div></div><div class="col-md-6 col-lg-4 mb-4" data-type="小吃"><div class="card h-100 shadow-sm"><img src="https://via.placeholder.com/300x200/d4a574/ffffff?text=平遥牛肉" class="card-img-top" alt="平遥牛肉"><div class="card-body"><h5 class="card-title">平遥牛肉</h5><p class="card-text">平遥古城特产,色泽红润,肉质鲜嫩,是著名的地方小吃。</p><div class="d-flex justify-content-between align-items-center"><span class="badge bg-info">小吃</span><div class="rating"><span class="text-warning">★★★★☆</span><small class="text-muted">(4.5)</small></div></div></div></div></div><div class="col-md-6 col-lg-4 mb-4" data-type="面食"><div class="card h-100 shadow-sm"><img src="https://via.placeholder.com/300x200/d4a574/ffffff?text=猫耳朵" class="card-img-top" alt="猫耳朵"><div class="card-body"><h5 class="card-title">猫耳朵</h5><p class="card-text">形似猫耳的面食,口感Q弹,是山西特色面食之一。</p><div class="d-flex justify-content-between align-items-center"><span class="badge bg-primary">面食</span><div class="rating"><span class="text-warning">★★★★☆</span><small class="text-muted">(4.4)</small></div></div></div></div></div><div class="col-md-6 col-lg-4 mb-4" data-type="汤品"><div class="card h-100 shadow-sm"><img src="https://via.placeholder.com/300x200/d4a574/ffffff?text=羊杂割" class="card-img-top" alt="羊杂割"><div class="card-body"><h5 class="card-title">羊杂割</h5><p class="card-text">山西传统汤品,营养丰富,味道鲜美,是冬日暖身佳品。</p><div class="d-flex justify-content-between align-items-center"><span class="badge bg-warning">汤品</span><div class="rating"><span class="text-warning">★★★★☆</span><small class="text-muted">(4.3)</small></div></div></div></div></div><div class="col-md-6 col-lg-4 mb-4" data-type="小吃"><div class="card h-100 shadow-sm"><img src="https://via.placeholder.com/300x200/d4a574/ffffff?text=太原头脑" class="card-img-top" alt="太原头脑"><div class="card-body"><h5 class="card-title">太原头脑</h5><p class="card-text">太原特色小吃,由羊肉、藕根、山药等熬制而成,营养丰富。</p><div class="d-flex justify-content-between align-items-center"><span class="badge bg-info">小吃</span><div class="rating"><span class="text-warning">★★★★☆</span><small class="text-muted">(4.2)</small></div></div></div></div></div></div></div></div>`;mainContent.appendChild(foodSection);// 添加筛选功能setTimeout(() => {const typeFilter = document.getElementById('foodTypeFilter');const searchInput = document.getElementById('foodSearch');function filterFood() {const selectedType = typeFilter ? typeFilter.value : '';const searchTerm = searchInput ? searchInput.value.toLowerCase() : '';const foodItems = document.querySelectorAll('#foodList .col-md-6');foodItems.forEach(item => {const type = item.getAttribute('data-type');const title = item.querySelector('.card-title').textContent.toLowerCase();const description = item.querySelector('.card-text').textContent.toLowerCase();const typeMatch = !selectedType || type === selectedType;const searchMatch = !searchTerm || title.includes(searchTerm) || description.includes(searchTerm);if (typeMatch && searchMatch) {item.style.display = 'block';} else {item.style.display = 'none';}});}if (typeFilter) typeFilter.addEventListener('change', filterFood);if (searchInput) searchInput.addEventListener('input', filterFood);}, 100);} else {foodSection.style.display = 'block';}console.log('✅ 美食推荐页面已显示');};// 页面加载完成后的初始化$(document).ready(function() {console.log('页面加载完成,初始化美食推荐功能...');// 重新绑定所有美食推荐相关的点击事件$('a[href="#food"], .nav-link[href="#food"], [onclick*="showSection(\'food\')"]').off('click').on('click', function(e) {e.preventDefault();console.log('点击美食推荐按钮');window.showFoodSection();});// 也绑定导航栏中的美食推荐链接$('.navbar-nav a').each(function() {if ($(this).text().includes('美食推荐')) {$(this).off('click').on('click', function(e) {e.preventDefault();console.log('点击导航栏美食推荐');window.showFoodSection();});}});console.log('✅ 美食推荐功能初始化完成');});</script>
</body>
</html>
http://www.dtcms.com/a/349625.html

相关文章:

  • Rust面试题及详细答案120道(58-65)-- 集合类型
  • 解锁处暑健康生活
  • Docker:部署Nginx
  • week4-[一维数组]数码个数
  • Gemini 2.5 Flash-Lite 与 GPT-5-mini:高性能低成本模型,如何选择?
  • 链表OJ习题(1)
  • redis-缓存-持久化
  • 使用 Gemini CLI作为 Claude Code的 subagent
  • OC-MVC模式下的折叠cell
  • 利用 Python 爬虫获取 1688 商品详情 API 返回值说明(代码示例)实战指南
  • 爬虫基础学习-爬取网页项目
  • vue2使用WaveSurfer实现简易的音频播放
  • 波音787项目:AR技术重塑航空制造的数字化转型
  • 用MessageBus优化模块通信:实现订阅/发布模式
  • nmcli命令详解
  • 文吃透朴素贝叶斯:从原理到实战
  • 【python文件处理】使用 open() 函数打开文件、 File 操作文件、使用 OS 对象操作文件目录的知识,使用 open() 函数打开文件
  • DMP-Net:面向脑组织术中成像的深度语义先验压缩光谱重建方法|文献速递-深度学习人工智能医疗图像
  • Android进入Activity时闪黑生命周期销毁并重建
  • 集成电路学习:什么是Caffe深度学习框架
  • 强化学习核心概念与算法详解-马尔可夫决策过程(MDP)+贝尔曼方程(Bellman Equation)
  • 合同管理软件的主要功能有什么?
  • 朴素贝叶斯学习笔记:从原理到实战(J享)
  • (LeetCode 每日一题) 498. 对角线遍历 (矩阵、模拟)
  • SSM从入门到实战:3.2 SpringMVC请求处理与控制器
  • 《C++哈希表:高效数据存储与检索的核心技术》
  • 朴素贝叶斯算法学习总结
  • MySQL 磁盘和 Redis 内存
  • 无人机航拍数据集|第22期 无人机城市交通目标检测YOLO数据集8624张yolov11/yolov8/yolov5可训练
  • Coze用户账号设置修改用户头像-前端源码