diff --git a/app/Http/Controllers/Admin/AdvertisementController.php b/app/Http/Controllers/Admin/AdvertisementController.php index 9dbf9bf..295bee8 100644 --- a/app/Http/Controllers/Admin/AdvertisementController.php +++ b/app/Http/Controllers/Admin/AdvertisementController.php @@ -21,7 +21,9 @@ class AdvertisementController extends AdminController // Tab 1: 廣告列表 $advertisements = Advertisement::with('company')->latest()->paginate(10); - $allAds = Advertisement::active()->get(); + + // Tab 2: 機台廣告設置 (所需資料) - 隱藏已過期的廣告 + $allAds = Advertisement::playing()->get(); // Tab 2: 機台廣告設置 (所需資料) // 取得使用者有權限的機台列表 (已透過 Global Scope 過濾) @@ -54,6 +56,8 @@ class AdvertisementController extends AdminController $request->type === 'image' ? 'max:10240' : 'max:51200', // Image 10MB, Video 50MB ], 'company_id' => 'nullable|exists:companies,id', + 'start_at' => 'nullable|date', + 'end_at' => 'nullable|date|after_or_equal:start_at', ]); $user = auth()->user(); @@ -71,13 +75,15 @@ class AdvertisementController extends AdminController $companyId = $user->company_id; } - Advertisement::create([ + $advertisement = Advertisement::create([ 'company_id' => $companyId, 'name' => $request->name, 'type' => $request->type, 'duration' => (int) $request->duration, 'url' => Storage::disk('public')->url($path), 'is_active' => true, + 'start_at' => $request->start_at, + 'end_at' => $request->end_at, ]); if ($request->wantsJson()) { @@ -99,6 +105,8 @@ class AdvertisementController extends AdminController 'duration' => 'required|in:15,30,60', 'is_active' => 'boolean', 'company_id' => 'nullable|exists:companies,id', + 'start_at' => 'nullable|date', + 'end_at' => 'nullable|date|after_or_equal:start_at', ]; if ($request->hasFile('file')) { @@ -111,7 +119,7 @@ class AdvertisementController extends AdminController $request->validate($rules); - $data = $request->only(['name', 'type', 'duration']); + $data = $request->only(['name', 'type', 'duration', 'start_at', 'end_at']); $data['is_active'] = $request->has('is_active'); $user = auth()->user(); @@ -150,7 +158,7 @@ class AdvertisementController extends AdminController return redirect()->back()->with('success', __('Advertisement updated successfully.')); } - public function destroy(Advertisement $advertisement) + public function destroy(Request $request, Advertisement $advertisement) { // 檢查是否有機台正投放中 if ($advertisement->machineAdvertisements()->exists()) { diff --git a/app/Http/Controllers/Api/V1/App/MachineController.php b/app/Http/Controllers/Api/V1/App/MachineController.php index dabac4e..6b20d0f 100644 --- a/app/Http/Controllers/Api/V1/App/MachineController.php +++ b/app/Http/Controllers/Api/V1/App/MachineController.php @@ -273,7 +273,7 @@ class MachineController extends Controller $advertisements = \App\Models\Machine\MachineAdvertisement::where('machine_id', $machine->id) ->with([ 'advertisement' => function ($query) { - $query->active(); + $query->playing(); } ]) ->get() diff --git a/app/Models/System/Advertisement.php b/app/Models/System/Advertisement.php index b887c96..8021ccd 100644 --- a/app/Models/System/Advertisement.php +++ b/app/Models/System/Advertisement.php @@ -18,11 +18,15 @@ class Advertisement extends Model 'duration', 'url', 'is_active', + 'start_at', + 'end_at', ]; protected $casts = [ 'duration' => 'integer', 'is_active' => 'boolean', + 'start_at' => 'datetime', + 'end_at' => 'datetime', ]; /** @@ -48,4 +52,21 @@ class Advertisement extends Model { return $query->where('is_active', true); } + + /** + * Scope a query to only include advertisements that should be playing now. + */ + public function scopePlaying($query) + { + $now = now(); + return $query->where('is_active', true) + ->where(function ($q) use ($now) { + $q->whereNull('start_at') + ->orWhere('start_at', '<=', $now); + }) + ->where(function ($q) use ($now) { + $q->whereNull('end_at') + ->orWhere('end_at', '>=', $now); + }); + } } diff --git a/database/migrations/2026_04_13_110941_add_scheduling_fields_to_advertisements_table.php b/database/migrations/2026_04_13_110941_add_scheduling_fields_to_advertisements_table.php new file mode 100644 index 0000000..0290820 --- /dev/null +++ b/database/migrations/2026_04_13_110941_add_scheduling_fields_to_advertisements_table.php @@ -0,0 +1,29 @@ +dateTime('start_at')->nullable()->after('url')->comment('發布時間'); + $table->dateTime('end_at')->nullable()->after('start_at')->comment('下架時間'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('advertisements', function (Blueprint $table) { + $table->dropColumn(['start_at', 'end_at']); + }); + } +}; diff --git a/lang/en.json b/lang/en.json index a8bdf4c..5df7d7d 100644 --- a/lang/en.json +++ b/lang/en.json @@ -1145,5 +1145,12 @@ "Service Terms": "Service Periods", "Contract": "Contract", "Warranty": "Warranty", - "Software": "Software" + "Software": "Software", + "Schedule": "Schedule", + "Immediate": "Immediate", + "Indefinite": "Indefinite", + "Ongoing": "Ongoing", + "Waiting": "Waiting", + "Publish Time": "Publish Time", + "Expired Time": "Expired Time" } \ No newline at end of file diff --git a/lang/ja.json b/lang/ja.json index 5a97e8b..ed9855d 100644 --- a/lang/ja.json +++ b/lang/ja.json @@ -1144,5 +1144,12 @@ "Service Terms": "サービス期間", "Contract": "契約", "Warranty": "保証", - "Software": "ソフトウェア" + "Software": "ソフトウェア", + "Schedule": "スケジュール設定", + "Immediate": "即時", + "Indefinite": "無期限", + "Ongoing": "進行中", + "Waiting": "待機中", + "Publish Time": "公開時間", + "Expired Time": "終了時間" } \ No newline at end of file diff --git a/lang/zh_TW.json b/lang/zh_TW.json index c9dbe6e..29109df 100644 --- a/lang/zh_TW.json +++ b/lang/zh_TW.json @@ -1145,5 +1145,12 @@ "Service Terms": "服務期程", "Contract": "合約", "Warranty": "保固", - "Software": "軟體" + "Software": "軟體", + "Schedule": "排程區間", + "Immediate": "立即", + "Indefinite": "無限期", + "Ongoing": "進行中", + "Waiting": "等待中", + "Publish Time": "發布時間", + "Expired Time": "下架時間" } \ No newline at end of file diff --git a/resources/views/admin/ads/index.blade.php b/resources/views/admin/ads/index.blade.php index 7ba8127..a0ca20f 100644 --- a/resources/views/admin/ads/index.blade.php +++ b/resources/views/admin/ads/index.blade.php @@ -71,6 +71,7 @@ $baseRoute = 'admin.data-config.advertisements'; @endif