168 lines
3.8 KiB
Vue
168 lines
3.8 KiB
Vue
<script setup lang="ts">
|
|
import { computed } from 'vue'
|
|
import { useRouter } from 'vue-router'
|
|
|
|
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 router = useRouter()
|
|
const isAdmin = computed(() => getAdminRole() === 'admin')
|
|
const navItems = computed(() => {
|
|
const baseItems = [
|
|
{ to: '/admin/dashboard', label: '概览' },
|
|
{ to: '/admin/orders', label: '订单' },
|
|
{ to: '/admin/tasks', label: '任务' },
|
|
{ to: '/admin/inventory', label: '库存' },
|
|
{ to: '/admin/message-deliveries', label: '消息发送' },
|
|
{ to: '/admin/webhook-events', label: 'Webhook' },
|
|
]
|
|
|
|
if (isAdmin.value) {
|
|
baseItems.splice(1, 0, { to: '/admin/users', label: '用户' })
|
|
baseItems.push({ to: '/admin/platform-shops', label: 'Agiso店铺' })
|
|
baseItems.push({ to: '/admin/platform-fulfillment', label: '履约配置' })
|
|
baseItems.push({ to: '/admin/audit-logs', label: '审计' })
|
|
}
|
|
|
|
return baseItems
|
|
})
|
|
|
|
async function submitLogout() {
|
|
try {
|
|
await logoutAdmin()
|
|
} catch {
|
|
// 后台退出是无状态的,本地清理优先
|
|
} finally {
|
|
clearAdminSession()
|
|
showSuccess('已退出后台')
|
|
await router.replace('/admin/login')
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<main class="admin-page">
|
|
<aside class="admin-sidebar">
|
|
<div class="admin-brand">
|
|
<strong>运营后台</strong>
|
|
<p>订单与交付管理</p>
|
|
</div>
|
|
|
|
<div class="admin-meta">
|
|
<span>当前账号</span>
|
|
<strong>{{ getAdminUsername() || '未读取' }}</strong>
|
|
<span>当前角色</span>
|
|
<strong>{{ getAdminRole() === 'admin' ? '管理员' : '普通运营' }}</strong>
|
|
<span>登录有效期</span>
|
|
<strong>{{ formatAdminDateTime(getAdminTokenExpiresAt()) }}</strong>
|
|
</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-button round class="logout-btn" @click="submitLogout">退出登录</el-button>
|
|
</aside>
|
|
|
|
<section class="admin-content">
|
|
<RouterView />
|
|
</section>
|
|
</main>
|
|
</template>
|
|
|
|
<style scoped>
|
|
.admin-page {
|
|
min-height: 100vh;
|
|
display: grid;
|
|
grid-template-columns: 240px minmax(0, 1fr);
|
|
background:
|
|
radial-gradient(circle at top left, rgba(73, 136, 255, 0.1), transparent 30%),
|
|
linear-gradient(180deg, #f3f7fc 0%, #edf3fb 100%);
|
|
}
|
|
|
|
.admin-sidebar {
|
|
padding: 24px 18px;
|
|
border-right: 1px solid rgba(86, 108, 138, 0.12);
|
|
background: rgba(255, 255, 255, 0.92);
|
|
backdrop-filter: blur(18px);
|
|
}
|
|
|
|
.admin-brand strong {
|
|
display: block;
|
|
font-size: 20px;
|
|
color: #203551;
|
|
}
|
|
|
|
.admin-brand p {
|
|
margin: 8px 0 0;
|
|
color: #6c7c92;
|
|
}
|
|
|
|
.admin-nav {
|
|
margin-top: 28px;
|
|
display: grid;
|
|
gap: 10px;
|
|
}
|
|
|
|
.admin-meta {
|
|
margin-top: 18px;
|
|
padding: 12px 14px;
|
|
border-radius: 14px;
|
|
background: #f5f8fc;
|
|
color: #5f7289;
|
|
display: grid;
|
|
gap: 4px;
|
|
font-size: 12px;
|
|
}
|
|
|
|
.admin-meta strong {
|
|
color: #1f3c5c;
|
|
word-break: break-all;
|
|
}
|
|
|
|
.admin-nav-link {
|
|
display: block;
|
|
padding: 12px 14px;
|
|
border-radius: 14px;
|
|
text-decoration: none;
|
|
color: #304866;
|
|
background: #f5f8fc;
|
|
border: 1px solid transparent;
|
|
}
|
|
|
|
.admin-nav-link.router-link-active {
|
|
color: #114899;
|
|
border-color: rgba(17, 72, 153, 0.14);
|
|
background: rgba(17, 72, 153, 0.08);
|
|
}
|
|
|
|
.admin-content {
|
|
padding: 24px;
|
|
}
|
|
|
|
.logout-btn {
|
|
margin-top: 18px;
|
|
width: 100%;
|
|
}
|
|
|
|
@media (max-width: 980px) {
|
|
.admin-page {
|
|
grid-template-columns: 1fr;
|
|
}
|
|
|
|
.admin-sidebar {
|
|
border-right: 0;
|
|
border-bottom: 1px solid rgba(86, 108, 138, 0.12);
|
|
}
|
|
}
|
|
</style>
|