feat: 接入运维真实数据与三角色权限链路

- 新增 model_deploy 与 model_operations 双库查询,支持模型列表、模型详情、单月监控结果和运维工作台真实接口。

- 关闭运维模块生产 Mock 数据,补充缺表/空数据降级、工作台空状态和首条纵向链路测试。

- 按业务团队、模型团队、管理员权限矩阵接入菜单、页面、操作按钮和后端接口权限校验,支持 business_team 角色。

- 更新工作台布局、深色欢迎卡片、全宽页面适配、顶部回退,以及权限分组展示。

- 新增架构实现基线、周目标完成情况和角色权限矩阵初始化 SQL 文档。
This commit is contained in:
郑龙捷
2026-09-02 15:02:47 +08:00
parent 6d044784ec
commit 74dd97428f
51 changed files with 2142 additions and 1062 deletions
+3 -1
View File
@@ -6,6 +6,7 @@ import { Card, CardContent } from "~/components/ui/card";
import { OperationsDataBoundary, OperationsDataProvider } from "~/features/operations/OperationsDataContext";
import {
isOperationsPageVisibleForRole,
useCanOperationsPage,
operationsPageFromPath,
useOperationsRole,
} from "~/features/operations/operationsRole";
@@ -15,8 +16,9 @@ export default function OperationsLayout() {
const location = useLocation();
const navigate = useNavigate();
const page = operationsPageFromPath(location.pathname);
const canViewByPermission = useCanOperationsPage(page);
if (!isOperationsPageVisibleForRole(role, page)) {
if (!isOperationsPageVisibleForRole(role, page) || !canViewByPermission) {
return (
<section className="grid h-full place-items-center bg-bg p-6">
<Card className="w-full max-w-xl">
+13 -13
View File
@@ -105,8 +105,8 @@ export const navigation: NavigationItem[] = [
page: "home",
children: [
{ label: "开发工作台", icon: Home, page: "home", activePath: "/workbench", targetPath: "/workbench" },
{ label: "运维工作台", icon: Gauge, page: "operations", activePath: "/operations", targetPath: "/operations", visibleToOperationsRoles: ["business", "model", "admin"] },
{ label: "平台使用统计", icon: ChartNoAxesColumn, page: "operations", activePath: "/operations/usage", targetPath: "/operations/usage", visibleToOperationsRoles: ["admin"] },
{ label: "运维工作台", icon: Gauge, page: "operations", activePath: "/operations", targetPath: "/operations", permission: "operations:workbench:view", visibleToOperationsRoles: ["business", "model", "admin"] },
{ label: "平台使用统计", icon: ChartNoAxesColumn, page: "operations", activePath: "/operations/usage", targetPath: "/operations/usage", permission: "operations:usage:view", visibleToOperationsRoles: ["admin"] },
],
},
{ label: "构建脚本", icon: Code, page: "scripts", permission: "script:view" },
@@ -116,9 +116,9 @@ export const navigation: NavigationItem[] = [
icon: Layers3,
page: "operations",
children: [
{ label: "模型大类概览", icon: Layers3, page: "operations", sub: "models", activePath: "/operations/models", visibleToOperationsRoles: ["business", "model", "admin"] },
{ label: "细分银行概览", icon: Building2, page: "operations", sub: "banks", activePath: "/operations/banks", visibleToOperationsRoles: ["business", "model", "admin"] },
{ label: "已上线模型详情", icon: ClipboardList, page: "operations", sub: "deployed-models", activePath: "/operations/deployed-models", visibleToOperationsRoles: ["model", "admin"] },
{ label: "模型大类概览", icon: Layers3, page: "operations", sub: "models", activePath: "/operations/models", permission: "operations:model-overview:view", visibleToOperationsRoles: ["business", "model", "admin"] },
{ label: "细分银行概览", icon: Building2, page: "operations", sub: "banks", activePath: "/operations/banks", permission: "operations:bank-overview:view", visibleToOperationsRoles: ["business", "model", "admin"] },
{ label: "已上线模型详情", icon: ClipboardList, page: "operations", sub: "deployed-models", activePath: "/operations/deployed-models", permission: "operations:deployed-models:view", visibleToOperationsRoles: ["model", "admin"] },
],
},
{
@@ -126,9 +126,9 @@ export const navigation: NavigationItem[] = [
icon: Activity,
page: "operations",
children: [
{ label: "监控明细", icon: ListFilter, page: "operations", sub: "monitoring", activePath: "/operations/monitoring", visibleToOperationsRoles: ["business", "model", "admin"] },
{ label: "监控诊断报告", icon: FileText, page: "operations", sub: "reports", activePath: "/operations/reports", visibleToOperationsRoles: ["business", "model", "admin"] },
{ label: "历史报告汇总", icon: Files, page: "operations", sub: "report-summary", activePath: "/operations/report-summary", visibleToOperationsRoles: ["business", "model", "admin"] },
{ label: "监控明细", icon: ListFilter, page: "operations", sub: "monitoring", activePath: "/operations/monitoring", permission: "operations:monitoring-overview:view", visibleToOperationsRoles: ["business", "model", "admin"] },
{ label: "监控诊断报告", icon: FileText, page: "operations", sub: "reports", activePath: "/operations/reports", permission: "operations:report:view", visibleToOperationsRoles: ["business", "model", "admin"] },
{ label: "历史报告汇总", icon: Files, page: "operations", sub: "report-summary", activePath: "/operations/report-summary", permission: "operations:report-summary:view", visibleToOperationsRoles: ["business", "model", "admin"] },
],
},
{
@@ -136,8 +136,8 @@ export const navigation: NavigationItem[] = [
icon: GitBranch,
page: "operations",
children: [
{ label: "全流程进度", icon: GitBranch, page: "operations", sub: "workflows", activePath: "/operations/workflows", visibleToOperationsRoles: ["business", "model", "admin"] },
{ label: "文档知识库", icon: BookOpen, page: "operations", sub: "knowledge", activePath: "/operations/knowledge", visibleToOperationsRoles: ["model", "admin"] },
{ label: "全流程进度", icon: GitBranch, page: "operations", sub: "workflows", activePath: "/operations/workflows", permission: "operations:workflow:view", visibleToOperationsRoles: ["business", "model", "admin"] },
{ label: "文档知识库", icon: BookOpen, page: "operations", sub: "knowledge", activePath: "/operations/knowledge", permission: "operations:knowledge:view", visibleToOperationsRoles: ["model", "admin"] },
],
},
{
@@ -148,9 +148,9 @@ export const navigation: NavigationItem[] = [
{ 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" },
{ label: "监控等级规则", icon: ShieldCheck, page: "operations", sub: "rules", activePath: "/operations/rules", visibleToOperationsRoles: ["model", "admin"] },
{ label: "报告 Prompt 管理", icon: MessageSquareText, page: "operations", sub: "prompts", activePath: "/operations/prompts", visibleToOperationsRoles: ["model", "admin"] },
{ label: "运维系统配置", icon: Wrench, page: "operations", sub: "settings", activePath: "/operations/settings", visibleToOperationsRoles: ["admin"] },
{ label: "监控等级规则", icon: ShieldCheck, page: "operations", sub: "rules", activePath: "/operations/rules", permission: "operations:rules:view", visibleToOperationsRoles: ["model", "admin"] },
{ label: "报告 Prompt 管理", icon: MessageSquareText, page: "operations", sub: "prompts", activePath: "/operations/prompts", permission: "operations:prompt:view", visibleToOperationsRoles: ["model", "admin"] },
{ label: "运维系统配置", icon: Wrench, page: "operations", sub: "settings", activePath: "/operations/settings", permission: "operations:settings:view", visibleToOperationsRoles: ["admin"] },
],
},
];
+21 -2
View File
@@ -83,7 +83,7 @@ function NavRow({
}) {
const itemIcon = <item.icon />;
const childActivePath = (child: NavigationItem) =>
child.activePath ?? pathForPage(child.page);
child.activePath ?? (child.sub ? `${pathForPage(child.page)}/${child.sub}` : pathForPage(child.page));
const childIsActive = (child: NavigationItem) => {
const activePath = childActivePath(child);
return pathname === activePath || Boolean(child.sub && pathname.startsWith(`${activePath}/`));
@@ -208,6 +208,7 @@ function AuthenticatedLayout() {
const setWorkspaceMenuOpen = useUiStore((s) => s.setWorkspaceMenuOpen);
const [sidebarCollapsed, setSidebarCollapsed] = useState(false);
const [operationsServiceOnline, setOperationsServiceOnline] = useState(false);
const bindingGeneration = useRef(0);
const can = usePermission;
@@ -245,6 +246,20 @@ function AuthenticatedLayout() {
// 心跳 / cleanup / 切页结束编辑 / 卸载前释放
useEditSessionLifecycle({ activePage });
useEffect(() => {
if (activePage !== "operations") return;
const controller = new AbortController();
void fetch("/api/v1/health", {
credentials: "same-origin",
signal: controller.signal,
})
.then((response) => setOperationsServiceOnline(response.ok))
.catch(() => {
if (!controller.signal.aborted) setOperationsServiceOnline(false);
});
return () => controller.abort();
}, [activePage]);
// 原 common/Sidebar 的编辑会话守卫上移到这里:切出 /scripts 时有活动编辑
// 会话先 endEditing,回工作台时清空选中脚本;再按当前激活页导航。
function guardedNavigate(targetPath: string) {
@@ -312,7 +327,7 @@ function AuthenticatedLayout() {
<SidebarInset className="h-screen min-w-0">
<Topbar
pageTitle={pageTitle}
apiOnline={apiOnline}
apiOnline={activePage === "operations" ? operationsServiceOnline : apiOnline}
user={user}
currentWorkspace={effectiveWorkspace}
workspaces={effectiveWorkspaces}
@@ -320,6 +335,10 @@ function AuthenticatedLayout() {
onSetWorkspaceMenuOpen={setWorkspaceMenuOpen}
onSetCurrentWorkspace={setCurrentWorkspace}
onLogout={logout}
onBack={() => {
if (window.history.length > 1) navigate(-1);
else navigate("/workbench");
}}
/>
<Outlet />