| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201 |
- <?php
- namespace App\Filament\Pages;
- use App\Services\KnowledgeServiceApi;
- use BackedEnum;
- use Filament\Actions\Action;
- use Filament\Pages\Page;
- use Illuminate\Http\Request;
- use Illuminate\Support\Collection;
- use Illuminate\Support\Str;
- use UnitEnum;
- class KnowledgePoints extends Page
- {
- protected static string|BackedEnum|null $navigationIcon = 'heroicon-o-map';
- protected static string|UnitEnum|null $navigationGroup = '知识图谱';
- protected static ?string $navigationLabel = '知识点总览';
- protected string $view = 'filament.pages.knowledge-points';
- public ?string $phaseFilter = null;
- public ?string $categoryFilter = null;
- public ?string $search = null;
- public int $page = 1;
- public int $perPage = 8;
- protected bool $loading = false;
- protected ?KnowledgeServiceApi $knowledgeService = null;
- protected ?string $selectedKpCode = null;
- // Private property to store loaded data
- private ?array $selectedPointData = null;
- public function mount(Request $request): void
- {
- // Only set properties that need to be available immediately
- // The search and filter properties will be set via getter
- $this->selectedKpCode = $request->query('selected');
- $this->page = (int) $request->query('page', 1);
- }
- public function getSelectedPointProperty(): ?array
- {
- if ($this->selectedPointData) {
- return $this->selectedPointData;
- }
- // If we have a specific kp code to load
- if ($this->selectedKpCode) {
- $this->selectedPointData = $this->getKnowledgeService()->getKnowledgePointDetail($this->selectedKpCode);
- return $this->selectedPointData;
- }
- // Get first point from paginated results
- $points = $this->paginatedPoints;
- if (!empty($points['data']) && count($points['data']) > 0) {
- $kpCode = $points['data'][0]['kp_code'];
- $this->selectedPointData = $this->getKnowledgeService()->getKnowledgePointDetail($kpCode);
- }
- return $this->selectedPointData;
- }
- protected function getKnowledgeService(): KnowledgeServiceApi
- {
- if (!$this->knowledgeService) {
- $this->knowledgeService = app(KnowledgeServiceApi::class);
- }
- return $this->knowledgeService;
- }
- public function selectPoint(string $kpCode): void
- {
- $this->selectedPoint = $this->getKnowledgeService()->getKnowledgePointDetail($kpCode);
- }
- public function getStatsProperty(): array
- {
- $all = $this->getKnowledgeService()->listKnowledgePoints();
- $phases = $all->groupBy('phase')->map->count()->sortDesc()->map(fn ($count, $phase) => "{$phase}·{$count}");
- $categories = $all->groupBy('category')->map->count()->sortDesc()->take(3)->map(fn ($count, $category) => "{$category}·{$count}");
- return [
- ['label' => '知识点数量', 'value' => number_format($all->count()), 'hint' => '当前版本节点'],
- ['label' => '学段覆盖', 'value' => $phases->implode(' | ') ?: '未配置', 'hint' => 'phase 字段'],
- ['label' => 'Top 类别', 'value' => $categories->implode(' | ') ?: '未配置', 'hint' => 'category 字段'],
- ['label' => '平均重要度', 'value' => number_format($all->avg('importance') ?? 0, 1), 'hint' => 'importance'],
- ];
- }
- public function getPhaseOptionsProperty(): array
- {
- return $this->getKnowledgeService()
- ->listKnowledgePoints()
- ->pluck('phase')
- ->filter()
- ->unique()
- ->sort()
- ->mapWithKeys(fn ($phase) => [$phase => $phase])
- ->all();
- }
- public function getCategoryOptionsProperty(): array
- {
- return $this->getKnowledgeService()
- ->listKnowledgePoints()
- ->pluck('category')
- ->filter()
- ->unique()
- ->sort()
- ->mapWithKeys(fn ($category) => [$category => $category])
- ->all();
- }
- public function getPaginatedPointsProperty(): array
- {
- // Get filters from URL
- $request = request();
- $phaseFilter = $request->query('phase');
- $categoryFilter = $request->query('category');
- $searchTerm = trim((string) $request->query('search'));
- // Get all points
- $filters = array_filter([
- 'phase' => $phaseFilter,
- 'category' => $categoryFilter,
- ]);
- $allPoints = $this->getKnowledgeService()->listKnowledgePoints(
- perPage: 200,
- filters: $filters
- );
- // Apply search filter on the client side
- if ($searchTerm !== '') {
- $allPoints = $allPoints->filter(function (array $record) use ($searchTerm): bool {
- return Str::contains(Str::lower($record['cn_name'] ?? ''), Str::lower($searchTerm))
- || Str::contains(Str::lower($record['kp_code'] ?? ''), Str::lower($searchTerm))
- || Str::contains(Str::lower($record['description'] ?? ''), Str::lower($searchTerm));
- });
- }
- // Paginate the results
- $total = $allPoints->count();
- $totalPages = (int) ceil($total / $this->perPage);
- $offset = ($this->page - 1) * $this->perPage;
- $records = $allPoints->slice($offset, $this->perPage)->values();
- return [
- 'data' => $records,
- 'total' => $total,
- 'page' => $this->page,
- 'total_pages' => $totalPages,
- 'has_prev' => $this->page > 1,
- 'has_next' => $this->page < $totalPages,
- ];
- }
- public function getSelectedSkillsProperty(): Collection
- {
- $selectedPoint = $this->selectedPointData;
- return collect($selectedPoint['skills'] ?? []);
- }
- public function getRelatedNodesProperty(): array
- {
- $point = $this->selectedPointData;
- if (! $point) {
- return ['parents' => [], 'children' => []];
- }
- $parents = collect($point['parents'] ?? [])
- ->map(fn ($name, $index) => [
- 'id' => "parent-{$index}",
- 'label' => $name,
- 'relation' => 'parent',
- ])->values()->all();
- $children = collect($point['children'] ?? [])
- ->map(fn ($name, $index) => [
- 'id' => "child-{$index}",
- 'label' => $name,
- 'relation' => 'child',
- ])->values()->all();
- return ['parents' => $parents, 'children' => $children];
- }
- }
|