import { Activity, Building2, Server, ShieldCheck, Users } from "lucide-react"; import { Badge } from "@/components/ui/badge"; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; import type { AuditLog, Membership, Organization, PublicAccount, RoleDefinition, SystemIncident } from "@/modules/core/types"; import { ROLE_LABELS } from "@/modules/core/types"; import type { RoleId } from "@/modules/core/types"; type SettingsOverviewProps = { accounts: PublicAccount[]; roles: RoleDefinition[]; auditLogs: AuditLog[]; organizations: Organization[]; memberships: Membership[]; incidents: SystemIncident[]; }; function formatRoleLabel(role: string): string { if (role in ROLE_LABELS) { return ROLE_LABELS[role as RoleId]; } return role; } export function SettingsOverview({ accounts, roles, auditLogs, organizations, memberships, incidents, }: SettingsOverviewProps): React.ReactElement { const activeAccountCount = accounts.filter((account) => account.status === "active").length; const disabledAccountCount = accounts.length - activeAccountCount; const activeOrganizationCount = organizations.filter((organization) => organization.status === "active").length; const openIncidentCount = incidents.filter((incident) => incident.status === "open").length; const deniedAuditCount = auditLogs.filter((log) => log.result === "denied").length; const failureAuditCount = auditLogs.filter((log) => log.result === "failure").length; const successAuditCount = auditLogs.filter((log) => log.result === "success").length; const totalPermissionCount = roles.reduce((sum, role) => sum + role.permissions.length, 0); const actionCounts = auditLogs.reduce>((counts, log) => { counts[log.action] = (counts[log.action] ?? 0) + 1; return counts; }, {}); const topActions = Object.entries(actionCounts) .sort((left, right) => right[1] - left[1]) .slice(0, 4); return (
System configuration

系统设置

机构、用户、角色、权限、审计和故障中心。

机构租户 {organizations.length}

启用 {activeOrganizationCount} 个,多租户数据隔离

系统账号 {accounts.length}

启用 {activeAccountCount} 个,停用 {disabledAccountCount} 个

角色数量 {roles.length}

累计覆盖 {totalPermissionCount} 项权限

0 ? "border-red-200 bg-red-50/70" : undefined}>
0 ? "text-red-700" : undefined}>故障事件 0 ? "mt-2 text-3xl text-red-700" : "mt-2 text-3xl"}> {openIncidentCount}
0 ? "size-5 text-red-600" : "size-5 text-primary"} aria-hidden="true" />

0 ? "text-sm text-red-700" : "text-sm text-muted-foreground"}> 总计 {incidents.length} 条,开放 {openIncidentCount} 条

审计日志 {auditLogs.length}

成功 {successAuditCount} 条,最近 100 条

风险标记
红色:拒绝/失败审计 {deniedAuditCount + failureAuditCount}
开放故障 {openIncidentCount}
黄色:停用账号 {disabledAccountCount}
绿色:成功审计 {successAuditCount}
高频动作 {topActions.map(([action, count]) => (
{action} {count} 次
))} {topActions.length === 0 ?

暂无审计动作统计

: null}
机构租户
{organizations.map((organization) => ( ))} {organizations.length === 0 ? ( ) : null}
机构 Slug 状态 创建时间
{organization.name} {organization.slug} {organization.status === "active" ? "启用" : "停用"} {new Date(organization.createdAt).toLocaleString("zh-CN")}
暂无机构
故障中心 {incidents.slice(0, 6).map((incident) => (

{incident.title}

{incident.status}

{incident.description}

{incident.source} / {new Date(incident.createdAt).toLocaleString("zh-CN")}

))} {incidents.length === 0 ?

暂无故障事件

: null}
角色与权限 {roles.map((role) => (

{role.label}

{role.permissions.length} 权限

{role.description}

{role.permissions.map((permission) => ( {permission} ))}
))}
账号列表
{accounts.map((account) => ( ))}
账号 角色 状态 创建时间

{account.name}

{account.email}

{formatRoleLabel(account.role)} {account.status === "active" ? "启用" : account.status === "pending" ? "待审批" : "停用"} {new Date(account.createdAt).toLocaleString("zh-CN")}
机构成员关系
{memberships.map((membership) => ( ))} {memberships.length === 0 ? ( ) : null}
账号 ID 机构 ID 角色 状态 创建时间
{membership.accountId.slice(0, 8)} {membership.organizationId.slice(0, 8)} {membership.roleLabel} {membership.status} {new Date(membership.createdAt).toLocaleString("zh-CN")}
暂无成员关系
审计日志
{auditLogs.map((log) => ( ))} {auditLogs.length === 0 ? ( ) : null}
时间 操作者 动作 对象 结果 原因
{new Date(log.timestamp).toLocaleString("zh-CN")} {log.actorEmail ?? "系统"} {log.action} {log.targetType} {log.targetId ? ` / ${log.targetId.slice(0, 8)}` : ""} {log.result} {log.reason}
暂无审计日志
); }