文件
jw-beauty/admin-console/src/components/AdminLayout.vue
T
Guoguo 453f3854bd refactor: convert admin console to SPA with dynamic component switching
- Create shell page (pages/admin/index.vue) with AdminLayout + keep-alive
- Convert 9 pages to view components (views/*.vue)
- AdminLayout emits navigate events instead of uni.redirectTo
- Sidebar navigation no longer causes full page reload
- List views cached with keep-alive, detail views re-mount fresh
- Fix: add name property to 5 cached views for keep-alive matching
- Fix: add navigationStyle custom to prevent double nav bar
- Fix: remove duplicate mounted() in RecordView/LogView
2026-04-29 06:24:46 -07:00

167 行
3.6 KiB
Vue

<template>
<view class="admin-layout">
<view class="sidebar">
<view class="sidebar-logo">🌸 光子美容仪</view>
<view class="sidebar-sub">管理后台</view>
<view class="sidebar-menu">
<view
v-for="item in menuItems"
:key="item.view"
class="sidebar-item"
:class="{ active: currentPage === item.view }"
@click="navigate(item.view)"
>
<text class="sidebar-icon">{{ item.icon }}</text>
<text>{{ item.label }}</text>
</view>
</view>
</view>
<view class="main-content">
<view class="top-header">
<text class="header-title">{{ pageTitle }}</text>
<view class="header-right">
<text class="header-user">👤 {{ adminName }}</text>
<text class="header-logout" @click="onLogout">退出</text>
</view>
</view>
<view class="content-body">
<slot></slot>
</view>
</view>
</view>
</template>
<script>
import { useUserStore } from '../store/user'
export default {
props: {
currentPage: { type: String, default: '' }
},
data() {
return {
menuItems: [
{ icon: '📊', label: '仪表盘', view: 'dashboard' },
{ icon: '📱', label: '设备管理', view: 'device' },
{ icon: '👥', label: '用户管理', view: 'user' },
{ icon: '💳', label: '订阅管理', view: 'subscription' },
{ icon: '📋', label: '护理记录', view: 'record' },
{ icon: '📝', label: '操作日志', view: 'log' },
{ icon: '⚙️', label: '系统设置', view: 'settings' }
]
}
},
computed: {
pageTitle() {
var item = this.menuItems.find(m => m.view === this.currentPage)
return item ? item.icon + ' ' + item.label : '光子美容仪管理后台'
},
adminName() {
var store = useUserStore()
return (store.adminInfo && store.adminInfo.real_name) || '管理员'
}
},
methods: {
navigate(view) {
this.$emit('navigate', view)
},
onLogout() {
var store = useUserStore()
store.clearToken()
uni.reLaunch({ url: '/pages/login/index' })
}
}
}
</script>
<style scoped>
.admin-layout {
display: flex;
min-height: 100vh;
}
.sidebar {
position: fixed;
left: 0;
top: 0;
bottom: 0;
width: 220px;
background: #001529;
padding: 20px 0;
z-index: 100;
}
.sidebar-logo {
color: #fff;
font-size: 18px;
font-weight: 600;
padding: 0 20px 6px;
text-align: center;
}
.sidebar-sub {
color: rgba(255,255,255,0.35);
font-size: 12px;
text-align: center;
padding-bottom: 20px;
border-bottom: 1px solid rgba(255,255,255,0.1);
margin-bottom: 10px;
}
.sidebar-menu {
list-style: none;
}
.sidebar-item {
padding: 12px 20px;
color: rgba(255,255,255,0.65);
font-size: 14px;
display: flex;
align-items: center;
gap: 10px;
cursor: pointer;
}
.sidebar-item:hover {
color: #fff;
background: rgba(255,255,255,0.08);
}
.sidebar-item.active {
color: #fff;
background: #E6508C;
}
.sidebar-icon {
font-size: 16px;
}
.main-content {
margin-left: 220px;
flex: 1;
min-height: 100vh;
background: #f0f2f5;
}
.top-header {
background: #fff;
padding: 16px 24px;
display: flex;
justify-content: space-between;
align-items: center;
border-bottom: 1px solid #f0f0f0;
}
.header-title {
font-size: 18px;
font-weight: 600;
color: #333;
}
.header-right {
display: flex;
align-items: center;
gap: 16px;
}
.header-user {
color: #666;
font-size: 14px;
}
.header-logout {
color: #E6508C;
cursor: pointer;
font-size: 14px;
}
.content-body {
padding: 20px;
}
</style>