fix: #159 getSummary/getTrend optimization + #160 admin auth guard
Some checks failed
Deploy API Server / build-and-deploy (push) Failing after 23s

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
wangdl 2026-06-09 21:50:31 +08:00
parent 1442b9b69e
commit 8dfda9f10e
2 changed files with 21 additions and 21 deletions

View File

@ -1,7 +1,9 @@
import { Controller, Get, Param, Post, Query, UseGuards } from '@nestjs/common'; import { Controller, Get, Param, Post, Query, UseGuards } from '@nestjs/common';
import { AdminJwtGuard } from '../../common/guards/admin-jwt.guard';
import { PrismaService } from '../../infrastructure/database/prisma.service'; import { PrismaService } from '../../infrastructure/database/prisma.service';
@Controller('admin/learning') @Controller('admin/learning')
@UseGuards(AdminJwtGuard)
export class AdminReadingController { export class AdminReadingController {
constructor(private readonly prisma: PrismaService) {} constructor(private readonly prisma: PrismaService) {}

View File

@ -110,43 +110,40 @@ export class ReadingController {
@Get('learning/summary') @Get('learning/summary')
async getSummary(@Req() req: any) { async getSummary(@Req() req: any) {
const userId = req.user.id; const userId = req.user.id;
const activities = await this.activityRepo.findAll(userId);
if (!activities.length) {
return { todaySeconds: 0, weekSeconds: 0, totalSeconds: 0, activeDays: 0, sessionsCount: 0, materialsReadCount: 0, markedReadCount: 0, dailyAverageSeconds: 0 };
}
const now = new Date(); const now = new Date();
const todayStr = now.toISOString().split('T')[0]; const todayStr = now.toISOString().split('T')[0];
const weekAgo = new Date(now.getTime() - 7 * 24 * 60 * 60 * 1000); const weekAgo = new Date(now.getTime() - 7 * 24 * 60 * 60 * 1000);
let todaySeconds = 0, weekSeconds = 0, totalSeconds = 0, activeDays = 0; // Query recent 90 days for week/today + aggregate totals
let sessionsCount = 0, materialsReadCount = 0, markedReadCount = 0; const from = new Date(now.getTime() - 90 * 24 * 60 * 60 * 1000);
const activities = await this.activityRepo.findByDateRange(userId, from, now);
const allActivities = await this.activityRepo.findAll(userId);
for (const a of activities) { if (!allActivities.length) {
const dateStr = a.activityDate instanceof Date ? a.activityDate.toISOString().split('T')[0] : String(a.activityDate).split('T')[0]; return { todaySeconds: 0, weekSeconds: 0, totalSeconds: 0, activeDays: 0, sessionsCount: 0, materialsReadCount: 0, markedReadCount: 0, dailyAverageSeconds: 0 };
}
let todaySeconds = 0, weekSeconds = 0, recentSeconds = 0;
let totalSeconds = 0, activeDays = 0, sessionsCount = 0, materialsReadCount = 0, markedReadCount = 0;
for (const a of allActivities) {
totalSeconds += a.readingSeconds; totalSeconds += a.readingSeconds;
sessionsCount += a.sessionsCount; sessionsCount += a.sessionsCount;
materialsReadCount += a.materialsReadCount; materialsReadCount += a.materialsReadCount;
markedReadCount += a.markedReadCount; markedReadCount += a.markedReadCount;
if (a.readingSeconds > 0) activeDays++; if (a.readingSeconds > 0) activeDays++;
}
for (const a of activities) {
const dateStr = a.activityDate instanceof Date ? a.activityDate.toISOString().split('T')[0] : String(a.activityDate).split('T')[0];
if (dateStr === todayStr) todaySeconds += a.readingSeconds; if (dateStr === todayStr) todaySeconds += a.readingSeconds;
const actDate = a.activityDate instanceof Date ? a.activityDate : new Date(a.activityDate); const actDate = a.activityDate instanceof Date ? a.activityDate : new Date(a.activityDate);
if (actDate >= weekAgo) weekSeconds += a.readingSeconds; if (actDate >= weekAgo) weekSeconds += a.readingSeconds;
} }
return { return {
todaySeconds, todaySeconds, weekSeconds, totalSeconds, activeDays,
weekSeconds, sessionsCount, materialsReadCount, markedReadCount,
totalSeconds,
activeDays,
sessionsCount,
materialsReadCount,
markedReadCount,
dailyAverageSeconds: activeDays > 0 ? Math.round(totalSeconds / activeDays) : 0, dailyAverageSeconds: activeDays > 0 ? Math.round(totalSeconds / activeDays) : 0,
}; };
} }
@ -155,8 +152,10 @@ export class ReadingController {
async getTrend(@Req() req: any, @Query('days') daysStr?: string) { async getTrend(@Req() req: any, @Query('days') daysStr?: string) {
const userId = req.user.id; const userId = req.user.id;
const days = Math.min(Number(daysStr ?? 7) || 7, 90); const days = Math.min(Number(daysStr ?? 7) || 7, 90);
const now = new Date();
const from = new Date(now.getTime() - days * 24 * 60 * 60 * 1000);
const activities = await this.activityRepo.findAll(userId); const activities = await this.activityRepo.findByDateRange(userId, from, now);
const dataMap = new Map<string, number>(); const dataMap = new Map<string, number>();
for (const a of activities) { for (const a of activities) {
const ds = a.activityDate instanceof Date ? a.activityDate.toISOString().split('T')[0] : String(a.activityDate).split('T')[0]; const ds = a.activityDate instanceof Date ? a.activityDate.toISOString().split('T')[0] : String(a.activityDate).split('T')[0];
@ -164,7 +163,6 @@ export class ReadingController {
} }
const series: Array<{ date: string; value: number }> = []; const series: Array<{ date: string; value: number }> = [];
const now = new Date();
for (let i = days - 1; i >= 0; i--) { for (let i = days - 1; i >= 0; i--) {
const d = new Date(now.getTime() - i * 24 * 60 * 60 * 1000); const d = new Date(now.getTime() - i * 24 * 60 * 60 * 1000);
const ds = d.toISOString().split('T')[0]; const ds = d.toISOString().split('T')[0];