|
@@ -17,12 +17,14 @@ class BackfillExamAnalysisResultsCommand extends Command
|
|
|
private const ACTION_ANALYSIS = 'analysis';
|
|
private const ACTION_ANALYSIS = 'analysis';
|
|
|
private const ACTION_PDF_ONLY = 'pdf_only';
|
|
private const ACTION_PDF_ONLY = 'pdf_only';
|
|
|
private const ACTION_SYNC_PDF_URL = 'sync_pdf_url';
|
|
private const ACTION_SYNC_PDF_URL = 'sync_pdf_url';
|
|
|
|
|
+ private const ACTION_NEEDS_REVIEW = 'needs_review';
|
|
|
|
|
|
|
|
protected $signature = 'exam:backfill-analysis-results
|
|
protected $signature = 'exam:backfill-analysis-results
|
|
|
{--since= : papers.completed_at >= 该时间(默认今天 00:00:00)}
|
|
{--since= : papers.completed_at >= 该时间(默认今天 00:00:00)}
|
|
|
{--paper= : 仅处理指定 paper_id}
|
|
{--paper= : 仅处理指定 paper_id}
|
|
|
{--student= : 仅处理指定 student_id}
|
|
{--student= : 仅处理指定 student_id}
|
|
|
{--limit=100 : 最多处理多少条候选试卷}
|
|
{--limit=100 : 最多处理多少条候选试卷}
|
|
|
|
|
+ {--force-analysis : 允许重算已有但无效的分析数据(默认不覆盖)}
|
|
|
{--dry-run : 只打印待回填列表,不执行回填}';
|
|
{--dry-run : 只打印待回填列表,不执行回填}';
|
|
|
|
|
|
|
|
protected $description = '回填 exam_analysis_results 缺失分析数据或缺失 PDF URL 的试卷';
|
|
protected $description = '回填 exam_analysis_results 缺失分析数据或缺失 PDF URL 的试卷';
|
|
@@ -41,6 +43,7 @@ class BackfillExamAnalysisResultsCommand extends Command
|
|
|
$limit = max(1, (int) $this->option('limit'));
|
|
$limit = max(1, (int) $this->option('limit'));
|
|
|
$paperFilter = $this->option('paper');
|
|
$paperFilter = $this->option('paper');
|
|
|
$studentFilter = $this->option('student');
|
|
$studentFilter = $this->option('student');
|
|
|
|
|
+ $forceAnalysis = (bool) $this->option('force-analysis');
|
|
|
$isDryRun = (bool) $this->option('dry-run');
|
|
$isDryRun = (bool) $this->option('dry-run');
|
|
|
|
|
|
|
|
$paperRows = DB::connection('mysql')
|
|
$paperRows = DB::connection('mysql')
|
|
@@ -61,6 +64,7 @@ class BackfillExamAnalysisResultsCommand extends Command
|
|
|
self::ACTION_ANALYSIS => 0,
|
|
self::ACTION_ANALYSIS => 0,
|
|
|
self::ACTION_PDF_ONLY => 0,
|
|
self::ACTION_PDF_ONLY => 0,
|
|
|
self::ACTION_SYNC_PDF_URL => 0,
|
|
self::ACTION_SYNC_PDF_URL => 0,
|
|
|
|
|
+ self::ACTION_NEEDS_REVIEW => 0,
|
|
|
];
|
|
];
|
|
|
|
|
|
|
|
foreach ($paperRows as $paper) {
|
|
foreach ($paperRows as $paper) {
|
|
@@ -85,11 +89,21 @@ class BackfillExamAnalysisResultsCommand extends Command
|
|
|
$latest->analysis_data ?? null,
|
|
$latest->analysis_data ?? null,
|
|
|
$latest->id ?? null,
|
|
$latest->id ?? null,
|
|
|
$latest->analysis_pdf_url ?? null,
|
|
$latest->analysis_pdf_url ?? null,
|
|
|
- $studentReportPdfUrl
|
|
|
|
|
|
|
+ $studentReportPdfUrl,
|
|
|
|
|
+ $forceAnalysis
|
|
|
);
|
|
);
|
|
|
|
|
|
|
|
$counts[$action]++;
|
|
$counts[$action]++;
|
|
|
- if ($action === self::ACTION_SKIP) {
|
|
|
|
|
|
|
+ if ($action === self::ACTION_SKIP || $action === self::ACTION_NEEDS_REVIEW) {
|
|
|
|
|
+ if ($action === self::ACTION_NEEDS_REVIEW) {
|
|
|
|
|
+ $this->warn(sprintf(
|
|
|
|
|
+ '跳过需人工确认的已有分析记录:paper_id=%s student_id=%s analysis_id=%s(如确认要重算,单张使用 --force-analysis --paper=%s)',
|
|
|
|
|
+ $paper->paper_id,
|
|
|
|
|
+ $paper->student_id,
|
|
|
|
|
+ $latest->id ?? 'null',
|
|
|
|
|
+ $paper->paper_id
|
|
|
|
|
+ ));
|
|
|
|
|
+ }
|
|
|
continue;
|
|
continue;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -104,11 +118,12 @@ class BackfillExamAnalysisResultsCommand extends Command
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
$this->info(sprintf(
|
|
$this->info(sprintf(
|
|
|
- '扫描完成:已完成试卷 %d 条,需补分析 %d 条,仅补PDF %d 条,同步PDF URL %d 条,已跳过 %d 条(since=%s, limit=%d)',
|
|
|
|
|
|
|
+ '扫描完成:已完成试卷 %d 条,需补分析 %d 条,仅补PDF %d 条,同步PDF URL %d 条,需人工确认 %d 条,已跳过 %d 条(since=%s, limit=%d)',
|
|
|
$paperRows->count(),
|
|
$paperRows->count(),
|
|
|
$counts[self::ACTION_ANALYSIS],
|
|
$counts[self::ACTION_ANALYSIS],
|
|
|
$counts[self::ACTION_PDF_ONLY],
|
|
$counts[self::ACTION_PDF_ONLY],
|
|
|
$counts[self::ACTION_SYNC_PDF_URL],
|
|
$counts[self::ACTION_SYNC_PDF_URL],
|
|
|
|
|
+ $counts[self::ACTION_NEEDS_REVIEW],
|
|
|
$counts[self::ACTION_SKIP],
|
|
$counts[self::ACTION_SKIP],
|
|
|
$since->toDateTimeString(),
|
|
$since->toDateTimeString(),
|
|
|
$limit
|
|
$limit
|
|
@@ -145,7 +160,7 @@ class BackfillExamAnalysisResultsCommand extends Command
|
|
|
'paper_id' => $item->paper_id,
|
|
'paper_id' => $item->paper_id,
|
|
|
'student_id' => $item->student_id,
|
|
'student_id' => $item->student_id,
|
|
|
'questions' => $questions,
|
|
'questions' => $questions,
|
|
|
- 'force_recalculate' => true,
|
|
|
|
|
|
|
+ 'force_recalculate' => $forceAnalysis,
|
|
|
];
|
|
];
|
|
|
|
|
|
|
|
$taskId = $taskManager->createTask(TaskManager::TASK_TYPE_ANALYSIS, [
|
|
$taskId = $taskManager->createTask(TaskManager::TASK_TYPE_ANALYSIS, [
|
|
@@ -204,15 +219,17 @@ class BackfillExamAnalysisResultsCommand extends Command
|
|
|
mixed $analysisDataRaw,
|
|
mixed $analysisDataRaw,
|
|
|
mixed $analysisId,
|
|
mixed $analysisId,
|
|
|
mixed $analysisPdfUrl,
|
|
mixed $analysisPdfUrl,
|
|
|
- mixed $studentReportPdfUrl
|
|
|
|
|
|
|
+ mixed $studentReportPdfUrl,
|
|
|
|
|
+ bool $forceAnalysis
|
|
|
): string
|
|
): string
|
|
|
{
|
|
{
|
|
|
|
|
+ $hasAnalysisRow = $analysisId !== null;
|
|
|
$hasValidAnalysis = $this->hasValidAnalysisData($analysisDataRaw, $analysisId);
|
|
$hasValidAnalysis = $this->hasValidAnalysisData($analysisDataRaw, $analysisId);
|
|
|
$hasAnalysisPdf = $this->hasNonEmptyString($analysisPdfUrl);
|
|
$hasAnalysisPdf = $this->hasNonEmptyString($analysisPdfUrl);
|
|
|
$hasStudentReportPdf = $this->hasNonEmptyString($studentReportPdfUrl);
|
|
$hasStudentReportPdf = $this->hasNonEmptyString($studentReportPdfUrl);
|
|
|
|
|
|
|
|
if (! $hasValidAnalysis) {
|
|
if (! $hasValidAnalysis) {
|
|
|
- return self::ACTION_ANALYSIS;
|
|
|
|
|
|
|
+ return (! $hasAnalysisRow || $forceAnalysis) ? self::ACTION_ANALYSIS : self::ACTION_NEEDS_REVIEW;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
if ($hasAnalysisPdf) {
|
|
if ($hasAnalysisPdf) {
|