TextbookTable.php 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. <?php
  2. namespace App\Filament\Resources\TextbookResource\Tables;
  3. use App\Filament\Resources\TextbookResource;
  4. use Filament\Actions\EditAction;
  5. use Filament\Actions\Action;
  6. use Filament\Actions\BulkAction;
  7. use Filament\Tables;
  8. use Filament\Tables\Columns\TextColumn;
  9. use Filament\Tables\Filters\SelectFilter;
  10. use Filament\Tables\Table;
  11. use Illuminate\Database\Eloquent\Model;
  12. use Filament\Tables\Enums\FiltersLayout;
  13. use Filament\Tables\Filters\Filter;
  14. use Filament\Forms\Components\TextInput;
  15. class TextbookTable
  16. {
  17. public static function make(Table $table): Table
  18. {
  19. // 直接返回配置好的表格,不使用query()
  20. return $table
  21. ->defaultSort('id', 'asc')
  22. ->columns([
  23. TextColumn::make('id')->label('ID')->sortable(),
  24. TextColumn::make('official_title')->label('教材名称')->searchable()->wrap(),
  25. TextColumn::make('series_name')->label('教材系列')->sortable(),
  26. TextColumn::make('series_id')->label('系列ID')->sortable(),
  27. TextColumn::make('stage')
  28. ->label('学段')
  29. ->sortable()
  30. ->formatStateUsing(fn ($state) => match ($state) {
  31. 'primary' => '小学',
  32. 'junior' => '初中',
  33. 'senior' => '高中',
  34. default => $state ?: '未标注',
  35. }),
  36. TextColumn::make('grade')->label('年级')->sortable(),
  37. TextColumn::make('semester')->label('学期')->sortable(),
  38. TextColumn::make('isbn')->label('ISBN')->toggleable(isToggledHiddenByDefault: true),
  39. TextColumn::make('status')
  40. ->label('状态')
  41. ->sortable()
  42. ->formatStateUsing(fn ($state) => match ($state) {
  43. 'draft' => '草稿',
  44. 'published' => '已发布',
  45. 'archived' => '已归档',
  46. default => $state ?: '未知',
  47. }),
  48. TextColumn::make('created_at')
  49. ->label('创建时间')
  50. ->dateTime()
  51. ->sortable()
  52. ->toggleable(isToggledHiddenByDefault: true),
  53. TextColumn::make('updated_at')
  54. ->label('更新时间')
  55. ->dateTime()
  56. ->sortable()
  57. ->toggleable(isToggledHiddenByDefault: true),
  58. ])
  59. ->filters([
  60. SelectFilter::make('stage')
  61. ->label('学段')
  62. ->options([
  63. 'primary' => '小学',
  64. 'junior' => '初中',
  65. 'senior' => '高中',
  66. ]),
  67. SelectFilter::make('grade')
  68. ->label('年级')
  69. ->options(collect(range(1, 12))->mapWithKeys(fn ($grade) => [$grade => "{$grade}年级"])->all()),
  70. SelectFilter::make('semester')
  71. ->label('学期')
  72. ->options([
  73. 1 => '上学期',
  74. 2 => '下学期',
  75. ]),
  76. SelectFilter::make('status')
  77. ->label('发布状态')
  78. ->options([
  79. 'draft' => '草稿',
  80. 'published' => '已发布',
  81. 'archived' => '已归档',
  82. ]),
  83. Filter::make('keyword')
  84. ->label('关键词')
  85. ->form([
  86. TextInput::make('value')
  87. ->placeholder('教材名称 / ISBN / 系列'),
  88. ]),
  89. ], layout: FiltersLayout::AboveContentCollapsible)
  90. ->actions([
  91. EditAction::make()
  92. ->label('编辑')
  93. ->icon('heroicon-o-pencil-square')
  94. ->iconButton()
  95. ->tooltip('编辑'),
  96. Action::make('delete')
  97. ->label('删除')
  98. ->color('danger')
  99. ->icon('heroicon-o-trash')
  100. ->iconButton()
  101. ->tooltip('删除')
  102. ->requiresConfirmation()
  103. ->modalHeading('删除教材')
  104. ->modalDescription('确定要删除这个教材吗?此操作无法撤销。')
  105. ->action(function (Model $record) {
  106. // 添加调试日志
  107. \Log::info('Deleting textbook', ['id' => $record->id, 'record' => $record]);
  108. if (!$record || !$record->id) {
  109. \Filament\Notifications\Notification::make()
  110. ->title('错误')
  111. ->body('无效的教材记录。')
  112. ->danger()
  113. ->send();
  114. return;
  115. }
  116. $apiService = app(\App\Services\TextbookApiService::class);
  117. $deleted = $apiService->deleteTextbook($record->id);
  118. \Log::info('Delete result', ['deleted' => $deleted]);
  119. if ($deleted) {
  120. \Filament\Notifications\Notification::make()
  121. ->title('成功')
  122. ->body('教材删除成功。')
  123. ->success()
  124. ->send();
  125. } else {
  126. \Filament\Notifications\Notification::make()
  127. ->title('错误')
  128. ->body('删除失败,请重试。')
  129. ->danger()
  130. ->send();
  131. }
  132. }),
  133. Action::make('view_catalog')
  134. ->label('查看目录')
  135. ->icon('heroicon-o-list-bullet')
  136. ->iconButton()
  137. ->tooltip('查看目录')
  138. ->url(fn(Model $record): string =>
  139. route('filament.admin.resources.textbook-catalogs.index', ['tableFilters[textbook_id][value]' => $record->id])
  140. ),
  141. ])
  142. ->bulkActions([
  143. \Filament\Actions\BulkActionGroup::make([
  144. \Filament\Actions\DeleteBulkAction::make()
  145. ->label('批量删除'),
  146. BulkAction::make('archive')
  147. ->label('批量归档')
  148. ->color('warning')
  149. ->icon('heroicon-o-archive-box')
  150. ->requiresConfirmation()
  151. ->action(function ($records): void {
  152. $apiService = app(\App\Services\TextbookApiService::class);
  153. foreach ($records as $record) {
  154. $apiService->updateTextbook((int) $record->id, ['status' => 'archived']);
  155. }
  156. }),
  157. ]),
  158. ])
  159. ->recordUrl(fn (Model $record): string => route('filament.admin.resources.textbooks.view', $record))
  160. ->defaultSort('sort_order')
  161. ->paginated([10, 25, 50, 100]);
  162. }
  163. }