feat: add system configuration platform
This commit is contained in:
@@ -1,15 +1,97 @@
|
||||
import type { Permission, RoleDefinition, RoleId } from "@/modules/core/types";
|
||||
import { ROLE_LABELS } from "@/modules/core/types";
|
||||
import { and, eq, inArray, isNull, or } from "drizzle-orm";
|
||||
|
||||
export const ROLE_DEFINITIONS: RoleDefinition[] = [
|
||||
import { getDatabase } from "@/modules/core/server/db";
|
||||
import { permissions, rolePermissions, roles } from "@/modules/core/server/schema";
|
||||
import type { Permission, RoleDefinition, RoleId } from "@/modules/core/types";
|
||||
import { PERMISSIONS, ROLE_LABELS } from "@/modules/core/types";
|
||||
|
||||
type PermissionDefinition = {
|
||||
id: Permission;
|
||||
label: string;
|
||||
category: string;
|
||||
description: string;
|
||||
};
|
||||
|
||||
export const PERMISSION_DEFINITIONS: PermissionDefinition[] = [
|
||||
{ id: "platform:manage", label: "平台管理", category: "平台", description: "管理平台级配置和跨机构操作。" },
|
||||
{ id: "organization:read", label: "查看机构", category: "机构", description: "查看机构、院区和租户信息。" },
|
||||
{ id: "organization:manage", label: "管理机构", category: "机构", description: "创建、编辑和停用机构。" },
|
||||
{ id: "account:read", label: "查看用户", category: "用户", description: "查看账号、成员和申请。" },
|
||||
{ id: "account:manage", label: "管理用户", category: "用户", description: "创建、审批、启停和分配用户。" },
|
||||
{ id: "role:read", label: "查看角色", category: "权限", description: "查看角色和权限矩阵。" },
|
||||
{ id: "role:manage", label: "管理角色", category: "权限", description: "创建自定义角色并配置权限组合。" },
|
||||
{ id: "permission:read", label: "查看权限", category: "权限", description: "查看系统注册权限点。" },
|
||||
{ id: "audit:read", label: "查看审计", category: "审计", description: "查看关键操作审计日志。" },
|
||||
{ id: "incident:read", label: "查看故障", category: "运维", description: "查看系统健康和故障中心。" },
|
||||
{ id: "incident:manage", label: "处理故障", category: "运维", description: "确认、处理和关闭故障事件。" },
|
||||
{ id: "facility:read", label: "查看房间床位", category: "床位", description: "查看房间、床位和占用状态。" },
|
||||
{ id: "facility:manage", label: "管理房间床位", category: "床位", description: "维护院区、房间、床位和床位状态。" },
|
||||
{ id: "admission:read", label: "查看入住", category: "入住", description: "查看入住、换床、退住历史。" },
|
||||
{ id: "admission:manage", label: "管理入住", category: "入住", description: "办理入住、换床和退住。" },
|
||||
{ id: "elder:read", label: "查看老人档案", category: "老人", description: "查看老人基础档案。" },
|
||||
{ id: "elder:create", label: "新增老人档案", category: "老人", description: "创建老人档案。" },
|
||||
{ id: "elder:update", label: "更新老人档案", category: "老人", description: "更新老人档案和照护信息。" },
|
||||
{ id: "elder:delete", label: "删除老人档案", category: "老人", description: "删除老人档案。" },
|
||||
];
|
||||
|
||||
type SeedRole = {
|
||||
key: RoleId;
|
||||
scope: "platform" | "organization";
|
||||
description: string;
|
||||
permissions: Permission[];
|
||||
};
|
||||
|
||||
export const SYSTEM_ROLE_DEFINITIONS: SeedRole[] = [
|
||||
{
|
||||
id: "admin",
|
||||
label: ROLE_LABELS.admin,
|
||||
description: "管理账号、权限、审计日志与全部业务数据。",
|
||||
key: "platform_admin",
|
||||
scope: "platform",
|
||||
description: "平台最高权限,管理所有机构、角色、审计和故障中心。",
|
||||
permissions: [...PERMISSIONS],
|
||||
},
|
||||
{
|
||||
key: "platform_operator",
|
||||
scope: "platform",
|
||||
description: "平台运营角色,管理机构和跨机构用户配置。",
|
||||
permissions: [
|
||||
"organization:read",
|
||||
"organization:manage",
|
||||
"account:read",
|
||||
"account:manage",
|
||||
"role:read",
|
||||
"permission:read",
|
||||
"audit:read",
|
||||
"incident:read",
|
||||
],
|
||||
},
|
||||
{
|
||||
key: "platform_auditor",
|
||||
scope: "platform",
|
||||
description: "平台审计角色,只读查看机构、审计和故障。",
|
||||
permissions: ["organization:read", "account:read", "role:read", "permission:read", "audit:read", "incident:read"],
|
||||
},
|
||||
{
|
||||
key: "platform_ops",
|
||||
scope: "platform",
|
||||
description: "平台运维角色,处理系统故障和运行状态。",
|
||||
permissions: ["organization:read", "audit:read", "incident:read", "incident:manage"],
|
||||
},
|
||||
{
|
||||
key: "org_admin",
|
||||
scope: "organization",
|
||||
description: "机构管理员,管理本机构用户、角色、房间床位、入住和审计。",
|
||||
permissions: [
|
||||
"organization:read",
|
||||
"account:read",
|
||||
"account:manage",
|
||||
"role:read",
|
||||
"role:manage",
|
||||
"permission:read",
|
||||
"audit:read",
|
||||
"incident:read",
|
||||
"facility:read",
|
||||
"facility:manage",
|
||||
"admission:read",
|
||||
"admission:manage",
|
||||
"elder:read",
|
||||
"elder:create",
|
||||
"elder:update",
|
||||
@@ -17,43 +99,160 @@ export const ROLE_DEFINITIONS: RoleDefinition[] = [
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "manager",
|
||||
label: ROLE_LABELS.manager,
|
||||
description: "处理运营业务,可查看账号与审计日志,不管理账号角色。",
|
||||
permissions: ["account:read", "audit:read", "elder:read", "elder:create", "elder:update", "elder:delete"],
|
||||
key: "manager",
|
||||
scope: "organization",
|
||||
description: "运营主管,处理老人档案、床位入住和审计查看。",
|
||||
permissions: [
|
||||
"account:read",
|
||||
"role:read",
|
||||
"audit:read",
|
||||
"facility:read",
|
||||
"facility:manage",
|
||||
"admission:read",
|
||||
"admission:manage",
|
||||
"elder:read",
|
||||
"elder:create",
|
||||
"elder:update",
|
||||
"elder:delete",
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "caregiver",
|
||||
label: ROLE_LABELS.caregiver,
|
||||
description: "查看老人档案并维护照护相关信息。",
|
||||
permissions: ["elder:read", "elder:update"],
|
||||
key: "caregiver",
|
||||
scope: "organization",
|
||||
description: "照护人员,查看床位和维护老人照护信息。",
|
||||
permissions: ["facility:read", "admission:read", "elder:read", "elder:update"],
|
||||
},
|
||||
{
|
||||
id: "viewer",
|
||||
label: ROLE_LABELS.viewer,
|
||||
description: "只读查看老人档案。",
|
||||
permissions: ["elder:read"],
|
||||
key: "viewer",
|
||||
scope: "organization",
|
||||
description: "只读访客,查看老人、床位和入住信息。",
|
||||
permissions: ["facility:read", "admission:read", "elder:read"],
|
||||
},
|
||||
];
|
||||
|
||||
export function getRoleDefinition(role: RoleId): RoleDefinition {
|
||||
const roleDefinition = ROLE_DEFINITIONS.find((item) => item.id === role);
|
||||
if (roleDefinition) {
|
||||
return roleDefinition;
|
||||
export async function ensureSystemDefaults(): Promise<void> {
|
||||
const database = getDatabase();
|
||||
|
||||
await database
|
||||
.insert(permissions)
|
||||
.values(PERMISSION_DEFINITIONS)
|
||||
.onConflictDoUpdate({
|
||||
target: permissions.id,
|
||||
set: {
|
||||
label: permissions.label,
|
||||
category: permissions.category,
|
||||
description: permissions.description,
|
||||
isEnabled: true,
|
||||
},
|
||||
});
|
||||
|
||||
const existingRoles = await database.select().from(roles).where(isNull(roles.organizationId));
|
||||
const existingRoleKeys = new Set(existingRoles.map((role) => role.key));
|
||||
const seedRoles = SYSTEM_ROLE_DEFINITIONS.filter((role) => role.scope === "platform" && !existingRoleKeys.has(role.key));
|
||||
|
||||
if (seedRoles.length > 0) {
|
||||
await database.insert(roles).values(
|
||||
seedRoles.map((role) => ({
|
||||
key: role.key,
|
||||
scope: role.scope,
|
||||
label: ROLE_LABELS[role.key],
|
||||
description: role.description,
|
||||
isSystem: true,
|
||||
isEnabled: true,
|
||||
})),
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
id: "viewer",
|
||||
label: ROLE_LABELS.viewer,
|
||||
description: "只读查看老人档案。",
|
||||
permissions: ["elder:read"],
|
||||
};
|
||||
const platformRoles = await database.select().from(roles).where(isNull(roles.organizationId));
|
||||
const inserts = platformRoles.flatMap((role) => {
|
||||
const definition = SYSTEM_ROLE_DEFINITIONS.find((item) => item.key === role.key);
|
||||
if (!definition) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return definition.permissions.map((permissionId) => ({
|
||||
roleId: role.id,
|
||||
permissionId,
|
||||
}));
|
||||
});
|
||||
|
||||
if (inserts.length > 0) {
|
||||
await database.insert(rolePermissions).values(inserts).onConflictDoNothing();
|
||||
}
|
||||
}
|
||||
|
||||
export function getPermissionsForRole(role: RoleId): Permission[] {
|
||||
return [...getRoleDefinition(role).permissions];
|
||||
export async function seedOrganizationRoles(organizationId: string): Promise<void> {
|
||||
const database = getDatabase();
|
||||
const organizationRoles = SYSTEM_ROLE_DEFINITIONS.filter((role) => role.scope === "organization");
|
||||
|
||||
await database
|
||||
.insert(roles)
|
||||
.values(
|
||||
organizationRoles.map((role) => ({
|
||||
key: role.key,
|
||||
organizationId,
|
||||
scope: role.scope,
|
||||
label: ROLE_LABELS[role.key],
|
||||
description: role.description,
|
||||
isSystem: true,
|
||||
isEnabled: true,
|
||||
})),
|
||||
)
|
||||
.onConflictDoNothing();
|
||||
|
||||
const seededRoles = await database
|
||||
.select()
|
||||
.from(roles)
|
||||
.where(and(eq(roles.organizationId, organizationId), inArray(roles.key, organizationRoles.map((role) => role.key))));
|
||||
|
||||
const inserts = seededRoles.flatMap((role) => {
|
||||
const definition = SYSTEM_ROLE_DEFINITIONS.find((item) => item.key === role.key);
|
||||
if (!definition) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return definition.permissions.map((permissionId) => ({ roleId: role.id, permissionId }));
|
||||
});
|
||||
|
||||
if (inserts.length > 0) {
|
||||
await database.insert(rolePermissions).values(inserts).onConflictDoNothing();
|
||||
}
|
||||
}
|
||||
|
||||
export function hasPermission(role: RoleId, permission: Permission): boolean {
|
||||
return getRoleDefinition(role).permissions.includes(permission);
|
||||
export async function getRoleDefinitions(organizationId?: string): Promise<RoleDefinition[]> {
|
||||
const database = getDatabase();
|
||||
const rows = await database
|
||||
.select()
|
||||
.from(roles)
|
||||
.where(organizationId ? or(isNull(roles.organizationId), eq(roles.organizationId, organizationId)) : isNull(roles.organizationId));
|
||||
|
||||
const roleIds = rows.map((role) => role.id);
|
||||
const permissionRows =
|
||||
roleIds.length > 0
|
||||
? await database.select().from(rolePermissions).where(inArray(rolePermissions.roleId, roleIds))
|
||||
: [];
|
||||
|
||||
return rows.map((role) => ({
|
||||
id: role.id,
|
||||
key: role.key,
|
||||
label: role.label,
|
||||
description: role.description,
|
||||
scope: role.scope,
|
||||
organizationId: role.organizationId ?? undefined,
|
||||
isSystem: role.isSystem,
|
||||
isEnabled: role.isEnabled,
|
||||
permissions: permissionRows
|
||||
.filter((permission) => permission.roleId === role.id)
|
||||
.map((permission) => permission.permissionId as Permission),
|
||||
}));
|
||||
}
|
||||
|
||||
export async function getPermissionsForRole(roleId: string): Promise<Permission[]> {
|
||||
const database = getDatabase();
|
||||
const rows = await database.select().from(rolePermissions).where(eq(rolePermissions.roleId, roleId));
|
||||
return rows.map((row) => row.permissionId as Permission);
|
||||
}
|
||||
|
||||
export function hasPermission(permissionsList: readonly Permission[], permission: Permission): boolean {
|
||||
return permissionsList.includes(permission);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user