2026-09-09 22:05:00 +08:00
|
|
|
|
<template>
|
2026-09-13 21:39:32 +08:00
|
|
|
|
<div class="admin-scene" :class="{ 'sidebar-collapsed': isCollapse }">
|
|
|
|
|
|
<header class="scene-header" aria-label="善缘丹阳公益服务品牌信息">
|
|
|
|
|
|
<div class="scene-brand">
|
|
|
|
|
|
<img src="/brand/logo-mark.png" alt="善缘丹阳" />
|
|
|
|
|
|
<div class="scene-brand-copy">
|
2026-09-11 17:02:42 +08:00
|
|
|
|
<strong>善缘丹阳</strong>
|
2026-09-13 21:39:32 +08:00
|
|
|
|
<span>公益婚恋服务平台</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="scene-title">
|
|
|
|
|
|
<h1>管理端(运营后台)</h1>
|
|
|
|
|
|
<p>用专业的服务,帮助更多人遇见对的人</p>
|
2026-09-11 17:02:42 +08:00
|
|
|
|
</div>
|
2026-09-09 22:05:00 +08:00
|
|
|
|
</div>
|
2026-09-13 21:39:32 +08:00
|
|
|
|
<div class="scene-benefits" aria-label="平台服务原则">
|
|
|
|
|
|
<span><el-icon><StarFilled /></el-icon><b>公益为本</b><small>不以营利为目的</small></span>
|
|
|
|
|
|
<span><el-icon><Lock /></el-icon><b>真实可靠</b><small>严格审核 多重保障</small></span>
|
|
|
|
|
|
<span><el-icon><LocationFilled /></el-icon><b>本地服务</b><small>深耕丹阳 服务家乡</small></span>
|
|
|
|
|
|
<span><el-icon><Opportunity /></el-icon><b>成就幸福</b><small>让爱在丹阳生根发芽</small></span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</header>
|
2026-09-11 17:02:42 +08:00
|
|
|
|
|
2026-09-13 21:39:32 +08:00
|
|
|
|
<el-container class="admin-shell">
|
|
|
|
|
|
<el-aside :width="isCollapse ? '76px' : '208px'" class="admin-sidebar">
|
|
|
|
|
|
<div class="brand" :class="{ compact: isCollapse }">
|
|
|
|
|
|
<img class="brand-mark" src="/brand/logo-mark.png" alt="" />
|
|
|
|
|
|
<div v-if="!isCollapse" class="brand-copy">
|
|
|
|
|
|
<strong>善缘丹阳</strong>
|
|
|
|
|
|
<span>公益婚恋服务平台</span>
|
|
|
|
|
|
</div>
|
2026-09-11 17:02:42 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
|
2026-09-13 21:39:32 +08:00
|
|
|
|
<el-scrollbar class="menu-scroll">
|
|
|
|
|
|
<nav aria-label="管理后台主导航">
|
|
|
|
|
|
<el-menu
|
|
|
|
|
|
:default-active="activeMenu"
|
|
|
|
|
|
:collapse="isCollapse"
|
|
|
|
|
|
:router="true"
|
|
|
|
|
|
class="sidebar-menu"
|
|
|
|
|
|
>
|
|
|
|
|
|
<el-menu-item
|
|
|
|
|
|
v-for="item in visibleNavigation"
|
|
|
|
|
|
:key="item.label"
|
|
|
|
|
|
:index="item.path"
|
|
|
|
|
|
>
|
|
|
|
|
|
<el-icon><component :is="item.icon" /></el-icon>
|
|
|
|
|
|
<template #title>{{ item.label }}</template>
|
|
|
|
|
|
</el-menu-item>
|
|
|
|
|
|
</el-menu>
|
|
|
|
|
|
</nav>
|
|
|
|
|
|
</el-scrollbar>
|
|
|
|
|
|
|
|
|
|
|
|
<div v-if="!isCollapse" class="sidebar-motto">
|
|
|
|
|
|
<el-icon><StarFilled /></el-icon>
|
|
|
|
|
|
<span>汇聚善意<br />成就良缘</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<button
|
|
|
|
|
|
class="collapse-control"
|
|
|
|
|
|
type="button"
|
|
|
|
|
|
:aria-label="isCollapse ? '展开导航' : '收起导航'"
|
|
|
|
|
|
@click="isCollapse = !isCollapse"
|
|
|
|
|
|
>
|
|
|
|
|
|
<el-icon><Fold v-if="!isCollapse" /><Expand v-else /></el-icon>
|
|
|
|
|
|
<span v-if="!isCollapse">收起导航</span>
|
|
|
|
|
|
</button>
|
|
|
|
|
|
</el-aside>
|
|
|
|
|
|
|
|
|
|
|
|
<el-container class="workspace">
|
|
|
|
|
|
<el-header class="admin-topbar">
|
|
|
|
|
|
<div class="page-context">
|
|
|
|
|
|
<button class="mobile-collapse" type="button" aria-label="切换导航" @click="isCollapse = !isCollapse">
|
|
|
|
|
|
<el-icon><Expand v-if="isCollapse" /><Fold v-else /></el-icon>
|
|
|
|
|
|
</button>
|
|
|
|
|
|
<el-breadcrumb separator="/">
|
|
|
|
|
|
<el-breadcrumb-item :to="{ path: '/dashboard' }">工作台</el-breadcrumb-item>
|
|
|
|
|
|
<el-breadcrumb-item v-if="currentTitle !== '工作台'">{{ currentTitle }}</el-breadcrumb-item>
|
|
|
|
|
|
</el-breadcrumb>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="header-tools">
|
|
|
|
|
|
<el-input
|
|
|
|
|
|
v-model="globalSearch"
|
|
|
|
|
|
class="global-search"
|
|
|
|
|
|
clearable
|
|
|
|
|
|
aria-label="搜索后台页面"
|
|
|
|
|
|
placeholder="搜索用户、活动、内容…"
|
|
|
|
|
|
@keyup.enter="handleSearch"
|
|
|
|
|
|
>
|
|
|
|
|
|
<template #prefix><el-icon><Search /></el-icon></template>
|
|
|
|
|
|
</el-input>
|
|
|
|
|
|
<button class="notification-button" type="button" aria-label="查看系统通知" @click="showNotifications">
|
|
|
|
|
|
<el-icon><Bell /></el-icon>
|
|
|
|
|
|
<span class="notification-badge" aria-hidden="true">{{ notificationCount }}</span>
|
|
|
|
|
|
</button>
|
|
|
|
|
|
<el-dropdown trigger="click">
|
|
|
|
|
|
<span class="user-info">
|
|
|
|
|
|
<el-avatar :size="34">{{ (operator?.name || '工')[0] }}</el-avatar>
|
2026-09-11 17:02:42 +08:00
|
|
|
|
<strong>{{ operator?.name || '工作人员' }}</strong>
|
2026-09-13 21:39:32 +08:00
|
|
|
|
<el-icon><ArrowDown /></el-icon>
|
2026-09-11 17:02:42 +08:00
|
|
|
|
</span>
|
2026-09-13 21:39:32 +08:00
|
|
|
|
<template #dropdown>
|
|
|
|
|
|
<el-dropdown-menu>
|
|
|
|
|
|
<el-dropdown-item disabled>{{ currentRoleName }}</el-dropdown-item>
|
|
|
|
|
|
<el-dropdown-item divided @click="handleLogout">退出登录</el-dropdown-item>
|
|
|
|
|
|
</el-dropdown-menu>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
</el-dropdown>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</el-header>
|
2026-09-11 17:02:42 +08:00
|
|
|
|
|
2026-09-13 21:39:32 +08:00
|
|
|
|
<el-main class="admin-content">
|
|
|
|
|
|
<router-view v-slot="{ Component }">
|
|
|
|
|
|
<keep-alive><component :is="Component" /></keep-alive>
|
|
|
|
|
|
</router-view>
|
|
|
|
|
|
</el-main>
|
|
|
|
|
|
</el-container>
|
2026-09-09 22:05:00 +08:00
|
|
|
|
</el-container>
|
2026-09-13 21:39:32 +08:00
|
|
|
|
|
|
|
|
|
|
<footer class="scene-footer">
|
|
|
|
|
|
<strong>善缘丹阳</strong><span>公益婚恋服务平台</span>
|
|
|
|
|
|
<small>真实 · 真诚 · 公益 · 幸福</small>
|
|
|
|
|
|
</footer>
|
|
|
|
|
|
</div>
|
2026-09-09 22:05:00 +08:00
|
|
|
|
</template>
|
2026-09-11 17:02:42 +08:00
|
|
|
|
|
2026-09-09 22:05:00 +08:00
|
|
|
|
<script setup lang="ts">
|
2026-09-11 17:02:42 +08:00
|
|
|
|
import { computed, ref } from 'vue'
|
|
|
|
|
|
import { useRoute, useRouter } from 'vue-router'
|
|
|
|
|
|
import { ElMessage } from 'element-plus'
|
|
|
|
|
|
import {
|
|
|
|
|
|
ArrowDown,
|
|
|
|
|
|
Bell,
|
|
|
|
|
|
Calendar,
|
|
|
|
|
|
ChatDotRound,
|
|
|
|
|
|
Connection,
|
2026-09-13 21:39:32 +08:00
|
|
|
|
DataAnalysis,
|
2026-09-11 17:02:42 +08:00
|
|
|
|
DataBoard,
|
|
|
|
|
|
DocumentChecked,
|
|
|
|
|
|
Expand,
|
|
|
|
|
|
Fold,
|
|
|
|
|
|
Location,
|
2026-09-13 21:39:32 +08:00
|
|
|
|
LocationFilled,
|
|
|
|
|
|
Lock,
|
|
|
|
|
|
Opportunity,
|
2026-09-11 17:02:42 +08:00
|
|
|
|
Reading,
|
|
|
|
|
|
Search,
|
|
|
|
|
|
Setting,
|
2026-09-13 21:39:32 +08:00
|
|
|
|
StarFilled,
|
2026-09-11 17:02:42 +08:00
|
|
|
|
User,
|
2026-09-13 21:39:32 +08:00
|
|
|
|
UserFilled,
|
2026-09-11 17:02:42 +08:00
|
|
|
|
Warning,
|
|
|
|
|
|
} from '@element-plus/icons-vue'
|
|
|
|
|
|
import { useAuthStore } from '@/stores/auth'
|
|
|
|
|
|
|
2026-09-13 21:39:32 +08:00
|
|
|
|
interface NavigationItem {
|
|
|
|
|
|
label: string
|
|
|
|
|
|
path: string
|
|
|
|
|
|
permissions: string[]
|
|
|
|
|
|
icon: unknown
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const navigation: NavigationItem[] = [
|
|
|
|
|
|
{ label: '工作台', path: '/dashboard', permissions: [], icon: DataBoard },
|
|
|
|
|
|
{ label: '用户管理', path: '/users', permissions: ['user.view'], icon: User },
|
|
|
|
|
|
{ label: '资料审核', path: '/review', permissions: ['review.view'], icon: DocumentChecked },
|
|
|
|
|
|
{ label: '匹配管理', path: '/activities/interests', permissions: ['activity.review_registration'], icon: StarFilled },
|
|
|
|
|
|
{ label: '公益红娘', path: '/referral', permissions: ['referral.manage'], icon: Connection },
|
|
|
|
|
|
{ label: '公益咨询', path: '/counseling', permissions: ['counseling.service.view'], icon: ChatDotRound },
|
|
|
|
|
|
{ label: '活动管理', path: '/activities/interests', permissions: ['activity.review_registration'], icon: Calendar },
|
|
|
|
|
|
{ label: '内容管理', path: '/content', permissions: ['content.view'], icon: Reading },
|
|
|
|
|
|
{ label: '善缘服务站', path: '/service-station', permissions: ['service_location.view'], icon: Location },
|
|
|
|
|
|
{ label: '举报风控', path: '/risk/reports', permissions: ['risk.report.view'], icon: Warning },
|
|
|
|
|
|
{ label: '数据统计', path: '/analytics', permissions: ['analytics.view'], icon: DataAnalysis },
|
|
|
|
|
|
{ label: '组织人员', path: '/organizations', permissions: ['organization.manage'], icon: UserFilled },
|
|
|
|
|
|
{ label: '系统设置', path: '/operators', permissions: ['permission.manage'], icon: Setting },
|
|
|
|
|
|
]
|
|
|
|
|
|
|
2026-09-11 17:02:42 +08:00
|
|
|
|
const route = useRoute()
|
|
|
|
|
|
const router = useRouter()
|
|
|
|
|
|
const authStore = useAuthStore()
|
|
|
|
|
|
const isCollapse = ref(false)
|
|
|
|
|
|
const globalSearch = ref('')
|
2026-09-13 21:39:32 +08:00
|
|
|
|
const notificationCount = ref(0)
|
2026-09-11 17:02:42 +08:00
|
|
|
|
|
2026-09-13 21:39:32 +08:00
|
|
|
|
const activeMenu = computed(() => {
|
|
|
|
|
|
if (route.path === '/users/detail') return '/users'
|
|
|
|
|
|
return route.path
|
|
|
|
|
|
})
|
2026-09-11 17:02:42 +08:00
|
|
|
|
const currentTitle = computed(() => (route.meta?.title as string) || '页面')
|
|
|
|
|
|
const operator = computed(() => authStore.operator)
|
2026-09-13 21:39:32 +08:00
|
|
|
|
const permissions = computed(() => authStore.permissions || [])
|
|
|
|
|
|
const currentRoleName = computed(() => {
|
|
|
|
|
|
if (permissions.value.includes('permission.manage')) return '平台管理员'
|
|
|
|
|
|
if (permissions.value.includes('counseling.service.view')) return '公益咨询人员'
|
|
|
|
|
|
if (permissions.value.includes('service_appointment.view')) return '服务站运营人员'
|
|
|
|
|
|
if (permissions.value.includes('review.view')) return '资料审核人员'
|
|
|
|
|
|
return '运营人员'
|
|
|
|
|
|
})
|
|
|
|
|
|
const visibleNavigation = computed(() => navigation.filter((item) => item.permissions.every(hasPerm)))
|
2026-09-11 17:02:42 +08:00
|
|
|
|
|
|
|
|
|
|
function hasPerm(permission: string) {
|
2026-09-13 21:39:32 +08:00
|
|
|
|
return permissions.value.includes(permission)
|
2026-09-11 17:02:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function handleSearch() {
|
|
|
|
|
|
const query = globalSearch.value.trim()
|
2026-09-13 21:39:32 +08:00
|
|
|
|
if (!query) {
|
|
|
|
|
|
ElMessage.info('请输入要查找的页面名称')
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
2026-09-11 17:02:42 +08:00
|
|
|
|
const destination = router.getRoutes().find((item) => {
|
|
|
|
|
|
const title = String(item.meta?.title || '')
|
2026-09-13 21:39:32 +08:00
|
|
|
|
const required = (item.meta?.permissions as string[] | undefined) || []
|
|
|
|
|
|
return item.path !== '/login' && title.includes(query) && required.every(hasPerm)
|
2026-09-11 17:02:42 +08:00
|
|
|
|
})
|
|
|
|
|
|
if (!destination) {
|
|
|
|
|
|
ElMessage.info('没有找到可访问的相关页面')
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
router.push(destination.path)
|
|
|
|
|
|
globalSearch.value = ''
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function showNotifications() {
|
2026-09-13 21:39:32 +08:00
|
|
|
|
ElMessage.info(notificationCount.value ? `您有 ${notificationCount.value} 条待处理通知` : '当前没有新的系统通知')
|
2026-09-11 17:02:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function handleLogout() {
|
|
|
|
|
|
authStore.logout()
|
|
|
|
|
|
router.push('/login')
|
|
|
|
|
|
}
|
2026-09-09 22:05:00 +08:00
|
|
|
|
</script>
|
2026-09-11 17:02:42 +08:00
|
|
|
|
|
2026-09-09 22:05:00 +08:00
|
|
|
|
<style scoped>
|
2026-09-13 21:39:32 +08:00
|
|
|
|
.admin-scene {
|
|
|
|
|
|
min-width: 1100px;
|
|
|
|
|
|
min-height: 100vh;
|
|
|
|
|
|
padding: 18px 34px 14px;
|
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
|
background: #fff7f7 url('/brand/admin-danyang-backdrop.jpg') center / cover fixed no-repeat;
|
2026-09-11 17:02:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-09-13 21:39:32 +08:00
|
|
|
|
.scene-header {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
max-width: 1840px;
|
|
|
|
|
|
height: 124px;
|
|
|
|
|
|
margin: 0 auto;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
|
gap: 32px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.scene-brand,
|
|
|
|
|
|
.scene-benefits,
|
|
|
|
|
|
.scene-benefits span,
|
|
|
|
|
|
.scene-brand-copy {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.scene-brand > img {
|
|
|
|
|
|
width: 64px;
|
|
|
|
|
|
height: 64px;
|
|
|
|
|
|
object-fit: contain;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.scene-brand-copy {
|
|
|
|
|
|
min-width: 172px;
|
|
|
|
|
|
margin-left: 10px;
|
|
|
|
|
|
align-items: flex-start;
|
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
color: var(--admin-coral);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.scene-brand-copy strong {
|
|
|
|
|
|
font-size: 27px;
|
|
|
|
|
|
line-height: 1.15;
|
|
|
|
|
|
letter-spacing: 2px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.scene-brand-copy span {
|
|
|
|
|
|
margin-top: 5px;
|
|
|
|
|
|
font-size: 12px;
|
|
|
|
|
|
letter-spacing: 4px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.scene-title {
|
|
|
|
|
|
min-width: 370px;
|
|
|
|
|
|
margin-left: 28px;
|
|
|
|
|
|
padding-left: 28px;
|
|
|
|
|
|
border-left: 1px solid rgba(244, 95, 104, 0.22);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.scene-title h1 {
|
|
|
|
|
|
font-size: clamp(26px, 2.2vw, 38px);
|
|
|
|
|
|
line-height: 1.1;
|
|
|
|
|
|
letter-spacing: 1px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.scene-title p {
|
|
|
|
|
|
margin-top: 9px;
|
|
|
|
|
|
color: #66717a;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.scene-benefits {
|
|
|
|
|
|
gap: clamp(14px, 2vw, 34px);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.scene-benefits span {
|
|
|
|
|
|
display: grid;
|
|
|
|
|
|
grid-template-columns: 36px auto;
|
|
|
|
|
|
column-gap: 8px;
|
|
|
|
|
|
color: var(--admin-coral);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.scene-benefits .el-icon {
|
|
|
|
|
|
grid-row: 1 / 3;
|
|
|
|
|
|
font-size: 30px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.scene-benefits b {
|
|
|
|
|
|
font-size: 13px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.scene-benefits small {
|
|
|
|
|
|
margin-top: 2px;
|
|
|
|
|
|
color: #7b7f86;
|
|
|
|
|
|
font-size: 10px;
|
|
|
|
|
|
white-space: nowrap;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.admin-shell {
|
|
|
|
|
|
width: min(1840px, 100%);
|
|
|
|
|
|
height: calc(100vh - 174px);
|
|
|
|
|
|
min-height: 560px;
|
|
|
|
|
|
margin: 0 auto;
|
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
|
background: var(--admin-shell-bg);
|
|
|
|
|
|
border: 1px solid rgba(255, 255, 255, 0.9);
|
|
|
|
|
|
border-radius: var(--admin-shell-radius);
|
|
|
|
|
|
box-shadow: var(--admin-shadow);
|
|
|
|
|
|
backdrop-filter: blur(14px);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.admin-sidebar {
|
2026-09-11 17:02:42 +08:00
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
|
color: var(--admin-sidebar-text);
|
2026-09-13 21:39:32 +08:00
|
|
|
|
background: linear-gradient(180deg, #202d38 0%, #192733 100%);
|
2026-09-11 17:02:42 +08:00
|
|
|
|
border-right: 1px solid rgba(255, 255, 255, 0.06);
|
|
|
|
|
|
transition: width 0.2s ease;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.brand {
|
|
|
|
|
|
display: flex;
|
2026-09-13 21:39:32 +08:00
|
|
|
|
height: 82px;
|
|
|
|
|
|
padding: 17px 16px;
|
2026-09-11 17:02:42 +08:00
|
|
|
|
align-items: center;
|
2026-09-13 21:39:32 +08:00
|
|
|
|
gap: 11px;
|
2026-09-11 17:02:42 +08:00
|
|
|
|
border-bottom: 1px solid rgba(255, 255, 255, 0.08);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.brand.compact {
|
|
|
|
|
|
justify-content: center;
|
2026-09-13 21:39:32 +08:00
|
|
|
|
padding: 16px 8px;
|
2026-09-11 17:02:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.brand-mark {
|
2026-09-13 21:39:32 +08:00
|
|
|
|
width: 42px;
|
|
|
|
|
|
height: 42px;
|
2026-09-11 17:02:42 +08:00
|
|
|
|
flex: none;
|
|
|
|
|
|
object-fit: contain;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.brand-copy {
|
|
|
|
|
|
display: flex;
|
2026-09-13 21:39:32 +08:00
|
|
|
|
min-width: 0;
|
2026-09-11 17:02:42 +08:00
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
white-space: nowrap;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.brand-copy strong {
|
2026-09-13 21:39:32 +08:00
|
|
|
|
color: #fff;
|
|
|
|
|
|
font-size: 17px;
|
2026-09-11 17:02:42 +08:00
|
|
|
|
letter-spacing: 1px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.brand-copy span {
|
|
|
|
|
|
margin-top: 4px;
|
2026-09-13 21:39:32 +08:00
|
|
|
|
color: #b5c0c8;
|
|
|
|
|
|
font-size: 10px;
|
|
|
|
|
|
letter-spacing: 1.5px;
|
2026-09-11 17:02:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.menu-scroll {
|
|
|
|
|
|
flex: 1;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.sidebar-menu {
|
2026-09-13 21:39:32 +08:00
|
|
|
|
padding: 13px 9px;
|
2026-09-11 17:02:42 +08:00
|
|
|
|
border: 0;
|
|
|
|
|
|
background: transparent;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.sidebar-menu :deep(.el-menu-item) {
|
2026-09-13 21:39:32 +08:00
|
|
|
|
height: 41px;
|
|
|
|
|
|
margin: 2px 0;
|
2026-09-11 17:02:42 +08:00
|
|
|
|
color: var(--admin-sidebar-text);
|
|
|
|
|
|
border-radius: 9px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.sidebar-menu :deep(.el-menu-item:hover) {
|
2026-09-13 21:39:32 +08:00
|
|
|
|
color: #fff;
|
2026-09-11 17:02:42 +08:00
|
|
|
|
background: var(--admin-sidebar-surface);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.sidebar-menu :deep(.el-menu-item.is-active) {
|
2026-09-13 21:39:32 +08:00
|
|
|
|
color: #fff;
|
|
|
|
|
|
font-weight: 650;
|
|
|
|
|
|
background: linear-gradient(135deg, #f45f68, #ee727b);
|
|
|
|
|
|
box-shadow: 0 8px 18px rgba(244, 95, 104, 0.26);
|
2026-09-11 17:02:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-09-13 21:39:32 +08:00
|
|
|
|
.sidebar-menu :deep(.el-icon) {
|
|
|
|
|
|
font-size: 17px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.sidebar-motto {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
margin: 8px 15px 2px;
|
|
|
|
|
|
padding: 14px 12px;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
gap: 11px;
|
|
|
|
|
|
color: #ff969c;
|
|
|
|
|
|
font-family: KaiTi, STKaiti, serif;
|
|
|
|
|
|
font-size: 15px;
|
|
|
|
|
|
line-height: 1.45;
|
|
|
|
|
|
border-top: 1px solid rgba(255, 255, 255, 0.08);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.sidebar-motto .el-icon {
|
|
|
|
|
|
font-size: 31px;
|
2026-09-11 17:02:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.collapse-control {
|
|
|
|
|
|
display: flex;
|
2026-09-13 21:39:32 +08:00
|
|
|
|
height: 42px;
|
|
|
|
|
|
margin: 2px 10px 10px;
|
2026-09-11 17:02:42 +08:00
|
|
|
|
align-items: center;
|
|
|
|
|
|
justify-content: center;
|
2026-09-13 21:39:32 +08:00
|
|
|
|
gap: 7px;
|
2026-09-11 17:02:42 +08:00
|
|
|
|
color: var(--admin-sidebar-muted);
|
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
|
background: transparent;
|
|
|
|
|
|
border: 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.collapse-control:hover {
|
2026-09-13 21:39:32 +08:00
|
|
|
|
color: #fff;
|
2026-09-11 17:02:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.workspace {
|
|
|
|
|
|
min-width: 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-09-13 21:39:32 +08:00
|
|
|
|
.admin-topbar {
|
2026-09-11 17:02:42 +08:00
|
|
|
|
display: flex;
|
2026-09-13 21:39:32 +08:00
|
|
|
|
height: 64px;
|
|
|
|
|
|
padding: 0 24px;
|
2026-09-11 17:02:42 +08:00
|
|
|
|
align-items: center;
|
|
|
|
|
|
justify-content: space-between;
|
2026-09-13 21:39:32 +08:00
|
|
|
|
background: rgba(255, 255, 255, 0.96);
|
|
|
|
|
|
border-bottom: 1px solid #edf0f2;
|
2026-09-11 17:02:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-09-13 21:39:32 +08:00
|
|
|
|
.page-context,
|
2026-09-11 17:02:42 +08:00
|
|
|
|
.header-tools,
|
|
|
|
|
|
.user-info {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-09-13 21:39:32 +08:00
|
|
|
|
.page-context {
|
|
|
|
|
|
min-width: 180px;
|
|
|
|
|
|
gap: 12px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.mobile-collapse {
|
|
|
|
|
|
display: none;
|
|
|
|
|
|
color: #56616a;
|
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
|
background: transparent;
|
|
|
|
|
|
border: 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-09-11 17:02:42 +08:00
|
|
|
|
.header-tools {
|
2026-09-13 21:39:32 +08:00
|
|
|
|
gap: 14px;
|
2026-09-11 17:02:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.global-search {
|
2026-09-13 21:39:32 +08:00
|
|
|
|
width: clamp(220px, 22vw, 320px);
|
2026-09-11 17:02:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.global-search :deep(.el-input__wrapper) {
|
2026-09-13 21:39:32 +08:00
|
|
|
|
background: #f6f7f8;
|
|
|
|
|
|
border-radius: 9px;
|
|
|
|
|
|
box-shadow: inset 0 0 0 1px #e8eaed;
|
2026-09-11 17:02:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.notification-button {
|
|
|
|
|
|
position: relative;
|
|
|
|
|
|
display: grid;
|
2026-09-13 21:39:32 +08:00
|
|
|
|
width: 36px;
|
|
|
|
|
|
height: 36px;
|
|
|
|
|
|
color: #4f5b65;
|
2026-09-11 17:02:42 +08:00
|
|
|
|
cursor: pointer;
|
2026-09-13 21:39:32 +08:00
|
|
|
|
background: transparent;
|
|
|
|
|
|
border: 0;
|
|
|
|
|
|
border-radius: 9px;
|
2026-09-11 17:02:42 +08:00
|
|
|
|
place-items: center;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-09-13 21:39:32 +08:00
|
|
|
|
.notification-button:hover {
|
|
|
|
|
|
background: #f6f7f8;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.notification-badge {
|
2026-09-11 17:02:42 +08:00
|
|
|
|
position: absolute;
|
2026-09-13 21:39:32 +08:00
|
|
|
|
top: 2px;
|
|
|
|
|
|
right: 1px;
|
|
|
|
|
|
min-width: 15px;
|
|
|
|
|
|
height: 15px;
|
|
|
|
|
|
padding: 0 3px;
|
|
|
|
|
|
color: #fff;
|
|
|
|
|
|
font-size: 9px;
|
|
|
|
|
|
line-height: 15px;
|
|
|
|
|
|
text-align: center;
|
|
|
|
|
|
background: var(--admin-coral);
|
|
|
|
|
|
border-radius: 999px;
|
2026-09-11 17:02:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.user-info {
|
2026-09-13 21:39:32 +08:00
|
|
|
|
gap: 8px;
|
2026-09-11 17:02:42 +08:00
|
|
|
|
cursor: pointer;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.user-info .el-avatar {
|
2026-09-13 21:39:32 +08:00
|
|
|
|
color: #fff;
|
|
|
|
|
|
background: var(--admin-coral);
|
2026-09-11 17:02:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-09-13 21:39:32 +08:00
|
|
|
|
.user-info strong {
|
|
|
|
|
|
max-width: 92px;
|
|
|
|
|
|
overflow: hidden;
|
2026-09-11 17:02:42 +08:00
|
|
|
|
font-size: 13px;
|
2026-09-13 21:39:32 +08:00
|
|
|
|
text-overflow: ellipsis;
|
|
|
|
|
|
white-space: nowrap;
|
2026-09-11 17:02:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-09-13 21:39:32 +08:00
|
|
|
|
.admin-content {
|
2026-09-11 17:02:42 +08:00
|
|
|
|
padding: 0;
|
|
|
|
|
|
overflow: auto;
|
|
|
|
|
|
background: var(--admin-page-bg);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-09-13 21:39:32 +08:00
|
|
|
|
.scene-footer {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
max-width: 1840px;
|
|
|
|
|
|
height: 32px;
|
|
|
|
|
|
margin: 0 auto;
|
|
|
|
|
|
align-items: flex-end;
|
|
|
|
|
|
gap: 10px;
|
|
|
|
|
|
color: #8d8587;
|
|
|
|
|
|
font-size: 11px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.scene-footer strong {
|
|
|
|
|
|
color: var(--admin-coral);
|
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.scene-footer small {
|
|
|
|
|
|
margin-left: auto;
|
|
|
|
|
|
letter-spacing: 4px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@media (max-width: 1450px), (max-height: 820px) {
|
|
|
|
|
|
.admin-scene {
|
|
|
|
|
|
padding: 12px 24px 10px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.scene-header {
|
|
|
|
|
|
height: 96px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.scene-brand > img {
|
|
|
|
|
|
width: 52px;
|
|
|
|
|
|
height: 52px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.scene-brand-copy strong {
|
|
|
|
|
|
font-size: 22px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.scene-title {
|
|
|
|
|
|
min-width: 310px;
|
|
|
|
|
|
margin-left: 18px;
|
|
|
|
|
|
padding-left: 18px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.scene-title h1 {
|
|
|
|
|
|
font-size: 27px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.scene-benefits span:nth-child(-n + 2) {
|
|
|
|
|
|
display: none;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.admin-shell {
|
|
|
|
|
|
height: calc(100vh - 140px);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.scene-footer {
|
|
|
|
|
|
height: 28px;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@media (max-width: 1180px) {
|
|
|
|
|
|
.scene-title {
|
|
|
|
|
|
display: none;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.mobile-collapse {
|
|
|
|
|
|
display: inline-grid;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.admin-sidebar {
|
|
|
|
|
|
width: 76px !important;
|
2026-09-11 17:02:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.brand-copy,
|
|
|
|
|
|
.collapse-control span,
|
2026-09-13 21:39:32 +08:00
|
|
|
|
.sidebar-motto {
|
2026-09-11 17:02:42 +08:00
|
|
|
|
display: none;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.brand {
|
|
|
|
|
|
justify-content: center;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@media (max-width: 760px) {
|
2026-09-13 21:39:32 +08:00
|
|
|
|
.admin-scene {
|
|
|
|
|
|
min-width: 0;
|
|
|
|
|
|
padding: 0;
|
2026-09-11 17:02:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-09-13 21:39:32 +08:00
|
|
|
|
.scene-header,
|
|
|
|
|
|
.scene-footer,
|
2026-09-11 17:02:42 +08:00
|
|
|
|
.global-search,
|
2026-09-13 21:39:32 +08:00
|
|
|
|
.user-info strong {
|
2026-09-11 17:02:42 +08:00
|
|
|
|
display: none;
|
|
|
|
|
|
}
|
2026-09-13 21:39:32 +08:00
|
|
|
|
|
|
|
|
|
|
.admin-shell {
|
|
|
|
|
|
height: 100vh;
|
|
|
|
|
|
min-height: 0;
|
|
|
|
|
|
border-radius: 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.admin-topbar {
|
|
|
|
|
|
padding: 0 12px;
|
|
|
|
|
|
}
|
2026-09-11 17:02:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
</style>
|