fix(admin): 优化列表布局间距、滚动固定与侧栏子路由选中

统一嵌套卡片内边距与 Tabs 外壳样式,联赛单场支持表头/分页固定滚动;子页面下代理玩家菜单保持高亮。
This commit is contained in:
2026-06-22 16:48:40 +08:00
parent 78b426a388
commit b9257cc50a
7 changed files with 149 additions and 84 deletions

View File

@@ -77,7 +77,7 @@ const adminMenus = computed(() => {
const items: AdminMenuItem[] = [
{ key: 'dashboard', path: '/', label: t('nav.dashboard'), icon: 'dashboard', matchPrefix: true, permissions: [AdminPerm.reports], excludeRoles: ['SUPPORT'] },
{ key: 'matches', path: '/matches', label: t('nav.matches'), icon: 'matches', matchPrefix: true, permissions: [AdminPerm.matches] },
{ key: 'users', path: '/users', label: t('nav.agents_players'), icon: 'users', permissions: [AdminPerm.usersView, AdminPerm.agentsView] },
{ key: 'users', path: '/users', label: t('nav.agents_players'), icon: 'users', matchPrefix: true, permissions: [AdminPerm.usersView, AdminPerm.agentsView] },
{ key: 'finance-logs', path: '/finance-logs', label: t('nav.finance_logs'), icon: 'finance', permissions: [AdminPerm.reports], excludeRoles: ['MATCH_ADMIN'] },
{ key: 'deposit', path: '/deposit', label: t('nav.deposit_manage'), icon: 'deposit', matchPrefix: true, permissions: [AdminPerm.depositManage, AdminPerm.depositReview] },
{ key: 'cashback', path: '/cashback', label: t('nav.cashback'), icon: 'cashback', permissions: [AdminPerm.cashback], excludeRoles: ['MATCH_ADMIN', 'SUPPORT'] },
@@ -117,15 +117,17 @@ function isDepositSectionPath(path: string) {
return path === '/deposit' || path === '/deposit-orders' || path === '/payment-methods';
}
function isMenuActive(menu: { path: string; matchPrefix?: boolean }, path: string) {
if (path === menu.path) return true;
if (!menu.matchPrefix) return false;
if (menu.path === '/') return isDashboardSectionPath(path);
if (menu.path === '/deposit') return isDepositSectionPath(path);
if (menu.path === '/matches') return isMatchesSectionPath(path);
return path.startsWith(`${menu.path}/`);
}
const currentLabel = computed(() => {
const hit = menus.value.find((m) => {
if ('matchPrefix' in m && m.matchPrefix) {
if (m.path === '/') return isDashboardSectionPath(route.path);
if (m.path === '/deposit') return isDepositSectionPath(route.path);
return isMatchesSectionPath(route.path);
}
return route.path === m.path;
});
const hit = menus.value.find((m) => isMenuActive(m, route.path));
return hit?.label ?? '';
});
@@ -226,17 +228,7 @@ watch(() => route.path, () => {
<RouterLink
v-for="m in menus" :key="m.path" :to="m.path"
class="nav-item"
:class="{
active:
route.path === m.path ||
('matchPrefix' in m &&
m.matchPrefix &&
(m.path === '/'
? isDashboardSectionPath(route.path)
: m.path === '/deposit'
? isDepositSectionPath(route.path)
: isMatchesSectionPath(route.path))),
}"
:class="{ active: isMenuActive(m, route.path) }"
@click="onNavClick"
@mouseenter="prefetchNavRoute(m.path)"
@focus="prefetchNavRoute(m.path)"