From 4f674154b47a4baac273ae2bbfbb079d121889ab Mon Sep 17 00:00:00 2001 From: Lxy Date: Sun, 7 Jun 2026 00:27:49 +0800 Subject: [PATCH] =?UTF-8?q?fix=EF=BC=9A=20=E5=A2=9E=E5=8A=A0=E5=AF=BC?= =?UTF-8?q?=E5=87=BA=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/QuickPlanPanel.vue | 36 ++++++++++- src/components/Workbench.vue | 55 +++++++++++++++++ src/services/exportService.js | 99 +++++++++++++++++++++++++++++++ 3 files changed, 189 insertions(+), 1 deletion(-) create mode 100644 src/services/exportService.js diff --git a/src/components/QuickPlanPanel.vue b/src/components/QuickPlanPanel.vue index f382eb0..adc4829 100644 --- a/src/components/QuickPlanPanel.vue +++ b/src/components/QuickPlanPanel.vue @@ -129,6 +129,7 @@
+
@@ -143,7 +144,10 @@ {{ getSchemeLabel(previewIndex) }}

{{ previewScheme.name }}

- + + @@ -160,6 +163,7 @@ import { ref, computed, watch } from 'vue' import { useItineraryStore } from '../stores/itinerary' import MapView from './MapView.vue' +import { exportToMarkdown } from '../services/exportService' const store = useItineraryStore() const mapView = ref(null) @@ -229,6 +233,35 @@ const toggleRoute = () => { } } +function exportCurrentScheme() { + const idx = store.activeSchemeIndex + if (idx < 0 || idx >= store.quickSchemes.length) { + // 导出当前 points 数据 + const scheme = { + name: '我的行程', + route: store.points.map(p => p.name).join(' → '), + days: store.points.length, + totalKm: store.totalKm, + totalDriveTime: store.totalDriveTime, + budget: '—', + highlights: [], + daysDetail: store.points.map((p, i) => ({ + location: p.name, + desc: p.desc, + km: p.km, + driveTime: p.driveTime, + schedule: p.schedule || [], + foods: p.foods || [], + waypoints: p.waypoints || [] + })), + tips: '' + } + exportToMarkdown(scheme, '我的行程.md') + } else { + exportToMarkdown(store.quickSchemes[idx], `${store.quickSchemes[idx].name || '行程规划'}.md`) + } +} + // 监听 points 和 phase 变化,当进入工作台且有有效数据时自动获取真实路径 watch([() => store.points, () => store.phase], ([newPoints, newPhase]) => { console.log('[Workbench] watch 触发 - phase:', newPhase, 'points 长度:', newPoints.length) @@ -319,6 +352,28 @@ watch([() => store.points, () => store.phase], ([newPoints, newPhase]) => { color: #6c5ce7; } +.wb-export-btn { + padding: 6px 14px; + border-radius: 6px; + font-size: 12px; + cursor: pointer; + border: 1.5px solid #6c5ce7; + background: #fff; + color: #6c5ce7; + transition: all 0.2s; + font-weight: 500; +} + +.wb-export-btn:hover:not(:disabled) { + background: #6c5ce7; + color: #fff; +} + +.wb-export-btn:disabled { + opacity: 0.4; + cursor: not-allowed; +} + /* Wrap layout */ .wb-wrap { display: grid; diff --git a/src/services/exportService.js b/src/services/exportService.js new file mode 100644 index 0000000..783dc14 --- /dev/null +++ b/src/services/exportService.js @@ -0,0 +1,99 @@ +// 行程导出功能 +export function exportToMarkdown(scheme, filename = null) { + if (!scheme) return + + const md = generateMarkdown(scheme) + const blob = new Blob([md], { type: 'text/markdown;charset=utf-8' }) + const url = URL.createObjectURL(blob) + const link = document.createElement('a') + link.href = url + link.download = filename || `${scheme.name || '行程规划'}.md` + document.body.appendChild(link) + link.click() + document.body.removeChild(link) + URL.revokeObjectURL(url) +} + +function generateMarkdown(scheme) { + let md = `# ${scheme.name || '行程规划'}\n\n` + + // 基本信息 + md += `## 基本信息\n\n` + md += `- **路线**:${scheme.route || '—'}\n` + md += `- **天数**:${scheme.days || '—'}天\n` + md += `- **总里程**:~${scheme.totalKm || '—'}km\n` + md += `- **驾驶时间**:~${scheme.totalDriveTime || '—'}小时\n` + md += `- **预算**:${scheme.budget || '—'}\n\n` + + // 亮点 + if (scheme.highlights && scheme.highlights.length > 0) { + md += `## 行程亮点\n\n` + scheme.highlights.forEach(h => { + md += `- ${h}\n` + }) + md += '\n' + } + + // 每日行程 + if (scheme.daysDetail && scheme.daysDetail.length > 0) { + md += `## 每日行程\n\n` + scheme.daysDetail.forEach((day, idx) => { + md += `### Day ${idx + 1}:${day.location || '未知地点'}\n\n` + if (day.desc) md += `${day.desc}\n\n` + if (day.km) md += `- **里程**:${day.km}km\n` + if (day.driveTime) md += `- **驾驶时间**:${day.driveTime}h\n\n` + + if (day.spots && day.spots.length > 0) { + md += `**途经景点**:${day.spots.join('、')}\n\n` + } + + // 详细日程 + if (day.schedule && day.schedule.length > 0) { + md += `#### 日程安排\n\n` + md += `| 时间 | 行程 | 说明 |\n` + md += `|------|------|------|\n` + day.schedule.forEach(s => { + md += `| ${s.time || '—'} | ${s.title || s.content || '—'} | ${s.desc || '—'} |\n` + }) + md += '\n' + } + + // 途径推荐 + if (day.waypoints && day.waypoints.length > 0) { + md += `#### 途径推荐\n\n` + day.waypoints.forEach(wp => { + md += `- **${wp.icon || '📍'} ${wp.name}**:${wp.desc || '—'}\n` + }) + md += '\n' + } + + // 美食推荐 + if (day.foods && day.foods.length > 0) { + md += `#### 美食推荐\n\n` + day.foods.forEach(f => { + const name = typeof f === 'string' ? f : (f.name || f) + const icon = typeof f === 'object' ? (f.icon || '🍜') : '🍜' + const desc = typeof f === 'object' ? (f.desc || '') : '' + md += `- ${icon} **${name}**${desc ? `:${desc}` : ''}\n` + }) + md += '\n' + } + + // 住宿 + if (day.hotel) { + md += `**住宿推荐**:${day.hotel}\n\n` + } + + md += '---\n\n' + }) + } + + // 旅行贴士 + if (scheme.tips) { + md += `## 旅行贴士\n\n${scheme.tips}\n\n` + } + + md += `> 由智能行程规划系统生成\n` + + return md +}