ui优化
This commit is contained in:
@@ -1,49 +1,74 @@
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import {
|
||||
Box,
|
||||
Monitor,
|
||||
Connection,
|
||||
DataAnalysis,
|
||||
Document,
|
||||
List,
|
||||
Message,
|
||||
Service,
|
||||
Setting,
|
||||
Tickets,
|
||||
User,
|
||||
} from '@element-plus/icons-vue'
|
||||
|
||||
import { showSuccess } from '@/lib/feedback'
|
||||
import { logoutAdmin } from '@/services/admin'
|
||||
import { clearAdminSession, getAdminRole, getAdminTokenExpiresAt, getAdminUsername } from '@/utils/admin-auth'
|
||||
import { formatAdminDateTime } from '@/utils/admin-time'
|
||||
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
|
||||
const currentRole = computed(() => getAdminRole())
|
||||
const isAdmin = computed(() => currentRole.value === 'admin')
|
||||
const isOperator = computed(() => currentRole.value === 'operator')
|
||||
|
||||
const roleLabel = computed(() => {
|
||||
if (currentRole.value === 'admin') {
|
||||
return '管理员'
|
||||
}
|
||||
|
||||
if (currentRole.value === 'support') {
|
||||
return '客服'
|
||||
}
|
||||
|
||||
if (currentRole.value === 'admin') return '管理员'
|
||||
if (currentRole.value === 'support') return '客服'
|
||||
return '普通运营'
|
||||
})
|
||||
|
||||
const navItems = computed(() => {
|
||||
const baseItems = [
|
||||
{ to: '/admin/dashboard', label: '概览' },
|
||||
{ to: '/admin/orders', label: '订单' },
|
||||
{ to: '/admin/tasks', label: '任务' },
|
||||
{ to: '/admin/manual-redeem', label: '人工兑换' },
|
||||
{ to: '/admin/message-deliveries', label: '消息发送' },
|
||||
const items: { to: string; label: string; icon: typeof DataAnalysis }[] = [
|
||||
{ to: '/admin/dashboard', label: '概览', icon: DataAnalysis },
|
||||
]
|
||||
|
||||
if (isAdmin.value) {
|
||||
items.push({ to: '/admin/users', label: '用户', icon: User })
|
||||
}
|
||||
|
||||
items.push(
|
||||
{ to: '/admin/orders', label: '订单', icon: Document },
|
||||
{ to: '/admin/tasks', label: '任务', icon: List },
|
||||
)
|
||||
|
||||
if (isAdmin.value || isOperator.value) {
|
||||
baseItems.splice(3, 0, { to: '/admin/inventory', label: '库存' })
|
||||
baseItems.push({ to: '/admin/webhook-events', label: 'Webhook' })
|
||||
items.push({ to: '/admin/inventory', label: '库存', icon: Box })
|
||||
}
|
||||
|
||||
items.push(
|
||||
{ to: '/admin/manual-redeem', label: '人工兑换', icon: Service },
|
||||
{ to: '/admin/message-deliveries', label: '消息发送', icon: Message },
|
||||
)
|
||||
|
||||
if (isAdmin.value || isOperator.value) {
|
||||
items.push({ to: '/admin/webhook-events', label: 'Webhook', icon: Connection })
|
||||
}
|
||||
|
||||
if (isAdmin.value) {
|
||||
baseItems.splice(1, 0, { to: '/admin/users', label: '用户' })
|
||||
baseItems.push({ to: '/admin/platform-shops', label: '平台配置' })
|
||||
baseItems.push({ to: '/admin/platform-fulfillment', label: '履约配置' })
|
||||
baseItems.push({ to: '/admin/audit-logs', label: '审计' })
|
||||
items.push(
|
||||
{ to: '/admin/platform-shops', label: '平台配置', icon: Setting },
|
||||
{ to: '/admin/platform-fulfillment', label: '履约配置', icon: Tickets },
|
||||
{ to: '/admin/audit-logs', label: '审计', icon: Monitor },
|
||||
)
|
||||
}
|
||||
|
||||
return baseItems
|
||||
return items
|
||||
})
|
||||
|
||||
async function submitLogout() {
|
||||
@@ -60,32 +85,30 @@ async function submitLogout() {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<main class="admin-page">
|
||||
<div class="admin-page">
|
||||
<aside class="admin-sidebar">
|
||||
<div class="admin-brand">
|
||||
<div class="sidebar-brand">
|
||||
<strong>运营后台</strong>
|
||||
<p>订单与交付管理</p>
|
||||
</div>
|
||||
|
||||
<div class="admin-meta">
|
||||
<span>当前账号</span>
|
||||
<strong>{{ getAdminUsername() || '未读取' }}</strong>
|
||||
<span>当前角色</span>
|
||||
<strong>{{ roleLabel }}</strong>
|
||||
<span>登录有效期</span>
|
||||
<strong>{{ formatAdminDateTime(getAdminTokenExpiresAt()) }}</strong>
|
||||
<div class="sidebar-user">
|
||||
<div class="user-name">{{ getAdminUsername() || '未读取' }}</div>
|
||||
<div class="user-role">{{ roleLabel }}</div>
|
||||
<div class="user-expiry">有效期至 {{ formatAdminDateTime(getAdminTokenExpiresAt()) }}</div>
|
||||
</div>
|
||||
|
||||
<nav class="admin-nav">
|
||||
<RouterLink
|
||||
v-for="item in navItems"
|
||||
:key="item.to"
|
||||
class="admin-nav-link"
|
||||
:to="item.to"
|
||||
>
|
||||
{{ item.label }}
|
||||
</RouterLink>
|
||||
</nav>
|
||||
<el-menu
|
||||
:default-active="route.path"
|
||||
router
|
||||
class="sidebar-menu"
|
||||
:ellipsis="false"
|
||||
>
|
||||
<el-menu-item v-for="item in navItems" :key="item.to" :index="item.to">
|
||||
<el-icon><component :is="item.icon" /></el-icon>
|
||||
<span>{{ item.label }}</span>
|
||||
</el-menu-item>
|
||||
</el-menu>
|
||||
|
||||
<el-button round class="logout-btn" @click="submitLogout">退出登录</el-button>
|
||||
</aside>
|
||||
@@ -93,95 +116,103 @@ async function submitLogout() {
|
||||
<section class="admin-content">
|
||||
<RouterView />
|
||||
</section>
|
||||
</main>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.admin-page {
|
||||
height: 100vh;
|
||||
display: grid;
|
||||
grid-template-columns: 240px minmax(0, 1fr);
|
||||
grid-template-columns: 260px minmax(0, 1fr);
|
||||
overflow: hidden;
|
||||
background:
|
||||
radial-gradient(circle at top left, rgba(73, 136, 255, 0.1), transparent 30%),
|
||||
linear-gradient(180deg, #f3f7fc 0%, #edf3fb 100%);
|
||||
linear-gradient(180deg, var(--bg-page) 0%, #edf3fb 100%);
|
||||
}
|
||||
|
||||
.admin-sidebar {
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 24px 18px;
|
||||
padding: var(--space-6) 0;
|
||||
overflow-y: auto;
|
||||
border-right: 1px solid rgba(86, 108, 138, 0.12);
|
||||
background: rgba(255, 255, 255, 0.92);
|
||||
border-right: 1px solid var(--border-default);
|
||||
background: var(--bg-sidebar);
|
||||
backdrop-filter: blur(18px);
|
||||
}
|
||||
|
||||
.admin-brand strong {
|
||||
.sidebar-brand {
|
||||
padding: 0 var(--space-5);
|
||||
margin-bottom: var(--space-4);
|
||||
}
|
||||
|
||||
.sidebar-brand strong {
|
||||
display: block;
|
||||
font-size: 20px;
|
||||
color: #203551;
|
||||
font-size: var(--text-xl);
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.admin-brand p {
|
||||
margin: 8px 0 0;
|
||||
color: #6c7c92;
|
||||
.sidebar-brand p {
|
||||
margin: var(--space-2) 0 0;
|
||||
color: var(--text-secondary);
|
||||
font-size: var(--text-sm);
|
||||
}
|
||||
|
||||
.admin-nav {
|
||||
margin-top: 28px;
|
||||
display: grid;
|
||||
gap: 10px;
|
||||
align-content: start;
|
||||
}
|
||||
|
||||
.admin-meta {
|
||||
margin-top: 18px;
|
||||
padding: 12px 14px;
|
||||
border-radius: 14px;
|
||||
.sidebar-user {
|
||||
margin: 0 var(--space-4) var(--space-4);
|
||||
padding: var(--space-3);
|
||||
border-radius: var(--radius-md);
|
||||
background: #f5f8fc;
|
||||
color: #5f7289;
|
||||
display: grid;
|
||||
gap: 4px;
|
||||
font-size: 12px;
|
||||
font-size: var(--text-xs);
|
||||
}
|
||||
|
||||
.admin-meta strong {
|
||||
color: #1f3c5c;
|
||||
word-break: break-all;
|
||||
.user-name {
|
||||
color: var(--text-primary);
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.admin-nav-link {
|
||||
display: block;
|
||||
padding: 12px 14px;
|
||||
border-radius: 14px;
|
||||
text-decoration: none;
|
||||
color: #304866;
|
||||
background: #f5f8fc;
|
||||
border: 1px solid transparent;
|
||||
.user-role {
|
||||
color: var(--text-secondary);
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
.admin-nav-link.router-link-active {
|
||||
color: #114899;
|
||||
border-color: rgba(17, 72, 153, 0.14);
|
||||
background: rgba(17, 72, 153, 0.08);
|
||||
.user-expiry {
|
||||
color: var(--text-muted);
|
||||
margin-top: 4px;
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.sidebar-menu {
|
||||
border-right: none;
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.sidebar-menu :deep(.el-menu-item) {
|
||||
margin: 2px var(--space-2);
|
||||
border-radius: var(--radius-md);
|
||||
min-height: 44px;
|
||||
line-height: 44px;
|
||||
}
|
||||
|
||||
.sidebar-menu :deep(.el-menu-item.is-active) {
|
||||
color: var(--color-primary);
|
||||
background: var(--color-primary-light);
|
||||
}
|
||||
|
||||
.logout-btn {
|
||||
margin: var(--space-3) var(--space-4) 0;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.admin-content {
|
||||
min-width: 0;
|
||||
height: 100vh;
|
||||
padding: 24px;
|
||||
padding: var(--space-6);
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.logout-btn {
|
||||
margin-top: auto;
|
||||
flex-shrink: 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
@media (max-width: 980px) {
|
||||
@media (max-width: 900px) {
|
||||
.admin-page {
|
||||
height: auto;
|
||||
min-height: 100vh;
|
||||
@@ -193,16 +224,15 @@ async function submitLogout() {
|
||||
height: auto;
|
||||
overflow: visible;
|
||||
border-right: 0;
|
||||
border-bottom: 1px solid rgba(86, 108, 138, 0.12);
|
||||
border-bottom: 1px solid var(--border-default);
|
||||
padding-bottom: var(--space-4);
|
||||
}
|
||||
|
||||
.sidebar-menu { overflow: visible; }
|
||||
|
||||
.admin-content {
|
||||
height: auto;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.logout-btn {
|
||||
margin-top: 18px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user