|
@@ -308,8 +308,9 @@ class DiagnosticChapterService
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
* 获取章节摸底目标章节
|
|
* 获取章节摸底目标章节
|
|
|
- * - 传入 targetChapterIds: 仅在指定章节范围内按顺序找“有题知识点”章节(允许重复摸底)
|
|
|
|
|
- * - 未传 targetChapterIds: 保持原逻辑,找第一个未摸底章节
|
|
|
|
|
|
|
+ * - 传入 targetChapterIds: 先在指定章节内按顺序找第一个未摸底章节;
|
|
|
|
|
+ * 若指定章节都已摸底,则在该章节所属教材内继续按顺序找未摸底章节。
|
|
|
|
|
+ * - 未传 targetChapterIds: 保持原逻辑,找教材内第一个未摸底章节。
|
|
|
*/
|
|
*/
|
|
|
public function getFirstUndiagnosedChapter(int $textbookId, int $studentId, ?array $targetChapterIds = null): ?array
|
|
public function getFirstUndiagnosedChapter(int $textbookId, int $studentId, ?array $targetChapterIds = null): ?array
|
|
|
{
|
|
{
|
|
@@ -317,8 +318,7 @@ class DiagnosticChapterService
|
|
|
? array_values(array_unique(array_filter(array_map('intval', $targetChapterIds), fn ($id) => $id > 0)))
|
|
? array_values(array_unique(array_filter(array_map('intval', $targetChapterIds), fn ($id) => $id > 0)))
|
|
|
: [];
|
|
: [];
|
|
|
|
|
|
|
|
- // 只要传了 chapter_id_list(非空),就以传入参数为准;
|
|
|
|
|
- // 仅当未传或为空时,才走教材默认章节逻辑。
|
|
|
|
|
|
|
+ // 指定章节摸底流程:先在传入列表找未摸底章节,若都摸底则扩展到同教材继续找。
|
|
|
if (!empty($targetChapterIds)) {
|
|
if (!empty($targetChapterIds)) {
|
|
|
// 兜底:允许传入 section/subsection,自动向上映射到 chapter
|
|
// 兜底:允许传入 section/subsection,自动向上映射到 chapter
|
|
|
$targetChapterIds = $this->normalizeToChapterIds($targetChapterIds);
|
|
$targetChapterIds = $this->normalizeToChapterIds($targetChapterIds);
|
|
@@ -335,14 +335,21 @@ class DiagnosticChapterService
|
|
|
$chapterMap = TextbookCatalog::query()
|
|
$chapterMap = TextbookCatalog::query()
|
|
|
->whereIn('id', $targetChapterIds)
|
|
->whereIn('id', $targetChapterIds)
|
|
|
->where('node_type', 'chapter')
|
|
->where('node_type', 'chapter')
|
|
|
- ->get()
|
|
|
|
|
|
|
+ ->get(['id', 'textbook_id', 'title', 'parent_id', 'node_type', 'sort_order', 'display_no'])
|
|
|
->keyBy('id');
|
|
->keyBy('id');
|
|
|
|
|
|
|
|
|
|
+ $orderedChapters = [];
|
|
|
foreach ($targetChapterIds as $chapterId) {
|
|
foreach ($targetChapterIds as $chapterId) {
|
|
|
$chapter = $chapterMap->get($chapterId);
|
|
$chapter = $chapterMap->get($chapterId);
|
|
|
if (!$chapter) {
|
|
if (!$chapter) {
|
|
|
continue;
|
|
continue;
|
|
|
}
|
|
}
|
|
|
|
|
+ $orderedChapters[] = $chapter;
|
|
|
|
|
+
|
|
|
|
|
+ // 指定列表优先找“未摸底”章节
|
|
|
|
|
+ if ($this->hasChapterDiagnostic($studentId, (int) $chapter->id)) {
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
$chapterData = $this->getChapterKnowledgePointsSimple($chapter->id);
|
|
$chapterData = $this->getChapterKnowledgePointsSimple($chapter->id);
|
|
|
$kpCodesWithQuestions = $this->filterKpCodesWithQuestions($chapterData['kp_codes']);
|
|
$kpCodesWithQuestions = $this->filterKpCodesWithQuestions($chapterData['kp_codes']);
|
|
@@ -351,25 +358,71 @@ class DiagnosticChapterService
|
|
|
continue;
|
|
continue;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- Log::info('DiagnosticChapterService: 指定章节摸底命中章节(允许重复)', [
|
|
|
|
|
- 'textbook_id' => $textbookId,
|
|
|
|
|
|
|
+ Log::info('DiagnosticChapterService: 指定章节摸底命中未摸底章节', [
|
|
|
|
|
+ 'textbook_id' => $chapter->textbook_id,
|
|
|
'student_id' => $studentId,
|
|
'student_id' => $studentId,
|
|
|
'target_chapter_ids' => $targetChapterIds,
|
|
'target_chapter_ids' => $targetChapterIds,
|
|
|
'chapter_id' => $chapter->id,
|
|
'chapter_id' => $chapter->id,
|
|
|
- 'chapter_name' => $chapter->name ?? '',
|
|
|
|
|
|
|
+ 'chapter_name' => $chapter->name ?? $chapter->title ?? '',
|
|
|
'kp_count' => count($kpCodesWithQuestions),
|
|
'kp_count' => count($kpCodesWithQuestions),
|
|
|
]);
|
|
]);
|
|
|
|
|
|
|
|
return [
|
|
return [
|
|
|
'chapter_id' => $chapter->id,
|
|
'chapter_id' => $chapter->id,
|
|
|
- 'chapter_name' => $chapter->name ?? '',
|
|
|
|
|
|
|
+ 'chapter_name' => $chapter->name ?? $chapter->title ?? '',
|
|
|
'section_ids' => $chapterData['section_ids'],
|
|
'section_ids' => $chapterData['section_ids'],
|
|
|
'kp_codes' => $kpCodesWithQuestions,
|
|
'kp_codes' => $kpCodesWithQuestions,
|
|
|
];
|
|
];
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- Log::warning('DiagnosticChapterService: 指定章节均无可用题目知识点', [
|
|
|
|
|
- 'textbook_id' => $textbookId,
|
|
|
|
|
|
|
+ if (empty($orderedChapters)) {
|
|
|
|
|
+ Log::warning('DiagnosticChapterService: 指定章节未找到有效chapter节点', [
|
|
|
|
|
+ 'student_id' => $studentId,
|
|
|
|
|
+ 'target_chapter_ids' => $targetChapterIds,
|
|
|
|
|
+ ]);
|
|
|
|
|
+ return null;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 指定章节都已摸底:在同教材内继续按顺序找未摸底章节
|
|
|
|
|
+ $anchorTextbookId = (int) ($orderedChapters[0]->textbook_id ?? $textbookId);
|
|
|
|
|
+ $chaptersInTextbook = TextbookCatalog::query()
|
|
|
|
|
+ ->where('textbook_id', $anchorTextbookId)
|
|
|
|
|
+ ->where('node_type', 'chapter')
|
|
|
|
|
+ ->orderBy('sort_order')
|
|
|
|
|
+ ->orderBy('display_no')
|
|
|
|
|
+ ->orderBy('id')
|
|
|
|
|
+ ->get();
|
|
|
|
|
+
|
|
|
|
|
+ foreach ($chaptersInTextbook as $chapter) {
|
|
|
|
|
+ if ($this->hasChapterDiagnostic($studentId, (int) $chapter->id)) {
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ $chapterData = $this->getChapterKnowledgePointsSimple($chapter->id);
|
|
|
|
|
+ $kpCodesWithQuestions = $this->filterKpCodesWithQuestions($chapterData['kp_codes']);
|
|
|
|
|
+ if (empty($kpCodesWithQuestions)) {
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ Log::info('DiagnosticChapterService: 指定章节已摸底完,切换同教材后续未摸底章节', [
|
|
|
|
|
+ 'anchor_textbook_id' => $anchorTextbookId,
|
|
|
|
|
+ 'student_id' => $studentId,
|
|
|
|
|
+ 'target_chapter_ids' => $targetChapterIds,
|
|
|
|
|
+ 'chapter_id' => $chapter->id,
|
|
|
|
|
+ 'chapter_name' => $chapter->name ?? $chapter->title ?? '',
|
|
|
|
|
+ 'kp_count' => count($kpCodesWithQuestions),
|
|
|
|
|
+ ]);
|
|
|
|
|
+
|
|
|
|
|
+ return [
|
|
|
|
|
+ 'chapter_id' => $chapter->id,
|
|
|
|
|
+ 'chapter_name' => $chapter->name ?? $chapter->title ?? '',
|
|
|
|
|
+ 'section_ids' => $chapterData['section_ids'],
|
|
|
|
|
+ 'kp_codes' => $kpCodesWithQuestions,
|
|
|
|
|
+ ];
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ Log::warning('DiagnosticChapterService: 指定章节及同教材章节均无可用未摸底章节', [
|
|
|
|
|
+ 'textbook_id' => $anchorTextbookId,
|
|
|
'student_id' => $studentId,
|
|
'student_id' => $studentId,
|
|
|
'target_chapter_ids' => $targetChapterIds,
|
|
'target_chapter_ids' => $targetChapterIds,
|
|
|
]);
|
|
]);
|