| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147 |
- <?php
- namespace App\Filament\Pages;
- use App\Services\QuestionBulkImportService;
- use BackedEnum;
- use Filament\Forms;
- use Filament\Notifications\Notification;
- use Filament\Pages\Page;
- use Filament\Schemas\Components\Section;
- use Filament\Schemas\Schema;
- use Filament\Support\Enums\Width;
- use Illuminate\Support\Facades\File;
- use Illuminate\Support\Facades\Storage;
- use UnitEnum;
- class QuestionsJsonImportPage extends Page implements Forms\Contracts\HasForms
- {
- use Forms\Concerns\InteractsWithForms;
- /**
- * 主入口在「待入库质检」页右侧;本页仅保留直达 URL,不出现在侧栏。
- */
- protected static bool $shouldRegisterNavigation = false;
- protected static ?string $title = '题库 JSON 一键导入';
- protected static string|BackedEnum|null $navigationIcon = 'heroicon-o-arrow-up-tray';
- protected static ?string $navigationLabel = 'JSON 一键导入';
- protected static string|UnitEnum|null $navigationGroup = '题库管理';
- protected static ?int $navigationSort = 6;
- /**
- * 固定路径,便于收藏与文档:/admin/questions-json-import
- */
- protected static ?string $slug = 'questions-json-import';
- protected Width|string|null $maxContentWidth = Width::Full;
- protected string $view = 'filament.pages.questions-json-import';
- /** @var array<string, mixed> */
- public array $data = [
- 'dry_run' => false,
- 'sql_only' => false,
- 'with_id' => false,
- ];
- public ?string $lastSqlPath = null;
- public ?string $lastMessage = null;
- public function mount(): void
- {
- $this->form->fill($this->data);
- }
- public function form(Schema $schema): Schema
- {
- return $schema
- ->schema([
- Section::make('从 JSON 导入 questions')
- ->description('支持整段 JSON 数组或 NDJSON(每行一题)。左侧选文件与选项,右侧点击「一键导入」执行。')
- ->schema([
- Forms\Components\FileUpload::make('json_file')
- ->label('JSON 文件')
- ->disk('local')
- ->directory('imports/questions')
- ->acceptedFileTypes(['application/json', 'text/plain', 'text/json'])
- ->maxSize(51200)
- ->helperText('最大约 50MB;字段含 question_code、kp_code、stem、options、answer、solution 等'),
- Forms\Components\Toggle::make('dry_run')
- ->label('仅校验(dry-run,不写库)')
- ->default(false),
- Forms\Components\Toggle::make('sql_only')
- ->label('仅生成 SQL(不写入本地 questions)')
- ->default(false),
- Forms\Components\Toggle::make('with_id')
- ->label('SQL 中含 id(仅当目标库必须对齐原主键时勾选;默认不含 id)')
- ->default(false),
- ])
- ->columns(1),
- ])
- ->statePath('data');
- }
- public function runImport(): void
- {
- $this->lastMessage = null;
- $this->lastSqlPath = null;
- $data = $this->data;
- $relative = $data['json_file'] ?? null;
- if (! is_string($relative) || $relative === '') {
- Notification::make()->title('请选择 JSON 文件')->warning()->send();
- return;
- }
- $fullPath = Storage::disk('local')->path($relative);
- if (! File::isFile($fullPath)) {
- Notification::make()->title('文件不存在')->body($fullPath)->danger()->send();
- return;
- }
- $dryRun = (bool) ($data['dry_run'] ?? false);
- $sqlOnly = (bool) ($data['sql_only'] ?? false);
- $withId = (bool) ($data['with_id'] ?? false);
- $service = app(QuestionBulkImportService::class);
- $pipeline = $service->runImportPipeline($fullPath, $dryRun, $sqlOnly, $withId);
- if (! $pipeline['ok']) {
- Notification::make()->title('导入失败')->body($pipeline['error'] ?? '')->danger()->send();
- return;
- }
- $this->lastSqlPath = $pipeline['sql_path'] ?? null;
- $this->lastMessage = $pipeline['message'] ?? null;
- if ($sqlOnly) {
- Notification::make()->title('SQL 已生成')->body($this->lastSqlPath ?? '')->success()->send();
- return;
- }
- $body = (string) $this->lastMessage;
- $stats = $pipeline['stats'] ?? null;
- if (is_array($stats) && $stats['errors'] !== []) {
- $body .= "\n".implode("\n", array_slice($stats['errors'], 0, 8));
- if (count($stats['errors']) > 8) {
- $body .= "\n… 另有 ".(count($stats['errors']) - 8).' 条错误';
- }
- }
- Notification::make()
- ->title($dryRun ? '校验完成(dry-run)' : '导入完成')
- ->body($body)
- ->success()
- ->send();
- }
- }
|