api-server/src/modules/review/admin-review.controller.ts
WangDL 2bfa9ad7c3
All checks were successful
Deploy API Server / build-and-deploy (push) Successful in 41s
fix: M3 audit — scheduleState persistence, AI→ReviewCard subscriber, ActiveRecall queue, streak bug, domain events
- M3-02: Add scheduleState to ReviewCard model + persist in updateCard/insertCard
- M3-02: Add ReviewCardSubscriber (OnEvent 'ai.analysis.completed' → generateCards)
- M3-02: Add AdminReviewController (GET /admin-api/reviews)
- M3-01: ActiveRecall now enqueues via AiAnalysisService instead of direct workflow call
- M3-01: FocusItem model adds source field, worker uses status:'open'
- M3-03: Fix streak calculation (break on gap), add StreakUpdatedEvent/DailyGoalAchievedEvent
- M3-03: Add LearningGoal/StreakRecord/LearningStats to Prisma schema
- M3-03: Fix FocusItem recommendation query (status:'pending' → 'open')

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-24 16:17:34 +08:00

47 lines
1.5 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 { Controller, Get, Query, UseGuards } from '@nestjs/common';
import { ApiTags, ApiBearerAuth, ApiOperation, ApiQuery } from '@nestjs/swagger';
import { PrismaService } from '../../infrastructure/database/prisma.service';
import { AdminAuthGuard } from '../../common/guards/admin-auth.guard';
import { AdminRolesGuard } from '../../common/guards/admin-roles.guard';
@ApiTags('admin-review')
@ApiBearerAuth()
@Controller('admin-api/reviews')
@UseGuards(AdminAuthGuard, AdminRolesGuard)
export class AdminReviewController {
constructor(private readonly prisma: PrismaService) {}
@Get()
@ApiOperation({ summary: '复习卡片列表Admin' })
@ApiQuery({ name: 'search', required: false })
@ApiQuery({ name: 'status', required: false })
@ApiQuery({ name: 'page', required: false })
@ApiQuery({ name: 'limit', required: false })
async list(
@Query('search') search?: string,
@Query('status') status?: string,
@Query('page') page?: string,
@Query('limit') limit?: string,
) {
const take = Math.min(Number(limit) || 20, 100);
const skip = (Math.max(Number(page) || 1, 1) - 1) * take;
const where: any = {};
if (status) where.status = status;
if (search) {
where.frontText = { contains: search };
}
const [items, total] = await Promise.all([
this.prisma.reviewCard.findMany({
where,
orderBy: { createdAt: 'desc' },
take,
skip,
}),
this.prisma.reviewCard.count({ where }),
]);
return { items, total };
}
}