import mongoose, { Document, Schema } from 'mongoose'; // 单词接口 export interface IWord extends Document { word: string; translation: string; pronunciation?: string; example?: string; wordSet: mongoose.Types.ObjectId; createdAt: Date; updatedAt: Date; } // 单词集接口 export interface IWordSet extends Document { name: string; description?: string; owner: mongoose.Types.ObjectId; totalWords: number; createdAt: Date; updatedAt: Date; } // 单词学习记录接口 export interface IWordRecord extends Document { user: mongoose.Types.ObjectId; word: mongoose.Types.ObjectId; mode: 'chinese-to-english' | 'audio-to-english' | 'multiple-choice'; streak: number; totalCorrect: number; totalWrong: number; mastered: boolean; inWrongBook: boolean; lastTestedAt: Date; lastMasteredAt: Date; createdAt: Date; } // 单词测试记录接口 export interface IVocabularyTestRecord extends Document { user: mongoose.Types.ObjectId; wordSet: mongoose.Types.ObjectId; testType: 'chinese-to-english' | 'audio-to-english' | 'multiple-choice'; attempt?: mongoose.Types.ObjectId; stats: { totalWords: number; correctWords: number; accuracy: number; startTime: Date; endTime: Date; duration: number; }; results?: Array<{ word: mongoose.Types.ObjectId; userAnswer: string; correctAnswer: string; isCorrect: boolean; }>; createdAt: Date; } export interface IVocabularyTestAttempt extends Document { user: mongoose.Types.ObjectId; wordSet: mongoose.Types.ObjectId; testType: 'chinese-to-english' | 'audio-to-english' | 'multiple-choice'; questionWordIds: mongoose.Types.ObjectId[]; questionTokens: string[]; issuedAt: Date; expiresAt: Date; submittedAt?: Date; status: 'active' | 'submitted' | 'expired'; createdAt: Date; updatedAt: Date; } // 单词模式 const WordSchema = new Schema({ word: { type: String, required: true, trim: true }, translation: { type: String, required: true, trim: true }, pronunciation: { type: String, trim: true }, example: { type: String, trim: true }, wordSet: { type: Schema.Types.ObjectId, ref: 'WordSet', required: true }, }, { timestamps: true }); // 为单词模型添加索引 WordSchema.index({ word: 1, wordSet: 1 }, { unique: true }); WordSchema.index({ translation: 'text', word: 'text' }); // 单词集模式 const WordSetSchema = new Schema({ name: { type: String, required: true, trim: true }, description: { type: String, trim: true }, owner: { type: Schema.Types.ObjectId, ref: 'User', required: true }, totalWords: { type: Number, default: 0 }, }, { timestamps: true }); // 为单词集模型添加索引 WordSetSchema.index({ name: 1, owner: 1 }, { unique: true }); // 简化的嵌套模式统计 const ModeStatsSchema = new Schema({ streak: { type: Number, default: 0 }, totalCorrect: { type: Number, default: 0 }, totalWrong: { type: Number, default: 0 }, mastered: { type: Boolean, default: false }, inWrongBook: { type: Boolean, default: false }, lastTestedAt: Date, lastMasteredAt: Date }, { _id: false }); // 简化后的主记录模式 const WordRecordSchema = new Schema({ user: { type: Schema.Types.ObjectId, ref: 'User', required: true }, word: { type: Schema.Types.ObjectId, ref: 'Word', required: true }, // 各模式的基础统计数据 multipleChoice: { type: ModeStatsSchema, default: () => ({}) }, audioToEnglish: { type: ModeStatsSchema, default: () => ({}) }, chineseToEnglish: { type: ModeStatsSchema, default: () => ({}) }, // 只在顶层保留整体掌握状态 isFullyMastered: { type: Boolean, default: false }, lastFullyMasteredAt: Date, createdAt: { type: Date, default: Date.now } }); // 单词测试记录模式 const VocabularyTestRecordSchema = new Schema({ user: { type: Schema.Types.ObjectId, ref: 'User', required: true }, wordSet: { type: Schema.Types.ObjectId, ref: 'WordSet', required: true }, attempt: { type: Schema.Types.ObjectId, ref: 'VocabularyTestAttempt' }, testType: { type: String, enum: ['chinese-to-english', 'audio-to-english', 'multiple-choice'], required: true }, stats: { totalWords: { type: Number, required: true }, correctWords: { type: Number, required: true }, accuracy: { type: Number, required: true }, startTime: { type: Date, required: true }, endTime: { type: Date, required: true }, duration: { type: Number, required: true } }, results: [{ word: { type: Schema.Types.ObjectId, ref: 'Word', required: true }, userAnswer: { type: String, default: '' }, correctAnswer: { type: String, required: true }, isCorrect: { type: Boolean, required: true } }], createdAt: { type: Date, default: Date.now } }); // 单词测试会话模式,用于防止直接伪造测试提交 const VocabularyTestAttemptSchema = new Schema({ user: { type: Schema.Types.ObjectId, ref: 'User', required: true }, wordSet: { type: Schema.Types.ObjectId, ref: 'WordSet', required: true }, testType: { type: String, enum: ['chinese-to-english', 'audio-to-english', 'multiple-choice'], required: true }, questionWordIds: [{ type: Schema.Types.ObjectId, ref: 'Word', required: true }], questionTokens: [{ type: String, required: true }], issuedAt: { type: Date, required: true }, expiresAt: { type: Date, required: true }, submittedAt: Date, status: { type: String, enum: ['active', 'submitted', 'expired'], default: 'active', required: true } }, { timestamps: true }); VocabularyTestAttemptSchema.index({ user: 1, status: 1, expiresAt: 1 }); VocabularyTestAttemptSchema.index({ expiresAt: 1 }); // 创建和导出模型 export const Word = mongoose.model('Word', WordSchema); export const WordSet = mongoose.model('WordSet', WordSetSchema); export const WordRecord = mongoose.model('WordRecord', WordRecordSchema); export const VocabularyTestRecord = mongoose.model('VocabularyTestRecord', VocabularyTestRecordSchema); export const VocabularyTestAttempt = mongoose.model('VocabularyTestAttempt', VocabularyTestAttemptSchema); export default { Word, WordSet, WordRecord, VocabularyTestRecord, VocabularyTestAttempt };