feat(identity): 完成 A2 角色权限与数据范围全栈落地

背景:A2 开卡前完成 H1 权限门,确认权限点目录、特殊权限、SoD 三对、六类数据范围与超管隐式全集口径(ADR-001)。

改动:
- shared:30 权限点 / 10 模块目录与元数据、特殊权限 6 编码、SoD 三对、角色与权限树契约;/me 改 dataScopes 多角色并集。
- prisma:expand 迁移新增 permissions / data_scopes;种子按原型口径重写角色权限、数据范围与 8 项特殊授予。
- api:角色 CRUD / 复制 / 停用 / 删除、权限点启动同步、SoD 40304、系统角色保护、六类范围 ScopeContext 与 CustomerDirectory 端口、变更审计与 outbox。
- web:方案 B 主从分栏三角色页面(列表 / 编辑器 / 新建),权限树、范围选择、特殊权限二次确认、保存影响、SoD 冲突、只读态与模板预填。
- 测试:角色集成 13 条 + A2 e2e 1 条;A1 全量回归。

验证:format:check / lint / typecheck / test(306)/ test:int(27)/ A2 e2e(1,复跑通过)/ openapi:export 全绿。
This commit is contained in:
Stev_Wang committed 2026-11-03 12:26:51 +08:00
1 parent f97f97b0cd
commit 61894df401
80 files changed
+14380 -237

No files matched your search

+39
View File
@@ -24,6 +24,21 @@ const UserNewPage = lazy(async () => {
return { default: module.UserNewPage };
});
const RolesPage = lazy(async () => {
const module = await import('@/pages/system/roles/RolesPage');
return { default: module.RolesPage };
});
const RoleEditorPage = lazy(async () => {
const module = await import('@/pages/system/roles/RoleEditorPage');
return { default: module.RoleEditorPage };
});
const RoleNewPage = lazy(async () => {
const module = await import('@/pages/system/roles/RoleNewPage');
return { default: module.RoleNewPage };
});
function withSkeleton(node: ReactNode): ReactNode {
return <Suspense fallback={<PageSkeleton rows={8} />}>{node}</Suspense>;
}
@@ -82,6 +97,30 @@ export const router = createBrowserRouter([
</RequirePermission>
),
},
{
path: 'system/roles',
element: (
<RequirePermission permission={Permission.ROLE_VIEW}>
{withSkeleton(<RolesPage />)}
</RequirePermission>
),
},
{
path: 'system/roles/new',
element: (
<RequirePermission permission={Permission.ROLE_MANAGE}>
{withSkeleton(<RoleNewPage />)}
</RequirePermission>
),
},
{
path: 'system/roles/:id',
element: (
<RequirePermission permission={Permission.ROLE_VIEW}>
{withSkeleton(<RoleEditorPage />)}
</RequirePermission>
),
},
{
path: ':moduleKey/:itemKey?',
lazy: async () => ({