From 5aead55840ba19c06470ae8e5fe065f135be5317 Mon Sep 17 00:00:00 2001 From: Lexcubia Date: Fri, 25 Apr 2025 12:16:02 +0800 Subject: [PATCH] =?UTF-8?q?refactor(components):=20=E9=87=8D=E6=9E=84?= =?UTF-8?q?=E5=8E=86=E5=8F=B2=E4=BC=9A=E8=AF=9D=E7=BB=84=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 移除 HistoryButton 组件,创建新的 HistoryList 组件 - 更新 ChatHeader 和 ChatModeSelector 组件,集成新的 HistoryList 组件 - 优化历史会话的展示和交互逻辑 --- src/components/chat/HistoryButton.vue | 196 ------------- src/components/chat/HistoryList.vue | 197 +++++++++++++ src/views/chat/ChatHeader.vue | 22 -- src/views/chat/ChatModeSelector.vue | 408 ++++++++------------------ 4 files changed, 314 insertions(+), 509 deletions(-) delete mode 100644 src/components/chat/HistoryButton.vue create mode 100644 src/components/chat/HistoryList.vue diff --git a/src/components/chat/HistoryButton.vue b/src/components/chat/HistoryButton.vue deleted file mode 100644 index 56bb10b..0000000 --- a/src/components/chat/HistoryButton.vue +++ /dev/null @@ -1,196 +0,0 @@ - - - - - \ No newline at end of file diff --git a/src/components/chat/HistoryList.vue b/src/components/chat/HistoryList.vue new file mode 100644 index 0000000..5859bad --- /dev/null +++ b/src/components/chat/HistoryList.vue @@ -0,0 +1,197 @@ + + + + + \ No newline at end of file diff --git a/src/views/chat/ChatHeader.vue b/src/views/chat/ChatHeader.vue index b84feb5..beceffa 100644 --- a/src/views/chat/ChatHeader.vue +++ b/src/views/chat/ChatHeader.vue @@ -19,7 +19,6 @@
- { font-weight: normal; flex-shrink: 0; } - - .title-history-btn { - :deep(.history-btn) { - height: 32px; - padding: 0 12px; - color: var(--el-text-color-secondary); - transition: all 0.3s ease; - font-size: 14px; - - &:hover { - color: var(--el-color-primary); - background-color: var(--el-color-primary-light-9); - } - - :deep(.el-icon) { - font-size: 16px; - margin-right: 4px; - } - } - } } .actions { diff --git a/src/views/chat/ChatModeSelector.vue b/src/views/chat/ChatModeSelector.vue index 5688b53..cd6ba02 100644 --- a/src/views/chat/ChatModeSelector.vue +++ b/src/views/chat/ChatModeSelector.vue @@ -27,6 +27,8 @@ {{ mode.name }} + + @@ -55,9 +57,10 @@ import { useChatStore } from '@/store/chat' import { useSettingsStore } from '@/store/settings' import { computed, ref, onMounted, onUnmounted } from 'vue' -import { ChatDotRound, ChatLineRound, ChatRound, Service, Setting } from '@element-plus/icons-vue' -import { ElMenu, ElMenuItem, ElIcon, ElPopover } from 'element-plus' +import { ChatDotRound, ChatLineRound, ChatRound, Service, Setting, Clock, Delete } from '@element-plus/icons-vue' +import { ElMenu, ElMenuItem, ElIcon, ElPopover, ElMessageBox } from 'element-plus' import SettingsPanel from '@/components/settings/SettingsPanel.vue' +import HistoryList from '@/components/chat/HistoryList.vue' const chatStore = useChatStore() const settingsStore = useSettingsStore() @@ -77,8 +80,40 @@ const currentModeHistory = computed(() => { return chatStore.conversations.filter(chat => chat.mode === chatStore.currentMode) }) -const selectMode = (modeId) => { - chatStore.setCurrentMode(modeId) +const formatChatTitle = (chat) => { + if (chat.messages && chat.messages.length > 0) { + const firstMessage = chat.messages[0].question + return firstMessage.length > 20 ? firstMessage.substring(0, 20) + '...' : firstMessage + } + return `会话 ${chat.conversationId.substring(0, 8)}` +} + +const handleDelete = async (conversationId) => { + try { + await ElMessageBox.confirm( + '确定要删除这个会话吗?删除后无法恢复。', + '删除确认', + { + confirmButtonText: '确定', + cancelButtonText: '取消', + type: 'warning', + confirmButtonClass: 'el-button--danger' + } + ) + chatStore.deleteConversation(conversationId) + } catch { + // 用户取消删除 + } +} + +const selectMode = (id) => { + // 检查是否是会话ID + const isConversationId = chatStore.conversations.some(chat => chat.conversationId === id) + if (isConversationId) { + chatStore.switchConversation(id) + } else { + chatStore.setCurrentMode(id) + } } const isMobile = ref(false) @@ -153,310 +188,46 @@ onUnmounted(() => { padding: 8px; flex-grow: 1; overflow-y: auto; - - :deep(.el-menu-item) { - height: 44px; - line-height: 44px; - color: var(--el-text-color-regular); - border-radius: 8px; - margin-bottom: 4px; - padding: 0 12px !important; - overflow: hidden; - - .el-icon { - margin-right: 12px; - font-size: 18px; - width: 18px; - } - - &.is-active { - background-image: linear-gradient(135deg, var(--el-color-primary) 0%, var(--el-color-primary-light-3) 100%); - color: var(--el-color-white); - box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2); - - .el-icon { - color: var(--el-color-white); - } - } - - &:not(.is-active):hover { - background-color: var(--el-color-primary-light-9); - color: var(--el-color-primary); - } - - .mode-name { - font-size: 14px; - margin-left: 12px; - white-space: nowrap; - opacity: 1; - transform: translateX(0); - - body:not(.no-animations) & { - transition: opacity 0.3s ease-in-out; - } - } - } } -.mode-setting-btn { - position: absolute; - right: 8px; - top: 50%; - transform: translateY(-50%); - color: var(--el-text-color-secondary); - - &:hover { - color: var(--el-color-primary); - } -} - -/* 移动端样式 */ -@media screen and (max-width: 768px) { - .mode-selector-backdrop { - position: fixed; - top: 0; - left: 0; - right: 0; - bottom: 0; - background-color: var(--el-overlay-color-lighter); - z-index: 9; - display: none; - - &.visible { - display: block; - } - } - - .mode-selector { - position: fixed; - left: 0; - top: 0; - - &.collapsed { - transform: translateX(-100%); - } - } -} - -.mode-selector.collapsed { - .mode-header { - padding: 0; - display: flex; - align-items: center; - justify-content: center; - height: 60px; - - .mode-header-collapsed-logo { - display: flex; - align-items: center; - height: 100%; - } - - .mode-header-icon.collapsed { - height: 32px; - filter: drop-shadow(0 0 0.75em rgba(var(--el-color-primary-rgb), 0.6)); - vertical-align: middle; - } - } - - .mode-menu { - padding: 8px 12px; - } - - :deep(.el-menu-item) { - width: 40px; - height: 40px; - padding: 0 !important; - display: flex; - align-items: center; - justify-content: center; - margin: 0 auto 4px auto; - - .el-icon { - margin-right: 0; - } - - .mode-name { - display: none; - } - } - - .settings-button { - width: 40px; - height: 40px; - .mode-name, - .button-text { - opacity: 0; - } - } -} - -.sidebar-footer { - height: 48px; - padding: 0 12px; - display: flex; - align-items: center; - justify-content: center; -} - -.settings-button { - display: flex; - align-items: center; - height: 40px; - width: 100%; - padding: 0 12px; +:deep(.mode-item) { + height: 44px; + line-height: 44px; color: var(--el-text-color-regular); border-radius: 8px; - cursor: pointer; - transition: background-color 0.2s ease-in-out, color 0.2s ease-in-out; + margin-bottom: 4px; + padding: 0 12px !important; + overflow: hidden; .el-icon { margin-right: 12px; font-size: 18px; width: 18px; } + + &.is-active { + background-image: linear-gradient(135deg, var(--el-color-primary) 0%, var(--el-color-primary-light-3) 100%); + color: var(--el-color-white); + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2); - &:hover { - background-color: var(--el-fill-color-light); + .el-icon { + color: var(--el-color-white); + } + } + + &:not(.is-active):hover { + background-color: var(--el-color-primary-light-9); color: var(--el-color-primary); } - - .button-text { + + .mode-name { font-size: 14px; white-space: nowrap; opacity: 1; - transition: opacity 0.3s ease-in-out; - } -} - -.mode-selector.collapsed { - .sidebar-footer { - padding: 0; - } - - .settings-button { - justify-content: center; - width: 40px; - padding: 0; - - .el-icon { - margin-right: 0; - } - - .button-text { - opacity: 0; - pointer-events: none; - } + transform: translateX(0); - &:hover { - background-color: var(--el-fill-color-light); - } - } -} - - - - - + + \ No newline at end of file