feat(chat): 优化历史会话列表并添加新建会话功能
- 重构 HistoryList 组件,使其在展开和折叠状态下均有更好展示 - 在 ChatModeSelector 中添加新建会话按钮 - 优化 ChatInterface 样式,提高输入区域可用性 - 调整 chat store 中的 startNewChat 方法逻辑
This commit is contained in:
parent
5aead55840
commit
c22eaf781c
|
@ -1,38 +1,68 @@
|
||||||
<template>
|
<template>
|
||||||
<el-menu-item-group class="history-item-group" v-show="!isCollapsed">
|
<!-- 展开状态 -->
|
||||||
<template #title>
|
<el-menu
|
||||||
<el-icon><Clock /></el-icon>
|
class="history-menu"
|
||||||
<span>历史会话</span>
|
:collapse="isCollapsed"
|
||||||
</template>
|
:default-active="chatStore.conversationId || ''"
|
||||||
<template v-if="currentModeHistory.length">
|
@select="handleSelect"
|
||||||
<el-menu-item
|
>
|
||||||
v-for="chat in currentModeHistory"
|
<el-menu-item-group class="history-item-group" v-if="!isCollapsed">
|
||||||
:key="chat.conversationId"
|
<template #title>
|
||||||
:index="chat.conversationId"
|
<el-icon><Clock /></el-icon>
|
||||||
class="history-item"
|
<span class="history-title">历史会话</span>
|
||||||
>
|
</template>
|
||||||
<div class="history-content">
|
<template v-if="currentModeHistory.length">
|
||||||
<span class="history-title">{{ formatChatTitle(chat) }}</span>
|
<el-menu-item
|
||||||
<el-button
|
v-for="chat in currentModeHistory"
|
||||||
class="delete-btn"
|
:key="chat.conversationId"
|
||||||
:icon="Delete"
|
:index="chat.conversationId"
|
||||||
link
|
class="history-item"
|
||||||
@click.stop="handleDelete(chat.conversationId)"
|
>
|
||||||
/>
|
<div class="history-item-content">
|
||||||
</div>
|
<span class="history-item-title">{{ formatChatTitle(chat) }}</span>
|
||||||
|
<el-button
|
||||||
|
class="delete-btn"
|
||||||
|
:icon="Delete"
|
||||||
|
link
|
||||||
|
@click.stop="handleDelete(chat.conversationId)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</el-menu-item>
|
||||||
|
</template>
|
||||||
|
<el-menu-item v-else disabled class="history-empty">
|
||||||
|
<span class="mode-name">暂无历史会话</span>
|
||||||
</el-menu-item>
|
</el-menu-item>
|
||||||
</template>
|
</el-menu-item-group>
|
||||||
<el-menu-item v-else disabled class="history-empty">
|
|
||||||
<span class="mode-name">暂无历史会话</span>
|
<!-- 折叠状态 -->
|
||||||
</el-menu-item>
|
<el-sub-menu v-else index="history" class="history-collapsed" popper-class="history-popper">
|
||||||
</el-menu-item-group>
|
<template #title>
|
||||||
|
<el-icon><Clock /></el-icon>
|
||||||
|
</template>
|
||||||
|
<template v-if="currentModeHistory.length">
|
||||||
|
<el-menu-item
|
||||||
|
v-for="chat in currentModeHistory"
|
||||||
|
:key="chat.conversationId"
|
||||||
|
:index="chat.conversationId"
|
||||||
|
class="history-collapsed-item"
|
||||||
|
:title="formatChatTitle(chat)"
|
||||||
|
>
|
||||||
|
<template #title>{{ formatChatTitle(chat) }}</template>
|
||||||
|
</el-menu-item>
|
||||||
|
</template>
|
||||||
|
<el-menu-item v-else disabled class="history-collapsed-empty">
|
||||||
|
<el-icon><InfoFilled /></el-icon>
|
||||||
|
<template #title>暂无历史会话</template>
|
||||||
|
</el-menu-item>
|
||||||
|
</el-sub-menu>
|
||||||
|
</el-menu>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { computed } from 'vue'
|
import { computed } from 'vue'
|
||||||
import { useChatStore } from '@/store/chat'
|
import { useChatStore } from '@/store/chat'
|
||||||
import { useSettingsStore } from '@/store/settings'
|
import { useSettingsStore } from '@/store/settings'
|
||||||
import { Clock, Delete } from '@element-plus/icons-vue'
|
import { Clock, Delete, InfoFilled } from '@element-plus/icons-vue'
|
||||||
import { ElMessageBox } from 'element-plus'
|
import { ElMessageBox } from 'element-plus'
|
||||||
|
|
||||||
const chatStore = useChatStore()
|
const chatStore = useChatStore()
|
||||||
|
@ -52,6 +82,12 @@ const formatChatTitle = (chat) => {
|
||||||
return `会话 ${chat.conversationId.substring(0, 8)}`
|
return `会话 ${chat.conversationId.substring(0, 8)}`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const handleSelect = (conversationId) => {
|
||||||
|
if (conversationId !== 'history') {
|
||||||
|
chatStore.switchConversation(conversationId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const handleDelete = async (conversationId) => {
|
const handleDelete = async (conversationId) => {
|
||||||
try {
|
try {
|
||||||
await ElMessageBox.confirm(
|
await ElMessageBox.confirm(
|
||||||
|
@ -72,9 +108,13 @@ const handleDelete = async (conversationId) => {
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
.history-menu {
|
||||||
|
background: transparent;
|
||||||
|
border: none;
|
||||||
|
padding: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
.history-item-group {
|
.history-item-group {
|
||||||
margin-top: 16px;
|
|
||||||
|
|
||||||
:deep(.el-menu-item-group__title) {
|
:deep(.el-menu-item-group__title) {
|
||||||
padding: 8px 12px !important;
|
padding: 8px 12px !important;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
|
@ -82,18 +122,21 @@ const handleDelete = async (conversationId) => {
|
||||||
color: var(--el-text-color-regular);
|
color: var(--el-text-color-regular);
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 8px;
|
|
||||||
line-height: 20px;
|
line-height: 20px;
|
||||||
|
|
||||||
.el-icon {
|
.el-icon {
|
||||||
font-size: 16px;
|
font-size: 18px;
|
||||||
margin-right: 2px;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(.el-menu-item-group__content) {
|
:deep(.el-menu-item-group__content) {
|
||||||
padding-left: 12px;
|
padding-left: 12px;
|
||||||
}
|
}
|
||||||
|
.history-title {
|
||||||
|
margin-left: 12px;
|
||||||
|
font-weight: bold;
|
||||||
|
color: var(--el-text-color-regular);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.history-item {
|
.history-item {
|
||||||
|
@ -102,7 +145,7 @@ const handleDelete = async (conversationId) => {
|
||||||
color: var(--el-text-color-regular);
|
color: var(--el-text-color-regular);
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
margin-bottom: 4px;
|
margin-bottom: 4px;
|
||||||
margin-left: 24px;
|
margin-left: 12px;
|
||||||
padding: 0 12px !important;
|
padding: 0 12px !important;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
transition: all 0.3s ease;
|
transition: all 0.3s ease;
|
||||||
|
@ -118,7 +161,7 @@ const handleDelete = async (conversationId) => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.history-content {
|
.history-item-content {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
|
@ -128,7 +171,7 @@ const handleDelete = async (conversationId) => {
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.history-title {
|
.history-item-title {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
@ -147,13 +190,12 @@ const handleDelete = async (conversationId) => {
|
||||||
height: 24px;
|
height: 24px;
|
||||||
width: 24px;
|
width: 24px;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
color: var(--el-text-color-secondary);
|
color: var(--el-text-color-regular);
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
color: var(--el-color-danger);
|
color: var(--el-color-danger);
|
||||||
background-color: var(--el-color-danger-light-9);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(.el-icon) {
|
:deep(.el-icon) {
|
||||||
|
@ -164,12 +206,16 @@ const handleDelete = async (conversationId) => {
|
||||||
.history-item:hover .delete-btn {
|
.history-item:hover .delete-btn {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
transform: translateX(0);
|
transform: translateX(0);
|
||||||
|
color: var(--el-color-regular);
|
||||||
|
&:hover {
|
||||||
|
color: var(--el-color-danger);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.history-empty {
|
.history-empty {
|
||||||
opacity: 0.6;
|
opacity: 0.6;
|
||||||
cursor: not-allowed;
|
cursor: not-allowed;
|
||||||
color: var(--el-text-color-secondary);
|
color: var(--el-text-color-regular);
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
padding: 0 12px !important;
|
padding: 0 12px !important;
|
||||||
margin-right: 12px;
|
margin-right: 12px;
|
||||||
|
@ -177,9 +223,61 @@ const handleDelete = async (conversationId) => {
|
||||||
line-height: 44px !important;
|
line-height: 44px !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 折叠状态样式
|
||||||
|
.history-collapsed {
|
||||||
|
:deep(.el-sub-menu__title) {
|
||||||
|
height: 40px;
|
||||||
|
line-height: 40px;
|
||||||
|
padding: 0 12px !important;
|
||||||
|
|
||||||
|
.el-icon {
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.history-popper {
|
||||||
|
border-radius: 8px;
|
||||||
|
}
|
||||||
|
.history-collapsed-item {
|
||||||
|
height: 40px !important;
|
||||||
|
line-height: 40px !important;
|
||||||
|
padding: 0 12px !important;
|
||||||
|
margin: 8px 12px;
|
||||||
|
border-radius: 8px;
|
||||||
|
color: var(--el-text-color-regular);
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: var(--el-fill-color-light);
|
||||||
|
color: var(--el-color-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.history-collapsed-empty {
|
||||||
|
@extend .history-collapsed-item;
|
||||||
|
opacity: 0.6;
|
||||||
|
cursor: not-allowed;
|
||||||
|
color: var(--el-text-color-secondary);
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: transparent;
|
||||||
|
color: var(--el-text-color-secondary);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 暗黑模式适配
|
// 暗黑模式适配
|
||||||
:deep(html.dark) {
|
:deep(html.dark) {
|
||||||
.history-item {
|
.history-collapsed-item {
|
||||||
&:hover {
|
&:hover {
|
||||||
background-color: var(--el-fill-color-darker);
|
background-color: var(--el-fill-color-darker);
|
||||||
}
|
}
|
||||||
|
@ -189,9 +287,5 @@ const handleDelete = async (conversationId) => {
|
||||||
color: var(--el-color-white);
|
color: var(--el-color-white);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.delete-btn:hover {
|
|
||||||
background-color: rgba(var(--el-color-danger-rgb), 0.2);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
|
@ -301,9 +301,9 @@ export const useChatStore = defineStore('chat', {
|
||||||
|
|
||||||
startNewChat() {
|
startNewChat() {
|
||||||
// 如果当前有活跃会话,将其标记为完成
|
// 如果当前有活跃会话,将其标记为完成
|
||||||
if (this.conversationId && this.messages[this.conversationId]) {
|
// if (this.conversationId && this.messages[this.conversationId]) {
|
||||||
this.messages[this.conversationId].conversationStatus = 'finished'
|
// this.messages[this.conversationId].conversationStatus = 'finished'
|
||||||
}
|
// }
|
||||||
|
|
||||||
// 只清除当前会话相关的消息缓存
|
// 只清除当前会话相关的消息缓存
|
||||||
if (this.conversationId) {
|
if (this.conversationId) {
|
||||||
|
|
|
@ -73,13 +73,6 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="input-area">
|
<div class="input-area">
|
||||||
<el-button
|
|
||||||
class="new-chat-btn"
|
|
||||||
@click="chatStore.startNewChat"
|
|
||||||
:disabled="newChatButtonsDisabled"
|
|
||||||
>
|
|
||||||
新会话
|
|
||||||
</el-button>
|
|
||||||
<el-input
|
<el-input
|
||||||
v-model="messageInput"
|
v-model="messageInput"
|
||||||
type="textarea"
|
type="textarea"
|
||||||
|
@ -153,12 +146,6 @@ const sendButtonsDisabled = computed(() => {
|
||||||
if (!currentConversation.conversationStatus) return false
|
if (!currentConversation.conversationStatus) return false
|
||||||
return ['finished', 'typing'].includes(currentConversation.conversationStatus)
|
return ['finished', 'typing'].includes(currentConversation.conversationStatus)
|
||||||
})
|
})
|
||||||
const newChatButtonsDisabled = computed(() => {
|
|
||||||
if (!chatStore.currentConversation) return false
|
|
||||||
const currentConversation = chatStore.currentConversation
|
|
||||||
if (!currentConversation.conversationStatus) return false
|
|
||||||
return ['typing'].includes(currentConversation.conversationStatus)
|
|
||||||
})
|
|
||||||
|
|
||||||
// 获取最后一条包含dafen字段的消息
|
// 获取最后一条包含dafen字段的消息
|
||||||
const lastMessageWithDafen = computed(() => {
|
const lastMessageWithDafen = computed(() => {
|
||||||
|
@ -684,52 +671,40 @@ html.dark .background-section .background-content {
|
||||||
}
|
}
|
||||||
|
|
||||||
.input-area {
|
.input-area {
|
||||||
position: absolute;
|
|
||||||
bottom: 0;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: flex-end;
|
align-items: flex-end;
|
||||||
gap: 12px;
|
gap: 8px;
|
||||||
padding: 16px;
|
padding: 16px 20px;
|
||||||
background: var(--el-color-primary-light-8);
|
|
||||||
border-top: 1px solid var(--el-border-color-light);
|
border-top: 1px solid var(--el-border-color-light);
|
||||||
z-index: 3;
|
background-color: var(--el-bg-color);
|
||||||
:deep(.el-textarea) {
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
|
||||||
|
.el-textarea {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
|
|
||||||
.el-textarea__inner {
|
:deep(.el-textarea__inner) {
|
||||||
min-height: 40px !important;
|
border-radius: 8px;
|
||||||
padding: 8px 12px;
|
|
||||||
font-size: 14px;
|
|
||||||
line-height: 1.5;
|
|
||||||
border-radius: 4px;
|
|
||||||
border-color: var(--el-border-color);
|
|
||||||
background-color: var(--el-bg-color);
|
|
||||||
transition: all 0.3s;
|
|
||||||
resize: none;
|
resize: none;
|
||||||
|
padding: 8px 12px;
|
||||||
&:hover {
|
min-height: 40px !important;
|
||||||
border-color: var(--el-border-color-hover);
|
max-height: 120px;
|
||||||
}
|
line-height: 24px;
|
||||||
|
font-size: 14px;
|
||||||
&:focus {
|
|
||||||
border-color: var(--el-color-primary);
|
|
||||||
box-shadow: 0 0 0 2px var(--el-color-primary-light-8);
|
|
||||||
}
|
|
||||||
|
|
||||||
&:disabled {
|
&:disabled {
|
||||||
background-color: var(--el-fill-color-light);
|
background-color: var(--el-input-disabled-bg);
|
||||||
border-color: var(--el-border-color-lighter);
|
|
||||||
color: var(--el-text-color-placeholder);
|
|
||||||
cursor: not-allowed;
|
cursor: not-allowed;
|
||||||
}
|
}
|
||||||
|
|
||||||
&::placeholder {
|
|
||||||
color: var(--el-text-color-placeholder);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.send-btn {
|
||||||
|
height: 40px;
|
||||||
|
padding: 0 20px;
|
||||||
|
border-radius: 8px;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dark mode override for input area
|
// Dark mode override for input area
|
||||||
|
|
|
@ -23,14 +23,19 @@
|
||||||
:collapse="settingsStore.sidebarCollapsed"
|
:collapse="settingsStore.sidebarCollapsed"
|
||||||
@select="selectMode"
|
@select="selectMode"
|
||||||
>
|
>
|
||||||
|
<el-menu-item class="mode-item new-chat-item" @click="handleNewChat">
|
||||||
|
<el-icon><Plus /></el-icon>
|
||||||
|
<span class="mode-name">新建会话</span>
|
||||||
|
</el-menu-item>
|
||||||
|
|
||||||
<el-menu-item v-for="mode in chatModes" :key="mode.id" :index="mode.id" class="mode-item">
|
<el-menu-item v-for="mode in chatModes" :key="mode.id" :index="mode.id" class="mode-item">
|
||||||
<el-icon><component :is="mode.icon" /></el-icon>
|
<el-icon><component :is="mode.icon" /></el-icon>
|
||||||
<span class="mode-name">{{ mode.name }}</span>
|
<span class="mode-name">{{ mode.name }}</span>
|
||||||
</el-menu-item>
|
</el-menu-item>
|
||||||
|
|
||||||
<HistoryList />
|
|
||||||
</el-menu>
|
</el-menu>
|
||||||
|
<HistoryList />
|
||||||
<!-- Settings Button Popover -->
|
<!-- Settings Button Popover -->
|
||||||
<el-popover
|
<el-popover
|
||||||
placement="top-end"
|
placement="top-end"
|
||||||
|
@ -57,7 +62,7 @@
|
||||||
import { useChatStore } from '@/store/chat'
|
import { useChatStore } from '@/store/chat'
|
||||||
import { useSettingsStore } from '@/store/settings'
|
import { useSettingsStore } from '@/store/settings'
|
||||||
import { computed, ref, onMounted, onUnmounted } from 'vue'
|
import { computed, ref, onMounted, onUnmounted } from 'vue'
|
||||||
import { ChatDotRound, ChatLineRound, ChatRound, Service, Setting, Clock, Delete } from '@element-plus/icons-vue'
|
import { ChatDotRound, ChatLineRound, ChatRound, Service, Setting, Clock, Delete, Plus } from '@element-plus/icons-vue'
|
||||||
import { ElMenu, ElMenuItem, ElIcon, ElPopover, ElMessageBox } from 'element-plus'
|
import { ElMenu, ElMenuItem, ElIcon, ElPopover, ElMessageBox } from 'element-plus'
|
||||||
import SettingsPanel from '@/components/settings/SettingsPanel.vue'
|
import SettingsPanel from '@/components/settings/SettingsPanel.vue'
|
||||||
import HistoryList from '@/components/chat/HistoryList.vue'
|
import HistoryList from '@/components/chat/HistoryList.vue'
|
||||||
|
@ -116,6 +121,10 @@ const selectMode = (id) => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const handleNewChat = () => {
|
||||||
|
chatStore.startNewChat()
|
||||||
|
}
|
||||||
|
|
||||||
const isMobile = ref(false)
|
const isMobile = ref(false)
|
||||||
|
|
||||||
const checkMobile = () => {
|
const checkMobile = () => {
|
||||||
|
@ -162,6 +171,7 @@ onUnmounted(() => {
|
||||||
padding: 0 16px;
|
padding: 0 16px;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
flex-shrink: 0;
|
||||||
|
|
||||||
&-title {
|
&-title {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
@ -186,8 +196,18 @@ onUnmounted(() => {
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
border: none;
|
border: none;
|
||||||
padding: 8px;
|
padding: 8px;
|
||||||
flex-grow: 1;
|
overflow: visible;
|
||||||
overflow-y: auto;
|
}
|
||||||
|
|
||||||
|
.new-chat-item {
|
||||||
|
margin-bottom: 12px !important;
|
||||||
|
border: 1px solid var(--el-border-color-lighter);
|
||||||
|
background-color: var(--el-fill-color-light) !important;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
box-shadow: var(--el-box-shadow-light);
|
||||||
|
color: var(--el-color-primary);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(.mode-item) {
|
:deep(.mode-item) {
|
||||||
|
@ -200,7 +220,7 @@ onUnmounted(() => {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
|
||||||
.el-icon {
|
.el-icon {
|
||||||
margin-right: 12px;
|
margin: 0;
|
||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
width: 18px;
|
width: 18px;
|
||||||
}
|
}
|
||||||
|
@ -216,11 +236,12 @@ onUnmounted(() => {
|
||||||
}
|
}
|
||||||
|
|
||||||
&:not(.is-active):hover {
|
&:not(.is-active):hover {
|
||||||
background-color: var(--el-color-primary-light-9);
|
background-color: var(--el-fill-color-light);
|
||||||
color: var(--el-color-primary);
|
color: var(--el-color-primary);
|
||||||
}
|
}
|
||||||
|
|
||||||
.mode-name {
|
.mode-name {
|
||||||
|
margin-left: 12px;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
|
@ -232,16 +253,98 @@ onUnmounted(() => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.mode-setting-btn {
|
.mode-selector.collapsed {
|
||||||
position: absolute;
|
.mode-header {
|
||||||
right: 8px;
|
padding: 0;
|
||||||
top: 50%;
|
display: flex;
|
||||||
transform: translateY(-50%);
|
align-items: center;
|
||||||
color: var(--el-text-color-secondary);
|
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;
|
||||||
|
margin-top: auto;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.settings-button {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
height: 40px;
|
||||||
|
width: 100%;
|
||||||
|
padding: 0 12px;
|
||||||
|
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;
|
||||||
|
|
||||||
|
.el-icon {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 18px;
|
||||||
|
width: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
|
background-color: var(--el-fill-color-light);
|
||||||
color: var(--el-color-primary);
|
color: var(--el-color-primary);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.button-text {
|
||||||
|
margin-left: 12px;
|
||||||
|
font-size: 14px;
|
||||||
|
white-space: nowrap;
|
||||||
|
opacity: 1;
|
||||||
|
transition: opacity 0.3s ease-in-out;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 移动端样式 */
|
/* 移动端样式 */
|
||||||
|
@ -307,7 +410,7 @@ onUnmounted(() => {
|
||||||
margin: 0 auto 4px auto;
|
margin: 0 auto 4px auto;
|
||||||
|
|
||||||
.el-icon {
|
.el-icon {
|
||||||
margin-right: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mode-name {
|
.mode-name {
|
||||||
|
@ -325,95 +428,6 @@ onUnmounted(() => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.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;
|
|
||||||
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;
|
|
||||||
|
|
||||||
.el-icon {
|
|
||||||
margin-right: 12px;
|
|
||||||
font-size: 18px;
|
|
||||||
width: 18px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
background-color: var(--el-fill-color-light);
|
|
||||||
color: var(--el-color-primary);
|
|
||||||
}
|
|
||||||
|
|
||||||
.button-text {
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
background-color: var(--el-fill-color-light);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<style lang="scss">
|
|
||||||
.settings-popover-popper {
|
|
||||||
min-width: 350px !important;
|
|
||||||
padding: 0 !important;
|
|
||||||
border: none !important;
|
|
||||||
box-shadow: var(--el-box-shadow-light);
|
|
||||||
border-radius: 8px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<style lang="scss">
|
|
||||||
/* Dark mode override */
|
|
||||||
html.dark .mode-selector {
|
|
||||||
background-color: var(--el-color-primary-dark-2);
|
|
||||||
border-right-color: var(--el-border-color-dark);
|
|
||||||
|
|
||||||
/* Dark mode hover */
|
|
||||||
.mode-menu :deep(.el-menu-item):not(.is-active):hover {
|
|
||||||
background-color: var(--el-fill-color);
|
|
||||||
color: var(--el-color-primary);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
.history-content {
|
.history-content {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
@ -466,4 +480,28 @@ html.dark .mode-selector {
|
||||||
opacity: 0.6;
|
opacity: 0.6;
|
||||||
cursor: not-allowed;
|
cursor: not-allowed;
|
||||||
}
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.settings-popover-popper {
|
||||||
|
min-width: 350px !important;
|
||||||
|
padding: 0 !important;
|
||||||
|
border: none !important;
|
||||||
|
box-shadow: var(--el-box-shadow-light);
|
||||||
|
border-radius: 8px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
/* Dark mode override */
|
||||||
|
html.dark .mode-selector {
|
||||||
|
background-color: var(--el-color-primary-dark-2);
|
||||||
|
border-right-color: var(--el-border-color-dark);
|
||||||
|
|
||||||
|
/* Dark mode hover */
|
||||||
|
.mode-menu :deep(.el-menu-item):not(.is-active):hover {
|
||||||
|
background-color: var(--el-fill-color);
|
||||||
|
color: var(--el-color-primary);
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
Loading…
Reference in New Issue