zhemima/msmail
0
1<script setup lang="ts">2import { useRoute, useRouter } from 'vue-router';3import { ref, onMounted } from 'vue';4import logo from './assets/logo.png'5import { ipApi } from './services/ipApi';6 7const router = useRouter();8const route = useRoute();9const menuVisible = ref(false);10const serverIP = ref('');11 12const menu = [13 {14 name: '收件',15 path: '/mail',16 icon: 'system-log'17 },18 {19 name: '账号',20 path: '/account',21 icon: 'user-list'22 },23 {24 name: '设置',25 path: '/setting',26 icon: 'setting-1'27 },28 {29 name: '调试',30 path: '/debug',31 icon: 'bug'32 }33];34 35const logout = () => {36 window.localStorage.removeItem('isAuthenticated');37 router.push('/login');38};39 40const toggleMenu = () => {41 menuVisible.value = !menuVisible.value;42};43 44// 获取服务器IP45const fetchServerIP = async () => {46 try {47 const serverInfo = await ipApi.getServerInfo();48 serverIP.value = serverInfo.serverIP;49 } catch (error) {50 console.error('获取服务器IP失败:', error);51 serverIP.value = '获取失败';52 }53};54 55// 组件挂载时获取服务器IP56onMounted(() => {57 if (route.path !== '/login') {58 fetchServerIP();59 }60});61 62//解析token63const parseToken = () => {64 try {65 const token = localStorage.getItem('token') as string;66 const [, payload] = token.split('.');67 const data = JSON.parse(atob(payload));68 return data;69 } catch (error) {70 return null;71 }72};73const jwtToken = parseToken();74 75</script>76 77<template>78 <template v-if="route.path === '/login'">79 <router-view />80 </template>81 <t-layout v-else class="h-screen">82 <!-- 移动端抽屉菜单 -->83 <t-drawer v-model:visible="menuVisible" placement="left" size="232" :footer="false" :header="false"84 :close-on-overlay-click="true" class="lg:hidden">85 <t-menu :value="route.path" theme="dark" class="h-full bg-transparent ">86 <template #logo>87 <router-link to="/" class="flex items-center gap-2 p-4">88 <img :src="logo" alt="logo" class="w-8 h-8" />89 <h1 class="text-xl font-bold text-white">MS MAIL</h1>90 </router-link>91 </template>92 <t-menu-item v-for="item in menu" :key="item.path" :value="item.path" :to="item.path"93 @click="menuVisible = false" class="menu-item mx-4 my-2 rounded-xl">94 <template #icon>95 <t-icon :name="item.icon" />96 </template>97 {{ item.name }}98 </t-menu-item>99 </t-menu>100 </t-drawer>101 102 <!-- 桌面端侧边栏 -->103 <t-aside class="sidebar backdrop-blur-lg hidden lg:block">104 <t-menu :value="route.path" theme="dark" class="bg-transparent">105 <template #logo>106 <router-link to="/" class="flex items-center gap-2">107 <img :src="logo" alt="logo" class="w-10 h-10 transition-transform hover:scale-110" />108 <h1 class="text-2xl font-bold text-white tracking-wider">MS MAIL</h1>109 </router-link>110 </template>111 <t-menu-item v-for="item in menu" :key="item.path" :value="item.path" :to="item.path"112 class="menu-item mx-4 my-2 rounded-xl">113 <template #icon>114 <t-icon :name="item.icon" class="text-xl" />115 </template>116 <span class="font-medium">{{ item.name }}</span>117 </t-menu-item>118 </t-menu>119 </t-aside>120 121 122 <t-layout class="w-full">123 <t-header class="header backdrop-blur-xl border-b border-gray-100">124 <div class="flex items-center justify-between h-full px-2 sm:px-4 lg:px-8">125 <!-- 移动端菜单按钮和标题 -->126 <div class="flex items-center gap-2 sm:gap-4 ">127 <div class="lg:hidden">128 <t-button theme="default" variant="text" class=" min-w-[40px]" @click="toggleMenu">129 <t-icon name="menu" size="20px" sm:size="24px" />130 </t-button>131 </div>132 <h1133 class="text-base sm:text-xl lg:text-2xl font-bold bg-gradient-to-r from-blue-600 to-indigo-600 bg-clip-text text-transparent truncate max-w-[150px] sm:max-w-full">134 {{ jwtToken?.sub }}135 </h1>136 </div>137 <div class="flex items-center gap-2 sm:gap-4">138 <t-button theme="danger" @click="logout" class="logout-btn text-sm sm:text-base py-1 px-2 sm:px-4">139 <template #icon>140 <t-icon name="logout" class="text-sm sm:text-base" />141 </template>142 <span>退出</span>143 </t-button>144 </div>145 </div>146 </t-header>147 148 <!-- 内容区域 -->149 <t-content class="content bg-gray-50/30 flex-1 overflow-y-auto w-full">150 <router-view v-slot="{ Component }">151 <transition name="fade-slide" mode="out-in">152 <component :is="Component" />153 </transition>154 </router-view>155 </t-content>156 157 <!-- 页脚 -->158 <t-footer class="footer backdrop-blur-sm py-4 text-center text-sm text-gray-600">159 <div class="flex flex-col items-center gap-1">160 <span class="opacity-75">© 微软邮箱管理系统</span>161 <span v-if="serverIP" class="text-xs opacity-60">服务器IP: {{ serverIP }}</span>162 </div>163 </t-footer>164 </t-layout>165 166 </t-layout>167</template>168 169<style scoped>170@reference "./assets/base.css";171 172.sidebar {173 @apply bg-gradient-to-br from-blue-600 via-blue-700 to-indigo-800;174 box-shadow: 0 0 20px rgba(0, 0, 0, 0.1);175}176 177.header {178 @apply bg-white/80 sticky top-0 z-10;179 box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);180}181 182.menu-item {183 @apply transition-all duration-300 hover:bg-white/15 active:scale-95;184 @apply flex items-center gap-3 px-4 py-3;185}186 187.logout-btn {188 @apply transition-transform hover:scale-105 active:scale-95;189}190 191.fade-slide-enter-active,192.fade-slide-leave-active {193 transition: all 0.3s ease;194}195 196.fade-slide-enter-from {197 opacity: 0;198 transform: translateY(20px);199}200 201.fade-slide-leave-to {202 opacity: 0;203 transform: translateY(-20px);204}205 206/* :deep(.t-default-menu.t-menu--dark){207 @apply bg-transparent;208} */209 210:deep(.t-drawer__body) {211 @apply p-0;212}213 214:deep(.t-drawer__body) {215 @apply p-0;216}217 218:deep(::-webkit-scrollbar) {219 @apply w-2;220}221 222:deep(::-webkit-scrollbar-thumb) {223 @apply bg-gray-400/30 rounded-full transition-colors hover:bg-gray-400/50;224}225 226:deep(::-webkit-scrollbar-track) {227 @apply bg-transparent;228}229 230.content {231 background-image: radial-gradient(circle at 50% 50%,232 rgba(255, 255, 255, 0.8) 0%,233 rgba(240, 240, 250, 0.6) 100%);234}235 236.footer {237 @apply bg-white/60;238}239 240/* 添加移动端响应式样式 */241@media (max-width: 1024px) {242 .sidebar {243 display: none;244 }245}246 247.drawer-menu {248 @apply bg-gradient-to-br from-blue-600 via-blue-700 to-indigo-800;249}250</style>251 