From 1442b9b69e16bc0d0da84ca48ac222d7a66ca78d Mon Sep 17 00:00:00 2001 From: wangdl Date: Tue, 9 Jun 2026 21:46:37 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20admin=20controller=20audit=20=E2=80=94?= =?UTF-8?q?=20merge=20duplicate=20controllers,=20add=20Post=20import,=20va?= =?UTF-8?q?lidate=20params?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.7 --- .../reading-event/admin-reading.controller.ts | 43 +++++++++---------- 1 file changed, 20 insertions(+), 23 deletions(-) diff --git a/src/modules/reading-event/admin-reading.controller.ts b/src/modules/reading-event/admin-reading.controller.ts index bb7c901..9a26b6f 100644 --- a/src/modules/reading-event/admin-reading.controller.ts +++ b/src/modules/reading-event/admin-reading.controller.ts @@ -1,10 +1,12 @@ -import { Controller, Get, Param, Query } from '@nestjs/common'; +import { Controller, Get, Param, Post, Query, UseGuards } from '@nestjs/common'; import { PrismaService } from '../../infrastructure/database/prisma.service'; @Controller('admin/learning') export class AdminReadingController { constructor(private readonly prisma: PrismaService) {} + // ── Dashboard ── + @Get('dashboard') async getDashboard() { const now = new Date(); @@ -35,7 +37,6 @@ export class AdminReadingController { materials: { totalRead, totalMarkedRead }, }; } -} // ── ReadingEvent ── @@ -169,16 +170,12 @@ export class AdminReadingController { async getRecord(@Param('id') id: string) { return this.prisma.learningRecord.findUnique({ where: { id } }); } -} -// ── Diagnosis ── - -@Controller('admin/learning') -export class AdminDiagnosticController { - constructor(private readonly prisma: PrismaService) {} + // ── Diagnosis ── @Get('user-timeline') - async userTimeline(@Query('userId') userId: string) { + async userTimeline(@Query('userId') userId?: string) { + if (!userId) return { error: 'userId is required' }; const events = await this.prisma.readingEvent.findMany({ where: { userId }, orderBy: { clientTimestampMs: 'asc' }, take: 200, select: { eventType: true, materialId: true, clientTimestampMs: true, activeSecondsDelta: true }, @@ -187,7 +184,8 @@ export class AdminDiagnosticController { } @Get('user-diagnose') - async userDiagnose(@Query('userId') userId: string) { + async userDiagnose(@Query('userId') userId?: string) { + if (!userId) return { error: 'userId is required' }; const [sessions, progressList, dailyActivities, records] = await Promise.all([ this.prisma.learningSession.findMany({ where: { userId }, orderBy: { startedAt: 'desc' }, take: 50 }), this.prisma.materialReadingProgress.findMany({ where: { userId } }), @@ -198,7 +196,8 @@ export class AdminDiagnosticController { } @Get('material-diagnose') - async materialDiagnose(@Query('materialId') materialId: string) { + async materialDiagnose(@Query('materialId') materialId?: string) { + if (!materialId) return { error: 'materialId is required' }; const [events, progress] = await Promise.all([ this.prisma.readingEvent.findMany({ where: { materialId }, orderBy: { clientTimestampMs: 'desc' }, take: 100 }), this.prisma.materialReadingProgress.findMany({ where: { materialId } }), @@ -230,13 +229,8 @@ export class AdminDiagnosticController { ]); return { items, total, page, limit }; } -} -// ── Operations ── - -@Controller('admin/learning') -export class AdminOperationsController { - constructor(private readonly prisma: PrismaService) {} + // ── Operations ── @Post('recalculate') async recalculate() { @@ -249,14 +243,17 @@ export class AdminOperationsController { if (startDate) where.createdAt = { gte: new Date(startDate) }; if (endDate) where.createdAt = { ...where.createdAt, lte: new Date(endDate) }; - let data: any[] = []; + const take = 5000; switch (type) { - case 'events': data = await this.prisma.readingEvent.findMany({ where, take: 10000 }); break; - case 'sessions': data = await this.prisma.learningSession.findMany({ where, take: 10000 }); break; + case 'events': { + const data = await this.prisma.readingEvent.findMany({ where, take, orderBy: { createdAt: 'desc' } }); + return { type, count: data.length, data }; + } + case 'sessions': { + const data = await this.prisma.learningSession.findMany({ where, take, orderBy: { startedAt: 'desc' } }); + return { type, count: data.length, data }; + } default: return { error: 'Invalid export type. Use: events, sessions' }; } - return { type, count: data.length, data }; } } -EOF -echo "Admin diagnostic + operations endpoints added" \ No newline at end of file