滙入大量歌手會有問題 修正 20250506

This commit is contained in:
allen.yan 2025-05-06 18:09:54 +08:00
parent 0821b16ac6
commit e748b7ff3d
8 changed files with 139 additions and 48 deletions

BIN
.DS_Store vendored

Binary file not shown.

BIN
app/.DS_Store vendored Normal file

Binary file not shown.

BIN
app/Enums/.DS_Store vendored Normal file

Binary file not shown.

View File

@ -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;

View File

@ -0,0 +1,42 @@
<?php
namespace App\Jobs;
use App\Imports\ArtistDataImport;
use Illuminate\Bus\Queueable;
use Illuminate\Support\Facades\Storage;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Maatwebsite\Excel\Facades\Excel;
//use Illuminate\Foundation\Queue\Queueable;
class ImportArtistJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
protected string $filePath;
public $timeout = 3600;
/**
* Create a new job instance.
*/
public function __construct(string $filePath)
{
$this->filePath = $filePath;
}
/**
* Execute the job.
*/
public function handle(): void
{
Excel::import(new ArtistDataImport, $this->filePath);
// 匯入完成後刪除檔案
if (Storage::exists($this->filePath)) {
Storage::delete($this->filePath);
}
}
}

View File

@ -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', '已排入背景匯入作業,請稍候查看結果');
}
}

View File

@ -3,33 +3,48 @@
{{-- 說明區塊 --}}
<div class="mb-4 p-4 bg-gray-100 border border-gray-300 rounded text-sm text-gray-700">
<p class="font-semibold mb-2">匯入格式說明</p>
<p class="mb-2">請依下列表格格式準備 CSV 檔案:</p>
<p class="mb-2">請依下列表格格式準備 Excel CSV 檔案:</p>
<div class="overflow-x-auto">
<table class="min-w-full text-sm text-left border border-collapse border-gray-300 mb-2">
<div class="overflow-x-auto mb-2">
<table class="min-w-full text-sm text-left border border-collapse border-gray-300">
<thead class="bg-gray-200">
<tr>
<th class="border border-gray-300 px-3 py-1">類別</th>
<th class="border border-gray-300 px-3 py-1">名稱</th>
<th class="border border-gray-300 px-3 py-1">欄位名稱</th>
<th class="border border-gray-300 px-3 py-1">說明</th>
<th class="border border-gray-300 px-3 py-1">範例</th>
</tr>
</thead>
<tbody>
<tr>
<td class="border border-gray-300 px-3 py-1"></td>
<td class="border border-gray-300 px-3 py-1">某男</td>
<td class="border border-gray-300 px-3 py-1">歌手姓名</td>
<td class="border border-gray-300 px-3 py-1">歌手姓名唯一</td>
<td class="border border-gray-300 px-3 py-1">田馥甄</td>
</tr>
<tr>
<td class="border border-gray-300 px-3 py-1">歌手注音</td>
<td class="border border-gray-300 px-3 py-1">歌手注音第一字碼</td>
<td class="border border-gray-300 px-3 py-1">ㄊㄈㄓ</td>
</tr>
<tr>
<td class="border border-gray-300 px-3 py-1">歌手分類</td>
<td class="border border-gray-300 px-3 py-1">男、女、團、外、其他</td>
<td class="border border-gray-300 px-3 py-1"></td>
<td class="border border-gray-300 px-3 py-1">某女</td>
</tr>
<tr>
<td class="border border-gray-300 px-3 py-1">狀態</td>
<td class="border border-gray-300 px-3 py-1">是否啟用1啟用0停用</td>
<td class="border border-gray-300 px-3 py-1">1</td>
</tr>
<tr>
<td class="border border-gray-300 px-3 py-1">歌手筆畫</td>
<td class="border border-gray-300 px-3 py-1">字首筆劃</td>
<td class="border border-gray-300 px-3 py-1">5</td>
</tr>
</tbody>
</table>
</div>
<p class="text-gray-600 text-xs">
類別欄位僅可使用:<strong></strong><strong></strong><strong></strong><strong></strong><strong>其他</strong>
</p>
</div>
{{-- 檔案上傳 --}}
<input type="file" wire:model="file" accept=".csv, .xls, .xlsx" class="mb-4 w-full" />

View File

@ -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
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