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); - } + }