fix: 代码整合修复 - Entity类型、题库生成、评估流程等14项修复

This commit is contained in:
Developer
2026-05-14 09:55:07 +08:00
parent 122ab5e96f
commit 368eddfd75
17 changed files with 1666 additions and 115 deletions
+218
View File
@@ -526,6 +526,10 @@ private async getModel(tenantId: string): Promise<ChatOpenAI> {
language,
questions_json: questionsFromBank.length > 0 ? questionsFromBank : [],
questionSource,
startedAt: new Date(),
currentQuestionStartedAt: new Date(),
totalTimeLimit: template?.totalTimeLimit || 1800,
perQuestionTimeLimit: template?.perQuestionTimeLimit || 300,
};
const content = await this.getSessionContent(sessionData);
@@ -1442,6 +1446,82 @@ const initialState: Partial<EvaluationState> = {
};
}
async getRadarStats(userId: string, tenantId: string, role: string, templateId?: string): Promise<any> {
const isAdmin = role === 'super_admin' || role === 'admin';
const qb = this.sessionRepository.createQueryBuilder('session');
qb.where('session.tenantId = :tenantId', { tenantId });
qb.andWhere('session.status = :status', { status: AssessmentStatus.COMPLETED });
if (!isAdmin) {
qb.andWhere('session.userId = :userId', { userId });
}
if (templateId) {
qb.andWhere('session.templateId = :templateId', { templateId });
}
const sessions = await qb.take(100).getMany();
const dimensionScores: Record<string, number[]> = {
PROMPT: [],
LLM: [],
IDE: [],
DEV_PATTERN: [],
WORK_CAPABILITY: [],
};
for (const session of sessions) {
const messages = session.messages || [];
for (const msg of messages) {
if (msg.dimension && msg.score !== undefined) {
dimensionScores[msg.dimension]?.push(msg.score);
}
}
}
const radarData: Record<string, number> = {};
for (const [dim, scores] of Object.entries(dimensionScores)) {
if (scores.length > 0) {
radarData[dim] = Math.round((scores.reduce((a, b) => a + b, 0) / scores.length) * 10) / 10;
} else {
radarData[dim] = 0;
}
}
return { radarData, sampleCount: sessions.length };
}
async getTrendStats(userId: string, tenantId: string, role: string, startDate?: string, endDate?: string): Promise<any> {
const isAdmin = role === 'super_admin' || role === 'admin';
const qb = this.sessionRepository.createQueryBuilder('session');
qb.where('session.tenantId = :tenantId', { tenantId });
qb.andWhere('session.status = :status', { status: AssessmentStatus.COMPLETED });
if (!isAdmin) {
qb.andWhere('session.userId = :userId', { userId });
}
if (startDate) {
qb.andWhere('session.createdAt >= :startDate', { startDate: new Date(startDate) });
}
if (endDate) {
qb.andWhere('session.createdAt <= :endDate', { endDate: new Date(endDate) });
}
const sessions = await qb
.orderBy('session.createdAt', 'ASC')
.take(50)
.getMany();
const trendData = sessions.map(session => ({
date: session.createdAt,
score: session.finalScore || 0,
template: session.template?.name || '-',
}));
return { trendData, count: sessions.length };
}
async reviewAssessment(
sessionId: string,
newScore: number,
@@ -1477,6 +1557,8 @@ const initialState: Partial<EvaluationState> = {
}
session.finalScore = newScore;
const passingScore = session.templateJson?.passingScore || 90;
(session as any).passed = newScore >= passingScore;
session.reviewedBy = reviewerId;
session.reviewedAt = new Date();
session.reviewComment = comment || null;
@@ -1515,4 +1597,140 @@ const initialState: Partial<EvaluationState> = {
this.logger.log(`[cleanupOldSessions] Deleted ${toDelete.length} old sessions for user ${userId}`);
}
}
async checkTimeLimits(sessionId: string): Promise<{
totalTimeRemaining: number;
questionTimeRemaining: number;
isTotalTimeout: boolean;
isQuestionTimeout: boolean;
}> {
const session = await this.sessionRepository.findOne({
where: { id: sessionId },
});
if (!session || session.status === AssessmentStatus.COMPLETED) {
return {
totalTimeRemaining: 0,
questionTimeRemaining: 0,
isTotalTimeout: true,
isQuestionTimeout: true,
};
}
const now = new Date();
const startTime = session.startedAt ? new Date(session.startedAt) : now;
const questionStartTime = session.currentQuestionStartedAt ? new Date(session.currentQuestionStartedAt) : now;
const totalElapsed = Math.floor((now.getTime() - startTime.getTime()) / 1000);
const questionElapsed = Math.floor((now.getTime() - questionStartTime.getTime()) / 1000);
const totalTimeRemaining = Math.max(0, session.totalTimeLimit - totalElapsed);
const questionTimeRemaining = Math.max(0, session.perQuestionTimeLimit - questionElapsed);
return {
totalTimeRemaining,
questionTimeRemaining,
isTotalTimeout: totalElapsed >= session.totalTimeLimit,
isQuestionTimeout: questionElapsed >= session.perQuestionTimeLimit,
};
}
async updateQuestionStartTime(sessionId: string): Promise<void> {
const session = await this.sessionRepository.findOne({
where: { id: sessionId },
});
if (session) {
session.currentQuestionStartedAt = new Date();
await this.sessionRepository.save(session);
}
}
async verifyCertificate(certificateId: string): Promise<{
valid: boolean;
certificate?: {
id: string;
level: string;
totalScore: number;
passed: boolean;
issuedAt: Date;
userId: string;
};
message?: string;
}> {
const certificate = await this.certificateRepository.findOne({
where: { id: certificateId },
relations: ['user'],
});
if (!certificate) {
return { valid: false, message: 'Certificate not found' };
}
return {
valid: true,
certificate: {
id: certificate.id,
level: certificate.level,
totalScore: certificate.totalScore,
passed: certificate.passed,
issuedAt: certificate.issuedAt,
userId: certificate.userId,
},
};
}
async getPublicCertificateInfo(sessionId: string): Promise<{
exists: boolean;
certificate?: {
level: string;
totalScore: number;
passed: boolean;
issuedAt: Date;
dimensionScores: Record<string, number>;
};
message?: string;
}> {
const certificate = await this.certificateRepository.findOne({
where: { sessionId },
});
if (!certificate) {
return { exists: false, message: 'Certificate not found for this session' };
}
return {
exists: true,
certificate: {
level: certificate.level,
totalScore: certificate.totalScore,
passed: certificate.passed,
issuedAt: certificate.issuedAt,
dimensionScores: certificate.dimensionScores || {},
},
};
}
async forceEndAssessment(sessionId: string): Promise<AssessmentSession> {
const session = await this.sessionRepository.findOne({
where: { id: sessionId },
});
if (!session) {
throw new NotFoundException('Assessment session not found');
}
if (session.status === AssessmentStatus.COMPLETED) {
return session;
}
session.status = AssessmentStatus.COMPLETED;
session.finalReport = '评估已被管理员强制结束';
session.finalScore = 0;
await this.sessionRepository.save(session);
this.logger.log(`[forceEndAssessment] Session ${sessionId} force ended by admin`);
return session;
}
}