SourcePaperResource.php 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. <?php
  2. namespace App\Filament\Resources;
  3. use App\Filament\Resources\SourcePaperResource\Pages;
  4. use App\Filament\Resources\SourcePaperResource\RelationManagers\PaperPartsRelationManager;
  5. use App\Filament\Resources\SourcePaperResource\RelationManagers\PreQuestionCandidatesRelationManager;
  6. use App\Models\SourcePaper;
  7. use Filament\Forms;
  8. use Filament\Resources\Resource;
  9. use Filament\Schemas\Schema;
  10. use Filament\Tables;
  11. use Filament\Tables\Table;
  12. use Filament\Actions\ViewAction;
  13. use Illuminate\Database\Eloquent\Model;
  14. use BackedEnum;
  15. use UnitEnum;
  16. use Filament\Tables\Enums\FiltersLayout;
  17. use Filament\Tables\Filters\SelectFilter;
  18. use Filament\Tables\Filters\Filter;
  19. use Filament\Forms\Components\TextInput;
  20. use Illuminate\Database\Eloquent\Builder;
  21. class SourcePaperResource extends Resource
  22. {
  23. protected static ?string $model = SourcePaper::class;
  24. protected static bool $shouldRegisterNavigation = false;
  25. protected static BackedEnum|string|null $navigationIcon = 'heroicon-o-document-text';
  26. protected static UnitEnum|string|null $navigationGroup = '卷子导入流程';
  27. protected static ?string $navigationLabel = '源卷子列表';
  28. protected static ?int $navigationSort = 3;
  29. public static function canCreate(): bool
  30. {
  31. return false;
  32. }
  33. public static function canEdit(Model $record): bool
  34. {
  35. return false;
  36. }
  37. public static function form(Schema $schema): Schema
  38. {
  39. return $schema->schema([
  40. Forms\Components\TextInput::make('title')->label('标题')->disabled(),
  41. Forms\Components\TextInput::make('full_title')->label('完整标题')->disabled(),
  42. Forms\Components\TextInput::make('chapter')->label('章节')->disabled(),
  43. Forms\Components\TextInput::make('grade')->label('年级')->disabled(),
  44. Forms\Components\TextInput::make('term')->label('学期')->disabled(),
  45. Forms\Components\Textarea::make('raw_markdown')
  46. ->label('卷子原始 Markdown')
  47. ->rows(12)
  48. ->disabled(),
  49. ]);
  50. }
  51. public static function table(Table $table): Table
  52. {
  53. return $table
  54. ->columns([
  55. Tables\Columns\TextColumn::make('order')->label('顺序')->sortable(),
  56. Tables\Columns\TextColumn::make('title')->label('卷标题')->searchable(),
  57. Tables\Columns\TextColumn::make('file.original_filename')->label('来源文件')->toggleable(),
  58. Tables\Columns\TextColumn::make('grade')->label('年级'),
  59. Tables\Columns\TextColumn::make('term')->label('学期'),
  60. Tables\Columns\TextColumn::make('source_type')->label('类型'),
  61. Tables\Columns\TextColumn::make('parts_sum_question_count')
  62. ->label('题量')
  63. ->getStateUsing(fn (Model $record) => $record->parts_sum_question_count ?? 0)
  64. ->sortable(),
  65. Tables\Columns\TextColumn::make('parts_count')
  66. ->label('区块数')
  67. ->getStateUsing(fn (Model $record) => $record->parts_count ?? 0)
  68. ->sortable(),
  69. ])
  70. ->filters([
  71. SelectFilter::make('grade')
  72. ->label('年级')
  73. ->options(collect(range(1, 12))->mapWithKeys(fn ($grade) => [$grade => "{$grade}年级"])->all()),
  74. SelectFilter::make('term')
  75. ->label('学期')
  76. ->options([
  77. '上学期' => '上学期',
  78. '下学期' => '下学期',
  79. ]),
  80. SelectFilter::make('source_type')
  81. ->label('来源类型')
  82. ->options([
  83. 'textbook' => '教材',
  84. 'exam' => '考试',
  85. 'other' => '其他',
  86. ]),
  87. Filter::make('question_range')
  88. ->label('题量范围')
  89. ->form([
  90. TextInput::make('min')->placeholder('最小题量')->numeric(),
  91. TextInput::make('max')->placeholder('最大题量')->numeric(),
  92. ])
  93. ->query(function (Builder $query, array $data) {
  94. $min = $data['min'] ?? null;
  95. $max = $data['max'] ?? null;
  96. if ($min !== null && $min !== '') {
  97. $query->having('parts_sum_question_count', '>=', (int) $min);
  98. }
  99. if ($max !== null && $max !== '') {
  100. $query->having('parts_sum_question_count', '<=', (int) $max);
  101. }
  102. }),
  103. ], layout: FiltersLayout::AboveContentCollapsible)
  104. ->actions([
  105. ViewAction::make()
  106. ->icon('heroicon-o-eye')
  107. ->iconButton()
  108. ->tooltip('查看详情'),
  109. ])
  110. ->recordUrl(fn (Model $record): string => route('filament.admin.resources.source-papers.view', $record));
  111. }
  112. public static function getRelations(): array
  113. {
  114. return [
  115. PaperPartsRelationManager::class,
  116. PreQuestionCandidatesRelationManager::class,
  117. ];
  118. }
  119. public static function getPages(): array
  120. {
  121. return [
  122. 'index' => Pages\ListSourcePapers::route('/'),
  123. 'view' => Pages\ViewSourcePaper::route('/{record}'),
  124. ];
  125. }
  126. public static function getEloquentQuery(): Builder
  127. {
  128. return parent::getEloquentQuery()
  129. ->with(['file'])
  130. ->withCount(['parts', 'candidates'])
  131. ->withSum('parts', 'question_count');
  132. }
  133. }