From 8b8f77cfccaa326ba2ff58b75657ee1e4b829d03 Mon Sep 17 00:00:00 2001 From: MT-Fire <798521692@qq.com> Date: Thu, 12 Mar 2026 10:24:22 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E9=94=99=E8=AF=AF?= =?UTF-8?q?=E6=BB=9A=E5=8A=A8=E5=88=B0=E5=BA=95=E9=83=A8=E7=9A=84=E9=97=AE?= =?UTF-8?q?=E9=A2=98=E3=80=82=E5=88=A0=E9=99=A4=E5=AD=97=E6=95=B0=E6=98=BE?= =?UTF-8?q?=E7=A4=BA=EF=BC=8C=E6=B7=BB=E5=8A=A0toast=E6=8F=90=E7=A4=BA?= =?UTF-8?q?=E8=B6=85=E8=BF=87=E5=AD=97=E6=95=B0=E3=80=82=E8=BE=93=E5=85=A5?= =?UTF-8?q?=E6=A1=86=E6=89=A9=E5=A4=A7=E6=8C=89=E9=92=AE=E7=A7=BB=E5=8A=A8?= =?UTF-8?q?=E8=87=B3=E5=B7=A6=E4=BE=A7=E3=80=82=E5=88=A0=E9=99=A4=E4=BE=A7?= =?UTF-8?q?=E8=BE=B9=E6=A0=8F=E8=BE=B9=E6=A1=86=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/chat/MessageList.vue | 5 +- src/components/input/ChatInput.vue | 94 +++++++++++++++----------- src/components/sidebar/ChatSidebar.vue | 5 +- 3 files changed, 61 insertions(+), 43 deletions(-) diff --git a/src/components/chat/MessageList.vue b/src/components/chat/MessageList.vue index 040534f..28572ae 100644 --- a/src/components/chat/MessageList.vue +++ b/src/components/chat/MessageList.vue @@ -229,7 +229,10 @@ defineExpose({ }); onMounted(() => { - scrollToBottom(false); + // 只有当有消息时才滚动到底部,否则保持在顶部显示欢迎界面 + if (visibleMessages.value.length > 0) { + scrollToBottom(false); + } }); diff --git a/src/components/input/ChatInput.vue b/src/components/input/ChatInput.vue index d0d4d8f..48e28be 100644 --- a/src/components/input/ChatInput.vue +++ b/src/components/input/ChatInput.vue @@ -54,6 +54,7 @@ v-model="inputText" :placeholder="placeholder" :rows="1" + @beforeinput="handleBeforeInput" @input="autoResize" @focus="isFocused = true" @blur="isFocused = false" @@ -90,6 +91,11 @@
+ + - - -
- -
- - {{ charCount }} / {{ maxChars }} - - - {{ sendOnEnter ? "Enter 发送, Shift+Enter 换行" : "Ctrl+Enter 发送" }} -
@@ -190,7 +179,7 @@ const props = withDefaults( placeholder: "输入你的问题...", isStreaming: false, sendOnEnter: false, - maxChars: 4000, + maxChars: 10, disabled: false, // 默认全部支持 supports_thinking: true, @@ -231,6 +220,18 @@ const textareaRef = ref(null); const fileInputRef = ref(null); const imageInputRef = ref(null); +// toast 节流 +let lastToastTime = 0; +const toastThrottleMs = 2000; + +function showThrottledToast(message: string, type: 'error' = 'error') { + const now = Date.now(); + if (now - lastToastTime >= toastThrottleMs) { + lastToastTime = now; + window.$toast?.(message, type); + } +} + // 计算属性 const charCount = computed(() => inputText.value.length); const isUploading = computed(() => attachments.value.some((a) => a.uploading)); @@ -254,6 +255,27 @@ function autoResize() { textarea.style.height = `${Math.min(textarea.scrollHeight, maxHeight)+1}px`; } +// 处理输入前事件,限制字数 +function handleBeforeInput(event: InputEvent) { + // 如果不是插入文本的操作(如删除、退格等),允许 + if (!event.data) return; + + // 检查输入后是否会超过限制 + const currentLength = inputText.value.length; + const insertLength = event.data?.length || 0; + const selectionStart = (event.target as HTMLTextAreaElement).selectionStart || 0; + const selectionEnd = (event.target as HTMLTextAreaElement).selectionEnd || 0; + const selectedLength = selectionEnd - selectionStart; + + // 计算输入后的长度 + const newLength = currentLength - selectedLength + insertLength; + + if (newLength > props.maxChars) { + event.preventDefault(); + showThrottledToast(`已超${props.maxChars}字上限,请删除部分内容`); + } +} + // 处理键盘事件 function handleKeydown(event: KeyboardEvent) { // Ctrl+Enter 或 Cmd+Enter 发送 @@ -298,6 +320,22 @@ async function handlePaste(event: ClipboardEvent) { const items = event.clipboardData?.items; if (!items) return; + // 检查粘贴文本是否会超过字数限制 + const text = event.clipboardData?.getData('text'); + if (text) { + const textarea = event.target as HTMLTextAreaElement; + const selectionStart = textarea.selectionStart || 0; + const selectionEnd = textarea.selectionEnd || 0; + const selectedLength = selectionEnd - selectionStart; + const newLength = inputText.value.length - selectedLength + text.length; + + if (newLength > props.maxChars) { + event.preventDefault(); + showThrottledToast(`已超${props.maxChars}字上限,请删除部分内容`); + return; + } + } + for (const item of items) { if (item.type.startsWith("image/")) { event.preventDefault(); @@ -718,26 +756,6 @@ onMounted(() => { } } -.toolbar-right { - display: flex; - align-items: center; - gap: 16px; -} - -.char-count { - font-size: 12px; - color: #9ca3af; - - &.warning { - color: #f59e0b; - } -} - -.send-hint { - font-size: 12px; - color: #9ca3af; -} - @keyframes pulse { 0%, 100% { diff --git a/src/components/sidebar/ChatSidebar.vue b/src/components/sidebar/ChatSidebar.vue index c83f3b9..ab5cf35 100644 --- a/src/components/sidebar/ChatSidebar.vue +++ b/src/components/sidebar/ChatSidebar.vue @@ -279,7 +279,6 @@ if (typeof window !== "undefined") { position: relative; height: 100vh; background: #ffffff; - border-right: 1px solid #e2e8f0; transition: width 0.3s ease; overflow: hidden; flex-shrink: 0; @@ -690,8 +689,6 @@ if (typeof window !== "undefined") { cursor: col-resize; z-index: 10; - &:hover { - background: rgba(59, 130, 246, 0.3); - } + }