加入完成訊息
song 滙入大量歌曲會有問題 修正 加入 歌曲字數 加入 檔案完成後刪除功能 加入 暫存檔案刪除功能 20250507
This commit is contained in:
parent
0969a07a3e
commit
c1125ae141
@ -23,21 +23,31 @@ class ArtistDataImport implements ToCollection, WithHeadingRow, WithChunkReading
|
|||||||
}
|
}
|
||||||
public function collection(Collection $rows)
|
public function collection(Collection $rows)
|
||||||
{
|
{
|
||||||
$toInsert = [];
|
// 建立現有歌手名稱的查找表,避免重複建立
|
||||||
|
static $existingNames = null;
|
||||||
|
|
||||||
|
if ($existingNames === null) {
|
||||||
|
$existingNames = array_flip(array_map('trim', Artist::pluck('name')->all()));
|
||||||
|
}
|
||||||
|
|
||||||
|
$toInsert = [];
|
||||||
|
|
||||||
foreach ($rows as $row) {
|
foreach ($rows as $row) {
|
||||||
$name=trim($row['歌手姓名'] ?? '');
|
$name=trim($row['歌手姓名'] ?? '');
|
||||||
if (empty($name)) continue;
|
if (empty($name)) continue;
|
||||||
|
|
||||||
|
// 若資料庫已有該名稱,跳過
|
||||||
|
if (isset($existingNames[$name])) continue;
|
||||||
|
|
||||||
// 字元處理
|
// 字元處理
|
||||||
$simplified = ChineseNameConverter::convertToSimplified($name);
|
$simplified = ChineseNameConverter::convertToSimplified($name);
|
||||||
if (!array_key_exists('歌手注音', $row)) {
|
if (!$row->has('歌手注音')) {
|
||||||
$phoneticAbbr = ChineseNameConverter::getKTVZhuyinAbbr($simplified);
|
$phoneticAbbr = ChineseNameConverter::getKTVZhuyinAbbr($simplified);
|
||||||
} else {
|
} else {
|
||||||
$phoneticAbbr = trim($row['歌手注音']);
|
$phoneticAbbr = trim($row['歌手注音']);
|
||||||
}
|
}
|
||||||
$pinyinAbbr = ChineseNameConverter::getKTVPinyinAbbr($simplified);
|
$pinyinAbbr = ChineseNameConverter::getKTVPinyinAbbr($simplified);
|
||||||
if (!array_key_exists('歌手注音', $row)) {
|
if (!$row->has('歌手筆畫')) {
|
||||||
$chars = preg_split('//u', $name, -1, PREG_SPLIT_NO_EMPTY);
|
$chars = preg_split('//u', $name, -1, PREG_SPLIT_NO_EMPTY);
|
||||||
$firstChar = $chars[0] ?? null;
|
$firstChar = $chars[0] ?? null;
|
||||||
$strokesAbbr = $firstChar ? ChineseStrokesConverter::getStrokes($firstChar) : null;
|
$strokesAbbr = $firstChar ? ChineseStrokesConverter::getStrokes($firstChar) : null;
|
||||||
@ -45,6 +55,7 @@ class ArtistDataImport implements ToCollection, WithHeadingRow, WithChunkReading
|
|||||||
$strokesAbbr = trim($row['歌手筆畫']);
|
$strokesAbbr = trim($row['歌手筆畫']);
|
||||||
}
|
}
|
||||||
// 準備 song 資料
|
// 準備 song 資料
|
||||||
|
$now = now();
|
||||||
$toInsert[] = [
|
$toInsert[] = [
|
||||||
'name' => $name,
|
'name' => $name,
|
||||||
'category' => ArtistCategory::tryFrom(trim($row['歌手分類'] ?? '未定義')) ?? ArtistCategory::Unset,
|
'category' => ArtistCategory::tryFrom(trim($row['歌手分類'] ?? '未定義')) ?? ArtistCategory::Unset,
|
||||||
@ -52,8 +63,13 @@ class ArtistDataImport implements ToCollection, WithHeadingRow, WithChunkReading
|
|||||||
'phonetic_abbr' => $phoneticAbbr,
|
'phonetic_abbr' => $phoneticAbbr,
|
||||||
'pinyin_abbr' => $pinyinAbbr,
|
'pinyin_abbr' => $pinyinAbbr,
|
||||||
'strokes_abbr' => $strokesAbbr,
|
'strokes_abbr' => $strokesAbbr,
|
||||||
'enable' =>trim($row['狀態'] ?? 1)
|
'enable' =>trim($row['狀態'] ?? 1),
|
||||||
|
'created_at' => $now,
|
||||||
|
'updated_at' => $now,
|
||||||
];
|
];
|
||||||
|
|
||||||
|
// 新增到快取,避免後面重複匯入
|
||||||
|
$existingNames[$name] = true;
|
||||||
}
|
}
|
||||||
Artist::insert($toInsert);
|
Artist::insert($toInsert);
|
||||||
}
|
}
|
||||||
|
@ -8,12 +8,15 @@ use App\Models\SongCategory;
|
|||||||
use App\Enums\ArtistCategory;
|
use App\Enums\ArtistCategory;
|
||||||
use App\Enums\SongLanguageType;
|
use App\Enums\SongLanguageType;
|
||||||
use App\Enums\SongSituation;
|
use App\Enums\SongSituation;
|
||||||
|
use App\Helpers\ChineseNameConverter;
|
||||||
|
use App\Helpers\ChineseStrokesConverter;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
use Illuminate\Support\Str;
|
use Illuminate\Support\Str;
|
||||||
use Illuminate\Support\Facades\Log;
|
use Illuminate\Support\Facades\Log;
|
||||||
use Maatwebsite\Excel\Concerns\ToCollection;
|
use Maatwebsite\Excel\Concerns\ToCollection;
|
||||||
use Maatwebsite\Excel\Concerns\WithHeadingRow;
|
use Maatwebsite\Excel\Concerns\WithHeadingRow;
|
||||||
use Maatwebsite\Excel\Concerns\WithChunkReading;
|
use Maatwebsite\Excel\Concerns\WithChunkReading;
|
||||||
|
use Maatwebsite\Excel\Imports\HeadingRowFormatter;
|
||||||
|
|
||||||
class SongDataImport implements ToCollection, WithHeadingRow, WithChunkReading
|
class SongDataImport implements ToCollection, WithHeadingRow, WithChunkReading
|
||||||
{
|
{
|
||||||
@ -22,13 +25,22 @@ class SongDataImport implements ToCollection, WithHeadingRow, WithChunkReading
|
|||||||
|
|
||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
|
// 關閉 heading row 格式化
|
||||||
|
HeadingRowFormatter::default('none');
|
||||||
// 快取分類代碼對應 ID
|
// 快取分類代碼對應 ID
|
||||||
$this->categoryMap = SongCategory::pluck('id', 'code')->toArray();
|
$this->categoryMap = SongCategory::pluck('id', 'code')->toArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function collection(Collection $rows)
|
public function collection(Collection $rows)
|
||||||
{
|
{
|
||||||
$songsToInsert = [];
|
// 建立現有歌手名稱的查找表,避免重複建立
|
||||||
|
static $existingIDs = null;
|
||||||
|
|
||||||
|
if ($existingIDs === null) {
|
||||||
|
$existingIDs = array_flip(array_map('trim', Song::pluck('id')->all()));
|
||||||
|
}
|
||||||
|
|
||||||
|
$ToInsert = [];
|
||||||
$artistMap = []; // [song_id => [artist_id]]
|
$artistMap = []; // [song_id => [artist_id]]
|
||||||
$categoryMap = []; // [song_id => [category_id]]
|
$categoryMap = []; // [song_id => [category_id]]
|
||||||
|
|
||||||
@ -38,32 +50,69 @@ class SongDataImport implements ToCollection, WithHeadingRow, WithChunkReading
|
|||||||
if (!$songId) {
|
if (!$songId) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
// 若資料庫已有該編號,跳過
|
||||||
|
if (isset($existingIDs[$songId])) continue;
|
||||||
|
|
||||||
|
// 字元處理
|
||||||
|
$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 ? ChineseStrokesConverter::getStrokes($firstChar) : null;
|
||||||
|
} else {
|
||||||
|
$strokesAbbr=trim($row['kk3'] ?? 0);
|
||||||
|
}
|
||||||
|
if (!$row->has('kk4')) {//歌名字數
|
||||||
|
$songNumber = mb_strlen($songName, 'UTF-8');
|
||||||
|
} else {
|
||||||
|
$songNumber=trim($row['kk4'] ?? 0);
|
||||||
|
}
|
||||||
|
|
||||||
// 準備 song 資料
|
// 準備 song 資料
|
||||||
$songsToInsert[] = [
|
$ToInsert[] = [
|
||||||
'id' => $songId,
|
'id' => $songId,
|
||||||
'name' => trim($row['歌名'] ?? ''),
|
'name' => $songName,
|
||||||
'adddate' => trim($row['日期'] ?? null),
|
'adddate' => trim($row['日期'] ?? null),
|
||||||
'filename' => trim($row['檔名'] ?? ''),
|
'filename' => trim($row['檔名'] ?? ''),
|
||||||
'language_type' => SongLanguageType::tryFrom(trim($row['語別'] ?? '')) ?? SongLanguageType::Unset,
|
'language_type' => SongLanguageType::tryFrom(trim($row['語別'] ?? '')) ?? SongLanguageType::Unset,
|
||||||
'db_change' => trim($row['分貝增減'] ?? 0),
|
'db_change' => trim($row['kk2'] ?? 0),//分貝增減
|
||||||
'vocal' => trim($row['人聲'] ?? 0),
|
'vocal' => trim($row['kk6'] ?? 0),//人聲
|
||||||
'situation' => SongSituation::tryFrom(trim($row['情境'] ?? '')) ?? SongSituation::Unset,
|
'situation' => SongSituation::tryFrom(trim($row['kk7'] ?? '')) ?? SongSituation::Unset,//情境
|
||||||
'copyright01' => trim($row['版權01'] ?? ''),
|
'copyright01' => trim($row['版權01'] ?? ''),
|
||||||
'copyright02' => trim($row['版權02'] ?? ''),
|
'copyright02' => trim($row['版權02'] ?? ''),
|
||||||
'note01' => trim($row['備註01'] ?? ''),
|
'note01' => trim($row['版權03'] ?? ''),
|
||||||
'note02' => trim($row['備註02'] ?? ''),
|
'note02' => trim($row['版權04'] ?? ''),
|
||||||
'note03' => trim($row['備註03'] ?? ''),
|
'note03' => trim($row['版權05'] ?? ''),
|
||||||
'note04' => trim($row['備註04'] ?? ''),
|
'note04' => trim($row['版權06'] ?? ''),
|
||||||
'enable' => trim($row['狀態'] ?? 1),
|
'enable' => trim($row['狀態'] ?? 1),
|
||||||
|
|
||||||
|
'simplified' => $simplified,
|
||||||
|
'phonetic_abbr' => $phoneticAbbr,
|
||||||
|
'pinyin_abbr' => $pinyinAbbr,
|
||||||
|
'strokes_abbr' => $strokesAbbr,
|
||||||
|
'song_number' => $songNumber,
|
||||||
|
|
||||||
'song_counts' => trim($row['點播次數'] ?? 0),
|
'song_counts' => trim($row['點播次數'] ?? 0),
|
||||||
];
|
];
|
||||||
|
|
||||||
// 歌星 A/B 處理
|
|
||||||
foreach (['歌星A', '歌星B'] as $key) {
|
foreach (['歌星A', '歌星B'] as $key) {
|
||||||
$artistName = trim($row[$key] ?? '');
|
$artistName = trim($row[$key] ?? '');
|
||||||
if ($artistName === '') continue;
|
if ($artistName === '') continue;
|
||||||
|
|
||||||
|
// 若是歌星B,且與歌星A相同,則跳過
|
||||||
|
if ($key === '歌星B' && $artistName === trim($row['歌星A'] ?? '')) continue;
|
||||||
|
|
||||||
$artistId = $this->getOrCreateArtistId($artistName);
|
$artistId = $this->getOrCreateArtistId($artistName);
|
||||||
$artistMap[$songId][] = $artistId;
|
$artistMap[$songId][] = $artistId;
|
||||||
}
|
}
|
||||||
@ -78,10 +127,13 @@ class SongDataImport implements ToCollection, WithHeadingRow, WithChunkReading
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 新增到快取,避免後面重複匯入
|
||||||
|
$existingIDs[$songId] = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 寫入資料庫
|
// 寫入資料庫
|
||||||
Song::insert($songsToInsert);
|
Song::insert($ToInsert);
|
||||||
|
|
||||||
// 同步關聯(建議可用事件或批次處理)
|
// 同步關聯(建議可用事件或批次處理)
|
||||||
foreach ($artistMap as $songId => $artistIds) {
|
foreach ($artistMap as $songId => $artistIds) {
|
||||||
@ -115,7 +167,7 @@ class SongDataImport implements ToCollection, WithHeadingRow, WithChunkReading
|
|||||||
|
|
||||||
public function chunkSize(): int
|
public function chunkSize(): int
|
||||||
{
|
{
|
||||||
return 1000;
|
return 100;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function headingRow(): int
|
public function headingRow(): int
|
||||||
|
@ -33,6 +33,8 @@ class ImportArtistJob implements ShouldQueue
|
|||||||
*/
|
*/
|
||||||
public function handle(): void
|
public function handle(): void
|
||||||
{
|
{
|
||||||
|
ini_set('memory_limit', '-1'); // ✅ 增加記憶體限制
|
||||||
|
|
||||||
Excel::import(new ArtistDataImport, $this->filePath);
|
Excel::import(new ArtistDataImport, $this->filePath);
|
||||||
// 匯入完成後刪除檔案
|
// 匯入完成後刪除檔案
|
||||||
if (Storage::exists($this->filePath)) {
|
if (Storage::exists($this->filePath)) {
|
||||||
|
44
app/Jobs/ImportSongJob.php
Normal file
44
app/Jobs/ImportSongJob.php
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Jobs;
|
||||||
|
|
||||||
|
use App\Imports\SongDataImport;
|
||||||
|
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 ImportSongJob implements ShouldQueue
|
||||||
|
{
|
||||||
|
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||||
|
|
||||||
|
protected string $filePath;
|
||||||
|
public $timeout = 36000;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new job instance.
|
||||||
|
*/
|
||||||
|
public function __construct(string $filePath)
|
||||||
|
{
|
||||||
|
$this->filePath = $filePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the job.
|
||||||
|
*/
|
||||||
|
public function handle(): void
|
||||||
|
{
|
||||||
|
ini_set('memory_limit', '-1'); // ✅ 增加記憶體限制
|
||||||
|
|
||||||
|
Excel::import(new SongDataImport, $this->filePath);
|
||||||
|
// 匯入完成後刪除檔案
|
||||||
|
if (Storage::exists($this->filePath)) {
|
||||||
|
Storage::delete($this->filePath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -2,14 +2,19 @@
|
|||||||
|
|
||||||
namespace App\Livewire\Admin;
|
namespace App\Livewire\Admin;
|
||||||
|
|
||||||
use Livewire\Component;
|
|
||||||
use Illuminate\Validation\Rule;
|
use Illuminate\Validation\Rule;
|
||||||
use Illuminate\Support\Facades\Auth;
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
|
||||||
|
use Livewire\Component;
|
||||||
|
use WireUi\Traits\WireUiActions;
|
||||||
|
|
||||||
use App\Models\Artist;
|
use App\Models\Artist;
|
||||||
use App\Enums\ArtistCategory;
|
use App\Enums\ArtistCategory;
|
||||||
|
|
||||||
class ArtistForm extends Component
|
class ArtistForm extends Component
|
||||||
{
|
{
|
||||||
|
use WireUiActions;
|
||||||
|
|
||||||
protected $listeners = ['openModal','closeModal', 'deleteArtist'];
|
protected $listeners = ['openModal','closeModal', 'deleteArtist'];
|
||||||
|
|
||||||
public bool $canCreate;
|
public bool $canCreate;
|
||||||
@ -65,19 +70,19 @@ class ArtistForm extends Component
|
|||||||
if ($this->canEdit) {
|
if ($this->canEdit) {
|
||||||
$artist = Artist::findOrFail($this->artistId);
|
$artist = Artist::findOrFail($this->artistId);
|
||||||
$artist->update($this->fields);
|
$artist->update($this->fields);
|
||||||
$this->dispatch('notify', [
|
$this->notification()->send([
|
||||||
|
'icon' => 'success',
|
||||||
'title' => '成功',
|
'title' => '成功',
|
||||||
'description' => '歌手已更新',
|
'description' => '歌手已更新',
|
||||||
'icon' => 'success',
|
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if ($canCreate) {
|
if ($canCreate) {
|
||||||
$artist = Artist::create($this->fields);
|
$artist = Artist::create($this->fields);
|
||||||
$this->dispatch('notify', [
|
$this->notification()->send([
|
||||||
|
'icon' => 'success',
|
||||||
'title' => '成功',
|
'title' => '成功',
|
||||||
'description' => '歌手已新增',
|
'description' => '歌手已新增',
|
||||||
'icon' => 'success',
|
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -90,7 +95,12 @@ class ArtistForm extends Component
|
|||||||
{
|
{
|
||||||
if ($this->canDelect) {
|
if ($this->canDelect) {
|
||||||
Artist::findOrFail($id)->delete();
|
Artist::findOrFail($id)->delete();
|
||||||
session()->flash('message', '歌手已刪除');
|
$this->notification()->send([
|
||||||
|
'icon' => 'success',
|
||||||
|
'title' => '成功',
|
||||||
|
'description' => '歌手已刪除',
|
||||||
|
]);
|
||||||
|
|
||||||
$this->dispatch('pg:eventRefresh-artist-table');
|
$this->dispatch('pg:eventRefresh-artist-table');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,14 +3,17 @@
|
|||||||
namespace App\Livewire\Admin;
|
namespace App\Livewire\Admin;
|
||||||
|
|
||||||
use Illuminate\Support\Facades\Auth;
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
use Illuminate\Support\Facades\Storage;
|
||||||
|
use Illuminate\Support\Facades\File;
|
||||||
|
use WireUi\Traits\WireUiActions;
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
use Livewire\WithFileUploads;
|
use Livewire\WithFileUploads;
|
||||||
use App\Jobs\ImportArtistJob;
|
use App\Jobs\ImportArtistJob;
|
||||||
use Illuminate\Support\Facades\Storage;
|
|
||||||
|
|
||||||
class ArtistImportData extends Component
|
class ArtistImportData extends Component
|
||||||
{
|
{
|
||||||
use WithFileUploads;
|
use WithFileUploads, WireUiActions;
|
||||||
|
|
||||||
protected $listeners = ['openModal','closeModal'];
|
protected $listeners = ['openModal','closeModal'];
|
||||||
|
|
||||||
@ -20,6 +23,8 @@ class ArtistImportData extends Component
|
|||||||
|
|
||||||
public $file;
|
public $file;
|
||||||
|
|
||||||
|
public string|null $tmpPath = null;
|
||||||
|
|
||||||
public function mount()
|
public function mount()
|
||||||
{
|
{
|
||||||
$this->canCreate = Auth::user()?->can('song-edit') ?? false;
|
$this->canCreate = Auth::user()?->can('song-edit') ?? false;
|
||||||
@ -29,8 +34,11 @@ class ArtistImportData extends Component
|
|||||||
{
|
{
|
||||||
$this->showModal = true;
|
$this->showModal = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function closeModal()
|
public function closeModal()
|
||||||
{
|
{
|
||||||
|
$this->deleteTmpFile(); // 關閉 modal 時刪除暫存檔案
|
||||||
|
$this->reset(['file', 'tmpPath']);
|
||||||
$this->showModal = false;
|
$this->showModal = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -41,15 +49,28 @@ class ArtistImportData extends Component
|
|||||||
'file' => 'required|file|mimes:csv,xlsx,xls'
|
'file' => 'required|file|mimes:csv,xlsx,xls'
|
||||||
]);
|
]);
|
||||||
if ($this->canCreate) {
|
if ($this->canCreate) {
|
||||||
|
// 取得原始 tmp 路徑
|
||||||
|
$tmpPath = $this->file->getRealPath();
|
||||||
// 儲存檔案至 storage
|
// 儲存檔案至 storage
|
||||||
$path = $this->file->storeAs('imports', uniqid() . '_' . $this->file->getClientOriginalName());
|
$path = $this->file->storeAs('imports', uniqid() . '_' . $this->file->getClientOriginalName());
|
||||||
|
|
||||||
// 丟到 queue 執行
|
// 丟到 queue 執行
|
||||||
ImportArtistJob::dispatch($path);
|
ImportArtistJob::dispatch($path);
|
||||||
|
|
||||||
$this->reset('file');
|
$this->notification()->send([
|
||||||
|
'icon' => 'info',
|
||||||
|
'title' => $this->file->getClientOriginalName(),
|
||||||
|
'description' => '已排入背景匯入作業,請稍候查看結果',
|
||||||
|
]);
|
||||||
|
$this->deleteTmpFile(); // 匯入後也順便刪除 tmp 檔
|
||||||
|
$this->reset(['file', 'tmpPath']);
|
||||||
$this->showModal = false;
|
$this->showModal = false;
|
||||||
session()->flash('message', '已排入背景匯入作業,請稍候查看結果');
|
}
|
||||||
|
}
|
||||||
|
protected function deleteTmpFile()
|
||||||
|
{
|
||||||
|
if ($this->tmpPath && File::exists($this->tmpPath)) {
|
||||||
|
File::delete($this->tmpPath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,9 +19,12 @@ use PowerComponents\LivewirePowerGrid\Traits\WithExport;
|
|||||||
use PowerComponents\LivewirePowerGrid\Components\SetUp\Exportable;
|
use PowerComponents\LivewirePowerGrid\Components\SetUp\Exportable;
|
||||||
use PowerComponents\LivewirePowerGrid\Facades\Rule;
|
use PowerComponents\LivewirePowerGrid\Facades\Rule;
|
||||||
use Livewire\Attributes\On;
|
use Livewire\Attributes\On;
|
||||||
|
use WireUi\Traits\WireUiActions;
|
||||||
|
|
||||||
final class ArtistTable extends PowerGridComponent
|
final class ArtistTable extends PowerGridComponent
|
||||||
{
|
{
|
||||||
|
use WireUiActions;
|
||||||
|
|
||||||
public string $tableName = 'artist-table';
|
public string $tableName = 'artist-table';
|
||||||
public bool $canCreate;
|
public bool $canCreate;
|
||||||
public bool $canEdit;
|
public bool $canEdit;
|
||||||
@ -166,12 +169,24 @@ final class ArtistTable extends PowerGridComponent
|
|||||||
$this->noUpdated($id,$field,$value);
|
$this->noUpdated($id,$field,$value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#[On('onUpdatedToggleable')]
|
||||||
|
public function onUpdatedToggleable($id, $field, $value): void
|
||||||
|
{
|
||||||
|
if (in_array($field,['enable']) && $this->canEdit) {
|
||||||
|
$this->noUpdated($id,$field,$value);
|
||||||
|
}
|
||||||
|
}
|
||||||
private function noUpdated($id,$field,$value){
|
private function noUpdated($id,$field,$value){
|
||||||
$artist = Artist::find($id);
|
$artist = Artist::find($id);
|
||||||
if ($artist) {
|
if ($artist) {
|
||||||
$artist->{$field} = $value;
|
$artist->{$field} = $value;
|
||||||
$artist->save(); // 明確觸發 saving
|
$artist->save(); // 明確觸發 saving
|
||||||
}
|
}
|
||||||
|
$this->notification()->send([
|
||||||
|
'icon' => 'success',
|
||||||
|
'title' => $id.'.'.__('artists.'.$field).':'.$value,
|
||||||
|
'description' => '已經寫入',
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function filters(): array
|
public function filters(): array
|
||||||
|
@ -2,15 +2,25 @@
|
|||||||
|
|
||||||
namespace App\Livewire\Admin;
|
namespace App\Livewire\Admin;
|
||||||
|
|
||||||
|
use Illuminate\Validation\Rule;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
|
use WireUi\Traits\WireUiActions;
|
||||||
|
|
||||||
use Spatie\Permission\Models\Role;
|
use Spatie\Permission\Models\Role;
|
||||||
use Spatie\Permission\Models\Permission;
|
use Spatie\Permission\Models\Permission;
|
||||||
|
|
||||||
class RoleForm extends Component
|
class RoleForm extends Component
|
||||||
{
|
{
|
||||||
|
use WireUiActions;
|
||||||
|
|
||||||
protected $listeners = ['openCreateRoleModal','openEditRoleModal', 'deleteRole'];
|
protected $listeners = ['openCreateRoleModal','openEditRoleModal', 'deleteRole'];
|
||||||
|
|
||||||
|
public bool $canCreate;
|
||||||
|
public bool $canEdit;
|
||||||
|
public bool $canDelect;
|
||||||
|
|
||||||
public $showCreateModal=false;
|
public $showCreateModal=false;
|
||||||
public ?int $roleId = null;
|
public ?int $roleId = null;
|
||||||
public $name = '';
|
public $name = '';
|
||||||
@ -22,6 +32,9 @@ class RoleForm extends Component
|
|||||||
public function mount()
|
public function mount()
|
||||||
{
|
{
|
||||||
$this->permissions = Permission::all();
|
$this->permissions = Permission::all();
|
||||||
|
$this->canCreate = Auth::user()?->can('role-edit') ?? false;
|
||||||
|
$this->canEdit = Auth::user()?->can('role-edit') ?? false;
|
||||||
|
$this->canDelect = Auth::user()?->can('role-delete') ?? false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function openCreateRoleModal()
|
public function openCreateRoleModal()
|
||||||
@ -47,14 +60,26 @@ class RoleForm extends Component
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
if ($this->roleId) {
|
if ($this->roleId) {
|
||||||
$role = Role::findOrFail($this->roleId);
|
if ($this->canEdit) {
|
||||||
$role->update(['name' => $this->name]);
|
$role = Role::findOrFail($this->roleId);
|
||||||
$role->syncPermissions($this->selectedPermissions);
|
$role->update(['name' => $this->name]);
|
||||||
session()->flash('message', '角色已更新');
|
$role->syncPermissions($this->selectedPermissions);
|
||||||
|
$this->notification()->send([
|
||||||
|
'icon' => 'success',
|
||||||
|
'title' => '成功',
|
||||||
|
'description' => '角色已更新',
|
||||||
|
]);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
$role = Role::create(['name' => $this->name]);
|
if ($canCreate) {
|
||||||
$role->syncPermissions($this->selectedPermissions);
|
$role = Role::create(['name' => $this->name]);
|
||||||
session()->flash('message', '角色已新增');
|
$role->syncPermissions($this->selectedPermissions);
|
||||||
|
$this->notification()->send([
|
||||||
|
'icon' => 'success',
|
||||||
|
'title' => '成功',
|
||||||
|
'description' => '角色已新增',
|
||||||
|
]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->resetFields();
|
$this->resetFields();
|
||||||
@ -64,8 +89,15 @@ class RoleForm extends Component
|
|||||||
|
|
||||||
public function deleteRole($id)
|
public function deleteRole($id)
|
||||||
{
|
{
|
||||||
Role::findOrFail($id)->delete();
|
if ($this->canDelect) {
|
||||||
session()->flash('message', '角色已刪除');
|
Role::findOrFail($id)->delete();
|
||||||
|
$this->notification()->send([
|
||||||
|
'icon' => 'success',
|
||||||
|
'title' => '成功',
|
||||||
|
'description' => '角色已刪除',
|
||||||
|
]);
|
||||||
|
$this->dispatch('pg:eventRefresh-role-table');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function resetFields()
|
public function resetFields()
|
||||||
|
@ -13,9 +13,13 @@ use PowerComponents\LivewirePowerGrid\Facades\Filter;
|
|||||||
use PowerComponents\LivewirePowerGrid\Facades\PowerGrid;
|
use PowerComponents\LivewirePowerGrid\Facades\PowerGrid;
|
||||||
use PowerComponents\LivewirePowerGrid\PowerGridFields;
|
use PowerComponents\LivewirePowerGrid\PowerGridFields;
|
||||||
use PowerComponents\LivewirePowerGrid\PowerGridComponent;
|
use PowerComponents\LivewirePowerGrid\PowerGridComponent;
|
||||||
|
use Livewire\Attributes\On;
|
||||||
|
use WireUi\Traits\WireUiActions;
|
||||||
|
|
||||||
final class RoleTable extends PowerGridComponent
|
final class RoleTable extends PowerGridComponent
|
||||||
{
|
{
|
||||||
|
use WireUiActions;
|
||||||
|
|
||||||
public string $tableName = 'role-table';
|
public string $tableName = 'role-table';
|
||||||
public bool $canCreate;
|
public bool $canCreate;
|
||||||
public bool $canEdit;
|
public bool $canEdit;
|
||||||
@ -128,6 +132,11 @@ final class RoleTable extends PowerGridComponent
|
|||||||
$role->{$field} = $value;
|
$role->{$field} = $value;
|
||||||
$role->save(); // 明確觸發 saving
|
$role->save(); // 明確觸發 saving
|
||||||
}
|
}
|
||||||
|
$this->notification()->send([
|
||||||
|
'icon' => 'success',
|
||||||
|
'title' => $id.'.'.__('roles.'.$field).':'.$value,
|
||||||
|
'description' => '已經寫入',
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
public function filters(): array
|
public function filters(): array
|
||||||
{
|
{
|
||||||
|
@ -2,7 +2,11 @@
|
|||||||
|
|
||||||
namespace App\Livewire\Admin;
|
namespace App\Livewire\Admin;
|
||||||
|
|
||||||
|
use Illuminate\Validation\Rule;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
|
use WireUi\Traits\WireUiActions;
|
||||||
|
|
||||||
use App\Enums\SongLanguageType;
|
use App\Enums\SongLanguageType;
|
||||||
use App\Enums\SongSituation;
|
use App\Enums\SongSituation;
|
||||||
@ -11,7 +15,13 @@ use App\Models\SongCategory;
|
|||||||
|
|
||||||
class SongForm extends Component
|
class SongForm extends Component
|
||||||
{
|
{
|
||||||
|
use WireUiActions;
|
||||||
|
|
||||||
protected $listeners = ['openModal','closeModal', 'deleteSong'];
|
protected $listeners = ['openModal','closeModal', 'deleteSong'];
|
||||||
|
|
||||||
|
public bool $canCreate;
|
||||||
|
public bool $canEdit;
|
||||||
|
public bool $canDelect;
|
||||||
|
|
||||||
public bool $showModal = false;
|
public bool $showModal = false;
|
||||||
|
|
||||||
@ -88,10 +98,18 @@ class SongForm extends Component
|
|||||||
if ($this->songId) {
|
if ($this->songId) {
|
||||||
$song = Song::findOrFail($this->songId);
|
$song = Song::findOrFail($this->songId);
|
||||||
$song->update($this->fields);
|
$song->update($this->fields);
|
||||||
session()->flash('message', '歌曲已更新');
|
$this->notification()->send([
|
||||||
|
'icon' => 'success',
|
||||||
|
'title' => '成功',
|
||||||
|
'description' => '歌曲已更新',
|
||||||
|
]);
|
||||||
} else {
|
} else {
|
||||||
$song = Song::create($this->fields);
|
$song = Song::create($this->fields);
|
||||||
session()->flash('message', '歌曲已新增');
|
$this->notification()->send([
|
||||||
|
'icon' => 'success',
|
||||||
|
'title' => '成功',
|
||||||
|
'description' => '歌曲已新增',
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
// ⭐ 同步多對多關聯
|
// ⭐ 同步多對多關聯
|
||||||
$song->artists()->sync($this->selectedArtists ?? []);
|
$song->artists()->sync($this->selectedArtists ?? []);
|
||||||
@ -105,7 +123,11 @@ class SongForm extends Component
|
|||||||
public function deleteSong($id)
|
public function deleteSong($id)
|
||||||
{
|
{
|
||||||
Song::findOrFail($id)->delete();
|
Song::findOrFail($id)->delete();
|
||||||
session()->flash('message', '歌曲已刪除');
|
$this->notification()->send([
|
||||||
|
'icon' => 'success',
|
||||||
|
'title' => '成功',
|
||||||
|
'description' => '歌曲已刪除',
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function resetFields()
|
public function resetFields()
|
||||||
|
@ -3,14 +3,17 @@
|
|||||||
namespace App\Livewire\Admin;
|
namespace App\Livewire\Admin;
|
||||||
|
|
||||||
use Illuminate\Support\Facades\Auth;
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
use Illuminate\Support\Facades\Storage;
|
||||||
|
use Illuminate\Support\Facades\File;
|
||||||
|
use WireUi\Traits\WireUiActions;
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
use Livewire\WithFileUploads;
|
use Livewire\WithFileUploads;
|
||||||
use Maatwebsite\Excel\Facades\Excel;
|
use App\Jobs\ImportSongJob;
|
||||||
use App\Imports\SongDataImport;
|
|
||||||
|
|
||||||
class SongImportData extends Component
|
class SongImportData extends Component
|
||||||
{
|
{
|
||||||
use WithFileUploads;
|
use WithFileUploads, WireUiActions;
|
||||||
|
|
||||||
protected $listeners = ['openModal','closeModal'];
|
protected $listeners = ['openModal','closeModal'];
|
||||||
|
|
||||||
@ -20,6 +23,8 @@ class SongImportData extends Component
|
|||||||
|
|
||||||
public $file;
|
public $file;
|
||||||
|
|
||||||
|
public string|null $tmpPath = null;
|
||||||
|
|
||||||
public function mount()
|
public function mount()
|
||||||
{
|
{
|
||||||
$this->canCreate = Auth::user()?->can('song-edit') ?? false;
|
$this->canCreate = Auth::user()?->can('song-edit') ?? false;
|
||||||
@ -29,8 +34,11 @@ class SongImportData extends Component
|
|||||||
{
|
{
|
||||||
$this->showModal = true;
|
$this->showModal = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function closeModal()
|
public function closeModal()
|
||||||
{
|
{
|
||||||
|
$this->deleteTmpFile(); // 關閉 modal 時刪除暫存檔案
|
||||||
|
$this->reset(['file', 'tmpPath']);
|
||||||
$this->showModal = false;
|
$this->showModal = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -41,13 +49,28 @@ class SongImportData extends Component
|
|||||||
'file' => 'required|file|mimes:csv,xlsx,xls'
|
'file' => 'required|file|mimes:csv,xlsx,xls'
|
||||||
]);
|
]);
|
||||||
if ($this->canCreate) {
|
if ($this->canCreate) {
|
||||||
$import = new SongDataImport();
|
// 取得原始 tmp 路徑
|
||||||
Excel::import($import, $this->file);
|
$tmpPath = $this->file->getRealPath();
|
||||||
$success = $import->successCount;
|
// 儲存檔案至 storage
|
||||||
$fail = $import->failCount;
|
$path = $this->file->storeAs('imports', uniqid() . '_' . $this->file->getClientOriginalName());
|
||||||
$this->reset('file');
|
|
||||||
$this->showModal =false;
|
// 丟到 queue 執行
|
||||||
session()->flash('message', '匯入完成:成功 $success 筆,失敗 $fail 筆。');
|
ImportSongJob::dispatch($path);
|
||||||
|
|
||||||
|
$this->notification()->send([
|
||||||
|
'icon' => 'info',
|
||||||
|
'title' => $this->file->getClientOriginalName(),
|
||||||
|
'description' => '已排入背景匯入作業,請稍候查看結果',
|
||||||
|
]);
|
||||||
|
$this->deleteTmpFile(); // 匯入後也順便刪除 tmp 檔
|
||||||
|
$this->reset(['file', 'tmpPath']);
|
||||||
|
$this->showModal = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
protected function deleteTmpFile()
|
||||||
|
{
|
||||||
|
if ($this->tmpPath && File::exists($this->tmpPath)) {
|
||||||
|
File::delete($this->tmpPath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,9 +20,12 @@ use PowerComponents\LivewirePowerGrid\Traits\WithExport;
|
|||||||
use PowerComponents\LivewirePowerGrid\Components\SetUp\Exportable;
|
use PowerComponents\LivewirePowerGrid\Components\SetUp\Exportable;
|
||||||
use PowerComponents\LivewirePowerGrid\Facades\Rule;
|
use PowerComponents\LivewirePowerGrid\Facades\Rule;
|
||||||
use Livewire\Attributes\On;
|
use Livewire\Attributes\On;
|
||||||
|
use WireUi\Traits\WireUiActions;
|
||||||
|
|
||||||
final class SongTable extends PowerGridComponent
|
final class SongTable extends PowerGridComponent
|
||||||
{
|
{
|
||||||
|
use WireUiActions;
|
||||||
|
|
||||||
public string $tableName = 'song-table';
|
public string $tableName = 'song-table';
|
||||||
public bool $canCreate;
|
public bool $canCreate;
|
||||||
public bool $canEdit;
|
public bool $canEdit;
|
||||||
@ -203,7 +206,14 @@ final class SongTable extends PowerGridComponent
|
|||||||
{
|
{
|
||||||
$this->js('alert(window.pgBulkActions.get(\'' . $this->tableName . '\'))');
|
$this->js('alert(window.pgBulkActions.get(\'' . $this->tableName . '\'))');
|
||||||
if($this->checkboxValues){
|
if($this->checkboxValues){
|
||||||
Song::destroy($this->checkboxValues);
|
foreach ($this->checkboxValues as $id) {
|
||||||
|
$song = Song::find($id);
|
||||||
|
if ($song) {
|
||||||
|
$song->artists()->detach();
|
||||||
|
$song->categories()->detach();
|
||||||
|
$song->delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
$this->js('window.pgBulkActions.clearAll()'); // clear the count on the interface.
|
$this->js('window.pgBulkActions.clearAll()'); // clear the count on the interface.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -238,6 +248,11 @@ final class SongTable extends PowerGridComponent
|
|||||||
$song->{$field} = $value;
|
$song->{$field} = $value;
|
||||||
$song->save(); // 明確觸發 saving
|
$song->save(); // 明確觸發 saving
|
||||||
}
|
}
|
||||||
|
$this->notification()->send([
|
||||||
|
'icon' => 'success',
|
||||||
|
'title' => $id.'.'.__('songs.'.$field).':'.$value,
|
||||||
|
'description' => '已經寫入',
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -2,7 +2,11 @@
|
|||||||
|
|
||||||
namespace App\Livewire\Admin;
|
namespace App\Livewire\Admin;
|
||||||
|
|
||||||
|
use Illuminate\Validation\Rule;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
|
use WireUi\Traits\WireUiActions;
|
||||||
|
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use App\Enums\UserGender;
|
use App\Enums\UserGender;
|
||||||
@ -11,10 +15,15 @@ use Spatie\Permission\Models\Role;
|
|||||||
|
|
||||||
class UserForm extends Component
|
class UserForm extends Component
|
||||||
{
|
{
|
||||||
|
use WireUiActions;
|
||||||
|
|
||||||
protected $listeners = ['openCreateUserModal','openEditUserModal', 'deleteUser'];
|
protected $listeners = ['openCreateUserModal','openEditUserModal', 'deleteUser'];
|
||||||
|
|
||||||
public bool $showCreateModal = false;
|
public bool $canCreate;
|
||||||
|
public bool $canEdit;
|
||||||
|
public bool $canDelect;
|
||||||
|
|
||||||
|
public bool $showCreateModal = false;
|
||||||
|
|
||||||
public array $genderOptions =[];
|
public array $genderOptions =[];
|
||||||
public array $statusOptions =[];
|
public array $statusOptions =[];
|
||||||
@ -52,6 +61,9 @@ class UserForm extends Component
|
|||||||
'value' => $status->value,
|
'value' => $status->value,
|
||||||
])->toArray();
|
])->toArray();
|
||||||
$this->rolesOptions = Role::all();
|
$this->rolesOptions = Role::all();
|
||||||
|
$this->canCreate = Auth::user()?->can('user-edit') ?? false;
|
||||||
|
$this->canEdit = Auth::user()?->can('user-edit') ?? false;
|
||||||
|
$this->canDelect = Auth::user()?->can('user-delete') ?? false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function openCreateUserModal()
|
public function openCreateUserModal()
|
||||||
@ -72,17 +84,29 @@ class UserForm extends Component
|
|||||||
|
|
||||||
public function save()
|
public function save()
|
||||||
{
|
{
|
||||||
$this->validate();
|
//$this->validate();
|
||||||
|
|
||||||
if ($this->userId) {
|
if ($this->userId) {
|
||||||
$user = User::findOrFail($this->userId);
|
if ($this->canEdit) {
|
||||||
$user->update($this->fields);
|
$user = User::findOrFail($this->userId);
|
||||||
$user->syncRoles($this->selectedRoles);
|
$user->update($this->fields);
|
||||||
session()->flash('message', '使用者已更新');
|
$user->syncRoles($this->selectedRoles);
|
||||||
|
$this->notification()->send([
|
||||||
|
'icon' => 'success',
|
||||||
|
'title' => '成功',
|
||||||
|
'description' => '使用者已更新',
|
||||||
|
]);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
$user = User::create($this->fields);
|
if ($canCreate) {
|
||||||
$user->syncRoles($this->selectedRoles);
|
$user = User::create($this->fields);
|
||||||
session()->flash('message', '使用者已新增');
|
$user->syncRoles($this->selectedRoles);
|
||||||
|
$this->notification()->send([
|
||||||
|
'icon' => 'success',
|
||||||
|
'title' => '成功',
|
||||||
|
'description' => '使用者已新增',
|
||||||
|
]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->resetFields();
|
$this->resetFields();
|
||||||
@ -92,8 +116,15 @@ class UserForm extends Component
|
|||||||
|
|
||||||
public function deleteUser($id)
|
public function deleteUser($id)
|
||||||
{
|
{
|
||||||
User::findOrFail($id)->delete();
|
if ($this->canDelect) {
|
||||||
session()->flash('message', '使用者已刪除');
|
User::findOrFail($id)->delete();
|
||||||
|
$this->notification()->send([
|
||||||
|
'icon' => 'success',
|
||||||
|
'title' => '成功',
|
||||||
|
'description' => '使用者已刪除',
|
||||||
|
]);
|
||||||
|
$this->dispatch('pg:eventRefresh-user-table');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function resetFields()
|
public function resetFields()
|
||||||
|
@ -19,9 +19,11 @@ use PowerComponents\LivewirePowerGrid\PowerGridComponent;
|
|||||||
use PowerComponents\LivewirePowerGrid\Components\SetUp\Exportable;
|
use PowerComponents\LivewirePowerGrid\Components\SetUp\Exportable;
|
||||||
use PowerComponents\LivewirePowerGrid\Facades\Rule;
|
use PowerComponents\LivewirePowerGrid\Facades\Rule;
|
||||||
use Livewire\Attributes\On;
|
use Livewire\Attributes\On;
|
||||||
|
use WireUi\Traits\WireUiActions;
|
||||||
|
|
||||||
final class UserTable extends PowerGridComponent
|
final class UserTable extends PowerGridComponent
|
||||||
{
|
{
|
||||||
|
use WireUiActions;
|
||||||
//use WithExport ;
|
//use WithExport ;
|
||||||
|
|
||||||
public string $tableName = 'user-table';
|
public string $tableName = 'user-table';
|
||||||
@ -174,7 +176,7 @@ final class UserTable extends PowerGridComponent
|
|||||||
if ($this->canDelect) {
|
if ($this->canDelect) {
|
||||||
$this->js('alert(window.pgBulkActions.get(\'' . $this->tableName . '\'))');
|
$this->js('alert(window.pgBulkActions.get(\'' . $this->tableName . '\'))');
|
||||||
if($this->checkboxValues){
|
if($this->checkboxValues){
|
||||||
Artist::destroy($this->checkboxValues);
|
User::destroy($this->checkboxValues);
|
||||||
$this->js('window.pgBulkActions.clearAll()'); // clear the count on the interface.
|
$this->js('window.pgBulkActions.clearAll()'); // clear the count on the interface.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -202,11 +204,16 @@ final class UserTable extends PowerGridComponent
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
private function noUpdated($id,$field,$value){
|
private function noUpdated($id,$field,$value){
|
||||||
$artist = Artist::find($id);
|
$user = User::find($id);
|
||||||
if ($artist) {
|
if ($user) {
|
||||||
$artist->{$field} = $value;
|
$user->{$field} = $value;
|
||||||
$artist->save(); // 明確觸發 saving
|
$user->save(); // 明確觸發 saving
|
||||||
}
|
}
|
||||||
|
$this->notification()->send([
|
||||||
|
'icon' => 'success',
|
||||||
|
'title' => $id.'.'.__('users.'.$field).':'.$value,
|
||||||
|
'description' => '已經寫入',
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
public function filters(): array
|
public function filters(): array
|
||||||
{
|
{
|
||||||
|
@ -31,6 +31,7 @@ class Song extends Model
|
|||||||
'phonetic_abbr',
|
'phonetic_abbr',
|
||||||
'pinyin_abbr',
|
'pinyin_abbr',
|
||||||
'strokes_abbr',
|
'strokes_abbr',
|
||||||
|
'song_number',
|
||||||
'song_counts',
|
'song_counts',
|
||||||
];
|
];
|
||||||
|
|
||||||
@ -77,6 +78,7 @@ class Song extends Model
|
|||||||
$chars = preg_split('//u', $song->name, -1, PREG_SPLIT_NO_EMPTY);
|
$chars = preg_split('//u', $song->name, -1, PREG_SPLIT_NO_EMPTY);
|
||||||
$firstChar = $chars[0] ?? null;
|
$firstChar = $chars[0] ?? null;
|
||||||
$song->strokes_abbr=$firstChar ? ChineseStrokesConverter::getStrokes($firstChar) : null;
|
$song->strokes_abbr=$firstChar ? ChineseStrokesConverter::getStrokes($firstChar) : null;
|
||||||
|
$song->song_number = mb_strlen($song->name, 'UTF-8');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -31,6 +31,7 @@ return new class extends Migration
|
|||||||
$table->string('phonetic_abbr')->comment('歌曲注音');
|
$table->string('phonetic_abbr')->comment('歌曲注音');
|
||||||
$table->string('pinyin_abbr')->comment('歌曲拼音');
|
$table->string('pinyin_abbr')->comment('歌曲拼音');
|
||||||
$table->integer('strokes_abbr')->default(0)->comment('歌曲筆劃');
|
$table->integer('strokes_abbr')->default(0)->comment('歌曲筆劃');
|
||||||
|
$table->integer('song_number')->default(0)->comment('歌曲字數');
|
||||||
$table->integer('song_counts')->default(0)->comment('點播次數');
|
$table->integer('song_counts')->default(0)->comment('點播次數');
|
||||||
$table->timestamps();
|
$table->timestamps();
|
||||||
});
|
});
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<x-wireui:modal-card title="{{ __('artists.ImportData') }}" blur wire:model.defer="showModal">
|
<x-wireui:modal-card title="{{ __('artists.ImportData') }}" blur wire:model.defer="showModal" hide-close>
|
||||||
|
|
||||||
{{-- 說明區塊 --}}
|
{{-- 說明區塊 --}}
|
||||||
<div class="mb-4 p-4 bg-gray-100 border border-gray-300 rounded text-sm text-gray-700">
|
<div class="mb-4 p-4 bg-gray-100 border border-gray-300 rounded text-sm text-gray-700">
|
||||||
|
@ -1,18 +1,6 @@
|
|||||||
|
|
||||||
<x-layouts.admin>
|
<x-layouts.admin>
|
||||||
|
<x-wireui:notifications/>
|
||||||
<x-wireui:notifications />
|
|
||||||
<script>
|
|
||||||
window.$wireui.notify({
|
|
||||||
title: '提示',
|
|
||||||
description: '{{ session('message') }}',
|
|
||||||
icon: 'success'
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
{{-- 單一 Livewire 元件,內含資料表與 Modal --}}
|
|
||||||
|
|
||||||
|
|
||||||
<livewire:admin.artist-table />
|
<livewire:admin.artist-table />
|
||||||
<livewire:admin.artist-form />
|
<livewire:admin.artist-form />
|
||||||
<livewire:admin.artist-import-data />
|
<livewire:admin.artist-import-data />
|
||||||
|
@ -1,17 +1,6 @@
|
|||||||
|
|
||||||
<x-layouts.admin>
|
<x-layouts.admin>
|
||||||
@if (session()->has('message'))
|
<x-wireui:notifications/>
|
||||||
<x-wireui:notifications />
|
|
||||||
<script>
|
|
||||||
window.$wireui.notify({
|
|
||||||
title: '提示',
|
|
||||||
description: '{{ session('message') }}',
|
|
||||||
icon: 'success'
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
@endif
|
|
||||||
|
|
||||||
{{-- 單一 Livewire 元件,內含資料表與 Modal --}}
|
|
||||||
<livewire:admin.role-table />
|
<livewire:admin.role-table />
|
||||||
<livewire:admin.role-form />
|
<livewire:admin.role-form />
|
||||||
</x-layouts.admin>
|
</x-layouts.admin>
|
@ -1,4 +1,4 @@
|
|||||||
<x-wireui:modal-card title="{{ __('songs.ImportData') }}" blur wire:model.defer="showModal">
|
<x-wireui:modal-card title="{{ __('songs.ImportData') }}" blur wire:model.defer="showModal" hide-close>
|
||||||
|
|
||||||
{{-- resources/views/components/import-format-info.blade.php --}}
|
{{-- resources/views/components/import-format-info.blade.php --}}
|
||||||
|
|
||||||
@ -26,16 +26,6 @@
|
|||||||
<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>
|
||||||
<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">993794.mpg</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td class="border border-gray-300 px-3 py-1">日期</td>
|
|
||||||
<td class="border border-gray-300 px-3 py-1">新增日期(格式:YYYY-MM-DD)</td>
|
|
||||||
<td class="border border-gray-300 px-3 py-1">2015-08-14</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
<tr>
|
||||||
<td class="border border-gray-300 px-3 py-1">歌星A</td>
|
<td class="border border-gray-300 px-3 py-1">歌星A</td>
|
||||||
<td class="border border-gray-300 px-3 py-1">可填入歌手名稱</td>
|
<td class="border border-gray-300 px-3 py-1">可填入歌手名稱</td>
|
||||||
@ -46,60 +36,70 @@
|
|||||||
<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>
|
||||||
|
<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">993794.mpg</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="border border-gray-300 px-3 py-1">日期</td>
|
||||||
|
<td class="border border-gray-300 px-3 py-1">新增日期(格式:YYYY-MM-DD)</td>
|
||||||
|
<td class="border border-gray-300 px-3 py-1">2015-08-14</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="border border-gray-300 px-3 py-1">分類</td>
|
||||||
|
<td class="border border-gray-300 px-3 py-1">可填入多個分類代碼(用 , 分隔)A1(情歌),B1(選秀),C1(串燒),D1(90年),E1(懷念),F1(大陸)</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">XXY</td>
|
||||||
|
</tr>
|
||||||
<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>
|
||||||
<td class="border border-gray-300 px-3 py-1">國語</td>
|
<td class="border border-gray-300 px-3 py-1">國語</td>
|
||||||
</tr>
|
</tr>
|
||||||
<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">可填入多個分類代碼(用 , 分隔)A1(情歌),B1(選秀),C1(串燒),D1(90年),E1(懷念),F1(大陸)</td>
|
<td class="border border-gray-300 px-3 py-1">記錄此歌曲被點播的次數</td>
|
||||||
<td class="border border-gray-300 px-3 py-1">A1,B1,C1,D1,E1,F1</td>
|
<td class="border border-gray-300 px-3 py-1">519</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">-2</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"></td>
|
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="border border-gray-300 px-3 py-1">版權01</td>
|
<td class="border border-gray-300 px-3 py-1">版權01</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>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="border border-gray-300 px-3 py-1">版權02</td>
|
<td class="border border-gray-300 px-3 py-1">版權02</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>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="border border-gray-300 px-3 py-1">備註01</td>
|
<td class="border border-gray-300 px-3 py-1">版權03</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>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="border border-gray-300 px-3 py-1">備註02</td>
|
<td class="border border-gray-300 px-3 py-1">版權04</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>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="border border-gray-300 px-3 py-1">備註03</td>
|
<td class="border border-gray-300 px-3 py-1">版權05</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>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="border border-gray-300 px-3 py-1">備註04</td>
|
<td class="border border-gray-300 px-3 py-1">版權06</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">2023重錄版</td>
|
<td class="border border-gray-300 px-3 py-1"></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="border border-gray-300 px-3 py-1">狀態</td>
|
<td class="border border-gray-300 px-3 py-1">狀態</td>
|
||||||
@ -107,9 +107,29 @@
|
|||||||
<td class="border border-gray-300 px-3 py-1">1</td>
|
<td class="border border-gray-300 px-3 py-1">1</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="border border-gray-300 px-3 py-1">點播次數</td>
|
<td class="border border-gray-300 px-3 py-1">kk2</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">128</td>
|
<td class="border border-gray-300 px-3 py-1"></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="border border-gray-300 px-3 py-1">kk3</td>
|
||||||
|
<td class="border border-gray-300 px-3 py-1">歌名第一個字筆畫</td>
|
||||||
|
<td class="border border-gray-300 px-3 py-1">3</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="border border-gray-300 px-3 py-1">kk4</td>
|
||||||
|
<td class="border border-gray-300 px-3 py-1">歌名字數</td>
|
||||||
|
<td class="border border-gray-300 px-3 py-1">3</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="border border-gray-300 px-3 py-1">kk6</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">kk7</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>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
@ -1,17 +1,6 @@
|
|||||||
|
|
||||||
<x-layouts.admin>
|
<x-layouts.admin>
|
||||||
@if (session()->has('message'))
|
<x-wireui:notifications/>
|
||||||
<x-wireui:notifications />
|
|
||||||
<script>
|
|
||||||
window.$wireui.notify({
|
|
||||||
title: '提示',
|
|
||||||
description: '{{ session('message') }}',
|
|
||||||
icon: 'success'
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
@endif
|
|
||||||
|
|
||||||
{{-- 單一 Livewire 元件,內含資料表與 Modal --}}
|
|
||||||
<livewire:admin.song-table />
|
<livewire:admin.song-table />
|
||||||
<livewire:admin.song-form />
|
<livewire:admin.song-form />
|
||||||
<livewire:admin.song-import-data />
|
<livewire:admin.song-import-data />
|
||||||
|
@ -1,17 +1,6 @@
|
|||||||
|
|
||||||
<x-layouts.admin>
|
<x-layouts.admin>
|
||||||
@if (session()->has('message'))
|
<x-wireui:notifications/>
|
||||||
<x-wireui:notifications />
|
|
||||||
<script>
|
|
||||||
window.$wireui.notify({
|
|
||||||
title: '提示',
|
|
||||||
description: '{{ session('message') }}',
|
|
||||||
icon: 'success'
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
@endif
|
|
||||||
|
|
||||||
{{-- 單一 Livewire 元件,內含資料表與 Modal --}}
|
|
||||||
<livewire:admin.user-table />
|
<livewire:admin.user-table />
|
||||||
<livewire:admin.user-form />
|
<livewire:admin.user-form />
|
||||||
</x-layouts.admin>
|
</x-layouts.admin>
|
Loading…
x
Reference in New Issue
Block a user