feat(portal-shell): v2.0 P0 shadcn standardization + security + streaming + error handling
- shadcn/ui 标准化:废弃纸感令牌,统一 bg-background/text-foreground 等 - Tailwind v4 + @theme inline,移除 tailwind.config.js - React 19 use() + Suspense 流式渲染,首屏骨架秒出 - 三级错误边界:Route → Section → Widget 层层兜底 - 错误上报:useErrorReport → sendBeacon → /api/log mock 端点 - 三层安全边界:L1 角色门禁 / L2 权限点门禁 / L3 数据范围 - 权限位图 base36 压缩:67 权限点 → ~14 字符,JWT 体积减少 ≥ 99% - notify 统一 Toast 封装,禁止业务直接 import sonner - PluginBoundary 替代 PluginLoader(错误边界 + Suspense + Skeleton 三件套) 验证:typecheck 0 错误 / lint 0 错误 / build 6 路由生成成功
This commit is contained in:
135
packages/shared-ts/src/contracts/layout.ts
Normal file
135
packages/shared-ts/src/contracts/layout.ts
Normal file
@@ -0,0 +1,135 @@
|
||||
/**
|
||||
* Layout 与 Slot 配置类型(portal-shell spec §4、§6.2)
|
||||
*
|
||||
* 对应 config-service PluginConfigResponse(三层合并后的插件配置)。
|
||||
* 类型与 services/config-service 的 GraphQL schema 对齐,
|
||||
* 通过 apollo-router GraphQL 查询 pluginConfig(userId, role) 获取。
|
||||
*
|
||||
* 关联:portal-shell spec §4.1 5 种 Layout 模板、§4.2 Slot 系统、§6.2 PluginConfigResponse
|
||||
*/
|
||||
import type { Role } from "./plugin.js";
|
||||
|
||||
/** Layout 模板信息(对应 config-service LayoutTemplateInfo) */
|
||||
export interface LayoutTemplateInfo {
|
||||
/** Layout ID:'classic' | 'focus' | 'split' | 'triple' | 'canvas' */
|
||||
layoutId: string;
|
||||
/** 显示名 */
|
||||
displayName: string;
|
||||
/** 描述 */
|
||||
description: string;
|
||||
/** 可用 slot 列表,如 ["top", "side", "main"] */
|
||||
availableSlots: string[];
|
||||
/** Layout schema JSON 字符串(grid 配置等) */
|
||||
layoutSchemaJson: string;
|
||||
}
|
||||
|
||||
/** Slot 配置(对应 config-service SlotConfig) */
|
||||
export interface SlotConfig {
|
||||
/** Slot 名称:'top' | 'side' | 'main' | 'main-left' | 'main-right' | 'right' | 'canvas-grid' */
|
||||
slotName: string;
|
||||
/** 导航项列表(side slot 的导航菜单项) */
|
||||
navItems: string[];
|
||||
}
|
||||
|
||||
/** 插件放置(三层合并后,对应 config-service PluginPlacement) */
|
||||
export interface PluginPlacement {
|
||||
/** 插件 ID */
|
||||
pluginId: string;
|
||||
/** 插入的 slot 名称 */
|
||||
slot: string;
|
||||
/** 显示顺序(升序) */
|
||||
sortOrder: number;
|
||||
/** 尺寸 JSON 字符串({colSpan, rowSpan}) */
|
||||
sizeJson: string;
|
||||
/** 三层合并后的最终 props JSON 字符串 */
|
||||
propsJson: string;
|
||||
/** 是否可见 */
|
||||
isVisible: boolean;
|
||||
}
|
||||
|
||||
/** 插件注册项(对应 config-service PluginRegistryItem) */
|
||||
export interface PluginRegistryItem {
|
||||
/** 插件 ID */
|
||||
pluginId: string;
|
||||
/** 分类:'universal' | 'sidebar' | 'topbar' | 'teacher' | 'student' | 'parent' | 'admin' */
|
||||
category: string;
|
||||
/** 版本(semver) */
|
||||
version: string;
|
||||
/** 显示名 */
|
||||
displayName: string;
|
||||
/** 描述 */
|
||||
description: string;
|
||||
/** 可访问此插件的角色列表 */
|
||||
requiredRoles: string[];
|
||||
/** 是否内置插件 */
|
||||
isBuiltin: boolean;
|
||||
/** 是否全局启用 */
|
||||
isActive: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* 三层合并后的插件配置响应(对应 config-service PluginConfigResponse)
|
||||
*
|
||||
* 由 config-service 合并三层配置后返回:
|
||||
* Layer 1: plugin_registry(系统默认)
|
||||
* Layer 2: role_plugin_mapping(角色模板)
|
||||
* Layer 3: user_layout_override(用户覆盖)
|
||||
*/
|
||||
export interface PluginConfigResponse {
|
||||
/** 当前启用的 Layout 模板 */
|
||||
activeLayout: LayoutTemplateInfo | null;
|
||||
/** Slot 配置列表 */
|
||||
slots: SlotConfig[];
|
||||
/** 插件放置列表(三层合并后) */
|
||||
plugins: PluginPlacement[];
|
||||
/** 插件注册表(所有可用插件) */
|
||||
registry: PluginRegistryItem[];
|
||||
}
|
||||
|
||||
/** Layout 模板 ID 枚举(portal-shell spec §4.1) */
|
||||
export const LAYOUT_TEMPLATE_IDS = [
|
||||
"classic",
|
||||
"focus",
|
||||
"split",
|
||||
"triple",
|
||||
"canvas",
|
||||
] as const;
|
||||
|
||||
/** Layout 模板 ID 类型 */
|
||||
export type LayoutTemplateId = (typeof LAYOUT_TEMPLATE_IDS)[number];
|
||||
|
||||
/** Slot 名称枚举(portal-shell spec §4.2) */
|
||||
export const SLOT_NAMES = [
|
||||
"top",
|
||||
"side",
|
||||
"main",
|
||||
"main-left",
|
||||
"main-right",
|
||||
"right",
|
||||
"canvas-grid",
|
||||
] as const;
|
||||
|
||||
/** Slot 名称类型 */
|
||||
export type SlotName = (typeof SLOT_NAMES)[number];
|
||||
|
||||
/** 角色-Layout 默认配置(admin 配置角色默认模板) */
|
||||
export interface RoleLayoutDefault {
|
||||
role: Role;
|
||||
layoutId: string;
|
||||
slotOverrides: Record<string, unknown>;
|
||||
}
|
||||
|
||||
/** 用户布局覆盖(用户自定义) */
|
||||
export interface UserLayoutOverride {
|
||||
userId: string;
|
||||
activeLayout: string;
|
||||
slotOverrides: Record<string, unknown>;
|
||||
pluginPlacements: Array<{
|
||||
pluginId: string;
|
||||
slot: string;
|
||||
sortOrder: number;
|
||||
size: { colSpan: number; rowSpan: number };
|
||||
props: Record<string, unknown>;
|
||||
}>;
|
||||
hiddenPlugins: string[];
|
||||
}
|
||||
Reference in New Issue
Block a user