919 lines
24 KiB
Vue
919 lines
24 KiB
Vue
<script setup lang="ts">
|
||
import type { ConversationItem } from 'vue-element-plus-x/types/Conversations';
|
||
import type { ChatSessionVo } from '@/api/session/types';
|
||
import { ChatLineSquare, Expand, Fold, MoreFilled, Plus } from '@element-plus/icons-vue';
|
||
import { useRoute, useRouter } from 'vue-router';
|
||
import { get_session } from '@/api';
|
||
import { useDesignStore } from '@/stores';
|
||
import { useSessionStore } from '@/stores/modules/session';
|
||
|
||
const route = useRoute();
|
||
const router = useRouter();
|
||
const designStore = useDesignStore();
|
||
const sessionStore = useSessionStore();
|
||
|
||
const sessionId = computed(() => route.params?.id);
|
||
const conversationsList = computed(() => sessionStore.sessionList);
|
||
const loadMoreLoading = computed(() => sessionStore.isLoadingMore);
|
||
const active = ref<string | undefined>();
|
||
const isCollapsed = computed(() => designStore.isCollapseConversationList);
|
||
|
||
onMounted(async () => {
|
||
await sessionStore.requestSessionList();
|
||
if (conversationsList.value.length > 0 && sessionId.value) {
|
||
const currentSessionRes = await get_session(`${sessionId.value}`);
|
||
sessionStore.setCurrentSession(currentSessionRes.data);
|
||
}
|
||
});
|
||
|
||
watch(
|
||
() => sessionStore.currentSession,
|
||
(newValue) => {
|
||
active.value = newValue ? `${newValue.id}` : undefined;
|
||
},
|
||
);
|
||
|
||
// 创建会话
|
||
function handleCreatChat() {
|
||
sessionStore.createSessionBtn();
|
||
}
|
||
|
||
// 切换会话
|
||
function handleChange(item: ConversationItem<ChatSessionVo>) {
|
||
sessionStore.setCurrentSession(item);
|
||
router.replace({
|
||
name: 'chatConversationWithId',
|
||
params: {
|
||
id: item.id,
|
||
},
|
||
});
|
||
}
|
||
|
||
// 处理组件触发的加载更多事件
|
||
async function handleLoadMore() {
|
||
if (!sessionStore.hasMore)
|
||
return;
|
||
await sessionStore.loadMoreSessions();
|
||
}
|
||
|
||
// 右键菜单
|
||
function handleMenuCommand(command: string, item: ConversationItem<ChatSessionVo>) {
|
||
switch (command) {
|
||
case 'delete':
|
||
ElMessageBox.confirm('删除后,聊天记录将不可恢复。', '确定删除对话?', {
|
||
confirmButtonText: '确定',
|
||
cancelButtonText: '取消',
|
||
type: 'warning',
|
||
confirmButtonClass: 'el-button--danger',
|
||
cancelButtonClass: 'el-button--info',
|
||
roundButton: true,
|
||
autofocus: false,
|
||
})
|
||
.then(() => {
|
||
sessionStore.deleteSessions([item.id!]);
|
||
nextTick(() => {
|
||
if (item.id === active.value) {
|
||
sessionStore.createSessionBtn();
|
||
}
|
||
});
|
||
})
|
||
.catch(() => {
|
||
// 取消删除
|
||
});
|
||
break;
|
||
case 'rename':
|
||
ElMessageBox.prompt('', '编辑对话名称', {
|
||
confirmButtonText: '确定',
|
||
cancelButtonText: '取消',
|
||
inputErrorMessage: '请输入对话名称',
|
||
confirmButtonClass: 'el-button--primary',
|
||
cancelButtonClass: 'el-button--info',
|
||
roundButton: true,
|
||
inputValue: item.sessionTitle,
|
||
autofocus: false,
|
||
inputValidator: (value) => {
|
||
return !!value;
|
||
},
|
||
}).then(({ value }) => {
|
||
sessionStore
|
||
.updateSession({
|
||
id: item.id!,
|
||
sessionTitle: value,
|
||
sessionContent: item.sessionContent,
|
||
})
|
||
.then(() => {
|
||
ElMessage({
|
||
type: 'success',
|
||
message: '修改成功',
|
||
});
|
||
nextTick(() => {
|
||
if (sessionStore.currentSession?.id === item.id) {
|
||
sessionStore.setCurrentSession({
|
||
...item,
|
||
sessionTitle: value,
|
||
});
|
||
}
|
||
});
|
||
});
|
||
});
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
}
|
||
|
||
// 折叠/展开侧边栏
|
||
function toggleSidebar() {
|
||
// designStore.setIsCollapseConversationList(!designStore.isCollapseConversationList);
|
||
}
|
||
|
||
// 点击logo创建新会话(仅在折叠状态)
|
||
function handleLogoClick() {
|
||
if (isCollapsed.value) {
|
||
handleCreatChat();
|
||
}
|
||
}
|
||
|
||
// 处理右键菜单(折叠状态下使用)
|
||
function handleContextMenu(event: MouseEvent, item: ConversationItem<ChatSessionVo>) {
|
||
event.preventDefault();
|
||
// 在折叠状态下触发删除确认
|
||
ElMessageBox.confirm('删除后,聊天记录将不可恢复。', '确定删除对话?', {
|
||
confirmButtonText: '确定',
|
||
cancelButtonText: '取消',
|
||
type: 'warning',
|
||
confirmButtonClass: 'el-button--danger',
|
||
cancelButtonClass: 'el-button--info',
|
||
roundButton: true,
|
||
autofocus: false,
|
||
})
|
||
.then(() => {
|
||
sessionStore.deleteSessions([item.id!]);
|
||
nextTick(() => {
|
||
if (item.id === active.value) {
|
||
sessionStore.createSessionBtn();
|
||
}
|
||
});
|
||
})
|
||
.catch(() => {
|
||
// 取消删除
|
||
});
|
||
}
|
||
|
||
// 折叠状态下点击更多按钮
|
||
function handleCollapsedMenuClick(event: MouseEvent, item: ConversationItem<ChatSessionVo>) {
|
||
event.stopPropagation();
|
||
|
||
// 创建一个简单的菜单
|
||
ElMessageBox({
|
||
title: '对话操作',
|
||
message: `
|
||
<div style="padding: 8px 0;">
|
||
<div class="menu-item" data-action="rename" style="padding: 8px 12px; cursor: pointer; border-radius: 4px; margin: 4px 0;">
|
||
<span style="font-size: 14px;">重命名</span>
|
||
</div>
|
||
<div class="menu-item" data-action="delete" style="padding: 8px 12px; cursor: pointer; border-radius: 4px; margin: 4px 0; color: #f56c6c;">
|
||
<span style="font-size: 14px;">删除对话</span>
|
||
</div>
|
||
</div>
|
||
`,
|
||
showConfirmButton: false,
|
||
showCancelButton: false,
|
||
dangerouslyUseHTMLString: true,
|
||
customClass: 'collapsed-menu-dialog',
|
||
closeOnClickModal: true,
|
||
closeOnPressEscape: true,
|
||
}).then(() => {
|
||
// 对话框关闭
|
||
}).catch(() => {
|
||
// 对话框关闭
|
||
});
|
||
|
||
// 添加菜单项点击事件
|
||
nextTick(() => {
|
||
const menuItems = document.querySelectorAll('.menu-item');
|
||
menuItems.forEach((itemEl) => {
|
||
itemEl.addEventListener('click', (e) => {
|
||
const action = (e.currentTarget as HTMLElement).dataset.action;
|
||
if (action === 'delete') {
|
||
ElMessageBox.confirm('删除后,聊天记录将不可恢复。', '确定删除对话?', {
|
||
confirmButtonText: '确定',
|
||
cancelButtonText: '取消',
|
||
type: 'warning',
|
||
confirmButtonClass: 'el-button--danger',
|
||
cancelButtonClass: 'el-button--info',
|
||
roundButton: true,
|
||
autofocus: false,
|
||
})
|
||
.then(() => {
|
||
sessionStore.deleteSessions([item.id!]);
|
||
nextTick(() => {
|
||
if (item.id === active.value) {
|
||
sessionStore.createSessionBtn();
|
||
}
|
||
});
|
||
})
|
||
.catch(() => {
|
||
// 取消删除
|
||
});
|
||
}
|
||
else if (action === 'rename') {
|
||
ElMessageBox.prompt('', '编辑对话名称', {
|
||
confirmButtonText: '确定',
|
||
cancelButtonText: '取消',
|
||
inputErrorMessage: '请输入对话名称',
|
||
confirmButtonClass: 'el-button--primary',
|
||
cancelButtonClass: 'el-button--info',
|
||
roundButton: true,
|
||
inputValue: item.sessionTitle,
|
||
autofocus: false,
|
||
inputValidator: (value) => {
|
||
return !!value;
|
||
},
|
||
}).then(({ value }) => {
|
||
sessionStore
|
||
.updateSession({
|
||
id: item.id!,
|
||
sessionTitle: value,
|
||
sessionContent: item.sessionContent,
|
||
})
|
||
.then(() => {
|
||
ElMessage({
|
||
type: 'success',
|
||
message: '修改成功',
|
||
});
|
||
nextTick(() => {
|
||
if (sessionStore.currentSession?.id === item.id) {
|
||
sessionStore.setCurrentSession({
|
||
...item,
|
||
sessionTitle: value,
|
||
});
|
||
}
|
||
});
|
||
});
|
||
});
|
||
}
|
||
|
||
// 关闭菜单对话框
|
||
document.querySelector('.collapsed-menu-dialog .el-message-box__headerbtn')?.dispatchEvent(new Event('click'));
|
||
});
|
||
});
|
||
});
|
||
}
|
||
</script>
|
||
|
||
<template>
|
||
<div
|
||
class="aside-container"
|
||
:class="{ 'aside-collapsed': isCollapsed }"
|
||
>
|
||
<div class="aside-wrapper">
|
||
<!-- 头部 -->
|
||
<div class="aside-header">
|
||
<!-- 展开状态显示logo和标题 -->
|
||
<div
|
||
v-if="!isCollapsed"
|
||
class="header-content-expanded flex items-center gap-8px hover:cursor-pointer"
|
||
@click="handleCreatChat"
|
||
>
|
||
<span class="logo-text max-w-150px text-overflow">会话</span>
|
||
</div>
|
||
|
||
<!-- 折叠状态只显示logo -->
|
||
<div
|
||
v-else
|
||
class="header-content-collapsed flex items-center justify-center hover:cursor-pointer"
|
||
@click="handleLogoClick"
|
||
>
|
||
<el-icon size="20">
|
||
<ChatLineSquare />
|
||
</el-icon>
|
||
</div>
|
||
|
||
<!-- 折叠按钮 -->
|
||
<el-tooltip
|
||
:content="isCollapsed ? '展开侧边栏' : '折叠侧边栏'"
|
||
placement="bottom"
|
||
>
|
||
<el-button
|
||
class="collapse-btn"
|
||
type="text"
|
||
@click="toggleSidebar"
|
||
>
|
||
<el-icon v-if="isCollapsed">
|
||
<Expand />
|
||
</el-icon>
|
||
<el-icon v-else>
|
||
<Fold />
|
||
</el-icon>
|
||
</el-button>
|
||
</el-tooltip>
|
||
</div>
|
||
|
||
<!-- 内容区域 -->
|
||
<div class="aside-body">
|
||
<!-- 创建会话按钮 -->
|
||
<div class="creat-chat-btn-wrapper">
|
||
<div
|
||
class="creat-chat-btn"
|
||
:class="{ 'creat-chat-btn-collapsed': isCollapsed }"
|
||
@click="handleCreatChat"
|
||
>
|
||
<el-icon class="add-icon">
|
||
<Plus />
|
||
</el-icon>
|
||
<span v-if="!isCollapsed" class="creat-chat-text">
|
||
新对话
|
||
</span>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 会话列表 -->
|
||
<div class="aside-content">
|
||
<div v-if="conversationsList.length > 0" class="conversations-wrap">
|
||
<Conversations
|
||
v-model:active="active"
|
||
:items="conversationsList"
|
||
:label-max-width="isCollapsed ? 0 : 140"
|
||
:show-tooltip="!isCollapsed"
|
||
:tooltip-offset="60"
|
||
show-built-in-menu
|
||
groupable
|
||
row-key="id"
|
||
label-key="sessionTitle"
|
||
:tooltip-placement="isCollapsed ? 'right-start' : 'right'"
|
||
:load-more="handleLoadMore"
|
||
:load-more-loading="loadMoreLoading"
|
||
:items-style="{
|
||
marginLeft: '8px',
|
||
marginRight: '8px',
|
||
userSelect: 'none',
|
||
borderRadius: isCollapsed ? '12px' : '10px',
|
||
padding: isCollapsed ? '12px 8px' : '8px 12px',
|
||
justifyContent: isCollapsed ? 'center' : 'space-between',
|
||
width: isCollapsed ? '64px' : 'auto',
|
||
height: isCollapsed ? '64px' : 'auto',
|
||
minHeight: '48px',
|
||
flexDirection: isCollapsed ? 'column' : 'row',
|
||
position: 'relative',
|
||
overflow: 'hidden',
|
||
}"
|
||
:items-active-style="{
|
||
backgroundColor: '#fff',
|
||
boxShadow: '0 1px 2px rgba(0, 0, 0, 0.05)',
|
||
color: 'rgba(0, 0, 0, 0.85)',
|
||
}"
|
||
:items-hover-style="{
|
||
backgroundColor: 'rgba(0, 0, 0, 0.04)',
|
||
}"
|
||
@menu-command="handleMenuCommand"
|
||
@change="handleChange"
|
||
@contextmenu="handleContextMenu"
|
||
>
|
||
<!-- 自定义折叠状态下的会话项内容 -->
|
||
<template #default="{ item }">
|
||
<div class="conversation-item-content">
|
||
<div v-if="isCollapsed" class="collapsed-item">
|
||
<div
|
||
class="avatar-circle"
|
||
@click="handleChange(item)"
|
||
@contextmenu="(e) => handleContextMenu(e, item)"
|
||
>
|
||
{{ item.sessionTitle?.charAt(0) || 'A' }}
|
||
</div>
|
||
<div v-if="item.unreadCount" class="unread-indicator">
|
||
{{ item.unreadCount > 99 ? '99+' : item.unreadCount }}
|
||
</div>
|
||
<!-- 折叠状态下的更多操作按钮 -->
|
||
<div
|
||
class="collapsed-menu-trigger"
|
||
@click.stop="(e) => handleCollapsedMenuClick(e, item)"
|
||
@contextmenu.stop="(e) => handleContextMenu(e, item)"
|
||
>
|
||
<el-icon size="14">
|
||
<MoreFilled />
|
||
</el-icon>
|
||
</div>
|
||
</div>
|
||
<div v-else class="expanded-item">
|
||
<div class="conversation-info">
|
||
<div class="conversation-title">
|
||
{{ item.sessionTitle }}
|
||
</div>
|
||
<div v-if="item.sessionContent" class="conversation-preview">
|
||
{{ item.sessionContent.substring(0, 30) }}{{ item.sessionContent.length > 30 ? '...' : '' }}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
</Conversations>
|
||
</div>
|
||
|
||
<el-empty
|
||
v-else
|
||
class="h-full flex-center"
|
||
:description="isCollapsed ? '' : '暂无对话记录'"
|
||
>
|
||
<template #description>
|
||
<span v-if="!isCollapsed">暂无对话记录</span>
|
||
</template>
|
||
</el-empty>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<style scoped lang="scss">
|
||
// 基础样式
|
||
.aside-container {
|
||
height: 100%;
|
||
border-right: 0.5px solid var(--s-color-border-tertiary, rgb(0 0 0 / 8%));
|
||
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||
overflow: hidden;
|
||
flex-shrink: 0;
|
||
background-color: var(--sidebar-background-color, #f9fafb);
|
||
|
||
// 展开状态 - 240px
|
||
&:not(.aside-collapsed) {
|
||
width: 240px;
|
||
|
||
.aside-wrapper {
|
||
width: 240px;
|
||
}
|
||
}
|
||
|
||
// 折叠状态 - 100px
|
||
&.aside-collapsed {
|
||
width: 100px;
|
||
|
||
.aside-wrapper {
|
||
width: 100px;
|
||
}
|
||
}
|
||
}
|
||
|
||
.aside-wrapper {
|
||
display: flex;
|
||
flex-direction: column;
|
||
height: 100%;
|
||
transition: width 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||
}
|
||
|
||
// 头部样式
|
||
.aside-header {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
height: 56px;
|
||
padding: 0 12px;
|
||
border-bottom: 1px solid var(--s-color-border-tertiary, rgb(0 0 0 / 8%));
|
||
//background-color: var(--sidebar-header-bg, #ffffff);
|
||
|
||
.header-content-expanded {
|
||
flex: 1;
|
||
}
|
||
|
||
.header-content-collapsed {
|
||
width: 36px;
|
||
height: 36px;
|
||
border-radius: 8px;
|
||
transition: background-color 0.2s ease;
|
||
|
||
&:hover {
|
||
background-color: rgba(0, 0, 0, 0.04);
|
||
}
|
||
|
||
.el-icon {
|
||
color: var(--el-text-color-secondary);
|
||
}
|
||
}
|
||
|
||
.logo-text {
|
||
font-size: 16px;
|
||
font-weight: 700;
|
||
color: rgb(0 0 0 / 85%);
|
||
transform: skewX(-2deg);
|
||
}
|
||
|
||
.collapse-btn {
|
||
width: 32px;
|
||
height: 32px;
|
||
padding: 0;
|
||
color: var(--el-text-color-secondary);
|
||
transition: transform 0.2s ease;
|
||
|
||
&:hover {
|
||
color: var(--el-text-color-primary);
|
||
background-color: var(--el-fill-color-light);
|
||
transform: scale(1.1);
|
||
}
|
||
|
||
.el-icon {
|
||
font-size: 18px;
|
||
}
|
||
}
|
||
}
|
||
|
||
// 内容区域
|
||
.aside-body {
|
||
flex: 1;
|
||
display: flex;
|
||
flex-direction: column;
|
||
padding: 0 4px;
|
||
overflow: hidden;
|
||
|
||
.creat-chat-btn-wrapper {
|
||
padding: 12px 8px 4px;
|
||
|
||
.creat-chat-btn {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
height: 40px;
|
||
color: #0057ff;
|
||
cursor: pointer;
|
||
user-select: none;
|
||
background-color: rgb(0 87 255 / 6%);
|
||
border: 1px solid rgb(0 102 255 / 15%);
|
||
border-radius: 12px;
|
||
transition: all 0.2s ease;
|
||
|
||
&:hover {
|
||
background-color: rgb(0 87 255 / 12%);
|
||
transform: translateY(-1px);
|
||
}
|
||
|
||
&.creat-chat-btn-collapsed {
|
||
width: 40px;
|
||
height: 40px;
|
||
border-radius: 50%;
|
||
margin: 0 auto;
|
||
}
|
||
|
||
.add-icon {
|
||
width: 24px;
|
||
height: 24px;
|
||
font-size: 16px;
|
||
}
|
||
|
||
.creat-chat-text {
|
||
font-size: 14px;
|
||
font-weight: 700;
|
||
line-height: 22px;
|
||
margin-left: 6px;
|
||
transition: opacity 0.2s ease;
|
||
}
|
||
}
|
||
}
|
||
|
||
.aside-content {
|
||
flex: 1;
|
||
display: flex;
|
||
flex-direction: column;
|
||
min-height: 0;
|
||
overflow: hidden;
|
||
|
||
.conversations-wrap {
|
||
flex: 1;
|
||
overflow-y: auto;
|
||
overflow-x: hidden;
|
||
padding: 0 4px;
|
||
|
||
&::-webkit-scrollbar {
|
||
width: 4px;
|
||
}
|
||
|
||
&::-webkit-scrollbar-track {
|
||
background: transparent;
|
||
}
|
||
|
||
&::-webkit-scrollbar-thumb {
|
||
background: rgba(0, 0, 0, 0.1);
|
||
border-radius: 2px;
|
||
}
|
||
|
||
&:hover::-webkit-scrollbar-thumb {
|
||
background: rgba(0, 0, 0, 0.2);
|
||
}
|
||
|
||
.conversation-item-content {
|
||
width: 100%;
|
||
height: 100%;
|
||
|
||
.collapsed-item {
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
justify-content: center;
|
||
position: relative;
|
||
width: 100%;
|
||
height: 100%;
|
||
|
||
.avatar-circle {
|
||
width: 36px;
|
||
height: 36px;
|
||
border-radius: 50%;
|
||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||
color: white;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
font-size: 14px;
|
||
font-weight: 600;
|
||
cursor: pointer;
|
||
transition: transform 0.2s ease;
|
||
|
||
&:hover {
|
||
transform: scale(1.05);
|
||
}
|
||
}
|
||
|
||
.unread-indicator {
|
||
position: absolute;
|
||
top: 2px;
|
||
right: 2px;
|
||
min-width: 16px;
|
||
height: 16px;
|
||
padding: 0 4px;
|
||
background-color: #ff4d4f;
|
||
color: white;
|
||
border-radius: 8px;
|
||
font-size: 10px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
z-index: 1;
|
||
font-weight: 600;
|
||
}
|
||
|
||
.collapsed-menu-trigger {
|
||
position: absolute;
|
||
bottom: 4px;
|
||
right: 4px;
|
||
width: 20px;
|
||
height: 20px;
|
||
border-radius: 50%;
|
||
background-color: rgba(0, 0, 0, 0.05);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
cursor: pointer;
|
||
opacity: 0;
|
||
transition: all 0.2s ease;
|
||
z-index: 2;
|
||
|
||
.el-icon {
|
||
color: var(--el-text-color-secondary);
|
||
font-size: 12px;
|
||
}
|
||
|
||
&:hover {
|
||
background-color: rgba(0, 0, 0, 0.1);
|
||
opacity: 1;
|
||
}
|
||
}
|
||
|
||
&:hover .collapsed-menu-trigger {
|
||
opacity: 0.7;
|
||
}
|
||
}
|
||
|
||
.expanded-item {
|
||
display: flex;
|
||
align-items: center;
|
||
width: 100%;
|
||
min-width: 0;
|
||
|
||
.conversation-info {
|
||
flex: 1;
|
||
min-width: 0;
|
||
margin-right: 8px;
|
||
overflow: hidden;
|
||
|
||
.conversation-title {
|
||
font-size: 14px;
|
||
font-weight: 500;
|
||
color: var(--el-text-color-primary);
|
||
line-height: 1.4;
|
||
margin-bottom: 4px;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
max-width: 100%;
|
||
}
|
||
|
||
.conversation-preview {
|
||
font-size: 12px;
|
||
color: var(--el-text-color-secondary);
|
||
line-height: 1.4;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
max-width: 100%;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// 样式穿透 - 重点修复溢出问题
|
||
:deep() {
|
||
.conversations-list {
|
||
background-color: transparent !important;
|
||
width: 100% !important;
|
||
}
|
||
|
||
.conversation-group-title {
|
||
padding-left: 12px !important;
|
||
background-color: transparent !important;
|
||
transition: all 0.3s ease;
|
||
|
||
.title-text {
|
||
opacity: 0.6;
|
||
font-size: 12px;
|
||
transition: opacity 0.2s ease;
|
||
}
|
||
}
|
||
|
||
.conversation-item {
|
||
transition: all 0.3s ease;
|
||
width: 100% !important;
|
||
max-width: 100% !important;
|
||
box-sizing: border-box !important;
|
||
|
||
&-inner {
|
||
width: 100% !important;
|
||
max-width: 100% !important;
|
||
box-sizing: border-box !important;
|
||
display: flex !important;
|
||
justify-content: space-between !important;
|
||
align-items: center !important;
|
||
}
|
||
|
||
&-content {
|
||
flex: 1 !important;
|
||
min-width: 0 !important;
|
||
max-width: calc(100% - 32px) !important;
|
||
overflow: hidden !important;
|
||
box-sizing: border-box !important;
|
||
}
|
||
|
||
// 确保操作按钮区域在展开状态下正常显示
|
||
&-actions {
|
||
flex-shrink: 0 !important;
|
||
display: flex !important;
|
||
align-items: center !important;
|
||
opacity: 1 !important;
|
||
visibility: visible !important;
|
||
transition: all 0.3s ease;
|
||
|
||
.el-button {
|
||
transition: all 0.2s ease;
|
||
width: 24px !important;
|
||
height: 24px !important;
|
||
padding: 0 !important;
|
||
margin-left: 4px !important;
|
||
flex-shrink: 0 !important;
|
||
|
||
&:hover {
|
||
transform: scale(1.1);
|
||
}
|
||
|
||
.el-icon {
|
||
font-size: 16px !important;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// 折叠状态样式
|
||
.aside-collapsed {
|
||
.conversation-group-title {
|
||
display: none !important;
|
||
}
|
||
|
||
.conversation-item {
|
||
justify-content: center !important;
|
||
padding: 12px 8px !important;
|
||
height: 64px !important;
|
||
min-height: 64px !important;
|
||
|
||
&-label {
|
||
display: none !important;
|
||
}
|
||
|
||
&-actions {
|
||
// 折叠状态下隐藏默认操作按钮,使用自定义的
|
||
display: none !important;
|
||
opacity: 0 !important;
|
||
visibility: hidden !important;
|
||
}
|
||
|
||
&-content {
|
||
max-width: 100% !important;
|
||
}
|
||
}
|
||
}
|
||
|
||
// 展开状态样式
|
||
&:not(.aside-collapsed) {
|
||
.conversation-item {
|
||
&-actions {
|
||
display: flex !important;
|
||
opacity: 1 !important;
|
||
visibility: visible !important;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// 自定义对话框样式
|
||
:deep(.collapsed-menu-dialog) {
|
||
.el-message-box {
|
||
width: 160px !important;
|
||
padding: 12px !important;
|
||
|
||
&__header {
|
||
padding: 0 0 8px 0 !important;
|
||
border-bottom: none !important;
|
||
}
|
||
|
||
&__title {
|
||
font-size: 14px !important;
|
||
font-weight: 600 !important;
|
||
}
|
||
|
||
&__content {
|
||
padding: 0 !important;
|
||
}
|
||
|
||
&__headerbtn {
|
||
top: 8px !important;
|
||
right: 8px !important;
|
||
|
||
.el-icon {
|
||
font-size: 14px !important;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// 移动端适配
|
||
@media (max-width: 768px) {
|
||
.aside-container {
|
||
position: fixed;
|
||
left: 0;
|
||
top: 0;
|
||
bottom: 0;
|
||
z-index: 1000;
|
||
width: 280px !important;
|
||
transform: translateX(-100%);
|
||
transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||
box-shadow: 2px 0 8px rgba(0, 0, 0, 0.15);
|
||
|
||
&.aside-collapsed {
|
||
transform: translateX(-100%);
|
||
width: 100px !important;
|
||
}
|
||
|
||
&:not(.aside-collapsed) {
|
||
transform: translateX(0);
|
||
}
|
||
}
|
||
|
||
.aside-wrapper {
|
||
width: 280px !important;
|
||
|
||
.aside-collapsed & {
|
||
width: 100px !important;
|
||
}
|
||
}
|
||
|
||
// 移动端遮罩层
|
||
.aside-overlay {
|
||
position: fixed;
|
||
top: 0;
|
||
left: 0;
|
||
right: 0;
|
||
bottom: 0;
|
||
background-color: rgba(0, 0, 0, 0.5);
|
||
z-index: 999;
|
||
animation: fadeIn 0.3s ease;
|
||
}
|
||
}
|
||
|
||
// 动画
|
||
@keyframes fadeIn {
|
||
from {
|
||
opacity: 0;
|
||
}
|
||
to {
|
||
opacity: 1;
|
||
}
|
||
}
|
||
</style>
|