2
0
Pārlūkot izejas kodu

♻️ refactor(exam): 优化考试相关类型定义与服务实现

- 调整ExamSocketMessageType类型,移除对BaseSocketMessage的依赖
- 修改userId类型从string统一为number,保持前后端数据类型一致
- 为storeAnswer、getAnswers等方法添加明确的Answer类型约束
- 优化price字段处理,使用Number()替代parseFloat()确保类型转换一致性
- 移除Answer接口中冗余的userId定义,继承自QuizContent
- 完善calculateScore方法参数类型,提升代码类型安全性
yourname 6 mēneši atpakaļ
vecāks
revīzija
ed3134df64

+ 3 - 6
src/client/mobile/components/Exam/types.ts

@@ -1,5 +1,3 @@
-import type { SocketMessage as BaseSocketMessage, SocketMessageType } from '@d8d-appcontainer/types';
-
 // 基础答题记录
 export interface AnswerRecord {
   date: string;
@@ -17,7 +15,7 @@ export interface QuizContent {
   price: number | string;
   holdingStock: string;
   holdingCash: string;
-  userId: string;
+  userId: number;
 }
 
 // 题目状态
@@ -27,10 +25,10 @@ export interface QuizState {
   id?: string; // 新增可选id字段
 }
 
-export type ExamSocketMessageType = SocketMessageType | 'question' | 'answer' | 'settlement' | 'submit' | 'restart';
+export type ExamSocketMessageType = 'question' | 'answer' | 'settlement' | 'submit' | 'restart';
 
 // Socket消息
-export interface ExamSocketMessage extends Omit<BaseSocketMessage, 'type' | 'content'> {
+export interface ExamSocketMessage {
   type: ExamSocketMessageType;
   content: QuizContent;
 }
@@ -43,7 +41,6 @@ export interface ExamSocketRoomMessage {
 
 // 答案
 export interface Answer extends QuizContent {
-  userId: string;
   profitAmount?: number;
   profitPercent?: number;
   totalProfitAmount?: number;

+ 7 - 6
src/server/socket/services/exam.service.ts

@@ -4,6 +4,7 @@ import { redisService } from './redis.service';
 import { AppDataSource } from '@/server/data-source';
 import { SubmissionRecords } from '@/server/modules/submission/submission-records.entity';
 import debug from 'debug';
+import type { Answer } from '@/client/mobile/components/Exam/types';
 
 const log = debug('socket:exam');
 
@@ -67,7 +68,7 @@ export class ExamService {
     }
   }
 
-  async storeAnswer(socket: AuthenticatedSocket, roomId: string, questionId: string, answer: any): Promise<boolean> {
+  async storeAnswer(socket: AuthenticatedSocket, roomId: string, questionId: string, answer: Answer): Promise<boolean> {
     try {
       if (!socket.user) throw new Error('用户未认证');
       
@@ -87,7 +88,7 @@ export class ExamService {
     }
   }
 
-  async getAnswers(roomId: string, questionId?: string) {
+  async getAnswers(roomId: string, questionId?: string): Promise<Answer[]> {
     try {
       return await redisService.getAnswers(roomId, questionId);
     } catch (error) {
@@ -96,7 +97,7 @@ export class ExamService {
     }
   }
 
-  async getUserAnswers(roomId: string, userId: number) {
+  async getUserAnswers(roomId: string, userId: number): Promise<Answer[]> {
     try {
       return await redisService.getUserAnswers(roomId, userId);
     } catch (error) {
@@ -203,7 +204,7 @@ export class ExamService {
         // 转换Redis中的答案数据为提交记录实体
         const submissionRecord = new SubmissionRecords();
         submissionRecord.classroomNo = roomId;
-        submissionRecord.userId = answer.userId?.toString() || null;
+        submissionRecord.userId = answer.userId || null;
         submissionRecord.score = this.calculateScore(answer);
         submissionRecord.code = answer.code || null;
         submissionRecord.trainingDate = answer.date ? new Date(answer.date) : null;
@@ -211,7 +212,7 @@ export class ExamService {
         submissionRecord.status = 1; // 状态:1-正常
         submissionRecord.holdingStock = answer.holdingStock || null;
         submissionRecord.holdingCash = answer.holdingCash || null;
-        submissionRecord.price = answer.price ? parseFloat(answer.price) : null;
+        submissionRecord.price = Number(answer.price);
         submissionRecord.profitAmount = answer.profitAmount || null;
         submissionRecord.profitPercent = answer.profitPercent || null;
         submissionRecord.totalProfitAmount = answer.totalProfitAmount || null;
@@ -234,7 +235,7 @@ export class ExamService {
   /**
    * 计算得分(可根据业务需求自定义评分逻辑)
    */
-  private calculateScore(answer: any): number | null {
+  private calculateScore(answer: Answer): number | null {
     // 这里可以根据答题内容计算得分
     // 示例:根据收益率计算得分,收益率越高得分越高
     if (answer.profitPercent !== undefined && answer.profitPercent !== null) {

+ 6 - 5
src/server/socket/services/redis.service.ts

@@ -1,5 +1,6 @@
 import Redis from 'ioredis';
 import debug from 'debug';
+import type { Answer } from '@/client/mobile/components/Exam/types';
 
 const log = debug('socket:redis');
 
@@ -82,7 +83,7 @@ export class RedisService {
     roomId: string,
     userId: number,
     questionId: string,
-    answer: any
+    answer: Answer
   ) {
     const key = `exam:${roomId}:answers:${userId}:${questionId}`;
     await this.client.hset(key, 'data', JSON.stringify(answer));
@@ -90,13 +91,13 @@ export class RedisService {
     await this.client.expire(key, 30 * 24 * 60 * 60);
   }
 
-  async getAnswers(roomId: string, questionId?: string): Promise<any[]> {
+  async getAnswers(roomId: string, questionId?: string): Promise<Answer[]> {
     const pattern = questionId
       ? `exam:${roomId}:answers:*:${questionId}`
       : `exam:${roomId}:answers:*`;
     
     const keys = await this.client.keys(pattern);
-    const answers: any[] = [];
+    const answers: Answer[] = [];
 
     for (const key of keys) {
       const data = await this.client.hget(key, 'data');
@@ -119,10 +120,10 @@ export class RedisService {
     return answers;
   }
 
-  async getUserAnswers(roomId: string, userId: number): Promise<any[]> {
+  async getUserAnswers(roomId: string, userId: number): Promise<Answer[]> {
     const pattern = `exam:${roomId}:answers:${userId}:*`;
     const keys = await this.client.keys(pattern);
-    const answers: any[] = [];
+    const answers: Answer[] = [];
 
     for (const key of keys) {
       const data = await this.client.hget(key, 'data');