'datetime', 'updated_at' => 'datetime', 'image_count' => 'integer', 'total_questions' => 'integer', 'analysis_pdf_url' => 'string', ]; public function questions(): HasMany { return $this->hasMany(OCRQuestionResult::class, 'ocr_record_id', 'id'); } public function ocrRawData() { return $this->hasOne(\App\Models\OCRRawData::class, 'ocr_record_id', 'id'); } public function student() { return $this->belongsTo(Student::class, 'user_id', 'student_id'); } public function getStatusBadgeAttribute(): string { return match ($this->status) { 'pending' => '待处理', 'processing' => '处理中', 'completed' => '已完成', 'failed' => '失败', default => '未知', }; } // 兼容性方法:获取 student_id public function getStudentIdAttribute(): ?string { return $this->user_id; } // 兼容性方法:设置 student_id public function setStudentIdAttribute(?string $value): void { // 同时设置两个字段以保持数据一致性 $this->attributes['student_id'] = $value; $this->attributes['user_id'] = $value; } public function getImagePathAttribute(): string { // 将 file_path 映射为 image_path 以保持兼容性 return $this->file_path ?? ''; } public function getImageUrlAttribute(): string { // 使用 file_path(通过上面的访问器也可以通过 image_path 访问) $path = $this->file_path; if ($path && file_exists(public_path($path))) { return asset($path); } return ''; } /** * 获取处理完成时间(确保返回 Carbon 对象) */ public function getProcessedAtAttribute($value): ?\Carbon\Carbon { if (empty($value)) { return null; } // 如果已经是 Carbon 实例,直接返回 if ($value instanceof \Carbon\Carbon) { return $value; } // 如果是字符串,解析为 Carbon 实例 if (is_string($value)) { return \Carbon\Carbon::parse($value); } return null; } public function getProgressPercentageAttribute(): int { if ($this->total_questions === 0) { return 0; } return intval(($this->processed_questions / $this->total_questions) * 100); } public function getPaperTypeLabelAttribute(): string { return match($this->paper_type) { 'unit_test' => '单元测试', 'midterm' => '期中考试', 'final' => '期末考试', 'homework' => '家庭作业', 'quiz' => '随堂测验', 'other' => '其他', default => '未分类', }; } }