重构首页

This commit is contained in:
2026-05-26 16:01:13 +08:00
parent ded04de609
commit f0e36381d3
9 changed files with 1718 additions and 637 deletions

View File

@@ -0,0 +1,250 @@
<template>
<div class="sidebar">
<div class="sidebar-header">
<div class="brand-dot"></div>
<div class="user-info">
<el-avatar :size="42" src="https://cube.elemecdn.com/0/88/03b0d39583f48206768a7534e55bcpng.png" />
<div class="user-details">
<div class="user-name">助手</div>
<div class="user-status">在线</div>
</div>
</div>
<el-button class="new-chat-btn" @click="handleNewChat">
<el-icon><Plus /></el-icon>
新增对话
</el-button>
</div>
<div class="sidebar-menu">
<div v-for="item in menuItems" :key="item.key" class="menu-item" :class="{ active: activeMenu === item.key }" @click="handleMenuClick(item)">
<el-icon :size="18" class="menu-icon">
<component :is="item.icon" />
</el-icon>
<span class="menu-label">{{ item.label }}</span>
<el-badge v-if="item.badge" :value="item.badge" class="menu-badge" />
</div>
</div>
<div class="sidebar-footer">
<el-button text class="footer-btn" @click="handleSettings">
<el-icon><Setting /></el-icon>
设置
</el-button>
</div>
</div>
</template>
<script setup lang="ts">
import { Document, Folder, ChatDotRound, MagicStick, Cpu, VideoPlay, Setting, Plus } from '@element-plus/icons-vue';
import { useRouter } from 'vue-router';
interface MenuItem {
key: string;
label: string;
icon: any;
badge?: number;
route?: string;
}
interface Props {
activeMenu: string;
}
interface Emits {
(e: 'menu-change', key: string): void;
(e: 'new-chat'): void;
}
defineProps<Props>();
const emit = defineEmits<Emits>();
const router = useRouter();
const menuItems: MenuItem[] = [
{ key: 'chat', label: '对话', icon: ChatDotRound },
{ key: 'diary', label: '日记', icon: Document, badge: 3 },
{ key: 'files', label: '文件', icon: Folder },
{ key: 'skills', label: '技能管理', icon: MagicStick, route: '/settings/skill' },
{ key: 'models', label: '模型管理', icon: Cpu, route: '/settings/modelConfig/modelModule' },
{ key: 'creation', label: '内容创作', icon: VideoPlay, route: '/settings/creation' },
];
const handleMenuClick = (item: MenuItem) => {
if (item.route) {
router.push(item.route);
} else {
emit('menu-change', item.key);
}
};
const handleNewChat = () => {
emit('new-chat');
};
const handleSettings = () => {
router.push('/personal');
};
</script>
<style scoped lang="scss">
.sidebar {
width: 252px;
background: linear-gradient(180deg, #ffffff 0%, #f9fbff 100%);
border-right: 1px solid #e7edf7;
display: flex;
flex-direction: column;
height: 100%;
box-shadow: 6px 0 20px rgba(15, 23, 42, 0.04);
}
.sidebar-header {
padding: 18px 16px 14px;
border-bottom: 1px solid #e9eef7;
position: relative;
}
.new-chat-btn {
margin-top: 10px;
width: 100%;
height: 34px;
border-radius: 10px;
border: 1px solid #dbe7f7;
background: linear-gradient(135deg, #f8fbff 0%, #eff6ff 100%);
color: #1f4db8;
font-weight: 600;
letter-spacing: 0.2px;
&:hover {
color: #1e40af;
border-color: #bfdbfe;
background: linear-gradient(135deg, #eff6ff 0%, #e0eeff 100%);
}
}
.brand-dot {
position: absolute;
right: 16px;
top: 18px;
width: 8px;
height: 8px;
border-radius: 999px;
background: linear-gradient(135deg, #60a5fa 0%, #2563eb 100%);
box-shadow: 0 0 0 4px rgba(59, 130, 246, 0.14);
}
.user-info {
display: flex;
align-items: center;
gap: 12px;
padding: 8px 8px 6px;
border-radius: 12px;
background: linear-gradient(180deg, rgba(255, 255, 255, 0.86) 0%, rgba(248, 251, 255, 0.92) 100%);
border: 1px solid #e7edf7;
}
.user-details {
flex: 1;
}
.user-name {
font-size: 15px;
font-weight: 700;
color: #111827;
margin-bottom: 4px;
letter-spacing: 0.2px;
}
.user-status {
font-size: 12px;
color: #10b981;
font-weight: 500;
}
.sidebar-menu {
flex: 1;
padding: 12px 10px;
overflow-y: auto;
scrollbar-width: none;
-ms-overflow-style: none;
&::-webkit-scrollbar {
display: none;
}
}
.menu-item {
display: flex;
align-items: center;
gap: 10px;
padding: 11px 12px;
margin-bottom: 6px;
border-radius: 11px;
cursor: pointer;
transition: all 0.22s ease;
color: #64748b;
position: relative;
border: 1px solid transparent;
&:hover {
background: #f3f7ff;
color: #1f2937;
border-color: #e3ecfb;
}
&.active {
background: linear-gradient(135deg, rgba(59, 130, 246, 0.16) 0%, rgba(37, 99, 235, 0.12) 100%);
color: #1f4db8;
font-weight: 600;
border-color: rgba(59, 130, 246, 0.2);
box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.55);
&::before {
content: '';
position: absolute;
left: -2px;
top: 50%;
transform: translateY(-50%);
width: 3px;
height: 18px;
background: linear-gradient(180deg, #60a5fa 0%, #2563eb 100%);
border-radius: 0 4px 4px 0;
}
}
}
.menu-icon {
opacity: 0.92;
}
.menu-label {
flex: 1;
font-size: 13px;
}
.menu-badge {
:deep(.el-badge__content) {
background: #ef4444;
border: none;
box-shadow: 0 2px 6px rgba(239, 68, 68, 0.25);
}
}
.sidebar-footer {
padding: 10px;
border-top: 1px solid #e9eef7;
}
.footer-btn {
width: 100%;
justify-content: flex-start;
gap: 8px;
color: #64748b;
font-size: 13px;
border-radius: 10px;
padding: 10px 12px;
&:hover {
background: #f4f7fd;
color: #1f2937;
}
}
</style>