当用户提到以下关键词时自动触发:
使用 AskUserQuestion 工具收集以下信息:
如果用户已在消息中提供了部分信息,直接使用,只询问缺失项。
车辆类型决定后续所有模块的输出差异:
| 模块 | 纯电(BEV) | 插混(PHEV) | 增程(EREV) | 燃油(ICE) |
|---|---|---|---|---|
| ------ | ----------- | ----------- | ----------- | ---------- |
| 充电站搜索 | ✅ 必搜 | 可选 | ✅ 必搜 | ❌ |
| 续航检查 | ✅ 严格 | ❌ | ⚠️ 宽松 | ❌ |
| 充电时间块 | ✅ 必排 | ❌ | ✅ 建议排 | ❌ |
| 费用计算 | 电费为主 | 电+油 | 电费为主 | 油费 |
| 床车优势 | ✅ 展示 | ✅ 展示 | ✅ 展示 | ❌ |
| EV准备清单 | ✅ 展示 | ✅ 部分展示 | ✅ 展示 | ❌ |
| EV注意事项 | ✅ 展示 | ⚠️ 部分展示 | ✅ 展示 | ❌ |
在完成基本信息收集后,必须主动询问用户是否有想去的景点或餐厅:
> "有没有特别想去的景点或者想吃的餐厅?可以直接告诉我名字,我来帮你查信息、排进行程里。没有的话我就按热门推荐来安排。"
使用 AskUserQuestion 工具,提供以下选项:
用户提供的每个地点都需要经过以下步骤:
对用户提供的每个地点,使用 WebSearch 搜索详细信息:
搜索模板:
- 景点类:"{地点名} 门票 开放时间 地址"、"{地点名} 攻略 游玩时长"
- 餐厅类:"{地点名} 地址 人均 招牌菜 大众点评"、"{地点名} 怎么样 推荐"
- 通用坐标:"{地点名} 经纬度 GPS坐标"、"{地点名} 地址 地图"
- 🆕 充电相关:"{地点名} 充电桩 新能源 停车充电"(仅新能源车时搜索)
每个用户自提地点至少搜索2次,确保信息完整。
从搜索结果中提取并补全以下字段(缺失的标注为"待确认"):
| 字段 | 景点类 | 餐厅类 |
|---|---|---|
| ------ | -------- | -------- |
| 名称 | ✅ | ✅ |
| 类型 | scenic / food | food |
| 地址 | ✅ | ✅ |
| 经纬度 | ✅ 必须 | ✅ 必须 |
| 门票/人均 | 门票价格 | 人均消费 |
| 推荐时长 | 游玩时长 | 用餐时长 |
| 特色标签 | 打卡亮点 | 招牌菜 |
| 来源标注 | 👤 用户指定 | 👤 用户指定 |
| 🆕 是否有充电桩 | ✅ 搜索确认 | ✅ 搜索确认 |
用户自提的地点使用特殊来源标签,与搜索推荐区分:
| 来源类型 | 标注方式 | CSS class |
|---|---|---|
| --------- | --------- | ----------- |
| 用户指定-景点 | 👤 我想去 | source-user-spot |
| 用户指定-餐厅 | 👤 我想吃 | source-user-food |
| 用户指定-综合 | 👤 用户推荐 | source-user |
对应 CSS 样式:
.source-user-spot { background: #ede9fe; color: #7c3aed; }
.source-user-food { background: #fce7f3; color: #db2777; }
.source-user { background: #f0f9ff; color: #0369a1; }
用户提供的地点往往不够充实(比如只提了2个景点1家店),导致攻略空洞。智能补充推荐确保每份攻略内容丰满、实用,遵循"互补不重复"原则:不与用户自提地点重复,优先填补地理/类型/时段空白。
| 维度 | 每天最低 | 理想范围 | 说明 |
|---|---|---|---|
| ------ | --------- | --------- | ------ |
| 景点/活动 | 3个 | 4-5个 | 含用户自提+补充 |
| 餐厅 | 2家 | 3-4家 | 至少午餐+晚餐各1家 |
| 露营地 | 1个 | 2个(含备选) | 过夜时必须有 |
| 小众隐藏点 | 1个 | 2-3个 | 增加惊喜感 |
| 拍照打卡点 | 2个 | 3-4个 | 含机位/时段建议 |
| 特色体验 | 1项 | 2-3项 | 非景点类(看日出/夜市/海边散步等) |
用户自提地点集中在某个区域时,补充其他区域的代表景点。
用户只提景点没提餐厅,或只提餐厅没提景点时,补全缺失类型。
行程中有大段空闲时间(>3小时无安排),补充轻量级活动填充。
补充适合特定时段的活动,让行程从早到晚都有安排。
补充用户可能不知道的特色体验,增加攻略独特性。
智能补充流程(在用户自提地点信息搜索完成后执行):
Step A: 密度评估
For each day:
1. 统计用户自提的景点数(N_spot)、餐厅数(N_food)、体验数(N_exp)
2. 对照密度最低标准,标记缺失项
3. 汇总所有缺失项为"补充任务清单"
Step B: 区域分析
1. 将用户自提地点在地图上标注,识别覆盖了哪些区域
2. 标记"空白区域"——用户完全未涉及的区域
3. 标记"薄弱区域"——用户只涉及1个地点的区域
Step C: 补充搜索
For each 补充任务:
1. 按策略优先级搜索:地理补缺 > 类型补全 > 时段填充 > 节奏优化 > 体验升级
2. 每个缺失项至少搜索2次,交叉验证
3. 补充地点同样需要获取经纬度坐标
Step D: 补充筛选
1. 去重:排除与用户自提地点重复的推荐
2. 质量过滤:优先选择多源验证的推荐(如同时出现在小红书+大众点评)
3. 距离优先:补充地点优先选在用户已有地点附近(减少路程)
4. 数量控制:每个缺失项补充1-2个,不超过3个(避免推荐过载)
5. 标记来源为 🔵 智能推荐
补充推荐地点与用户自提地点走相同的搜索+信息补全流程,但有以下差异:
| 字段 | 用户自提 | 智能补充 |
|---|---|---|
| ------ | --------- | --------- |
| must | true(不可删除) | false(可被路线优化裁剪) |
| source | 👤 | 🔵 |
| 地图图标 | 紫色/粉色特殊标记 | 默认蓝/红色标记 |
| 角标 | "必"字角标 | 无角标 |
| 展示位置 | 列在前面 | 列在用户自提之后 |
| CSS class | user-spot / user-food | ai-spot / ai-food |
| 来源类型 | 标注方式 | CSS class | 说明 |
|---|---|---|---|
| --------- | --------- | ----------- | ------ |
| 智能推荐-景点 | 🔵 智能推荐 | source-ai-spot | 系统根据区域/类型补充 |
| 智能推荐-美食 | 🟤 智能推荐 | source-ai-food | 系统根据区域/类型补充 |
| 智能推荐-体验 | 🟢 智能推荐 | source-ai-exp | 系统补充的特色体验 |
对应 CSS 样式:
.source-ai-spot { background: #dbeafe; color: #2563eb; }
.source-ai-food { background: #fef3c7; color: #b45309; }
.source-ai-exp { background: #d1fae5; color: #047857; }
<!-- 美食攻略区域示例 -->
<div class="card">
<h2>🍜 美食攻略</h2>
<!-- 第一部分:用户指定餐厅(特殊卡片,优先展示) -->
<h3>👤 我想吃的</h3>
<div class="user-food">...</div>
<!-- 第二部分:智能补充推荐 -->
<h3>🔵 附近还有这些好吃的</h3>
<div class="ai-food">
<h4>军民海鲜楼 <span class="source-tag source-ai-food">🟤 智能推荐</span> <span class="source-tag source-dzdp">🟠 大众点评必吃榜</span></h4>
<p>📍 连云区墟沟海鲜美食城 | 💰 人均120元</p>
<p>📝 招牌:蒜蓉粉丝蒸扇贝、清蒸石斑鱼</p>
</div>
...
</div>
必须使用 WebSearch 工具联网搜索以下信息,确保攻略时效性和准确性:
1. 路线信息:"南京到{目的城市}自驾路线 高速费用 公里数"
2. 美食推荐(多源交叉验证):
- 小红书:"{目的城市}美食攻略 小红书 必吃 2025"、"{目的城市}美食 猴儿甜 乌啦啦 小红书推荐"
- 大众点评:"{目的城市}大众点评 必吃榜 高分餐厅 2025"、"{目的城市}美食 大众点评必吃榜"
- 抖音博主:"{目的城市}美食 抖音博主推荐 2025"、"{目的城市}美食探店 抖音"
3. 露营地:"{目的城市}床车露营地 停车场过夜 24小时卫生间"、"{目的城市}房车营地 露营地推荐"
4. 景点打卡:"{目的城市}拍照打卡点 网红景点 门票价格"、"{目的城市}小众景点 隐藏打卡点"
5. 沿途景点:"南京到{目的城市}沿途景点 经过哪些城市"
6. 地理坐标(关键!):
- "{目的城市}主要景点 经纬度 坐标"
- "{景点名} 地址 经度 纬度"
- 通过 WebSearch 搜索每个打卡点和露营地的经纬度坐标
7. 用户自提地点:按上文"用户自提地点的处理流程"执行
8. 🆕 充电站规划(仅新能源车):
- "{目的城市} 充电站 新能源 充电桩分布"
- "南京到{目的城市} 高速充电站 服务区"
- "{目的城市} 超充站 直流快充 800V"
- "{露营地名称} 充电桩 新能源"
- "{景区名称} 停车场 充电桩"
- "{商场名称} 充电桩 停车充电"(嘉瑞宝等商场是否有充电桩)
9. 🆕 智能补充推荐(按需搜索,仅在密度不足时):
- 景点补充:"{目的城市}{缺失区域}景点推荐 2025"、"{目的城市}必去景点 本地人推荐"
- 美食补充:"{目的城市}{缺失区域}美食推荐 2025"、"{目的城市}必吃餐厅 本地人去"
- 隐藏打卡:"{目的城市}小众景点 隐藏打卡 2025"、"{目的城市}拍照好看的地方 本地人私藏"
- 特色体验:"{目的城市}特色体验 活动 2025"、"{目的城市}海边/夜市/看日出 体验"
- 餐饮补全:"{用户景点名}附近美食推荐"、"{用户景点名}周边餐厅 大众点评"
- 时段填充:"{目的城市}看日出 最佳地点"、"{目的城市}夜市 夜景 2025"
- 节奏补充:"{目的城市}老街 步行街 逛街"、"{目的城市}咖啡店 打卡推荐"
每个类别至少搜索2-3次,使用 WebFetch 获取搜索结果页面的详细内容。
每个打卡点、露营地、推荐餐厅、用户自提地点、🆕充电站都必须获取经纬度坐标,方法:
纬度,经度 格式(如连岛:34.7586,119.4665)充电站搜索结果需提取以下字段:
| 字段 | 说明 | 示例 |
|---|---|---|
| ------ | ------ | ------ |
| 名称 | 充电站名称 | 国家电网XX服务区充电站 |
| 类型 | 快充/慢充/超充 | 直流快充 |
| 桩数 | 充电桩数量 | 4桩 |
| 功率 | 单桩最大功率 | 120kW / 480kW(超充) |
| 费用 | 充电单价+服务费 | 1.2元/度+0.8元/度服务费 |
| 营业时间 | 是否24小时 | 24小时 / 08:00-22:00 |
| 经纬度 | 地图标注坐标 | 34.75, 119.47 |
| 运营商 | e充电/特来电/星星等 | 国家电网 |
美食推荐必须标注信息来源,增强可信度:
| 来源类型 | 标注方式 | 搜索方式 |
|---|---|---|
| --------- | --------- | --------- |
| 小红书博主推荐 | 🔴 小红书@博主名 推荐 | 搜索"XX 小红书 美食 博主推荐" |
| 大众点评必吃榜 | 🟠 大众点评必吃榜 | 搜索"XX 大众点评必吃榜" |
| 大众点评高分 | 🟡 大众点评4.5+分 | 搜索"XX 大众点评 高分餐厅" |
| 抖音探店博主 | 🎵 抖音@博主名 推荐 | 搜索"XX 抖音 美食探店" |
| B站UP主 | 📺 B站@UP主 推荐 | 搜索"XX B站 美食 UP主" |
| 本地人推荐 | 👨🌾 本地人口碑 | 搜索"XX 本地人 吃什么" |
| 用户指定 | 👤 我想去 / 👤 我想吃 | 用户直接提供 |
| 🆕 智能推荐 | 🔵 智能推荐 | 系统根据密度检查自动补充 |
每家餐厅至少标注一个来源,多个来源更佳。
路线规划必须遵循以下原则,避免走回头路:
将所有地点(搜索推荐 + 用户自提 + 🆕充电站)汇总为一个地点池:
地点池 = [
{ name: "连岛大沙湾", type: "scenic", lat: 34.768, lng: 119.448, duration: 2, must: false, hasCharger: true, source: "search" },
{ name: "花果山", type: "scenic", lat: 34.628, lng: 119.278, duration: 4, must: false, hasCharger: false, source: "search" },
{ name: "军民海鲜楼", type: "food", lat: 34.751, lng: 119.366, duration: 1, must: false, hasCharger: false, source: "ai" },
{ name: "用户自提景点", type: "scenic", lat: xx, lng: xx, duration: xx, must: true, hasCharger: xx, source: "user" },
{ name: "🆕 嘉瑞宝充电站", type: "charge", lat: xx, lng: xx, duration: 0.75, power: "120kW", plugs: 4, source: "search" },
...
]
]
must: true 表示用户指定地点,不可删除。source 标记来源:user(用户自提) / ai(智能补充) / search(常规搜索)。🆕 hasCharger 标记是否有充电桩。
🆕 裁剪优先级:当时间超载需要裁剪时,按以下顺序裁剪:
source: "ai", must: false)— 最先裁剪source: "search", must: false)source: "user", must: true)— 不可裁剪根据地点的经纬度,将地点划分为区域。划分方法:
方法A - 按行政区划(优先):
方法B - 按距离聚类(兜底):
区域命名示例:
将区域分配到每天,遵循以下规则:
分配逻辑(伪代码):
For each day:
1. 选择一个区域(尚未安排的区域中离前一天结束点最近的)
2. 将该区域的所有景点按地理位置从起点方向往远端排列
3. 在景点之间自然嵌入用餐时间:
- 11:30-13:00: 选离11点所在景点最近的餐厅
- 17:30-19:00: 选离最后一个景点最近的餐厅
4. 安排露营地在当天最后活动区域附近
5. 检查时间是否超载,超载则将部分低优先级景点移至备选
6. 🆕 内容密度检查:
a. 统计当日景点数 ≥ 3?餐厅数 ≥ 2?有小众点?有特色体验?
b. 不满足 → 触发"智能补充推荐"搜索(见"智能补充推荐机制")
c. 补充后的新地点重新纳入路线排序
d. 再次检查时间是否超载,超载则裁剪 🔵智能补充 > 常规推荐 > ❌用户自提
对纯电动车和增程式车辆,每日行程需通过续航检查:
Step 3.5: 续航里程检查
For each day:
1. 计算当日总行驶里程(出发点 → 各景点 → 露营地/返程)
2. 如果当日里程 > 续航的70%(留30%余量):
a. 在路线中插入充电站作为停留点
b. 充电站优先级:
① 景区/商场停车场充电桩(充电+游玩重叠,不浪费时间)
② 目的地城市快充站(用餐时间充电)
③ 高速服务区充电桩(长途中途补电)
c. 充电时间块:快充约30-60分钟,超充约15-30分钟,慢充2-4小时
3. 如果单段里程 > 续航的50%:
a. 在该段中途插入高速服务区充电站
b. 搜索 "南京到{目的城市} 途充电站 服务区"
4. 远程路线续航评估示例(南京→连云港 约330km):
a. 纯电400km续航:中途服务区补电1次(约30min快充),充至80%
b. 纯电500-600km续航:可直达,到达后当天补电
c. 纯电700km+续航:直达无压力
d. 插混/增程:无需中途充电,到达后充电即可
5. 冬季续航打折:
- 实际续航 = 标称续航 × 0.65(冬季低温+制热)
- 重新计算所有里程约束
同一天内的地点,按以下规则排序:
这确保了路线呈单向扇形展开,不会折返。
生成路线后进行以下检查:
路线规划区域应展示以下内容:
| 天数 | 游玩区域 | 主要景点 | 餐饮安排 | 露营地 | 行车里程 | 🆕 充电安排 |
|------|---------|---------|---------|--------|---------|------------|
| Day1 | 连云区·海滨 | 连岛→老街 | 午:墟沟海鲜 晚:盐河巷 | 连岛停车场 | 约35km | 景区慢充 |
| Day2 | 云台山+海州区 | 花果山→兄弟酒家 | 午:兄弟酒家 | - | 约25km | 出发前补满 |
攻略必须以 精美 HTML 页面 的形式输出,保存为 {目的城市}自驾攻略.html,然后使用 preview_url 工具预览展示。
HTML 页面必须包含以下部分,按顺序展示:
必须使用 Leaflet.js(开源免费,无需API Key):
<!-- 在 <head> 中引入 -->
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" />
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
```javascript
L.tileLayer('https://webrd0{s}.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=8&x={x}&y={y}&z={z}', {
subdomains: ['1', '2', '3', '4'],
maxZoom: 18,
attribution: '© 高德地图'
})
```
备选底图(OpenStreetMap):
```javascript
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: 18
})
```
使用不同颜色的 Marker 区分地点类型:
| 地点类型 | 标记颜色 | 图标 | 变量命名 | 用户自提样式 |
|---|---|---|---|---|
| --------- | --------- | ------ | --------- | ------------ |
| 景点打卡点 | 🔵 蓝色 | 🏔️ | spotMarkers | 紫色外环 + "必" 字角标 |
| 美食餐厅 | 🔴 红色 | 🍜 | foodMarkers | 粉色外环 + "必" 字角标 |
| 露营地 | 🟢 绿色 | 🏕️ | campMarkers | 同默认 |
| 沿途休息点 | 🟡 黄色 | ⛽ | restMarkers | 同默认 |
| 🆕 充电站 | 🟠 橙色 | ⚡ | chargeMarkers | 同默认 |
| 用户指定景点 | 🟣 紫色 | ⭐ | userSpotMarkers | 带发光环 |
| 用户指定餐厅 | 🩷 粉色 | 🍴 | userFoodMarkers | 带发光环 |
使用 Leaflet 的 L.divIcon 创建自定义图标:
// 景点图标(蓝色)
const spotIcon = L.divIcon({
className: 'custom-marker',
html: '<div style="background:#3b82f6;color:white;width:32px;height:32px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:16px;box-shadow:0 2px 6px rgba(0,0,0,0.3);">🏔️</div>',
iconSize: [32, 32],
iconAnchor: [16, 16],
popupAnchor: [0, -18]
});
// 🆕 充电站图标(橙色)
const chargeIcon = L.divIcon({
className: 'custom-marker',
html: '<div style="background:#f97316;color:white;width:32px;height:32px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:16px;box-shadow:0 2px 6px rgba(0,0,0,0.3);">⚡</div>',
iconSize: [32, 32],
iconAnchor: [16, 16],
popupAnchor: [0, -18]
});
// 用户指定景点图标(紫色+角标)
const userSpotIcon = L.divIcon({
className: 'custom-marker',
html: `<div style="position:relative;">
<div style="background:#7c3aed;color:white;width:32px;height:32px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:16px;box-shadow:0 0 0 3px #c4b5fd,0 2px 8px rgba(124,58,237,0.4);">⭐</div>
<div style="position:absolute;top:-4px;right:-4px;background:#ef4444;color:white;font-size:9px;width:14px;height:14px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-weight:bold;">必</div>
</div>`,
iconSize: [36, 36],
iconAnchor: [18, 18],
popupAnchor: [0, -20]
});
// 用户指定餐厅图标(粉色+角标)
const userFoodIcon = L.divIcon({
className: 'custom-marker',
html: `<div style="position:relative;">
<div style="background:#db2777;color:white;width:32px;height:32px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:16px;box-shadow:0 0 0 3px #f9a8d4,0 2px 8px rgba(219,39,119,0.4);">🍴</div>
<div style="position:absolute;top:-4px;right:-4px;background:#ef4444;color:white;font-size:9px;width:14px;height:14px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-weight:bold;">必</div>
</div>`,
iconSize: [36, 36],
iconAnchor: [18, 18],
popupAnchor: [0, -20]
});
为同一天的地点绘制区域范围圈,帮助用户直观理解路线聚合:
// Day1 区域圈(连云区海滨)
const day1Circle = L.circle([34.76, 119.44], {
radius: 3000, // 3km半径
color: '#3b82f6',
fillColor: '#3b82f6',
fillOpacity: 0.08,
weight: 1,
dashArray: '5, 5'
}).addTo(map);
day1Circle.bindPopup('📅 Day1 区域:连云区·海滨');
点击标记弹出信息卡片,包含:
L.marker([纬度, 经度], {icon: spotIcon})
.addTo(map)
.bindPopup(`
<div style="min-width:200px;">
<h4 style="margin:0 0 6px;font-size:15px;">🏔️ 景点名称</h4>
<p style="margin:0 0 4px;font-size:13px;color:#666;">📍 地址信息</p>
<p style="margin:0 0 4px;font-size:13px;color:#e67e22;">🎫 门票:XX元</p>
<p style="margin:0 0 4px;font-size:13px;">📝 简要介绍</p>
<p style="margin:0;font-size:12px;color:#999;">⏰ 最佳时间:XX</p>
</div>
`);
// 🆕 充电站 Popup
L.marker([纬度, 经度], {icon: chargeIcon})
.addTo(map)
.bindPopup(`
<div style="min-width:220px;">
<h4 style="margin:0 0 6px;font-size:15px;">⚡ 充电站名称</h4>
<p style="margin:0 0 4px;font-size:13px;color:#666;">📍 地址信息</p>
<p style="margin:0 0 4px;font-size:13px;color:#f97316;">🔌 类型:直流快充 / 慢充 / 超充</p>
<p style="margin:0 0 4px;font-size:13px;">⚡ 桩数:X桩 | 功率:XXXkW</p>
<p style="margin:0 0 4px;font-size:13px;">💰 费用:X.X元/度 + 服务费X.X元/度</p>
<p style="margin:0;font-size:12px;color:#999;">🕐 营业:24小时 / 08:00-22:00</p>
</div>
`);
// 用户自提地点 Popup(带"用户指定"标签)
L.marker([纬度, 经度], {icon: userSpotIcon})
.addTo(map)
.bindPopup(`
<div style="min-width:200px;">
<h4 style="margin:0 0 6px;font-size:15px;">⭐ 景点名称 <span style="font-size:11px;background:#ede9fe;color:#7c3aed;padding:2px 6px;border-radius:8px;">👤 我想去</span></h4>
<p style="margin:0 0 4px;font-size:13px;color:#666;">📍 地址信息</p>
<p style="margin:0 0 4px;font-size:13px;color:#e67e22;">🎫 门票:XX元</p>
<p style="margin:0 0 4px;font-size:13px;">📝 简要介绍</p>
<p style="margin:0;font-size:12px;color:#999;">⏰ 最佳时间:XX</p>
</div>
`);
地图右下角添加图例,说明各标记含义:
const legend = L.control({position: 'bottomright'});
legend.onAdd = function(map) {
const div = L.DomUtil.create('div', 'map-legend');
div.innerHTML = `
<div style="background:white;padding:10px;border-radius:8px;box-shadow:0 2px 8px rgba(0,0,0,0.15);font-size:13px;">
<h4 style="margin:0 0 8px;">📍 图例</h4>
<p>🏔️ 景点打卡点</p>
<p>🍜 美食餐厅</p>
<p>🏕️ 露营地</p>
<p>⛽ 沿途休息点</p>
<p>⚡ 充电站</p>
<p style="border-top:1px dashed #ddd;margin-top:6px;padding-top:6px;">⭐ 用户指定景点</p>
<p>🍴 用户指定餐厅</p>
</div>
`;
return div;
};
legend.addTo(map);
用折线连接同一天的行程点,不同天用不同颜色:
// Day 1 路线(蓝色虚线)
const day1Points = [
[出发点纬度, 出发点经度],
[景点1纬度, 景点1经度],
[景点2纬度, 景点2经度],
[露营点纬度, 露营点经度]
];
L.polyline(day1Points, {color: '#3b82f6', weight: 3, dashArray: '10, 6', opacity: 0.7})
.addTo(map)
.bindPopup('Day 1 行车路线');
-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serifbox-shadow: 0 2px 12px rgba(0,0,0,0.08)用户指定的景点/餐厅在攻略中有特殊视觉标识:
/* 用户指定来源标签 */
.source-user-spot { background: #ede9fe; color: #7c3aed; }
.source-user-food { background: #fce7f3; color: #db2777; }
.source-user { background: #f0f9ff; color: #0369a1; }
/* 用户指定景点卡片 - 紫色左边框 */
.user-spot { border-left: 4px solid #7c3aed; padding: 12px 16px; margin-bottom: 12px; background: #faf5ff; border-radius: 0 8px 8px 0; }
.user-spot h4::after { content: ' ⭐必去'; font-size: 12px; color: #7c3aed; font-weight: normal; }
/* 用户指定餐厅卡片 - 粉色左边框 */
.user-food { border-left: 4px solid #db2777; padding: 12px 16px; margin-bottom: 12px; background: #fdf2f8; border-radius: 0 8px 8px 0; }
.user-food h4::after { content: ' 🍴必吃'; font-size: 12px; color: #db2777; font-weight: normal; }
/* 路线合理性说明 */
.route-note { background: #f0fdf4; border: 1px solid #bbf7d0; border-radius: 8px; padding: 12px 16px; margin-top: 12px; font-size: 14px; color: #166534; }
.route-note .note-icon { margin-right: 6px; }
/* 新能源床车优势区域 */
.ev-camp-advantage { background: linear-gradient(135deg, #ecfdf5, #f0fdf4); border: 2px solid #86efac; border-radius: 10px; padding: 16px; margin-bottom: 12px; }
.ev-camp-advantage h4 { color: #166534; margin-bottom: 8px; font-size: 16px; }
.ev-camp-advantage li { font-size: 14px; color: #334155; margin: 6px 0; line-height: 1.6; }
/* 行程时间表 */
.timeline-item.charge::before { background: #f97316; box-shadow: 0 0 0 2px #fdba74; }
/* 充电站卡片 */
.charge-card { border-left: 4px solid #f97316; padding: 12px 16px; margin-bottom: 12px; background: #fff7ed; border-radius: 0 8px 8px 0; }
.charge-card h4 { font-size: 16px; margin-bottom: 6px; }
.charge-card p { font-size: 13px; color: #555; margin: 3px 0; }
/* 续航提醒 */
.range-warning { background: #fff7ed; border: 1px solid #fed7aa; border-radius: 8px; padding: 12px 16px; margin-top: 12px; font-size: 14px; color: #9a3412; }
路线规划卡片中应包含以下内容:
<!-- 区域聚合说明 -->
<div class="route-note">
<span class="note-icon">📍</span> 路线设计说明:所有打卡点按<strong>区域聚合</strong>排列,同区域景点安排在同一天,避免来回折返。<br>
🆕 <span class="note-icon">🔋</span> 续航规划:纯电500km续航,全程330km可直达,到达后当日补电即可。
</div>
<!-- 续航提醒(如需要) -->
<div class="range-warning">
⚠️ 续航提醒:当日里程约350km,超过续航70%(350km),建议中途服务区补电30分钟。
</div>
<!-- 每日区域概览 -->
<div class="route-box">
<h4>📅 Day 1 · 连云区·海滨区域</h4>
<p>🏖️ 连岛 → 🏘️ 老街 → 🦀 墟沟海鲜 → ⚡ 嘉瑞宝充电 → 🏮 盐河巷</p>
<p style="font-size:13px;color:#666;">一路向南不走回头路,全程约35km | 🆕 嘉瑞宝补电45min</p>
</div>
新能源车(纯电/增程)费用表格模板:
<div class="card">
<h2>💰 费用预估(2人 · 🔋纯电)</h2>
<table>
<thead><tr><th>项目</th><th>明细</th><th>费用</th></tr></thead>
<tbody>
<tr><td>🚗 高速费(往返)</td><td>G25+G15 约330km×2</td><td>约320元</td></tr>
<tr><td>⚡ 电费(家充出发)</td><td>出发前家充约15度 × 0.55元</td><td>约8元</td></tr>
<tr><td>⚡ 电费(公共快充)</td><td>目的地补电约40度 × 1.5元</td><td>约60元</td></tr>
<tr><td>⚡ 电费(高速快充)</td><td>中途补电约20度 × 1.8元</td><td>约36元</td></tr>
<tr><td>🎫 景点门票</td><td>XX元/人 × 2</td><td>约XX元</td></tr>
<!-- 餐饮、停车等同前 -->
</tbody>
</table>
<div style="margin-top:16px;padding:16px;background:#ecfdf5;border-radius:10px;text-align:center;">
<p style="font-size:14px;color:#666;margin-bottom:4px;">2人预估总费用</p>
<p class="cost-total">约 1,000 - 1,300 元</p>
<p style="font-size:13px;color:#166534;">🔋 比油车节省约 300-500 元油费!</p>
</div>
</div>
燃油车费用表格模板(保持原有逻辑不变):
<div class="card">
<h2>💰 费用预估(2人 · ⛽燃油)</h2>
<table>
<thead><tr><th>项目</th><th>明细</th><th>费用</th></tr></thead>
<tbody>
<tr><td>🚗 高速费(往返)</td><td>G25+G15 约330km×2</td><td>约320元</td></tr>
<tr><td>⛽ 油费(往返)</td><td>约660km × 0.6元/km</td><td>约400元</td></tr>
<!-- 其余同前 -->
</tbody>
</table>
</div>
| 充电场景 | 单价参考 | 说明 |
|---|---|---|
| --------- | --------- | ------ |
| 家用充电桩 | 0.55元/度 | 谷电约0.35元/度 |
| 公共慢充 | 0.8-1.2元/度 | 含服务费 |
| 公共快充 | 1.2-1.8元/度 | 含服务费 |
| 高速服务区快充 | 1.5-2.0元/度 | 高峰可能更贵 |
| 超充站(800V) | 1.5-2.5元/度 | 速度最快 |
百公里耗电参考:纯电轿车12-15度/100km,纯电SUV 16-20度/100km
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{目的城市} 自驾床车旅行攻略</title>
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" />
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
<style>
/* 全局样式 */
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; background: #f0f4f8; color: #1a1a2e; line-height: 1.6; }
.container { max-width: 960px; margin: 0 auto; padding: 16px; }
/* 头图区 */
.hero { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; padding: 40px 24px; border-radius: 16px; margin-bottom: 20px; text-align: center; }
.hero h1 { font-size: 28px; margin-bottom: 8px; }
.hero .meta { font-size: 15px; opacity: 0.9; }
/* 地图区 */
.map-section { background: white; border-radius: 12px; padding: 20px; margin-bottom: 20px; box-shadow: 0 2px 12px rgba(0,0,0,0.08); }
.map-section h2 { font-size: 20px; margin-bottom: 12px; }
#map { width: 100%; height: 500px; border-radius: 10px; z-index: 1; }
.map-legend p { margin: 4px 0; }
/* 通用卡片 */
.card { background: white; border-radius: 12px; padding: 20px; margin-bottom: 20px; box-shadow: 0 2px 12px rgba(0,0,0,0.08); }
.card h2 { font-size: 20px; margin-bottom: 16px; padding-bottom: 8px; border-bottom: 2px solid #eef2ff; }
/* 表格 */
table { width: 100%; border-collapse: collapse; font-size: 14px; }
th { background: #f8fafc; padding: 10px 12px; text-align: left; font-weight: 600; border-bottom: 2px solid #e2e8f0; }
td { padding: 10px 12px; border-bottom: 1px solid #f1f5f9; }
/* 美食来源标签 */
.source-tag { display: inline-block; font-size: 11px; padding: 2px 8px; border-radius: 10px; margin-right: 4px; font-weight: 500; }
.source-xhs { background: #fff0f0; color: #e63946; }
.source-dzdp { background: #fff3e0; color: #e67e22; }
.source-douyin { background: #f3e5f5; color: #9c27b0; }
.source-bilibili { background: #e3f2fd; color: #2196f3; }
.source-local { background: #e8f5e9; color: #43a047; }
.source-user-spot { background: #ede9fe; color: #7c3aed; }
.source-user-food { background: #fce7f3; color: #db2777; }
.source-user { background: #f0f9ff; color: #0369a1; }
.source-ai-spot { background: #dbeafe; color: #2563eb; }
.source-ai-food { background: #fef3c7; color: #b45309; }
.source-ai-exp { background: #d1fae5; color: #047857; }
/* 餐厅卡片 */
.restaurant { border-left: 4px solid #e63946; padding: 12px 16px; margin-bottom: 12px; background: #fefefe; border-radius: 0 8px 8px 0; }
.restaurant h4 { font-size: 16px; margin-bottom: 6px; }
.restaurant p { font-size: 13px; color: #555; margin: 3px 0; }
/* 用户指定卡片 */
.user-spot { border-left: 4px solid #7c3aed; padding: 12px 16px; margin-bottom: 12px; background: #faf5ff; border-radius: 0 8px 8px 0; }
.user-spot h4 { font-size: 16px; margin-bottom: 6px; }
.user-spot h4::after { content: ' ⭐必去'; font-size: 12px; color: #7c3aed; font-weight: normal; }
.user-spot p { font-size: 13px; color: #555; margin: 3px 0; }
.user-food { border-left: 4px solid #db2777; padding: 12px 16px; margin-bottom: 12px; background: #fdf2f8; border-radius: 0 8px 8px 0; }
.user-food h4 { font-size: 16px; margin-bottom: 6px; }
.user-food h4::after { content: ' 🍴必吃'; font-size: 12px; color: #db2777; font-weight: normal; }
.user-food p { font-size: 13px; color: #555; margin: 3px 0; }
/* 🆕 智能补充推荐卡片 */
.ai-spot { border-left: 4px solid #3b82f6; padding: 12px 16px; margin-bottom: 12px; background: #eff6ff; border-radius: 0 8px 8px 0; }
.ai-spot h4 { font-size: 16px; margin-bottom: 6px; }
.ai-spot p { font-size: 13px; color: #555; margin: 3px 0; }
.ai-food { border-left: 4px solid #f59e0b; padding: 12px 16px; margin-bottom: 12px; background: #fffbeb; border-radius: 0 8px 8px 0; }
.ai-food h4 { font-size: 16px; margin-bottom: 6px; }
.ai-food p { font-size: 13px; color: #555; margin: 3px 0; }
.ai-exp { border-left: 4px solid #10b981; padding: 12px 16px; margin-bottom: 12px; background: #ecfdf5; border-radius: 0 8px 8px 0; }
.ai-exp h4 { font-size: 16px; margin-bottom: 6px; }
.ai-exp p { font-size: 13px; color: #555; margin: 3px 0; }
/* 补充推荐分区标题 */
.supplement-title { font-size: 16px; font-weight: 600; color: #6b7280; margin: 16px 0 10px; padding: 6px 12px; background: #f3f4f6; border-radius: 6px; display: inline-block; }
.supplement-title::before { margin-right: 6px; }
/* 露营地卡片 */
.campsite { border-left: 4px solid #43a047; padding: 12px 16px; margin-bottom: 12px; background: #fefefe; border-radius: 0 8px 8px 0; }
.campsite h4 { font-size: 16px; margin-bottom: 6px; }
/* 🆕 新能源床车优势区域 */
.ev-camp-advantage { background: linear-gradient(135deg, #ecfdf5, #f0fdf4); border: 2px solid #86efac; border-radius: 10px; padding: 16px; margin-bottom: 12px; }
.ev-camp-advantage h4 { color: #166534; margin-bottom: 8px; font-size: 16px; }
.ev-camp-advantage li { font-size: 14px; color: #334155; margin: 6px 0; line-height: 1.6; }
/* 🆕 充电站卡片 */
.charge-card { border-left: 4px solid #f97316; padding: 12px 16px; margin-bottom: 12px; background: #fff7ed; border-radius: 0 8px 8px 0; }
.charge-card h4 { font-size: 16px; margin-bottom: 6px; }
.charge-card p { font-size: 13px; color: #555; margin: 3px 0; }
/* 行程时间表 */
.timeline { position: relative; padding-left: 24px; }
.timeline::before { content: ''; position: absolute; left: 8px; top: 0; bottom: 0; width: 2px; background: #ddd; }
.timeline-item { position: relative; margin-bottom: 16px; padding: 10px 16px; background: #f8fafc; border-radius: 8px; }
.timeline-item::before { content: ''; position: absolute; left: -20px; top: 14px; width: 12px; height: 12px; border-radius: 50%; background: #667eea; border: 2px solid white; }
.timeline-item.food::before { background: #e63946; }
.timeline-item.scenic::before { background: #3b82f6; }
.timeline-item.camp::before { background: #43a047; }
.timeline-item.user-spot::before { background: #7c3aed; }
.timeline-item.user-food::before { background: #db2777; }
.timeline-item.charge::before { background: #f97316; box-shadow: 0 0 0 2px #fdba74; }
.timeline-item.drive::before { background: #f59e0b; }
.timeline-time { font-weight: 700; color: #667eea; font-size: 14px; }
.timeline-title { font-weight: 600; font-size: 15px; }
.timeline-detail { font-size: 13px; color: #666; }
.timeline-tip { font-size: 12px; color: #f59e0b; margin-top: 2px; }
/* 路线说明 */
.route-note { background: #f0fdf4; border: 1px solid #bbf7d0; border-radius: 8px; padding: 12px 16px; margin-top: 12px; font-size: 14px; color: #166534; }
.route-box { background: #f0f9ff; border: 2px solid #bae6fd; border-radius: 10px; padding: 16px; margin-bottom: 12px; }
.route-box h4 { color: #0369a1; margin-bottom: 8px; }
/* 🆕 续航提醒 */
.range-warning { background: #fff7ed; border: 1px solid #fed7aa; border-radius: 8px; padding: 12px 16px; margin-top: 12px; font-size: 14px; color: #9a3412; }
/* 准备清单 */
.checklist { columns: 2; column-gap: 20px; }
.checklist label { display: block; font-size: 14px; padding: 4px 0; break-inside: avoid; }
.checklist input[type="checkbox"] { margin-right: 6px; }
/* 费用表格 */
.cost-total { font-size: 22px; font-weight: 700; color: #e63946; }
/* 注意事项 */
.warning { background: #fff8e1; border-left: 4px solid #ffc107; padding: 12px 16px; margin-bottom: 8px; border-radius: 0 8px 8px 0; font-size: 14px; }
.danger { background: #fef2f2; border-left: 4px solid #ef4444; padding: 12px 16px; margin-bottom: 8px; border-radius: 0 8px 8px 0; font-size: 14px; }
.info-tip { background: #eff6ff; border-left: 4px solid #3b82f6; padding: 12px 16px; margin-bottom: 8px; border-radius: 0 8px 8px 0; font-size: 14px; }
/* 季节提醒 */
.season-tip { background: linear-gradient(135deg, #e8f5e9, #f1f8e9); padding: 16px; border-radius: 10px; margin-top: 12px; }
/* 响应式 */
@media (max-width: 640px) {
.hero h1 { font-size: 22px; }
.checklist { columns: 1; }
#map { height: 350px; }
}
</style>
</head>
<body>
<div class="container">
<!-- 头图区 -->
<div class="hero">
<h1>🚗 {目的城市} 自驾床车旅行攻略</h1>
<div class="meta">📍 南京 → {目的城市} | 📅 {N}天 | 👥 {人数}人 | {出行类型} | 🆕 {车辆类型}</div>
</div>
<!-- 🗺️ 交互式地图 -->
<div class="map-section">
<h2>🗺️ 打卡地图(点击标记查看详情)</h2>
<div id="map"></div>
</div>
<!-- 路线规划 -->
<div class="card">
<h2>🛣️ 路线规划</h2>
<!-- 区域聚合说明 + 🆕续航规划说明 + 🆕补充推荐说明 -->
<!-- 总览表格(🆕含充电安排列) + 每日区域概览 + 路线合理性说明 + 🆕续航提醒 -->
<!-- 🆕 补充推荐汇总:列出所有智能补充的地点,说明补充理由 -->
</div>
<!-- 美食攻略 -->
<div class="card">
<h2>🍜 美食攻略</h2>
<!-- 用户指定餐厅(特殊卡片,优先展示) -->
<!-- 🆕 智能补充推荐餐厅(ai-food样式,带 🔵智能推荐 标签) -->
<!-- 搜索推荐餐厅(含来源标签) + 特色小吃 -->
</div>
<!-- 露营攻略 -->
<div class="card">
<h2>🏕️ 床车露营攻略</h2>
<!-- 🆕 新能源床车优势区域(仅新能源车显示) -->
<!-- 露营地卡片(🆕标注充电桩信息) + 备选方案 -->
</div>
<!-- 🆕 充电规划 -->
<div class="card">
<h2>⚡ 充电规划</h2>
<!-- 仅新能源车显示 -->
<!-- 沿途充电站 + 目的地充电站 + 充电策略建议 -->
</div>
<!-- 每日行程 -->
<div class="card">
<h2>🚗 每日行程</h2>
<!-- 按优化路线排列的逐日时间线(🆕含充电时间块) -->
</div>
<!-- 打卡点 -->
<div class="card">
<h2>📸 拍照打卡点</h2>
<!-- 用户指定打卡点(紫色卡片) -->
<!-- 🆕 智能补充打卡点(ai-spot样式,带 🔵智能推荐 标签) -->
<!-- 必打卡 + 隐藏打卡点 -->
</div>
<!-- 准备清单 -->
<div class="card">
<h2>🎒 出行准备清单</h2>
<!-- 分类 checklist(🆕含新能源专属分类) -->
</div>
<!-- 费用预估 -->
<div class="card">
<h2>💰 费用预估(🆕{车辆类型})</h2>
<!-- 🆕 双模式费用表格:电费/油费 -->
</div>
<!-- 注意事项 -->
<div class="card">
<h2>⚠️ 注意事项</h2>
<!-- 🆕 新能源专属提醒 + 通用提醒 + 季节提醒 -->
</div>
</div>
<script>
// 初始化地图
const map = L.map('map').setView([目的城市中心纬度, 目的城市中心经度], 12);
// 添加底图
L.tileLayer('https://webrd0{s}.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=8&x={x}&y={y}&z={z}', {
subdomains: ['1', '2', '3', '4'],
maxZoom: 18,
attribution: '© 高德地图'
}).addTo(map);
// 定义图标
// ... (景点蓝/美食红/露营绿/休息黄/充电橙/用户紫/用户粉)
// 添加区域高亮圈
// ... (每天的游玩范围圈)
// 添加标注点
// ... (每个地点的 marker + popup,🆕含充电站)
// 添加路线连线
// ... (每天的行程折线,按优化顺序)
// 添加图例(🆕含充电站)
// ...
// 自适应显示所有标注点
const allMarkers = [...spotMarkers, ...foodMarkers, ...campMarkers, ...chargeMarkers, ...userSpotMarkers, ...userFoodMarkers];
const group = L.featureGroup(allMarkers);
map.fitBounds(group.getBounds().pad(0.1));
</script>
</body>
</html>
在原有准备清单基础上,新能源车新增以下分类:
🔌 新能源专属:
□ 国网充电卡/APP(e充电)
□ 特来电APP
□ 星星充电APP
□ 云快充APP
□ 随车充(3.5kW便携充电枪,露营民宿应急用)
□ 充电线缆(16A空调插座转接头)
□ 充电桩预约截图(热门站点五一可能排队)
□ 车辆随车充转接头(如有)
攻略中必须包含以下新能源专属提醒(仅新能源车显示):
🔋 新能源车注意事项:
- 五一高速充电桩可能排队,提前在APP查看桩状态,错峰充电(午餐时间/深夜充电人少)
- 续航在高速120km/h下会缩水约20-30%,规划时留足余量
- 冬季续航再打7-8折,空调制热耗电大,规划时按标称续航×0.65
- 驻车空调很爽但注意电量,至少保留15%应急
- V2L放电注意别把电量放太低,建议>20%时停止对外供电
- 山路/堵车/开空调都会影响续航,保守规划比冒险好
- 到达目的地后优先找充电桩补满,第二天出发无焦虑
- 露营过夜可开驻车空调,约1-2度电/小时,8小时约8-16度电
根据出行季节自动补充以下提醒:
共 2 个版本