TextbookExcelImportPage.php 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. <?php
  2. namespace App\Filament\Pages\TextbookImport;
  3. use App\Services\Import\TextbookExcelImporter;
  4. use App\Services\TextbookApiService;
  5. use PhpOffice\PhpSpreadsheet\IOFactory;
  6. use Filament\Pages\Page;
  7. use UnitEnum;
  8. use BackedEnum;
  9. use Filament\Actions\Action;
  10. use Filament\Forms;
  11. use Filament\Forms\Components\FileUpload;
  12. use Filament\Notifications\Notification;
  13. use Illuminate\Support\Facades\Storage;
  14. use Illuminate\Support\Facades\Log;
  15. use Livewire\WithFileUploads;
  16. use Livewire\Component;
  17. use Livewire\Attributes\Validate;
  18. class TextbookExcelImportPage extends Page
  19. {
  20. use WithFileUploads;
  21. protected static string|BackedEnum|null $navigationIcon = 'heroicon-o-document-arrow-up';
  22. protected static ?string $navigationLabel = 'Excel导入';
  23. protected static UnitEnum|string|null $navigationGroup = '教材管理';
  24. protected static ?int $navigationSort = 4;
  25. public string $view = 'filament.pages.textbook-import';
  26. #[Validate('required|string')]
  27. public $selectedType = 'textbook_series';
  28. #[Validate('required|file|mimes:xlsx,xls|max:10240')]
  29. public $file;
  30. public $importResult = null;
  31. protected $importer;
  32. protected $apiService;
  33. public function boot()
  34. {
  35. $this->importer = app(TextbookExcelImporter::class);
  36. $this->apiService = app(TextbookApiService::class);
  37. }
  38. public function mount()
  39. {
  40. $this->importer = app(TextbookExcelImporter::class);
  41. $this->apiService = app(TextbookApiService::class);
  42. // 检查URL参数,设置默认导入类型
  43. $type = request()->get('type');
  44. if (in_array($type, ['textbook_series', 'textbook', 'textbook_catalog'])) {
  45. $this->selectedType = $type;
  46. }
  47. }
  48. public function getHeaderActions(): array
  49. {
  50. return [
  51. Action::make('downloadTemplate')
  52. ->label('下载模板')
  53. ->icon('heroicon-o-arrow-down-tray')
  54. ->color('primary')
  55. ->action('downloadTemplate'),
  56. Action::make('import')
  57. ->label('导入数据')
  58. ->icon('heroicon-o-cloud-arrow-up')
  59. ->color('success')
  60. ->action('importData')
  61. ->requiresConfirmation()
  62. ->modalHeading('确认导入')
  63. ->modalDescription('确定要导入Excel文件中的数据吗?此操作将同步到题库服务。')
  64. ->modalSubmitActionLabel('确认导入'),
  65. ];
  66. }
  67. public function downloadTemplate()
  68. {
  69. try {
  70. $importer = app(TextbookExcelImporter::class);
  71. if ($this->selectedType === 'textbook_series') {
  72. $filePath = $importer->generateTextbookSeriesTemplate();
  73. $fileName = '教材系列导入模板.xlsx';
  74. } elseif ($this->selectedType === 'textbook') {
  75. $filePath = $importer->generateTextbookTemplate();
  76. $fileName = '教材导入模板.xlsx';
  77. } else {
  78. $filePath = $importer->generateTextbookCatalogTemplate();
  79. $fileName = '教材目录导入模板.xlsx';
  80. }
  81. return response()->download($filePath, $fileName)->deleteFileAfterSend();
  82. } catch (\Exception $e) {
  83. Notification::make()
  84. ->title('模板生成失败')
  85. ->body($e->getMessage())
  86. ->danger()
  87. ->send();
  88. }
  89. }
  90. public function importData()
  91. {
  92. $this->validate();
  93. try {
  94. $importer = app(TextbookExcelImporter::class);
  95. // 保存上传的文件
  96. $path = $this->file->store('imports', 'local');
  97. // 获取完整文件路径
  98. $fullPath = storage_path('app/' . $path);
  99. // 执行导入
  100. if ($this->selectedType === 'textbook_series') {
  101. $result = $importer->importTextbookSeries($fullPath);
  102. } elseif ($this->selectedType === 'textbook') {
  103. $result = $importer->importTextbook($fullPath);
  104. } else {
  105. // 教材目录导入 - 需要从Excel中获取textbook_id
  106. $spreadsheet = IOFactory::load($fullPath);
  107. $sheet = $spreadsheet->getActiveSheet();
  108. $data = $sheet->toArray();
  109. // 获取第一行数据中的教材ID
  110. $firstRow = $data[1] ?? [];
  111. $textbookId = (int)($firstRow[0] ?? 0);
  112. if ($textbookId <= 0) {
  113. throw new \Exception('Excel文件中未找到有效的教材ID,请确保第一列包含教材ID');
  114. }
  115. $result = $importer->importTextbookCatalog($fullPath, $textbookId);
  116. }
  117. // 删除临时文件
  118. Storage::disk('local')->delete($path);
  119. $this->importResult = $result;
  120. if ($result['success']) {
  121. $message = sprintf(
  122. '导入完成!成功: %d 条,失败: %d 条',
  123. $result['success_count'],
  124. $result['error_count']
  125. );
  126. Notification::make()
  127. ->title('导入成功')
  128. ->body($message)
  129. ->success()
  130. ->send();
  131. } else {
  132. Notification::make()
  133. ->title('导入失败')
  134. ->body($result['message'])
  135. ->danger()
  136. ->send();
  137. }
  138. } catch (\Exception $e) {
  139. Notification::make()
  140. ->title('导入失败')
  141. ->body($e->getMessage())
  142. ->danger()
  143. ->send();
  144. Log::error('Excel导入失败', ['error' => $e->getMessage()]);
  145. }
  146. }
  147. }