feat(frontend): enforce RBAC and refine burst analysis

This commit is contained in:
2026-07-30 16:45:10 +08:00
parent f355ddd002
commit 723931b6ae
15 changed files with 772 additions and 390 deletions
+56 -48
View File
@@ -106,24 +106,30 @@ type DatabaseHealth = {
const businessRoleOptions = [
{ value: "admin", label: "系统管理员" },
{ value: "operator", label: "运行人员" },
{ value: "user", label: "普通用户" },
{ value: "viewer", label: "只读用户" },
];
const projectRoleLabels: Record<string, string> = {
owner: "项目负责人",
admin: "项目管理员",
member: "项目成员",
viewer: "只读成员",
};
const projectRoleOptions = [
{ value: "admin", label: projectRoleLabels.admin },
{ value: "member", label: projectRoleLabels.member },
{ value: "viewer", label: projectRoleLabels.viewer },
];
const projectRolePermissionSummary = [
{
role: "项目成员",
permissions: "WebGIS 编辑、SCADA 清洗、水力模拟、爆管、风险和监测点优化分析",
},
{
role: "只读成员",
permissions: "默认工作台、WebGIS、SCADA 和既有模拟结果只读",
},
];
const projectStatusOptions = [
{ value: "active", label: "启用" },
{ value: "inactive", label: "停用" },
@@ -1340,7 +1346,7 @@ export const SystemAdminPanel = () => {
<Stack spacing={2}>
<SectionHeader
title="项目成员"
description="维护当前项目内权限;此处只管理项目管理员、项目成员和只读成员,项目负责人另行维护。"
description="项目访问角色保存在 Metadata DB 的 user_project_membership.project_role。模型上传由桌面端发起,仅系统管理员可执行。"
action={
<Button
variant="outlined"
@@ -1352,6 +1358,25 @@ export const SystemAdminPanel = () => {
</Button>
}
/>
<Paper variant="outlined" sx={{ p: 2, borderRadius: 2 }}>
<Typography variant="subtitle2" fontWeight={800} sx={{ mb: 1 }}>
固定项目权限
</Typography>
<Stack
direction={{ xs: "column", md: "row" }}
spacing={1}
useFlexGap
flexWrap="wrap"
>
{projectRolePermissionSummary.map((item) => (
<Chip
key={item.role}
label={`${item.role}:${item.permissions}`}
variant="outlined"
/>
))}
</Stack>
</Paper>
{!hasProjectId && (
<Alert severity="warning" sx={{ borderRadius: 2 }}>
当前未选择管理项目。
@@ -1467,7 +1492,6 @@ export const SystemAdminPanel = () => {
)}
{members.map((member) => {
const isSelf = member.user_id === currentAdmin?.id;
const isOwner = member.project_role === "owner";
return (
<TableRow key={member.id} hover>
@@ -1486,54 +1510,38 @@ export const SystemAdminPanel = () => {
</TableCell>
<TableCell>{member.email}</TableCell>
<TableCell>
{isOwner ? (
<Tooltip title="项目负责人不在系统管理页维护">
<Chip
<Tooltip title={isSelf ? "不能操作当前登录用户" : ""}>
<span>
<FormControl
size="small"
color="warning"
label={getProjectRoleLabel(member.project_role)}
/>
</Tooltip>
) : (
<Tooltip title={isSelf ? "不能操作当前登录用户" : ""}>
<span>
<FormControl
size="small"
sx={{ minWidth: 140 }}
disabled={isSelf}
sx={{ minWidth: 140 }}
disabled={isSelf}
>
<Select
value={member.project_role}
onChange={(e) =>
updateMemberRole(member, e.target.value)
}
renderValue={(value) =>
getProjectRoleLabel(String(value))
}
>
<Select
value={member.project_role}
onChange={(e) =>
updateMemberRole(member, e.target.value)
}
renderValue={(value) =>
getProjectRoleLabel(String(value))
}
>
{projectRoleOptions.map((role) => (
<MenuItem key={role.value} value={role.value}>
{role.label}
</MenuItem>
))}
</Select>
</FormControl>
</span>
</Tooltip>
)}
{projectRoleOptions.map((role) => (
<MenuItem key={role.value} value={role.value}>
{role.label}
</MenuItem>
))}
</Select>
</FormControl>
</span>
</Tooltip>
</TableCell>
<TableCell>
<StatusChip active={member.is_active} />
</TableCell>
<TableCell align="right">
<Tooltip
title={
isSelf
? "不能操作当前登录用户"
: isOwner
? "项目负责人不在系统管理页维护"
: ""
}
title={isSelf ? "不能操作当前登录用户" : ""}
>
<span>
<Button
@@ -1542,7 +1550,7 @@ export const SystemAdminPanel = () => {
variant="outlined"
startIcon={<RemoveCircleOutlineIcon />}
onClick={() => removeMember(member)}
disabled={isSelf || isOwner}
disabled={isSelf}
>
移除
</Button>