KTV/app/Jobs/ImportSongChunkJob.php
allen.yan ea0e10bb64 修正滙入功能 與寫相關記錄
修正滙入時暫存檔不會刪的問題
20250510
2025-05-10 19:41:43 +08:00

187 lines
7.1 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
namespace App\Jobs;
use App\Models\Song;
use App\Models\Artist;
use App\Models\SongCategory;
use App\Enums\ArtistCategory;
use App\Enums\SongLanguageType;
use App\Enums\SongSituation;
use App\Helpers\ChineseNameConverter;
use App\Helpers\ChineseStrokesConverter;
use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Log;
class ImportSongChunkJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
protected Collection $rows;
protected String $id;
protected array $categoryMap = [];
protected array $artistCache =[];
public function __construct(Collection $rows,String $id)
{
$this->rows = $rows;
$this->id = $id;
$this->categoryMap = SongCategory::pluck('id', 'code')->toArray();
}
public function handle(): void
{
Log::warning('匯入啟動', [
'model' => "ImportSongChunkJob",
'rows_id' =>$this->id,
]);
$ToInsert = [];
$artistMap = [];
$categoryMap = [];
foreach ($this->rows as $index => $row) {
$songId = trim($row['編號'] ?? '');
if (!$songId || Song::where('id', $songId)->exists()) {
continue;
}
try {
// 字元處理
$songName=trim($row['歌名'] ?? '');
$simplified=ChineseNameConverter::convertToSimplified($songName);// 繁體轉簡體
if (!$row->has('注音')) {
$phoneticAbbr = ChineseNameConverter::getKTVZhuyinAbbr($simplified);// 注音符號
} else {
$phoneticAbbr = trim($row['注音'] ?? '');
}
if (!$row->has('拼音')) {
$pinyinAbbr = ChineseNameConverter::getKTVPinyinAbbr($simplified);// 拼音首字母
} else {
$pinyinAbbr = trim($row['拼音'] ?? '');
}
if (!$row->has('kk3')) {//歌名第一個字筆畫
$chars = preg_split('//u', $songName, -1, PREG_SPLIT_NO_EMPTY);
$firstChar = $chars[0] ?? null;
$strokesAbbr=( $firstChar && preg_match('/\p{Han}/u', $firstChar) )? ChineseStrokesConverter::getStrokes($firstChar) : 0;
} else {
$strokesAbbr=trim($row['kk3'] ?? 0);
}
if (!$row->has('kk4')) {//歌名字數
$songNumber = mb_strlen($songName, 'UTF-8');
} else {
$songNumber=trim($row['kk4'] ?? 0);
}
// 準備 song 資料
$ToInsert[] = [
'id' => $songId,
'name' => $this->formatText($row['歌名']),
'adddate' => $this->parseExcelDate($row['日期'] ?? null),
'filename' => trim($row['檔名'] ?? ''),
'language_type' => SongLanguageType::tryFrom(trim($row['語別'] ?? '')) ?? SongLanguageType::Unset,
'db_change' => trim($row['kk2'] ?? 0),//分貝增減
'vocal' => trim($row['kk6'] ?? 0),//人聲
'situation' => SongSituation::tryFrom(trim($row['kk7'] ?? '')) ?? SongSituation::Unset,//情境
'copyright01' => trim($row['版權01'] ?? ''),
'copyright02' => trim($row['版權02'] ?? ''),
'note01' => trim($row['版權03'] ?? ''),
'note02' => trim($row['版權04'] ?? ''),
'note03' => trim($row['版權05'] ?? ''),
'note04' => trim($row['版權06'] ?? ''),
'enable' => trim($row['狀態'] ?? 1),
'simplified' => $simplified,
'phonetic_abbr' => $phoneticAbbr,
'pinyin_abbr' => $pinyinAbbr,
'strokes_abbr' => $strokesAbbr,
'song_number' => $songNumber,
'song_counts' => trim($row['點播次數'] ?? 0),
];
// 處理關聯 - 歌手
$artistIds = [];
foreach (['歌星A', '歌星B'] as $key) {
$artistName = trim($row[$key] ?? '');
if ($artistName === '') continue;
// 若是歌星B且與歌星A相同則跳過
if ($key === '歌星B' && $artistName === trim($row['歌星A'] ?? '')) continue;
$artistMap[$songId][] = $this->getOrCreateArtistId($artistName);
}
// 分類處理(多個用 , 分隔)
if (!empty($row['分類'])) {
$categoryIds = [];
$codes = explode(',', $row['分類']);
foreach ($codes as $code) {
$code = trim($code);
if (isset($this->categoryMap[$code])) {
$categoryMap[$songId][] = $this->categoryMap[$code];
}
}
}
} catch (\Throwable $e) {
\Log::error("Row {$index} failed: {$e->getMessage()}", [
'row' => $row,
'trace' => $e->getTraceAsString()
]);
}
}
// 寫入資料庫
Song::insert($ToInsert);
// 同步關聯(建議可用事件或批次處理)
foreach ($artistMap as $songId => $artistIds) {
$song = Song::find($songId);
if ($song) {
$song->artists()->sync($artistIds);
}
}
foreach ($categoryMap as $songId => $categoryIds) {
$song = Song::find($songId);
if ($song) {
$song->categories()->sync($categoryIds);
}
}
}
private function getOrCreateArtistId(string $name): int
{
if (isset($this->artistCache[$name])) {
return $this->artistCache[$name];
}
$artist = Artist::firstOrCreate(
['name' => $name],
['category' => ArtistCategory::Unset]
);
return $this->artistCache[$name] = $artist->id;
}
protected function formatText($value)
{
if (is_numeric($value) && $value < 1 && $value > 0) {
// 嘗試判斷為時間類型的小數,轉為時間字串
$time = \PhpOffice\PhpSpreadsheet\Shared\Date::excelToDateTimeObject($value);
return $time->format('H:i');
}
return trim((string) $value);
}
private function parseExcelDate($value): ?string
{
if (is_numeric($value)) {
return \Carbon\Carbon::createFromFormat('Y-m-d', '1900-01-01')
->addDays((int)$value - 2)
->format('Y-m-d');
}
try {
return \Carbon\Carbon::parse($value)->format('Y-m-d');
} catch (\Exception $e) {
return null;
}
}
}