feat: role CRUD page

This commit is contained in:
tao.chen
2026-08-25 22:52:00 +08:00
parent 5ed7e12a23
commit 6fe2d0b42e
12 changed files with 891 additions and 6 deletions
+3 -2
View File
@@ -1,8 +1,8 @@
import { Home, Code, Calendar, Settings, Users, Folder } from "lucide-react";
import { Home, Code, Calendar, Settings, Users, Folder, ShieldCheck } from "lucide-react";
import type { ComponentType } from "react";
export type ActivePage = "home" | "scripts" | "schedules" | "system";
export type SubPage = "users" | "projects";
export type SubPage = "users" | "projects" | "roles";
export type NavigationItem = {
/** 菜单显示名 */
@@ -33,6 +33,7 @@ export const navigation: NavigationItem[] = [
children: [
{ label: "用户管理", icon: Users, page: "system", sub: "users", permission: "system:user:view" },
{ label: "项目管理", icon: Folder, page: "system", sub: "projects", permission: "system:project:view" },
{ label: "角色管理", icon: ShieldCheck, page: "system", sub: "roles", permission: "system:role:view" },
],
},
];
+3 -3
View File
@@ -3,7 +3,7 @@ import { Outlet, useLocation, useNavigate } from "react-router";
import { PanelLeft, ChevronRight } from "lucide-react";
import { navigation } from "./platform.navigation";
import type { ActivePage, NavigationItem } from "./platform.navigation";
import type { ActivePage, NavigationItem, SubPage } from "./platform.navigation";
import { Collapsible } from "@base-ui/react/collapsible";
import type { Route } from "./+types/platform";
@@ -70,7 +70,7 @@ function NavRow({
can: (code: string) => boolean;
activePage: ActivePage;
pathname: string;
onNavigate: (sub?: "users" | "projects") => void;
onNavigate: (sub?: SubPage) => void;
}) {
const itemIcon = <item.icon />;
const childActivePath = (child: NavigationItem) =>
@@ -208,7 +208,7 @@ function AuthenticatedLayout() {
// 原 common/Sidebar 的编辑会话守卫上移到这里:切出 /scripts 时有活动编辑
// 会话先 endEditing,回工作台时清空选中脚本;再按当前激活页导航。
function guardedNavigate(page: ActivePage, sub?: "users" | "projects") {
function guardedNavigate(page: ActivePage, sub?: SubPage) {
if (page !== "scripts" && editSessionHandle.current) {
void endEditing(true);
} else if (page === "home") {
+23
View File
@@ -0,0 +1,23 @@
import { useAuth } from "~/context/AuthContext";
import { useScriptWorkspaceStore } from "~/features/platform/state/scriptWorkspaceStore";
import { useUiStore } from "~/features/platform/state/uiStore";
import { RoleManagementPage } from "~/features/admin/RoleManagementPage";
/**
* /system/roles 路由页。RoleManagementPage 内部有 useState
* 在 user / workspace 切换时必须重挂载以重置本地状态
* (见 CLAUDE.md「Route components with their own internal state」)。
*/
export default function RoleManagementRoute() {
const { user, currentWorkspace } = useAuth();
const setApiOnline = useScriptWorkspaceStore((s) => s.setApiOnline);
const pushToast = useUiStore((s) => s.pushToast);
return (
<RoleManagementPage
key={`${user?.user_id ?? "anon"}-${currentWorkspace?.workspace_id ?? "none"}`}
onNotify={pushToast}
onConnectionChange={setApiOnline}
/>
);
}