fix: 增加导出功能

refactor
Lxy 1 week ago
parent 4de216d00c
commit 4f674154b4

@ -129,6 +129,7 @@
</div> </div>
<div class="pc-actions"> <div class="pc-actions">
<button class="pc-btn preview" @click.stop="openPreview(i)">预览</button> <button class="pc-btn preview" @click.stop="openPreview(i)">预览</button>
<button class="pc-btn export" @click.stop="exportSingleScheme(i)">📥 导出</button>
<button class="pc-btn select" @click.stop="selectScheme(i)">选择此方案</button> <button class="pc-btn select" @click.stop="selectScheme(i)">选择此方案</button>
</div> </div>
</div> </div>
@ -143,8 +144,11 @@
<span class="pc-badge" :class="getBadgeClass(previewIndex)">{{ getSchemeLabel(previewIndex) }}</span> <span class="pc-badge" :class="getBadgeClass(previewIndex)">{{ getSchemeLabel(previewIndex) }}</span>
<h2>{{ previewScheme.name }}</h2> <h2>{{ previewScheme.name }}</h2>
</div> </div>
<div class="modal-header-actions">
<button class="btn-sm outline" @click="exportPreviewScheme">📥 </button>
<button class="modal-close" @click="closePreview">×</button> <button class="modal-close" @click="closePreview">×</button>
</div> </div>
</div>
<div class="modal-meta"> <div class="modal-meta">
<span>{{ previewScheme.days }}</span> <span>{{ previewScheme.days }}</span>
@ -223,6 +227,7 @@
import { ref, computed, onMounted } from 'vue' import { ref, computed, onMounted } from 'vue'
import { useItineraryStore } from '../stores/itinerary' import { useItineraryStore } from '../stores/itinerary'
import { quickPlan } from '../services/aiService' import { quickPlan } from '../services/aiService'
import { exportToMarkdown } from '../services/exportService'
const store = useItineraryStore() const store = useItineraryStore()
@ -393,6 +398,12 @@ function regeneratePlan() {
generatePlan() generatePlan()
} }
function exportSingleScheme(index) {
const scheme = allSchemes.value[index]
if (!scheme) return
exportToMarkdown(scheme, `${scheme.name || '行程规划'}.md`)
}
function selectScheme(index) { function selectScheme(index) {
const scheme = allSchemes.value[index] const scheme = allSchemes.value[index]
if (!scheme) { if (!scheme) {
@ -424,6 +435,13 @@ function closePreview() {
previewIndex.value = -1 previewIndex.value = -1
} }
function exportPreviewScheme() {
if (previewIndex.value < 0) return
const scheme = previewScheme.value
if (!scheme) return
exportToMarkdown(scheme, `${scheme.name || '行程规划'}.md`)
}
onMounted(() => { onMounted(() => {
if (store.quickSchemes.length > 0) { if (store.quickSchemes.length > 0) {
// Stay in list view to show existing schemes // Stay in list view to show existing schemes
@ -832,6 +850,16 @@ onMounted(() => {
background: #f0f0f5; background: #f0f0f5;
} }
.pc-btn.export {
background: #fff;
border: 1.5px solid #00b894;
color: #00b894;
}
.pc-btn.export:hover {
background: #f0f0f5;
}
.pc-btn.select { .pc-btn.select {
background: linear-gradient(135deg, #6c5ce7, #a29bfe); background: linear-gradient(135deg, #6c5ce7, #a29bfe);
color: #fff; color: #fff;
@ -888,6 +916,12 @@ onMounted(() => {
border-bottom: 1px solid #eee; border-bottom: 1px solid #eee;
} }
.modal-header-actions {
display: flex;
align-items: center;
gap: 8px;
}
.modal-header h2 { .modal-header h2 {
font-size: 20px; font-size: 20px;
font-weight: 700; font-weight: 700;

@ -24,6 +24,9 @@
{{ getSchemeLabel(i) }} {{ getSchemeLabel(i) }}
</button> </button>
</div> </div>
<button class="wb-export-btn" @click="exportCurrentScheme" :disabled="store.quickSchemes.length === 0">
📥 导出行程
</button>
</div> </div>
<!-- Main content --> <!-- Main content -->
@ -160,6 +163,7 @@
import { ref, computed, watch } from 'vue' import { ref, computed, watch } from 'vue'
import { useItineraryStore } from '../stores/itinerary' import { useItineraryStore } from '../stores/itinerary'
import MapView from './MapView.vue' import MapView from './MapView.vue'
import { exportToMarkdown } from '../services/exportService'
const store = useItineraryStore() const store = useItineraryStore()
const mapView = ref(null) 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 // points phase
watch([() => store.points, () => store.phase], ([newPoints, newPhase]) => { watch([() => store.points, () => store.phase], ([newPoints, newPhase]) => {
console.log('[Workbench] watch 触发 - phase:', newPhase, 'points 长度:', newPoints.length) console.log('[Workbench] watch 触发 - phase:', newPhase, 'points 长度:', newPoints.length)
@ -319,6 +352,28 @@ watch([() => store.points, () => store.phase], ([newPoints, newPhase]) => {
color: #6c5ce7; 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 */ /* Wrap layout */
.wb-wrap { .wb-wrap {
display: grid; display: grid;

@ -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
}
Loading…
Cancel
Save