debt(D6): Admin 导航单源 —— NAV_ITEMS 派生侧栏/命令面板/面包屑
- 新增 admin/nav.ts: 唯一配置源 NAV_ITEMS(to/label/group/icon/hideFromSidebar) - COMMAND_PALETTE_PAGES / ROUTE_LABELS / NAV_SECTIONS 全部由其派生 - 删除 AdminLayout 中三份平行清单(已出现漂移: data-pipeline 不在侧栏、 「系统」vs「系统设置」命名不一致、monitoring/eval 顺序两处相反) - 已知微差: 命令面板「评估与监控」组内顺序统一为侧栏口径(eval 在前) - 行为不变: 路由/标签/分组标题均保持现状;data-pipeline 保持仅面板可达
This commit is contained in:
@@ -9,6 +9,7 @@ import { useState, useEffect, useCallback } from 'react'
|
|||||||
import { NavLink, Outlet, useLocation } from 'react-router-dom'
|
import { NavLink, Outlet, useLocation } from 'react-router-dom'
|
||||||
import { fetchAuthState, logout, UNAUTHORIZED_EVENT } from './api'
|
import { fetchAuthState, logout, UNAUTHORIZED_EVENT } from './api'
|
||||||
import { fetchHealth } from './dal'
|
import { fetchHealth } from './dal'
|
||||||
|
import { COMMAND_PALETTE_PAGES, ROUTE_LABELS, NAV_SECTIONS } from './nav'
|
||||||
import Login from './Login'
|
import Login from './Login'
|
||||||
import { useCommandPalette, CommandPalette } from './useCommandPalette'
|
import { useCommandPalette, CommandPalette } from './useCommandPalette'
|
||||||
|
|
||||||
@@ -88,58 +89,9 @@ function Icon({ name }: { name: string }) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const NAV_PAGES: Array<{ to: string; label: string; group: string }> = [
|
// D6: 导航三视图(侧栏/命令面板/面包屑)统一由 admin/nav.ts 的 NAV_ITEMS
|
||||||
{ to: '/admin', label: '仪表盘', group: '概览' },
|
// 单源派生 —— 此处的 NAV_PAGES/ROUTE_LABELS/NAV_SECTIONS 平行清单已删除,
|
||||||
{ to: '/admin/collection', label: '数据采集', group: '数据流水线' },
|
// 新增页面/改标签只改 nav.ts 一处。
|
||||||
{ to: '/admin/data-completeness', label: '数据完整性', group: '数据流水线' },
|
|
||||||
{ to: '/admin/data-pipeline', label: '数据管线', group: '数据流水线' },
|
|
||||||
{ to: '/admin/predictions', label: '预测历史', group: '数据流水线' },
|
|
||||||
{ to: '/admin/backtest', label: '回测', group: '数据流水线' },
|
|
||||||
{ to: '/admin/monitoring', label: '监控', group: '评估与监控' },
|
|
||||||
{ to: '/admin/eval', label: '评估', group: '评估与监控' },
|
|
||||||
{ to: '/admin/settings', label: '设置', group: '系统' },
|
|
||||||
{ to: '/admin/logs', label: '日志', group: '系统' },
|
|
||||||
]
|
|
||||||
|
|
||||||
// 路由 → 面包屑标签
|
|
||||||
const ROUTE_LABELS: Record<string, string> = {
|
|
||||||
'/admin': '仪表盘',
|
|
||||||
'/admin/collection': '数据采集',
|
|
||||||
'/admin/data-completeness': '数据完整性',
|
|
||||||
'/admin/data-pipeline': '数据管线',
|
|
||||||
'/admin/predictions': '预测历史',
|
|
||||||
'/admin/backtest': '回测',
|
|
||||||
'/admin/monitoring': '监控',
|
|
||||||
'/admin/settings': '设置',
|
|
||||||
'/admin/logs': '日志',
|
|
||||||
'/admin/eval': '评估',
|
|
||||||
}
|
|
||||||
|
|
||||||
const NAV_SECTIONS: { title: string; items: Array<{ to: string; label: string; icon: string }> }[] = [
|
|
||||||
{
|
|
||||||
title: '数据流水线',
|
|
||||||
items: [
|
|
||||||
{ to: '/admin/collection', label: '数据采集', icon: 'collection' },
|
|
||||||
{ to: '/admin/data-completeness', label: '数据完整性', icon: 'chart' },
|
|
||||||
{ to: '/admin/predictions', label: '预测历史', icon: 'logs' },
|
|
||||||
{ to: '/admin/backtest', label: '回测', icon: 'repeat' },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '评估与监控',
|
|
||||||
items: [
|
|
||||||
{ to: '/admin/eval', label: '评估', icon: 'eval' },
|
|
||||||
{ to: '/admin/monitoring', label: '监控', icon: 'monitor' },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '系统设置',
|
|
||||||
items: [
|
|
||||||
{ to: '/admin/settings', label: '设置', icon: 'settings' },
|
|
||||||
{ to: '/admin/logs', label: '日志', icon: 'logs' },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
]
|
|
||||||
|
|
||||||
/** 报眉日期行,与前台同款式 */
|
/** 报眉日期行,与前台同款式 */
|
||||||
function dateLine(): string {
|
function dateLine(): string {
|
||||||
@@ -156,7 +108,7 @@ export default function AdminLayout() {
|
|||||||
const [healthOk, setHealthOk] = useState<boolean | null>(null)
|
const [healthOk, setHealthOk] = useState<boolean | null>(null)
|
||||||
const [authed, setAuthed] = useState<boolean | null>(null)
|
const [authed, setAuthed] = useState<boolean | null>(null)
|
||||||
const location = useLocation()
|
const location = useLocation()
|
||||||
const palette = useCommandPalette(NAV_PAGES)
|
const palette = useCommandPalette(COMMAND_PALETTE_PAGES)
|
||||||
|
|
||||||
// 登录门禁:挂载时探测会话,收到 401 事件(会话过期)自动切回登录页
|
// 登录门禁:挂载时探测会话,收到 401 事件(会话过期)自动切回登录页
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|||||||
@@ -0,0 +1,67 @@
|
|||||||
|
/**
|
||||||
|
* Admin 导航单源(D6)。
|
||||||
|
*
|
||||||
|
* 背景: 侧栏(NAV_SECTIONS)、命令面板(NAV_PAGES)、面包屑(ROUTE_LABELS)
|
||||||
|
* 此前各维护一份平行清单,已出现漂移 —— data-pipeline 不在侧栏、
|
||||||
|
* 「系统」vs「系统设置」命名不一致、monitoring/eval 两处顺序相反。
|
||||||
|
*
|
||||||
|
* 现在只允许维护 NAV_ITEMS 一份,其余视图一律由此派生;
|
||||||
|
* 禁止再新建平行导航清单(修改入口/新增页面只改这里)。
|
||||||
|
*/
|
||||||
|
|
||||||
|
export interface NavItem {
|
||||||
|
to: string
|
||||||
|
label: string
|
||||||
|
/** 命令面板中的分组名(展示原样) */
|
||||||
|
group: string
|
||||||
|
/** 侧栏图标名(见 AdminLayout 的 Icon) */
|
||||||
|
icon: string
|
||||||
|
/** 仅命令面板/面包屑可达,不进侧栏(深链页) */
|
||||||
|
hideFromSidebar?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 唯一的导航配置源。顺序 = 侧栏渲染顺序(命令面板分组内顺序与之相同)。 */
|
||||||
|
export const NAV_ITEMS: NavItem[] = [
|
||||||
|
{ to: '/admin', label: '仪表盘', group: '概览', icon: 'chart' },
|
||||||
|
{ to: '/admin/collection', label: '数据采集', group: '数据流水线', icon: 'collection' },
|
||||||
|
{ to: '/admin/data-completeness', label: '数据完整性', group: '数据流水线', icon: 'chart' },
|
||||||
|
{ to: '/admin/data-pipeline', label: '数据管线', group: '数据流水线', icon: 'chart', hideFromSidebar: true },
|
||||||
|
{ to: '/admin/predictions', label: '预测历史', group: '数据流水线', icon: 'logs' },
|
||||||
|
{ to: '/admin/backtest', label: '回测', group: '数据流水线', icon: 'repeat' },
|
||||||
|
{ to: '/admin/eval', label: '评估', group: '评估与监控', icon: 'eval' },
|
||||||
|
{ to: '/admin/monitoring', label: '监控', group: '评估与监控', icon: 'monitor' },
|
||||||
|
{ to: '/admin/settings', label: '设置', group: '系统', icon: 'settings' },
|
||||||
|
{ to: '/admin/logs', label: '日志', group: '系统', icon: 'logs' },
|
||||||
|
]
|
||||||
|
|
||||||
|
/** 命令面板条目(原 NAV_PAGES 的唯一来源) */
|
||||||
|
export const COMMAND_PALETTE_PAGES = NAV_ITEMS.map(({ to, label, group }) => ({ to, label, group }))
|
||||||
|
|
||||||
|
/** 路由 → 面包屑标签(原 ROUTE_LABELS 的唯一来源) */
|
||||||
|
export const ROUTE_LABELS: Record<string, string> = Object.fromEntries(
|
||||||
|
NAV_ITEMS.map(i => [i.to, i.label]),
|
||||||
|
)
|
||||||
|
|
||||||
|
/** 侧栏分组标题的历史显示名(仅侧栏使用;与面板分组名不同时在此映射) */
|
||||||
|
const SIDEBAR_GROUP_TITLES: Record<string, string> = {
|
||||||
|
系统: '系统设置',
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 侧栏分组(原 NAV_SECTIONS 的唯一来源)。
|
||||||
|
* 仪表盘(group=概览)在 AdminLayout 中独立渲染于顶部,不进分组循环。
|
||||||
|
*/
|
||||||
|
export const NAV_SECTIONS = (() => {
|
||||||
|
const sidebarItems = NAV_ITEMS.filter(i => !i.hideFromSidebar && i.group !== '概览')
|
||||||
|
const titles: string[] = []
|
||||||
|
for (const i of sidebarItems) {
|
||||||
|
const title = SIDEBAR_GROUP_TITLES[i.group] ?? i.group
|
||||||
|
if (!titles.includes(title)) titles.push(title)
|
||||||
|
}
|
||||||
|
return titles.map(title => ({
|
||||||
|
title,
|
||||||
|
items: sidebarItems
|
||||||
|
.filter(i => (SIDEBAR_GROUP_TITLES[i.group] ?? i.group) === title)
|
||||||
|
.map(({ to, label, icon }) => ({ to, label, icon })),
|
||||||
|
}))
|
||||||
|
})()
|
||||||
Reference in New Issue
Block a user