Переглянути джерело

feat: direct_mastery_level(直接学习掌握度),用于判断达标时优先使用

gwd 1 тиждень тому
батько
коміт
a09f8c4cfc

+ 41 - 12
app/Models/StudentKnowledgeMastery.php

@@ -16,6 +16,7 @@ class StudentKnowledgeMastery extends Model
         'student_id',
         'kp_code',
         'mastery_level',
+        'direct_mastery_level', // 直接学习掌握度(答题计算),判断达标时优先使用
         'confidence_level',
         'total_attempts',
         'correct_attempts',
@@ -41,6 +42,7 @@ class StudentKnowledgeMastery extends Model
 
     protected $casts = [
         'mastery_level' => 'decimal:4',
+        'direct_mastery_level' => 'decimal:4',
         'confidence_level' => 'decimal:4',
         'mastery_change' => 'decimal:4',
         'avg_time_seconds' => 'decimal:2',
@@ -119,14 +121,23 @@ class StudentKnowledgeMastery extends Model
         }
 
         // 使用 DB::table 避免 Eloquent accessor 把数字转成文字标签
-        $levels = \Illuminate\Support\Facades\DB::table('student_knowledge_mastery')
+        // 【新增】同时获取 direct_mastery_level,判断时优先使用
+        $records = \Illuminate\Support\Facades\DB::table('student_knowledge_mastery')
             ->where('student_id', $studentId)
             ->whereIn('kp_code', $kpCodes)
-            ->pluck('mastery_level', 'kp_code')
-            ->toArray();
+            ->get(['kp_code', 'mastery_level', 'direct_mastery_level'])
+            ->keyBy('kp_code');
 
         foreach ($kpCodes as $kpCode) {
-            $level = isset($levels[$kpCode]) ? (float) $levels[$kpCode] : 0.0;
+            $record = $records->get($kpCode);
+            // 优先使用 direct_mastery_level(直接学习掌握度)
+            if ($record) {
+                $level = $record->direct_mastery_level !== null
+                    ? (float) $record->direct_mastery_level
+                    : (float) $record->mastery_level;
+            } else {
+                $level = 0.0;
+            }
             if ($level < $threshold) {
                 return false;
             }
@@ -151,11 +162,12 @@ class StudentKnowledgeMastery extends Model
         }
 
         // 获取掌握度(使用 DB::table 避免 Eloquent accessor 把数字转成文字标签)
-        $levels = \Illuminate\Support\Facades\DB::table('student_knowledge_mastery')
+        // 【新增】同时获取 direct_mastery_level,判断时优先使用
+        $records = \Illuminate\Support\Facades\DB::table('student_knowledge_mastery')
             ->where('student_id', $studentId)
             ->whereIn('kp_code', $kpCodes)
-            ->pluck('mastery_level', 'kp_code')
-            ->toArray();
+            ->get(['kp_code', 'mastery_level', 'direct_mastery_level'])
+            ->keyBy('kp_code');
 
         // 获取有题目的知识点
         $kpCodesWithQuestions = \App\Models\Question::query()
@@ -174,7 +186,15 @@ class StudentKnowledgeMastery extends Model
 
             $hasAnyKpWithQuestions = true;
 
-            $level = isset($levels[$kpCode]) ? (float) $levels[$kpCode] : 0.0;
+            // 优先使用 direct_mastery_level(直接学习掌握度)
+            $record = $records->get($kpCode);
+            if ($record) {
+                $level = $record->direct_mastery_level !== null
+                    ? (float) $record->direct_mastery_level
+                    : (float) $record->mastery_level;
+            } else {
+                $level = 0.0;
+            }
             if ($level < $threshold) {
                 return false;
             }
@@ -199,11 +219,12 @@ class StudentKnowledgeMastery extends Model
         }
 
         // 获取掌握度(使用 DB::table 避免 Eloquent accessor 把数字转成文字标签)
-        $levels = \Illuminate\Support\Facades\DB::table('student_knowledge_mastery')
+        // 【新增】同时获取 direct_mastery_level,判断时优先使用
+        $records = \Illuminate\Support\Facades\DB::table('student_knowledge_mastery')
             ->where('student_id', $studentId)
             ->whereIn('kp_code', $kpCodes)
-            ->pluck('mastery_level', 'kp_code')
-            ->toArray();
+            ->get(['kp_code', 'mastery_level', 'direct_mastery_level'])
+            ->keyBy('kp_code');
 
         // 获取有题目的知识点
         $kpCodesWithQuestions = \App\Models\Question::query()
@@ -218,7 +239,15 @@ class StudentKnowledgeMastery extends Model
                 continue;
             }
 
-            $level = isset($levels[$kpCode]) ? (float) $levels[$kpCode] : 0.0;
+            // 优先使用 direct_mastery_level(直接学习掌握度)
+            $record = $records->get($kpCode);
+            if ($record) {
+                $level = $record->direct_mastery_level !== null
+                    ? (float) $record->direct_mastery_level
+                    : (float) $record->mastery_level;
+            } else {
+                $level = 0.0;
+            }
             if ($level < $threshold) {
                 return $kpCode;
             }

+ 16 - 3
app/Services/DiagnosticChapterService.php

@@ -503,11 +503,23 @@ class DiagnosticChapterService
         }
 
         // 获取掌握度(使用 DB::table 避免 Eloquent accessor 把数字转成文字标签)
-        $levels = \Illuminate\Support\Facades\DB::table('student_knowledge_mastery')
+        // 【新增】同时获取 direct_mastery_level 和 mastery_level,判断时优先使用 direct_mastery_level
+        $masteryRecords = \Illuminate\Support\Facades\DB::table('student_knowledge_mastery')
             ->where('student_id', $studentId)
             ->whereIn('kp_code', $kpCodes)
-            ->pluck('mastery_level', 'kp_code')
-            ->toArray();
+            ->get(['kp_code', 'mastery_level', 'direct_mastery_level'])
+            ->keyBy('kp_code');
+
+        // 构建有效掌握度映射:优先使用 direct_mastery_level,其次使用 mastery_level
+        $levels = [];
+        foreach ($masteryRecords as $kpCode => $record) {
+            // 优先使用 direct_mastery_level(直接学习掌握度)
+            if ($record->direct_mastery_level !== null) {
+                $levels[$kpCode] = (float) $record->direct_mastery_level;
+            } else {
+                $levels[$kpCode] = (float) $record->mastery_level;
+            }
+        }
 
         // 【调试】记录查询到的掌握度
         Log::info('DiagnosticChapterService: 查询掌握度结果', [
@@ -515,6 +527,7 @@ class DiagnosticChapterService
             'student_id_type' => gettype($studentId),
             'input_kp_codes' => $kpCodes,
             'found_levels' => $levels,
+            'raw_records' => $masteryRecords->toArray(),
         ]);
 
         // 获取每个知识点的题目数量

+ 4 - 16
app/Services/MasteryCalculator.php

@@ -158,11 +158,13 @@ class MasteryCalculator
         $newMastery = max(0.0, min(1.0, $newMastery));
 
         // 【公司要求】保存到数据库(只保存核心掌握度数据)
+        // 【新增】同时更新 direct_mastery_level(直接学习掌握度),用于判断达标时优先使用
         DB::table('student_knowledge_mastery')
             ->updateOrInsert(
                 ['student_id' => $studentId, 'kp_code' => $kpCode],
                 [
                     'mastery_level' => $newMastery,
+                    'direct_mastery_level' => $newMastery, // 直接学习掌握度,不会被子节点聚合覆盖
                     'confidence_level' => 0.0, // 不再计算置信度
                     'total_attempts' => ($historyMastery->total_attempts ?? 0) + $totalAttempts,
                     'correct_attempts' => ($historyMastery->correct_attempts ?? 0) + $correctAttempts,
@@ -328,23 +330,9 @@ class MasteryCalculator
         $results = [];
 
         foreach ($kpCodes as $kpCode) {
+            // calculateMasteryLevel 内部的 calculateMasteryWithExamDifficulty 已经会保存到数据库
+            // 包括 direct_mastery_level,所以这里不需要再次保存
             $masteryData = $this->calculateMasteryLevel($studentId, $kpCode);
-
-            // 保存到数据库
-            DB::table('student_knowledge_mastery')
-                ->updateOrInsert(
-                    ['student_id' => $studentId, 'kp_code' => $kpCode],
-                    [
-                        'mastery_level' => $masteryData['mastery'],
-                        'confidence_level' => $masteryData['confidence'],
-                        'total_attempts' => $masteryData['total_attempts'],
-                        'correct_attempts' => $masteryData['correct_attempts'],
-                        'mastery_trend' => $masteryData['trend'],
-                        'last_mastery_update' => now(),
-                        'updated_at' => now(),
-                    ]
-                );
-
             $results[$kpCode] = $masteryData;
         }