From 91cf8f5d44b0fc94d4ac7bd9283938eaceeeb644 Mon Sep 17 00:00:00 2001 From: Lxy Date: Sat, 6 Jun 2026 20:49:17 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E9=87=8D=E6=9E=84=E5=88=9D=E6=AD=A5?= =?UTF-8?q?=E5=8F=AF=E7=94=A8=EF=BC=8C=E4=BD=86=E6=98=AF=E5=8A=9F=E8=83=BD?= =?UTF-8?q?=E7=BC=BA=E5=A4=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- design/design-prototype-v2.html | 464 +++++++++++++++++++ src/components/ChatInterface.vue | 390 +++++++--------- src/components/CustomPlanPanel.vue | 318 ++++++------- src/components/MapView.vue | 2 +- src/components/QuickPlanPanel.vue | 710 +++++++++++++---------------- src/components/Workbench.vue | 659 +++++++++++++++++++------- src/services/aiService.js | 60 ++- src/views/HomePage.vue | 286 ++++++++---- src/views/SettingsPage.vue | 39 +- 9 files changed, 1837 insertions(+), 1091 deletions(-) create mode 100644 design/design-prototype-v2.html diff --git a/design/design-prototype-v2.html b/design/design-prototype-v2.html new file mode 100644 index 0000000..a0993b1 --- /dev/null +++ b/design/design-prototype-v2.html @@ -0,0 +1,464 @@ + + + + + +智能行程规划系统 - 交互设计 v2 + + + + + + +
+ + +
+
+

智能行程规划

+

选择一种方式开始你的旅行规划

+
+
+
+
+

快速规划

+

输入目的地和天数,一键生成多个旅行方案供你选择

+
快速生成多方案对比即输即得
+
+
+
💬
+

聊天问答式

+

通过对话交流,我逐步了解你的需求,为你量身定制完美行程

+
多轮对话逐步收集信息个性化规划
+
+
+
✏️
+

自定义行程

+

输入你已规划的行程,AI 评估合理性并给出优化建议

+
行程评估智能建议优化方案
+
+
+
+ + +
+

⚡ 快速规划

输入目的地和天数,立即生成多个旅行方案

+
+
+
+
+
+
+
+
+
+
+ +
+ +
+ + +
+
+

📋 为你生成了 3 个方案

+
+
方案A经典熊猫与古堰休闲游
+
3天🚗 ~650km💰 ¥3200
+
成都→都江堰→青城山→成都
+
世界遗产都江堰水利工程青城山道教清幽成都熊猫基地
+
+
+
+
方案B川西深度生态游
+
📅 3天🚗 ~1200km💰 ¥4500
+
成都→九寨沟→黄龙→若尔盖→成都
+
九寨沟彩林与瀑布群黄龙钙华池与雪山若尔盖湿地草原星空
+
+
+
+
方案C川南秘境探索线
+
📅 3天🚗 ~850km💰 ¥2800
+
成都→宜宾→蜀南竹海→兴文石海→成都
+
蜀南竹海翡翠长廊兴文天坑溶洞奇观宜宾长江第一城文化
+
+
+
+
+ + +
+
+
+
+
🤖
+
你好!我是你的行程规划助手。请告诉我:
• 想去哪里?(单个地点或多个地点组合)
• 几月出发?几天行程?
• 交通方式?(自驾/公共交通/步行)
• 有什么特殊需求?(带老人/小孩/特定景点)

示例:9月去云南,5天,自驾,带老人
+
+
+
👤
+
9月去四川,大概5天时间,自驾
+
+
+
🤖
+
已为你生成 2 个方案,请查看下方卡片。

【方案A】九寨黄龙秋韵线
路线:成都-绵阳-九寨沟-黄龙-松潘-成都
5天 · 1150km · ¥3500

【方案B】四姑娘山丹巴环线
路线:成都-四姑娘山-丹巴甲居藏寨-康定-成都
5天 · 980km · ¥3200
+
+
+
+
+ 方案A +

九寨黄龙秋韵线

+
🚗 ~1150km   ⏱ 18h   📅 5天   💰 ¥3500
+ +
+
+ 方案B +

四姑娘山丹巴环线

+
🚗 ~980km   ⏱ 16h   📅 5天   💰 ¥3200
+ +
+
+
+ + +
+
+
+ + +
+
+

✏️ 自定义行程

+

输入你已规划的行程,AI 评估合理性并给出优化建议

+
+
+
+ + +
+
+
+ + +
+
+ + +
+
+ +
+
+ + +
+
+ +
+
+ + + +
+ +
+ + +
+
📋 行程时间线
+
+
+
+
成都市区
+
Day 1 · 0km
+
+
+
+
+
+
都江堰景区
+
Day 2 · 60km
+
+
+
+
+
+
青城山
+
Day 3 · 25km
+
+
+
+ + +
+
+ + +
+
+
+

成都市区

+

天府之国核心,美食与慢生活之都

+
+
+
+
+
0km
+
行驶里程
+
+
+
+
驾驶时间
+
+
+
Day 1
+
第几天
+
+
+
+

行程安排

+
上午参观大熊猫繁育研究基地
+
下午逛宽窄巷子、武侯祠,品尝火锅
+
+
+

🍽️ 美食推荐

+
+ 担担面龙抄手麻辣火锅 +
+
+
+

🏨 住宿推荐

+
春熙路商圈精品酒店
+
+
+

💡 注意事项

+
市区早晚高峰拥堵,建议错峰出行
+
+
+
+
🗺️ 地图交互区域
+
+
+
+ + +
+

交互设计说明

+

本原型展示了从需求输入到方案生成的完整流程,风格统一、简洁。

+
+ + + + diff --git a/src/components/ChatInterface.vue b/src/components/ChatInterface.vue index b08b441..f5aef32 100644 --- a/src/components/ChatInterface.vue +++ b/src/components/ChatInterface.vue @@ -1,33 +1,27 @@ @@ -120,6 +89,10 @@ const scrollToBottom = async () => { } } +function getSchemeLabel(i) { + return String.fromCharCode(65 + (i % 26)) +} + const sendMessage = async () => { if (!inputText.value.trim() || isGenerating.value) return @@ -136,31 +109,27 @@ const sendMessage = async () => { let thinkingContent = '' const result = await chatWithAI(userMsg, (streamContent) => { - // Parse streaming content for thinking thinkingContent = streamContent - // Update thinking status based on progress if (streamContent.includes('thinking')) { - thinkingStatus.value = '🧠 AI 正在思考并搜索目的地信息...' + thinkingStatus.value = 'AI 正在思考并搜索目的地信息...' } else if (streamContent.includes('schemes')) { - thinkingStatus.value = '📋 正在生成旅行方案...' + thinkingStatus.value = '正在生成旅行方案...' } else if (streamContent.includes('points')) { - thinkingStatus.value = '📍 正在规划详细行程...' + thinkingStatus.value = '正在规划详细行程...' } }) isGenerating.value = false - // Add bot response message with thinking process const botMsg = { role: 'bot', - content: `已为你生成 ${result.schemes.length} 个方案,请查看下方卡片。\n\n${result.schemes.map((s, i) => `【方案${String.fromCharCode(65 + i)}】${s.name}\n路线:${s.route}\n${s.days}天 · ${s.totalKm}km · ${s.budget}`).join('\n\n')}`, + content: `已为你生成 ${result.schemes.length} 个方案,请查看下方卡片。\n\n${result.schemes.map((s, i) => `【${getSchemeLabel(i)}】${s.name}\n路线:${s.route}\n${s.days}天 \u00b7 ${s.totalKm}km \u00b7 ${s.budget}`).join('\n\n')}`, thinking: result.thinking, thinkingExpanded: false } messages.value.push(botMsg) - // Set schemes for card display schemes.value = result.schemes await scrollToBottom() @@ -171,7 +140,7 @@ const sendMessage = async () => { role: 'bot', content: '抱歉,生成方案时遇到了问题。', error: error.message.includes('API Key') - ? '请先访问 /settings 配置你的 AI API Key' + ? '请先访问设置页面配置你的 AI API Key' : error.message + ',请重试' }) await scrollToBottom() @@ -182,7 +151,6 @@ const selectScheme = (index) => { const scheme = schemes.value[index] if (!scheme) return - // Load the selected scheme into the itinerary store store.loadFromAI(scheme) store.setPhase('workbench') } @@ -192,75 +160,79 @@ const selectScheme = (index) => { .chat-interface { display: flex; flex-direction: column; - height: 100vh; - background: #f5f5f5; - position: relative; + height: calc(100vh - 130px); + max-width: 800px; + margin: 0 auto; + padding: 24px 32px; } -.chat-header { - text-align: center; - padding: 30px 20px; - background: linear-gradient(135deg, #1b4332, #2d6a4f); - color: #fff; -} - -.chat-header h1 { margin: 0 0 8px; font-size: 24px; } -.chat-header p { margin: 0; opacity: 0.8; font-size: 14px; } - -.chat-messages { +.chat-msgs { flex: 1; overflow-y: auto; - padding: 20px; + padding: 20px 0; display: flex; flex-direction: column; - gap: 16px; + gap: 18px; } -.message { +.chat-bubble { display: flex; - gap: 12px; - max-width: 85%; + gap: 10px; + max-width: 75%; } -.message.bot { align-self: flex-start; } -.message.user { align-self: flex-end; flex-direction: row-reverse; } +.chat-bubble.bot { align-self: flex-start; } +.chat-bubble.user { align-self: flex-end; flex-direction: row-reverse; } -.avatar { - width: 36px; - height: 36px; - border-radius: 50%; +.cb-av { + width: 34px; + height: 34px; + border-radius: 10px; display: flex; align-items: center; justify-content: center; - font-size: 18px; - background: #e8f5e9; + font-size: 16px; flex-shrink: 0; } -.message.user .avatar { background: #e3f2fd; } +.bot-av { + background: #e8e4ff; +} + +.bot-av::before { + content: '🤖'; +} + +.user-av { + background: #d1fae5; +} -.bubble { +.user-av::before { + content: '👤'; +} + +.cb-body { padding: 12px 16px; - border-radius: 16px; + border-radius: 14px; font-size: 14px; line-height: 1.6; } -.message.bot .bubble { +.chat-bubble.bot .cb-body { background: #fff; - color: #333; + color: #2d3436; border-bottom-left-radius: 4px; + box-shadow: 0 2px 6px rgba(0,0,0,0.04); } -.message.user .bubble { - background: #2a9d8f; +.chat-bubble.user .cb-body { + background: linear-gradient(135deg, #6c5ce7, #a29bfe); color: #fff; border-bottom-right-radius: 4px; } -.example { - opacity: 0.8; - font-size: 13px; +.message-content { + white-space: pre-wrap; } /* Thinking process */ @@ -285,6 +257,10 @@ const selectScheme = (index) => { .thinking-header:hover { background: #f0f0f0; } +.thinking-icon::before { + content: '🧠'; +} + .thinking-toggle { margin-left: auto; font-size: 12px; @@ -315,10 +291,6 @@ const selectScheme = (index) => { color: #856404; } -.message-content { - white-space: pre-wrap; -} - /* Loading */ .thinking { display: flex; @@ -330,7 +302,7 @@ const selectScheme = (index) => { width: 6px; height: 6px; border-radius: 50%; - background: #2a9d8f; + background: #6c5ce7; animation: pulse 1.4s infinite; } @@ -342,156 +314,122 @@ const selectScheme = (index) => { 40% { opacity: 1; transform: scale(1); } } -/* Input */ -.chat-input-area { - display: flex; - gap: 8px; - padding: 16px 20px; - background: #fff; - border-top: 1px solid #eee; -} - -.chat-input-area input { - flex: 1; - padding: 12px 16px; - border: 1px solid #ddd; - border-radius: 24px; - font-size: 14px; - outline: none; - transition: border-color 0.2s; -} - -.chat-input-area input:focus { border-color: #2a9d8f; } -.chat-input-area input:disabled { background: #f5f5f5; cursor: not-allowed; } - -.chat-input-area button { - padding: 12px 24px; - background: #2a9d8f; - color: #fff; - border: none; - border-radius: 24px; - font-size: 14px; - cursor: pointer; - transition: background 0.2s; -} - -.chat-input-area button:hover:not(:disabled) { background: #21867a; } -.chat-input-area button:disabled { opacity: 0.5; cursor: not-allowed; } - /* Scheme cards */ -.scheme-cards { - position: absolute; - bottom: 80px; - left: 20px; - right: 20px; - background: #fff; - border-radius: 16px; - padding: 20px; - box-shadow: 0 -4px 20px rgba(0,0,0,0.1); - max-height: 60vh; - overflow-y: auto; -} - -.scheme-cards h3 { - margin: 0 0 16px; - font-size: 16px; - color: #1b4332; -} - -.cards-grid { +.chat-cards { display: grid; - grid-template-columns: repeat(3, 1fr); + grid-template-columns: 1fr 1fr; gap: 12px; + padding: 16px 0; } -.scheme-card { - border: 2px solid #e0e0e0; +.cc { + background: #fff; border-radius: 12px; padding: 16px; + border: 1.5px solid #eee; cursor: pointer; transition: all 0.2s; } -.scheme-card:hover { - border-color: #2a9d8f; - transform: translateY(-2px); - box-shadow: 0 4px 12px rgba(42,157,143,0.2); +.cc:hover { + border-color: #6c5ce7; } -.card-header { - display: flex; - align-items: center; - gap: 8px; - margin-bottom: 12px; -} - -.card-badge { - background: #f4a261; - color: #1b4332; +.cc-badge { + font-size: 11px; padding: 2px 8px; border-radius: 4px; - font-size: 11px; + background: #fff3e0; + color: #e17055; font-weight: 600; } -.card-header h4 { - margin: 0; +.cc-badge.badge-b { + background: #e0f2fe; + color: #0984e3; +} + +.cc h4 { font-size: 14px; - color: #333; + margin: 6px 0 4px; + color: #2d3436; } -.card-stats { - display: grid; - grid-template-columns: 1fr 1fr; - gap: 4px; - margin-bottom: 8px; +.cc-meta { font-size: 12px; - color: #666; + color: #636e72; } -.card-highlights { +.cc-link { + margin-top: 10px; + font-size: 12px; + color: #6c5ce7; + font-weight: 600; +} + +/* Input */ +.chat-input-bar { + padding: 14px 0; display: flex; - flex-wrap: wrap; - gap: 4px; - margin-bottom: 8px; + gap: 10px; } -.highlight-tag { - background: #e8f5e9; - color: #2a9d8f; - padding: 2px 8px; - border-radius: 4px; - font-size: 11px; +.chat-input-bar input { + flex: 1; + padding: 12px 18px; + border: 1.5px solid #dfe6e9; + border-radius: 24px; + font-size: 14px; + outline: none; + transition: border 0.2s; } -.card-route { - font-size: 11px; - color: #888; - margin-bottom: 12px; - padding: 6px; - background: #f8f9fa; - border-radius: 6px; +.chat-input-bar input:focus { + border-color: #6c5ce7; } -.card-action { - text-align: center; - color: #2a9d8f; - font-weight: 600; - font-size: 13px; +.chat-input-bar input:disabled { + background: #f5f7fa; + cursor: not-allowed; } -.slide-up-enter-active, .slide-up-leave-active { - transition: all 0.3s ease; +.chat-input-bar button { + width: 44px; + height: 44px; + border-radius: 50%; + background: linear-gradient(135deg, #6c5ce7, #a29bfe); + color: #fff; + border: none; + cursor: pointer; + font-size: 16px; + transition: all 0.2s; +} + +.chat-input-bar button:hover:not(:disabled) { + transform: translateY(-1px); + box-shadow: 0 4px 14px rgba(108,92,231,0.35); +} + +.chat-input-bar button:disabled { + opacity: 0.5; + cursor: not-allowed; } -.slide-up-enter-from, .slide-up-leave-to { - transform: translateY(20px); - opacity: 0; +.chat-input-bar button::before { + content: '➤'; } -@media (max-width: 900px) { - .cards-grid { +@media (max-width: 768px) { + .chat-interface { + padding: 16px; + } + + .chat-cards { grid-template-columns: 1fr; } + + .chat-bubble { + max-width: 90%; + } } diff --git a/src/components/CustomPlanPanel.vue b/src/components/CustomPlanPanel.vue index 1137d38..9cbeac8 100644 --- a/src/components/CustomPlanPanel.vue +++ b/src/components/CustomPlanPanel.vue @@ -1,74 +1,57 @@