diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a03aab0..535ebda 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -488,10 +488,16 @@ importers: rxjs: specifier: ^7.8.0 version: 7.8.2 + zod: + specifier: ^3.23.0 + version: 3.25.76 devDependencies: '@nestjs/cli': specifier: ^10.4.0 version: 10.4.9 + '@types/express': + specifier: ^4.17.0 + version: 4.17.25 '@types/node': specifier: ^22.0.0 version: 22.20.0 diff --git a/services/teacher-bff/package.json b/services/teacher-bff/package.json index a639a36..cdd2eea 100644 --- a/services/teacher-bff/package.json +++ b/services/teacher-bff/package.json @@ -19,10 +19,12 @@ "prom-client": "^15.1.0", "@opentelemetry/api": "^1.9.0", "reflect-metadata": "^0.2.2", - "rxjs": "^7.8.0" + "rxjs": "^7.8.0", + "zod": "^3.23.0" }, "devDependencies": { "@nestjs/cli": "^10.4.0", + "@types/express": "^4.17.0", "@types/node": "^22.0.0", "eslint": "^9.10.0", "typescript": "^5.6.0", diff --git a/services/teacher-bff/src/teacher/teacher.controller.ts b/services/teacher-bff/src/teacher/teacher.controller.ts index b69a061..259c654 100644 --- a/services/teacher-bff/src/teacher/teacher.controller.ts +++ b/services/teacher-bff/src/teacher/teacher.controller.ts @@ -1,19 +1,28 @@ -import { Controller, Get, Req } from '@nestjs/common'; -import type { Request } from 'express'; -import { TeacherService } from './teacher.service.js'; +import { Controller, Get, Req, UnauthorizedException } from "@nestjs/common"; +import type { Request } from "express"; +import { TeacherService } from "./teacher.service.js"; -interface AuthenticatedRequest extends Request { - userId?: string; -} - -@Controller('teacher') +@Controller("teacher") export class TeacherController { constructor(private readonly service: TeacherService) {} - @Get('dashboard') + @Get("dashboard") async dashboard(@Req() req: Request) { - const authReq = req as AuthenticatedRequest; - const data = await this.service.getDashboard(authReq.userId as string); - return { success: true, data }; + const userId = req.headers["x-user-id"] as string; + if (!userId) { + throw new UnauthorizedException("Missing x-user-id header"); + } + const data = await this.service.getDashboard(userId); + return { success: true as const, data }; + } + + @Get("viewports") + async viewports(@Req() req: Request) { + const userId = req.headers["x-user-id"] as string; + if (!userId) { + throw new UnauthorizedException("Missing x-user-id header"); + } + const data = await this.service.getViewports(userId); + return { success: true as const, data }; } } diff --git a/services/teacher-bff/src/teacher/teacher.service.ts b/services/teacher-bff/src/teacher/teacher.service.ts index c0d80fa..9b324e3 100644 --- a/services/teacher-bff/src/teacher/teacher.service.ts +++ b/services/teacher-bff/src/teacher/teacher.service.ts @@ -1,22 +1,52 @@ -import { Injectable } from '@nestjs/common'; -import { env } from '../config/env.js'; +import { Injectable } from "@nestjs/common"; +import { env } from "../config/env.js"; + +export interface ViewportItem { + key: string; + label: string; + route: string; + icon: string | null; + sortOrder: string; + requiredPermission: string | null; +} @Injectable() export class TeacherService { // 聚合 IAM + classes 服务的数据 - async getDashboard(userId: string): Promise { + async getDashboard(userId: string): Promise<{ + user: unknown; + classes: unknown; + }> { const [iamRes, classesRes] = await Promise.allSettled([ fetch(`${env.IamServiceUrl}/iam/me`, { - headers: { 'x-user-id': userId }, + headers: { "x-user-id": userId }, }), fetch(`${env.ClassesServiceUrl}/classes`, { - headers: { 'x-user-id': userId }, + headers: { "x-user-id": userId }, }), ]); return { - user: iamRes.status === 'fulfilled' ? await iamRes.value.json() : null, - classes: classesRes.status === 'fulfilled' ? await classesRes.value.json() : null, + user: iamRes.status === "fulfilled" ? await iamRes.value.json() : null, + classes: + classesRes.status === "fulfilled" + ? await classesRes.value.json() + : null, }; } + + // 聚合 IAM 视口配置(L1 导航) + async getViewports(userId: string): Promise { + const res = await fetch(`${env.IamServiceUrl}/iam/viewports`, { + headers: { "x-user-id": userId }, + }); + if (!res.ok) { + return []; + } + const json = (await res.json()) as { + success: boolean; + data?: ViewportItem[]; + }; + return json.data ?? []; + } }