import { Injectable } from "@nestjs/common"; import { env } from "../config/env.js"; import { logger } from "../shared/observability/logger.js"; import { BadGatewayError } from "../shared/errors/application-error.js"; export interface ViewportItem { key: string; label: string; route: string; icon: string | null; sortOrder: string; requiredPermission: string | null; } interface DownstreamEnvelope { success: boolean; data?: T; } interface DashboardData { user: unknown; classes: unknown; } @Injectable() export class TeacherService { // 聚合 IAM + classes 服务的数据 async getDashboard(userId: string): Promise { const [iamRes, classesRes] = await Promise.allSettled([ fetch(`${env.IamServiceUrl}/iam/me`, { headers: { "x-user-id": userId }, }), fetch(`${env.ClassesServiceUrl}/classes`, { headers: { "x-user-id": userId }, }), ]); let user: unknown = null; let classes: unknown = null; if (iamRes.status === "fulfilled") { if (iamRes.value.ok) { user = await iamRes.value.json(); } else { logger.warn( { status: iamRes.value.status, url: iamRes.value.url }, "Downstream IAM service call failed", ); } } else { logger.warn( { err: iamRes.reason, service: "iam" }, "Downstream IAM service call rejected", ); } if (classesRes.status === "fulfilled") { if (classesRes.value.ok) { classes = await classesRes.value.json(); } else { logger.warn( { status: classesRes.value.status, url: classesRes.value.url }, "Downstream classes service call failed", ); } } else { logger.warn( { err: classesRes.reason, service: "classes" }, "Downstream classes service call rejected", ); } return { user, classes }; } // 聚合 IAM 视口配置(L1 导航) async getViewports(userId: string): Promise { const res = await fetch(`${env.IamServiceUrl}/iam/viewports`, { headers: { "x-user-id": userId }, }); if (!res.ok) { logger.warn( { status: res.status, url: res.url }, "Downstream IAM service call failed", ); throw new BadGatewayError(`Downstream service returned ${res.status}`, { service: "iam", endpoint: "viewports", status: res.status, }); } const json = (await res.json()) as DownstreamEnvelope; return json.data ?? []; } // 聚合班级下的考试列表(core-edu) async listExamsByClass(userId: string, classId: string): Promise { const res = await fetch( `${env.CoreEduServiceUrl}/exams/class/${encodeURIComponent(classId)}`, { headers: { "x-user-id": userId } }, ); if (!res.ok) { logger.warn( { status: res.status, url: res.url }, "Downstream core-edu service call failed", ); throw new BadGatewayError(`Downstream service returned ${res.status}`, { service: "core-edu", endpoint: "exams-by-class", status: res.status, }); } const json = (await res.json()) as DownstreamEnvelope; return json.data ?? []; } // 聚合班级下的作业列表(core-edu) async listHomeworkByClass(userId: string, classId: string): Promise { const res = await fetch( `${env.CoreEduServiceUrl}/homework/class/${encodeURIComponent(classId)}`, { headers: { "x-user-id": userId } }, ); if (!res.ok) { logger.warn( { status: res.status, url: res.url }, "Downstream core-edu service call failed", ); throw new BadGatewayError(`Downstream service returned ${res.status}`, { service: "core-edu", endpoint: "homework-by-class", status: res.status, }); } const json = (await res.json()) as DownstreamEnvelope; return json.data ?? []; } // 聚合考试下的成绩列表(core-edu) async listGradesByExam(userId: string, examId: string): Promise { const res = await fetch( `${env.CoreEduServiceUrl}/grades/exam/${encodeURIComponent(examId)}`, { headers: { "x-user-id": userId } }, ); if (!res.ok) { logger.warn( { status: res.status, url: res.url }, "Downstream core-edu service call failed", ); throw new BadGatewayError(`Downstream service returned ${res.status}`, { service: "core-edu", endpoint: "grades-by-exam", status: res.status, }); } const json = (await res.json()) as DownstreamEnvelope; return json.data ?? []; } }