diff --git a/app/Enums/RoomStatus.php b/app/Enums/RoomStatus.php new file mode 100644 index 0000000..b9cd372 --- /dev/null +++ b/app/Enums/RoomStatus.php @@ -0,0 +1,25 @@ + __('enums.room.status.Active'), + self::Closed => __('enums.room.status.Closed'), + self::Error => __('enums.room.status.Error'), + self::Maintenance => __('enums.room.status.Maintenance'), + }; + } +} diff --git a/app/Models/.DS_Store b/app/Models/.DS_Store new file mode 100644 index 0000000..5008ddf Binary files /dev/null and b/app/Models/.DS_Store differ diff --git a/app/Models/Branch.php b/app/Models/Branch.php new file mode 100644 index 0000000..48de8f2 --- /dev/null +++ b/app/Models/Branch.php @@ -0,0 +1,26 @@ + */ + use HasFactory; + + protected $fillable = [ + 'name', + 'external_ip', + ]; + + public function rooms() { + return $this->hasMany(Room::class); + } + public function songs(){ + return $this->belongsToMany(Song::class) + ->withPivot('counts') + ->withTimestamps(); + } +} diff --git a/app/Models/Room.php b/app/Models/Room.php new file mode 100644 index 0000000..ad8c5df --- /dev/null +++ b/app/Models/Room.php @@ -0,0 +1,25 @@ + */ + use HasFactory; + + protected $casts = [ + 'started_at' => 'datetime', + 'ended_at' => 'datetime', + ]; + + public function branch() { + return $this->belongsTo(Branch::class); + } + + public function statusLogs() { + return $this->hasMany(RoomStatusLog::class); + } +} diff --git a/app/Models/RoomStatusLog.php b/app/Models/RoomStatusLog.php new file mode 100644 index 0000000..d36c84a --- /dev/null +++ b/app/Models/RoomStatusLog.php @@ -0,0 +1,31 @@ + */ + use HasFactory; + + public $timestamps = false; + + protected $fillable = + [ + 'room_id', + 'user_id', + 'status', + 'message', + 'logged_at' + ]; + + protected $casts = [ + 'logged_at' => 'datetime', + ]; + + public function room() { + return $this->belongsTo(Room::class); + } +} diff --git a/app/Models/Song.php b/app/Models/Song.php index 043aa7d..f40efd5 100644 --- a/app/Models/Song.php +++ b/app/Models/Song.php @@ -60,7 +60,11 @@ class Song extends Model public function categories(){ return $this->belongsToMany(SongCategory::class); } - + public function branches(){ + return $this->belongsToMany(Branch::class) + ->withPivot('counts') + ->withTimestamps(); + } protected static function booted() { // 無論是 creating 或 updating,都執行這段共用的邏輯 diff --git a/app/Observers/RoomObserver.php b/app/Observers/RoomObserver.php new file mode 100644 index 0000000..01a9775 --- /dev/null +++ b/app/Observers/RoomObserver.php @@ -0,0 +1,57 @@ +wasChanged('status')) { + RoomStatusLog::create([ + 'room_id' => $room->id, + 'user_id' => Auth::id(), // 若是 console 或系統自動操作可能為 null + 'status' => $room->status, + 'message' => '狀態自動變更紀錄', + 'logged_at' => now(), + ]); + } + } + + /** + * Handle the Room "deleted" event. + */ + public function deleted(Room $room): void + { + // + } + + /** + * Handle the Room "restored" event. + */ + public function restored(Room $room): void + { + // + } + + /** + * Handle the Room "force deleted" event. + */ + public function forceDeleted(Room $room): void + { + // + } +} diff --git a/database/.DS_Store b/database/.DS_Store new file mode 100644 index 0000000..b1ea27f Binary files /dev/null and b/database/.DS_Store differ diff --git a/database/migrations/.DS_Store b/database/migrations/.DS_Store new file mode 100644 index 0000000..5008ddf Binary files /dev/null and b/database/migrations/.DS_Store differ diff --git a/database/migrations/2025_05_06_055303_create_branches_table.php b/database/migrations/2025_05_06_055303_create_branches_table.php new file mode 100644 index 0000000..19e9ebf --- /dev/null +++ b/database/migrations/2025_05_06_055303_create_branches_table.php @@ -0,0 +1,29 @@ +id(); + $table->string('name'); + $table->ipAddress('external_ip'); // 對外 IP + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('branches'); + } +}; diff --git a/database/migrations/2025_05_06_055307_create_rooms_table.php b/database/migrations/2025_05_06_055307_create_rooms_table.php new file mode 100644 index 0000000..a71a614 --- /dev/null +++ b/database/migrations/2025_05_06_055307_create_rooms_table.php @@ -0,0 +1,34 @@ +id(); + $table->foreignId('branch_id')->constrained()->onDelete('cascade'); // 關聯分店 + $table->string('name'); // 包廂名稱 + $table->string('internal_ip'); // 內部 IP + $table->unsignedSmallInteger('port'); // 通訊 Port + $table->enum('status', ['active', 'closed', 'error', 'maintenance']); // 狀態:啟用中 / 已結束 + $table->dateTime('started_at'); // 開始時間 + $table->dateTime('ended_at')->nullable(); // 結束時間 + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('rooms'); + } +}; diff --git a/database/migrations/2025_05_06_055312_create_room_status_logs_table.php b/database/migrations/2025_05_06_055312_create_room_status_logs_table.php new file mode 100644 index 0000000..8c27e98 --- /dev/null +++ b/database/migrations/2025_05_06_055312_create_room_status_logs_table.php @@ -0,0 +1,31 @@ +id(); + $table->foreignId('room_id')->constrained()->onDelete('cascade'); + $table->foreignId('user_id')->nullable()->constrained()->onDelete('set null'); // 操作者,可為 null(系統) + $table->enum('status', ['active', 'closed', 'error', 'maintenance']); + $table->text('message')->nullable(); // 可填異常原因或操作說明 + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('room_status_logs'); + } +}; diff --git a/database/migrations/2025_05_06_055313_create_branch_song_table.php b/database/migrations/2025_05_06_055313_create_branch_song_table.php new file mode 100644 index 0000000..8a57888 --- /dev/null +++ b/database/migrations/2025_05_06_055313_create_branch_song_table.php @@ -0,0 +1,33 @@ +unsignedBigInteger('song_id'); + $table->unsignedBigInteger('branch_id'); + $table->integer('counts')->default(0)->comment('點播次數'); + $table->foreign('song_id')->references('id')->on('songs')->restrictOnDelete()->restrictOnUpdate(); + $table->foreign('branch_id')->references('id')->on('branches')->restrictOnDelete()->restrictOnUpdate(); + $table->primary(['song_id', 'branch_id']); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('branch_song'); + } +};