feat(client): 初始化前端壳与鉴权守卫(P1-5)
- 技术栈:React 18 + TypeScript + Vite + Tailwind - API 层:ApiError + 401 自动刷新 + single-flight 重试 - 鉴权:内存 Access Token + Cookie Refresh + 启动 bootstrap - RBAC:权限映射 + RequireAuth/RequirePermission 路由守卫 - 布局:OA 工作台壳层 + 侧边栏 + 5 个占位页面 - 样式:复用 hyb-web 视觉 token(单向同步) - 文档:新增 client README,补充 server 联调说明
这个提交包含在:
@@ -0,0 +1,73 @@
|
||||
import { Navigate, Route, Routes } from "react-router-dom";
|
||||
import { AppShellLayout } from "../layouts/AppShellLayout";
|
||||
import { AuthLayout } from "../layouts/AuthLayout";
|
||||
import { DashboardPage } from "../pages/DashboardPage";
|
||||
import { ForbiddenPage } from "../pages/ForbiddenPage";
|
||||
import { InvoicePoolPage } from "../pages/InvoicePoolPage";
|
||||
import { LoginPage } from "../pages/LoginPage";
|
||||
import { NotFoundPage } from "../pages/NotFoundPage";
|
||||
import { ProfilePage } from "../pages/ProfilePage";
|
||||
import { ReimbursementsPage } from "../pages/ReimbursementsPage";
|
||||
import { WorkflowTasksPage } from "../pages/WorkflowTasksPage";
|
||||
import { GuestOnly, RequireAuth, RequirePermission } from "./guards";
|
||||
|
||||
export function AppRouter() {
|
||||
return (
|
||||
<Routes>
|
||||
<Route
|
||||
path="/login"
|
||||
element={
|
||||
<GuestOnly>
|
||||
<AuthLayout />
|
||||
</GuestOnly>
|
||||
}
|
||||
>
|
||||
<Route index element={<LoginPage />} />
|
||||
</Route>
|
||||
|
||||
<Route
|
||||
path="/"
|
||||
element={
|
||||
<RequireAuth>
|
||||
<AppShellLayout />
|
||||
</RequireAuth>
|
||||
}
|
||||
>
|
||||
<Route index element={<Navigate to="/dashboard" replace />} />
|
||||
<Route path="dashboard" element={<DashboardPage />} />
|
||||
|
||||
<Route
|
||||
path="reimbursements"
|
||||
element={
|
||||
<RequirePermission anyOf={["expense.view_own", "expense.view_all"]}>
|
||||
<ReimbursementsPage />
|
||||
</RequirePermission>
|
||||
}
|
||||
/>
|
||||
|
||||
<Route
|
||||
path="workflow/tasks"
|
||||
element={
|
||||
<RequirePermission anyOf={["expense.approve"]}>
|
||||
<WorkflowTasksPage />
|
||||
</RequirePermission>
|
||||
}
|
||||
/>
|
||||
|
||||
<Route
|
||||
path="invoice-pool"
|
||||
element={
|
||||
<RequirePermission anyOf={["invoice.upload", "invoice.view_own", "invoice.manage"]}>
|
||||
<InvoicePoolPage />
|
||||
</RequirePermission>
|
||||
}
|
||||
/>
|
||||
|
||||
<Route path="settings/profile" element={<ProfilePage />} />
|
||||
</Route>
|
||||
|
||||
<Route path="/403" element={<ForbiddenPage />} />
|
||||
<Route path="*" element={<NotFoundPage />} />
|
||||
</Routes>
|
||||
);
|
||||
}
|
||||
在新工单中引用
屏蔽一个用户