Lan
2026-01-09 10:13:00 +08:00
parent b7da890897
commit 3d862ec5b9
4 changed files with 110 additions and 34 deletions
+14 -1
View File
@@ -20,6 +20,18 @@
<ShieldCheckIcon class="w-4 h-4 mr-1 text-green-400" /> <ShieldCheckIcon class="w-4 h-4 mr-1 text-green-400" />
{{ t('send.secureEncryption') }} {{ t('send.secureEncryption') }}
</span> </span>
<div class="flex items-center space-x-4">
<router-link
to="/login"
class="text-sm hover:text-indigo-300 transition duration-300 flex items-center"
:class="[
isDarkMode
? 'text-gray-400 hover:text-indigo-400'
: 'text-gray-500 hover:text-indigo-600'
]"
>
<UserIcon class="w-4 h-4" />
</router-link>
<button <button
@click="$emit('toggle-drawer')" @click="$emit('toggle-drawer')"
class="text-sm hover:text-indigo-300 transition duration-300 flex items-center" class="text-sm hover:text-indigo-300 transition duration-300 flex items-center"
@@ -30,11 +42,12 @@
</button> </button>
</div> </div>
</div> </div>
</div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { inject } from 'vue' import { inject } from 'vue'
import { ShieldCheckIcon, ClipboardListIcon } from 'lucide-vue-next' import { ShieldCheckIcon, ClipboardListIcon, UserIcon } from 'lucide-vue-next'
import { useI18n } from 'vue-i18n' import { useI18n } from 'vue-i18n'
const { t } = useI18n() const { t } = useI18n()
+1
View File
@@ -53,6 +53,7 @@ export default {
// Admin module // Admin module
admin: { admin: {
logout: 'Logout',
dashboard: { dashboard: {
title: 'Dashboard', title: 'Dashboard',
totalFiles: 'Total Files', totalFiles: 'Total Files',
+1
View File
@@ -52,6 +52,7 @@ export default {
// 管理员模块 // 管理员模块
admin: { admin: {
logout: '退出登录',
dashboard: { dashboard: {
title: '仪表盘', title: '仪表盘',
totalFiles: '总文件数', totalFiles: '总文件数',
+82 -21
View File
@@ -1,25 +1,37 @@
<template> <template>
<div class="h-screen flex flex-col lg:flex-row transition-colors duration-300" <div
:class="[isDarkMode ? 'bg-gray-900' : 'bg-gray-50']"> class="h-screen flex flex-col lg:flex-row transition-colors duration-300"
:class="[isDarkMode ? 'bg-gray-900' : 'bg-gray-50']"
>
<!-- Sidebar --> <!-- Sidebar -->
<aside <aside
class="fixed inset-y-0 border-transparent left-0 z-50 w-64 transform transition-all duration-300 ease-in-out lg:relative lg:translate-x-0 border-r flex flex-col h-full lg:h-screen" class="fixed inset-y-0 border-transparent left-0 z-50 w-64 transform transition-all duration-300 ease-in-out lg:relative lg:translate-x-0 border-r flex flex-col h-full lg:h-screen"
:class="[ :class="[
isDarkMode isDarkMode ? 'bg-gray-800 bg-opacity-90 backdrop-filter backdrop-blur-xl ' : 'bg-white ',
? 'bg-gray-800 bg-opacity-90 backdrop-filter backdrop-blur-xl '
: 'bg-white ',
{ '-translate-x-full': !isSidebarOpen } { '-translate-x-full': !isSidebarOpen }
]"> ]"
>
<!-- Logo区域 --> <!-- Logo区域 -->
<div class="flex items-center justify-between h-16 px-4 border-b" <div
:class="[isDarkMode ? 'border-gray-700' : 'border-gray-200']"> class="flex items-center justify-between h-16 px-4 border-b"
:class="[isDarkMode ? 'border-gray-700' : 'border-gray-200']"
>
<div class="flex items-center"> <div class="flex items-center">
<div class="rounded-full bg-gradient-to-r from-indigo-500 via-purple-500 to-pink-500 p-1 animate-spin-slow"> <div
class="rounded-full bg-gradient-to-r from-indigo-500 via-purple-500 to-pink-500 p-1 animate-spin-slow"
>
<div class="rounded-full p-1" :class="[isDarkMode ? 'bg-gray-800' : 'bg-white']"> <div class="rounded-full p-1" :class="[isDarkMode ? 'bg-gray-800' : 'bg-white']">
<BoxIcon class="w-6 h-6" :class="[isDarkMode ? 'text-indigo-400' : 'text-indigo-600']" /> <BoxIcon
class="w-6 h-6"
:class="[isDarkMode ? 'text-indigo-400' : 'text-indigo-600']"
/>
</div> </div>
</div> </div>
<h1 @click="router.push('/')" class="ml-2 text-xl font-semibold cursor-pointer" :class="[isDarkMode ? 'text-white' : 'text-gray-800']"> <h1
@click="router.push('/')"
class="ml-2 text-xl font-semibold cursor-pointer"
:class="[isDarkMode ? 'text-white' : 'text-gray-800']"
>
{{ t('common.appName') }} {{ t('common.appName') }}
</h1> </h1>
</div> </div>
@@ -32,8 +44,10 @@
<nav class="flex-1 overflow-y-auto custom-scrollbar"> <nav class="flex-1 overflow-y-auto custom-scrollbar">
<ul class="p-4 space-y-2"> <ul class="p-4 space-y-2">
<li v-for="item in menuItems" :key="item.id"> <li v-for="item in menuItems" :key="item.id">
<a @click="router.push(item.redirect)" <a
class="flex items-center p-2 rounded-lg transition-colors duration-200" :class="[ @click="router.push(item.redirect)"
class="flex items-center p-2 rounded-lg transition-colors duration-200"
:class="[
router.currentRoute.value.name === item.id router.currentRoute.value.name === item.id
? isDarkMode ? isDarkMode
? 'bg-indigo-900 text-indigo-400' ? 'bg-indigo-900 text-indigo-400'
@@ -41,20 +55,39 @@
: isDarkMode : isDarkMode
? 'text-gray-400 hover:bg-gray-700' ? 'text-gray-400 hover:bg-gray-700'
: 'text-gray-600 hover:bg-gray-100' : 'text-gray-600 hover:bg-gray-100'
]"> ]"
>
<component :is="item.icon" class="w-5 h-5 mr-3" /> <component :is="item.icon" class="w-5 h-5 mr-3" />
{{ item.name }} {{ item.name }}
</a> </a>
</li> </li>
</ul> </ul>
</nav> </nav>
<!-- 退出登录按钮 -->
<div class="p-4 border-t" :class="[isDarkMode ? 'border-gray-700' : 'border-gray-200']">
<button
@click="handleLogout"
class="flex items-center w-full p-2 rounded-lg transition-colors duration-200"
:class="[
isDarkMode
? 'text-gray-400 hover:bg-gray-700 hover:text-white'
: 'text-gray-600 hover:bg-gray-100 hover:text-gray-900'
]"
>
<LogOutIcon class="w-5 h-5 mr-3" />
{{ t('admin.logout') }}
</button>
</div>
</aside> </aside>
<!-- Main Content --> <!-- Main Content -->
<div class="flex-1 flex flex-col h-full"> <div class="flex-1 flex flex-col h-full">
<!-- Header --> <!-- Header -->
<header class="shadow-md border-b transition-colors duration-300 h-16" <header
:class="[isDarkMode ? 'bg-gray-800 border-gray-700' : 'bg-white border-gray-200']"> class="shadow-md border-b transition-colors duration-300 h-16"
:class="[isDarkMode ? 'bg-gray-800 border-gray-700' : 'bg-white border-gray-200']"
>
<div class="flex items-center justify-between h-16 px-4"> <div class="flex items-center justify-between h-16 px-4">
<button @click="toggleSidebar" class="lg:hidden"> <button @click="toggleSidebar" class="lg:hidden">
<MenuIcon class="w-6 h-6" :class="[isDarkMode ? 'text-gray-400' : 'text-gray-600']" /> <MenuIcon class="w-6 h-6" :class="[isDarkMode ? 'text-gray-400' : 'text-gray-600']" />
@@ -63,8 +96,10 @@
</header> </header>
<!-- Content --> <!-- Content -->
<main class="overflow-y-auto transition-colors duration-300 custom-scrollbar" <main
:class="[isDarkMode ? 'bg-gray-900' : 'bg-gray-50']"> class="overflow-y-auto transition-colors duration-300 custom-scrollbar"
:class="[isDarkMode ? 'bg-gray-900' : 'bg-gray-50']"
>
<router-view /> <router-view />
</main> </main>
</div> </div>
@@ -73,9 +108,18 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref, inject, onMounted, onUnmounted } from 'vue' import { ref, inject, onMounted, onUnmounted } from 'vue'
import { BoxIcon, MenuIcon, XIcon, FolderIcon, CogIcon, LayoutDashboardIcon } from 'lucide-vue-next' import {
BoxIcon,
MenuIcon,
XIcon,
FolderIcon,
CogIcon,
LayoutDashboardIcon,
LogOutIcon
} from 'lucide-vue-next'
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
import { useI18n } from 'vue-i18n' import { useI18n } from 'vue-i18n'
import { useAdminStore } from '@/stores/adminStore'
interface MenuItem { interface MenuItem {
id: string id: string
@@ -87,9 +131,20 @@ interface MenuItem {
const router = useRouter() const router = useRouter()
const { t } = useI18n() const { t } = useI18n()
const isDarkMode = inject('isDarkMode') const isDarkMode = inject('isDarkMode')
const adminStore = useAdminStore()
const menuItems: MenuItem[] = [ const menuItems: MenuItem[] = [
{ id: 'Dashboard', name: t('admin.dashboard.title'), icon: LayoutDashboardIcon, redirect: '/admin/dashboard' }, {
{ id: 'FileManage', name: t('admin.fileManage.title'), icon: FolderIcon, redirect: '/admin/files' }, id: 'Dashboard',
name: t('admin.dashboard.title'),
icon: LayoutDashboardIcon,
redirect: '/admin/dashboard'
},
{
id: 'FileManage',
name: t('admin.fileManage.title'),
icon: FolderIcon,
redirect: '/admin/files'
},
{ id: 'Settings', name: t('admin.settings.title'), icon: CogIcon, redirect: '/admin/settings' } { id: 'Settings', name: t('admin.settings.title'), icon: CogIcon, redirect: '/admin/settings' }
] ]
@@ -138,6 +193,12 @@ const loadFiles = async () => {
onMounted(() => { onMounted(() => {
loadFiles() loadFiles()
}) })
// 登出处理
const handleLogout = () => {
adminStore.logout()
router.push('/login')
}
</script> </script>
<style> <style>