*/ protected $fillable = [ 'title', 'file_path', 'file_name', 'file_size', 'mime_type', 'uploaded_by', 'description', 'markdown_path', 'conversion_status', 'conversion_error', 'knowledge_base_id', ]; /** * 获取文档所属的知识库 */ public function knowledgeBase(): BelongsTo { return $this->belongsTo(KnowledgeBase::class); } /** * 获取文档的上传者 */ public function uploader(): BelongsTo { return $this->belongsTo(User::class, 'uploaded_by'); } /** * 获取文档的所有下载日志 */ public function downloadLogs(): HasMany { return $this->hasMany(DownloadLog::class); } /** * 获取可搜索的数组数据 * 用于 Meilisearch 索引 */ public function toSearchableArray(): array { return [ 'id' => $this->id, 'title' => $this->title, 'file_name' => $this->file_name, 'description' => $this->description, 'markdown_content' => $this->getMarkdownContent(), 'knowledge_base_id' => $this->knowledge_base_id, 'uploaded_by' => $this->uploaded_by, 'created_at' => $this->created_at?->timestamp, ]; } /** * 判断文档是否应该被索引 * 只有转换完成的文档才会被索引 */ public function shouldBeSearchable(): bool { return $this->conversion_status === 'completed'; } /** * 获取完整的 Markdown 内容 * 从文件系统读取 Markdown 文件 */ public function getMarkdownContent(): ?string { if (!$this->markdown_path) { return null; } try { if (Storage::disk('markdown')->exists($this->markdown_path)) { return Storage::disk('markdown')->get($this->markdown_path); } } catch (\Exception $e) { \Log::warning('Failed to read markdown content', [ 'document_id' => $this->id, 'markdown_path' => $this->markdown_path, 'error' => $e->getMessage() ]); } return null; } /** * 检查文档是否已转换为 Markdown */ public function hasMarkdown(): bool { return !empty($this->markdown_path) && $this->conversion_status === 'completed'; } }