resolveKnowledgeBaseIds($accessibleStationIds, $filters); $searchBuilder = Document::search($query); if (!empty($filters['uploaded_by'])) { $searchBuilder->where('uploaded_by', $filters['uploaded_by']); } if (!empty($kbIds)) { $searchBuilder->query(fn ($q) => $q->whereIn('knowledge_base_id', $kbIds)); } return $searchBuilder->get(); } catch (\Exception $e) { Log::error('文档搜索失败', [ 'query' => $query, 'filters' => $filters, 'error' => $e->getMessage(), ]); return new Collection(); } } /** * 解析最终可搜索的知识库 ID 列表 * * 1. 从 accessibleStationIds 得到可访问 KB(全局 KB + 关联 station 的 KB) * 2. 从 filters 得到用户指定的 KB(station_ids + knowledge_base_ids 并集) * 3. 取交集(若有 filter 指定),否则用可访问范围 */ private function resolveKnowledgeBaseIds(array $accessibleStationIds, array $filters): array { // 权限边界 $accessibleKbIds = null; if (!empty($accessibleStationIds)) { $accessibleKbIds = KnowledgeBase::where(function ($q) use ($accessibleStationIds) { $q->whereDoesntHave('stations') ->orWhereHas('stations', fn ($sq) => $sq->whereIn('stations.id', $accessibleStationIds)); })->pluck('id')->toArray(); } // 用户主动筛选 $kbIdsFromStations = []; if (!empty($filters['station_ids'])) { $kbIdsFromStations = KnowledgeBase::where(function ($q) use ($filters) { $q->whereDoesntHave('stations') ->orWhereHas('stations', fn ($sq) => $sq->whereIn('stations.id', $filters['station_ids'])); })->pluck('id')->toArray(); } $kbIdsFromFilter = $filters['knowledge_base_ids'] ?? []; if (!empty($kbIdsFromStations) && !empty($kbIdsFromFilter)) { $filterKbIds = array_values(array_intersect($kbIdsFromStations, $kbIdsFromFilter)); } elseif (!empty($kbIdsFromStations)) { $filterKbIds = $kbIdsFromStations; } elseif (!empty($kbIdsFromFilter)) { $filterKbIds = $kbIdsFromFilter; } else { $filterKbIds = []; } // 合并 if ($accessibleKbIds === null) { return $filterKbIds; // 无权限限制 } if (empty($filterKbIds)) { return $accessibleKbIds; // 无主动筛选,用权限范围 } return array_values(array_intersect($filterKbIds, $accessibleKbIds)); // 取交集 } /** * 准备文档的可搜索数据 */ public function prepareSearchableData(Document $document): array { return [ 'id' => $document->id, 'title' => $document->title, 'description' => $document->description, 'markdown_content' => $document->getMarkdownContent(), 'knowledge_base_id' => $document->knowledge_base_id, 'uploaded_by' => $document->uploaded_by, 'created_at' => $document->created_at?->timestamp, 'updated_at' => $document->updated_at?->timestamp, ]; } public function indexDocument(Document $document): void { try { if (!$document->shouldBeSearchable()) { return; } $document->searchable(); } catch (\Exception $e) { Log::error('文档索引失败', ['document_id' => $document->id, 'error' => $e->getMessage()]); } } public function updateDocumentIndex(Document $document): void { try { if ($document->shouldBeSearchable()) { $document->searchable(); } else { $this->removeDocumentFromIndex($document); } } catch (\Exception $e) { Log::error('文档索引更新失败', ['document_id' => $document->id, 'error' => $e->getMessage()]); } } public function removeDocumentFromIndex(Document $document): void { try { $document->unsearchable(); } catch (\Exception $e) { Log::error('文档索引移除失败', ['document_id' => $document->id, 'error' => $e->getMessage()]); } } }