importer = app(TextbookExcelImporter::class); $this->apiService = app(TextbookApiService::class); } public function mount() { $this->importer = app(TextbookExcelImporter::class); $this->apiService = app(TextbookApiService::class); // 检查URL参数,设置默认导入类型 $type = request()->get('type'); if (in_array($type, ['textbook_series', 'textbook', 'textbook_catalog'])) { $this->selectedType = $type; } } public function getHeaderActions(): array { return [ Action::make('downloadTemplate') ->label('下载模板') ->icon('heroicon-o-arrow-down-tray') ->color('primary') ->action('downloadTemplate'), Action::make('import') ->label('导入数据') ->icon('heroicon-o-cloud-arrow-up') ->color('success') ->action('importData') ->requiresConfirmation() ->modalHeading('确认导入') ->modalDescription('确定要导入Excel文件中的数据吗?此操作将同步到题库服务。') ->modalSubmitActionLabel('确认导入'), ]; } public function downloadTemplate() { try { $importer = app(TextbookExcelImporter::class); if ($this->selectedType === 'textbook_series') { $filePath = $importer->generateTextbookSeriesTemplate(); $fileName = '教材系列导入模板.xlsx'; } elseif ($this->selectedType === 'textbook') { $filePath = $importer->generateTextbookTemplate(); $fileName = '教材导入模板.xlsx'; } else { $filePath = $importer->generateTextbookCatalogTemplate(); $fileName = '教材目录导入模板.xlsx'; } return response()->download($filePath, $fileName)->deleteFileAfterSend(); } catch (\Exception $e) { Notification::make() ->title('模板生成失败') ->body($e->getMessage()) ->danger() ->send(); } } public function importData() { $this->validate(); $temporaryPath = null; $finalPath = null; try { $importer = app(TextbookExcelImporter::class); // 获取文件的临时路径(Livewire 上传的文件会有临时路径) $temporaryPath = $this->file->getRealPath(); if (!$temporaryPath || !file_exists($temporaryPath)) { throw new \Exception('文件上传失败,请重新上传'); } // 检查文件是否可读 if (!is_readable($temporaryPath)) { throw new \Exception('文件不可读,请检查文件权限'); } // 调试信息 Log::info('文件上传信息', [ 'original_name' => $this->file->getClientOriginalName(), 'temporary_path' => $temporaryPath, 'exists' => file_exists($temporaryPath), 'is_file' => is_file($temporaryPath), 'readable' => is_readable($temporaryPath), 'file_size' => filesize($temporaryPath), 'mime_type' => $this->file->getMimeType(), ]); // 执行导入 - 直接使用临时路径 if ($this->selectedType === 'textbook_series') { $result = $importer->importTextbookSeries($temporaryPath); } elseif ($this->selectedType === 'textbook') { $result = $importer->importTextbook($temporaryPath); } else { // 教材目录导入 - 需要从Excel中获取textbook_id $spreadsheet = IOFactory::load($temporaryPath); $sheet = $spreadsheet->getActiveSheet(); $data = $sheet->toArray(); $header = $data[0] ?? []; $textbookIdIndex = 0; $seriesIdIndex = null; foreach ($header as $index => $label) { $label = trim((string) $label); if ($label !== '' && str_contains($label, '教材ID')) { $textbookIdIndex = $index; } if ($label !== '' && str_contains($label, '系列ID')) { $seriesIdIndex = $index; } } $textbookId = 0; $seriesId = null; foreach (array_slice($data, 1) as $row) { $candidate = (int) ($row[$textbookIdIndex] ?? 0); if ($candidate > 0) { $textbookId = $candidate; break; } } if ($seriesIdIndex !== null) { foreach (array_slice($data, 1) as $row) { $candidate = (int) ($row[$seriesIdIndex] ?? 0); if ($candidate > 0) { $seriesId = $candidate; break; } } } if ($textbookId <= 0) { throw new \Exception('Excel文件中未找到有效的教材ID,请确保第一列包含教材ID'); } $result = $importer->importTextbookCatalog($temporaryPath, $textbookId, $seriesId); } $this->importResult = $result; if ($result['success']) { $message = sprintf( '导入完成!成功: %d 条,失败: %d 条', $result['success_count'], $result['error_count'] ); Notification::make() ->title('导入成功') ->body($message) ->success() ->send(); } else { Notification::make() ->title('导入失败') ->body($result['message']) ->danger() ->send(); } } catch (\Exception $e) { Notification::make() ->title('导入失败') ->body($e->getMessage()) ->danger() ->send(); Log::error('Excel导入失败', [ 'error' => $e->getMessage(), 'temporary_path' => $temporaryPath, 'final_path' => $finalPath, 'trace' => $e->getTraceAsString(), ]); } // 不需要手动删除文件,临时文件会在请求结束后自动清理 } }