加入 ⻆色權限控制
修正 'n' => 'ㄣ' 轉值問題 加入 歌手搜尋功能 DB 開 點播次數欄位 20250505
This commit is contained in:
parent
077d418357
commit
d9924bf05b
@ -2,8 +2,12 @@
|
||||
|
||||
namespace App\Enums;
|
||||
|
||||
use App\Enums\Traits\HasLabels;
|
||||
|
||||
enum ArtistCategory: string
|
||||
{
|
||||
use HasLabels;
|
||||
|
||||
case Unset = '未定義';
|
||||
case Male = '男';
|
||||
case Female = '女';
|
||||
@ -23,9 +27,4 @@ enum ArtistCategory: string
|
||||
self::Unset => __('enums.Unset'),
|
||||
};
|
||||
}
|
||||
|
||||
public function labelPowergridFilter(): String
|
||||
{
|
||||
return $this -> labels();
|
||||
}
|
||||
}
|
@ -2,8 +2,12 @@
|
||||
|
||||
namespace App\Enums;
|
||||
|
||||
use App\Enums\Traits\HasLabels;
|
||||
|
||||
enum SongLanguageType: string
|
||||
{
|
||||
use HasLabels;
|
||||
|
||||
case Unset = '未定義';
|
||||
case Mandarin = '國語';
|
||||
case Taiwanese = '台語';
|
||||
@ -31,9 +35,4 @@ enum SongLanguageType: string
|
||||
self::Other => __('enums.song.LanguageType.Other'),
|
||||
};
|
||||
}
|
||||
|
||||
public function labelPowergridFilter(): String
|
||||
{
|
||||
return $this -> labels();
|
||||
}
|
||||
}
|
@ -2,8 +2,12 @@
|
||||
|
||||
namespace App\Enums;
|
||||
|
||||
use App\Enums\Traits\HasLabels;
|
||||
|
||||
enum SongSituation: string
|
||||
{
|
||||
use HasLabels;
|
||||
|
||||
case Unset = '未定義';
|
||||
case Romantic = '浪漫';
|
||||
case Soft = '柔和';
|
||||
@ -22,8 +26,4 @@ enum SongSituation: string
|
||||
};
|
||||
}
|
||||
|
||||
public function labelPowergridFilter(): String
|
||||
{
|
||||
return $this -> labels();
|
||||
}
|
||||
}
|
20
app/Enums/Traits/HasLabels.php
Normal file
20
app/Enums/Traits/HasLabels.php
Normal file
@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace App\Enums\Traits;
|
||||
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
trait HasLabels
|
||||
{
|
||||
public static function options(): Collection
|
||||
{
|
||||
return collect(self::cases())->mapWithKeys(function (self $case) {
|
||||
return [$case->value => $case->labels()];
|
||||
});
|
||||
}
|
||||
|
||||
public function labelPowergridFilter(): string
|
||||
{
|
||||
return $this->labels();
|
||||
}
|
||||
}
|
@ -2,8 +2,12 @@
|
||||
|
||||
namespace App\Enums;
|
||||
|
||||
use App\Enums\Traits\HasLabels;
|
||||
|
||||
enum UserGender: string
|
||||
{
|
||||
use HasLabels;
|
||||
|
||||
case Male = 'male';
|
||||
case Female = 'female';
|
||||
case Other = 'other';
|
||||
@ -20,8 +24,4 @@ enum UserGender: string
|
||||
};
|
||||
}
|
||||
|
||||
public function labelPowergridFilter(): String
|
||||
{
|
||||
return $this -> labels();
|
||||
}
|
||||
}
|
@ -2,8 +2,12 @@
|
||||
|
||||
namespace App\Enums;
|
||||
|
||||
use App\Enums\Traits\HasLabels;
|
||||
|
||||
enum UserStatus: int
|
||||
{
|
||||
use HasLabels;
|
||||
|
||||
case Active = 0; // 正常
|
||||
case Suspended = 1; // 停權
|
||||
case Deleting = 2; // 刪除中
|
||||
@ -17,9 +21,5 @@ enum UserStatus: int
|
||||
self::Deleting => __('enums.user.status.Deleting'),
|
||||
};
|
||||
}
|
||||
public function labelPowergridFilter(): String
|
||||
{
|
||||
return $this -> labels();
|
||||
}
|
||||
|
||||
}
|
@ -8,7 +8,7 @@ use Overtrue\Pinyin\Pinyin;
|
||||
class ChineseNameConverter
|
||||
{
|
||||
public static array $pinyinToZhuyinMap = [
|
||||
'a' => 'ㄚ' ,'o' => 'ㄛ' ,'e' => 'ㄜ' ,'er' => 'ㄦ','ai' => 'ㄞ' ,'ei' => 'ㄟ' ,'ao' => 'ㄠ' ,'ou' => 'ㄡ' ,'an' => 'ㄢ' ,'en' => 'ㄣ'
|
||||
'a' => 'ㄚ' ,'o' => 'ㄛ' ,'e' => 'ㄜ' ,'er' => 'ㄦ','ai' => 'ㄞ' ,'ei' => 'ㄟ' ,'ao' => 'ㄠ' ,'ou' => 'ㄡ' ,'an' => 'ㄢ' ,'n' => 'ㄣ','en' => 'ㄣ'
|
||||
,'ang' => 'ㄤ' ,'eng' => 'ㄥ' ,'yi' => 'ㄧ' ,'ya' => 'ㄧㄚ' ,'yo' => 'ㄧㄛ' ,'ye' => 'ㄧㄝ' ,'yai' => 'ㄧㄞ' ,'yao' => 'ㄧㄠ'
|
||||
,'you' => 'ㄧㄡ' ,'yan' => 'ㄧㄢ' ,'yin' => 'ㄧㄣ' ,'yang' => 'ㄧㄤ' ,'ying' => 'ㄧㄥ' ,'wu' => 'ㄨ' ,'wa' => 'ㄨㄚ' ,'wo' => 'ㄨㄛ'
|
||||
,'wai' => 'ㄨㄞ' ,'wei' => 'ㄨㄟ' ,'wan' => 'ㄨㄢ' ,'wen' => 'ㄨㄣ' ,'wang' => 'ㄨㄤ' ,'weng' => 'ㄨㄥ' ,'yu' => 'ㄩ' ,'yue' => 'ㄩㄝ'
|
||||
@ -79,6 +79,7 @@ class ChineseNameConverter
|
||||
'ū'=>'u', 'ú'=>'u', 'ǔ'=>'u', 'ù'=>'u',
|
||||
//'ǖ'=>'ü','ǘ'=>'ü','ǚ'=>'ü','ǜ'=>'ü',
|
||||
'ǖ'=>'u','ǘ'=>'u','ǚ'=>'u','ǜ'=>'u',
|
||||
'ǹ'=>'n',
|
||||
|
||||
];
|
||||
return strtr($pinyin, $map);
|
||||
|
30
app/Http/Controllers/ArtistController.php
Normal file
30
app/Http/Controllers/ArtistController.php
Normal file
@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\Artist;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class ArtistController extends Controller
|
||||
{
|
||||
|
||||
public function search(Request $request)
|
||||
{
|
||||
$query = Artist::query();
|
||||
|
||||
if ($request->filled('selected')) {
|
||||
// 取得已選擇的項目(初始化時用)
|
||||
return $query->whereIn('id', (array) $request->input('selected'))
|
||||
->get(['id', 'name']);
|
||||
}
|
||||
|
||||
if ($request->filled('search')) {
|
||||
// 關鍵字搜尋(選單輸入文字時用)
|
||||
$search = $request->input('search');
|
||||
$query->where('name', 'like', "%{$search}%");
|
||||
}
|
||||
|
||||
return $query->limit(10)->get(['id', 'name']);
|
||||
}
|
||||
|
||||
}
|
@ -2,7 +2,12 @@
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
abstract class Controller
|
||||
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
|
||||
use Illuminate\Foundation\Bus\DispatchesJobs;
|
||||
use Illuminate\Foundation\Validation\ValidatesRequests;
|
||||
use Illuminate\Routing\Controller as BaseController;
|
||||
|
||||
class Controller extends BaseController
|
||||
{
|
||||
//
|
||||
use AuthorizesRequests, DispatchesJobs, ValidatesRequests;
|
||||
}
|
@ -6,6 +6,7 @@ use App\Models\Artist;
|
||||
use App\Enums\ArtistCategory;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Blade;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use PowerComponents\LivewirePowerGrid\Button;
|
||||
@ -22,6 +23,10 @@ use Livewire\Attributes\On;
|
||||
final class ArtistTable extends PowerGridComponent
|
||||
{
|
||||
public string $tableName = 'artist-table';
|
||||
public bool $canCreate;
|
||||
public bool $canEdit;
|
||||
public bool $canDownload;
|
||||
public bool $canDelect;
|
||||
|
||||
//public bool $deferLoading = true;
|
||||
//public string $loadingComponent = 'components.power-grid-loading';
|
||||
@ -31,36 +36,47 @@ final class ArtistTable extends PowerGridComponent
|
||||
public function boot(): void
|
||||
{
|
||||
config(['livewire-powergrid.filter' => 'outside']);
|
||||
//權限設定
|
||||
$this->canCreate = Auth::user()?->can('song-edit') ?? false;
|
||||
$this->canEdit = Auth::user()?->can('song-edit') ?? false;
|
||||
$this->canDownload=Auth::user()?->can('song-delete') ?? false;
|
||||
$this->canDelect = Auth::user()?->can('song-delete') ?? false;
|
||||
}
|
||||
|
||||
public function setUp(): array
|
||||
{
|
||||
//$this->showCheckBox();
|
||||
if($this->canDownload || $this->canDelect){
|
||||
$this->showCheckBox();
|
||||
}
|
||||
|
||||
return [
|
||||
//PowerGrid::exportable(fileName: 'artist-file')
|
||||
// ->type(Exportable::TYPE_XLS, Exportable::TYPE_CSV),
|
||||
PowerGrid::header()
|
||||
$actions = [];
|
||||
if($this->canDownload){
|
||||
$actions[]=PowerGrid::exportable(fileName: 'artist-file')
|
||||
->type(Exportable::TYPE_XLS, Exportable::TYPE_CSV);
|
||||
}
|
||||
$header = PowerGrid::header()
|
||||
->withoutLoading()
|
||||
->showToggleColumns()
|
||||
->showToggleColumns();
|
||||
//->showSoftDeletes()
|
||||
//->showSearchInput()
|
||||
->includeViewOnTop('livewire.admin.artist-header')
|
||||
,
|
||||
PowerGrid::footer()
|
||||
->showPerPage()
|
||||
->showRecordCount(),
|
||||
];
|
||||
if($this->canCreate){
|
||||
$header->includeViewOnTop('livewire.admin.artist-header') ;
|
||||
}
|
||||
$actions[]=$header;
|
||||
$actions[]=PowerGrid::footer()->showPerPage()->showRecordCount();
|
||||
return $actions;
|
||||
}
|
||||
public function header(): array
|
||||
{
|
||||
return [
|
||||
/* Button::add('bulk-delete')
|
||||
$actions = [];
|
||||
if ($this->canDelect) {
|
||||
$actions[]=Button::add('bulk-delete')
|
||||
->slot('Bulk delete (<span x-text="window.pgBulkActions.count(\'' . $this->tableName . '\')"></span>)')
|
||||
->icon('solid-trash',['id' => 'my-custom-icon-id', 'class' => 'font-bold'])
|
||||
->class('inline-flex items-center gap-1 px-3 py-1 rounded ')
|
||||
->dispat ch('bulkDelete.' . $this->tableName, []),*/
|
||||
];
|
||||
->dispatch('bulkDelete.' . $this->tableName, []);
|
||||
}
|
||||
return $actions;
|
||||
}
|
||||
|
||||
public function datasource(): Builder
|
||||
@ -75,19 +91,23 @@ final class ArtistTable extends PowerGridComponent
|
||||
|
||||
public function fields(): PowerGridFields
|
||||
{
|
||||
$options = $this->categorySelectOptions();
|
||||
|
||||
return PowerGrid::fields()
|
||||
->add('id')
|
||||
->add('category_str', function (Artist $model) use ($options){
|
||||
->add('category_str', function (Artist $model) {
|
||||
if ($this->canEdit) {
|
||||
return Blade::render(
|
||||
'<x-select-category type="occurrence" :options=$options :modelId=$modelId :fieldName=$fieldName :selected=$selected/>',
|
||||
[
|
||||
'options' => $options,
|
||||
'options' => ArtistCategory::options(),
|
||||
'modelId' => intval($model->id),
|
||||
'fieldName'=>'category',
|
||||
'selected' => $model->category->value
|
||||
]);
|
||||
]
|
||||
);
|
||||
}
|
||||
// 沒有權限就顯示對應的文字
|
||||
|
||||
return $model->category->labelPowergridFilter(); // 假設 label() 會回傳顯示文字
|
||||
} )
|
||||
->add('name')
|
||||
->add('simplified')
|
||||
@ -99,51 +119,59 @@ final class ArtistTable extends PowerGridComponent
|
||||
|
||||
public function columns(): array
|
||||
{
|
||||
return [
|
||||
Column::make(__('artists.no'), 'id'),
|
||||
Column::make(__('artists.category'),'category_str', 'artists.category')->searchable(),
|
||||
Column::make(__('artists.name'), 'name')
|
||||
->sortable()
|
||||
->searchable(),
|
||||
$column=[];
|
||||
$column[]=Column::make(__('artists.no'), 'id');
|
||||
$column[]=Column::make(__('artists.category'),'category_str', 'artists.category')->searchable();
|
||||
$column[]=Column::make(__('artists.name'), 'name')->sortable()->searchable()
|
||||
->editOnClick(
|
||||
hasPermission: $this->canEdit,
|
||||
dataField: 'name',
|
||||
fallback: 'N/A',
|
||||
saveOnMouseOut: true
|
||||
);
|
||||
$column[]=Column::make(__('artists.name.simplified'), 'simplified')->sortable()->searchable()->hidden(true, false);
|
||||
$column[]=Column::make(__('artists.name.phinetic'), 'phonetic_abbr')->sortable()->searchable();
|
||||
$column[]=Column::make(__('artists.name.pinyin'), 'pinyin_abbr')->sortable()->searchable();
|
||||
$column[]=Column::make(__('artists.name.strokes'), 'strokes_abbr')->sortable()->searchable();
|
||||
$column[]=Column::make('Created at', 'created_at_formatted', 'created_at')->sortable()->hidden(true, false);
|
||||
$column[]=Column::action(__('artists.actions'));
|
||||
|
||||
Column::make(__('artists.name.simplified'), 'simplified')
|
||||
->sortable()
|
||||
->searchable()
|
||||
->hidden(true, false),
|
||||
|
||||
Column::make(__('artists.name.phinetic'), 'phonetic_abbr')
|
||||
->sortable()
|
||||
->searchable(),
|
||||
|
||||
Column::make(__('artists.name.pinyin'), 'pinyin_abbr')
|
||||
->sortable()
|
||||
->searchable(),
|
||||
Column::make(__('artists.name.strokes'), 'strokes_abbr')
|
||||
->sortable()
|
||||
->searchable(),
|
||||
|
||||
Column::make('Created at', 'created_at_formatted', 'created_at')
|
||||
->sortable()
|
||||
->hidden(true, false),
|
||||
|
||||
Column::action(__('artists.actions'))
|
||||
];
|
||||
return $column;
|
||||
}
|
||||
|
||||
public function categorySelectOptions():Collection
|
||||
#[On('bulkDelete.{tableName}')]
|
||||
public function bulkDelete(): void
|
||||
{
|
||||
return collect(ArtistCategory::cases())->mapWithKeys(function (ArtistCategory $case) {
|
||||
return [$case->value => $case->labels()];
|
||||
});
|
||||
if ($this->canDelect) {
|
||||
$this->js('alert(window.pgBulkActions.get(\'' . $this->tableName . '\'))');
|
||||
if($this->checkboxValues){
|
||||
Artist::destroy($this->checkboxValues);
|
||||
$this->js('window.pgBulkActions.clearAll()'); // clear the count on the interface.
|
||||
}
|
||||
}
|
||||
}
|
||||
#[On('categoryChanged')]
|
||||
public function categoryChanged($value,$fieldName, $modelId): void
|
||||
{
|
||||
// dd($value,$fieldName, $modelId);
|
||||
if($fieldName=='category'){
|
||||
Artist::find($modelId)?->update([$fieldName => $value]);
|
||||
if ($fieldName == 'category' && $this->canEdit) {
|
||||
$this->noUpdated($modelId,$fieldName,$value);
|
||||
}
|
||||
}
|
||||
#[On('onUpdatedEditable')]
|
||||
public function onUpdatedEditable($id, $field, $value): void
|
||||
{
|
||||
if ($field === 'name' && $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
|
||||
}
|
||||
}
|
||||
|
||||
public function filters(): array
|
||||
{
|
||||
return [
|
||||
@ -157,32 +185,24 @@ final class ArtistTable extends PowerGridComponent
|
||||
Filter::datetimepicker('created_at'),
|
||||
];
|
||||
}
|
||||
|
||||
/* #[On('bulkDelete.{tableName}')]
|
||||
public function bulkDelete(): void
|
||||
{
|
||||
$this->js('alert(window.pgBulkActions.get(\'' . $this->tableName . '\'))');
|
||||
if($this->checkboxValues){
|
||||
Artist::destroy($this->checkboxValues);
|
||||
$this->js('window.pgBulkActions.clearAll()'); // clear the count on the interface.
|
||||
}
|
||||
} */
|
||||
|
||||
public function actions(Artist $row): array
|
||||
{
|
||||
return [
|
||||
|
||||
Button::add('edit')
|
||||
$actions = [];
|
||||
if ($this->canEdit) {
|
||||
$actions[] =Button::add('edit')
|
||||
->slot(__('artists.edit'))
|
||||
->icon('solid-pencil-square')
|
||||
->class('inline-flex items-center gap-1 px-3 py-1 rounded ')
|
||||
->dispatchTo('admin.artist-form', 'openEditArtistModal', ['id' => $row->id]),
|
||||
/* Button::add('delete')
|
||||
->dispatchTo('admin.artist-form', 'openEditArtistModal', ['id' => $row->id]);
|
||||
}
|
||||
if($this->canDelect){
|
||||
$actions[] =Button::add('delete')
|
||||
->slot(__('artists.delete'))
|
||||
->icon('solid-trash')
|
||||
->class('inline-flex items-center gap-1 px-3 py-1 rounded ')
|
||||
->dispatchTo('admin.artist-form', 'deleteArtist', ['id' => $row->id]), */
|
||||
];
|
||||
->dispatchTo('admin.artist-form', 'deleteArtist', ['id' => $row->id]);
|
||||
}
|
||||
return $actions;
|
||||
}
|
||||
|
||||
|
||||
|
@ -5,6 +5,7 @@ namespace App\Livewire\Admin;
|
||||
use Spatie\Permission\Models\Role;
|
||||
use Spatie\Permission\Models\Permission;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use PowerComponents\LivewirePowerGrid\Button;
|
||||
use PowerComponents\LivewirePowerGrid\Column;
|
||||
@ -16,24 +17,46 @@ use PowerComponents\LivewirePowerGrid\PowerGridComponent;
|
||||
final class RoleTable extends PowerGridComponent
|
||||
{
|
||||
public string $tableName = 'role-table';
|
||||
public bool $canCreate;
|
||||
public bool $canEdit;
|
||||
public bool $canDelect;
|
||||
|
||||
public function boot(): void
|
||||
{
|
||||
config(['livewire-powergrid.filter' => 'outside']);
|
||||
//權限設定
|
||||
$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 setUp(): array
|
||||
{
|
||||
//$this->showCheckBox();
|
||||
|
||||
return [
|
||||
PowerGrid::header()
|
||||
// ->showSearchInput(),
|
||||
->includeViewOnTop('livewire.admin.role-header'),
|
||||
//PowerGrid::footer()
|
||||
// ->showPerPage()
|
||||
// ->showRecordCount(),
|
||||
];
|
||||
if($this->canDelect){
|
||||
$this->showCheckBox();
|
||||
}
|
||||
$actions = [];
|
||||
$header =PowerGrid::header();
|
||||
if($this->canCreate){
|
||||
$header->includeViewOnTop('livewire.admin.role-header');
|
||||
}
|
||||
$actions[]=$header;
|
||||
$actions[]=PowerGrid::footer()
|
||||
->showPerPage()
|
||||
->showRecordCount();
|
||||
return $actions;
|
||||
}
|
||||
public function header(): array
|
||||
{
|
||||
$actions = [];
|
||||
if ($this->canDelect) {
|
||||
$actions[]=Button::add('bulk-delete')
|
||||
->slot('Bulk delete (<span x-text="window.pgBulkActions.count(\'' . $this->tableName . '\')"></span>)')
|
||||
->icon('solid-trash',['id' => 'my-custom-icon-id', 'class' => 'font-bold'])
|
||||
->class('inline-flex items-center gap-1 px-3 py-1 rounded ')
|
||||
->dispatch('bulkDelete.' . $this->tableName, []);
|
||||
}
|
||||
return $actions;
|
||||
}
|
||||
|
||||
public function datasource(): Builder
|
||||
@ -67,18 +90,49 @@ final class RoleTable extends PowerGridComponent
|
||||
|
||||
public function columns(): array
|
||||
{
|
||||
return [
|
||||
Column::make(__('roles.no'), 'id')->sortable()->searchable(),
|
||||
Column::make(__('roles.name'), 'name')->sortable()->searchable(),
|
||||
Column::make(__('roles.permissions'), 'permissions_list'),
|
||||
Column::make('Created at', 'created_at_formatted', 'created_at')->sortable(),
|
||||
Column::action('Action')
|
||||
];
|
||||
$column=[];
|
||||
$column[]=Column::make(__('roles.no'), 'id')->sortable()->searchable();
|
||||
$column[]=Column::make(__('roles.name'), 'name')->sortable()->searchable()
|
||||
->editOnClick(
|
||||
hasPermission: $this->canEdit,
|
||||
dataField: 'name',
|
||||
fallback: 'N/A',
|
||||
saveOnMouseOut: true
|
||||
);
|
||||
$column[]=Column::make(__('roles.permissions'), 'permissions_list');
|
||||
$column[]=Column::make('Created at', 'created_at_formatted', 'created_at')->sortable();
|
||||
$column[]=Column::action('Action');
|
||||
return $column;
|
||||
}
|
||||
#[On('bulkDelete.{tableName}')]
|
||||
public function bulkDelete(): void
|
||||
{
|
||||
if ($this->canDelect) {
|
||||
$this->js('alert(window.pgBulkActions.get(\'' . $this->tableName . '\'))');
|
||||
if($this->checkboxValues){
|
||||
Role::destroy($this->checkboxValues);
|
||||
$this->js('window.pgBulkActions.clearAll()'); // clear the count on the interface.
|
||||
}
|
||||
}
|
||||
}
|
||||
#[On('onUpdatedEditable')]
|
||||
public function onUpdatedEditable($id, $field, $value): void
|
||||
{
|
||||
if ($field === 'name' && $this->canEdit) {
|
||||
$this->noUpdated($id,$field,$value);
|
||||
}
|
||||
}
|
||||
private function noUpdated($id,$field,$value){
|
||||
$role = Role::find($id);
|
||||
if ($role) {
|
||||
$role->{$field} = $value;
|
||||
$role->save(); // 明確觸發 saving
|
||||
}
|
||||
}
|
||||
|
||||
public function filters(): array
|
||||
{
|
||||
return [
|
||||
Filter::inputText('name')->placeholder(__('roles.name')),
|
||||
Filter::datetimepicker('created_at'),
|
||||
];
|
||||
}
|
||||
@ -86,18 +140,22 @@ final class RoleTable extends PowerGridComponent
|
||||
|
||||
public function actions(Role $row): array
|
||||
{
|
||||
return [
|
||||
Button::add('edit')
|
||||
$actions = [];
|
||||
if ($this->canEdit) {
|
||||
$actions[] =Button::add('edit')
|
||||
->slot(__('roles.edit'))
|
||||
->icon('solid-pencil-square')
|
||||
->class('inline-flex items-center gap-1 px-3 py-1 rounded ')
|
||||
->dispatchTo('admin.role-form', 'openEditRoleModal', ['id' => $row->id]),
|
||||
Button::add('delete')
|
||||
->dispatchTo('admin.role-form', 'openEditRoleModal', ['id' => $row->id]);
|
||||
}
|
||||
if($this->canDelect){
|
||||
$actions[] =Button::add('delete')
|
||||
->slot(__('roles.delete'))
|
||||
->icon('solid-trash')
|
||||
->class('inline-flex items-center gap-1 px-3 py-1 rounded ')
|
||||
->dispatchTo('admin.role-form', 'deleteRole', ['id' => $row->id]),
|
||||
];
|
||||
->dispatchTo('admin.role-form', 'deleteRole', ['id' => $row->id]);
|
||||
}
|
||||
return $actions;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -72,6 +72,9 @@ class SongForm extends Component
|
||||
$song = Song::findOrFail($id);
|
||||
$this->songId = $song->id;
|
||||
$this->fields = $song->only(array_keys($this->fields));
|
||||
$this->selectedCategories = $song->categories()->pluck('id')->toArray();
|
||||
$this->selectedArtists = $song->artists()->pluck('id')->toArray();
|
||||
//dd($this->fields,$this->selectedCategories,$this->selectedArtists);
|
||||
$this->showCreateModal = true;
|
||||
}
|
||||
|
||||
@ -84,9 +87,12 @@ class SongForm extends Component
|
||||
$song->update($this->fields);
|
||||
session()->flash('message', '歌曲已更新');
|
||||
} else {
|
||||
Song::create($this->fields);
|
||||
$song = Song::create($this->fields);
|
||||
session()->flash('message', '歌曲已新增');
|
||||
}
|
||||
// ⭐ 同步多對多關聯
|
||||
$song->artists()->sync($this->selectedArtists ?? []);
|
||||
$song->categories()->sync($this->selectedCategories ?? []);
|
||||
|
||||
$this->resetFields();
|
||||
$this->showCreateModal = false;
|
||||
|
@ -7,6 +7,7 @@ use App\Enums\SongLanguageType;
|
||||
use App\Enums\SongSituation;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Blade;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use PowerComponents\LivewirePowerGrid\Button;
|
||||
@ -23,6 +24,10 @@ use Livewire\Attributes\On;
|
||||
final class SongTable extends PowerGridComponent
|
||||
{
|
||||
public string $tableName = 'song-table';
|
||||
public bool $canCreate;
|
||||
public bool $canEdit;
|
||||
public bool $canDownload;
|
||||
public bool $canDelect;
|
||||
|
||||
/* public bool $deferLoading = true;
|
||||
|
||||
@ -33,36 +38,43 @@ final class SongTable extends PowerGridComponent
|
||||
public function boot(): void
|
||||
{
|
||||
config(['livewire-powergrid.filter' => 'outside']);
|
||||
$this->canCreate = Auth::user()?->can('song-edit') ?? false;
|
||||
$this->canEdit = Auth::user()?->can('song-edit') ?? false;
|
||||
$this->canDownload=Auth::user()?->can('song-delete') ?? false;
|
||||
$this->canDelect = Auth::user()?->can('song-delete') ?? false;
|
||||
}
|
||||
|
||||
public function setUp(): array
|
||||
{
|
||||
if($this->canDownload || $this->canDelect){
|
||||
$this->showCheckBox();
|
||||
}
|
||||
$actions = [];
|
||||
if($this->canDownload){
|
||||
$actions[]=PowerGrid::exportable(fileName: 'song-file')
|
||||
->type(Exportable::TYPE_XLS, Exportable::TYPE_CSV);
|
||||
}
|
||||
$header = PowerGrid::header()->showSoftDeletes()->showToggleColumns();
|
||||
if($this->canCreate){
|
||||
$header->includeViewOnTop('livewire.admin.song-header');
|
||||
}
|
||||
$actions[]=$header;
|
||||
$actions[]=PowerGrid::footer()->showPerPage()->showRecordCount();
|
||||
|
||||
return [
|
||||
PowerGrid::exportable(fileName: 'song-file')
|
||||
->type(Exportable::TYPE_XLS, Exportable::TYPE_CSV),
|
||||
PowerGrid::header()
|
||||
->showSoftDeletes()
|
||||
->showToggleColumns()
|
||||
//->showSearchInput()
|
||||
->includeViewOnTop('livewire.admin.song-header')
|
||||
,
|
||||
PowerGrid::footer()
|
||||
->showPerPage()
|
||||
->showRecordCount(),
|
||||
];
|
||||
return $actions;
|
||||
}
|
||||
|
||||
public function header(): array
|
||||
{
|
||||
return [
|
||||
Button::add('bulk-delete')
|
||||
$actions = [];
|
||||
if ($this->canDelect) {
|
||||
$actions[]=Button::add('bulk-delete')
|
||||
->slot('Bulk delete (<span x-text="window.pgBulkActions.count(\'' . $this->tableName . '\')"></span>)')
|
||||
->icon('solid-trash',['id' => 'my-custom-icon-id', 'class' => 'font-bold'])
|
||||
->class('inline-flex items-center gap-1 px-3 py-1 rounded ')
|
||||
->dispatch('bulkDelete.' . $this->tableName, []),
|
||||
];
|
||||
->dispatch('bulkDelete.' . $this->tableName, []);
|
||||
}
|
||||
return $actions;
|
||||
}
|
||||
|
||||
public function datasource(): Builder
|
||||
@ -94,7 +106,7 @@ final class SongTable extends PowerGridComponent
|
||||
return Blade::render(
|
||||
'<x-select-category type="occurrence" :options=$options :modelId=$modelId :fieldName=$fieldName :selected=$selected/>',
|
||||
[
|
||||
'options' => $this->languageTypeSelectOptions(),
|
||||
'options' => SongLanguageType::options(),
|
||||
'modelId' => intval($model->id),
|
||||
'fieldName'=>'language_type',
|
||||
'selected' => $model->language_type->value
|
||||
@ -108,7 +120,7 @@ final class SongTable extends PowerGridComponent
|
||||
return Blade::render(
|
||||
'<x-select-category type="occurrence" :options=$options :modelId=$modelId :fieldName=$fieldName :selected=$selected/>',
|
||||
[
|
||||
'options' => $this->situationSelectOptions(),
|
||||
'options' => SongSituation::options(),
|
||||
'modelId' => intval($model->id),
|
||||
'fieldName'=>'situation',
|
||||
'selected' => $model->situation->value
|
||||
@ -126,87 +138,41 @@ final class SongTable extends PowerGridComponent
|
||||
|
||||
public function columns(): array
|
||||
{
|
||||
return [
|
||||
Column::make(__('songs.id'), 'id'),
|
||||
Column::make(__('songs.name'), 'name')
|
||||
->sortable()
|
||||
->searchable(),
|
||||
Column::make(__('songs.simplified'), 'simplified')
|
||||
->sortable()
|
||||
->searchable()
|
||||
->hidden(true, false),
|
||||
Column::make(__('songs.name.phinetic'), 'phonetic_abbr')
|
||||
->sortable()
|
||||
->searchable()
|
||||
->hidden(true, false),
|
||||
Column::make(__('songs.name.pinyin'), 'pinyin_abbr')
|
||||
->sortable()
|
||||
->searchable()
|
||||
->hidden(true, false),
|
||||
Column::make(__('songs.name.strokes'), 'strokes_abbr')
|
||||
->sortable()
|
||||
->searchable()
|
||||
->hidden(true, false),
|
||||
|
||||
Column::make(__('songs.filename'), 'filename')
|
||||
->sortable()
|
||||
->searchable(),
|
||||
Column::make(__('songs.adddate'), 'adddate_formatted', 'adddate')
|
||||
->sortable(),
|
||||
//歌手
|
||||
Column::make(__('songs.artists'), 'song_artists'),
|
||||
Column::make(__('songs.language_type'),'language_type_str', 'songs.language_type')->searchable(),
|
||||
//分類
|
||||
Column::make(__('songs.categorys'), 'song_categories'),
|
||||
//點播次數
|
||||
Column::make('Db change', 'db_change'),
|
||||
Column::make(__('songs.vocal'), 'vocal')
|
||||
->toggleable(hasPermission: true, trueLabel: 'yes', falseLabel: 'no'),
|
||||
Column::make(__('songs.situation'), 'situation_str','songs.situation')->searchable(),
|
||||
|
||||
Column::make(__('songs.copyright01'), 'copyright01')
|
||||
->sortable()
|
||||
->searchable()
|
||||
->editOnClick(hasPermission: true, dataField: 'copyright01', fallback: 'N/A', saveOnMouseOut: true),
|
||||
|
||||
Column::make(__('songs.copyright02'), 'copyright02')
|
||||
->sortable()
|
||||
->searchable()
|
||||
->editOnClick(hasPermission: true, dataField: 'copyright02', fallback: 'N/A', saveOnMouseOut: true)
|
||||
->hidden(true, false),
|
||||
|
||||
Column::make(__('songs.note01'), 'note01')
|
||||
->sortable()
|
||||
->searchable()
|
||||
->editOnClick(hasPermission: true, dataField: 'note01', fallback: 'N/A', saveOnMouseOut: true),
|
||||
|
||||
Column::make(__('songs.note02'), 'note02')
|
||||
->sortable()
|
||||
->searchable()
|
||||
->editOnClick(hasPermission: true, dataField: 'note02', fallback: 'N/A', saveOnMouseOut: true)
|
||||
->hidden(true, false),
|
||||
|
||||
Column::make(__('songs.note03'), 'note03')
|
||||
->sortable()
|
||||
->searchable()
|
||||
->editOnClick(hasPermission: true, dataField: 'note03', fallback: 'N/A', saveOnMouseOut: true)
|
||||
->hidden(true, false),
|
||||
|
||||
Column::make(__('songs.note04'), 'note04')
|
||||
->sortable()
|
||||
->searchable()
|
||||
->editOnClick(hasPermission: true, dataField: 'note04', fallback: 'N/A', saveOnMouseOut: true)
|
||||
->hidden(true, false),
|
||||
|
||||
Column::make(__('songs.enable'), 'enable')
|
||||
->toggleable(hasPermission: true, trueLabel: 'yes', falseLabel: 'no'),
|
||||
|
||||
Column::make('Created at', 'created_at_formatted', 'created_at')
|
||||
->sortable()
|
||||
->hidden(true, false),
|
||||
|
||||
Column::action(__('songs.actions'))
|
||||
];
|
||||
$column=[];
|
||||
$column[]=Column::make(__('songs.id'), 'id')
|
||||
->editOnClick(hasPermission: $this->canEdit, dataField: 'id', fallback: 'N/A', saveOnMouseOut: true);
|
||||
$column[]=Column::make(__('songs.name'), 'name')->sortable()->searchable()
|
||||
->editOnClick(hasPermission: $this->canEdit, dataField: 'name', fallback: 'N/A', saveOnMouseOut: true);
|
||||
$column[]=Column::make(__('songs.simplified'), 'simplified')->sortable()->searchable()->hidden(true, false);
|
||||
$column[]=Column::make(__('songs.name.phinetic'), 'phonetic_abbr')->sortable()->searchable()->hidden(true, false);
|
||||
$column[]=Column::make(__('songs.name.pinyin'), 'pinyin_abbr')->sortable()->searchable()->hidden(true, false);
|
||||
$column[]=Column::make(__('songs.name.strokes'), 'strokes_abbr')->sortable()->searchable()->hidden(true, false);
|
||||
$column[]=Column::make(__('songs.filename'), 'filename')->sortable()->searchable()
|
||||
->editOnClick(hasPermission: $this->canEdit, dataField: 'filename', fallback: 'N/A', saveOnMouseOut: true);
|
||||
$column[]=Column::make(__('songs.adddate'), 'adddate_formatted', 'adddate')->sortable();
|
||||
$column[]=Column::make(__('songs.artists'), 'song_artists');
|
||||
$column[]=Column::make(__('songs.language_type'),'language_type_str', 'songs.language_type')->searchable();
|
||||
$column[]=Column::make(__('songs.categorys'), 'song_categories');
|
||||
$column[]=Column::make('Db change', 'db_change')
|
||||
->editOnClick(hasPermission: $this->canEdit, dataField: 'db_change', fallback: 'N/A', saveOnMouseOut: true);
|
||||
$column[]=Column::make(__('songs.vocal'), 'vocal')->toggleable(hasPermission: true, trueLabel: 'yes', falseLabel: 'no');
|
||||
$column[]=Column::make(__('songs.situation'), 'situation_str','songs.situation')->searchable();
|
||||
$column[]=Column::make(__('songs.copyright01'), 'copyright01')->sortable()->searchable()
|
||||
->editOnClick(hasPermission: $this->canEdit, dataField: 'copyright01', fallback: 'N/A', saveOnMouseOut: true);
|
||||
$column[]=Column::make(__('songs.copyright02'), 'copyright02')->sortable()->searchable()->hidden(true, false)
|
||||
->editOnClick(hasPermission: $this->canEdit, dataField: 'copyright02', fallback: 'N/A', saveOnMouseOut: true);
|
||||
$column[]=Column::make(__('songs.note01'), 'note01')->sortable()->searchable()
|
||||
->editOnClick(hasPermission: $this->canEdit, dataField: 'note01', fallback: 'N/A', saveOnMouseOut: true);
|
||||
$column[]=Column::make(__('songs.note02'), 'note02')->sortable()->searchable()->hidden(true, false)
|
||||
->editOnClick(hasPermission: $this->canEdit, dataField: 'note02', fallback: 'N/A', saveOnMouseOut: true);
|
||||
$column[]=Column::make(__('songs.note03'), 'note03')->sortable()->searchable()->hidden(true, false)
|
||||
->editOnClick(hasPermission: $this->canEdit, dataField: 'note03', fallback: 'N/A', saveOnMouseOut: true);
|
||||
$column[]=Column::make(__('songs.note04'), 'note04')->sortable()->searchable()->hidden(true, false)
|
||||
->editOnClick(hasPermission: $this->canEdit, dataField: 'note04', fallback: 'N/A', saveOnMouseOut: true);
|
||||
$column[]=Column::make(__('songs.enable'), 'enable')->toggleable(hasPermission: true, trueLabel: 'yes', falseLabel: 'no');
|
||||
$column[]=Column::make('Created at', 'created_at_formatted', 'created_at')->sortable()->hidden(true, false);
|
||||
$column[]=Column::action(__('songs.actions'));
|
||||
return $column;
|
||||
}
|
||||
|
||||
public function filters(): array
|
||||
@ -232,58 +198,70 @@ final class SongTable extends PowerGridComponent
|
||||
Filter::datetimepicker('created_at'),
|
||||
];
|
||||
}
|
||||
public function languageTypeSelectOptions():Collection
|
||||
#[On('bulkDelete.{tableName}')]
|
||||
public function bulkDelete(): void
|
||||
{
|
||||
return collect(SongLanguageType::cases())->mapWithKeys(function (SongLanguageType $case) {
|
||||
return [$case->value => $case->labels()];
|
||||
});
|
||||
$this->js('alert(window.pgBulkActions.get(\'' . $this->tableName . '\'))');
|
||||
if($this->checkboxValues){
|
||||
Song::destroy($this->checkboxValues);
|
||||
$this->js('window.pgBulkActions.clearAll()'); // clear the count on the interface.
|
||||
}
|
||||
public function situationSelectOptions():Collection
|
||||
{
|
||||
return collect(SongSituation::cases())->mapWithKeys(function (SongSituation $case) {
|
||||
return [$case->value => $case->labels()];
|
||||
});
|
||||
}
|
||||
#[On('categoryChanged')]
|
||||
public function categoryChanged($value,$fieldName, $modelId): void
|
||||
{
|
||||
// dd($value,$fieldName, $modelId);
|
||||
if (in_array($fieldName, ['language_type', 'situation'])) {
|
||||
Artist::find($modelId)?->update([$fieldName => $value]);
|
||||
$this->noUpdated($modelId,$fieldName,$value);
|
||||
}
|
||||
}
|
||||
#[On('bulkDelete.{tableName}')]
|
||||
public function bulkDelete(): void
|
||||
#[On('onUpdatedEditable')]
|
||||
public function onUpdatedEditable($id, $field, $value): void
|
||||
{
|
||||
$this->js('alert(window.pgBulkActions.get(\'' . $this->tableName . '\'))');
|
||||
if($this->checkboxValues){
|
||||
Artist::destroy($this->checkboxValues);
|
||||
$this->js('window.pgBulkActions.clearAll()'); // clear the count on the interface.
|
||||
if (in_array($field,[
|
||||
'name','filename','db_change',
|
||||
'copyright01','copyright02','note01','note02','note03','note04'
|
||||
]) && $this->canEdit) {
|
||||
$this->noUpdated($id,$field,$value);
|
||||
}
|
||||
}
|
||||
#[On('onUpdatedToggleable')]
|
||||
public function onUpdatedToggleable($id, $field, $value): void
|
||||
{
|
||||
if (in_array($field,['vocal','enable']) && $this->canEdit) {
|
||||
$this->noUpdated($id,$field,$value);
|
||||
}
|
||||
}
|
||||
private function noUpdated($id,$field,$value){
|
||||
$song = Song::find($id);
|
||||
if ($song) {
|
||||
$song->{$field} = $value;
|
||||
$song->save(); // 明確觸發 saving
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function actions(Song $row): array
|
||||
{
|
||||
return [
|
||||
|
||||
Button::add('edit')
|
||||
$actions = [];
|
||||
if ($this->canEdit) {
|
||||
$actions[]=Button::add('edit')
|
||||
->slot(__('songs.edit'))
|
||||
->icon('solid-pencil-square')
|
||||
->class('inline-flex items-center gap-1 px-3 py-1 rounded ')
|
||||
->dispatchTo('admin.song-form', 'openEditSongModal', ['id' => $row->id]),
|
||||
Button::add('delete')
|
||||
->dispatchTo('admin.song-form', 'openEditSongModal', ['id' => $row->id]);
|
||||
}
|
||||
if($this->canDelect){
|
||||
$actions[]=Button::add('delete')
|
||||
->slot(__('songs.delete'))
|
||||
->icon('solid-trash')
|
||||
->class('inline-flex items-center gap-1 px-3 py-1 rounded ')
|
||||
->dispatchTo('admin.song-form', 'deleteSong', ['id' => $row->id]),
|
||||
];
|
||||
->dispatchTo('admin.song-form', 'deleteSong', ['id' => $row->id]);
|
||||
}
|
||||
public function onUpdatedToggleable($id, $field, $value): void
|
||||
{
|
||||
$updated = Song::query()->where('id', $id)->update([
|
||||
$field => $value,
|
||||
]);
|
||||
|
||||
return $actions;
|
||||
}
|
||||
|
||||
/*
|
||||
public function actionRules($row): array
|
||||
{
|
||||
|
@ -6,6 +6,8 @@ use App\Models\User;
|
||||
use App\Enums\UserGender;
|
||||
use App\Enums\UserStatus;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Blade;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use PowerComponents\LivewirePowerGrid\Button;
|
||||
use PowerComponents\LivewirePowerGrid\Column;
|
||||
@ -25,38 +27,50 @@ final class UserTable extends PowerGridComponent
|
||||
public string $tableName = 'user-table';
|
||||
|
||||
public bool $showFilters = false;
|
||||
public bool $canCreate;
|
||||
public bool $canEdit;
|
||||
public bool $canDownload;
|
||||
public bool $canDelect;
|
||||
|
||||
public function boot(): void
|
||||
{
|
||||
config(['livewire-powergrid.filter' => 'outside']);
|
||||
//權限設定
|
||||
$this->canCreate = Auth::user()?->can('user-edit') ?? false;
|
||||
$this->canEdit = Auth::user()?->can('user-edit') ?? false;
|
||||
$this->canDownload=Auth::user()?->can('user-delete') ?? false;
|
||||
$this->canDelect = Auth::user()?->can('user-delete') ?? false;
|
||||
}
|
||||
|
||||
|
||||
public function setUp(): array
|
||||
{
|
||||
if($this->canDownload || $this->canDelect){
|
||||
$this->showCheckBox();
|
||||
|
||||
return [
|
||||
PowerGrid::exportable(fileName: 'my-export-file')
|
||||
->type(Exportable::TYPE_XLS, Exportable::TYPE_CSV),
|
||||
PowerGrid::header()
|
||||
//->showSoftDeletes()
|
||||
->showToggleColumns()
|
||||
//->showSearchInput()
|
||||
->includeViewOnTop('livewire.admin.user-header')
|
||||
,
|
||||
PowerGrid::footer()->showPerPage()->showRecordCount(),
|
||||
];
|
||||
}
|
||||
$actions = [];
|
||||
$actions[] =PowerGrid::exportable(fileName: 'user-file')
|
||||
->type(Exportable::TYPE_XLS, Exportable::TYPE_CSV);
|
||||
$header = PowerGrid::header()
|
||||
->showToggleColumns();
|
||||
if($this->canCreate){
|
||||
$header->includeViewOnTop('livewire.admin.user-header');
|
||||
}
|
||||
$actions[]=$header;
|
||||
$actions[]=PowerGrid::footer()->showPerPage()->showRecordCount();
|
||||
return $actions;
|
||||
}
|
||||
public function header(): array
|
||||
{
|
||||
return [
|
||||
Button::add('bulk-delete')
|
||||
$actions = [];
|
||||
if ($this->canDelect) {
|
||||
$actions[]=Button::add('bulk-delete')
|
||||
->slot('Bulk delete (<span x-text="window.pgBulkActions.count(\'' . $this->tableName . '\')"></span>)')
|
||||
->icon('solid-trash',['id' => 'my-custom-icon-id', 'class' => 'font-bold'])
|
||||
->class('inline-flex items-center gap-1 px-3 py-1 rounded ')
|
||||
->dispatch('bulkDelete.' . $this->tableName, []),
|
||||
];
|
||||
->dispatch('bulkDelete.' . $this->tableName, []);
|
||||
}
|
||||
return $actions;
|
||||
}
|
||||
|
||||
public function datasource(): Builder
|
||||
@ -71,14 +85,45 @@ final class UserTable extends PowerGridComponent
|
||||
|
||||
public function fields(): PowerGridFields
|
||||
{
|
||||
|
||||
return PowerGrid::fields()
|
||||
->add('id')
|
||||
->add('name')
|
||||
->add('email')
|
||||
->add('phone')
|
||||
->add('birthday_formatted',fn (User $model) => Carbon::parse($model->birthday)->format('Y-m-d'))
|
||||
->add('gender', fn (User $model) => UserGender::from($model->gender)->labels())
|
||||
->add('status', fn (User $model) => UserStatus::from($model->status)->labels())
|
||||
->add('gender_str', function (User $model) {
|
||||
if ($this->canEdit) {
|
||||
return Blade::render(
|
||||
'<x-select-category type="occurrence" :options=$options :modelId=$modelId :fieldName=$fieldName :selected=$selected/>',
|
||||
[
|
||||
'options' => UserGender::options(),
|
||||
'modelId' => intval($model->id),
|
||||
'fieldName'=>'gender',
|
||||
'selected' => $model->gender->value
|
||||
]
|
||||
);
|
||||
}
|
||||
// 沒有權限就顯示對應的文字
|
||||
|
||||
return $model->gender->labelPowergridFilter(); // 假設 label() 會回傳顯示文字
|
||||
} )
|
||||
->add('status_str', function (User $model) {
|
||||
if ($this->canEdit) {
|
||||
return Blade::render(
|
||||
'<x-select-category type="occurrence" :options=$options :modelId=$modelId :fieldName=$fieldName :selected=$selected/>',
|
||||
[
|
||||
'options' => UserStatus::options(),
|
||||
'modelId' => intval($model->id),
|
||||
'fieldName'=>'status',
|
||||
'selected' => $model->status->value
|
||||
]
|
||||
);
|
||||
}
|
||||
// 沒有權限就顯示對應的文字
|
||||
|
||||
return $model->status->labelPowergridFilter(); // 假設 label() 會回傳顯示文字
|
||||
} )
|
||||
->add('roles' ,fn(User $model)=> $model->roles->pluck('name')->implode(', '))
|
||||
->add('created_at_formatted', fn (User $model) => Carbon::parse($model->created_at)->format('Y-m-d H:i:s'));
|
||||
}
|
||||
@ -91,7 +136,7 @@ final class UserTable extends PowerGridComponent
|
||||
->sortable()
|
||||
->searchable()
|
||||
->editOnClick(
|
||||
hasPermission: true,
|
||||
hasPermission: $this->canEdit,
|
||||
dataField: 'name',
|
||||
fallback: 'N/A',
|
||||
saveOnMouseOut: true
|
||||
@ -100,7 +145,7 @@ final class UserTable extends PowerGridComponent
|
||||
->sortable()
|
||||
->searchable()
|
||||
->editOnClick(
|
||||
hasPermission: true,
|
||||
hasPermission: $this->canEdit,
|
||||
dataField: 'email',
|
||||
fallback: 'N/A',
|
||||
saveOnMouseOut: true
|
||||
@ -109,32 +154,71 @@ final class UserTable extends PowerGridComponent
|
||||
->sortable()
|
||||
->searchable()
|
||||
->editOnClick(
|
||||
hasPermission: true,
|
||||
hasPermission: $this->canEdit,
|
||||
dataField: 'phone',
|
||||
fallback: 'N/A',
|
||||
saveOnMouseOut: true
|
||||
),
|
||||
|
||||
Column::make(__('users.gender'), 'gender','users.gender'),
|
||||
Column::make(__('users.gender'), 'gender_str','users.gender'),
|
||||
Column::make(__('users.birthday'), 'birthday_formatted')->sortable()->searchable(),
|
||||
Column::make(__('users.status'), 'status','users.status'),
|
||||
Column::make(__('users.status'), 'status_str','users.status'),
|
||||
Column::make(__('users.role'), 'roles'),
|
||||
Column::make('建立時間', 'created_at_formatted', 'created_at')->sortable(),
|
||||
Column::action('操作')
|
||||
];
|
||||
}
|
||||
|
||||
#[On('bulkDelete.{tableName}')]
|
||||
public function bulkDelete(): void
|
||||
{
|
||||
if ($this->canDelect) {
|
||||
$this->js('alert(window.pgBulkActions.get(\'' . $this->tableName . '\'))');
|
||||
if($this->checkboxValues){
|
||||
Artist::destroy($this->checkboxValues);
|
||||
$this->js('window.pgBulkActions.clearAll()'); // clear the count on the interface.
|
||||
}
|
||||
}
|
||||
}
|
||||
#[On('categoryChanged')]
|
||||
public function categoryChanged($value,$fieldName, $modelId): void
|
||||
{
|
||||
// dd($value,$fieldName, $modelId);
|
||||
if (in_array($fieldName,['gender','status']) && $this->canEdit) {
|
||||
$this->noUpdated($modelId,$fieldName,$value);
|
||||
}
|
||||
}
|
||||
#[On('onUpdatedEditable')]
|
||||
public function onUpdatedEditable($id, $field, $value): void
|
||||
{
|
||||
if (in_array($field,['name','email','phone']) && $this->canEdit) {
|
||||
$this->noUpdated($id,$field,$value);
|
||||
}
|
||||
}
|
||||
#[On('onUpdatedToggleable')]
|
||||
public function onUpdatedToggleable($id, $field, $value): void
|
||||
{
|
||||
if (in_array($field,[]) && $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
|
||||
}
|
||||
}
|
||||
public function filters(): array
|
||||
{
|
||||
return [
|
||||
Filter::inputText('name')->placeholder(__('users.name')),
|
||||
Filter::inputText('email')->placeholder('Email'),
|
||||
Filter::inputText('phone')->placeholder(__('users.phone')),
|
||||
Filter::enumSelect('gender','users.gender')
|
||||
Filter::enumSelect('gender_str','users.gender')
|
||||
->datasource(UserGender::cases())
|
||||
->optionLabel('users.gender'),
|
||||
Filter::datepicker('birthday'),
|
||||
Filter::enumSelect('status', 'users.status')
|
||||
Filter::enumSelect('status_str', 'users.status')
|
||||
->datasource(UserStatus::cases())
|
||||
->optionLabel('users.status'),
|
||||
Filter::datetimepicker('created_at'),
|
||||
@ -143,47 +227,22 @@ final class UserTable extends PowerGridComponent
|
||||
|
||||
public function actions(User $row): array
|
||||
{
|
||||
return [
|
||||
|
||||
Button::add('edit')
|
||||
$actions = [];
|
||||
if ($this->canEdit) {
|
||||
$actions[]=Button::add('edit')
|
||||
->slot(__('users.edit'))
|
||||
->icon('solid-pencil-square')
|
||||
->class('inline-flex items-center gap-1 px-3 py-1 rounded ')
|
||||
->dispatchTo('admin.user-form', 'openEditUserModal', ['id' => $row->id]),
|
||||
Button::add('delete')
|
||||
->dispatchTo('admin.user-form', 'openEditUserModal', ['id' => $row->id]);
|
||||
}
|
||||
if($this->canDelect){
|
||||
$actions[]=Button::add('delete')
|
||||
->slot(__('users.delete'))
|
||||
->icon('solid-trash')
|
||||
->class('inline-flex items-center gap-1 px-3 py-1 rounded ')
|
||||
->dispatchTo('admin.user-form', 'deleteUser', ['id' => $row->id]),
|
||||
];
|
||||
}
|
||||
|
||||
public function onUpdatedEditable($id, $field, $value): void
|
||||
{
|
||||
$updated = User::query()->where('id', $id)->update([
|
||||
$field => $value,
|
||||
]);
|
||||
if ($updated) {
|
||||
$this->fillData();
|
||||
}
|
||||
}
|
||||
public function onUpdatedToggleable($id, $field, $value): void
|
||||
{
|
||||
$updated = User::query()->where('id', $id)->update([
|
||||
$field => $value,
|
||||
]);
|
||||
if ($updated) {
|
||||
$this->fillData();
|
||||
}
|
||||
}
|
||||
#[On('bulkDelete.{tableName}')]
|
||||
public function bulkDelete(): void
|
||||
{
|
||||
$this->js('alert(window.pgBulkActions.get(\'' . $this->tableName . '\'))');
|
||||
if($this->checkboxValues){
|
||||
User::destroy($this->checkboxValues);
|
||||
$this->js('window.pgBulkActions.clearAll()'); // clear the count on the interface.
|
||||
->dispatchTo('admin.user-form', 'deleteUser', ['id' => $row->id]);
|
||||
}
|
||||
return $actions;
|
||||
}
|
||||
|
||||
|
||||
|
@ -5,6 +5,7 @@ namespace App\Models;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use App\Helpers\ChineseNameConverter;
|
||||
use App\Helpers\ChineseStrokesConverter;
|
||||
|
||||
class Song extends Model
|
||||
{
|
||||
@ -70,7 +71,7 @@ class Song extends Model
|
||||
|
||||
$chars = preg_split('//u', $song->name, -1, PREG_SPLIT_NO_EMPTY);
|
||||
$firstChar = $chars[0] ?? null;
|
||||
$song->strokes_abbr=$firstChar ? getStrokeCountFromChar::getStrokes($firstChar) : null;
|
||||
$song->strokes_abbr=$firstChar ? ChineseStrokesConverter::getStrokes($firstChar) : null;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -48,7 +48,9 @@ class User extends Authenticatable
|
||||
return [
|
||||
'email_verified_at' => 'datetime',
|
||||
'password' => 'hashed',
|
||||
'birthday' => 'date'
|
||||
'birthday' => 'date',
|
||||
'gender' => \App\Enums\UserGender::class,
|
||||
'status' => \App\Enums\UserStatus::class,
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -6,6 +6,7 @@ use Illuminate\Foundation\Configuration\Middleware;
|
||||
|
||||
return Application::configure(basePath: dirname(__DIR__))
|
||||
->withRouting(
|
||||
api: __DIR__.'/../routes/api.php',
|
||||
web: __DIR__.'/../routes/web.php',
|
||||
commands: __DIR__.'/../routes/console.php',
|
||||
health: '/up',
|
||||
|
@ -30,7 +30,8 @@ return new class extends Migration
|
||||
$table->string('simplified')->comment('歌曲簡體');
|
||||
$table->string('phonetic_abbr')->comment('歌曲注音');
|
||||
$table->string('pinyin_abbr')->comment('歌曲拼音');
|
||||
$table->integer('strokes_abbr')->nullable()->comment('歌曲筆劃');
|
||||
$table->integer('strokes_abbr')->default(0)->comment('歌曲筆劃');
|
||||
$table->integer('song_counts')->default(0)->comment('點播次數');
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
@ -16,9 +16,9 @@ class ChineseNameConverterSeeder extends Seeder
|
||||
{
|
||||
//dd(ChineseStrokesConverter::getStrokes('羅'));
|
||||
|
||||
echo "羅:" . ChineseStrokesConverter::getStrokes('羅') . PHP_EOL;
|
||||
echo "陳:" . ChineseStrokesConverter::getStrokes('陳') . PHP_EOL;
|
||||
echo "阪:" . ChineseStrokesConverter::getStrokes('阪') . PHP_EOL;
|
||||
//dd(ChineseNameConverter::convertAll('比愛更愛'));
|
||||
//echo "羅:" . ChineseStrokesConverter::getStrokes('羅') . PHP_EOL;
|
||||
//echo "陳:" . ChineseStrokesConverter::getStrokes('陳') . PHP_EOL;
|
||||
//echo "阪:" . ChineseStrokesConverter::getStrokes('阪') . PHP_EOL;
|
||||
dd(ChineseNameConverter::convertAll('小嗯'));
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ return [
|
||||
'management' => '歌手管理',
|
||||
'list' => '歌手列表',
|
||||
'CreateNew' => '新增歌手',
|
||||
'EditArtist' => '編輯歌手',
|
||||
'create_edit' => '新增 / 編輯',
|
||||
'create' => '新增',
|
||||
'edit' => '編輯',
|
||||
@ -16,6 +17,8 @@ return [
|
||||
'name.pinyin' => '拼音',
|
||||
'name.strokes' => '筆劃',
|
||||
|
||||
'select_category' =>'選擇類別',
|
||||
|
||||
'actions' => '操作',
|
||||
'view' => '查看',
|
||||
'submit' => '提交',
|
||||
|
@ -3,6 +3,7 @@
|
||||
return [
|
||||
'list' => '角色列表',
|
||||
'CreateNew' => '新增角色',
|
||||
'EditRole' => '編輯角色',
|
||||
'edit' => '編輯',
|
||||
'delete' => '刪除',
|
||||
|
||||
@ -10,6 +11,9 @@ return [
|
||||
'name' => '名稱',
|
||||
'permissions' => '權限',
|
||||
|
||||
'role_name' =>'角色名稱',
|
||||
'select_permissions'=>'選擇權限',
|
||||
|
||||
'create' => '新增',
|
||||
'action' => '操作',
|
||||
'view' => '查看',
|
||||
|
@ -4,6 +4,7 @@ return [
|
||||
'management' => '歌曲管理',
|
||||
'list' => '歌曲列表',
|
||||
'CreateNew' => '新增歌曲',
|
||||
'EditSong' => '編輯歌曲',
|
||||
'create_edit' => '新增 / 編輯',
|
||||
'create' => '新增',
|
||||
'edit' => '編輯',
|
||||
@ -27,10 +28,17 @@ return [
|
||||
'note04' => '備註04',
|
||||
'enable' => '狀態',
|
||||
'name_length' => '歌名字數',
|
||||
'db_change'=>'分貝增減',
|
||||
'vocal' => '人聲',
|
||||
'situation' => '情境',
|
||||
'simplified' => '歌名簡體',
|
||||
|
||||
|
||||
'select_artists' =>'輸入搜尋歌手',
|
||||
'select_language_type'=>'選擇語言',
|
||||
'select_categorys'=>'選擇分類',
|
||||
'select_situation'=>'選擇情境',
|
||||
|
||||
'actions' => '操作',
|
||||
'view' => '查看',
|
||||
'submit' => '提交',
|
||||
|
@ -3,6 +3,7 @@
|
||||
return [
|
||||
'list' => '使用者列表',
|
||||
'CreateNew' => '新增使用者',
|
||||
'EditUser' => '編輯使用者',
|
||||
'edit' => '編輯',
|
||||
'delete' => '刪除',
|
||||
|
||||
@ -14,6 +15,10 @@ return [
|
||||
'status' => '狀態',
|
||||
'role' =>'角色',
|
||||
|
||||
'select_gender'=>'選擇性別',
|
||||
'select_status'=>'選擇狀態',
|
||||
'select_role'=>'選擇角色',
|
||||
|
||||
'create' => '新增',
|
||||
'action' => '操作',
|
||||
'view' => '查看',
|
||||
|
@ -1,9 +1,9 @@
|
||||
@if(auth()->user()->hasRole('Admin'))
|
||||
<x-layouts.admin>
|
||||
{{ $slot }}
|
||||
</x-layouts.admin>
|
||||
@else
|
||||
@if(auth()->user()->hasRole('User'))
|
||||
<x-layouts.user>
|
||||
{{ $slot }}
|
||||
</x-layouts.user>
|
||||
@else
|
||||
<x-layouts.admin>
|
||||
{{ $slot }}
|
||||
</x-layouts.admin>
|
||||
@endif
|
@ -1,20 +1,20 @@
|
||||
<x-wireui:modal-card title="{{ $artistId ? '編輯歌手' : '新增歌手' }}" blur wire:model.defer="showCreateModal">
|
||||
<x-wireui:modal-card title="{{ $artistId ? __('artists.EditArtist') : __('artists.CreateNew') }}" blur wire:model.defer="showCreateModal">
|
||||
<div class="space-y-4">
|
||||
<x-wireui:select
|
||||
label="類別"
|
||||
label="{{__('artists.category')}}"
|
||||
wire:model.defer="fields.category"
|
||||
placeholder="選擇類別"
|
||||
placeholder="{{__('artists.select_category')}}"
|
||||
:options="$categoryOptions"
|
||||
option-label="name"
|
||||
option-value="value"
|
||||
/>
|
||||
<x-wireui:input label="名稱" wire:model.defer="fields.name" />
|
||||
<x-wireui:input label="{{__('artists.name')}}" wire:model.defer="fields.name" />
|
||||
</div>
|
||||
|
||||
<x-slot name="footer">
|
||||
<div class="flex justify-between w-full">
|
||||
<x-wireui:button flat label="{{__('atrists.cancel')}}" @click="$wire.showCreateModal = false" />
|
||||
<x-wireui:button primary type="submit" label="儲存" />
|
||||
<x-wireui:button flat label="{{__('artists.cancel')}}" @click="$wire.showCreateModal = false" />
|
||||
<x-wireui:button primary label="{{__('artists.submit')}}" wire:click="save" />
|
||||
</div>
|
||||
</x-slot>
|
||||
</x-wireui:modal-card>
|
||||
|
@ -1,12 +1,10 @@
|
||||
<div>
|
||||
@if ($showCreateModal)
|
||||
<x-wireui:modal-card title="{{ $roleId ? '編輯角色' : '新增角色' }}" blur wire:model.defer="showCreateModal">
|
||||
<x-wireui:modal-card title="{{ $roleId ? __('roles.EditRole') : __('roles.CreateNew') }}" blur wire:model.defer="showCreateModal">
|
||||
<div class="space-y-4">
|
||||
<x-wireui:input label="角色名稱" wire:model.defer="name" />
|
||||
<x-wireui:input label="{{__('roles.role_name')}}" wire:model.defer="name" />
|
||||
<x-wireui:select
|
||||
label="權限"
|
||||
label="{{__('roles.permissions')}}"
|
||||
wire:model.defer="selectedPermissions"
|
||||
placeholder="選擇權限"
|
||||
placeholder="{{__('roles.select_permissions')}}"
|
||||
multiselect
|
||||
option-label="label"
|
||||
option-value="value"
|
||||
@ -20,6 +18,4 @@
|
||||
<x-wireui:button primary label="{{__('roles.submit')}}" wire:click="save" />
|
||||
</div>
|
||||
</x-slot>
|
||||
</x-wireui:modal-card>
|
||||
@endif
|
||||
</div>
|
||||
</x-wireui:modal-card>
|
@ -1,17 +1,15 @@
|
||||
<x-wireui:modal-card title="{{ $songId ? '編輯歌曲' : '新增歌曲' }}" wire:model.defer="showCreateModal">
|
||||
|
||||
<form wire:submit.prevent="save">
|
||||
<x-wireui:modal-card title="{{ $songId ? __('songs.EditSong') : __('songs.CreateNew') }}" wire:model.defer="showCreateModal">
|
||||
|
||||
<div class="grid grid-cols-3 gap-4 sm:grid-cols-3">
|
||||
<x-wireui:input label="歌曲編號" wire:model.defer="fields.id" required />
|
||||
<x-wireui:input label="歌曲名稱" wire:model.defer="fields.name" required />
|
||||
<x-wireui:input label="檔名" wire:model.defer="fields.filename" />
|
||||
<x-wireui:input label="{{__('songs.id')}}" wire:model.defer="fields.id" required />
|
||||
<x-wireui:input label="{{__('songs.name')}}" wire:model.defer="fields.name" required />
|
||||
<x-wireui:input label="{{__('songs.filename')}}" wire:model.defer="fields.filename" />
|
||||
</div>
|
||||
<div class="grid grid-cols-3 gap-4 sm:grid-cols-3">
|
||||
<x-wireui:select
|
||||
label="歌手"
|
||||
label="{{__('songs.artists')}}"
|
||||
wire:model.defer="selectedArtists"
|
||||
placeholder="輸入搜尋歌手"
|
||||
placeholder="{{__('songs.select_artists')}}"
|
||||
:async-data="route('api.artists.search')"
|
||||
option-label="name"
|
||||
option-value="id"
|
||||
@ -19,56 +17,56 @@
|
||||
hide-empty-message
|
||||
/>
|
||||
<x-wireui:select
|
||||
label="語言類型"
|
||||
label="{{__('songs.language_type')}}"
|
||||
wire:model.defer="fields.language_type"
|
||||
placeholder="選擇語言"
|
||||
placeholder="{{__('songs.select_language_type')}}"
|
||||
:options="$songLanguageType"
|
||||
option-label="name"
|
||||
option-value="value"
|
||||
/>
|
||||
<x-wireui:select
|
||||
label="分類"
|
||||
label="{{__('songs.categorys')}}"
|
||||
wire:model.defer="selectedCategories"
|
||||
:options="$songCategories->map(fn($c) => ['label' => $c->name, 'value' => $c->id])->toArray()"
|
||||
option-label="label"
|
||||
option-value="value"
|
||||
multiselect
|
||||
placeholder="選擇分類"
|
||||
placeholder="{{__('songs.select_categorys')}}"
|
||||
/>
|
||||
</div>
|
||||
<div class="grid grid-cols-3 gap-4 sm:grid-cols-3">
|
||||
|
||||
<x-wireui:select
|
||||
label="情境"
|
||||
label="{{__('songs.situation')}}"
|
||||
wire:model.defer="fields.situation"
|
||||
placeholder="選擇情境"
|
||||
placeholder="{{__('songs.select_situation')}}"
|
||||
:options="$songSituation"
|
||||
option-label="name"
|
||||
option-value="value"
|
||||
/>
|
||||
<x-wireui:input label="分貝增減" wire:model.defer="fields.db_change" />
|
||||
<x-wireui:input label="新增日期" wire:model.defer="fields.adddate" type="date" />
|
||||
<x-wireui:input label="{{__('songs.db_change')}}" wire:model.defer="fields.db_change" />
|
||||
<x-wireui:input label="{{__('songs.adddate')}}" wire:model.defer="fields.adddate" type="date" />
|
||||
|
||||
</div>
|
||||
<div class="grid grid-cols-2 gap-4 sm:grid-cols-2">
|
||||
<x-wireui:toggle label="人聲" wire:model.defer="fields.vocal" />
|
||||
<x-wireui:toggle label="啟用" wire:model.defer="fields.enable" />
|
||||
<x-wireui:toggle label="{{__('songs.vocal')}}" wire:model.defer="fields.vocal" />
|
||||
<x-wireui:toggle label="{{__('songs.enable')}}" wire:model.defer="fields.enable" />
|
||||
</div>
|
||||
<div class="grid grid-cols-2 gap-4 sm:grid-cols-2">
|
||||
<x-wireui:input label="版權1" wire:model.defer="fields.copyright01" />
|
||||
<x-wireui:input label="版權2" wire:model.defer="fields.copyright02" />
|
||||
<x-wireui:input label="{{__('songs.copyright01')}}" wire:model.defer="fields.copyright01" />
|
||||
<x-wireui:input label="{{__('songs.copyright02')}}" wire:model.defer="fields.copyright02" />
|
||||
</div>
|
||||
<div class="grid grid-cols-2 gap-4 sm:grid-cols-4">
|
||||
<x-wireui:textarea label="備註1" wire:model.defer="fields.note01" />
|
||||
<x-wireui:textarea label="備註2" wire:model.defer="fields.note02" />
|
||||
<x-wireui:textarea label="備註3" wire:model.defer="fields.note03" />
|
||||
<x-wireui:textarea label="備註4" wire:model.defer="fields.note04" />
|
||||
<x-wireui:textarea label="{{__('songs.note01')}}" wire:model.defer="fields.note01" />
|
||||
<x-wireui:textarea label="{{__('songs.note02')}}" wire:model.defer="fields.note02" />
|
||||
<x-wireui:textarea label="{{__('songs.note03')}}" wire:model.defer="fields.note03" />
|
||||
<x-wireui:textarea label="{{__('songs.note04')}}" wire:model.defer="fields.note04" />
|
||||
</div>
|
||||
|
||||
<x-slot name="footer">
|
||||
<div class="flex justify-between w-full">
|
||||
<x-wireui:button flat label="{{__('songs.cancel')}}" @click="$wire.showCreateModal = false" />
|
||||
<x-wireui:button primary type="submit" label="儲存" />
|
||||
<x-wireui:button primary label="{{__('songs.submit')}}" wire:click="save" />
|
||||
</div>
|
||||
</x-slot>
|
||||
|
||||
|
@ -1,29 +1,29 @@
|
||||
<x-wireui:modal-card title="{{ $userId ? '編輯使用者' : '新增使用者' }}" blur wire:model.defer="showCreateModal">
|
||||
<x-wireui:modal-card title="{{ $userId ? __('users.EditUser') : __('users.CreateNew') }}" blur wire:model.defer="showCreateModal">
|
||||
<div class="space-y-4">
|
||||
<x-wireui:input label="名稱" wire:model.defer="fields.name" required />
|
||||
<x-wireui:input label="{{__('users.name')}}" wire:model.defer="fields.name" required />
|
||||
<x-wireui:input label="Email" wire:model.defer="fields.email" required />
|
||||
<x-wireui:input label="Phone" wire:model.defer="fields.phone" />
|
||||
<x-wireui:select
|
||||
label="性別"
|
||||
label="{{__('users.gender')}}"
|
||||
wire:model.defer="fields.gender"
|
||||
placeholder="選擇性別"
|
||||
placeholder="{{__('users.select_gender')}}"
|
||||
:options="$genderOptions"
|
||||
option-label="name"
|
||||
option-value="value"
|
||||
/>
|
||||
<x-wireui:select
|
||||
label="狀態"
|
||||
label="{{__('users.status')}}"
|
||||
wire:model.defer="fields.status"
|
||||
placeholder="選擇狀態"
|
||||
placeholder="{{__('users.select_status')}}"
|
||||
:options="$statusOptions"
|
||||
option-label="name"
|
||||
option-value="value"
|
||||
/>
|
||||
|
||||
<x-wireui:select
|
||||
label="角色"
|
||||
label="{{__('users.role')}}"
|
||||
wire:model.defer="selectedRoles"
|
||||
placeholder="選擇角色"
|
||||
placeholder="{{__('users.select_role')}}"
|
||||
multiselect
|
||||
option-label="label"
|
||||
option-value="value"
|
||||
|
@ -22,10 +22,10 @@ new #[Layout('layouts.guest')] class extends Component
|
||||
|
||||
//$this->redirectIntended(default: route('dashboard', absolute: false), navigate: true);
|
||||
$user = auth()->user();
|
||||
if ($user->hasRole('Admin')) {
|
||||
$this->redirect(route('admin.dashboard'), navigate: true);
|
||||
} else {
|
||||
if ($user->hasRole('User')) {
|
||||
$this->redirect(route('dashboard'), navigate: true);
|
||||
} else {
|
||||
$this->redirect(route('admin.dashboard'), navigate: true);
|
||||
}
|
||||
}
|
||||
}; ?>
|
||||
|
7
routes/api.php
Normal file
7
routes/api.php
Normal file
@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Route;
|
||||
use App\Http\Controllers\ArtistController;
|
||||
|
||||
|
||||
Route::get('/artists/search', [App\Http\Controllers\ArtistController::class, 'search'])->name('api.artists.search');
|
@ -3,13 +3,11 @@
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
use App\Livewire\Admin\Dashboard as AdminDashboard;
|
||||
use App\Livewire\Admin\RoleTable;
|
||||
use App\Livewire\Admin\UserTable;
|
||||
use App\Livewire\Admin\ArtistTable;
|
||||
use App\Livewire\Admin\SongTable;
|
||||
|
||||
Route::view('/', 'welcome');
|
||||
|
||||
|
||||
|
||||
Route::view('dashboard', 'dashboard')
|
||||
->middleware(['auth', 'verified'])
|
||||
->name('dashboard');
|
||||
@ -19,36 +17,16 @@ Route::view('profile', 'profile')
|
||||
->name('profile');
|
||||
|
||||
require __DIR__.'/auth.php';
|
||||
Route::get('/api/artists/search', function (Request $request) {
|
||||
|
||||
return \App\Models\Artist::query()
|
||||
->where('name', 'like', "%{$request->input('search')}%")
|
||||
->limit(20)
|
||||
->get(['id', 'name']);
|
||||
})->name('api.artists.search');
|
||||
|
||||
Route::middleware(['auth'])->prefix('admin')->name('admin.')->group(function () {
|
||||
Route::get('/dashboard', AdminDashboard::class)->name('dashboard');
|
||||
|
||||
Route::get('/roles', function () {
|
||||
return view('livewire.admin.roles');
|
||||
})->name('roles');
|
||||
Route::get('/roles-table', RoleTable::class)->name('roles-table');
|
||||
|
||||
Route::get('/users', function () {
|
||||
return view('livewire.admin.users');
|
||||
})->name('users');
|
||||
Route::get('/users-table', UserTable::class)->name('users-table');
|
||||
|
||||
Route::get('/artists', function () {
|
||||
return view('livewire.admin.artists');
|
||||
})->name('artists');
|
||||
|
||||
Route::get('/artists-table', ArtistTable::class)->name('artists-table');
|
||||
|
||||
Route::get('/songs', function () {
|
||||
return view('livewire.admin.songs');
|
||||
})->name('songs');
|
||||
Route::get('/songs-table', ArtistTable::class)->name('songs-table');
|
||||
Route::get('/roles', function () {return view('livewire.admin.roles');})->name('roles');
|
||||
Route::get('/users', function () {return view('livewire.admin.users');})->name('users');
|
||||
Route::get('/artists', function () {return view('livewire.admin.artists');})->name('artists');
|
||||
Route::get('/songs', function () {return view('livewire.admin.songs');})->name('songs');
|
||||
Route::get('/branches', function () {return view('livewire.admin.branches');})->name('branches');
|
||||
Route::get('/rooms', function () {return view('livewire.admin.rooms');})->name('rooms');
|
||||
|
||||
});
|
Loading…
x
Reference in New Issue
Block a user