|
|
@@ -107,6 +107,7 @@ class MistakeBookService
|
|
|
]);
|
|
|
|
|
|
// 合并知识点到已有记录中
|
|
|
+ $updates = ['updated_at' => now()];
|
|
|
if ($kpIds) {
|
|
|
$existingKpIds = $existingMistake->kp_ids ?? [];
|
|
|
$newKpIds = is_array($kpIds) ? $kpIds : [$kpIds];
|
|
|
@@ -115,9 +116,7 @@ class MistakeBookService
|
|
|
$mergedKpIds = array_values(array_unique(array_merge($existingKpIds, $newKpIds)));
|
|
|
|
|
|
// 更新记录(仅更新 kp_ids)
|
|
|
- $existingMistake->update([
|
|
|
- 'kp_ids' => $mergedKpIds,
|
|
|
- ]);
|
|
|
+ $updates['kp_ids'] = $mergedKpIds;
|
|
|
|
|
|
Log::info('错题记录知识点合并成功', [
|
|
|
'student_id' => $studentId,
|
|
|
@@ -129,6 +128,8 @@ class MistakeBookService
|
|
|
]);
|
|
|
}
|
|
|
|
|
|
+ $existingMistake->update($updates);
|
|
|
+
|
|
|
return [
|
|
|
'duplicate' => true,
|
|
|
'mistake_id' => $existingMistake->id,
|
|
|
@@ -164,6 +165,121 @@ class MistakeBookService
|
|
|
});
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * 批量新增错题(同一学生/卷子)
|
|
|
+ *
|
|
|
+ * @param array<int, array> $payloads
|
|
|
+ * @return array
|
|
|
+ */
|
|
|
+ public function createMistakesBatch(array $payloads): array
|
|
|
+ {
|
|
|
+ if (empty($payloads)) {
|
|
|
+ return ['created' => 0, 'duplicates' => 0, 'updated' => 0];
|
|
|
+ }
|
|
|
+
|
|
|
+ $studentId = $payloads[0]['student_id'] ?? null;
|
|
|
+ $paperId = $payloads[0]['paper_id'] ?? null;
|
|
|
+ $source = $payloads[0]['source'] ?? MistakeRecord::SOURCE_PRACTICE;
|
|
|
+
|
|
|
+ if (!$studentId) {
|
|
|
+ throw new \InvalidArgumentException('学生ID不能为空');
|
|
|
+ }
|
|
|
+
|
|
|
+ $questionIds = [];
|
|
|
+ foreach ($payloads as $payload) {
|
|
|
+ if (!empty($payload['question_id'])) {
|
|
|
+ $questionIds[] = $payload['question_id'];
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ $questionIds = array_values(array_unique($questionIds));
|
|
|
+
|
|
|
+ return \DB::transaction(function () use ($payloads, $studentId, $paperId, $source, $questionIds) {
|
|
|
+ $existingMap = [];
|
|
|
+ if (!empty($questionIds)) {
|
|
|
+ $existing = MistakeRecord::where('student_id', $studentId)
|
|
|
+ ->where('source', $source)
|
|
|
+ ->when($paperId, fn ($q) => $q->where('paper_id', $paperId))
|
|
|
+ ->whereIn('question_id', $questionIds)
|
|
|
+ ->get();
|
|
|
+
|
|
|
+ foreach ($existing as $item) {
|
|
|
+ $existingMap[$item->question_id] = $item;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ $toInsert = [];
|
|
|
+ $created = 0;
|
|
|
+ $duplicates = 0;
|
|
|
+ $updated = 0;
|
|
|
+
|
|
|
+ foreach ($payloads as $payload) {
|
|
|
+ $questionId = $payload['question_id'] ?? null;
|
|
|
+ if (!$questionId) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ $kpIds = $payload['kp_ids'] ?? null;
|
|
|
+ $kpIds = is_array($kpIds) ? $kpIds : ($kpIds ? [$kpIds] : null);
|
|
|
+
|
|
|
+ if (isset($existingMap[$questionId])) {
|
|
|
+ $duplicates++;
|
|
|
+ $updates = ['updated_at' => now()];
|
|
|
+ if ($kpIds) {
|
|
|
+ $existingKpIds = $existingMap[$questionId]->kp_ids ?? [];
|
|
|
+ $merged = array_values(array_unique(array_merge($existingKpIds, $kpIds)));
|
|
|
+ if ($merged !== $existingKpIds) {
|
|
|
+ $updates['kp_ids'] = $merged;
|
|
|
+ $updated++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ $existingMap[$questionId]->update($updates);
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ $toInsert[] = [
|
|
|
+ 'student_id' => $studentId,
|
|
|
+ 'question_id' => $questionId,
|
|
|
+ 'paper_id' => $payload['paper_id'] ?? null,
|
|
|
+ 'student_answer' => $payload['my_answer'] ?? null,
|
|
|
+ 'correct_answer' => $payload['correct_answer'] ?? null,
|
|
|
+ 'question_text' => $payload['question_text'] ?? null,
|
|
|
+ 'knowledge_point' => $payload['knowledge_point'] ?? null,
|
|
|
+ 'explanation' => $payload['explanation'] ?? null,
|
|
|
+ 'kp_ids' => $kpIds,
|
|
|
+ 'source' => $payload['source'] ?? MistakeRecord::SOURCE_PRACTICE,
|
|
|
+ 'created_at' => $payload['happened_at'] ?? now(),
|
|
|
+ 'review_status' => MistakeRecord::REVIEW_STATUS_PENDING,
|
|
|
+ 'review_count' => 0,
|
|
|
+ ];
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!empty($toInsert)) {
|
|
|
+ // MistakeRecord::insert 不会触发模型事件,但速度更快
|
|
|
+ MistakeRecord::insert($toInsert);
|
|
|
+ $created = count($toInsert);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 统一刷新本次题目的 updated_at(无论是否合并)
|
|
|
+ if (!empty($questionIds)) {
|
|
|
+ \DB::table('mistake_records')
|
|
|
+ ->where('student_id', $studentId)
|
|
|
+ ->where('source', $source)
|
|
|
+ ->when($paperId, fn ($q) => $q->where('paper_id', $paperId))
|
|
|
+ ->whereIn('question_id', $questionIds)
|
|
|
+ ->update(['updated_at' => now()]);
|
|
|
+ }
|
|
|
+
|
|
|
+ $this->clearCache($studentId);
|
|
|
+
|
|
|
+ return [
|
|
|
+ 'created' => $created,
|
|
|
+ 'duplicates' => $duplicates,
|
|
|
+ 'updated' => $updated,
|
|
|
+ ];
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
* 获取错题列表
|
|
|
*/
|