fix: 前端页面架构重构初版

This commit is contained in:
Gsh
2025-12-28 22:42:17 +08:00
parent c649ad31c2
commit e4621d9049
53 changed files with 6098 additions and 845 deletions

View File

@@ -1,8 +1,288 @@
<!-- 手机端布局 -->
<script setup></script>
<!-- 移动端布局 -->
<script setup lang="ts">
import { ref } from 'vue';
import { useRouter } from 'vue-router';
import { useUserStore } from '@/stores';
const router = useRouter();
const userStore = useUserStore();
// 侧边栏抽屉状态
const drawerVisible = ref(false);
// 底部导航菜单
const bottomMenus = [
{
key: 'chat',
label: '对话',
icon: 'ChatDotRound',
path: '/chat/conversation',
},
{
key: 'image',
label: '图片',
icon: 'Picture',
path: '/chat/image',
},
{
key: 'video',
label: '视频',
icon: 'VideoCamera',
path: '/chat/video',
},
{
key: 'console',
label: '我的',
icon: 'User',
path: '/console',
},
];
// 侧边栏菜单
const sidebarMenus = [
{
key: 'model-library',
label: '模型库',
icon: 'Box',
path: '/model-library',
},
{
key: 'pricing',
label: '购买',
icon: 'ShoppingCart',
path: '/pricing',
},
{
key: 'logout',
label: '退出登录',
icon: 'SwitchButton',
action: 'logout',
},
];
// 当前路由
const currentPath = computed(() => router.currentRoute.value.path);
// 当前激活的底部菜单
const activeBottomMenu = computed(() => {
const path = currentPath.value;
if (path.includes('/chat/conversation')) return 'chat';
if (path.includes('/chat/image')) return 'image';
if (path.includes('/chat/video')) return 'video';
if (path.includes('/console')) return 'console';
return 'chat';
});
// 打开抽屉
function openDrawer() {
drawerVisible.value = true;
}
// 底部菜单点击
function handleBottomMenuClick(menu: typeof bottomMenus[0]) {
router.push(menu.path);
}
// 侧边栏菜单点击
function handleSidebarMenuClick(menu: typeof sidebarMenus[0]) {
if (menu.action === 'logout') {
userStore.logout();
drawerVisible.value = false;
}
else if (menu.path) {
router.push(menu.path);
drawerVisible.value = false;
}
}
</script>
<template>
<div />
<div class="mobile-layout">
<!-- 顶部栏 -->
<div class="mobile-header">
<el-button circle @click="openDrawer">
<el-icon><i-ep-menu /></el-icon>
</el-button>
<div class="header-title">意心AI</div>
<div class="header-avatar">
<el-avatar v-if="userStore.userInfo" :size="32" :src="userStore.userInfo.avatar">
{{ userStore.userInfo.name?.charAt(0) }}
</el-avatar>
</div>
</div>
<!-- 主内容区 -->
<div class="mobile-main">
<router-view />
</div>
<!-- 底部导航 -->
<div class="mobile-bottom-nav">
<div
v-for="menu in bottomMenus"
:key="menu.key"
class="nav-item"
:class="{ active: activeBottomMenu === menu.key }"
@click="handleBottomMenuClick(menu)"
>
<el-icon class="nav-icon">
<component :is="`i-ep-${menu.icon}`" />
</el-icon>
<div class="nav-label">
{{ menu.label }}
</div>
</div>
</div>
<!-- 侧边栏抽屉 -->
<el-drawer
v-model="drawerVisible"
title="菜单"
direction="ltr"
size="280px"
>
<!-- 用户信息 -->
<div v-if="userStore.userInfo" class="drawer-user">
<el-avatar :size="60" :src="userStore.userInfo.avatar">
{{ userStore.userInfo.name?.charAt(0) }}
</el-avatar>
<div class="user-info">
<div class="user-name">{{ userStore.userInfo.name }}</div>
<div class="user-email">{{ userStore.userInfo.email }}</div>
</div>
</div>
<!-- 菜单列表 -->
<el-menu class="drawer-menu">
<el-menu-item
v-for="menu in sidebarMenus"
:key="menu.key"
@click="handleSidebarMenuClick(menu)"
>
<el-icon>
<component :is="`i-ep-${menu.icon}`" />
</el-icon>
<span>{{ menu.label }}</span>
</el-menu-item>
</el-menu>
</el-drawer>
</div>
</template>
<style scoped lang="scss"></style>
<style scoped lang="scss">
.mobile-layout {
display: flex;
flex-direction: column;
width: 100%;
height: 100vh;
overflow: hidden;
background-color: var(--el-bg-color);
}
.mobile-header {
display: flex;
align-items: center;
justify-content: space-between;
height: 56px;
padding: 0 16px;
background-color: var(--el-bg-color);
border-bottom: 1px solid var(--el-border-color);
flex-shrink: 0;
}
.header-title {
flex: 1;
text-align: center;
font-size: 18px;
font-weight: 600;
color: var(--el-text-color-primary);
}
.header-avatar {
width: 40px;
display: flex;
justify-content: flex-end;
}
.mobile-main {
flex: 1;
overflow-y: auto;
overflow-x: hidden;
-webkit-overflow-scrolling: touch;
}
.mobile-bottom-nav {
display: flex;
align-items: center;
justify-content: space-around;
height: 56px;
padding-bottom: env(safe-area-inset-bottom);
background-color: var(--el-bg-color);
border-top: 1px solid var(--el-border-color);
flex-shrink: 0;
}
.nav-item {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 8px 12px;
cursor: pointer;
color: var(--el-text-color-secondary);
transition: all 0.2s;
&.active {
color: var(--el-color-primary);
.nav-icon {
transform: scale(1.1);
}
}
&:active {
opacity: 0.7;
}
}
.nav-icon {
font-size: 24px;
margin-bottom: 2px;
transition: transform 0.2s;
}
.nav-label {
font-size: 12px;
}
// 抽屉样式
.drawer-user {
display: flex;
flex-direction: column;
align-items: center;
padding: 24px 16px;
border-bottom: 1px solid var(--el-border-color);
margin-bottom: 16px;
}
.user-info {
margin-top: 12px;
text-align: center;
}
.user-name {
font-size: 16px;
font-weight: 600;
color: var(--el-text-color-primary);
}
.user-email {
font-size: 12px;
color: var(--el-text-color-secondary);
margin-top: 4px;
}
.drawer-menu {
border-right: none;
}
</style>