diff --git a/apps/frontend/src/components.d.ts b/apps/frontend/src/components.d.ts index 58b3b015..3ecc6fcf 100644 --- a/apps/frontend/src/components.d.ts +++ b/apps/frontend/src/components.d.ts @@ -45,6 +45,7 @@ declare module 'vue' { ElSelect: typeof import('element-plus/es')['ElSelect'] ElSkeleton: typeof import('element-plus/es')['ElSkeleton'] ElSpace: typeof import('element-plus/es')['ElSpace'] + ElSubMenu: typeof import('element-plus/es')['ElSubMenu'] ElSwitch: typeof import('element-plus/es')['ElSwitch'] ElTable: typeof import('element-plus/es')['ElTable'] ElTableColumn: typeof import('element-plus/es')['ElTableColumn'] diff --git a/apps/frontend/src/views/admin/layout/AdminLayout.vue b/apps/frontend/src/views/admin/layout/AdminLayout.vue index f2e40359..671839d0 100644 --- a/apps/frontend/src/views/admin/layout/AdminLayout.vue +++ b/apps/frontend/src/views/admin/layout/AdminLayout.vue @@ -2,6 +2,8 @@ import { computed, ref } from 'vue' import { useRoute, useRouter } from 'vue-router' import { + Bell, + Connection, Monitor, DataAnalysis, Document, @@ -27,6 +29,7 @@ import { formatAdminDateTime } from '@/utils/admin-time' const route = useRoute() const router = useRouter() const sidebarStorageKey = 'admin-sidebar-collapsed' +const isDevMode = import.meta.env.DEV const isSidebarCollapsed = ref( typeof window !== 'undefined' && window.localStorage.getItem(sidebarStorageKey) === '1', ) @@ -40,8 +43,33 @@ const roleLabel = computed(() => { return '普通运营' }) +type AdminNavItem = { + to: string + label: string + icon: typeof DataAnalysis + children?: AdminNavItem[] +} + +const platformConfigNavItems = computed(() => { + const items: AdminNavItem[] = [ + { to: '/admin/platform-shops?tab=ninetyone', label: '91卡券', icon: Connection }, + { to: '/admin/platform-shops?tab=notifications', label: '内部通知', icon: Bell }, + { to: '/admin/platform-shops?tab=kuaishouEticket', label: '快手小店核销', icon: Tickets }, + ] + + if (isDevMode) { + items.push({ + to: '/admin/platform-shops?tab=cloudtentacles', + label: 'cloudtentacles', + icon: Setting, + }) + } + + return items +}) + const navItems = computed(() => { - const items: { to: string; label: string; icon: typeof DataAnalysis }[] = [ + const items: AdminNavItem[] = [ { to: '/admin/dashboard', label: '概览', icon: DataAnalysis }, ] @@ -56,7 +84,12 @@ const navItems = computed(() => { if (isAdmin.value) { items.push( - { to: '/admin/platform-shops', label: '平台配置', icon: Setting }, + { + to: '/admin/platform-shops', + label: '平台配置', + icon: Setting, + children: platformConfigNavItems.value, + }, { to: '/admin/platform-fulfillment', label: '履约配置', icon: Tickets }, { to: '/admin/audit-logs', label: '审计', icon: Monitor }, ) @@ -65,6 +98,15 @@ const navItems = computed(() => { return items }) +const activeNavIndex = computed(() => { + if (route.path === '/admin/platform-shops') { + const tab = typeof route.query.tab === 'string' ? route.query.tab : 'ninetyone' + return `/admin/platform-shops?tab=${tab}` + } + + return route.path +}) + function toggleSidebarCollapse() { isSidebarCollapsed.value = !isSidebarCollapsed.value if (typeof window !== 'undefined') { @@ -112,17 +154,37 @@ async function submitLogout() { - - - {{ item.label }} - + @@ -235,18 +297,33 @@ async function submitLogout() { width: 100%; } -.sidebar-menu :deep(.el-menu-item) { +.sidebar-menu :deep(.el-menu-item), +.sidebar-menu :deep(.el-sub-menu__title) { margin: 2px var(--space-2); border-radius: var(--radius-md); min-height: 44px; line-height: 44px; } -.sidebar-menu :deep(.el-menu-item.is-active) { +.sidebar-menu :deep(.el-menu-item.is-active), +.sidebar-menu :deep(.el-sub-menu.is-active > .el-sub-menu__title) { color: var(--color-primary); background: var(--color-primary-light); } +.sidebar-menu :deep(.el-sub-menu .el-menu-item) { + margin-left: var(--space-4); + min-height: 38px; + line-height: 38px; + color: var(--text-secondary); + font-size: var(--text-sm); +} + +.sidebar-menu :deep(.el-sub-menu .el-menu-item.is-active) { + color: var(--color-primary); + font-weight: 700; +} + .logout-btn { margin: var(--space-3) var(--space-4) 0; flex-shrink: 0; @@ -263,13 +340,15 @@ async function submitLogout() { margin-bottom: var(--space-5); } -.is-sidebar-collapsed .sidebar-menu :deep(.el-menu-item) { +.is-sidebar-collapsed .sidebar-menu :deep(.el-menu-item), +.is-sidebar-collapsed .sidebar-menu :deep(.el-sub-menu__title) { justify-content: center; margin: 4px 10px; padding: 0; } -.is-sidebar-collapsed .sidebar-menu :deep(.el-menu-item .el-icon) { +.is-sidebar-collapsed .sidebar-menu :deep(.el-menu-item .el-icon), +.is-sidebar-collapsed .sidebar-menu :deep(.el-sub-menu__title .el-icon) { margin-right: 0; } @@ -313,7 +392,8 @@ async function submitLogout() { overflow: visible; } - .is-sidebar-collapsed .sidebar-menu :deep(.el-menu-item) { + .is-sidebar-collapsed .sidebar-menu :deep(.el-menu-item), + .is-sidebar-collapsed .sidebar-menu :deep(.el-sub-menu__title) { justify-content: flex-start; margin: 2px var(--space-2); padding: 0 var(--space-5); diff --git a/apps/frontend/src/views/admin/platform-shops/AdminPlatformShopsView.vue b/apps/frontend/src/views/admin/platform-shops/AdminPlatformShopsView.vue index db3a162b..e37d6dc4 100644 --- a/apps/frontend/src/views/admin/platform-shops/AdminPlatformShopsView.vue +++ b/apps/frontend/src/views/admin/platform-shops/AdminPlatformShopsView.vue @@ -1,5 +1,6 @@ @@ -267,150 +287,139 @@ onMounted(loadConfigs) @@ -422,68 +431,85 @@ onMounted(loadConfigs) gap: var(--space-4); } -/* 概览卡片网格 */ -.overview-grid { +.platform-detail { + min-width: 0; display: grid; - grid-template-columns: repeat(auto-fit, minmax(210px, 1fr)); gap: var(--space-4); } -.overview-card { - cursor: pointer; - transition: - border-color 0.2s ease, - box-shadow 0.2s ease; -} - -.overview-card :deep(.el-card__body) { - padding: 18px; -} - -.overview-card.is-active { - border-color: var(--border-hover); - box-shadow: var(--shadow-lg); -} - -.card-head { +.active-summary { display: flex; - gap: var(--space-2); - margin-bottom: var(--space-3); + justify-content: space-between; + gap: var(--space-4); + align-items: center; + padding: var(--space-4) var(--space-5); + border: 1px solid var(--border-default); + border-radius: var(--radius-lg); + background: rgba(255, 255, 255, 0.92); + box-shadow: var(--shadow-sm); } -.card-value { - font-size: 26px; - font-weight: 700; - color: var(--text-primary); - line-height: 1.1; +.active-summary-copy { + min-width: 0; } -.card-unit { - color: var(--text-muted); - font-size: var(--text-sm); - margin-top: var(--space-1); -} - -.card-meta { - color: var(--text-secondary); +.summary-kicker { + color: #2563eb; font-size: var(--text-xs); - margin-top: var(--space-2); + font-weight: 800; } -/* Tab 切换 */ -.platform-tabs { - margin-top: var(--space-2); +.active-summary h2 { + margin: 4px 0 0; + color: var(--text-primary); + font-size: var(--text-xl); + line-height: 1.25; } -@media (max-width: 900px) { - .overview-grid { - grid-template-columns: repeat(2, 1fr); +.active-summary p { + margin: var(--space-2) 0 0; + color: var(--text-secondary); + font-size: var(--text-sm); + line-height: 1.6; +} + +.summary-metrics { + flex: 0 0 auto; + display: flex; + gap: var(--space-3); + align-items: center; +} + +.summary-metric { + min-width: 112px; + display: grid; + gap: 4px; + padding: 10px 12px; + border: 1px solid rgba(148, 163, 184, 0.18); + border-radius: var(--radius-sm); + background: #f8fafc; +} + +.summary-metric span { + color: var(--text-muted); + font-size: var(--text-xs); + font-weight: 700; +} + +.summary-metric strong { + color: var(--text-primary); + font-size: var(--text-xl); + line-height: 1; +} + +@media (max-width: 720px) { + .active-summary { + align-items: stretch; + flex-direction: column; } -} -@media (max-width: 640px) { - .overview-grid { - grid-template-columns: 1fr; + .summary-metrics { + justify-content: space-between; } } diff --git a/apps/frontend/src/views/admin/platform-shops/components/AdminPlatformNinetyoneSection.vue b/apps/frontend/src/views/admin/platform-shops/components/AdminPlatformNinetyoneSection.vue index 78b20e4a..3e4b4214 100644 --- a/apps/frontend/src/views/admin/platform-shops/components/AdminPlatformNinetyoneSection.vue +++ b/apps/frontend/src/views/admin/platform-shops/components/AdminPlatformNinetyoneSection.vue @@ -28,21 +28,6 @@ defineProps()