|
|
@@ -0,0 +1,165 @@
|
|
|
+<?php
|
|
|
+
|
|
|
+namespace App\Services;
|
|
|
+
|
|
|
+use Illuminate\Support\Facades\Log;
|
|
|
+use App\Models\KnowledgePoint;
|
|
|
+use App\Models\StudentKnowledgeMastery;
|
|
|
+use App\Models\TextbookCatalog;
|
|
|
+use App\Models\TextbookChapterKnowledgeRelation;
|
|
|
+
|
|
|
+class DiagnosticChapterService
|
|
|
+{
|
|
|
+
|
|
|
+ public function getInitialChapterKnowledgePoints(int $textbookId): array
|
|
|
+ {
|
|
|
+ $chapter = TextbookCatalog::query()
|
|
|
+ ->where('textbook_id', $textbookId)
|
|
|
+ ->where('node_type', 'chapter')
|
|
|
+ ->orderBy('display_no')
|
|
|
+ ->orderBy('sort_order')
|
|
|
+ ->orderBy('id')
|
|
|
+ ->first();
|
|
|
+
|
|
|
+ if (!$chapter) {
|
|
|
+ Log::warning('DiagnosticChapterService: 未找到章节节点', [
|
|
|
+ 'textbook_id' => $textbookId,
|
|
|
+ ]);
|
|
|
+ return [];
|
|
|
+ }
|
|
|
+
|
|
|
+ $sectionIds = TextbookCatalog::query()
|
|
|
+ ->where('parent_id', $chapter->id)
|
|
|
+ ->where('node_type', 'section')
|
|
|
+ ->orderBy('display_no')
|
|
|
+ ->orderBy('sort_order')
|
|
|
+ ->orderBy('id')
|
|
|
+ ->pluck('id')
|
|
|
+ ->toArray();
|
|
|
+
|
|
|
+ if (empty($sectionIds)) {
|
|
|
+ Log::warning('DiagnosticChapterService: 章节下未找到section节点', [
|
|
|
+ 'textbook_id' => $textbookId,
|
|
|
+ 'chapter_id' => $chapter->id,
|
|
|
+ ]);
|
|
|
+ return [];
|
|
|
+ }
|
|
|
+
|
|
|
+ $kpCodes = TextbookChapterKnowledgeRelation::query()
|
|
|
+ ->whereIn('catalog_chapter_id', $sectionIds)
|
|
|
+ ->pluck('kp_code')
|
|
|
+ ->filter()
|
|
|
+ ->unique()
|
|
|
+ ->values()
|
|
|
+ ->toArray();
|
|
|
+
|
|
|
+ $kpCodes = $this->expandWithChildKnowledgePoints($kpCodes);
|
|
|
+
|
|
|
+ Log::info('DiagnosticChapterService: 获取首章知识点', [
|
|
|
+ 'textbook_id' => $textbookId,
|
|
|
+ 'chapter_id' => $chapter->id,
|
|
|
+ 'section_count' => count($sectionIds),
|
|
|
+ 'kp_count' => count($kpCodes),
|
|
|
+ ]);
|
|
|
+
|
|
|
+ return [
|
|
|
+ 'chapter_id' => $chapter->id,
|
|
|
+ 'section_ids' => $sectionIds,
|
|
|
+ 'kp_codes' => $kpCodes,
|
|
|
+ ];
|
|
|
+ }
|
|
|
+
|
|
|
+ public function getFirstUnmasteredChapterKnowledgePoints(int $textbookId, int $studentId, float $threshold = 0.9): array
|
|
|
+ {
|
|
|
+ $chapters = TextbookCatalog::query()
|
|
|
+ ->where('textbook_id', $textbookId)
|
|
|
+ ->where('node_type', 'chapter')
|
|
|
+ ->orderBy('display_no')
|
|
|
+ ->orderBy('sort_order')
|
|
|
+ ->orderBy('id')
|
|
|
+ ->get();
|
|
|
+
|
|
|
+ if ($chapters->isEmpty()) {
|
|
|
+ Log::warning('DiagnosticChapterService: 未找到章节节点', [
|
|
|
+ 'textbook_id' => $textbookId,
|
|
|
+ ]);
|
|
|
+ return [];
|
|
|
+ }
|
|
|
+
|
|
|
+ foreach ($chapters as $chapter) {
|
|
|
+ $sectionIds = TextbookCatalog::query()
|
|
|
+ ->where('parent_id', $chapter->id)
|
|
|
+ ->where('node_type', 'section')
|
|
|
+ ->orderBy('display_no')
|
|
|
+ ->orderBy('sort_order')
|
|
|
+ ->orderBy('id')
|
|
|
+ ->pluck('id')
|
|
|
+ ->toArray();
|
|
|
+
|
|
|
+ if (empty($sectionIds)) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ $kpCodes = TextbookChapterKnowledgeRelation::query()
|
|
|
+ ->whereIn('catalog_chapter_id', $sectionIds)
|
|
|
+ ->pluck('kp_code')
|
|
|
+ ->filter()
|
|
|
+ ->unique()
|
|
|
+ ->values()
|
|
|
+ ->toArray();
|
|
|
+
|
|
|
+ $kpCodes = $this->expandWithChildKnowledgePoints($kpCodes);
|
|
|
+
|
|
|
+ if (empty($kpCodes)) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ $allMastered = StudentKnowledgeMastery::allAtLeast($studentId, $kpCodes, $threshold);
|
|
|
+
|
|
|
+ Log::info('DiagnosticChapterService: 章节掌握度评估', [
|
|
|
+ 'student_id' => $studentId,
|
|
|
+ 'textbook_id' => $textbookId,
|
|
|
+ 'chapter_id' => $chapter->id,
|
|
|
+ 'section_count' => count($sectionIds),
|
|
|
+ 'kp_count' => count($kpCodes),
|
|
|
+ 'all_mastered' => $allMastered,
|
|
|
+ 'threshold' => $threshold,
|
|
|
+ ]);
|
|
|
+
|
|
|
+ if (!$allMastered) {
|
|
|
+ return [
|
|
|
+ 'chapter_id' => $chapter->id,
|
|
|
+ 'section_ids' => $sectionIds,
|
|
|
+ 'kp_codes' => $kpCodes,
|
|
|
+ 'all_mastered' => $allMastered,
|
|
|
+ ];
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ Log::info('DiagnosticChapterService: 所有章节均达到掌握度阈值', [
|
|
|
+ 'student_id' => $studentId,
|
|
|
+ 'textbook_id' => $textbookId,
|
|
|
+ 'threshold' => $threshold,
|
|
|
+ ]);
|
|
|
+
|
|
|
+ return [];
|
|
|
+ }
|
|
|
+
|
|
|
+ private function expandWithChildKnowledgePoints(array $kpCodes): array
|
|
|
+ {
|
|
|
+ if (empty($kpCodes)) {
|
|
|
+ return [];
|
|
|
+ }
|
|
|
+
|
|
|
+ $baseCodes = collect($kpCodes)->filter()->unique()->values()->all();
|
|
|
+ $children = KnowledgePoint::query()
|
|
|
+ ->whereIn('parent_kp_code', $baseCodes)
|
|
|
+ ->pluck('kp_code')
|
|
|
+ ->filter()
|
|
|
+ ->unique()
|
|
|
+ ->values()
|
|
|
+ ->toArray();
|
|
|
+
|
|
|
+ return array_values(array_unique(array_merge($baseCodes, $children)));
|
|
|
+ }
|
|
|
+}
|