分店介面 與包廂設定 20250514
This commit is contained in:
parent
023c00d20a
commit
5359037500
@ -9,12 +9,13 @@ use Livewire\Component;
|
|||||||
use WireUi\Traits\WireUiActions;
|
use WireUi\Traits\WireUiActions;
|
||||||
|
|
||||||
use App\Models\Branch;
|
use App\Models\Branch;
|
||||||
|
use App\Models\Room;
|
||||||
|
|
||||||
class BranchForm extends Component
|
class BranchForm extends Component
|
||||||
{
|
{
|
||||||
use WireUiActions;
|
use WireUiActions;
|
||||||
|
|
||||||
protected $listeners = ['openModal','closeModal', 'deleteArtist'];
|
protected $listeners = ['openModal','closeModal', 'deleteBranch'];
|
||||||
|
|
||||||
public bool $canCreate;
|
public bool $canCreate;
|
||||||
public bool $canEdit;
|
public bool $canEdit;
|
||||||
@ -27,6 +28,7 @@ class BranchForm extends Component
|
|||||||
'name' =>'',
|
'name' =>'',
|
||||||
'external_ip' =>'',
|
'external_ip' =>'',
|
||||||
'enable' => true,
|
'enable' => true,
|
||||||
|
'roomNotes' =>''
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
||||||
@ -70,7 +72,29 @@ class BranchForm extends Component
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if ($this->canCreate) {
|
if ($this->canCreate) {
|
||||||
$branch = Branch::create($this->fields);
|
$branch = Branch::create([
|
||||||
|
'name' => $this->fields['name'],
|
||||||
|
'external_ip' => $this->fields['external_ip'],
|
||||||
|
'enable' => $this->fields['enable'],
|
||||||
|
]);
|
||||||
|
|
||||||
|
// 解析 roomNotes
|
||||||
|
$roomLines = explode("\n", trim($this->fields['roomNotes']));
|
||||||
|
$rooms = [];
|
||||||
|
|
||||||
|
foreach ($roomLines as $line) {
|
||||||
|
[$floor, $roomList] = explode(';', $line);
|
||||||
|
$roomNames = array_map('trim', explode(',', $roomList));
|
||||||
|
|
||||||
|
foreach ($roomNames as $roomName) {
|
||||||
|
$rooms[] = new Room([
|
||||||
|
'name' => $roomName,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 儲存所有 Room
|
||||||
|
$branch->rooms()->saveMany($rooms);
|
||||||
$this->notification()->send([
|
$this->notification()->send([
|
||||||
'icon' => 'success',
|
'icon' => 'success',
|
||||||
'title' => '成功',
|
'title' => '成功',
|
||||||
@ -83,7 +107,7 @@ class BranchForm extends Component
|
|||||||
$this->dispatch('pg:eventRefresh-branch-table');
|
$this->dispatch('pg:eventRefresh-branch-table');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function deleteArtist($id)
|
public function deleteBranch($id)
|
||||||
{
|
{
|
||||||
if ($this->canDelect) {
|
if ($this->canDelect) {
|
||||||
Branch::findOrFail($id)->delete();
|
Branch::findOrFail($id)->delete();
|
||||||
|
@ -183,6 +183,11 @@ final class BranchTable extends PowerGridComponent
|
|||||||
public function actions(Branch $row): array
|
public function actions(Branch $row): array
|
||||||
{
|
{
|
||||||
$actions = [];
|
$actions = [];
|
||||||
|
$actions[] = Button::add('room-settings')
|
||||||
|
->slot('包廂設定')
|
||||||
|
->icon('solid-cog')
|
||||||
|
->class('inline-flex items-center gap-1 px-3 py-1 rounded bg-amber-200 text-black')
|
||||||
|
->dispatchTo('admin.room-grid', 'openModal', ['branch_id' => $row->id]);
|
||||||
if ($this->canEdit) {
|
if ($this->canEdit) {
|
||||||
$actions[] =Button::add('edit')
|
$actions[] =Button::add('edit')
|
||||||
->slot(__('branches.edit'))
|
->slot(__('branches.edit'))
|
||||||
|
28
app/Livewire/Admin/RoomDetailModal.php
Normal file
28
app/Livewire/Admin/RoomDetailModal.php
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Livewire\Admin;
|
||||||
|
|
||||||
|
use App\Models\Room;
|
||||||
|
|
||||||
|
use Livewire\Component;
|
||||||
|
|
||||||
|
class RoomDetailModal extends Component
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
protected $listeners = ['openModal'];
|
||||||
|
|
||||||
|
public $room;
|
||||||
|
public bool $showModal = false;
|
||||||
|
|
||||||
|
public function openModal($roomId)
|
||||||
|
{
|
||||||
|
$this->room = Room::find($roomId);
|
||||||
|
$this->showModal = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function render()
|
||||||
|
{
|
||||||
|
return view('livewire.admin.room-detail-modal');
|
||||||
|
}
|
||||||
|
}
|
35
app/Livewire/Admin/RoomGrid.php
Normal file
35
app/Livewire/Admin/RoomGrid.php
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Livewire\Admin;
|
||||||
|
|
||||||
|
use App\Models\Room;
|
||||||
|
use App\Models\Branch;
|
||||||
|
|
||||||
|
use Livewire\Component;
|
||||||
|
use Illuminate\Database\Eloquent\Collection;
|
||||||
|
|
||||||
|
|
||||||
|
class RoomGrid extends Component
|
||||||
|
{
|
||||||
|
protected $listeners = ['openModal','closeModal'];//,'refreshRooms' => '$refresh'
|
||||||
|
|
||||||
|
public bool $showModal = false;
|
||||||
|
public $branchName="";
|
||||||
|
public Collection $rooms;
|
||||||
|
|
||||||
|
public function mount()
|
||||||
|
{
|
||||||
|
$this->rooms = new Collection();
|
||||||
|
}
|
||||||
|
public function openModal($branch_id = null)
|
||||||
|
{
|
||||||
|
$this->branchName=Branch::where('id',$branch_id)->first()->name;
|
||||||
|
$this->rooms = Room::where('branch_id',$branch_id)->get();
|
||||||
|
$this->showModal = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function render()
|
||||||
|
{
|
||||||
|
return view('livewire.admin.room-grid');
|
||||||
|
}
|
||||||
|
}
|
@ -37,7 +37,7 @@ class Artist extends Model
|
|||||||
protected static function booted()
|
protected static function booted()
|
||||||
{
|
{
|
||||||
// 無論是 creating 或 updating,都執行這段共用的邏輯
|
// 無論是 creating 或 updating,都執行這段共用的邏輯
|
||||||
static::saving(function ($artist) {
|
static::saving(function (Artist $artist) {
|
||||||
$simplified=ChineseNameConverter::convertToSimplified($artist->name);// 繁體轉簡體
|
$simplified=ChineseNameConverter::convertToSimplified($artist->name);// 繁體轉簡體
|
||||||
$artist->simplified = $simplified;
|
$artist->simplified = $simplified;
|
||||||
$artist->phonetic_abbr = ChineseNameConverter::getKTVZhuyinAbbr($simplified);// 注音符號
|
$artist->phonetic_abbr = ChineseNameConverter::getKTVZhuyinAbbr($simplified);// 注音符號
|
||||||
@ -47,6 +47,11 @@ class Artist extends Model
|
|||||||
$firstChar = $chars[0] ?? null;
|
$firstChar = $chars[0] ?? null;
|
||||||
$artist->strokes_abbr=( $firstChar && preg_match('/\p{Han}/u', $firstChar) ) ? ChineseStrokesConverter::getStrokes($firstChar) : 0;
|
$artist->strokes_abbr=( $firstChar && preg_match('/\p{Han}/u', $firstChar) ) ? ChineseStrokesConverter::getStrokes($firstChar) : 0;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
static::deleting(function (Artist $artist) {
|
||||||
|
// 解除與歌曲的多對多關聯
|
||||||
|
$artist->songs()->detach();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -25,4 +25,10 @@ class Branch extends Model
|
|||||||
->withPivot('counts')
|
->withPivot('counts')
|
||||||
->withTimestamps();
|
->withTimestamps();
|
||||||
}
|
}
|
||||||
|
protected static function booted()
|
||||||
|
{
|
||||||
|
static::deleting(function (Branch $branch) {
|
||||||
|
$branch->rooms()->delete();
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,11 +11,41 @@ class Room extends Model
|
|||||||
/** @use HasFactory<\Database\Factories\ArtistFactory> */
|
/** @use HasFactory<\Database\Factories\ArtistFactory> */
|
||||||
use HasFactory, LogsModelActivity;
|
use HasFactory, LogsModelActivity;
|
||||||
|
|
||||||
|
protected $fillable = [
|
||||||
|
'name',
|
||||||
|
'internal_ip',
|
||||||
|
'port',
|
||||||
|
'status',
|
||||||
|
'started_at',
|
||||||
|
'ended_at',
|
||||||
|
];
|
||||||
|
|
||||||
protected $casts = [
|
protected $casts = [
|
||||||
|
'name' => 'string',
|
||||||
|
'internal_ip' =>'string',
|
||||||
|
'port' => 'int',
|
||||||
|
'status' => \App\Enums\RoomStatus::class,
|
||||||
'started_at' => 'datetime',
|
'started_at' => 'datetime',
|
||||||
'ended_at' => 'datetime',
|
'ended_at' => 'datetime',
|
||||||
|
|
||||||
];
|
];
|
||||||
|
|
||||||
|
public function str_started_at(){
|
||||||
|
$str ="Not Set";
|
||||||
|
if($this->started_at !=null){
|
||||||
|
$str = $this->started_at;
|
||||||
|
}
|
||||||
|
return $str;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function str_ended_at(){
|
||||||
|
$str ="Not Set";
|
||||||
|
if($this->ended_at !=null){
|
||||||
|
$str = $this->ended_at;
|
||||||
|
}
|
||||||
|
return $str;
|
||||||
|
}
|
||||||
|
|
||||||
public function branch() {
|
public function branch() {
|
||||||
return $this->belongsTo(Branch::class);
|
return $this->belongsTo(Branch::class);
|
||||||
}
|
}
|
||||||
|
@ -71,7 +71,7 @@ class Song extends Model
|
|||||||
protected static function booted()
|
protected static function booted()
|
||||||
{
|
{
|
||||||
// 無論是 creating 或 updating,都執行這段共用的邏輯
|
// 無論是 creating 或 updating,都執行這段共用的邏輯
|
||||||
static::saving(function ($song) {
|
static::saving(function (Song $song) {
|
||||||
$simplified=ChineseNameConverter::convertToSimplified($song->name);// 繁體轉簡體
|
$simplified=ChineseNameConverter::convertToSimplified($song->name);// 繁體轉簡體
|
||||||
$song->simplified = $simplified;
|
$song->simplified = $simplified;
|
||||||
$song->phonetic_abbr = ChineseNameConverter::getKTVZhuyinAbbr($simplified);// 注音符號
|
$song->phonetic_abbr = ChineseNameConverter::getKTVZhuyinAbbr($simplified);// 注音符號
|
||||||
@ -83,5 +83,12 @@ class Song extends Model
|
|||||||
$song->strokes_abbr=($firstChar && preg_match('/\p{Han}/u', $firstChar)) ? ChineseStrokesConverter::getStrokes($firstChar) : 0;
|
$song->strokes_abbr=($firstChar && preg_match('/\p{Han}/u', $firstChar)) ? ChineseStrokesConverter::getStrokes($firstChar) : 0;
|
||||||
$song->song_number = mb_strlen($song->name, 'UTF-8');
|
$song->song_number = mb_strlen($song->name, 'UTF-8');
|
||||||
});
|
});
|
||||||
|
static::deleting(function (Song $song) {
|
||||||
|
// Detach 關聯資料
|
||||||
|
$song->artists()->detach();
|
||||||
|
$song->categories()->detach();
|
||||||
|
$song->branches()->detach();
|
||||||
|
$song->users()->detach();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,10 +15,10 @@ return new class extends Migration
|
|||||||
$table->id();
|
$table->id();
|
||||||
$table->foreignId('branch_id')->constrained()->onDelete('cascade')->comment('關聯分店');
|
$table->foreignId('branch_id')->constrained()->onDelete('cascade')->comment('關聯分店');
|
||||||
$table->string('name')->comment('包廂名稱');
|
$table->string('name')->comment('包廂名稱');
|
||||||
$table->string('internal_ip')->comment('內部 IP');
|
$table->string('internal_ip')->nullable()->comment('內部 IP');
|
||||||
$table->unsignedSmallInteger('port')->comment('通訊 Port');
|
$table->unsignedSmallInteger('port')->nullable()->comment('通訊 Port');
|
||||||
$table->enum('status', ['active', 'closed', 'error', 'maintenance'])->comment('狀態'); // :啟用中 / 已結束
|
$table->enum('status', ['active', 'closed', 'error', 'maintenance'])->default('error')->comment('狀態'); // :啟用中 / 已結束
|
||||||
$table->dateTime('started_at')->comment('開始時間'); //
|
$table->dateTime('started_at')->nullable()->comment('開始時間'); //
|
||||||
$table->dateTime('ended_at')->nullable()->comment('結束時間'); //
|
$table->dateTime('ended_at')->nullable()->comment('結束時間'); //
|
||||||
$table->timestamps();
|
$table->timestamps();
|
||||||
});
|
});
|
||||||
|
@ -23,4 +23,9 @@ return [
|
|||||||
'user.status.Active' => '正常',
|
'user.status.Active' => '正常',
|
||||||
'user.status.Suspended' => '停權',
|
'user.status.Suspended' => '停權',
|
||||||
'user.status.Deleting' => '刪除中',
|
'user.status.Deleting' => '刪除中',
|
||||||
|
|
||||||
|
'room.status.Active' => '已占用',
|
||||||
|
'room.status.Closed' => '可用',
|
||||||
|
'room.status.Error' => '異常',
|
||||||
|
'room.status.Maintenance' => '維修',
|
||||||
];
|
];
|
20
resources/views/components/room-card.blade.php
Normal file
20
resources/views/components/room-card.blade.php
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
@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"
|
||||||
|
wire:click="$dispatchTo('admin.room-detail-modal','openModal', { roomId: {{ $room->id }} })">
|
||||||
|
<div class="font-bold">{{ $room->name }}</div>
|
||||||
|
<div class="text-sm text-{{ $statusColors[$room->status->value] ?? 'gray-500' }} text-center">
|
||||||
|
{{ $room->status->labels() }}
|
||||||
|
</div>
|
||||||
|
<div class="text-xs text-center whitespace-nowrap ">{{ $room->str_started_at() }}</div>
|
||||||
|
<div class="text-xs text-center whitespace-nowrap ">{{ $room->str_ended_at() }}</div>
|
||||||
|
|
||||||
|
</div>
|
@ -4,7 +4,9 @@
|
|||||||
<x-wireui:input label="{{__('branches.external_ip')}}" wire:model.defer="fields.external_ip" />
|
<x-wireui:input label="{{__('branches.external_ip')}}" wire:model.defer="fields.external_ip" />
|
||||||
<x-wireui:toggle label="{{__('branches.enable')}}" wire:model.defer="fields.enable" />
|
<x-wireui:toggle label="{{__('branches.enable')}}" wire:model.defer="fields.enable" />
|
||||||
</div>
|
</div>
|
||||||
|
@unless($branchId)
|
||||||
|
<x-wireui:textarea label="包廂資料" placeholder="請寫下包廂...範利<br>1樓;pc101,pc102,pc103" wire:model.defer="fields.roomNotes"/>
|
||||||
|
@endunless
|
||||||
<x-slot name="footer">
|
<x-slot name="footer">
|
||||||
<div class="flex justify-between w-full">
|
<div class="flex justify-between w-full">
|
||||||
<x-wireui:button flat label="{{__('branches.cancel')}}" wire:click="closeModal" />
|
<x-wireui:button flat label="{{__('branches.cancel')}}" wire:click="closeModal" />
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
<x-layouts.admin>
|
<x-layouts.admin>
|
||||||
<x-wireui:notifications/>
|
<x-wireui:notifications/>
|
||||||
<livewire:admin.branch-table />
|
<livewire:admin.branch-table />
|
||||||
|
<livewire:admin.room-grid />
|
||||||
<livewire:admin.branch-form />
|
<livewire:admin.branch-form />
|
||||||
<livewire:admin.branch-import-data />
|
<livewire:admin.branch-import-data />
|
||||||
</x-layouts.admin>
|
</x-layouts.admin>
|
29
resources/views/livewire/admin/room-detail-modal.blade.php
Normal file
29
resources/views/livewire/admin/room-detail-modal.blade.php
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
<x-wireui:modal id="room-detail-modal" wire:model.defer="showModal" persistent>
|
||||||
|
<x-wireui:card class="border border-gray-200">
|
||||||
|
<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"
|
||||||
|
x-on:click="close"
|
||||||
|
tabindex="-1"
|
||||||
|
>
|
||||||
|
<x-dynamic-component
|
||||||
|
:component="WireUi::component('icon')"
|
||||||
|
name="x-mark"
|
||||||
|
class="w-5 h-5"
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
|
</x-slot>
|
||||||
|
<x-slot name="title">
|
||||||
|
{{ $room->name ?? '未選擇' }}包廂設定
|
||||||
|
</x-slot>
|
||||||
|
<div class="grid grid-cols-3 gap-4 mb-4">
|
||||||
|
<x-wireui:button wire:click="startMachine" >開機</x-wireui:button>
|
||||||
|
<x-wireui:button wire:click="stopMachine" >關機</x-wireui:button>
|
||||||
|
<x-wireui:button wire:click="closeModal" >取消</x-wireui:button>
|
||||||
|
</div>
|
||||||
|
<div class="grid grid-cols-2 gap-4 mb-4">
|
||||||
|
<x-wireui:button wire:click="openAccount" >包廂開帳</x-wireui:button>
|
||||||
|
<x-wireui:button wire:click="closeAccount" >包廂關帳</x-wireui:button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</x-wireui:card>
|
||||||
|
</x-wireui:modal>
|
22
resources/views/livewire/admin/room-grid.blade.php
Normal file
22
resources/views/livewire/admin/room-grid.blade.php
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
<x-wireui:modal id="room-grid-modal" wire:model.defer="showModal" persistent >
|
||||||
|
<x-wireui:card class="border border-gray-200 w-full">
|
||||||
|
<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"
|
||||||
|
x-on:click="close"
|
||||||
|
tabindex="-1"
|
||||||
|
>
|
||||||
|
<x-dynamic-component :component="WireUi::component('icon')" name="x-mark" class="w-5 h-5"/>
|
||||||
|
</button>
|
||||||
|
</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">
|
||||||
|
@forelse($rooms as $room)
|
||||||
|
<x-room-card :room="$room" />
|
||||||
|
@empty
|
||||||
|
<div class="col-span-full text-center text-gray-500">尚無包廂資料</div>
|
||||||
|
@endforelse
|
||||||
|
</div>
|
||||||
|
<livewire:admin.room-detail-modal />
|
||||||
|
</x-wireui:card>
|
||||||
|
</x-wireui:modal>
|
Loading…
x
Reference in New Issue
Block a user