diff --git a/src/renderer/views/chat/ChatView.vue b/src/renderer/views/chat/ChatView.vue index b391a3e..e49f8de 100644 --- a/src/renderer/views/chat/ChatView.vue +++ b/src/renderer/views/chat/ChatView.vue @@ -22,21 +22,6 @@ - - - - - {{ q.header }} - {{ q.question }} - - - {{ opt.label }} - {{ opt.description }} - - - - - @@ -145,7 +130,6 @@ const hasActiveQuestion = computed(() => { if (!msg.parts) continue; for (const p of msg.parts) { if (p.type === 'tool' && p.tool === 'question' && p.state?.status === 'running' && p._questionId) return true; - if (p.type === 'question') return true; } } return false; @@ -327,13 +311,7 @@ function registerSSEListeners() { const msgId = props.tool?.messageID; const callId = props.tool?.callID; if (!msgId) return; - // 将 question 作为一个 part 插入对应消息 - upsertAssistantPart(msgId, { - id: props.id, - type: 'question', - questions: props.questions || [], - }); - // 同时将 question id 关联到对应的 tool part(通过 callID 匹配) + // 将 question id 关联到对应的 tool part(通过 callID 匹配) if (callId) { const msg = messages.value.find((m) => m.id === msgId); if (msg && msg.parts) { @@ -361,9 +339,16 @@ function unregisterSSEListeners() { async function sendAnswer(questionId, label) { if (!currentSessionId.value) return; - messages.value.push({ id: Date.now(), role: 'user', text: label }); isSending.value = true; - scrollToBottom(); + // 将对应 tool part 标记为已回答,使输入框在等待响应期间可见 + for (const msg of messages.value) { + if (!msg.parts) continue; + for (const p of msg.parts) { + if (p.type === 'tool' && p.tool === 'question' && p._questionId === questionId) { + if (p.state) p.state.status = 'answered'; + } + } + } try { const baseUrl = window.__opencodeBaseUrl || 'http://127.0.0.1:4096'; await axios.post(`${baseUrl}/question/${questionId}/reply`, { answers: [[label]] }); @@ -468,19 +453,23 @@ onUnmounted(() => { .bubble { max-width: 75%; + min-width: 48px; padding: 10px 14px; border-radius: 12px; font-size: 14px; line-height: 1.6; + box-sizing: border-box; } .bubble-wrap.user .bubble { + width: fit-content; background: #409eff; color: #fff; border-bottom-right-radius: 4px; } .bubble-wrap.assistant .bubble { + width: 75%; background: #f0f2f5; color: #303133; border-bottom-left-radius: 4px; diff --git a/src/renderer/views/home/HomeView.vue b/src/renderer/views/home/HomeView.vue index 09a922a..77032a2 100644 --- a/src/renderer/views/home/HomeView.vue +++ b/src/renderer/views/home/HomeView.vue @@ -45,22 +45,33 @@ - - - 添加文件 + + + 选择工作目录 - / - @ + + + + + + + / + + + @ + - + @@ -74,14 +85,23 @@ import { ref } from 'vue'; import { useRouter } from 'vue-router'; import { useAppStore } from '@/stores/app'; import { useHistoryStore } from '@/stores/history'; -import { Document, Plus, Promotion } from '@element-plus/icons-vue'; +import { Document, Plus, Promotion, FolderOpened, Paperclip } from '@element-plus/icons-vue'; import { ElMessage } from 'element-plus'; +import LucideIcon from '@/components/base/LucideIcon.vue'; const router = useRouter(); const appStore = useAppStore(); const historyStore = useHistoryStore(); const inputText = ref(''); const isCreating = ref(false); +const textareaRef = ref(null); + +function autoResize() { + const el = textareaRef.value; + if (!el) return; + el.style.height = 'auto'; + el.style.height = Math.min(el.scrollHeight, 323) + 'px'; +} // 处理发送消息 async function handleSend() { @@ -234,26 +254,28 @@ function handleKeydown(e) { .input-section { margin-top: auto; padding-top: 24px; + padding-bottom: 32px; } .input-wrapper { width: 760px; - height: 114px; border-radius: 12px; - border: 1px solid #dcdfe6; + border: 1px solid #dee0e4; display: flex; flex-direction: column; background: #ffffff; - box-shadow: 0 2px 12px rgba(0, 0, 0, 0.06); + box-shadow: 0px 1px 20px 0px #00000008; } .input-textarea { width: 758px; - height: 60px; + min-height: 60px; + max-height: 323px; padding: 16px; border: none; outline: none; resize: none; + overflow-y: auto; font-size: 14px; line-height: 20px; color: #303133; @@ -271,7 +293,6 @@ function handleKeydown(e) { display: flex; align-items: center; justify-content: space-between; - border-top: 1px solid #ebeef5; } .toolbar-left { @@ -296,20 +317,33 @@ function handleKeydown(e) { color: #409eff; } -.file-btn { - width: 84px; +.dir-btn { height: 28px; gap: 4px; padding: 0 8px; - border-radius: 6px; + background: #f5f6f7; + border-radius: 28px; font-size: 12px; + font-weight: 400; + line-height: 16px; + text-align: center; + + display: flex; + align-items: center; + justify-content: center; + cursor: pointer; + transition: all 0.2s ease; + color: #606266; +} +.dir-btn:hover { + background: #eeeff2; } -.symbol-btn { +.icon-btn { width: 28px; height: 28px; - padding: 0; - border-radius: 6px; + padding: 0 7px; + border-radius: 9999px; font-size: 12px; font-weight: 500; } @@ -323,8 +357,8 @@ function handleKeydown(e) { width: 32px; height: 32px; border: none; - background: #409eff; - border-radius: 8px; + background: #1a1a1a; + border-radius: 32px; display: flex; align-items: center; justify-content: center; @@ -334,6 +368,11 @@ function handleKeydown(e) { } .send-btn:hover { - background: #66b1ff; + background: #333333; +} + +.send-btn:disabled { + background: #8c8c8c; + cursor: not-allowed; }