diff --git a/.DS_Store b/.DS_Store index 6549c6a..7df8564 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/app/.DS_Store b/app/.DS_Store new file mode 100644 index 0000000..a5cbae3 Binary files /dev/null and b/app/.DS_Store differ diff --git a/app/Enums/.DS_Store b/app/Enums/.DS_Store new file mode 100644 index 0000000..5008ddf Binary files /dev/null and b/app/Enums/.DS_Store differ diff --git a/app/Imports/ArtistDataImport.php b/app/Imports/ArtistDataImport.php index 0862372..0a7cd80 100644 --- a/app/Imports/ArtistDataImport.php +++ b/app/Imports/ArtistDataImport.php @@ -4,44 +4,69 @@ namespace App\Imports; use App\Models\Artist; use App\Enums\ArtistCategory; -use Maatwebsite\Excel\Concerns\ToModel; +use App\Helpers\ChineseNameConverter; +use App\Helpers\ChineseStrokesConverter; +use Illuminate\Support\Collection; +use Maatwebsite\Excel\Concerns\ToCollection; use Maatwebsite\Excel\Concerns\WithHeadingRow; +use Maatwebsite\Excel\Concerns\WithChunkReading; +use Maatwebsite\Excel\Concerns\WithBatchInserts; use Maatwebsite\Excel\Imports\HeadingRowFormatter; -class ArtistDataImport implements ToModel, WithHeadingRow +class ArtistDataImport implements ToCollection, WithHeadingRow, WithChunkReading, WithBatchInserts { - public int $successCount = 0; - public int $failCount = 0; - + public function __construct() { // 關閉 heading row 格式化 HeadingRowFormatter::default('none'); } - - public function model(array $row) + public function collection(Collection $rows) { - $name = trim($row['名稱'] ?? ''); - $category = trim($row['類別'] ?? '未定義'); - $enable = trim($row['狀態'] ?? 1); - if (empty($name)) { - $this->failCount++; - return null; - } + $toInsert = []; - try { - Artist::firstOrCreate( - ['name' => $name], - ['category' => ArtistCategory::tryFrom($category) ?? ArtistCategory::Unset], - ['enable' => $enable], - ); - $this->successCount++; - } catch (\Throwable $e) { - $this->failCount++; + foreach ($rows as $row) { + $name=trim($row['歌手姓名'] ?? ''); + if (empty($name)) continue; + + // 字元處理 + $simplified = ChineseNameConverter::convertToSimplified($name); + if (!array_key_exists('歌手注音', $row)) { + $phoneticAbbr = ChineseNameConverter::getKTVZhuyinAbbr($simplified); + } else { + $phoneticAbbr = trim($row['歌手注音']); + } + $pinyinAbbr = ChineseNameConverter::getKTVPinyinAbbr($simplified); + if (!array_key_exists('歌手注音', $row)) { + $chars = preg_split('//u', $name, -1, PREG_SPLIT_NO_EMPTY); + $firstChar = $chars[0] ?? null; + $strokesAbbr = $firstChar ? ChineseStrokesConverter::getStrokes($firstChar) : null; + } else { + $strokesAbbr = trim($row['歌手筆畫']); + } + // 準備 song 資料 + $toInsert[] = [ + 'name' => $name, + 'category' => ArtistCategory::tryFrom(trim($row['歌手分類'] ?? '未定義')) ?? ArtistCategory::Unset, + 'simplified' => $simplified, + 'phonetic_abbr' => $phoneticAbbr, + 'pinyin_abbr' => $pinyinAbbr, + 'strokes_abbr' => $strokesAbbr, + 'enable' =>trim($row['狀態'] ?? 1) + ]; } - - return null; + Artist::insert($toInsert); } + + public function chunkSize(): int + { + return 100; + } + public function batchSize(): int + { + return 100; + } + public function headingRow(): int { return 1; diff --git a/app/Jobs/ImportArtistJob.php b/app/Jobs/ImportArtistJob.php new file mode 100644 index 0000000..1ed62af --- /dev/null +++ b/app/Jobs/ImportArtistJob.php @@ -0,0 +1,42 @@ +filePath = $filePath; + } + + /** + * Execute the job. + */ + public function handle(): void + { + Excel::import(new ArtistDataImport, $this->filePath); + // 匯入完成後刪除檔案 + if (Storage::exists($this->filePath)) { + Storage::delete($this->filePath); + } + } +} diff --git a/app/Livewire/Admin/ArtistImportData.php b/app/Livewire/Admin/ArtistImportData.php index d14b4d4..9b94084 100644 --- a/app/Livewire/Admin/ArtistImportData.php +++ b/app/Livewire/Admin/ArtistImportData.php @@ -5,8 +5,8 @@ namespace App\Livewire\Admin; use Illuminate\Support\Facades\Auth; use Livewire\Component; use Livewire\WithFileUploads; -use Maatwebsite\Excel\Facades\Excel; -use App\Imports\ArtistDataImport; +use App\Jobs\ImportArtistJob; +use Illuminate\Support\Facades\Storage; class ArtistImportData extends Component { @@ -41,13 +41,15 @@ class ArtistImportData extends Component 'file' => 'required|file|mimes:csv,xlsx,xls' ]); if ($this->canCreate) { - $import = new ArtistDataImport(); - Excel::import($import, $this->file); - $success = $import->successCount; - $fail = $import->failCount; + // 儲存檔案至 storage + $path = $this->file->storeAs('imports', uniqid() . '_' . $this->file->getClientOriginalName()); + + // 丟到 queue 執行 + ImportArtistJob::dispatch($path); + $this->reset('file'); - $this->showModal =false; - session()->flash('message', '匯入完成:成功 $success 筆,失敗 $fail 筆。'); + $this->showModal = false; + session()->flash('message', '已排入背景匯入作業,請稍候查看結果'); } } diff --git a/resources/views/livewire/admin/artist-import-data.blade.php b/resources/views/livewire/admin/artist-import-data.blade.php index ae378cf..5793060 100644 --- a/resources/views/livewire/admin/artist-import-data.blade.php +++ b/resources/views/livewire/admin/artist-import-data.blade.php @@ -3,33 +3,48 @@ {{-- 說明區塊 --}}
匯入格式說明
-請依下列表格格式準備 CSV 檔案:
+請依下列表格格式準備 Excel 或 CSV 檔案:
-類別 | -名稱 | +欄位名稱 | +說明 | +範例 |
---|---|---|---|---|
男 | -某男 | +歌手姓名 | +歌手姓名唯一 | +田馥甄 |
歌手注音 | +歌手注音第一字碼 | +ㄊㄈㄓ | +||
歌手分類 | +男、女、團、外、其他 | 女 | -某女 | +|
狀態 | +是否啟用(1:啟用,0:停用) | +1 | +||
歌手筆畫 | +字首筆劃 | +5 |
- ※ 類別欄位僅可使用:男、女、團、外、其他。 -
+ {{-- 檔案上傳 --}} diff --git a/開發手冊.ini b/開發手冊.ini index aeb9722..cb71e1a 100644 --- a/開發手冊.ini +++ b/開發手冊.ini @@ -82,6 +82,13 @@ php artisan make:livewire Admin/ArtistForm php artisan make:livewire Admin/SongForm -php artisan make:model Branches -m -php artisan make:model Rooms -m -php artisan make:model RoomStatusLogs -m \ No newline at end of file +php artisan make:model OperationLog -m + +php artisan make:observer GenericObserver --model=OperationLog + +php artisan make:model Branch -m +php artisan make:model Room -m +php artisan make:model RoomStatusLog -m + +php artisan make:observer RoomObserver --model=Room +