| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235 |
- <?php
- namespace App\Filament\Resources;
- use BackedEnum;
- use App\Filament\Resources\OCRRecordResource\Pages;
- use App\Models\OCRRecord;
- use App\Models\Student;
- use Filament\Resources\Resource;
- use Filament\Schemas\Schema;
- use Filament\Forms\Components\Select;
- use Filament\Forms\Components\FileUpload;
- use Filament\Forms\Components\Hidden;
- use Filament\Tables;
- use Filament\Tables\Table;
- use Illuminate\Database\Eloquent\Builder;
- use Filament\Infolists\Infolist;
- use Filament\Infolists\Components\TextEntry;
- use Filament\Infolists\Components\ImageEntry;
- use Filament\Infolists\Components\Section;
- use Filament\Resources\Pages\Page;
- use Filament\Resources\Pages\CreateRecord;
- use Illuminate\Database\Eloquent\Model;
- use Illuminate\Database\Eloquent\Collection;
- use Illuminate\Support\Facades\DB;
- class OCRRecordResource extends Resource
- {
- protected static ?string $model = OCRRecord::class;
- protected static ?string $slug = 'ocr-records-legacy';
- protected static ?string $modelLabel = 'OCR记录';
- protected static ?string $pluralModelLabel = 'OCR记录';
- protected static BackedEnum | string | null $navigationIcon = 'heroicon-o-camera';
- protected static ?string $navigationLabel = 'OCR识别记录';
- protected static ?int $navigationSort = 3;
- // 隐藏此Resource的导航,使用自定义DaisyUI页面
- protected static bool $shouldRegisterNavigation = false;
- public static function canCreate(): bool
- {
- return true;
- }
- public static function form(Schema $schema): Schema
- {
- return $schema->components([
- Select::make('student_id')
- ->label('选择学生')
- ->options(function () {
- return Student::query()
- ->orderBy('name')
- ->get()
- ->mapWithKeys(fn ($student) => [
- $student->student_id => "{$student->name} ({$student->grade} - {$student->class_name})"
- ]);
- })
- ->searchable()
- ->required(),
- FileUpload::make('image_path')
- ->label('卷子图片')
- ->image()
- ->directory('ocr-uploads')
- ->required()
- ->maxSize(10240)
- ->acceptedFileTypes(['image/jpeg', 'image/png', 'image/webp'])
- ->helperText('支持 JPG、PNG、WebP 格式,最大 10MB'),
- Hidden::make('status')
- ->default('pending'),
- Hidden::make('total_questions')
- ->default(0),
- Hidden::make('processed_questions')
- ->default(0),
- ]);
- }
- public static function table(Table $table): Table
- {
- return $table
- ->columns([
- Tables\Columns\TextColumn::make('student.name')
- ->label('学生姓名')
- ->searchable()
- ->sortable(),
- Tables\Columns\TextColumn::make('student.grade')
- ->label('年级')
- ->sortable(),
- Tables\Columns\TextColumn::make('student.class_name')
- ->label('班级')
- ->sortable(),
- Tables\Columns\TextColumn::make('image_filename')
- ->label('图片名称')
- ->searchable()
- ->wrap(),
- Tables\Columns\TextColumn::make('total_questions')
- ->label('题目总数')
- ->sortable()
- ->alignCenter(),
- Tables\Columns\TextColumn::make('processed_questions')
- ->label('已处理')
- ->sortable()
- ->alignCenter(),
- Tables\Columns\TextColumn::make('progress')
- ->label('处理进度')
- ->formatStateUsing(function ($record) {
- $total = $record->total_questions ?? 0;
- $processed = $record->processed_questions ?? 0;
- if ($total > 0) {
- return round(($processed / $total) * 100, 1) . '%';
- }
- return '-';
- })
- ->alignCenter(),
- Tables\Columns\TextColumn::make('confidence_avg')
- ->label('平均置信度')
- ->formatStateUsing(fn ($state) => $state ? round($state * 100, 2) . '%' : '-')
- ->color(fn ($state) => $state && $state > 0.7 ? 'success' : ($state && $state > 0.5 ? 'warning' : 'danger'))
- ->alignCenter(),
- Tables\Columns\TextColumn::make('status')
- ->label('状态')
- ->badge()
- ->formatStateUsing(fn (string $state): string => match ($state) {
- 'pending' => '待处理',
- 'processing' => '处理中',
- 'completed' => '已完成',
- 'failed' => '失败',
- default => $state,
- })
- ->color(fn (string $state): string => match ($state) {
- 'pending' => 'gray',
- 'processing' => 'info',
- 'completed' => 'success',
- 'failed' => 'danger',
- default => 'gray',
- })
- ->alignCenter(),
- Tables\Columns\TextColumn::make('created_at')
- ->label('创建时间')
- ->dateTime('Y-m-d H:i:s')
- ->sortable()
- ->toggleable(isToggledHiddenByDefault: false),
- Tables\Columns\TextColumn::make('processed_at')
- ->label('处理完成时间')
- ->dateTime('Y-m-d H:i:s')
- ->sortable()
- ->toggleable(isToggledHiddenByDefault: true),
- ])
- ->filters([
- Tables\Filters\SelectFilter::make('status')
- ->label('处理状态')
- ->options([
- 'pending' => '待处理',
- 'processing' => '处理中',
- 'completed' => '已完成',
- 'failed' => '失败',
- ]),
- Tables\Filters\SelectFilter::make('student_grade')
- ->label('年级')
- ->options(fn () => self::gradeOptions())
- ->query(function (Builder $query, array $data): void {
- if (!empty($data['value'])) {
- $query->whereHas('student', fn ($q) => $q->where('grade', $data['value']));
- }
- }),
- Tables\Filters\SelectFilter::make('student_class')
- ->label('班级')
- ->options(fn () => self::classOptions())
- ->query(function (Builder $query, array $data): void {
- if (!empty($data['value'])) {
- $query->whereHas('student', fn ($q) => $q->where('class_name', $data['value']));
- }
- }),
- Tables\Filters\Filter::make('created_today')
- ->label('今日创建')
- ->query(fn (Builder $query): Builder => $query->whereDate('created_at', today()))
- ->toggle(),
- ])
- ->actions([])
- ->defaultSort('created_at', 'desc')
- ->paginated([10, 25, 50, 100])
- ->poll('10s');
- }
- public static function getRelations(): array
- {
- return [
- //
- ];
- }
- public static function getPages(): array
- {
- return [
- 'index' => Pages\ListOCRRecords::route('/'),
- 'create' => Pages\CreateOCRRecord::route('/create'),
- 'view' => Pages\ViewOCRRecord::route('/{record}'),
- ];
- }
- protected static function gradeOptions(): array
- {
- return DB::table('students')
- ->distinct()
- ->pluck('grade', 'grade')
- ->toArray();
- }
- protected static function classOptions(): array
- {
- return DB::table('students')
- ->distinct()
- ->pluck('class_name', 'class_name')
- ->toArray();
- }
- public static function getRecordTitle(?Model $record): string|null
- {
- if (!$record) {
- return null;
- }
- $studentName = optional($record->student)->name ?? '未知学生';
- return "{$studentName} - {$record->image_filename}";
- }
- }
|