All checks were successful
Deploy API Server / build-and-deploy (push) Successful in 41s
- 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>
47 lines
1.5 KiB
TypeScript
47 lines
1.5 KiB
TypeScript
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 };
|
||
}
|
||
}
|