feat: M4-02 — admin learning data views (sessions, AI analysis, AI usage logs)
All checks were successful
Deploy API Server / build-and-deploy (push) Successful in 44s
All checks were successful
Deploy API Server / build-and-deploy (push) Successful in 44s
- Add AdminLearningController with 3 endpoints: GET /admin-api/learning/sessions — learning sessions list GET /admin-api/learning/analysis — AI analysis results GET /admin-api/learning/ai-usage — AI usage logs Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
5816ddf488
commit
90e921366a
100
src/modules/learning-session/admin-learning.controller.ts
Normal file
100
src/modules/learning-session/admin-learning.controller.ts
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
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-learning')
|
||||||
|
@ApiBearerAuth()
|
||||||
|
@Controller('admin-api/learning')
|
||||||
|
@UseGuards(AdminAuthGuard, AdminRolesGuard)
|
||||||
|
export class AdminLearningController {
|
||||||
|
constructor(private readonly prisma: PrismaService) {}
|
||||||
|
|
||||||
|
@Get('sessions')
|
||||||
|
@ApiOperation({ summary: '学习会话列表' })
|
||||||
|
@ApiQuery({ name: 'userId', required: false })
|
||||||
|
@ApiQuery({ name: 'page', required: false })
|
||||||
|
@ApiQuery({ name: 'limit', required: false })
|
||||||
|
async listSessions(
|
||||||
|
@Query('userId') userId?: 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 (userId) where.userId = userId;
|
||||||
|
|
||||||
|
const [items, total] = await Promise.all([
|
||||||
|
this.prisma.learningSession.findMany({
|
||||||
|
where,
|
||||||
|
orderBy: { startedAt: 'desc' },
|
||||||
|
take,
|
||||||
|
skip,
|
||||||
|
select: { id: true, userId: true, knowledgeBaseId: true, knowledgeItemId: true, mode: true, status: true, startedAt: true, endedAt: true, durationSeconds: true, focusMinutes: true },
|
||||||
|
}),
|
||||||
|
this.prisma.learningSession.count({ where }),
|
||||||
|
]);
|
||||||
|
return { items, total };
|
||||||
|
}
|
||||||
|
|
||||||
|
@Get('analysis')
|
||||||
|
@ApiOperation({ summary: 'AI 分析结果列表' })
|
||||||
|
@ApiQuery({ name: 'userId', required: false })
|
||||||
|
@ApiQuery({ name: 'page', required: false })
|
||||||
|
@ApiQuery({ name: 'limit', required: false })
|
||||||
|
async listAnalysis(
|
||||||
|
@Query('userId') userId?: 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 (userId) where.userId = userId;
|
||||||
|
|
||||||
|
const [items, total] = await Promise.all([
|
||||||
|
this.prisma.aiAnalysisResult.findMany({
|
||||||
|
where,
|
||||||
|
orderBy: { createdAt: 'desc' },
|
||||||
|
take,
|
||||||
|
skip,
|
||||||
|
select: { id: true, userId: true, jobId: true, summary: true, masteryScore: true, weaknesses: true, strengths: true, createdAt: true },
|
||||||
|
}),
|
||||||
|
this.prisma.aiAnalysisResult.count({ where }),
|
||||||
|
]);
|
||||||
|
return { items, total };
|
||||||
|
}
|
||||||
|
|
||||||
|
@Get('ai-usage')
|
||||||
|
@ApiOperation({ summary: 'AI 调用日志' })
|
||||||
|
@ApiQuery({ name: 'userId', required: false })
|
||||||
|
@ApiQuery({ name: 'model', required: false })
|
||||||
|
@ApiQuery({ name: 'page', required: false })
|
||||||
|
@ApiQuery({ name: 'limit', required: false })
|
||||||
|
async listAiUsage(
|
||||||
|
@Query('userId') userId?: string,
|
||||||
|
@Query('model') model?: 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 (userId) where.userId = userId;
|
||||||
|
if (model) where.model = { contains: model };
|
||||||
|
|
||||||
|
const [items, total] = await Promise.all([
|
||||||
|
this.prisma.aiUsageLog.findMany({
|
||||||
|
where,
|
||||||
|
orderBy: { createdAt: 'desc' },
|
||||||
|
take,
|
||||||
|
skip,
|
||||||
|
select: { id: true, userId: true, model: true, provider: true, inputTokens: true, outputTokens: true, estimatedCost: true, success: true, createdAt: true },
|
||||||
|
}),
|
||||||
|
this.prisma.aiUsageLog.count({ where }),
|
||||||
|
]);
|
||||||
|
return { items, total };
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,10 +1,11 @@
|
|||||||
import { Module } from '@nestjs/common';
|
import { Module } from '@nestjs/common';
|
||||||
import { LearningSessionController } from './learning-session.controller';
|
import { LearningSessionController } from './learning-session.controller';
|
||||||
|
import { AdminLearningController } from './admin-learning.controller';
|
||||||
import { LearningSessionService } from './learning-session.service';
|
import { LearningSessionService } from './learning-session.service';
|
||||||
import { LearningSessionRepository } from './learning-session.repository';
|
import { LearningSessionRepository } from './learning-session.repository';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
controllers: [LearningSessionController],
|
controllers: [LearningSessionController, AdminLearningController],
|
||||||
providers: [LearningSessionService, LearningSessionRepository],
|
providers: [LearningSessionService, LearningSessionRepository],
|
||||||
exports: [LearningSessionService],
|
exports: [LearningSessionService],
|
||||||
})
|
})
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user