調整畫面,加入user_song 20250429
This commit is contained in:
parent
cbc3fc9d34
commit
f203c8e20a
31
app/Enums/ArtistCategory.php
Normal file
31
app/Enums/ArtistCategory.php
Normal file
@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace App\Enums;
|
||||
|
||||
enum ArtistCategory: string
|
||||
{
|
||||
case Unset = 'unset';
|
||||
case Male = 'male';
|
||||
case Female = 'female';
|
||||
case Group = 'group';
|
||||
case Foreign = 'foreign';
|
||||
case Other = 'other';
|
||||
|
||||
// 返回對應的顯示文字
|
||||
public function labels(): string
|
||||
{
|
||||
return match($this) {
|
||||
self::Male => __('enums.Male'),
|
||||
self::Female => __('enums.Female'),
|
||||
self::Group => __('arist.category.Group'),
|
||||
self::Foreign => __('arist.category.Foreign'),
|
||||
self::Other => __('enums.Other'),
|
||||
self::Unset => __('enums.Unset'),
|
||||
};
|
||||
}
|
||||
|
||||
public function labelPowergridFilter(): String
|
||||
{
|
||||
return $this -> labels();
|
||||
}
|
||||
}
|
27
app/Enums/UserGender.php
Normal file
27
app/Enums/UserGender.php
Normal file
@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
namespace App\Enums;
|
||||
|
||||
enum UserGender: string
|
||||
{
|
||||
case Male = 'male';
|
||||
case Female = 'female';
|
||||
case Other = 'other';
|
||||
case Unset = 'unset';
|
||||
|
||||
// 返回對應的顯示文字
|
||||
public function labels(): string
|
||||
{
|
||||
return match($this) {
|
||||
self::Male => __('enums.user.gender.Male'),
|
||||
self::Female => __('enums.user.gender.Female'),
|
||||
self::Other => __('enums.Other'),
|
||||
self::Unset => __('enums.Unset'),
|
||||
};
|
||||
}
|
||||
|
||||
public function labelPowergridFilter(): String
|
||||
{
|
||||
return $this -> labels();
|
||||
}
|
||||
}
|
25
app/Enums/UserStatus.php
Normal file
25
app/Enums/UserStatus.php
Normal file
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace App\Enums;
|
||||
|
||||
enum UserStatus: int
|
||||
{
|
||||
case Active = 0; // 正常
|
||||
case Suspended = 1; // 停權
|
||||
case Deleting = 2; // 刪除中
|
||||
|
||||
// 返回對應的顯示文字
|
||||
public function labels(): string
|
||||
{
|
||||
return match($this) {
|
||||
self::Active => __('enums.user.status.Active'),
|
||||
self::Suspended => __('enums.user.status.Suspended'),
|
||||
self::Deleting => __('enums.user.status.Deleting'),
|
||||
};
|
||||
}
|
||||
public function labelPowergridFilter(): String
|
||||
{
|
||||
return $this -> labels();
|
||||
}
|
||||
|
||||
}
|
@ -5,7 +5,7 @@ namespace App\Livewire\Admin;
|
||||
use Livewire\Component;
|
||||
|
||||
use App\Models\Artist;
|
||||
use App\Models\ArtistCategory;
|
||||
use App\Enums\ArtistCategory;
|
||||
|
||||
class ArtistForm extends Component
|
||||
{
|
||||
@ -13,18 +13,25 @@ class ArtistForm extends Component
|
||||
|
||||
public bool $showCreateModal = false;
|
||||
public ?int $artistId = null;
|
||||
public $name;
|
||||
public $artistCategory = []; // 所有類別清單
|
||||
|
||||
public array $categoryOptions =[];
|
||||
public array $fields = [
|
||||
'category' =>'unset',
|
||||
'name' =>'',
|
||||
];
|
||||
public $selectedCategory = []; // 表單中選到的權限
|
||||
|
||||
protected $rules = [
|
||||
'name' => 'required|string|max:255',
|
||||
'selectedCategory' => 'required|array',
|
||||
'fields.category' => 'required|in:unset,male,female,group,foreign,other',
|
||||
'fields.name' => 'required|string|max:255',
|
||||
];
|
||||
|
||||
public function mount()
|
||||
{
|
||||
$this->artistCategory = ArtistCategory::all();
|
||||
$this->categoryOptions = collect(ArtistCategory::cases())->map(fn ($category) => [
|
||||
'name' => $category->labels(),
|
||||
'value' => $category->value,
|
||||
])->toArray();
|
||||
}
|
||||
|
||||
public function openCreateArtistModal()
|
||||
@ -37,8 +44,7 @@ class ArtistForm extends Component
|
||||
{
|
||||
$artist = Artist::findOrFail($id);
|
||||
$this->artistId = $artist->id;
|
||||
$this->name = $artist->name;
|
||||
$this->selectedCategory = $artist->category_id;
|
||||
$this->fields = $artist->only(array_keys($this->fields));
|
||||
$this->showCreateModal = true;
|
||||
}
|
||||
|
||||
@ -47,24 +53,17 @@ class ArtistForm extends Component
|
||||
$this->validate();
|
||||
|
||||
if ($this->artistId) {
|
||||
$role = Artist::findOrFail($this->artistId);
|
||||
$role->update([
|
||||
'category_id' => $this->selectedCategory,
|
||||
'name' => $this->name,
|
||||
]);
|
||||
|
||||
$artist = Artist::findOrFail($this->artistId);
|
||||
$artist->update($this->fields);
|
||||
session()->flash('message', '歌手已更新');
|
||||
} else {
|
||||
$role = Artist::create([
|
||||
'category_id' => $this->selectedCategory,
|
||||
'name' => $this->name,
|
||||
]);
|
||||
|
||||
$artist = Artist::create($this->fields);
|
||||
session()->flash('message', '歌手已新增');
|
||||
}
|
||||
|
||||
$this->resetFields();
|
||||
$this->showCreateModal = false;
|
||||
$this->dispatch('pg:eventRefresh-artist-table');
|
||||
}
|
||||
|
||||
public function deleteArtist($id)
|
||||
@ -75,8 +74,13 @@ class ArtistForm extends Component
|
||||
|
||||
public function resetFields()
|
||||
{
|
||||
$this->name = '';
|
||||
$this->selectedCategory = [];
|
||||
foreach ($this->fields as $key => $value) {
|
||||
if ($key == 'category') {
|
||||
$this->fields[$key] = 'unset';
|
||||
} else {
|
||||
$this->fields[$key] = '';
|
||||
}
|
||||
}
|
||||
$this->artistId = null;
|
||||
}
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
namespace App\Livewire\Admin;
|
||||
|
||||
use App\Models\Artist;
|
||||
use App\Models\ArtistCategory;
|
||||
use App\Enums\ArtistCategory;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use PowerComponents\LivewirePowerGrid\Button;
|
||||
@ -62,21 +62,19 @@ final class ArtistTable extends PowerGridComponent
|
||||
|
||||
public function datasource(): Builder
|
||||
{
|
||||
return Artist::query()->with('category');
|
||||
return Artist::query();
|
||||
}
|
||||
|
||||
public function relationSearch(): array
|
||||
{
|
||||
return [
|
||||
'category' => ['name'],
|
||||
];
|
||||
return [];
|
||||
}
|
||||
|
||||
public function fields(): PowerGridFields
|
||||
{
|
||||
return PowerGrid::fields()
|
||||
->add('id')
|
||||
->add('category_name', fn (Artist $model) => optional($model->category)->name)
|
||||
->add('category', fn (Artist $model) => ArtistCategory::from($model->category)->labels())
|
||||
->add('name')
|
||||
->add('simplified')
|
||||
->add('phonetic_abbr')
|
||||
@ -88,7 +86,7 @@ final class ArtistTable extends PowerGridComponent
|
||||
{
|
||||
return [
|
||||
Column::make(__('artists.no'), 'id'),
|
||||
Column::make(__('artists.category'),'category_name', 'category.name')->searchable(),
|
||||
Column::make(__('artists.category'),'category', 'artists.category')->searchable(),
|
||||
Column::make(__('artists.name'), 'name')
|
||||
->sortable()
|
||||
->searchable(),
|
||||
@ -117,10 +115,9 @@ final class ArtistTable extends PowerGridComponent
|
||||
public function filters(): array
|
||||
{
|
||||
return [
|
||||
Filter::select('category_name', 'category_id')
|
||||
->dataSource(ArtistCategory::all())
|
||||
->optionValue('id')
|
||||
->optionLabel('name'),
|
||||
Filter::enumSelect('gender','users.gender')
|
||||
->datasource(ArtistCategory::cases())
|
||||
->optionLabel('users.gender'),
|
||||
Filter::inputText('name')->placeholder(__('artists.name')),
|
||||
Filter::inputText('phonetic_abbr')->placeholder(__('artists.name.phinetic')),
|
||||
Filter::inputText('pinyin_abbr')->placeholder(__('artists.name.pinyin')),
|
||||
@ -154,6 +151,7 @@ final class ArtistTable extends PowerGridComponent
|
||||
->dispatchTo('admin.artist-form', 'deleteArtist', ['id' => $row->id]), */
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
public function actionRules($row): array
|
||||
|
@ -50,17 +50,16 @@ final class RoleTable extends PowerGridComponent
|
||||
return PowerGrid::fields()
|
||||
->add('id')
|
||||
->add('name')
|
||||
->add('permissions_list' ,fn(Role $model)=> $model->permissions->pluck('name')->implode(', '))
|
||||
->add('created_at_formatted', fn (Role $model) => Carbon::parse($model->created_at)->format('d/m/Y H:i:s'));
|
||||
}
|
||||
|
||||
public function columns(): array
|
||||
{
|
||||
return [
|
||||
Column::make('ID', 'id')->sortable()->searchable(),
|
||||
Column::make('名稱', 'name')->sortable()->searchable(),
|
||||
//Column::make('權限', 'permissions_list', function ($role) {
|
||||
// return $role->permissions->pluck('name')->implode(', ');
|
||||
//}),
|
||||
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')
|
||||
];
|
||||
@ -78,12 +77,12 @@ final class RoleTable extends PowerGridComponent
|
||||
{
|
||||
return [
|
||||
Button::add('edit')
|
||||
->slot('編輯')
|
||||
->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')
|
||||
->slot('刪除')
|
||||
->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]),
|
||||
|
@ -5,6 +5,8 @@ namespace App\Livewire\Admin;
|
||||
use Livewire\Component;
|
||||
|
||||
use App\Models\User;
|
||||
use App\Enums\UserGender;
|
||||
use App\Enums\UserStatus;
|
||||
use Spatie\Permission\Models\Role;
|
||||
|
||||
class UserForm extends Component
|
||||
@ -12,20 +14,44 @@ class UserForm extends Component
|
||||
protected $listeners = ['openCreateUserModal','openEditUserModal', 'deleteUser'];
|
||||
|
||||
public bool $showCreateModal = false;
|
||||
public ?int $userId = null;
|
||||
public $name;
|
||||
public $email;
|
||||
public $roles = []; // 所有角色清單
|
||||
|
||||
|
||||
public array $genderOptions =[];
|
||||
public array $statusOptions =[];
|
||||
public $rolesOptions = []; // 所有角色清單
|
||||
public $selectedRoles = []; // 表單中選到的權限
|
||||
public ?int $userId = null;
|
||||
public array $fields = [
|
||||
'name' =>'',
|
||||
'email' => '',
|
||||
'phone' => '',
|
||||
'birthday' => '',
|
||||
'gender' => 'unset',
|
||||
'status' => 0,
|
||||
];
|
||||
|
||||
|
||||
protected $rules = [
|
||||
'name' => 'required|string|max:255',
|
||||
'email' => 'required|string|max:255',
|
||||
'fields.name' => 'required|string|max:255',
|
||||
'fields.email' => 'required|string|email|max:255',
|
||||
'fields.phone' => 'nullable|regex:/^09\d{8}$/',
|
||||
'fields.birthday' =>'nullable|date',
|
||||
'fields.gender' => 'required|in:male,female,other,unset',
|
||||
'fields.status' => 'required|integer|in:0,1,2',
|
||||
];
|
||||
|
||||
public function mount()
|
||||
{
|
||||
$this->roles = Role::all();
|
||||
$this->fields['birthday'] = now()->toDateString();
|
||||
$this->genderOptions = collect(UserGender::cases())->map(fn ($gender) => [
|
||||
'name' => $gender->labels(),
|
||||
'value' => $gender->value,
|
||||
])->toArray();
|
||||
$this->statusOptions = collect(UserStatus::cases())->map(fn ($status) => [
|
||||
'name' => $status->labels(),
|
||||
'value' => $status->value,
|
||||
])->toArray();
|
||||
$this->rolesOptions = Role::all();
|
||||
}
|
||||
|
||||
public function openCreateUserModal()
|
||||
@ -38,8 +64,8 @@ class UserForm extends Component
|
||||
{
|
||||
$user = User::findOrFail($id);
|
||||
$this->userId = $user->id;
|
||||
$this->name = $user->name;
|
||||
$this->email =$user->email;
|
||||
$this->fields = $user->only(array_keys($this->fields));
|
||||
|
||||
$this->selectedRoles = $user->roles()->pluck('id')->toArray();
|
||||
$this->showCreateModal = true;
|
||||
}
|
||||
@ -49,24 +75,19 @@ class UserForm extends Component
|
||||
$this->validate();
|
||||
|
||||
if ($this->userId) {
|
||||
$role = User::findOrFail($this->userId);
|
||||
$role->update([
|
||||
'name' => $this->name,
|
||||
'email' => $this->email,
|
||||
]);
|
||||
$role->syncRolses($this->selectedRoles);
|
||||
$user = User::findOrFail($this->userId);
|
||||
$user->update($this->fields);
|
||||
$user->syncRoles($this->selectedRoles);
|
||||
session()->flash('message', '使用者已更新');
|
||||
} else {
|
||||
$role = User::create([
|
||||
'name' => $this->name,
|
||||
'email' => $this->email,
|
||||
]);
|
||||
$role->syncRolses($this->selectedRoles);
|
||||
$user = User::create($this->fields);
|
||||
$user->syncRoles($this->selectedRoles);
|
||||
session()->flash('message', '使用者已新增');
|
||||
}
|
||||
|
||||
$this->resetFields();
|
||||
$this->showCreateModal = false;
|
||||
$this->dispatch('pg:eventRefresh-user-table');
|
||||
}
|
||||
|
||||
public function deleteUser($id)
|
||||
@ -77,10 +98,19 @@ class UserForm extends Component
|
||||
|
||||
public function resetFields()
|
||||
{
|
||||
$this->name = '';
|
||||
$this->email = '';
|
||||
$this->selectedRoles = [];
|
||||
foreach ($this->fields as $key => $value) {
|
||||
if ($key == 'gender') {
|
||||
$this->fields[$key] = 'unset';
|
||||
} elseif ($key == 'status') {
|
||||
$this->fields[$key] = 0;
|
||||
} elseif ($key == 'birthday') {
|
||||
$this->fields[$key] = now()->toDateString();
|
||||
} else {
|
||||
$this->fields[$key] = '';
|
||||
}
|
||||
}
|
||||
$this->userId = null;
|
||||
$this->selectedRoles = [];
|
||||
}
|
||||
|
||||
public function render()
|
||||
|
@ -3,6 +3,8 @@
|
||||
namespace App\Livewire\Admin;
|
||||
|
||||
use App\Models\User;
|
||||
use App\Enums\UserGender;
|
||||
use App\Enums\UserStatus;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use PowerComponents\LivewirePowerGrid\Button;
|
||||
@ -11,14 +13,14 @@ use PowerComponents\LivewirePowerGrid\Facades\Filter;
|
||||
use PowerComponents\LivewirePowerGrid\Facades\PowerGrid;
|
||||
use PowerComponents\LivewirePowerGrid\PowerGridFields;
|
||||
use PowerComponents\LivewirePowerGrid\PowerGridComponent;
|
||||
use PowerComponents\LivewirePowerGrid\Traits\WithExport;
|
||||
//use PowerComponents\LivewirePowerGrid\Traits\WithExport;
|
||||
use PowerComponents\LivewirePowerGrid\Components\SetUp\Exportable;
|
||||
use PowerComponents\LivewirePowerGrid\Facades\Rule;
|
||||
use Livewire\Attributes\On;
|
||||
|
||||
final class UserTable extends PowerGridComponent
|
||||
{
|
||||
use WithExport;
|
||||
//use WithExport ;
|
||||
|
||||
public string $tableName = 'user-table';
|
||||
|
||||
@ -71,25 +73,68 @@ final class UserTable extends PowerGridComponent
|
||||
->add('id')
|
||||
->add('name')
|
||||
->add('email')
|
||||
->add('created_at_formatted', fn (User $model) => Carbon::parse($model->created_at)->format('d/m/Y H:i:s'));
|
||||
->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('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'));
|
||||
}
|
||||
|
||||
public function columns(): array
|
||||
{
|
||||
return [
|
||||
Column::make('ID', 'id'),
|
||||
Column::make('名稱', 'name')->sortable()->searchable(),
|
||||
Column::make('Email', 'email')->sortable()->searchable(),
|
||||
Column::make(__('users.name'), 'name')
|
||||
->sortable()
|
||||
->searchable()
|
||||
->editOnClick(
|
||||
hasPermission: true,
|
||||
dataField: 'name',
|
||||
fallback: 'N/A',
|
||||
saveOnMouseOut: true
|
||||
),
|
||||
Column::make('Email', 'email')
|
||||
->sortable()
|
||||
->searchable()
|
||||
->editOnClick(
|
||||
hasPermission: true,
|
||||
dataField: 'email',
|
||||
fallback: 'N/A',
|
||||
saveOnMouseOut: true
|
||||
),
|
||||
Column::make(__('users.phone'), 'phone')
|
||||
->sortable()
|
||||
->searchable()
|
||||
->editOnClick(
|
||||
hasPermission: true,
|
||||
dataField: 'phone',
|
||||
fallback: 'N/A',
|
||||
saveOnMouseOut: true
|
||||
),
|
||||
|
||||
Column::make(__('users.gender'), 'gender','users.gender'),
|
||||
Column::make(__('users.birthday'), 'birthday_formatted')->sortable()->searchable(),
|
||||
Column::make(__('users.status'), 'status','users.status'),
|
||||
Column::make(__('users.role'), 'roles'),
|
||||
Column::make('建立時間', 'created_at_formatted', 'created_at')->sortable(),
|
||||
Column::action('操作')
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
public function filters(): array
|
||||
{
|
||||
return [
|
||||
Filter::inputText('name')->placeholder('Dish Name'),
|
||||
Filter::inputText('email')->placeholder('Dish Email'),
|
||||
Filter::inputText('name')->placeholder(__('users.name')),
|
||||
Filter::inputText('email')->placeholder('Email'),
|
||||
Filter::inputText('phone')->placeholder(__('users.phone')),
|
||||
Filter::enumSelect('gender','users.gender')
|
||||
->datasource(UserGender::cases())
|
||||
->optionLabel('users.gender'),
|
||||
Filter::datepicker('birthday'),
|
||||
Filter::enumSelect('status', 'users.status')
|
||||
->datasource(UserStatus::cases())
|
||||
->optionLabel('users.status'),
|
||||
Filter::datetimepicker('created_at'),
|
||||
];
|
||||
}
|
||||
@ -99,17 +144,36 @@ final class UserTable extends PowerGridComponent
|
||||
return [
|
||||
|
||||
Button::add('edit')
|
||||
->slot('編輯')
|
||||
->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')
|
||||
->slot('刪除')
|
||||
->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
|
||||
{
|
||||
|
@ -13,18 +13,13 @@ class Artist extends Model
|
||||
use HasFactory;
|
||||
|
||||
protected $fillable = [
|
||||
'category_id',
|
||||
'category',
|
||||
'name',
|
||||
'simplified',
|
||||
'phonetic_abbr',
|
||||
'pinyin_abbr',
|
||||
];
|
||||
|
||||
public function category()
|
||||
{
|
||||
return $this->belongsTo(ArtistCategory::class, 'category_id', 'id');
|
||||
}
|
||||
|
||||
public function songs() {
|
||||
return $this->belongsToMany(Song::class);
|
||||
}
|
||||
|
@ -1,16 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class ArtistCategory extends Model
|
||||
{
|
||||
/** @use HasFactory<\Database\Factories\ArtistCategoryFactory> */
|
||||
use HasFactory;
|
||||
|
||||
protected $fillable = [
|
||||
'name',
|
||||
];
|
||||
}
|
@ -32,6 +32,10 @@ class Song extends Model
|
||||
'pinyin_abbr',
|
||||
];
|
||||
|
||||
public function users(){
|
||||
return $this->belongsToMany(User::class, 'user_song')->withTimestamps();
|
||||
}
|
||||
|
||||
public function str_artists(){
|
||||
return $this->artists->pluck('name')->implode(', ');
|
||||
}
|
||||
|
@ -21,6 +21,10 @@ class User extends Authenticatable
|
||||
protected $fillable = [
|
||||
'name',
|
||||
'email',
|
||||
'phone',
|
||||
'birthday',
|
||||
'gender',
|
||||
'status',
|
||||
'password',
|
||||
];
|
||||
|
||||
@ -44,6 +48,11 @@ class User extends Authenticatable
|
||||
return [
|
||||
'email_verified_at' => 'datetime',
|
||||
'password' => 'hashed',
|
||||
'birthday' => 'date'
|
||||
];
|
||||
}
|
||||
|
||||
public function songs() {
|
||||
return $this->belongsToMany(Song::class, 'user_song')->withTimestamps();
|
||||
}
|
||||
}
|
||||
|
@ -15,6 +15,10 @@ return new class extends Migration
|
||||
$table->id();
|
||||
$table->string('name');
|
||||
$table->string('email')->unique();
|
||||
$table->string('phone', 10)->unique();
|
||||
$table->date('birthday')->nullable(); // 生日
|
||||
$table->enum('gender', ['unset','male', 'female', 'other'])->default('unset'); // 性別
|
||||
$table->tinyInteger('status')->default(0); // 啟動
|
||||
$table->timestamp('email_verified_at')->nullable();
|
||||
$table->string('password');
|
||||
$table->rememberToken();
|
||||
|
@ -1,28 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('artist_categories', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('name')->unique();
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('artist_categories');
|
||||
}
|
||||
};
|
@ -13,14 +13,12 @@ return new class extends Migration
|
||||
{
|
||||
Schema::create('artists', function (Blueprint $table) {
|
||||
$table->bigIncrements('id');
|
||||
$table->unsignedBigInteger('category_id')->default(1)->comment('關聯 artist_category.id');//預設為 1(未定義))
|
||||
$table->enum('category', ['unset','male', 'female','group','foreign', 'other'])->default('unset'); // 性別
|
||||
$table->string('name')->comment('歌星名稱');
|
||||
$table->string('simplified')->comment('歌星簡體');
|
||||
$table->string('phonetic_abbr')->comment('歌星注音');
|
||||
$table->string('pinyin_abbr')->comment('歌星拼音');
|
||||
$table->timestamps();
|
||||
// 外鍵(如需要)
|
||||
$table->foreign('category_id')->references('id')->on('artist_categories')->restrictOnDelete()->restrictOnUpdate();
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('user_song', function (Blueprint $table) {
|
||||
$table->unsignedBigInteger('song_id');
|
||||
$table->unsignedBigInteger('user_id');
|
||||
|
||||
$table->foreign('song_id')->references('id')->on('songs')->restrictOnDelete()->restrictOnUpdate();
|
||||
$table->foreign('user_id')->references('id')->on('users')->restrictOnDelete()->restrictOnUpdate();
|
||||
$table->primary(['song_id', 'user_id']);
|
||||
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('user_song');
|
||||
}
|
||||
};
|
@ -1,22 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
|
||||
use Illuminate\Database\Seeder;
|
||||
use App\Models\ArtistCategory;
|
||||
|
||||
class ArtistCategorySeeder extends Seeder
|
||||
{
|
||||
/**
|
||||
* Run the database seeds.
|
||||
*/
|
||||
public function run(): void
|
||||
{
|
||||
$artistCategoryLists = ['未定義','男', '團', '女', '外'];
|
||||
|
||||
foreach ($artistCategoryLists as $category) {
|
||||
ArtistCategory::create(['name' => $category]);
|
||||
}
|
||||
}
|
||||
}
|
@ -16,12 +16,16 @@ class CreateAdminUserSeeder extends Seeder
|
||||
$user = User::create([
|
||||
'name' => 'Allen Yan(admin)',
|
||||
'email' => 'admin@gmail.com',
|
||||
'phone' => '0900000000',
|
||||
'birthday' => now()->toDateString(),
|
||||
'password' => bcrypt('aa1234')
|
||||
]);
|
||||
$user->assignRole('Admin');
|
||||
$user = User::create([
|
||||
'name' => 'Allen Yan(User)',
|
||||
'email' => 'allen.yan@gmail.com',
|
||||
'phone' => '0900000001',
|
||||
'birthday' => now()->toDateString(),
|
||||
'password' => bcrypt('aa1234')
|
||||
]);
|
||||
$user->assignRole('User');
|
||||
|
@ -17,7 +17,6 @@ class DatabaseSeeder extends Seeder
|
||||
PermissionTableSeeder::class,
|
||||
SongCategorySeeder::class,
|
||||
SongLanguageSeeder::class,
|
||||
ArtistCategorySeeder::class,
|
||||
CreateAdminUserSeeder::class,
|
||||
]);
|
||||
}
|
||||
|
13
resources/lang/zh-tw/enums.php
Normal file
13
resources/lang/zh-tw/enums.php
Normal file
@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'Unset' => '未定義',
|
||||
'Other' => '其他',
|
||||
'Male' =>'男',
|
||||
'Female' =>'女',
|
||||
'arist.category.Group' => '團',
|
||||
'arist.category.Foreign' => '外',
|
||||
'user.status.Active' => '正常',
|
||||
'user.status.Suspended' => '停權',
|
||||
'user.status.Deleting' => '刪除中',
|
||||
];
|
@ -8,6 +8,7 @@ return [
|
||||
|
||||
'no' => '編號',
|
||||
'name' => '名稱',
|
||||
'permissions' => '權限',
|
||||
|
||||
'create' => '新增',
|
||||
'action' => '操作',
|
||||
|
@ -8,6 +8,11 @@ return [
|
||||
|
||||
'no' => '編號',
|
||||
'name' => '名稱',
|
||||
'phone' => '手機門號',
|
||||
'gender' => '性別',
|
||||
'birthday' => '生日',
|
||||
'status' => '狀態',
|
||||
'role' =>'角色',
|
||||
|
||||
'create' => '新增',
|
||||
'action' => '操作',
|
||||
|
@ -1,24 +1,21 @@
|
||||
<div class="p-6 space-y-4">
|
||||
@if ($showCreateModal)
|
||||
<x-wireui:modal-card title="{{ $artistId ? '編輯歌手' : '新增歌手' }}" blur wire:model.defer="showCreateModal">
|
||||
<div class="space-y-4">
|
||||
<x-wireui:select
|
||||
label="類別"
|
||||
wire:model.defer="selectedCategory"
|
||||
placeholder="選擇類別"
|
||||
option-label="label"
|
||||
option-value="value"
|
||||
:options="$artistCategory->map(fn($p) => ['value' => $p->id, 'label' => $p->name])->toArray()"
|
||||
/>
|
||||
<x-wireui:input label="名稱" wire:model.defer="name" />
|
||||
</div>
|
||||
<x-wireui:modal-card title="{{ $artistId ? '編輯歌手' : '新增歌手' }}" blur wire:model.defer="showCreateModal">
|
||||
<div class="space-y-4">
|
||||
<x-wireui:select
|
||||
label="類別"
|
||||
wire:model.defer="fields.category"
|
||||
placeholder="選擇類別"
|
||||
:options="$categoryOptions"
|
||||
option-label="name"
|
||||
option-value="value"
|
||||
/>
|
||||
<x-wireui:input label="名稱" wire:model.defer="fields.name" />
|
||||
</div>
|
||||
|
||||
<x-slot name="footer">
|
||||
<div class="flex justify-center gap-2">
|
||||
<x-wireui:button primary label="{{__('artists.cancel')}}" x-on:click="$dispatch('close')" />
|
||||
<x-wireui:button primary label="{{__('artists.submit')}}" wire:click="save" />
|
||||
</div>
|
||||
</x-slot>
|
||||
</x-wireui:modal-card>
|
||||
@endif
|
||||
</div>
|
||||
<x-slot name="footer">
|
||||
<div class="flex justify-center gap-2">
|
||||
<x-wireui:button primary label="{{__('artists.cancel')}}" x-on:click="$dispatch('close')" />
|
||||
<x-wireui:button primary label="{{__('artists.submit')}}" wire:click="save" />
|
||||
</div>
|
||||
</x-slot>
|
||||
</x-wireui:modal-card>
|
||||
|
@ -1,28 +1,40 @@
|
||||
<div class="p-6 space-y-4">
|
||||
@if ($showCreateModal)
|
||||
<x-wireui:modal-card title="{{ $userId ? '編輯使用者' : '新增使用者' }}" blur wire:model.defer="showCreateModal">
|
||||
<div class="space-y-4">
|
||||
<x-wireui:input label="名稱" wire:model.defer="name" />
|
||||
<x-wireui:modal-card title="{{ $userId ? '編輯使用者' : '新增使用者' }}" blur wire:model.defer="showCreateModal">
|
||||
<div class="space-y-4">
|
||||
<x-wireui:input label="名稱" 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="性別"
|
||||
wire:model.defer="fields.gender"
|
||||
placeholder="選擇性別"
|
||||
:options="$genderOptions"
|
||||
option-label="name"
|
||||
option-value="value"
|
||||
/>
|
||||
<x-wireui:select
|
||||
label="狀態"
|
||||
wire:model.defer="fields.status"
|
||||
placeholder="選擇狀態"
|
||||
:options="$statusOptions"
|
||||
option-label="name"
|
||||
option-value="value"
|
||||
/>
|
||||
|
||||
<x-wireui:input label="Email" wire:model.defer="email" />
|
||||
<x-wireui:select
|
||||
label="角色"
|
||||
wire:model.defer="selectedRoles"
|
||||
placeholder="選擇角色"
|
||||
multiselect
|
||||
option-label="label"
|
||||
option-value="value"
|
||||
:options="$rolesOptions->map(fn($p) => ['value' => $p->id, 'label' => $p->name])->toArray()"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<x-wireui:select
|
||||
label="角色"
|
||||
wire:model.defer="selectedRoles"
|
||||
placeholder="選擇角色"
|
||||
multiselect
|
||||
option-label="label"
|
||||
option-value="value"
|
||||
:options="$roles->map(fn($p) => ['value' => $p->id, 'label' => $p->name])->toArray()"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<x-slot name="footer">
|
||||
<div class="flex justify-center gap-2">
|
||||
<x-wireui:button primary label="{{__('users.cancel')}}" x-on:click="$dispatch('close')" />
|
||||
<x-wireui:button primary label="{{__('users.submit')}}" wire:click="save" />
|
||||
</div>
|
||||
</x-slot>
|
||||
</x-wireui:modal-card>
|
||||
@endif
|
||||
</div>
|
||||
<x-slot name="footer">
|
||||
<div class="flex justify-center gap-2">
|
||||
<x-wireui:button primary label="{{__('users.cancel')}}" x-on:click="$dispatch('close')" />
|
||||
<x-wireui:button primary label="{{__('users.submit')}}" wire:click="save" />
|
||||
</div>
|
||||
</x-slot>
|
||||
</x-wireui:modal-card>
|
Loading…
x
Reference in New Issue
Block a user