feat(client): 导航布局收敛与移动端菜单(E3)

- Sidebar/Topbar 统一交互与样式
- 移动端抽屉菜单(Dialog)+ 账号下拉菜单(DropdownMenu)
- 导航项抽取为 NavLinks 便于后续扩展
这个提交包含在:
2026-02-08 23:22:22 +08:00
父节点 c7619e55b4
当前提交 8196bc6e77
共修改 4 个文件,包含 174 行新增和 76 行删除
+4 -62
查看文件
@@ -1,49 +1,6 @@
import { NavLink } from "react-router-dom";
import { useAuth } from "../../auth/AuthContext";
import { hasAnyPermission } from "../../auth/permissions";
type NavItem = {
to: string;
label: string;
anyOf?: string[];
};
const NAV_ITEMS: NavItem[] = [
{ to: "/dashboard", label: "仪表盘" },
{
to: "/reimbursements",
label: "我的报销",
anyOf: ["expense.view_own", "expense.view_all"],
},
{
to: "/workflow/tasks",
label: "待我处理",
anyOf: ["expense.approve"],
},
{
to: "/invoice-pool",
label: "票据中心",
anyOf: ["invoice.upload", "invoice.view_own", "invoice.manage"],
},
{
to: "/audit-logs",
label: "审计工作台",
anyOf: ["system.audit.view"],
},
{ to: "/settings/profile", label: "个人设置" },
];
import { NavLinks } from "./NavLinks";
export function Sidebar() {
const { permissions } = useAuth();
const visibleItems = NAV_ITEMS.filter((item) => {
if (!item.anyOf) {
return true;
}
return hasAnyPermission(permissions, item.anyOf);
});
return (
<aside className="hidden w-64 shrink-0 border-r border-slate-200 bg-white lg:flex lg:flex-col">
<div className="border-b border-slate-200 px-6 py-5">
@@ -51,24 +8,9 @@ export function Sidebar() {
<h1 className="mt-1 text-lg font-bold text-slate-900">海音达工作台</h1>
</div>
<nav className="flex-1 space-y-1 p-4">
{visibleItems.map((item) => (
<NavLink
key={item.to}
to={item.to}
className={({ isActive }) =>
[
"block rounded-lg px-3 py-2 text-sm font-medium transition-colors",
isActive
? "bg-primary-50 text-primary"
: "text-slate-700 hover:bg-slate-50 hover:text-slate-900",
].join(" ")
}
>
{item.label}
</NavLink>
))}
</nav>
<div className="flex-1 p-4">
<NavLinks />
</div>
</aside>
);
}