feat: 增加工作台页面的导出html功能,但是导出的html需要重新调整

refactor
Lxy 7 days ago
parent 4f674154b4
commit 9409a2c5e8

@ -24,8 +24,8 @@
{{ getSchemeLabel(i) }}
</button>
</div>
<button class="wb-export-btn" @click="exportCurrentScheme" :disabled="store.quickSchemes.length === 0">
📥 导出行程
<button class="wb-export-btn" @click="exportCurrentScheme">
📥 导出HTML
</button>
</div>
@ -163,7 +163,7 @@
import { ref, computed, watch } from 'vue'
import { useItineraryStore } from '../stores/itinerary'
import MapView from './MapView.vue'
import { exportToMarkdown } from '../services/exportService'
import { exportToHtml } from '../services/exportHtmlService'
const store = useItineraryStore()
const mapView = ref(null)
@ -235,8 +235,11 @@ const toggleRoute = () => {
function exportCurrentScheme() {
const idx = store.activeSchemeIndex
if (idx < 0 || idx >= store.quickSchemes.length) {
// points
if (idx >= 0 && idx < store.quickSchemes.length) {
//
exportToHtml(store.quickSchemes[idx], `${store.quickSchemes[idx].name || '行程规划'}.html`)
} else {
// points
const scheme = {
name: '我的行程',
route: store.points.map(p => p.name).join(' → '),
@ -252,13 +255,12 @@ function exportCurrentScheme() {
driveTime: p.driveTime,
schedule: p.schedule || [],
foods: p.foods || [],
waypoints: p.waypoints || []
waypoints: p.waypoints || [],
hotel: p.hotel || ''
})),
tips: ''
}
exportToMarkdown(scheme, '我的行程.md')
} else {
exportToMarkdown(store.quickSchemes[idx], `${store.quickSchemes[idx].name || '行程规划'}.md`)
exportToHtml(scheme, '我的行程.html')
}
}

@ -0,0 +1,195 @@
// 导出可交互的 HTML 行程文件
export function exportToHtml(scheme, filename = null) {
if (!scheme) return
const html = generateHtml(scheme)
const blob = new Blob([html], { type: 'text/html;charset=utf-8' })
const url = URL.createObjectURL(blob)
const link = document.createElement('a')
link.href = url
link.download = filename || `${scheme.name || '行程规划'}.html`
document.body.appendChild(link)
link.click()
document.body.removeChild(link)
URL.revokeObjectURL(url)
}
function generateHtml(scheme) {
const daysDetail = scheme.daysDetail || []
const points = []
// 从 daysDetail 中提取站点信息
daysDetail.forEach((day, idx) => {
points.push({
name: day.location || `Day ${idx + 1}`,
day: `Day ${idx + 1}`,
desc: day.desc || '',
km: day.km || '—',
driveTime: day.driveTime || '—',
schedule: day.schedule || [],
foods: day.foods || [],
waypoints: day.waypoints || [],
hotel: day.hotel || ''
})
})
return `<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>${scheme.name || '行程规划'}</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; background: #f5f7fa; color: #2d3436; line-height: 1.6; }
.container { max-width: 900px; margin: 0 auto; padding: 24px; }
.header { background: linear-gradient(135deg, #6c5ce7, #a29bfe); color: #fff; padding: 32px; border-radius: 16px; margin-bottom: 24px; }
.header h1 { font-size: 24px; margin-bottom: 12px; }
.meta { display: flex; gap: 16px; flex-wrap: wrap; font-size: 14px; opacity: 0.9; }
.meta span { background: rgba(255,255,255,0.2); padding: 4px 12px; border-radius: 6px; }
.highlights { background: #fff; padding: 20px; border-radius: 12px; margin-bottom: 20px; box-shadow: 0 2px 8px rgba(0,0,0,0.05); }
.highlights h2 { font-size: 18px; margin-bottom: 12px; color: #6c5ce7; }
.highlights ul { padding-left: 20px; }
.highlights li { margin-bottom: 6px; }
.tabs { display: flex; gap: 8px; margin-bottom: 20px; flex-wrap: wrap; }
.tab { padding: 10px 20px; background: #fff; border: 2px solid #eee; border-radius: 8px; cursor: pointer; font-weight: 600; transition: all 0.2s; }
.tab:hover { border-color: #6c5ce7; color: #6c5ce7; }
.tab.active { background: #6c5ce7; color: #fff; border-color: #6c5ce7; }
.day-content { background: #fff; padding: 24px; border-radius: 12px; box-shadow: 0 2px 8px rgba(0,0,0,0.05); display: none; }
.day-content.active { display: block; }
.day-header { display: flex; align-items: center; gap: 12px; margin-bottom: 16px; padding-bottom: 12px; border-bottom: 1px solid #eee; }
.day-badge { background: #6c5ce7; color: #fff; padding: 4px 12px; border-radius: 6px; font-size: 13px; font-weight: 600; }
.day-title { font-size: 18px; font-weight: 700; }
.day-km { margin-left: auto; font-size: 13px; color: #999; }
.schedule { margin-bottom: 20px; }
.schedule-item { display: flex; gap: 12px; margin-bottom: 12px; padding: 12px; background: #f8f9fa; border-radius: 8px; }
.schedule-time { font-size: 13px; font-weight: 600; color: #6c5ce7; min-width: 60px; }
.schedule-content { flex: 1; }
.schedule-content strong { display: block; margin-bottom: 4px; }
.schedule-content p { font-size: 14px; color: #636e72; margin: 0; }
.waypoints { margin-bottom: 20px; }
.waypoints h3 { font-size: 15px; margin-bottom: 10px; color: #636e72; }
.waypoint-list { display: flex; flex-wrap: wrap; gap: 8px; }
.waypoint-tag { background: #fff; border: 1px solid #dfe6e9; padding: 6px 12px; border-radius: 8px; font-size: 13px; }
.foods { margin-bottom: 20px; }
.foods h3 { font-size: 15px; margin-bottom: 10px; color: #636e72; }
.food-list { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 10px; }
.food-item { display: flex; align-items: center; gap: 8px; padding: 10px; background: #f8f9fa; border-radius: 8px; }
.food-icon { font-size: 20px; }
.hotel { background: #f0f4ff; padding: 14px; border-radius: 8px; border-left: 3px solid #6c5ce7; font-size: 14px; color: #636e72; }
.footer { text-align: center; margin-top: 32px; padding: 20px; color: #999; font-size: 12px; }
@media (max-width: 600px) {
.container { padding: 16px; }
.header { padding: 20px; }
.header h1 { font-size: 20px; }
.meta { flex-direction: column; gap: 8px; }
.tabs { gap: 6px; }
.tab { padding: 8px 14px; font-size: 13px; }
.day-content { padding: 16px; }
.food-list { grid-template-columns: 1fr; }
}
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>${scheme.name || '行程规划'}</h1>
<div class="meta">
<span>📍 ${scheme.route || '—'}</span>
<span>📅 ${scheme.days || '—'}</span>
<span>🚗 ~${scheme.totalKm || '—'}km</span>
<span>💰 ${scheme.budget || '—'}</span>
</div>
</div>
${scheme.highlights && scheme.highlights.length > 0 ? `
<div class="highlights">
<h2> 行程亮点</h2>
<ul>
${scheme.highlights.map(h => `<li>${h}</li>`).join('')}
</ul>
</div>
` : ''}
<div class="tabs">
${points.map((p, i) => `
<div class="tab ${i === 0 ? 'active' : ''}" onclick="showDay(${i})">Day ${i + 1}</div>
`).join('')}
</div>
${points.map((p, i) => `
<div class="day-content ${i === 0 ? 'active' : ''}" id="day-${i}">
<div class="day-header">
<span class="day-badge">Day ${i + 1}</span>
<span class="day-title">${p.name}</span>
<span class="day-km">${p.km}km · 驾车${p.driveTime}h</span>
</div>
${p.desc ? `<p style="margin-bottom:16px;color:#636e72;">${p.desc}</p>` : ''}
${p.schedule && p.schedule.length > 0 ? `
<div class="schedule">
<h3 style="margin-bottom:12px;">📅 日程安排</h3>
${p.schedule.map(s => `
<div class="schedule-item">
<div class="schedule-time">${s.time || '—'}</div>
<div class="schedule-content">
<strong>${s.title || s.content || '—'}</strong>
<p>${s.desc || ''}</p>
</div>
</div>
`).join('')}
</div>
` : ''}
${p.waypoints && p.waypoints.length > 0 ? `
<div class="waypoints">
<h3>🗺 途径推荐</h3>
<div class="waypoint-list">
${p.waypoints.map(wp => `
<div class="waypoint-tag">${wp.icon || '📍'} ${wp.name}</div>
`).join('')}
</div>
</div>
` : ''}
${p.foods && p.foods.length > 0 ? `
<div class="foods">
<h3>🍽 美食推荐</h3>
<div class="food-list">
${p.foods.map(f => {
const name = typeof f === 'string' ? f : (f.name || f)
const icon = typeof f === 'object' ? (f.icon || '🍜') : '🍜'
return `<div class="food-item"><span class="food-icon">${icon}</span><span>${name}</span></div>`
}).join('')}
</div>
</div>
` : ''}
${p.hotel ? `
<div class="hotel">🏨 住宿推荐${p.hotel}</div>
` : ''}
</div>
`).join('')}
${scheme.tips ? `
<div style="background:#fff8e1;padding:20px;border-radius:12px;margin-top:20px;border-left:3px solid #f39c12;">
<h3 style="margin-bottom:8px;">💡 旅行贴士</h3>
<p>${scheme.tips}</p>
</div>
` : ''}
<div class="footer">由智能行程规划系统生成</div>
</div>
<script>
function showDay(idx) {
document.querySelectorAll('.day-content').forEach(el => el.classList.remove('active'));
document.querySelectorAll('.tab').forEach(el => el.classList.remove('active'));
document.getElementById('day-' + idx).classList.add('active');
document.querySelectorAll('.tab')[idx].classList.add('active');
}
</script>
</body>
</html>`
}
Loading…
Cancel
Save