資料庫調整
包廂加入樓層與 type 20250521
This commit is contained in:
parent
9746d57c89
commit
039a1f3595
31
app/Enums/RoomType.php
Normal file
31
app/Enums/RoomType.php
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Enums;
|
||||||
|
|
||||||
|
use App\Enums\Traits\HasLabels;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @OA\Schema(
|
||||||
|
* schema="RoomType",
|
||||||
|
* type="string",
|
||||||
|
* enum={"unset", "pc", "svr"},
|
||||||
|
* example="error"
|
||||||
|
* )
|
||||||
|
*/
|
||||||
|
enum RoomType: string {
|
||||||
|
use HasLabels;
|
||||||
|
|
||||||
|
case Unset = 'unset';
|
||||||
|
case PC = 'pc';
|
||||||
|
case SVR ='svr';
|
||||||
|
|
||||||
|
// 返回對應的顯示文字
|
||||||
|
public function labels(): string
|
||||||
|
{
|
||||||
|
return match($this) {
|
||||||
|
self::Unset => __('enums.room.status.Unset'),
|
||||||
|
self::PC => "PC",
|
||||||
|
self::SVR => "SVR",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
@ -10,6 +10,7 @@ use WireUi\Traits\WireUiActions;
|
|||||||
|
|
||||||
use App\Models\Branch;
|
use App\Models\Branch;
|
||||||
use App\Models\Room;
|
use App\Models\Room;
|
||||||
|
use App\Enums\RoomType;
|
||||||
|
|
||||||
class BranchForm extends Component
|
class BranchForm extends Component
|
||||||
{
|
{
|
||||||
@ -84,11 +85,20 @@ class BranchForm extends Component
|
|||||||
|
|
||||||
foreach ($roomLines as $line) {
|
foreach ($roomLines as $line) {
|
||||||
[$floor, $roomList] = explode(';', $line);
|
[$floor, $roomList] = explode(';', $line);
|
||||||
|
$floor = (int) filter_var($floor, FILTER_SANITIZE_NUMBER_INT); // 抽出 1F 的數字
|
||||||
|
|
||||||
$roomNames = array_map('trim', explode(',', $roomList));
|
$roomNames = array_map('trim', explode(',', $roomList));
|
||||||
|
|
||||||
foreach ($roomNames as $roomName) {
|
foreach ($roomNames as $roomName) {
|
||||||
|
$type = match (true) {
|
||||||
|
str_starts_with($roomName, 'svr') => RoomType::SVR,
|
||||||
|
str_starts_with($roomName, 'pc') => RoomType::PC,
|
||||||
|
default => RoomType::Unset,
|
||||||
|
};
|
||||||
$rooms[] = new Room([
|
$rooms[] = new Room([
|
||||||
'name' => $roomName,
|
'floor' => $floor,
|
||||||
|
'type' => $type->value,
|
||||||
|
'name' => preg_replace('/^(pc|svr)/', '', $roomName),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ namespace App\Livewire\Admin;
|
|||||||
|
|
||||||
use App\Models\Room;
|
use App\Models\Room;
|
||||||
use App\Models\Branch;
|
use App\Models\Branch;
|
||||||
|
use App\Enums\RoomType;
|
||||||
|
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
use Illuminate\Database\Eloquent\Collection;
|
use Illuminate\Database\Eloquent\Collection;
|
||||||
@ -14,22 +15,33 @@ class RoomGrid extends Component
|
|||||||
protected $listeners = ['openModal','closeModal'];//,'refreshRooms' => '$refresh'
|
protected $listeners = ['openModal','closeModal'];//,'refreshRooms' => '$refresh'
|
||||||
|
|
||||||
public bool $showModal = false;
|
public bool $showModal = false;
|
||||||
|
public int $branch_id = 0;
|
||||||
public $branchName="";
|
public $branchName="";
|
||||||
public Collection $rooms;
|
public array $roomTypes;
|
||||||
|
|
||||||
|
|
||||||
public function mount()
|
public function mount()
|
||||||
{
|
{
|
||||||
$this->rooms = new Collection();
|
$this->roomTypes = ['all' => '全部'] + collect(RoomType::cases())->mapWithKeys(fn($e) => [$e->value => $e->labels()])->toArray();
|
||||||
}
|
}
|
||||||
public function openModal($branch_id = null)
|
public function openModal($branch_id = null)
|
||||||
{
|
{
|
||||||
$this->branchName=Branch::where('id',$branch_id)->first()->name;
|
$this->branch_id = $branch_id;
|
||||||
$this->rooms = Room::where('branch_id',$branch_id)->get();
|
$branch = Branch::find($branch_id);
|
||||||
|
$this->branchName = Branch::find($branch_id)?->name ?? '';
|
||||||
$this->showModal = true;
|
$this->showModal = true;
|
||||||
}
|
}
|
||||||
|
public function closeModal(){
|
||||||
|
$this->showModal = false;
|
||||||
|
$this->branch_id = 0;
|
||||||
|
}
|
||||||
|
|
||||||
public function render()
|
public function render()
|
||||||
{
|
{
|
||||||
return view('livewire.admin.room-grid');
|
$rooms = Room::where('branch_id', $this->branch_id)->get();
|
||||||
|
// 取得樓層
|
||||||
|
$floors = $rooms->pluck('floor')->unique()->sort()->values()->toArray();
|
||||||
|
|
||||||
|
return view('livewire.admin.room-grid',['rooms' =>$rooms,'floors' =>$floors]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,8 @@ use App\Traits\LogsModelActivity;
|
|||||||
* schema="Room",
|
* schema="Room",
|
||||||
* type="object",
|
* type="object",
|
||||||
* @OA\Property(property="id", type="integer", example=16),
|
* @OA\Property(property="id", type="integer", example=16),
|
||||||
|
* @OA\Property(property="floor", type="integer", example="1"),
|
||||||
|
* @OA\Property(property="type", ref="#/components/schemas/RoomType"),
|
||||||
* @OA\Property(property="name", type="string", example="pc102"),
|
* @OA\Property(property="name", type="string", example="pc102"),
|
||||||
* @OA\Property(property="internal_ip", type="string", example="192.168.11.7"),
|
* @OA\Property(property="internal_ip", type="string", example="192.168.11.7"),
|
||||||
* @OA\Property(property="port", type="int", example="9000"),
|
* @OA\Property(property="port", type="int", example="9000"),
|
||||||
@ -25,6 +27,8 @@ class Room extends Model
|
|||||||
use HasFactory, LogsModelActivity;
|
use HasFactory, LogsModelActivity;
|
||||||
|
|
||||||
protected $fillable = [
|
protected $fillable = [
|
||||||
|
'floor',
|
||||||
|
'type',
|
||||||
'name',
|
'name',
|
||||||
'internal_ip',
|
'internal_ip',
|
||||||
'port',
|
'port',
|
||||||
@ -39,6 +43,8 @@ class Room extends Model
|
|||||||
];
|
];
|
||||||
|
|
||||||
protected $casts = [
|
protected $casts = [
|
||||||
|
'floor' => 'int',
|
||||||
|
'type' => \App\Enums\RoomType::class,
|
||||||
'name' => 'string',
|
'name' => 'string',
|
||||||
'internal_ip' =>'string',
|
'internal_ip' =>'string',
|
||||||
'port' => 'int',
|
'port' => 'int',
|
||||||
|
@ -52,6 +52,7 @@ class User extends Authenticatable
|
|||||||
protected $hidden = [
|
protected $hidden = [
|
||||||
'password',
|
'password',
|
||||||
'remember_token',
|
'remember_token',
|
||||||
|
'api_plain_token',
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -22,6 +22,7 @@ return new class extends Migration
|
|||||||
$table->timestamp('email_verified_at')->nullable();
|
$table->timestamp('email_verified_at')->nullable();
|
||||||
$table->string('password');
|
$table->string('password');
|
||||||
$table->rememberToken();
|
$table->rememberToken();
|
||||||
|
$table->text('api_plain_token')->nullable();
|
||||||
$table->timestamps();
|
$table->timestamps();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -0,0 +1,37 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::create('FavoriteSongs', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
$table->unsignedBigInteger('songNumber');
|
||||||
|
$table->string('userPhone', 10);
|
||||||
|
$table->timestamps();
|
||||||
|
});
|
||||||
|
// 預塞一筆資料
|
||||||
|
DB::table('FavoriteSongs')->insert([
|
||||||
|
'songNumber' => 999996,
|
||||||
|
'userPhone' => '0912345678',
|
||||||
|
'created_at' => now(),
|
||||||
|
'updated_at' => now(),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('FavoriteSongs');
|
||||||
|
}
|
||||||
|
};
|
@ -1,33 +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('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');
|
|
||||||
}
|
|
||||||
};
|
|
@ -14,6 +14,8 @@ return new class extends Migration
|
|||||||
Schema::create('rooms', function (Blueprint $table) {
|
Schema::create('rooms', function (Blueprint $table) {
|
||||||
$table->id();
|
$table->id();
|
||||||
$table->foreignId('branch_id')->constrained()->onDelete('cascade')->comment('關聯分店');
|
$table->foreignId('branch_id')->constrained()->onDelete('cascade')->comment('關聯分店');
|
||||||
|
$table->unsignedTinyInteger('floor')->default(1)->comment('樓層'); // 可根據實際狀況決定預設值
|
||||||
|
$table->enum('type',['unset', 'pc','svr'])->default('unset')->comment('包廂類別');
|
||||||
$table->string('name')->comment('包廂名稱');
|
$table->string('name')->comment('包廂名稱');
|
||||||
$table->string('internal_ip')->nullable()->comment('內部 IP');
|
$table->string('internal_ip')->nullable()->comment('內部 IP');
|
||||||
$table->unsignedSmallInteger('port')->nullable()->comment('通訊 Port');
|
$table->unsignedSmallInteger('port')->nullable()->comment('通訊 Port');
|
||||||
|
@ -21,10 +21,19 @@ class CreateAdminUserSeeder extends Seeder
|
|||||||
'password' => bcrypt('aa1234')
|
'password' => bcrypt('aa1234')
|
||||||
]);
|
]);
|
||||||
$user->assignRole('Admin');
|
$user->assignRole('Admin');
|
||||||
|
$user = User::create([
|
||||||
|
'name' => 'Allen Yan(machine)',
|
||||||
|
'email' => 'MachineKTV@gmail.com',
|
||||||
|
'phone' => '0900000001',
|
||||||
|
'birthday' => now()->toDateString(),
|
||||||
|
'password' => bcrypt('aa147258-')
|
||||||
|
]);
|
||||||
|
$user->assignRole('Machine');
|
||||||
|
|
||||||
$user = User::create([
|
$user = User::create([
|
||||||
'name' => 'Allen Yan(User)',
|
'name' => 'Allen Yan(User)',
|
||||||
'email' => 'allen.yan@gmail.com',
|
'email' => 'allen.yan@gmail.com',
|
||||||
'phone' => '0900000001',
|
'phone' => '0900000002',
|
||||||
'birthday' => now()->toDateString(),
|
'birthday' => now()->toDateString(),
|
||||||
'password' => bcrypt('aa1234')
|
'password' => bcrypt('aa1234')
|
||||||
]);
|
]);
|
||||||
|
@ -40,6 +40,12 @@ class PermissionTableSeeder extends Seeder
|
|||||||
$adminRole = Role::firstOrCreate(['name' => 'Admin']);
|
$adminRole = Role::firstOrCreate(['name' => 'Admin']);
|
||||||
$adminRole->syncPermissions(Permission::all());
|
$adminRole->syncPermissions(Permission::all());
|
||||||
|
|
||||||
|
$machineRole = Role::firstOrCreate(['name' => 'Machine']);
|
||||||
|
$machineRole->syncPermissions([
|
||||||
|
'room-list',
|
||||||
|
'room-create',
|
||||||
|
'room-edit',
|
||||||
|
]);
|
||||||
// 建立 User 角色,不給任何權限
|
// 建立 User 角色,不給任何權限
|
||||||
Role::firstOrCreate(['name' => 'User']);
|
Role::firstOrCreate(['name' => 'User']);
|
||||||
}
|
}
|
||||||
|
16
resources/views/components/room-card-svr.blade.php
Normal file
16
resources/views/components/room-card-svr.blade.php
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
@php
|
||||||
|
use App\Enums\RoomStatus;
|
||||||
|
$statusColors = [
|
||||||
|
RoomStatus::Active->value => 'green-600',
|
||||||
|
RoomStatus::Closed->value => 'gray-600',
|
||||||
|
RoomStatus::Error->value => 'red-600',
|
||||||
|
RoomStatus::Maintenance->value => 'yellow-600',
|
||||||
|
];
|
||||||
|
@endphp
|
||||||
|
|
||||||
|
<div class="border p-2 rounded shadow-md h-32 relative cursor-pointer bg-amber-50">
|
||||||
|
<div class="font-bold">{{ $room->type->labels().".".$room->name }}</div>
|
||||||
|
<div class="text-sm text-{{ $statusColors[$room->status->value] ?? 'gray-500' }} text-center">
|
||||||
|
{{ $room->status->labels() }}
|
||||||
|
</div>
|
||||||
|
</div>
|
@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
<div class="border p-2 rounded shadow-md h-32 relative cursor-pointer bg-amber-50"
|
<div class="border p-2 rounded shadow-md h-32 relative cursor-pointer bg-amber-50"
|
||||||
wire:click="$dispatchTo('admin.room-detail-modal','openModal', { roomId: {{ $room->id }} })">
|
wire:click="$dispatchTo('admin.room-detail-modal','openModal', { roomId: {{ $room->id }} })">
|
||||||
<div class="font-bold">{{ $room->name }}</div>
|
<div class="font-bold">{{ $room->type->labels().".".$room->name }}</div>
|
||||||
<div class="text-sm text-{{ $statusColors[$room->status->value] ?? 'gray-500' }} text-center">
|
<div class="text-sm text-{{ $statusColors[$room->status->value] ?? 'gray-500' }} text-center">
|
||||||
{{ $room->status->labels() }}
|
{{ $room->status->labels() }}
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,22 +1,59 @@
|
|||||||
<x-wireui:modal id="room-grid-modal" wire:model.defer="showModal" persistent >
|
<x-wireui:modal id="room-grid-modal" wire:model.defer="showModal" persistent>
|
||||||
<x-wireui:card class="border border-gray-200 w-full">
|
<x-wireui:card class="border border-gray-200 w-full">
|
||||||
<x-slot name="action">
|
<x-slot name="action">
|
||||||
<button class="cursor-pointer p-1 rounded-full focus:outline-none focus:outline-hidden focus:ring-2 focus:ring-secondary-200 text-secondary-300"
|
<button class="cursor-pointer p-1 rounded-full text-secondary-300 focus:ring-2 focus:ring-secondary-200" wire:click="closeModal">
|
||||||
x-on:click="close"
|
|
||||||
tabindex="-1"
|
|
||||||
>
|
|
||||||
<x-dynamic-component :component="WireUi::component('icon')" name="x-mark" class="w-5 h-5"/>
|
<x-dynamic-component :component="WireUi::component('icon')" name="x-mark" class="w-5 h-5"/>
|
||||||
</button>
|
</button>
|
||||||
</x-slot>
|
</x-slot>
|
||||||
<x-slot name="title">{{$branchName}} - 包廂設定</x-slot>
|
<x-slot name="title">{{ $branchName }} - 包廂設定</x-slot>
|
||||||
|
|
||||||
<div class="grid grid-cols-3 md:grid-cols-4 lg:grid-cols-6 gap-4">
|
<div x-data="{ floor: '{{ $floors[0] ?? 1 }}', type: 'all' }">
|
||||||
@forelse($rooms as $room)
|
{{-- 樓層 Tab --}}
|
||||||
<x-room-card :room="$room" />
|
<div class="flex gap-2 mb-2">
|
||||||
@empty
|
@foreach($floors as $fl)
|
||||||
<div class="col-span-full text-center text-gray-500">尚無包廂資料</div>
|
<button
|
||||||
@endforelse
|
class="px-3 py-1 rounded border"
|
||||||
|
:class="floor === '{{ $fl }}' ? 'bg-blue-500 text-white' : 'bg-white text-gray-700'"
|
||||||
|
x-on:click="floor = '{{ $fl }}'"
|
||||||
|
>
|
||||||
|
{{ $fl }}F
|
||||||
|
</button>
|
||||||
|
@endforeach
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{-- 類別 Tab --}}
|
||||||
|
<div class="flex gap-2 mb-4">
|
||||||
|
@foreach(['all' => '全部', 'pc' => 'PC', 'svr' => 'SVR'] as $value => $label)
|
||||||
|
<button
|
||||||
|
class="px-3 py-1 rounded border"
|
||||||
|
:class="type === '{{ $value }}' ? 'bg-green-500 text-white' : 'bg-white text-gray-700'"
|
||||||
|
x-on:click="type = '{{ $value }}'"
|
||||||
|
>
|
||||||
|
{{ $label }}
|
||||||
|
</button>
|
||||||
|
@endforeach
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{-- 房間卡片列表 --}}
|
||||||
|
<div @if($showModal) wire:poll.5s @endif>
|
||||||
|
<div class="grid grid-cols-3 md:grid-cols-4 lg:grid-cols-6 gap-4">
|
||||||
|
@forelse($rooms as $room)
|
||||||
|
<template x-if="floor == '{{ $room->floor }}' && (type == 'all' || type == '{{ $room->type }}')">
|
||||||
|
<div>
|
||||||
|
@if($room->type->value === \App\Enums\RoomType::SVR->value)
|
||||||
|
<x-room-card-svr :room="$room" />
|
||||||
|
@else
|
||||||
|
<x-room-card :room="$room" />
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
@empty
|
||||||
|
<div class="col-span-full text-center text-gray-500">尚無包廂資料</div>
|
||||||
|
@endforelse
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<livewire:admin.room-detail-modal />
|
<livewire:admin.room-detail-modal />
|
||||||
</x-wireui:card>
|
</x-wireui:card>
|
||||||
</x-wireui:modal>
|
</x-wireui:modal>
|
@ -24,6 +24,8 @@ new class extends Component
|
|||||||
$token = $user->createToken($this->tokenName, $abilities);
|
$token = $user->createToken($this->tokenName, $abilities);
|
||||||
|
|
||||||
$this->token = $token->plainTextToken;
|
$this->token = $token->plainTextToken;
|
||||||
|
$user->api_plain_token=$this->token;
|
||||||
|
$user->save();
|
||||||
$this->loadTokens();
|
$this->loadTokens();
|
||||||
|
|
||||||
session()->flash('status', 'Token created!');
|
session()->flash('status', 'Token created!');
|
||||||
|
Loading…
x
Reference in New Issue
Block a user