fix: 前端页面架构重构初版
This commit is contained in:
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user