Ver Fonte

fix: questions_tem 表名 + 移除 question_qc_results 迁移

- 表名改为 questions_tem
- 不创建额外表,质检结果由命令输出不落库
- textbooks.is_deleted 存在时才过滤

Made-with: Cursor
yemeishu há 1 semana atrás
pai
commit
ca16b6ca02

+ 3 - 3
app/Console/Commands/RunQuestionQualityCheckCommand.php

@@ -10,14 +10,14 @@ use Illuminate\Support\Facades\Schema;
 class RunQuestionQualityCheckCommand extends Command
 {
     protected $signature = 'question:qc
-        {--table=question_tem : 待质检题目表名}
+        {--table=questions_tem : 待质检题目表名}
         {--kp= : 指定知识点,不传则按下学期题少 KP 筛选}
         {--limit=100 : 质检题目数量上限}
         {--textbook= : 教材 ID}
         {--semester=2 : 学期 1=上 2=下}
         {--dry-run : 仅输出筛选结果,不执行质检}';
 
-    protected $description = '题目自动质检:从 question_tem 按下学期题少 KP 筛选题目并执行校验';
+    protected $description = '题目自动质检:从 questions_tem 按下学期题少 KP 筛选题目并执行校验';
 
     public function handle(QuestionQualityCheckService $qcService): int
     {
@@ -102,7 +102,7 @@ class RunQuestionQualityCheckCommand extends Command
     }
 
     /**
-     * 将 question_tem 行映射为质检服务所需格式
+     * 将 questions_tem 行映射为质检服务所需格式
      */
     private function mapQuestionRow(array $row): array
     {

+ 7 - 54
app/Services/QuestionQualityCheckService.php

@@ -10,7 +10,7 @@ use Illuminate\Support\Facades\Schema;
  * 题目质检服务
  *
  * 校验规则:题干、答案、解析、选项、公式、PDF 呈现
- * 自动质检 + 人工质检结果分别记录到 question_qc_results
+ * 结果由命令输出,不落库(避免本地库覆盖)
  */
 class QuestionQualityCheckService
 {
@@ -27,7 +27,7 @@ class QuestionQualityCheckService
      * 对单道题目执行自动质检
      *
      * @param array $question 题目数据,需包含 stem, answer, solution, question_type, options
-     * @param int|null $questionTemId question_tem 表 ID
+     * @param int|null $questionTemId questions_tem 表 ID
      * @param int|null $questionId questions 表 ID
      * @return array ['passed' => bool, 'results' => array, 'errors' => array]
      */
@@ -108,10 +108,6 @@ class QuestionQualityCheckService
 
         $passed = empty($errors);
 
-        foreach ($results as $r) {
-            $this->saveQcResult($r, $questionTemId, $questionId, 'auto');
-        }
-
         return [
             'passed' => $passed,
             'results' => $results,
@@ -153,54 +149,8 @@ class QuestionQualityCheckService
         ];
     }
 
-    private function saveQcResult(array $r, ?int $questionTemId, ?int $questionId, string $source): void
-    {
-        if (!Schema::hasTable('question_qc_results')) {
-            return;
-        }
-        try {
-            DB::table('question_qc_results')->insert([
-                'question_tem_id' => $questionTemId,
-                'question_id' => $questionId,
-                'rule_code' => $r['rule_code'],
-                'rule_name' => $r['rule_name'] ?? null,
-                'passed' => $r['passed'],
-                'auto_result' => $r['auto_result'] ?? ($r['passed'] ? 'pass' : 'fail'),
-                'manual_result' => null,
-                'pdf_render_ok' => null,
-                'detail' => $r['detail'] ?? null,
-                'source' => $source,
-                'created_at' => now(),
-                'updated_at' => now(),
-            ]);
-        } catch (\Throwable $e) {
-            Log::warning('QuestionQualityCheckService: 保存质检结果失败', [
-                'rule_code' => $r['rule_code'],
-                'error' => $e->getMessage(),
-            ]);
-        }
-    }
-
-    /**
-     * 记录人工质检结果(更新已有自动质检记录)
-     */
-    public function recordManualResult(int $questionTemId, string $ruleCode, string $manualResult, ?bool $pdfRenderOk = null): void
-    {
-        if (!Schema::hasTable('question_qc_results')) {
-            return;
-        }
-        DB::table('question_qc_results')
-            ->where('question_tem_id', $questionTemId)
-            ->where('rule_code', $ruleCode)
-            ->update([
-                'manual_result' => $manualResult,
-                'pdf_render_ok' => $pdfRenderOk,
-                'updated_at' => now(),
-            ]);
-    }
-
     /**
-     * 获取下学期章节关联的、题少的 KP 列表(用于筛选 question_tem)
+     * 获取下学期章节关联的、题少的 KP 列表(用于筛选 questions_tem)
      *
      * @param int|null $textbookId 教材 ID,null 则取默认教材
      * @param int $semesterCode 学期 1=上 2=下
@@ -209,7 +159,10 @@ class QuestionQualityCheckService
      */
     public function getKpsWithFewQuestions(?int $textbookId = null, int $semesterCode = 2, int $limit = 50): array
     {
-        $textbooksQuery = DB::table('textbooks')->where('is_deleted', 0);
+        $textbooksQuery = DB::table('textbooks');
+        if (Schema::hasColumn('textbooks', 'is_deleted')) {
+            $textbooksQuery->where('is_deleted', 0);
+        }
         if ($textbookId) {
             $textbooksQuery->where('id', $textbookId);
         }

+ 0 - 40
database/migrations/2026_03_23_194507_create_question_qc_results_table.php

@@ -1,40 +0,0 @@
-<?php
-
-use Illuminate\Database\Migrations\Migration;
-use Illuminate\Database\Schema\Blueprint;
-use Illuminate\Support\Facades\Schema;
-
-return new class extends Migration
-{
-    /**
-     * Run the migrations.
-     */
-    public function up(): void
-    {
-        Schema::create('question_qc_results', function (Blueprint $table) {
-            $table->id();
-            $table->unsignedBigInteger('question_tem_id')->nullable()->comment('question_tem 表题目ID');
-            $table->unsignedBigInteger('question_id')->nullable()->comment('questions 表题目ID(入库后)');
-            $table->string('rule_code', 64)->comment('规则编码 STEM_EMPTY/ANSWER_EMPTY 等');
-            $table->string('rule_name', 128)->nullable()->comment('规则名称');
-            $table->boolean('passed')->default(false)->comment('是否通过');
-            $table->string('auto_result', 32)->nullable()->comment('自动质检结果 pass/fail/skip');
-            $table->string('manual_result', 32)->nullable()->comment('人工质检结果 pass/fail/skip');
-            $table->boolean('pdf_render_ok')->nullable()->comment('PDF 渲染是否正常');
-            $table->text('detail')->nullable()->comment('详情/错误信息');
-            $table->string('source', 32)->default('auto')->comment('来源 auto/manual');
-            $table->timestamps();
-
-            $table->index(['question_tem_id', 'rule_code']);
-            $table->index(['question_id', 'rule_code']);
-        });
-    }
-
-    /**
-     * Reverse the migrations.
-     */
-    public function down(): void
-    {
-        Schema::dropIfExists('question_qc_results');
-    }
-};

+ 6 - 6
docs/题库质检方案.md

@@ -2,7 +2,7 @@
 
 ## 一、背景
 
-### question_tem 表预期结构(与 questions 对齐)
+### questions_tem 表预期结构(与 questions 对齐)
 
 | 字段 | 说明 |
 |------|------|
@@ -14,7 +14,7 @@
 | options | 选项(JSON) |
 | kp_code | 知识点 |
 
-- 待入库题目在 `question_tem` 中,约 2 万道
+- 待入库题目在 `questions_tem` 中,约 2 万道
 - 需与 `questions` 正式表比对,确保不重复
 - 入库前**严格校验**,以学案/PDF 导出场景验证
 
@@ -38,8 +38,8 @@
 
 ### 2.3 结果记录
 
-- `question_qc_results`:自动质检 + 人工质检分别记录
-- 字段:question_id / question_tem_id、rule_code、passed、auto_result、manual_result、pdf_render_ok 等
+- 质检结果由命令输出,不落库(避免本地库覆盖导致表丢失)
+- 后续可接入 question_qc_results 等表做持久化
 
 ## 三、校验规则清单(可扩展)
 
@@ -58,7 +58,7 @@
 2. 通过 `textbook_chapter_knowledge_relation` 得到章节关联的 `kp_code`
 3. 统计 `questions` 中每个 kp_code 的题目数量
 4. **按题数升序**:优先选「题少的 KP」补充
-5. 从 `question_tem` 中筛选该 KP 的题目 → 质检 → 合格后入库
+5. 从 `questions_tem` 中筛选该 KP 的题目 → 质检 → 合格后入库
 
 ## 五、命令用法
 
@@ -79,7 +79,7 @@ php artisan question:qc --textbook=1 --semester=2 --limit=50
 ## 六、流程
 
 ```
-question_tem 选题(按下学期 KP 题少优先)
+questions_tem 选题(按下学期 KP 题少优先)
     → 自动质检(规则引擎)
     → 记录 auto_result
     → (可选)PDF 导出预演,检测渲染