This commit is contained in:
@@ -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()
|
||||||
|
|||||||
@@ -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',
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ export default {
|
|||||||
|
|
||||||
// 管理员模块
|
// 管理员模块
|
||||||
admin: {
|
admin: {
|
||||||
|
logout: '退出登录',
|
||||||
dashboard: {
|
dashboard: {
|
||||||
title: '仪表盘',
|
title: '仪表盘',
|
||||||
totalFiles: '总文件数',
|
totalFiles: '总文件数',
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
Reference in New Issue
Block a user