126 lines
3.0 KiB
TypeScript
126 lines
3.0 KiB
TypeScript
// IamClient Mock 实现(B8 裁决:上游就绪前的降级策略)
|
||
// DEV_MODE=true 时全部走 mock;DEV_MODE=false 时仅未就绪 RPC 走 mock
|
||
// mock 数据对齐 contract §4.2 mock 策略
|
||
import { Injectable } from "@nestjs/common";
|
||
import { BaseDownstreamClient } from "../base.client.js";
|
||
import type { CallContext } from "../types.js";
|
||
import type { IamClient } from "./iam-client.interface.js";
|
||
import type {
|
||
UserInfo,
|
||
ViewportItem,
|
||
EffectivePermissions,
|
||
} from "./iam.types.js";
|
||
|
||
/** 教师默认 mock 用户(contract §4.1 mock 策略) */
|
||
const MOCK_TEACHER: UserInfo = {
|
||
id: "teacher-001",
|
||
email: "teacher@edu.test",
|
||
name: "张老师",
|
||
roles: ["teacher"],
|
||
permissions: [
|
||
"exam:read",
|
||
"exam:write",
|
||
"homework:read",
|
||
"homework:write",
|
||
"grade:read",
|
||
"grade:write",
|
||
"class:read",
|
||
"student:read",
|
||
],
|
||
};
|
||
|
||
/** 教师默认 mock 视口(L1 导航) */
|
||
const MOCK_VIEWPORTS: ViewportItem[] = [
|
||
{
|
||
key: "dashboard",
|
||
label: "工作台",
|
||
route: "/dashboard",
|
||
icon: null,
|
||
sortOrder: 1,
|
||
requiredPermission: null,
|
||
},
|
||
{
|
||
key: "classes",
|
||
label: "我的班级",
|
||
route: "/classes",
|
||
icon: null,
|
||
sortOrder: 2,
|
||
requiredPermission: "class:read",
|
||
},
|
||
{
|
||
key: "exams",
|
||
label: "考试管理",
|
||
route: "/exams",
|
||
icon: null,
|
||
sortOrder: 3,
|
||
requiredPermission: "exam:read",
|
||
},
|
||
{
|
||
key: "homework",
|
||
label: "作业管理",
|
||
route: "/homework",
|
||
icon: null,
|
||
sortOrder: 4,
|
||
requiredPermission: "homework:read",
|
||
},
|
||
{
|
||
key: "grades",
|
||
label: "成绩管理",
|
||
route: "/grades",
|
||
icon: null,
|
||
sortOrder: 5,
|
||
requiredPermission: "grade:read",
|
||
},
|
||
{
|
||
key: "analytics",
|
||
label: "学情分析",
|
||
route: "/analytics",
|
||
icon: null,
|
||
sortOrder: 6,
|
||
requiredPermission: "student:read",
|
||
},
|
||
];
|
||
|
||
/** 教师默认 mock 权限(全权限 + OWN 数据范围) */
|
||
const MOCK_PERMISSIONS: EffectivePermissions = {
|
||
permissions: MOCK_TEACHER.permissions,
|
||
dataScope: "OWN",
|
||
};
|
||
|
||
@Injectable()
|
||
export class IamMockClient extends BaseDownstreamClient implements IamClient {
|
||
readonly serviceName = "iam" as const;
|
||
|
||
constructor() {
|
||
super();
|
||
this.initLogger();
|
||
}
|
||
|
||
async getUserInfo(ctx: CallContext): Promise<UserInfo> {
|
||
this.log.debug({ userId: ctx.userId }, "Mock getUserInfo");
|
||
// 返回 mock 教师,但 id 用请求中的 userId(保持一致性)
|
||
return { ...MOCK_TEACHER, id: ctx.userId };
|
||
}
|
||
|
||
async getViewports(ctx: CallContext): Promise<ViewportItem[]> {
|
||
this.log.debug({ userId: ctx.userId }, "Mock getViewports");
|
||
return MOCK_VIEWPORTS;
|
||
}
|
||
|
||
async getEffectivePermissions(
|
||
ctx: CallContext,
|
||
): Promise<EffectivePermissions> {
|
||
this.log.debug({ userId: ctx.userId }, "Mock getEffectivePermissions");
|
||
return MOCK_PERMISSIONS;
|
||
}
|
||
|
||
async checkHealth(): Promise<{
|
||
serving: boolean;
|
||
latencyMs: number;
|
||
error?: string;
|
||
}> {
|
||
// mock 模式下健康检查总是返回 serving=true
|
||
return { serving: true, latencyMs: 0 };
|
||
}
|
||
}
|