加入完成訊息

song 滙入大量歌曲會有問題 修正
加入 歌曲字數
加入 檔案完成後刪除功能
加入 暫存檔案刪除功能
20250507
This commit is contained in:
allen.yan 2025-05-07 15:35:06 +08:00
parent 0969a07a3e
commit c1125ae141
23 changed files with 438 additions and 161 deletions

BIN
.DS_Store vendored

Binary file not shown.

View File

@ -23,21 +23,31 @@ class ArtistDataImport implements ToCollection, WithHeadingRow, WithChunkReading
}
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) {
$name=trim($row['歌手姓名'] ?? '');
if (empty($name)) continue;
// 若資料庫已有該名稱,跳過
if (isset($existingNames[$name])) continue;
// 字元處理
$simplified = ChineseNameConverter::convertToSimplified($name);
if (!array_key_exists('歌手注音', $row)) {
if (!$row->has('歌手注音')) {
$phoneticAbbr = ChineseNameConverter::getKTVZhuyinAbbr($simplified);
} else {
$phoneticAbbr = trim($row['歌手注音']);
}
$pinyinAbbr = ChineseNameConverter::getKTVPinyinAbbr($simplified);
if (!array_key_exists('歌手注音', $row)) {
if (!$row->has('歌手筆畫')) {
$chars = preg_split('//u', $name, -1, PREG_SPLIT_NO_EMPTY);
$firstChar = $chars[0] ?? null;
$strokesAbbr = $firstChar ? ChineseStrokesConverter::getStrokes($firstChar) : null;
@ -45,6 +55,7 @@ class ArtistDataImport implements ToCollection, WithHeadingRow, WithChunkReading
$strokesAbbr = trim($row['歌手筆畫']);
}
// 準備 song 資料
$now = now();
$toInsert[] = [
'name' => $name,
'category' => ArtistCategory::tryFrom(trim($row['歌手分類'] ?? '未定義')) ?? ArtistCategory::Unset,
@ -52,8 +63,13 @@ class ArtistDataImport implements ToCollection, WithHeadingRow, WithChunkReading
'phonetic_abbr' => $phoneticAbbr,
'pinyin_abbr' => $pinyinAbbr,
'strokes_abbr' => $strokesAbbr,
'enable' =>trim($row['狀態'] ?? 1)
'enable' =>trim($row['狀態'] ?? 1),
'created_at' => $now,
'updated_at' => $now,
];
// 新增到快取,避免後面重複匯入
$existingNames[$name] = true;
}
Artist::insert($toInsert);
}

View File

@ -8,12 +8,15 @@ 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\Support\Collection;
use Illuminate\Support\Str;
use Illuminate\Support\Facades\Log;
use Maatwebsite\Excel\Concerns\ToCollection;
use Maatwebsite\Excel\Concerns\WithHeadingRow;
use Maatwebsite\Excel\Concerns\WithChunkReading;
use Maatwebsite\Excel\Imports\HeadingRowFormatter;
class SongDataImport implements ToCollection, WithHeadingRow, WithChunkReading
{
@ -22,13 +25,22 @@ class SongDataImport implements ToCollection, WithHeadingRow, WithChunkReading
public function __construct()
{
// 關閉 heading row 格式化
HeadingRowFormatter::default('none');
// 快取分類代碼對應 ID
$this->categoryMap = SongCategory::pluck('id', 'code')->toArray();
}
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]]
$categoryMap = []; // [song_id => [category_id]]
@ -38,32 +50,69 @@ class SongDataImport implements ToCollection, WithHeadingRow, WithChunkReading
if (!$songId) {
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 資料
$songsToInsert[] = [
$ToInsert[] = [
'id' => $songId,
'name' => trim($row['歌名'] ?? ''),
'name' => $songName,
'adddate' => trim($row['日期'] ?? null),
'filename' => trim($row['檔名'] ?? ''),
'language_type' => SongLanguageType::tryFrom(trim($row['語別'] ?? '')) ?? SongLanguageType::Unset,
'db_change' => trim($row['分貝增減'] ?? 0),
'vocal' => trim($row['人聲'] ?? 0),
'situation' => SongSituation::tryFrom(trim($row['情境'] ?? '')) ?? SongSituation::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['備註01'] ?? ''),
'note02' => trim($row['備註02'] ?? ''),
'note03' => trim($row['備註03'] ?? ''),
'note04' => trim($row['備註04'] ?? ''),
'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),
];
// 歌星 A/B 處理
foreach (['歌星A', '歌星B'] as $key) {
$artistName = trim($row[$key] ?? '');
if ($artistName === '') continue;
// 若是歌星B且與歌星A相同則跳過
if ($key === '歌星B' && $artistName === trim($row['歌星A'] ?? '')) continue;
$artistId = $this->getOrCreateArtistId($artistName);
$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) {
@ -115,7 +167,7 @@ class SongDataImport implements ToCollection, WithHeadingRow, WithChunkReading
public function chunkSize(): int
{
return 1000;
return 100;
}
public function headingRow(): int

View File

@ -33,6 +33,8 @@ class ImportArtistJob implements ShouldQueue
*/
public function handle(): void
{
ini_set('memory_limit', '-1'); // ✅ 增加記憶體限制
Excel::import(new ArtistDataImport, $this->filePath);
// 匯入完成後刪除檔案
if (Storage::exists($this->filePath)) {

View 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);
}
}
}

View File

@ -2,14 +2,19 @@
namespace App\Livewire\Admin;
use Livewire\Component;
use Illuminate\Validation\Rule;
use Illuminate\Support\Facades\Auth;
use Livewire\Component;
use WireUi\Traits\WireUiActions;
use App\Models\Artist;
use App\Enums\ArtistCategory;
class ArtistForm extends Component
{
use WireUiActions;
protected $listeners = ['openModal','closeModal', 'deleteArtist'];
public bool $canCreate;
@ -65,19 +70,19 @@ class ArtistForm extends Component
if ($this->canEdit) {
$artist = Artist::findOrFail($this->artistId);
$artist->update($this->fields);
$this->dispatch('notify', [
$this->notification()->send([
'icon' => 'success',
'title' => '成功',
'description' => '歌手已更新',
'icon' => 'success',
]);
}
} else {
if ($canCreate) {
$artist = Artist::create($this->fields);
$this->dispatch('notify', [
$this->notification()->send([
'icon' => 'success',
'title' => '成功',
'description' => '歌手已新增',
'icon' => 'success',
]);
}
}
@ -90,7 +95,12 @@ class ArtistForm extends Component
{
if ($this->canDelect) {
Artist::findOrFail($id)->delete();
session()->flash('message', '歌手已刪除');
$this->notification()->send([
'icon' => 'success',
'title' => '成功',
'description' => '歌手已刪除',
]);
$this->dispatch('pg:eventRefresh-artist-table');
}
}

View File

@ -3,14 +3,17 @@
namespace App\Livewire\Admin;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\File;
use WireUi\Traits\WireUiActions;
use Livewire\Component;
use Livewire\WithFileUploads;
use App\Jobs\ImportArtistJob;
use Illuminate\Support\Facades\Storage;
class ArtistImportData extends Component
{
use WithFileUploads;
use WithFileUploads, WireUiActions;
protected $listeners = ['openModal','closeModal'];
@ -20,6 +23,8 @@ class ArtistImportData extends Component
public $file;
public string|null $tmpPath = null;
public function mount()
{
$this->canCreate = Auth::user()?->can('song-edit') ?? false;
@ -29,8 +34,11 @@ class ArtistImportData extends Component
{
$this->showModal = true;
}
public function closeModal()
{
$this->deleteTmpFile(); // 關閉 modal 時刪除暫存檔案
$this->reset(['file', 'tmpPath']);
$this->showModal = false;
}
@ -41,15 +49,28 @@ class ArtistImportData extends Component
'file' => 'required|file|mimes:csv,xlsx,xls'
]);
if ($this->canCreate) {
// 取得原始 tmp 路徑
$tmpPath = $this->file->getRealPath();
// 儲存檔案至 storage
$path = $this->file->storeAs('imports', uniqid() . '_' . $this->file->getClientOriginalName());
// 丟到 queue 執行
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;
session()->flash('message', '已排入背景匯入作業,請稍候查看結果');
}
}
protected function deleteTmpFile()
{
if ($this->tmpPath && File::exists($this->tmpPath)) {
File::delete($this->tmpPath);
}
}

View File

@ -19,9 +19,12 @@ use PowerComponents\LivewirePowerGrid\Traits\WithExport;
use PowerComponents\LivewirePowerGrid\Components\SetUp\Exportable;
use PowerComponents\LivewirePowerGrid\Facades\Rule;
use Livewire\Attributes\On;
use WireUi\Traits\WireUiActions;
final class ArtistTable extends PowerGridComponent
{
use WireUiActions;
public string $tableName = 'artist-table';
public bool $canCreate;
public bool $canEdit;
@ -166,12 +169,24 @@ final class ArtistTable extends PowerGridComponent
$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){
$artist = Artist::find($id);
if ($artist) {
$artist->{$field} = $value;
$artist->save(); // 明確觸發 saving
}
$this->notification()->send([
'icon' => 'success',
'title' => $id.'.'.__('artists.'.$field).':'.$value,
'description' => '已經寫入',
]);
}
public function filters(): array

View File

@ -2,15 +2,25 @@
namespace App\Livewire\Admin;
use Illuminate\Validation\Rule;
use Illuminate\Support\Facades\Auth;
use Livewire\Component;
use WireUi\Traits\WireUiActions;
use Spatie\Permission\Models\Role;
use Spatie\Permission\Models\Permission;
class RoleForm extends Component
{
use WireUiActions;
protected $listeners = ['openCreateRoleModal','openEditRoleModal', 'deleteRole'];
public bool $canCreate;
public bool $canEdit;
public bool $canDelect;
public $showCreateModal=false;
public ?int $roleId = null;
public $name = '';
@ -22,6 +32,9 @@ class RoleForm extends Component
public function mount()
{
$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()
@ -47,14 +60,26 @@ class RoleForm extends Component
]);
if ($this->roleId) {
$role = Role::findOrFail($this->roleId);
$role->update(['name' => $this->name]);
$role->syncPermissions($this->selectedPermissions);
session()->flash('message', '角色已更新');
if ($this->canEdit) {
$role = Role::findOrFail($this->roleId);
$role->update(['name' => $this->name]);
$role->syncPermissions($this->selectedPermissions);
$this->notification()->send([
'icon' => 'success',
'title' => '成功',
'description' => '角色已更新',
]);
}
} else {
$role = Role::create(['name' => $this->name]);
$role->syncPermissions($this->selectedPermissions);
session()->flash('message', '角色已新增');
if ($canCreate) {
$role = Role::create(['name' => $this->name]);
$role->syncPermissions($this->selectedPermissions);
$this->notification()->send([
'icon' => 'success',
'title' => '成功',
'description' => '角色已新增',
]);
}
}
$this->resetFields();
@ -64,8 +89,15 @@ class RoleForm extends Component
public function deleteRole($id)
{
Role::findOrFail($id)->delete();
session()->flash('message', '角色已刪除');
if ($this->canDelect) {
Role::findOrFail($id)->delete();
$this->notification()->send([
'icon' => 'success',
'title' => '成功',
'description' => '角色已刪除',
]);
$this->dispatch('pg:eventRefresh-role-table');
}
}
public function resetFields()

View File

@ -13,9 +13,13 @@ use PowerComponents\LivewirePowerGrid\Facades\Filter;
use PowerComponents\LivewirePowerGrid\Facades\PowerGrid;
use PowerComponents\LivewirePowerGrid\PowerGridFields;
use PowerComponents\LivewirePowerGrid\PowerGridComponent;
use Livewire\Attributes\On;
use WireUi\Traits\WireUiActions;
final class RoleTable extends PowerGridComponent
{
use WireUiActions;
public string $tableName = 'role-table';
public bool $canCreate;
public bool $canEdit;
@ -128,6 +132,11 @@ final class RoleTable extends PowerGridComponent
$role->{$field} = $value;
$role->save(); // 明確觸發 saving
}
$this->notification()->send([
'icon' => 'success',
'title' => $id.'.'.__('roles.'.$field).':'.$value,
'description' => '已經寫入',
]);
}
public function filters(): array
{

View File

@ -2,7 +2,11 @@
namespace App\Livewire\Admin;
use Illuminate\Validation\Rule;
use Illuminate\Support\Facades\Auth;
use Livewire\Component;
use WireUi\Traits\WireUiActions;
use App\Enums\SongLanguageType;
use App\Enums\SongSituation;
@ -11,7 +15,13 @@ use App\Models\SongCategory;
class SongForm extends Component
{
use WireUiActions;
protected $listeners = ['openModal','closeModal', 'deleteSong'];
public bool $canCreate;
public bool $canEdit;
public bool $canDelect;
public bool $showModal = false;
@ -88,10 +98,18 @@ class SongForm extends Component
if ($this->songId) {
$song = Song::findOrFail($this->songId);
$song->update($this->fields);
session()->flash('message', '歌曲已更新');
$this->notification()->send([
'icon' => 'success',
'title' => '成功',
'description' => '歌曲已更新',
]);
} else {
$song = Song::create($this->fields);
session()->flash('message', '歌曲已新增');
$this->notification()->send([
'icon' => 'success',
'title' => '成功',
'description' => '歌曲已新增',
]);
}
// ⭐ 同步多對多關聯
$song->artists()->sync($this->selectedArtists ?? []);
@ -105,7 +123,11 @@ class SongForm extends Component
public function deleteSong($id)
{
Song::findOrFail($id)->delete();
session()->flash('message', '歌曲已刪除');
$this->notification()->send([
'icon' => 'success',
'title' => '成功',
'description' => '歌曲已刪除',
]);
}
public function resetFields()

View File

@ -3,14 +3,17 @@
namespace App\Livewire\Admin;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\File;
use WireUi\Traits\WireUiActions;
use Livewire\Component;
use Livewire\WithFileUploads;
use Maatwebsite\Excel\Facades\Excel;
use App\Imports\SongDataImport;
use App\Jobs\ImportSongJob;
class SongImportData extends Component
{
use WithFileUploads;
use WithFileUploads, WireUiActions;
protected $listeners = ['openModal','closeModal'];
@ -20,6 +23,8 @@ class SongImportData extends Component
public $file;
public string|null $tmpPath = null;
public function mount()
{
$this->canCreate = Auth::user()?->can('song-edit') ?? false;
@ -29,8 +34,11 @@ class SongImportData extends Component
{
$this->showModal = true;
}
public function closeModal()
{
$this->deleteTmpFile(); // 關閉 modal 時刪除暫存檔案
$this->reset(['file', 'tmpPath']);
$this->showModal = false;
}
@ -41,13 +49,28 @@ class SongImportData extends Component
'file' => 'required|file|mimes:csv,xlsx,xls'
]);
if ($this->canCreate) {
$import = new SongDataImport();
Excel::import($import, $this->file);
$success = $import->successCount;
$fail = $import->failCount;
$this->reset('file');
$this->showModal =false;
session()->flash('message', '匯入完成:成功 $success 筆,失敗 $fail 筆。');
// 取得原始 tmp 路徑
$tmpPath = $this->file->getRealPath();
// 儲存檔案至 storage
$path = $this->file->storeAs('imports', uniqid() . '_' . $this->file->getClientOriginalName());
// 丟到 queue 執行
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);
}
}

View File

@ -20,9 +20,12 @@ use PowerComponents\LivewirePowerGrid\Traits\WithExport;
use PowerComponents\LivewirePowerGrid\Components\SetUp\Exportable;
use PowerComponents\LivewirePowerGrid\Facades\Rule;
use Livewire\Attributes\On;
use WireUi\Traits\WireUiActions;
final class SongTable extends PowerGridComponent
{
use WireUiActions;
public string $tableName = 'song-table';
public bool $canCreate;
public bool $canEdit;
@ -203,7 +206,14 @@ final class SongTable extends PowerGridComponent
{
$this->js('alert(window.pgBulkActions.get(\'' . $this->tableName . '\'))');
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.
}
}
@ -238,6 +248,11 @@ final class SongTable extends PowerGridComponent
$song->{$field} = $value;
$song->save(); // 明確觸發 saving
}
$this->notification()->send([
'icon' => 'success',
'title' => $id.'.'.__('songs.'.$field).':'.$value,
'description' => '已經寫入',
]);
}

View File

@ -2,7 +2,11 @@
namespace App\Livewire\Admin;
use Illuminate\Validation\Rule;
use Illuminate\Support\Facades\Auth;
use Livewire\Component;
use WireUi\Traits\WireUiActions;
use App\Models\User;
use App\Enums\UserGender;
@ -11,10 +15,15 @@ use Spatie\Permission\Models\Role;
class UserForm extends Component
{
use WireUiActions;
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 $statusOptions =[];
@ -52,6 +61,9 @@ class UserForm extends Component
'value' => $status->value,
])->toArray();
$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()
@ -72,17 +84,29 @@ class UserForm extends Component
public function save()
{
$this->validate();
//$this->validate();
if ($this->userId) {
$user = User::findOrFail($this->userId);
$user->update($this->fields);
$user->syncRoles($this->selectedRoles);
session()->flash('message', '使用者已更新');
if ($this->canEdit) {
$user = User::findOrFail($this->userId);
$user->update($this->fields);
$user->syncRoles($this->selectedRoles);
$this->notification()->send([
'icon' => 'success',
'title' => '成功',
'description' => '使用者已更新',
]);
}
} else {
$user = User::create($this->fields);
$user->syncRoles($this->selectedRoles);
session()->flash('message', '使用者已新增');
if ($canCreate) {
$user = User::create($this->fields);
$user->syncRoles($this->selectedRoles);
$this->notification()->send([
'icon' => 'success',
'title' => '成功',
'description' => '使用者已新增',
]);
}
}
$this->resetFields();
@ -92,8 +116,15 @@ class UserForm extends Component
public function deleteUser($id)
{
User::findOrFail($id)->delete();
session()->flash('message', '使用者已刪除');
if ($this->canDelect) {
User::findOrFail($id)->delete();
$this->notification()->send([
'icon' => 'success',
'title' => '成功',
'description' => '使用者已刪除',
]);
$this->dispatch('pg:eventRefresh-user-table');
}
}
public function resetFields()

View File

@ -19,9 +19,11 @@ use PowerComponents\LivewirePowerGrid\PowerGridComponent;
use PowerComponents\LivewirePowerGrid\Components\SetUp\Exportable;
use PowerComponents\LivewirePowerGrid\Facades\Rule;
use Livewire\Attributes\On;
use WireUi\Traits\WireUiActions;
final class UserTable extends PowerGridComponent
{
use WireUiActions;
//use WithExport ;
public string $tableName = 'user-table';
@ -174,7 +176,7 @@ final class UserTable extends PowerGridComponent
if ($this->canDelect) {
$this->js('alert(window.pgBulkActions.get(\'' . $this->tableName . '\'))');
if($this->checkboxValues){
Artist::destroy($this->checkboxValues);
User::destroy($this->checkboxValues);
$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){
$artist = Artist::find($id);
if ($artist) {
$artist->{$field} = $value;
$artist->save(); // 明確觸發 saving
$user = User::find($id);
if ($user) {
$user->{$field} = $value;
$user->save(); // 明確觸發 saving
}
$this->notification()->send([
'icon' => 'success',
'title' => $id.'.'.__('users.'.$field).':'.$value,
'description' => '已經寫入',
]);
}
public function filters(): array
{

View File

@ -31,6 +31,7 @@ class Song extends Model
'phonetic_abbr',
'pinyin_abbr',
'strokes_abbr',
'song_number',
'song_counts',
];
@ -77,6 +78,7 @@ class Song extends Model
$chars = preg_split('//u', $song->name, -1, PREG_SPLIT_NO_EMPTY);
$firstChar = $chars[0] ?? null;
$song->strokes_abbr=$firstChar ? ChineseStrokesConverter::getStrokes($firstChar) : null;
$song->song_number = mb_strlen($song->name, 'UTF-8');
});
}
}

View File

@ -31,6 +31,7 @@ return new class extends Migration
$table->string('phonetic_abbr')->comment('歌曲注音');
$table->string('pinyin_abbr')->comment('歌曲拼音');
$table->integer('strokes_abbr')->default(0)->comment('歌曲筆劃');
$table->integer('song_number')->default(0)->comment('歌曲字數');
$table->integer('song_counts')->default(0)->comment('點播次數');
$table->timestamps();
});

View File

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

View File

@ -1,18 +1,6 @@
<x-layouts.admin>
<x-wireui:notifications />
<script>
window.$wireui.notify({
title: '提示',
description: '{{ session('message') }}',
icon: 'success'
});
</script>
{{-- 單一 Livewire 元件,內含資料表與 Modal --}}
<x-wireui:notifications/>
<livewire:admin.artist-table />
<livewire:admin.artist-form />
<livewire:admin.artist-import-data />

View File

@ -1,17 +1,6 @@
<x-layouts.admin>
@if (session()->has('message'))
<x-wireui:notifications />
<script>
window.$wireui.notify({
title: '提示',
description: '{{ session('message') }}',
icon: 'success'
});
</script>
@endif
{{-- 單一 Livewire 元件,內含資料表與 Modal --}}
<x-wireui:notifications/>
<livewire:admin.role-table />
<livewire:admin.role-form />
</x-layouts.admin>

View File

@ -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 --}}
@ -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>
</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">歌星A</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>
</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>
<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">可填入多個分類代碼(用 , 分隔A1(情歌),B1(選秀),C1(串燒),D1(90),E1(懷念),F1(大陸)</td>
<td class="border border-gray-300 px-3 py-1">A1,B1,C1,D1,E1,F1</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>
<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">519</td>
</tr>
<tr>
<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>
</tr>
<tr>
<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>
</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>
</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>
</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>
</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">2023重錄版</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>
@ -107,9 +107,29 @@
<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">128</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>
</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>
</tbody>
</table>

View File

@ -1,17 +1,6 @@
<x-layouts.admin>
@if (session()->has('message'))
<x-wireui:notifications />
<script>
window.$wireui.notify({
title: '提示',
description: '{{ session('message') }}',
icon: 'success'
});
</script>
@endif
{{-- 單一 Livewire 元件,內含資料表與 Modal --}}
<x-wireui:notifications/>
<livewire:admin.song-table />
<livewire:admin.song-form />
<livewire:admin.song-import-data />

View File

@ -1,17 +1,6 @@
<x-layouts.admin>
@if (session()->has('message'))
<x-wireui:notifications />
<script>
window.$wireui.notify({
title: '提示',
description: '{{ session('message') }}',
icon: 'success'
});
</script>
@endif
{{-- 單一 Livewire 元件,內含資料表與 Modal --}}
<x-wireui:notifications/>
<livewire:admin.user-table />
<livewire:admin.user-form />
</x-layouts.admin>