columns([ TextColumn::make('official_title') ->label('教材信息') ->html() ->formatStateUsing(function ($state, Model $record): string { $cover = $record->cover_path ?? null; $coverUrl = null; if ($cover) { $coverUrl = Str::startsWith($cover, ['http://', 'https://', '/']) ? $cover : Storage::disk('public')->url($cover); } $seriesName = $record->series->name ?? '未归类系列'; $stage = match ($record->stage) { 'primary' => '小学', 'junior' => '初中', 'senior' => '高中', default => $record->stage ?: '未标注', }; $semester = match ($record->semester) { 1 => '上学期', 2 => '下学期', default => '未标注', }; $naming = match ($record->naming_scheme) { 'new' => '新体系', 'old' => '旧体系', default => $record->naming_scheme ?: '未标注', }; $status = match ($record->status) { 'draft' => '草稿', 'published' => '已发布', 'archived' => '已归档', default => $record->status ?: '未知', }; $badgeTone = match ($record->status) { 'published' => 'text-emerald-600 bg-emerald-50 border-emerald-100', 'draft' => 'text-amber-600 bg-amber-50 border-amber-100', 'archived' => 'text-slate-500 bg-slate-100 border-slate-200', default => 'text-slate-500 bg-slate-100 border-slate-200', }; $title = e($state ?: '未命名教材'); $coverHtml = $coverUrl ? "\"封面\"" : "
封面
"; $gradeLabel = $record->grade ? "{$record->grade}年级" : '年级未标注'; $isbnLabel = $record->isbn ?: '未填写'; return << {$coverHtml}
{$title}
{$status}
{$seriesName} · {$stage} · {$gradeLabel} · {$semester}
体系:{$naming} ISBN:{$isbnLabel} ID:{$record->id}
HTML; }) ->wrap(), TextColumn::make('created_at') ->label('创建时间') ->dateTime() ->sortable() ->toggleable(isToggledHiddenByDefault: true), TextColumn::make('updated_at') ->label('更新时间') ->dateTime() ->sortable() ->toggleable(isToggledHiddenByDefault: true), ]) ->filters([ SelectFilter::make('stage') ->label('学段') ->options([ 'primary' => '小学', 'junior' => '初中', 'senior' => '高中', ]), SelectFilter::make('grade') ->label('年级') ->options(collect(range(1, 12))->mapWithKeys(fn ($grade) => [$grade => "{$grade}年级"])->all()), SelectFilter::make('semester') ->label('学期') ->options([ 1 => '上学期', 2 => '下学期', ]), SelectFilter::make('naming_scheme') ->label('教材体系') ->options([ 'new' => '新体系', 'old' => '旧体系', ]), SelectFilter::make('status') ->label('发布状态') ->options([ 'draft' => '草稿', 'published' => '已发布', 'archived' => '已归档', ]), Filter::make('keyword') ->label('关键词') ->form([ TextInput::make('value') ->placeholder('教材名称 / ISBN / 系列'), ]), ], layout: FiltersLayout::AboveContentCollapsible) ->actions([ EditAction::make() ->label('编辑') ->icon('heroicon-o-pencil-square') ->iconButton() ->tooltip('编辑'), Action::make('delete') ->label('删除') ->color('danger') ->icon('heroicon-o-trash') ->iconButton() ->tooltip('删除') ->requiresConfirmation() ->modalHeading('删除教材') ->modalDescription('确定要删除这个教材吗?此操作无法撤销。') ->action(function (Model $record) { // 添加调试日志 \Log::info('Deleting textbook', ['id' => $record->id, 'record' => $record]); if (!$record || !$record->id) { \Filament\Notifications\Notification::make() ->title('错误') ->body('无效的教材记录。') ->danger() ->send(); return; } $apiService = app(\App\Services\TextbookApiService::class); $deleted = $apiService->deleteTextbook($record->id); \Log::info('Delete result', ['deleted' => $deleted]); if ($deleted) { \Filament\Notifications\Notification::make() ->title('成功') ->body('教材删除成功。') ->success() ->send(); } else { \Filament\Notifications\Notification::make() ->title('错误') ->body('删除失败,请重试。') ->danger() ->send(); } }), Action::make('view_catalog') ->label('查看目录') ->icon('heroicon-o-list-bullet') ->iconButton() ->tooltip('查看目录') ->url(fn(Model $record): string => route('filament.admin.resources.textbook-catalogs.index', ['tableFilters[textbook_id][value]' => $record->id]) ), ]) ->bulkActions([ \Filament\Actions\BulkActionGroup::make([ \Filament\Actions\DeleteBulkAction::make() ->label('批量删除'), BulkAction::make('archive') ->label('批量归档') ->color('warning') ->icon('heroicon-o-archive-box') ->requiresConfirmation() ->action(function ($records): void { $apiService = app(\App\Services\TextbookApiService::class); foreach ($records as $record) { $apiService->updateTextbook((int) $record->id, ['status' => 'archived']); } }), ]), ]) ->recordUrl(fn (Model $record): string => route('filament.admin.resources.textbooks.view', $record)) ->defaultSort('sort_order') ->paginated([10, 25, 50, 100]); } }