Mars Developer 51f8d95bf9 first commit
2025-06-26 11:24:11 +08:00

199 lines
8.8 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="flex flex-col w-64 h-full bg-gray-800">
<!-- Logo区域 -->
<div class="flex items-center h-16 px-4 bg-gray-900 flex-shrink-0">
<div class="flex items-center">
<div class="flex-shrink-0">
<svg class="h-8 w-8 text-blue-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 5h12M9 3v2m1.048 9.5A18.022 18.022 0 716.412 9m6.088 9h7M11 21l5-10 5 10M12.751 5C11.783 10.77 8.07 15.61 3 18.129"></path>
</svg>
</div>
<div class="ml-3">
<div class="text-base font-medium text-white">翻译管理</div>
<div class="text-sm text-gray-300">系统后台</div>
</div>
</div>
</div>
<!-- 导航菜单 - 可滚动区域 -->
<nav class="flex-1 px-2 py-4 bg-gray-800 space-y-1 overflow-y-auto">
<NuxtLink
to="/dashboard"
class="group flex items-center px-2 py-2 text-sm font-medium rounded-md transition-colors duration-200"
:class="isActive('/dashboard') ? 'bg-gray-900 text-white' : 'text-gray-300 hover:bg-gray-700 hover:text-white'"
>
<svg class="mr-3 h-6 w-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 7v10a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2H5a2 2 0 00-2-2z"></path>
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 5a2 2 0 012-2h4a2 2 0 012 2v6a2 2 0 01-2 2H10a2 2 0 01-2-2V5z"></path>
</svg>
仪表板
</NuxtLink>
<NuxtLink
to="/users"
class="group flex items-center px-2 py-2 text-sm font-medium rounded-md transition-colors duration-200"
:class="isActive('/users') ? 'bg-gray-900 text-white' : 'text-gray-300 hover:bg-gray-700 hover:text-white'"
>
<svg class="mr-3 h-6 w-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4.354a4 4 0 110 5.292M15 21H3v-1a6 6 0 0112 0v1zm0 0h6v-1a6 6 0 00-9-5.197m13.5-9a2.5 2.5 0 11-5 0 2.5 2.5 0 015 0z"></path>
</svg>
用户管理
</NuxtLink>
<NuxtLink
to="/orders"
class="group flex items-center px-2 py-2 text-sm font-medium rounded-md transition-colors duration-200"
:class="isActive('/orders') ? 'bg-gray-900 text-white' : 'text-gray-300 hover:bg-gray-700 hover:text-white'"
>
<svg class="mr-3 h-6 w-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"></path>
</svg>
订单管理
</NuxtLink>
<NuxtLink
to="/finance"
class="group flex items-center px-2 py-2 text-sm font-medium rounded-md transition-colors duration-200"
:class="isActive('/finance') ? 'bg-gray-900 text-white' : 'text-gray-300 hover:bg-gray-700 hover:text-white'"
>
<svg class="mr-3 h-6 w-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8c-1.657 0-3 .895-3 2s1.343 2 3 2 3 .895 3 2-1.343 2-3 2m0-8c1.11 0 2.08.402 2.599 1M12 8V7m0 1v8m0 0v1m0-1c-1.11 0-2.08-.402-2.599-1"></path>
</svg>
财务管理
</NuxtLink>
<NuxtLink
to="/reports"
class="group flex items-center px-2 py-2 text-sm font-medium rounded-md transition-colors duration-200"
:class="isActive('/reports') ? 'bg-gray-900 text-white' : 'text-gray-300 hover:bg-gray-700 hover:text-white'"
>
<svg class="mr-3 h-6 w-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z"></path>
</svg>
数据报表
</NuxtLink>
<NuxtLink
to="/settings"
class="group flex items-center px-2 py-2 text-sm font-medium rounded-md transition-colors duration-200"
:class="isActive('/settings') ? 'bg-gray-900 text-white' : 'text-gray-300 hover:bg-gray-700 hover:text-white'"
>
<svg class="mr-3 h-6 w-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z"></path>
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"></path>
</svg>
系统设置
</NuxtLink>
</nav>
<!-- 用户信息和注销 - 固定在底部 -->
<div class="flex-shrink-0 bg-gray-700 p-4 border-t border-gray-600">
<div class="flex items-center">
<div class="flex-shrink-0">
<div class="h-8 w-8 rounded-full bg-gray-500 flex items-center justify-center">
<ClientOnly>
<span class="text-sm font-medium text-white">{{ userInitial || '系' }}</span>
<template #fallback>
<span class="text-sm font-medium text-white"></span>
</template>
</ClientOnly>
</div>
</div>
<div class="ml-3 flex-1 min-w-0">
<ClientOnly>
<p class="text-sm font-medium text-white truncate">{{ userInfo.name || '系统管理员' }}</p>
<p class="text-xs text-gray-300 truncate">{{ userInfo.role || '管理员' }}</p>
<template #fallback>
<p class="text-sm font-medium text-white truncate">系统管理员</p>
<p class="text-xs text-gray-300 truncate">管理员</p>
</template>
</ClientOnly>
</div>
<button
@click="handleLogout"
class="ml-3 flex-shrink-0 bg-gray-600 p-2 rounded-md text-gray-400 hover:text-white hover:bg-gray-500 focus:outline-none focus:ring-2 focus:ring-white transition-colors duration-200"
title="注销"
>
<svg class="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 16l4-4m0 0l-4-4m4 4H7m6 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h4a3 3 0 013 3v1"></path>
</svg>
</button>
</div>
</div>
</div>
</template>
<script setup>
import { useRouter } from 'vue-router'
// 修复导入 - 从我们的composables导入useClientState
// import { useClientState } from 'vue'
const router = useRouter()
// 临时注释掉useClientState的使用直接使用localStorage
// const { userInfo, initClientState, logout, setupStorageListener } = useClientState()
// 用户信息
const userInfo = ref({
name: '系统管理员',
role: '管理员'
})
// 判断菜单项是否活跃
const isActive = (path) => {
return router.currentRoute.value.path === path
}
// 加载用户信息
const loadUserInfo = () => {
if (process.client) {
const adminUser = localStorage.getItem('adminUser')
const isAuthenticated = localStorage.getItem('isAuthenticated')
if (isAuthenticated === 'true' && adminUser) {
try {
const user = JSON.parse(adminUser)
userInfo.value = {
name: user.full_name || user.name || '系统管理员',
role: user.role === 'admin' ? '管理员' : user.role || '管理员'
}
} catch (error) {
console.error('解析用户信息失败:', error)
}
}
}
}
// 处理退出登录
const handleLogout = () => {
if (confirm('确定要退出登录吗?')) {
if (process.client) {
localStorage.removeItem('user')
localStorage.removeItem('isAuthenticated')
localStorage.removeItem('adminUser')
window.location.replace('/login')
}
}
}
// 用户姓名首字母
const userInitial = computed(() => {
return userInfo.value.name ? userInfo.value.name.charAt(0) : 'A'
})
// 挂载时初始化
onMounted(() => {
loadUserInfo()
// 设置存储监听器
if (process.client) {
window.addEventListener('storage', loadUserInfo)
}
})
// 监听路由变化
watch(() => router.currentRoute.value.path, () => {
loadUserInfo()
})
</script>