- 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
167 行
3.6 KiB
Vue
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>
|