|
|
@@ -41,6 +41,15 @@ class ExamAnswerAnalysisService
|
|
|
*/
|
|
|
public function analyzeExamAnswers(array $examData): array
|
|
|
{
|
|
|
+ $flowStart = microtime(true);
|
|
|
+ $lastMark = $flowStart;
|
|
|
+ $timings = [];
|
|
|
+ $mark = static function (string $label) use (&$lastMark, &$timings): void {
|
|
|
+ $now = microtime(true);
|
|
|
+ $timings[$label] = round(($now - $lastMark) * 1000, 1);
|
|
|
+ $lastMark = $now;
|
|
|
+ };
|
|
|
+
|
|
|
Log::info('开始分析考试答题', [
|
|
|
'paper_id' => $examData['paper_id'] ?? 'unknown',
|
|
|
'student_id' => $examData['student_id'] ?? 'unknown',
|
|
|
@@ -53,20 +62,25 @@ class ExamAnswerAnalysisService
|
|
|
|
|
|
// 0. 自动计算分数并补充未提交的题目
|
|
|
$questions = $this->autoCalculateScores($questions, $paperId);
|
|
|
+ $mark('auto_calculate_scores_ms');
|
|
|
|
|
|
// 更新 examData 中的 questions(包含补充的题目)
|
|
|
$examData['questions'] = $questions;
|
|
|
|
|
|
// 【公司要求】1. 获取学案基准难度(取自学案的difficulty_category)
|
|
|
$examBaseDifficulty = $this->getExamBaseDifficulty($examData['paper_id'] ?? '');
|
|
|
+ $mark('get_exam_base_difficulty_ms');
|
|
|
|
|
|
// 2. 获取题目知识点映射(批量查询,避免N+1)
|
|
|
$questionMappings = $this->getQuestionKnowledgeMappings($questions);
|
|
|
+ $mark('get_question_knowledge_mappings_ms');
|
|
|
|
|
|
// 3. 保存答题记录到数据库(复用已查询的知识点映射)
|
|
|
$recordChangeState = $this->saveExamAnswerRecords($examData, $questionMappings);
|
|
|
+ $mark('save_exam_answer_records_ms');
|
|
|
// 同步回写 paper_questions 判分结果,保证 PDF 与分析链路一致
|
|
|
$this->syncPaperQuestionGrading($examData);
|
|
|
+ $mark('sync_paper_question_grading_ms');
|
|
|
$hasAnswerChanged = (bool) ($recordChangeState['steps_changed'] ?? false)
|
|
|
|| (bool) ($recordChangeState['questions_changed'] ?? false);
|
|
|
if ($hasAnswerChanged) {
|
|
|
@@ -107,29 +121,45 @@ class ExamAnswerAnalysisService
|
|
|
'paper_id' => $examData['paper_id'],
|
|
|
'analysis_id' => $existing->id,
|
|
|
]);
|
|
|
+ $mark('reuse_existing_analysis_ms');
|
|
|
+ $timings['total_ms'] = round((microtime(true) - $flowStart) * 1000, 1);
|
|
|
+ Log::warning('ExamAnswerAnalysisService: 答题分析耗时明细', [
|
|
|
+ 'paper_id' => $paperId,
|
|
|
+ 'student_id' => $studentId,
|
|
|
+ 'question_count' => count($questions),
|
|
|
+ 'reused_existing_analysis' => true,
|
|
|
+ 'timing' => $timings,
|
|
|
+ ]);
|
|
|
|
|
|
return $existingData;
|
|
|
}
|
|
|
}
|
|
|
+ $mark('reuse_check_ms');
|
|
|
|
|
|
// 【公司要求】4. 计算每个知识点的加权掌握度(传入学案基准难度)
|
|
|
// 核心算法:难度映射 → 权重计算 → 数值更新(newMastery = oldMastery + change)
|
|
|
$knowledgeMasteryVector = $this->calculateKnowledgeMasteryVector($questions, $questionMappings, $examBaseDifficulty, $studentId, $paperId);
|
|
|
+ $mark('calculate_knowledge_mastery_vector_ms');
|
|
|
|
|
|
// 【公司要求】5. 更新学生掌握度(包含多级父节点掌握度计算)
|
|
|
$updatedMastery = $this->updateStudentMastery($studentId, $knowledgeMasteryVector);
|
|
|
+ $mark('update_student_mastery_ms');
|
|
|
|
|
|
// 5. 生成题目维度分析
|
|
|
$questionAnalysis = $this->analyzeQuestions($questions, $questionMappings);
|
|
|
+ $mark('analyze_questions_ms');
|
|
|
|
|
|
// 6. 生成知识点维度分析
|
|
|
$knowledgePointAnalysis = $this->analyzeKnowledgePoints($knowledgeMasteryVector, $questionMappings);
|
|
|
+ $mark('analyze_knowledge_points_ms');
|
|
|
|
|
|
// 7. 生成整体掌握度总结
|
|
|
$overallSummary = $this->generateOverallSummary($updatedMastery);
|
|
|
+ $mark('generate_overall_summary_ms');
|
|
|
|
|
|
// 8. 生成智能出卷推荐依据
|
|
|
$smartQuizRecommendation = $this->generateSmartQuizRecommendation($updatedMastery);
|
|
|
+ $mark('generate_smart_quiz_recommendation_ms');
|
|
|
|
|
|
// 9. 保存分析结果
|
|
|
$analysisResult = [
|
|
|
@@ -146,6 +176,7 @@ class ExamAnswerAnalysisService
|
|
|
// 【新增】创建掌握度快照,并返回 current_mastery(仅kp->mastery)
|
|
|
$snapshotInfo = $this->createMasterySnapshot($studentId, $paperId, $analysisResult);
|
|
|
$analysisResult['current_mastery'] = $snapshotInfo['current_mastery'] ?? [];
|
|
|
+ $mark('create_mastery_snapshot_ms');
|
|
|
|
|
|
$this->saveAnalysisResult(
|
|
|
$studentId,
|
|
|
@@ -153,12 +184,23 @@ class ExamAnswerAnalysisService
|
|
|
$analysisResult,
|
|
|
$hasAnswerChanged ? $questions : []
|
|
|
);
|
|
|
+ $mark('save_analysis_result_ms');
|
|
|
|
|
|
Log::info('考试答题分析完成', [
|
|
|
'student_id' => $studentId,
|
|
|
'paper_id' => $examData['paper_id'],
|
|
|
'analyzed_knowledge_points' => count($knowledgeMasteryVector),
|
|
|
]);
|
|
|
+ $timings['total_ms'] = round((microtime(true) - $flowStart) * 1000, 1);
|
|
|
+ Log::warning('ExamAnswerAnalysisService: 答题分析耗时明细', [
|
|
|
+ 'paper_id' => $paperId,
|
|
|
+ 'student_id' => $studentId,
|
|
|
+ 'question_count' => count($questions),
|
|
|
+ 'submitted_question_count' => count($examData['questions'] ?? []),
|
|
|
+ 'knowledge_point_count' => count($knowledgeMasteryVector),
|
|
|
+ 'has_answer_changed' => $hasAnswerChanged,
|
|
|
+ 'timing' => $timings,
|
|
|
+ ]);
|
|
|
|
|
|
return $analysisResult;
|
|
|
}
|