import { v4 as uuidv4 } from 'uuid'; import { query, run, get } from '../database'; import { Question } from './question'; export interface QuizRecord { id: string; userId: string; totalScore: number; correctCount: number; totalCount: number; createdAt: string; } export interface QuizAnswer { id: string; recordId: string; questionId: string; userAnswer: string | string[]; score: number; isCorrect: boolean; createdAt: string; questionContent?: string; questionType?: string; correctAnswer?: string | string[]; questionScore?: number; questionAnalysis?: string; } export interface SubmitAnswerData { questionId: string; userAnswer: string | string[]; score: number; isCorrect: boolean; } export interface SubmitQuizData { userId: string; answers: SubmitAnswerData[]; } export class QuizModel { // 创建答题记录 static async createRecord(data: { userId: string; totalScore: number; correctCount: number; totalCount: number }): Promise { const id = uuidv4(); const sql = ` INSERT INTO quiz_records (id, user_id, total_score, correct_count, total_count) VALUES (?, ?, ?, ?, ?) `; await run(sql, [id, data.userId, data.totalScore, data.correctCount, data.totalCount]); return this.findRecordById(id) as Promise; } // 创建答题答案 static async createAnswer(data: Omit): Promise { const id = uuidv4(); const userAnswerStr = Array.isArray(data.userAnswer) ? JSON.stringify(data.userAnswer) : data.userAnswer; const sql = ` INSERT INTO quiz_answers (id, record_id, question_id, user_answer, score, is_correct) VALUES (?, ?, ?, ?, ?, ?) `; await run(sql, [id, data.recordId, data.questionId, userAnswerStr, data.score, data.isCorrect]); return { id, recordId: data.recordId, questionId: data.questionId, userAnswer: data.userAnswer, score: data.score, isCorrect: data.isCorrect, createdAt: new Date().toISOString() }; } // 批量创建答题答案 static async createAnswers(recordId: string, answers: SubmitAnswerData[]): Promise { const createdAnswers: QuizAnswer[] = []; for (const answer of answers) { const createdAnswer = await this.createAnswer({ recordId, questionId: answer.questionId, userAnswer: answer.userAnswer, score: answer.score, isCorrect: answer.isCorrect }); createdAnswers.push(createdAnswer); } return createdAnswers; } // 提交答题 static async submitQuiz(data: SubmitQuizData): Promise<{ record: QuizRecord; answers: QuizAnswer[] }> { const totalScore = data.answers.reduce((sum, answer) => sum + answer.score, 0); const correctCount = data.answers.filter(answer => answer.isCorrect).length; const totalCount = data.answers.length; // 创建答题记录 const record = await this.createRecord({ userId: data.userId, totalScore, correctCount, totalCount }); // 创建答题答案 const answers = await this.createAnswers(record.id, data.answers); return { record, answers }; } // 根据ID查找答题记录 static async findRecordById(id: string): Promise { const sql = `SELECT id, user_id as userId, total_score as totalScore, correct_count as correctCount, total_count as totalCount, created_at as createdAt FROM quiz_records WHERE id = ?`; const record = await get(sql, [id]); return record || null; } // 获取用户的答题记录 static async findRecordsByUserId(userId: string, limit = 10, offset = 0): Promise<{ records: QuizRecord[]; total: number }> { const recordsSql = ` SELECT id, user_id as userId, total_score as totalScore, correct_count as correctCount, total_count as totalCount, created_at as createdAt FROM quiz_records WHERE user_id = ? ORDER BY created_at DESC LIMIT ? OFFSET ? `; const countSql = `SELECT COUNT(*) as total FROM quiz_records WHERE user_id = ?`; const [records, countResult] = await Promise.all([ query(recordsSql, [userId, limit, offset]), get(countSql, [userId]) ]); return { records, total: countResult.total }; } // 获取所有答题记录(管理员用) static async findAllRecords(limit = 10, offset = 0): Promise<{ records: any[]; total: number }> { const recordsSql = ` SELECT r.id, r.user_id as userId, u.name as userName, u.phone as userPhone, r.total_score as totalScore, r.correct_count as correctCount, r.total_count as totalCount, r.created_at as createdAt, r.subject_id as subjectId, s.name as subjectName, r.task_id as taskId FROM quiz_records r JOIN users u ON r.user_id = u.id LEFT JOIN exam_subjects s ON r.subject_id = s.id ORDER BY r.created_at DESC LIMIT ? OFFSET ? `; const countSql = `SELECT COUNT(*) as total FROM quiz_records`; const [records, countResult] = await Promise.all([ query(recordsSql, [limit, offset]), get(countSql) ]); // 对于每条记录,计算该考试任务的参与人数 const processedRecords = await Promise.all(records.map(async (record) => { let examCount = 0; if (record.taskId) { // 统计该任务的参与人数 const taskCountSql = `SELECT COUNT(DISTINCT user_id) as count FROM quiz_records WHERE task_id = ?`; const taskCountResult = await get(taskCountSql, [record.taskId]); examCount = taskCountResult.count || 0; } else if (record.subjectId) { // 统计该科目的参与人数 const subjectCountSql = `SELECT COUNT(DISTINCT user_id) as count FROM quiz_records WHERE subject_id = ?`; const subjectCountResult = await get(subjectCountSql, [record.subjectId]); examCount = subjectCountResult.count || 0; } return { ...record, examCount }; })); return { records: processedRecords, total: countResult.total }; } // 获取答题答案详情 static async findAnswersByRecordId(recordId: string): Promise { const sql = ` SELECT a.id, a.record_id as recordId, a.question_id as questionId, a.user_answer as userAnswer, a.score, a.is_correct as isCorrect, a.created_at as createdAt, q.content as questionContent, q.type as questionType, q.answer as correctAnswer, q.score as questionScore, q.analysis as questionAnalysis FROM quiz_answers a JOIN questions q ON a.question_id = q.id WHERE a.record_id = ? ORDER BY a.created_at ASC `; const answers = await query(sql, [recordId]); return answers.map(row => ({ id: row.id, recordId: row.recordId, questionId: row.questionId, userAnswer: this.parseAnswer(row.userAnswer, row.questionType), score: row.score, isCorrect: Boolean(row.isCorrect), createdAt: row.createdAt, questionContent: row.questionContent, questionType: row.questionType, correctAnswer: this.parseAnswer(row.correctAnswer, row.questionType), questionScore: row.questionScore, questionAnalysis: row.questionAnalysis ?? '' })); } // 解析答案 private static parseAnswer(answer: string, type: string): string | string[] { if (type === 'multiple' || type === 'checkbox') { try { return JSON.parse(answer); } catch (e) { return answer; } } return answer; } // 获取统计数据 static async getStatistics(): Promise<{ totalUsers: number; totalRecords: number; averageScore: number; typeStats: Array<{ type: string; total: number; correct: number; correctRate: number }>; }> { const totalUsersSql = `SELECT COUNT(*) as total FROM users`; const totalRecordsSql = `SELECT COUNT(*) as total FROM quiz_records`; const averageScoreSql = `SELECT AVG(total_score) as average FROM quiz_records`; const typeStatsSql = ` SELECT q.type, COUNT(*) as total, SUM(CASE WHEN qa.is_correct = 1 THEN 1 ELSE 0 END) as correct, ROUND(SUM(CASE WHEN qa.is_correct = 1 THEN 1.0 ELSE 0.0 END) * 100 / COUNT(*), 2) as correctRate FROM quiz_answers qa JOIN questions q ON qa.question_id = q.id GROUP BY q.type `; const [totalUsers, totalRecords, averageScore, typeStats] = await Promise.all([ get(totalUsersSql), get(totalRecordsSql), get(averageScoreSql), query(typeStatsSql) ]); return { totalUsers: totalUsers.total, totalRecords: totalRecords.total, averageScore: Math.round(averageScore.average * 100) / 100, typeStats }; } }