Files
Edu/services/teacher-bff/src/teacher/teacher.service.ts
SpecialX 0a71b02e04
Some checks failed
CI / quality-ts (push) Failing after 48s
CI / quality-go (push) Failing after 4s
CI / quality-proto (push) Failing after 2s
CI / deploy (push) Has been skipped
fix: code compliance audit and fix across all services
NestJS (6 services): implement @RequirePermission decorator with
SetMetadata+Reflector, register APP_GUARD globally, fix as assertions
to type guards, add explicit return types, fix import type for express,
fix /metrics implicit any, replace native Error with ApplicationError,
remove typeorm remnants, register LifecycleService.

teacher-bff: add logger, ApplicationError, GlobalErrorFilter, forward
real userId to downstream, log downstream failures, migrate health
controller to shared/health.

Go (2 services): interface to any, doc comments, CORS dev whitelist,
JWT secret fail-fast, push-gateway internal API auth, metrics and
readyz endpoints, remove dead code.

Python (2 services): lifespan return type, dev_mode to bool, data-ana
APIRouter, ai POST body model, ClickHouse async wrapping.
2026-07-09 17:28:27 +08:00

159 lines
4.6 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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<T> {
success: boolean;
data?: T;
}
interface DashboardData {
user: unknown;
classes: unknown;
}
@Injectable()
export class TeacherService {
// 聚合 IAM + classes 服务的数据
async getDashboard(userId: string): Promise<DashboardData> {
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<ViewportItem[]> {
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<ViewportItem[]>;
return json.data ?? [];
}
// 聚合班级下的考试列表core-edu
async listExamsByClass(userId: string, classId: string): Promise<unknown> {
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<unknown>;
return json.data ?? [];
}
// 聚合班级下的作业列表core-edu
async listHomeworkByClass(userId: string, classId: string): Promise<unknown> {
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<unknown>;
return json.data ?? [];
}
// 聚合考试下的成绩列表core-edu
async listGradesByExam(userId: string, examId: string): Promise<unknown> {
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<unknown>;
return json.data ?? [];
}
}