加入完成訊息
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)
|
||||
{
|
||||
$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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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)) {
|
||||
|
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;
|
||||
|
||||
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');
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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()
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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()
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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' => '已經寫入',
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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()
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
});
|
||||
|
@ -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">
|
||||
|
@ -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 />
|
||||
|
@ -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>
|
@ -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>
|
||||
|
@ -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 />
|
||||
|
@ -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>
|
Loading…
x
Reference in New Issue
Block a user