',
+ [
+ 'options' => TextAdColors::options(),
+ 'modelId' => intval($model->id),
+ 'fieldName'=>'color',
+ 'selected' => $model->color->value
+ ]
+ );
+ }
+ // 沒有權限就顯示對應的文字
+
+ return $model->color->labelPowergridFilter(); // 假設 label() 會回傳顯示文字
+ } )
+ ->add('is_active')
+ ->add('created_at');
+ }
+
+ public function columns(): array
+ {
+ $column=[];
+ $column[] = Column::make(__('broadcast-templates.id'), 'id');
+ $column[] = Column::make(__('broadcast-templates.content'), 'content_short', 'broadcast-templates.content')->sortable()->searchable();
+ $column[] = Column::make(__('broadcast-templates.color'),'color_str', 'text-ads.color')->searchable();
+ $column[] = Column::make(__('broadcast-templates.is_active'), 'is_active')->toggleable(hasPermission: $this->canEdit, trueLabel: 'yes', falseLabel: 'no');
+ $column[] = Column::make(__('broadcast-templates.created_at'), 'created_at')->sortable()->searchable();
+ $column[] = Column::action(__('broadcast-templates.actions'));
+ return $column;
+ }
+
+ public function filters(): array
+ {
+ return [
+ ];
+ }
+ #[On('bulkDelete.{tableName}')]
+ public function bulkDelete(): void
+ {
+ $this->js('alert(window.pgBulkActions.get(\'' . $this->tableName . '\'))');
+ if($this->checkboxValues){
+ foreach ($this->checkboxValues as $id) {
+ $template = BroadcastTemplate::find($id);
+ if ($template) {
+ $template->delete();
+ }
+ }
+ $this->js('window.pgBulkActions.clearAll()'); // clear the count on the interface.
+ }
+ }
+ #[On('selectChanged')]
+ public function selectChanged($value,$fieldName, $modelId): void
+ {
+ //dd($value,$fieldName, $modelId);
+ if (in_array($fieldName, ['color'])) {
+ $this->noUpdated($modelId,$fieldName,$value);
+ }
+ }
+ #[On('onUpdatedEditable')]
+ public function onUpdatedEditable($id, $field, $value): void
+ {
+ if (in_array($field,[
+ ''
+ ]) && $this->canEdit) {
+ $this->noUpdated($id,$field,$value);
+ }
+ }
+ #[On('onUpdatedToggleable')]
+ public function onUpdatedToggleable($id, $field, $value): void
+ {
+ if (in_array($field,['is_active']) && $this->canEdit) {
+ $this->noUpdated($id,$field,$value);
+ }
+ }
+ private function noUpdated($id,$field,$value){
+ $template = BroadcastTemplate::find($id);
+ if ($template) {
+ $template->{$field} = $value;
+ $template->save(); // 明確觸發 saving
+ }
+ $this->notification()->send([
+ 'icon' => 'success',
+ 'title' => $id.'.'.__('broadcast.'.$field).':'.$value,
+ 'description' => '已經寫入',
+ ]);
+ }
+
+ public function actions(BroadcastTemplate $row): array
+ {
+ $actions = [];
+ if ($this->canEdit) {
+ $actions[]=Button::add('edit')
+ ->slot(__('broadcast-templates.edit'))
+ ->icon('solid-pencil-square')
+ ->class('inline-flex items-center gap-1 px-3 py-1 rounded ')
+ ->dispatchTo('forms.broadcast-template-form', 'openModal', ['id' => $row->id]);
+ }
+ if($this->canDelect){
+ $actions[]=Button::add('delete')
+ ->slot(__('broadcast-templates.delete'))
+ ->icon('solid-trash')
+ ->class('inline-flex items-center gap-1 px-3 py-1 rounded ')
+ ->dispatchTo('forms.broadcast-template-form', 'deleteBroadcast', ['id' => $row->id]);
+ }
+ return $actions;
+ }
+
+ /*
+ public function actionRules($row): array
+ {
+ return [
+ // Hide button edit for ID 1
+ Rule::button('edit')
+ ->when(fn($row) => $row->id === 1)
+ ->hide(),
+ ];
+ }
+ */
+}
diff --git a/app/Models/BroadcastTemplate.php b/app/Models/BroadcastTemplate.php
new file mode 100644
index 0000000..a53b78f
--- /dev/null
+++ b/app/Models/BroadcastTemplate.php
@@ -0,0 +1,18 @@
+ \App\Enums\TextAdColors::class,
+ 'is_active' => 'boolean',
+ ];
+}
diff --git a/app/Models/TextBroadcast.php b/app/Models/TextBroadcast.php
new file mode 100644
index 0000000..94da1fe
--- /dev/null
+++ b/app/Models/TextBroadcast.php
@@ -0,0 +1,20 @@
+belongsToMany(Room::class, 'text_broadcast_room');
+ }
+
+ public function template()
+ {
+ return $this->belongsTo(BroadcastTemplate::class);
+ }
+}
diff --git a/database/migrations/2025_06_26_114551_create_text_ads_table.php b/database/migrations/2025_06_26_114551_create_text_ads_table.php
index 777d8a0..7d17046 100644
--- a/database/migrations/2025_06_26_114551_create_text_ads_table.php
+++ b/database/migrations/2025_06_26_114551_create_text_ads_table.php
@@ -14,7 +14,7 @@ return new class extends Migration
Schema::create('text_ads', function (Blueprint $table) {
$table->id();
$table->string('content')->comment('廣告內容');
- $table->enum('color', ['black','white', 'red', 'green','blue'])->default('black')->comment('顯示顏色');
+ $table->enum('color', ['white', 'red', 'green','blue'])->default('white')->comment('顯示顏色');
$table->integer('duration')->default(1)->comment('播放間隔時間(分鐘)');
$table->boolean('is_active')->default(true); // 啟用狀態
$table->timestamps();
diff --git a/database/migrations/2025_08_03_162846_create_broadcast_table.php b/database/migrations/2025_08_03_162846_create_broadcast_table.php
new file mode 100644
index 0000000..8174571
--- /dev/null
+++ b/database/migrations/2025_08_03_162846_create_broadcast_table.php
@@ -0,0 +1,44 @@
+id();
+ $table->text('content')->comment('公告內容'); // e.g., "親愛的 **name**,歡迎光臨!"
+ $table->enum('color', ['white', 'red', 'green','blue'])->default('white')->comment('顯示顏色');
+ $table->boolean('is_active')->default(true); // 啟用狀態
+ $table->timestamps();
+ });
+ Schema::create('text_broadcasts', function (Blueprint $table) {
+ $table->id();
+ $table->foreignId('template_id')->nullable()->constrained('broadcast_templates')->nullOnDelete();
+ $table->text('content'); // Final content with variables replaced
+ $table->enum('target_type', ['all', 'rooms'])->default('all');
+ $table->timestamps();
+ });
+ Schema::create('text_broadcast_room', function (Blueprint $table) {
+ $table->id();
+ $table->foreignId('text_broadcast_id')->constrained()->onDelete('cascade');
+ $table->foreignId('room_id')->constrained()->onDelete('cascade');
+ });
+ }
+
+ /**
+ * Reverse the migrations.
+ */
+ public function down(): void
+ {
+ Schema::dropIfExists('text_broadcast_room');
+ Schema::dropIfExists('text_broadcasts');
+ Schema::dropIfExists('broadcast_templates');
+ }
+};
diff --git a/database/seeders/BroadcastTemplateSeeder.php b/database/seeders/BroadcastTemplateSeeder.php
new file mode 100644
index 0000000..691456a
--- /dev/null
+++ b/database/seeders/BroadcastTemplateSeeder.php
@@ -0,0 +1,58 @@
+ '親愛的 **name**,祝你生日快樂!',
+ 'color' => TextAdColors::White,
+ ],
+ [
+ 'content' => '**room_name** 歡迎您蒞臨本店,祝您有美好的一天!',
+ 'color' => TextAdColors::White,
+ ],
+ [
+ 'content' => '**name** 拾獲您的證件,請至櫃台領取',
+ 'color' => TextAdColors::White,
+ ],
+ [
+ 'content' => '**name** 請移動你的愛車,謝謝!!',
+ 'color' => TextAdColors::White,
+ ],
+ [
+ 'content' => '**name** 祝你生日快樂!!',
+ 'color' => TextAdColors::White,
+ ],
+ [
+ 'content' => '**name** 櫃台有您訪客!!',
+ 'color' => TextAdColors::White,
+ ],
+ [
+ 'content' => '**room_name** 警察臨檢不便之處敬請原諒!!',
+ 'color' => TextAdColors::White,
+ ],
+ [
+ 'content' => '**name** 您的愛車被拖吊了!!',
+ 'color' => TextAdColors::White,
+ ],
+ [
+ 'content' => '**name** 請移動您的愛車,謝謝',
+ 'color' => TextAdColors::White,
+ ],
+ ];
+ foreach ($txs as $tx) {
+ BroadcastTemplate::create([
+ 'content' => $tx['content'],
+ 'color' => $tx['color'],
+ 'is_active' => true,
+ ]);
+ }
+ }
+}
diff --git a/database/seeders/DatabaseSeeder.php b/database/seeders/DatabaseSeeder.php
index 10aa327..642bfb1 100644
--- a/database/seeders/DatabaseSeeder.php
+++ b/database/seeders/DatabaseSeeder.php
@@ -14,11 +14,7 @@ class DatabaseSeeder extends Seeder
{
(new TransferSqliteTableJob('database/User.data', false))->handle();
$this->call([
- // TextAdPermissionSeeder::class,
- // TextAdSeeder::class,
- // PermissionTableSeeder::class,
- // CreateAdminUserSeeder::class,
- // FavoriteSongsSeeder::class,
+ BroadcastTemplateSeeder::class,
]);
}
}
diff --git a/resources/lang/zh-tw/broadcast-templates.php b/resources/lang/zh-tw/broadcast-templates.php
new file mode 100644
index 0000000..c7d2d68
--- /dev/null
+++ b/resources/lang/zh-tw/broadcast-templates.php
@@ -0,0 +1,27 @@
+ '文字公告管理',
+ 'list' => '文字公告列表',
+ 'CreateNew' => '新增文字公告',
+ 'EditArtist' => '編輯文字公告',
+ 'ImportData' => '滙入文字公告',
+ 'create_edit' => '新增 / 編輯',
+ 'create' => '新增',
+ 'edit' => '編輯',
+ 'delete' => '刪除',
+ 'id' => '編號',
+ 'name' => '主題',
+ 'content' => '內容',
+ 'description' => '描述',
+ 'color' => '顏色',
+ 'duration' => '播放間隔時間(分鐘)',
+ 'is_active' => '是否推播',
+ 'created_at' =>'建立於',
+
+
+ 'actions' => '操作',
+ 'view' => '查看',
+ 'submit' => '提交',
+ 'cancel' => '取消',
+];
\ No newline at end of file
diff --git a/resources/views/components/select-dropdown.blade.php b/resources/views/components/select-dropdown.blade.php
new file mode 100644
index 0000000..4580191
--- /dev/null
+++ b/resources/views/components/select-dropdown.blade.php
@@ -0,0 +1,16 @@
+@props(['options', 'modelId' , 'fieldName', 'selected' ])
+
+
+
\ No newline at end of file
diff --git a/resources/views/livewire/admin/broadcast-templates.blade.php b/resources/views/livewire/admin/broadcast-templates.blade.php
new file mode 100644
index 0000000..b4151ad
--- /dev/null
+++ b/resources/views/livewire/admin/broadcast-templates.blade.php
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/resources/views/livewire/forms/broadcast-template-form.blade.php b/resources/views/livewire/forms/broadcast-template-form.blade.php
new file mode 100644
index 0000000..3ffb545
--- /dev/null
+++ b/resources/views/livewire/forms/broadcast-template-form.blade.php
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/resources/views/livewire/headers/broadcast-template.blade.php b/resources/views/livewire/headers/broadcast-template.blade.php
new file mode 100644
index 0000000..a22d6cf
--- /dev/null
+++ b/resources/views/livewire/headers/broadcast-template.blade.php
@@ -0,0 +1,10 @@
+
+ @if ($canCreate)
+
+ @endif
+
\ No newline at end of file
diff --git a/resources/views/livewire/layout/admin/sidebar.blade.php b/resources/views/livewire/layout/admin/sidebar.blade.php
index f9be3c9..f117289 100644
--- a/resources/views/livewire/layout/admin/sidebar.blade.php
+++ b/resources/views/livewire/layout/admin/sidebar.blade.php
@@ -15,6 +15,7 @@ new class extends Component
['label' => 'Room', 'route' => 'admin.rooms', 'icon' => 'building-library', 'permission' => 'room-list'],
['label' => 'RoomGrid', 'route' => 'admin.room-grids', 'icon' => 'film', 'permission' => 'room-list'],
['label' => 'TextAd', 'route' => 'admin.text-ads', 'icon' => 'megaphone', 'permission' => 'text-ad-list'],
+ ['label' => 'BroadcastTemplate', 'route' => 'admin.broadcast-templates', 'icon' => 'megaphone', 'permission' => 'broadcast-list'],
];
/**
diff --git a/routes/web.php b/routes/web.php
index 3464fa7..e7fbfb0 100644
--- a/routes/web.php
+++ b/routes/web.php
@@ -27,4 +27,5 @@ Route::middleware(['auth'])->prefix('admin')->name('admin.')->group(function ()
Route::get('/rooms', function () {return view('livewire.admin.rooms');})->name('rooms');
Route::get('/room-grids', function () {return view('livewire.admin.room-grids');})->name('room-grids');
Route::get('/text-ads', function () {return view('livewire.admin.text-ads');})->name('text-ads');
+ Route::get('/broadcast-templates', function () {return view('livewire.admin.broadcast-templates');})->name('broadcast-templates');
});
\ No newline at end of file