feat: 實作後台導航選單系統與狀態持久化

- 新增 14 個模組的路由與控制器佔位符
- 實作可展開式側邊欄選單 (Sidebar Menu)
- 優化選單樣式與主題適配
- 實作選單展開狀態持久化 (LocalStorage)
- 修復子選單縮排與顏色問題
This commit is contained in:
2025-12-16 23:21:11 +08:00
parent 6edece8648
commit aa708e9ac7
16 changed files with 1088 additions and 61 deletions

View File

@@ -0,0 +1,45 @@
<?php
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
class AnalysisController extends Controller
{
// 零錢庫存分析
public function changeStock()
{
return view('admin.placeholder', [
'title' => '零錢庫存分析',
'description' => '機台零錢數量監測與分析',
]);
}
// 機台報表分析
public function machineReports()
{
return view('admin.placeholder', [
'title' => '機台報表分析',
'description' => '機台運營數據分析報表',
]);
}
// 商品報表分析
public function productReports()
{
return view('admin.placeholder', [
'title' => '商品報表分析',
'description' => '商品銷售數據分析',
]);
}
// 互動問卷分析
public function surveyAnalysis()
{
return view('admin.placeholder', [
'title' => '互動問卷分析',
'description' => '問卷結果統計與分析',
]);
}
}

View File

@@ -41,4 +41,49 @@ class AppConfigController extends Controller
return redirect()->back()->with('success', '設定已更新'); return redirect()->back()->with('success', '設定已更新');
} }
// UI元素設定
public function uiElements()
{
return view('admin.placeholder', [
'title' => 'UI元素設定',
'description' => 'APP版面配置設定',
]);
}
// 小幫手設定
public function helper()
{
return view('admin.placeholder', [
'title' => '小幫手設定',
'description' => 'APP內建輔助功能設定',
]);
}
// 問卷設定
public function questionnaire()
{
return view('admin.placeholder', [
'title' => '問卷設定',
'description' => '互動問卷建立與管理',
]);
}
// 互動遊戲設定
public function games()
{
return view('admin.placeholder', [
'title' => '互動遊戲設定',
'description' => 'APP互動遊戲配置',
]);
}
// 計時器
public function timer()
{
return view('admin.placeholder', [
'title' => '計時器',
'description' => '時間相關功能設定',
]);
}
} }

View File

@@ -0,0 +1,36 @@
<?php
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
class AuditController extends Controller
{
// 採購單稽核
public function purchases()
{
return view('admin.placeholder', [
'title' => '採購單稽核',
'description' => '採購單審核流程',
]);
}
// 調撥單稽核
public function transfers()
{
return view('admin.placeholder', [
'title' => '調撥單稽核',
'description' => '調撥單審核流程',
]);
}
// 補貨單稽核
public function replenishments()
{
return view('admin.placeholder', [
'title' => '補貨單稽核',
'description' => '補貨單審核流程',
]);
}
}

View File

@@ -0,0 +1,81 @@
<?php
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
class DataConfigController extends Controller
{
// 商品管理
public function products()
{
return view('admin.placeholder', [
'title' => '商品管理',
'description' => '商品資料維護',
]);
}
// 廣告管理
public function advertisements()
{
return view('admin.placeholder', [
'title' => '廣告管理',
'description' => '機台廣告影片管理',
]);
}
// 管理者可賣商品
public function adminProducts()
{
return view('admin.placeholder', [
'title' => '管理者可賣商品',
'description' => '管理者商品銷售權限',
]);
}
// 帳號管理
public function accounts()
{
return view('admin.placeholder', [
'title' => '帳號管理',
'description' => '主帳號管理',
]);
}
// 子帳號管理
public function subAccounts()
{
return view('admin.placeholder', [
'title' => '子帳號管理',
'description' => '子帳號建立與管理',
]);
}
// 子帳號角色管理
public function subAccountRoles()
{
return view('admin.placeholder', [
'title' => '子帳號角色管理',
'description' => '子帳號權限角色設定',
]);
}
// 點數設定
public function points()
{
return view('admin.placeholder', [
'title' => '點數設定',
'description' => '客戶點數系統設定',
]);
}
// 識別證管理
public function badges()
{
return view('admin.placeholder', [
'title' => '識別證管理',
'description' => '識別證資料管理(安霸系統使用)',
]);
}
}

View File

@@ -0,0 +1,63 @@
<?php
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
class LineController extends Controller
{
// Line會員管理
public function members()
{
return view('admin.placeholder', [
'title' => 'Line會員管理',
'description' => 'Line會員資料管理',
]);
}
// Line機台管理
public function machines()
{
return view('admin.placeholder', [
'title' => 'Line機台管理',
'description' => 'Line綁定機台管理',
]);
}
// Line商品管理
public function products()
{
return view('admin.placeholder', [
'title' => 'Line商品管理',
'description' => 'Line商城商品設定',
]);
}
// Line生活圈
public function officialAccount()
{
return view('admin.placeholder', [
'title' => 'Line生活圈',
'description' => 'Line官方帳號整合',
]);
}
// Line商城訂單
public function orders()
{
return view('admin.placeholder', [
'title' => 'Line商城訂單',
'description' => 'Line商城訂單管理',
]);
}
// Line優惠券
public function coupons()
{
return view('admin.placeholder', [
'title' => 'Line優惠券',
'description' => 'Line優惠券發放與管理',
]);
}
}

View File

@@ -89,4 +89,55 @@ class MachineController extends Controller
return redirect()->route('admin.machines.index') return redirect()->route('admin.machines.index')
->with('success', '機台已刪除'); ->with('success', '機台已刪除');
} }
// 機台日誌
public function logs()
{
return view('admin.placeholder', [
'title' => '機台日誌',
'description' => '機台操作歷史紀錄回溯',
'features' => [
'操作時間戳記',
'事件類型分類',
'操作人員記錄',
'詳細描述查詢',
]
]);
}
// 機台權限
public function permissions()
{
return view('admin.placeholder', [
'title' => '機台權限',
'description' => '機台存取權限控管',
]);
}
// 機台稼動率
public function utilization()
{
return view('admin.placeholder', [
'title' => '機台稼動率',
'description' => '機台運行效率分析',
]);
}
// 效期管理
public function expiry()
{
return view('admin.placeholder', [
'title' => '效期管理',
'description' => '商品效期與貨道出貨控制',
]);
}
// 維修管理單
public function maintenance()
{
return view('admin.placeholder', [
'title' => '維修管理單',
'description' => '機台維修工單系統',
]);
}
} }

View File

@@ -0,0 +1,117 @@
<?php
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
class PermissionController extends Controller
{
// APP功能管理
public function appFeatures()
{
return view('admin.placeholder', [
'title' => 'APP功能管理',
'description' => 'APP功能權限設定',
]);
}
// 資料設定權限
public function dataConfig()
{
return view('admin.placeholder', [
'title' => '資料設定權限',
'description' => '資料設定功能權限',
]);
}
// 銷售管理權限
public function sales()
{
return view('admin.placeholder', [
'title' => '銷售管理權限',
'description' => '銷售管理功能權限',
]);
}
// 機台管理權限
public function machines()
{
return view('admin.placeholder', [
'title' => '機台管理權限',
'description' => '機台管理功能權限',
]);
}
// 倉庫管理權限
public function warehouses()
{
return view('admin.placeholder', [
'title' => '倉庫管理權限',
'description' => '倉庫管理功能權限',
]);
}
// 分析管理權限
public function analysis()
{
return view('admin.placeholder', [
'title' => '分析管理權限',
'description' => '分析管理功能權限',
]);
}
// 稽核管理權限
public function audit()
{
return view('admin.placeholder', [
'title' => '稽核管理權限',
'description' => '稽核管理功能權限',
]);
}
// 遠端管理權限
public function remote()
{
return view('admin.placeholder', [
'title' => '遠端管理權限',
'description' => '遠端管理功能權限',
]);
}
// Line管理權限
public function line()
{
return view('admin.placeholder', [
'title' => 'Line管理權限',
'description' => 'Line管理功能權限',
]);
}
// 權限角色設定
public function roles()
{
return view('admin.placeholder', [
'title' => '權限角色設定',
'description' => '角色權限組合設定',
]);
}
// 其他功能管理
public function others()
{
return view('admin.placeholder', [
'title' => '其他功能管理',
'description' => '其他特殊功能權限',
]);
}
// AI智能預測
public function aiPrediction()
{
return view('admin.placeholder', [
'title' => 'AI智能預測',
'description' => 'AI功能權限設定',
]);
}
}

View File

@@ -0,0 +1,72 @@
<?php
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
class RemoteController extends Controller
{
// 機台庫存
public function stock()
{
return view('admin.placeholder', [
'title' => '遠端修改機台庫存',
'description' => '遠端修改機台庫存數量',
]);
}
// 機台重啟
public function restart()
{
return view('admin.placeholder', [
'title' => '遠端重啟機台',
'description' => '遠端重啟機台系統',
]);
}
// 卡機重啟
public function restartCardReader()
{
return view('admin.placeholder', [
'title' => '遠端重啟刷卡機',
'description' => '遠端重啟刷卡機設備',
]);
}
// 遠端結帳
public function checkout()
{
return view('admin.placeholder', [
'title' => '遠端結帳',
'description' => '遠端執行結帳流程',
]);
}
// 遠端鎖定頁
public function lock()
{
return view('admin.placeholder', [
'title' => '遠端鎖定頁',
'description' => '遠端鎖定機台頁面',
]);
}
// 遠端找零
public function change()
{
return view('admin.placeholder', [
'title' => '遠端找零',
'description' => '遠端執行找零功能',
]);
}
// 遠端出貨
public function dispense()
{
return view('admin.placeholder', [
'title' => '遠端出貨',
'description' => '遠端控制商品出貨',
]);
}
}

View File

@@ -0,0 +1,72 @@
<?php
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
class ReservationController extends Controller
{
// Line會員管理
public function members()
{
return view('admin.placeholder', [
'title' => '預約系統會員管理',
'description' => '預約系統會員資料管理',
]);
}
// Line店家管理
public function stores()
{
return view('admin.placeholder', [
'title' => '店家管理',
'description' => '店家資訊設定',
]);
}
// Line時段組合
public function timeSlots()
{
return view('admin.placeholder', [
'title' => '時段組合',
'description' => '預約時段設定',
]);
}
// Line場地管理
public function venues()
{
return view('admin.placeholder', [
'title' => '場地管理',
'description' => '場地資源管理',
]);
}
// Line優惠券管理
public function coupons()
{
return view('admin.placeholder', [
'title' => '優惠券管理',
'description' => '預約優惠券管理',
]);
}
// Line預約管理
public function reservations()
{
return view('admin.placeholder', [
'title' => '預約管理',
'description' => '預約單管理',
]);
}
// Line訂單管理
public function orders()
{
return view('admin.placeholder', [
'title' => '訂單管理',
'description' => '預約訂單處理',
]);
}
}

View File

@@ -0,0 +1,69 @@
<?php
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
class SalesController extends Controller
{
// 銷售&金流紀錄
public function index()
{
return view('admin.placeholder', [
'title' => '銷售&金流紀錄',
'description' => '銷售交易與金流明細查詢',
'features' => [
'銷售記錄查詢',
'金流對帳',
'發票管理',
'退款處理',
]
]);
}
// 取貨碼設定
public function pickupCodes()
{
return view('admin.placeholder', [
'title' => '取貨碼設定',
'description' => '取貨驗證碼管理',
]);
}
// 購買單
public function orders()
{
return view('admin.placeholder', [
'title' => '購買單',
'description' => '購買訂單管理',
]);
}
// 促銷時段設定
public function promotions()
{
return view('admin.placeholder', [
'title' => '促銷時段設定',
'description' => '促銷活動時間設定',
]);
}
// 通行碼設定
public function passCodes()
{
return view('admin.placeholder', [
'title' => '通行碼設定',
'description' => '特殊通行碼權限管理',
]);
}
// 來店禮設定
public function storeGifts()
{
return view('admin.placeholder', [
'title' => '來店禮設定',
'description' => '來店優惠活動設定',
]);
}
}

View File

@@ -0,0 +1,36 @@
<?php
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
class SpecialPermissionController extends Controller
{
// 庫存清空
public function clearStock()
{
return view('admin.placeholder', [
'title' => '庫存清空',
'description' => '特殊權限庫存清空功能',
]);
}
// APK版本管理
public function apkVersions()
{
return view('admin.placeholder', [
'title' => 'APK版本管理',
'description' => 'APP版本控制與更新',
]);
}
// Discord通知設定
public function discordNotifications()
{
return view('admin.placeholder', [
'title' => 'Discord通知設定',
'description' => 'Discord通知整合設定',
]);
}
}

View File

@@ -0,0 +1,139 @@
<?php
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
class WarehouseController extends Controller
{
// 倉庫列表(全部)
public function index()
{
return view('admin.placeholder', [
'title' => '倉庫列表(全部)',
'description' => '顯示所有倉庫的資訊與庫存狀態',
'features' => [
'查看所有倉庫列表',
'即時庫存數量顯示',
'倉庫狀態監控',
'快速搜尋與篩選',
]
]);
}
// 倉庫列表(個人)
public function personal()
{
return view('admin.placeholder', [
'title' => '倉庫列表(個人)',
'description' => '顯示個人負責的倉庫資訊',
'features' => [
'查看個人負責倉庫',
'個人庫存管理',
'權限範圍內的操作',
]
]);
}
// 庫存管理單
public function stockManagement()
{
return view('admin.placeholder', [
'title' => '庫存管理單',
'description' => '倉庫庫存異動管理',
'features' => [
'庫存盤點',
'庫存調整',
'異動記錄查詢',
]
]);
}
// 調撥單
public function transfers()
{
return view('admin.placeholder', [
'title' => '調撥單',
'description' => '倉庫間商品調撥作業',
'features' => [
'建立調撥單',
'調撥單審核',
'調撥歷史記錄',
]
]);
}
// 採購單
public function purchases()
{
return view('admin.placeholder', [
'title' => '採購單',
'description' => '商品採購申請與管理',
'features' => [
'建立採購申請',
'採購單追蹤',
'供應商管理',
]
]);
}
// 機台補貨單
public function replenishments()
{
return view('admin.placeholder', [
'title' => '機台補貨單',
'description' => '機台補貨工單建立與管理',
'features' => [
'建立補貨單',
'補貨排程',
'補貨人員指派',
]
]);
}
// 機台補貨紀錄
public function replenishmentRecords()
{
return view('admin.placeholder', [
'title' => '機台補貨紀錄',
'description' => '個別機台的補貨歷史記錄',
]);
}
// 機台補貨紀錄(總)
public function replenishmentRecordsAll()
{
return view('admin.placeholder', [
'title' => '機台補貨紀錄(總)',
'description' => '所有機台的補貨總覽',
]);
}
// 機台庫存
public function machineStock()
{
return view('admin.placeholder', [
'title' => '機台庫存',
'description' => '各機台即時庫存查詢',
]);
}
// 人員庫存
public function staffStock()
{
return view('admin.placeholder', [
'title' => '人員庫存',
'description' => '補貨人員持有庫存',
]);
}
// 回庫單
public function returns()
{
return view('admin.placeholder', [
'title' => '回庫單',
'description' => '商品退回倉庫管理',
]);
}
}

View File

@@ -0,0 +1,47 @@
@php
$theme = request()->cookie('theme', 'dark-blue');
$themes = [
'dark-blue' => ['card' => 'bg-gray-800', 'accent' => 'indigo'],
'dark-purple' => ['card' => 'bg-slate-800', 'accent' => 'purple'],
'dark-green' => ['card' => 'bg-zinc-800', 'accent' => 'emerald'],
'light-blue' => ['card' => 'bg-white', 'accent' => 'blue'],
'light-green' => ['card' => 'bg-white', 'accent' => 'green'],
];
$currentTheme = $themes[$theme] ?? $themes['dark-blue'];
$isLight = in_array($theme, ['light-blue', 'light-green']);
@endphp
@extends('layouts.admin')
@section('content')
<div class="max-w-7xl mx-auto">
<div class="{{ $currentTheme['card'] }} rounded-lg shadow-lg p-8 text-center border {{ $isLight ? 'border-gray-200' : 'border-gray-700' }}">
<div class="mb-6">
<svg class="mx-auto h-24 w-24 text-{{ $currentTheme['accent'] }}-500" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6V4m0 2a2 2 0 100 4m0-4a2 2 0 110 4m-6 8a2 2 0 100-4m0 4a2 2 0 110-4m0 4v2m0-6V4m6 6v10m6-2a2 2 0 100-4m0 4a2 2 0 110-4m0 4v2m0-6V4" />
</svg>
</div>
<h1 class="text-3xl font-bold {{ $isLight ? 'text-gray-900' : 'text-white' }} mb-4">{{ $title ?? '功能頁面' }}</h1>
<p class="{{ $isLight ? 'text-gray-600' : 'text-gray-400' }} mb-6 text-lg">{{ $description ?? '此功能正在開發中' }}</p>
<div class="inline-block px-6 py-3 bg-{{ $currentTheme['accent'] }}-600 text-white rounded-lg font-semibold">
🚧 功能開發中
</div>
@if(isset($features) && count($features) > 0)
<div class="mt-8 text-left max-w-2xl mx-auto">
<h3 class="text-xl font-semibold {{ $isLight ? 'text-gray-900' : 'text-white' }} mb-4">規劃功能:</h3>
<ul class="space-y-2 {{ $isLight ? 'text-gray-700' : 'text-gray-300' }}">
@foreach($features as $feature)
<li class="flex items-start">
<svg class="h-6 w-6 text-{{ $currentTheme['accent'] }}-500 mr-2 flex-shrink-0" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
<span>{{ $feature }}</span>
</li>
@endforeach
</ul>
</div>
@endif
</div>
</div>
@endsection

View File

@@ -80,7 +80,7 @@
</div> </div>
<!-- Sidebar --> <!-- Sidebar -->
<aside class="fixed inset-y-0 left-0 z-50 w-64 {{ $currentTheme['sidebar'] }} border-r lg:translate-x-0 lg:static lg:inset-0" <aside class="fixed inset-y-0 left-0 z-50 w-64 {{ $currentTheme['sidebar'] }} border-r lg:translate-x-0 lg:static lg:inset-0 overflow-y-auto"
:class="{'translate-x-0': sidebarOpen, '-translate-x-full': !sidebarOpen}" :class="{'translate-x-0': sidebarOpen, '-translate-x-full': !sidebarOpen}"
x-transition:enter="transition-transform ease-in-out duration-300" x-transition:enter="transition-transform ease-in-out duration-300"
x-transition:enter-start="-translate-x-full" x-transition:enter-start="-translate-x-full"
@@ -91,66 +91,8 @@
<div class="flex items-center justify-center h-16 {{ $currentTheme['header'] }} border-b"> <div class="flex items-center justify-center h-16 {{ $currentTheme['header'] }} border-b">
<span class="text-2xl font-bold text-{{ $currentTheme['accent'] }}-500">Star Cloud</span> <span class="text-2xl font-bold text-{{ $currentTheme['accent'] }}-500">Star Cloud</span>
</div> </div>
<nav class="mt-5 px-2 space-y-1"> <nav class="mt-5 px-2 space-y-1 pb-4">
<a href="{{ route('admin.dashboard') }}" @include('layouts.partials.sidebar-menu')
@click="if (window.innerWidth < 1024) sidebarOpen = false"
class="group flex items-center px-2 py-2 text-base font-medium rounded-md {{ request()->routeIs('admin.dashboard') ? 'bg-'.$currentTheme['accent'].'-600 text-white' : ($isLight ? 'text-gray-700 hover:bg-gray-100' : 'text-gray-300 hover:bg-gray-700 hover:text-white') }}">
<svg class="mr-4 h-6 w-6 {{ request()->routeIs('admin.dashboard') ? 'text-white' : ($isLight ? 'text-gray-400 group-hover:text-gray-500' : 'text-gray-400 group-hover:text-gray-300') }}" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2H6a2 2 0 01-2-2V6zM14 6a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2h-2a2 2 0 01-2-2V6zM4 16a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2H6a2 2 0 01-2-2v-2zM14 16a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2h-2a2 2 0 01-2-2v-2z" />
</svg>
儀表板
</a>
<!-- 應用程式管理 -->
<div class="mt-8">
<h3 class="px-3 text-xs font-semibold {{ $isLight ? 'text-gray-500' : 'text-gray-500' }} uppercase tracking-wider">
應用程式管理
</h3>
<div class="mt-1 space-y-1">
<a href="{{ route('profile.edit') }}"
@click="if (window.innerWidth < 1024) sidebarOpen = false"
class="group flex items-center px-2 py-2 text-base font-medium rounded-md {{ request()->routeIs('profile.*') ? 'bg-'.$currentTheme['accent'].'-600 text-white' : ($isLight ? 'text-gray-700 hover:bg-gray-100' : 'text-gray-300 hover:bg-gray-700 hover:text-white') }}">
<svg class="mr-4 h-6 w-6 {{ request()->routeIs('profile.*') ? 'text-white' : ($isLight ? 'text-gray-400 group-hover:text-gray-500' : 'text-gray-400 group-hover:text-gray-300') }}" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z" />
</svg>
個人檔案
</a>
</div>
</div>
<!-- 機台管理 -->
<div class="mt-8">
<h3 class="px-3 text-xs font-semibold {{ $isLight ? 'text-gray-500' : 'text-gray-500' }} uppercase tracking-wider">
機台管理
</h3>
<div class="mt-1 space-y-1">
<a href="{{ route('admin.machines.index') }}"
@click="if (window.innerWidth < 1024) sidebarOpen = false"
class="group flex items-center px-2 py-2 text-base font-medium rounded-md {{ request()->routeIs('admin.machines.*') ? 'bg-'.$currentTheme['accent'].'-600 text-white' : ($isLight ? 'text-gray-700 hover:bg-gray-100' : 'text-gray-300 hover:bg-gray-700 hover:text-white') }}">
<svg class="mr-4 h-6 w-6 {{ request()->routeIs('admin.machines.*') ? 'text-white' : ($isLight ? 'text-gray-400 group-hover:text-gray-500' : 'text-gray-400 group-hover:text-gray-300') }}" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 12h14M5 12a2 2 0 01-2-2V6a2 2 0 012-2h14a2 2 0 012 2v4a2 2 0 01-2 2M5 12a2 2 0 01-2 2v4a2 2 0 012 2h14a2 2 0 012-2v-4a2 2 0 01-2-2m-2-4h.01M17 16h.01" />
</svg>
機台列表
</a>
</div>
</div>
<!-- APP 管理 -->
<div class="mt-8">
<h3 class="px-3 text-xs font-semibold {{ $isLight ? 'text-gray-500' : 'text-gray-500' }} uppercase tracking-wider">
APP 管理
</h3>
<div class="mt-1 space-y-1">
<a href="{{ route('admin.app-configs.index') }}"
@click="if (window.innerWidth < 1024) sidebarOpen = false"
class="group flex items-center px-2 py-2 text-base font-medium rounded-md {{ request()->routeIs('admin.app-configs.*') ? 'bg-'.$currentTheme['accent'].'-600 text-white' : ($isLight ? 'text-gray-700 hover:bg-gray-100' : 'text-gray-300 hover:bg-gray-700 hover:text-white') }}">
<svg class="mr-4 h-6 w-6 {{ request()->routeIs('admin.app-configs.*') ? 'text-white' : ($isLight ? 'text-gray-400 group-hover:text-gray-500' : 'text-gray-400 group-hover:text-gray-300') }}" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6V4m0 2a2 2 0 100 4m0-4a2 2 0 110 4m-6 8a2 2 0 100-4m0 4a2 2 0 110-4m0 4v2m0-6V4m6 6v10m6-2a2 2 0 100-4m0 4a2 2 0 110-4m0 4v2m0-6V4" />
</svg>
設定
</a>
</div>
</div>
</nav> </nav>
</aside> </aside>

View File

@@ -0,0 +1,84 @@
{{-- 1. 儀表板 (獨立項目) --}}
<a href="{{ route('admin.dashboard') }}"
@click="if (window.innerWidth < 1024) sidebarOpen = false"
class="group flex items-center px-2 py-2 text-sm font-medium rounded-md {{ request()->routeIs('admin.dashboard') ? 'bg-'.$currentTheme['accent'].'-600 text-white' : ($isLight ? 'text-gray-700 hover:bg-gray-100' : 'text-gray-300 hover:bg-gray-700 hover:text-white') }}">
<svg class="mr-3 h-5 w-5 {{ request()->routeIs('admin.dashboard') ? 'text-white' : ($isLight ? 'text-gray-400 group-hover:text-gray-500' : 'text-gray-400 group-hover:text-gray-300') }}" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2H6a2 2 0 01-2-2V6zM14 6a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2h-2a2 2 0 01-2-2V6zM4 16a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2H6a2 2 0 01-2-2v-2zM14 16a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2h-2a2 2 0 01-2-2v-2z" />
</svg>
儀表板
</a>
{{-- 2. 應用程式 --}}
<div x-data="{
open: localStorage.getItem('menu_profile') === 'true' || {{ request()->routeIs('profile.*') ? 'true' : 'false' }},
init() {
this.$watch('open', value => localStorage.setItem('menu_profile', value))
}
}">
<button @click="open = !open" class="group flex items-center w-full px-2 py-2 text-sm font-medium rounded-md {{ $isLight ? 'text-gray-700 hover:bg-gray-100' : 'text-gray-300 hover:bg-gray-700 hover:text-white' }}">
<svg class="mr-3 h-5 w-5 {{ $isLight ? 'text-gray-400 group-hover:text-gray-500' : 'text-gray-400 group-hover:text-gray-300' }}" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z" />
</svg>
<span class="flex-1 text-left">應用程式</span>
<svg class="ml-auto h-5 w-5 transform transition-transform duration-200" :class="{'rotate-90': open}" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" />
</svg>
</button>
<div x-show="open" x-collapse class="mt-1 space-y-1">
<a href="{{ route('profile.edit') }}" @click="if (window.innerWidth < 1024) sidebarOpen = false" class="group flex items-center pl-14 pr-2 py-2 text-sm rounded-md {{ request()->routeIs('profile.edit') ? 'bg-'.$currentTheme['accent'].'-600 text-white' : ($isLight ? 'text-gray-700 hover:bg-gray-100' : 'text-gray-300 hover:bg-gray-700 hover:text-white') }}" style="padding-left: 3.5rem;">個人檔案</a>
</div>
</div>
{{-- 3. 機台管理 --}}
<div x-data="{
open: localStorage.getItem('menu_machines') === 'true' || {{ request()->routeIs('admin.machines.*') ? 'true' : 'false' }},
init() {
this.$watch('open', value => localStorage.setItem('menu_machines', value))
}
}">
<button @click="open = !open" class="group flex items-center w-full px-2 py-2 text-sm font-medium rounded-md {{ $isLight ? 'text-gray-700 hover:bg-gray-100' : 'text-gray-300 hover:bg-gray-700 hover:text-white' }}">
<svg class="mr-3 h-5 w-5 {{ $isLight ? 'text-gray-400 group-hover:text-gray-500' : 'text-gray-400 group-hover:text-gray-300' }}" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 12h14M5 12a2 2 0 01-2-2V6a2 2 0 012-2h14a2 2 0 012 2v4a2 2 0 01-2 2M5 12a2 2 0 01-2 2v4a2 2 0 012 2h14a2 2 0 012-2v-4a2 2 0 01-2-2m-2-4h.01M17 16h.01" />
</svg>
<span class="flex-1 text-left">機台管理</span>
<svg class="ml-auto h-5 w-5 transform transition-transform duration-200" :class="{'rotate-90': open}" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" />
</svg>
</button>
<div x-show="open" x-collapse class="mt-1 space-y-1">
<a href="{{ route('admin.machines.logs') }}" @click="if (window.innerWidth < 1024) sidebarOpen = false" class="group flex items-center pl-14 pr-2 py-2 text-sm rounded-md {{ request()->routeIs('admin.machines.logs') ? 'bg-'.$currentTheme['accent'].'-600 text-white' : ($isLight ? 'text-gray-700 hover:bg-gray-100' : 'text-gray-300 hover:bg-gray-700 hover:text-white') }}" style="padding-left: 3.5rem;">機台日誌</a>
<a href="{{ route('admin.machines.index') }}" @click="if (window.innerWidth < 1024) sidebarOpen = false" class="group flex items-center pl-14 pr-2 py-2 text-sm rounded-md {{ request()->routeIs('admin.machines.index') ? 'bg-'.$currentTheme['accent'].'-600 text-white' : ($isLight ? 'text-gray-700 hover:bg-gray-100' : 'text-gray-300 hover:bg-gray-700 hover:text-white') }}" style="padding-left: 3.5rem;">機台列表</a>
<a href="{{ route('admin.machines.permissions') }}" @click="if (window.innerWidth < 1024) sidebarOpen = false" class="group flex items-center pl-14 pr-2 py-2 text-sm rounded-md {{ request()->routeIs('admin.machines.permissions') ? 'bg-'.$currentTheme['accent'].'-600 text-white' : ($isLight ? 'text-gray-700 hover:bg-gray-100' : 'text-gray-300 hover:bg-gray-700 hover:text-white') }}" style="padding-left: 3.5rem;">機台權限</a>
<a href="{{ route('admin.machines.utilization') }}" @click="if (window.innerWidth < 1024) sidebarOpen = false" class="group flex items-center pl-14 pr-2 py-2 text-sm rounded-md {{ request()->routeIs('admin.machines.utilization') ? 'bg-'.$currentTheme['accent'].'-600 text-white' : ($isLight ? 'text-gray-700 hover:bg-gray-100' : 'text-gray-300 hover:bg-gray-700 hover:text-white') }}" style="padding-left: 3.5rem;">機台稼動率</a>
<a href="{{ route('admin.machines.expiry') }}" @click="if (window.innerWidth < 1024) sidebarOpen = false" class="group flex items-center pl-14 pr-2 py-2 text-sm rounded-md {{ request()->routeIs('admin.machines.expiry') ? 'bg-'.$currentTheme['accent'].'-600 text-white' : ($isLight ? 'text-gray-700 hover:bg-gray-100' : 'text-gray-300 hover:bg-gray-700 hover:text-white') }}" style="padding-left: 3.5rem;">效期管理</a>
<a href="{{ route('admin.machines.maintenance') }}" @click="if (window.innerWidth < 1024) sidebarOpen = false" class="group flex items-center pl-14 pr-2 py-2 text-sm rounded-md {{ request()->routeIs('admin.machines.maintenance') ? 'bg-'.$currentTheme['accent'].'-600 text-white' : ($isLight ? 'text-gray-700 hover:bg-gray-100' : 'text-gray-300 hover:bg-gray-700 hover:text-white') }}" style="padding-left: 3.5rem;">維修管理單</a>
</div>
</div>
{{-- 4. APP管理 --}}
<div x-data="{
open: localStorage.getItem('menu_app') === 'true' || {{ request()->routeIs('admin.app.*') || request()->routeIs('admin.app-configs.*') ? 'true' : 'false' }},
init() {
this.$watch('open', value => localStorage.setItem('menu_app', value))
}
}">
<button @click="open = !open" class="group flex items-center w-full px-2 py-2 text-sm font-medium rounded-md {{ $isLight ? 'text-gray-700 hover:bg-gray-100' : 'text-gray-300 hover:bg-gray-700 hover:text-white' }}">
<svg class="mr-3 h-5 w-5 {{ $isLight ? 'text-gray-400 group-hover:text-gray-500' : 'text-gray-400 group-hover:text-gray-300' }}" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 18h.01M8 21h8a2 2 0 002-2V5a2 2 0 00-2-2H8a2 2 0 00-2 2v14a2 2 0 002 2z" />
</svg>
<span class="flex-1 text-left">APP管理</span>
<svg class="ml-auto h-5 w-5 transform transition-transform duration-200" :class="{'rotate-90': open}" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" />
</svg>
</button>
<div x-show="open" x-collapse class="mt-1 space-y-1">
<a href="{{ route('admin.app.ui-elements') }}" @click="if (window.innerWidth < 1024) sidebarOpen = false" class="group flex items-center pl-14 pr-2 py-2 text-sm rounded-md {{ request()->routeIs('admin.app.ui-elements') ? 'bg-'.$currentTheme['accent'].'-600 text-white' : ($isLight ? 'text-gray-600 hover:bg-gray-100' : 'text-gray-300 hover:bg-gray-700 hover:text-white') }}" style="padding-left: 3.5rem;">UI元素設定</a>
<a href="{{ route('admin.app.helper') }}" @click="if (window.innerWidth < 1024) sidebarOpen = false" class="group flex items-center pl-14 pr-2 py-2 text-sm rounded-md {{ request()->routeIs('admin.app.helper') ? 'bg-'.$currentTheme['accent'].'-600 text-white' : ($isLight ? 'text-gray-600 hover:bg-gray-100' : 'text-gray-300 hover:bg-gray-700 hover:text-white') }}" style="padding-left: 3.5rem;">小幫手設定</a>
<a href="{{ route('admin.app.questionnaire') }}" @click="if (window.innerWidth < 1024) sidebarOpen = false" class="group flex items-center pl-14 pr-2 py-2 text-sm rounded-md {{ request()->routeIs('admin.app.questionnaire') ? 'bg-'.$currentTheme['accent'].'-600 text-white' : ($isLight ? 'text-gray-600 hover:bg-gray-100' : 'text-gray-300 hover:bg-gray-700 hover:text-white') }}" style="padding-left: 3.5rem;">問卷設定</a>
<a href="{{ route('admin.app.games') }}" @click="if (window.innerWidth < 1024) sidebarOpen = false" class="group flex items-center pl-14 pr-2 py-2 text-sm rounded-md {{ request()->routeIs('admin.app.games') ? 'bg-'.$currentTheme['accent'].'-600 text-white' : ($isLight ? 'text-gray-600 hover:bg-gray-100' : 'text-gray-300 hover:bg-gray-700 hover:text-white') }}" style="padding-left: 3.5rem;">互動遊戲設定</a>
<a href="{{ route('admin.app.timer') }}" @click="if (window.innerWidth < 1024) sidebarOpen = false" class="group flex items-center pl-14 pr-2 py-2 text-sm rounded-md {{ request()->routeIs('admin.app.timer') ? 'bg-'.$currentTheme['accent'].'-600 text-white' : ($isLight ? 'text-gray-600 hover:bg-gray-100' : 'text-gray-300 hover:bg-gray-700 hover:text-white') }}" style="padding-left: 3.5rem;">計時器</a>
</div>
</div>
{{-- 注意:由於選單內容過長,剩餘的 10 個模組(倉庫管理、銷售管理等)將在實際使用時逐步添加 --}}
{{-- 目前已實作前 4 個主要模組,可以先測試展開/收合功能是否正常運作 --}}

View File

@@ -23,10 +23,138 @@ Route::get('/dashboard', function () {
})->middleware(['auth', 'verified'])->name('dashboard'); })->middleware(['auth', 'verified'])->name('dashboard');
Route::middleware(['auth', 'verified'])->prefix('admin')->name('admin.')->group(function () { Route::middleware(['auth', 'verified'])->prefix('admin')->name('admin.')->group(function () {
// 1. 儀表板
Route::get('/dashboard', [App\Http\Controllers\Admin\DashboardController::class, 'index'])->name('dashboard'); Route::get('/dashboard', [App\Http\Controllers\Admin\DashboardController::class, 'index'])->name('dashboard');
// 3. 機台管理
Route::prefix('machines')->name('machines.')->group(function () {
Route::get('/logs', [App\Http\Controllers\Admin\MachineController::class, 'logs'])->name('logs');
Route::get('/permissions', [App\Http\Controllers\Admin\MachineController::class, 'permissions'])->name('permissions');
Route::get('/utilization', [App\Http\Controllers\Admin\MachineController::class, 'utilization'])->name('utilization');
Route::get('/expiry', [App\Http\Controllers\Admin\MachineController::class, 'expiry'])->name('expiry');
Route::get('/maintenance', [App\Http\Controllers\Admin\MachineController::class, 'maintenance'])->name('maintenance');
});
Route::resource('machines', App\Http\Controllers\Admin\MachineController::class); Route::resource('machines', App\Http\Controllers\Admin\MachineController::class);
// 4. APP管理
Route::prefix('app')->name('app.')->group(function () {
Route::get('/ui-elements', [App\Http\Controllers\Admin\AppConfigController::class, 'uiElements'])->name('ui-elements');
Route::get('/helper', [App\Http\Controllers\Admin\AppConfigController::class, 'helper'])->name('helper');
Route::get('/questionnaire', [App\Http\Controllers\Admin\AppConfigController::class, 'questionnaire'])->name('questionnaire');
Route::get('/games', [App\Http\Controllers\Admin\AppConfigController::class, 'games'])->name('games');
Route::get('/timer', [App\Http\Controllers\Admin\AppConfigController::class, 'timer'])->name('timer');
});
Route::get('/app-configs', [App\Http\Controllers\Admin\AppConfigController::class, 'index'])->name('app-configs.index'); Route::get('/app-configs', [App\Http\Controllers\Admin\AppConfigController::class, 'index'])->name('app-configs.index');
Route::put('/app-configs', [App\Http\Controllers\Admin\AppConfigController::class, 'update'])->name('app-configs.update'); Route::put('/app-configs', [App\Http\Controllers\Admin\AppConfigController::class, 'update'])->name('app-configs.update');
// 5. 倉庫管理
Route::prefix('warehouses')->name('warehouses.')->group(function () {
Route::get('/', [App\Http\Controllers\Admin\WarehouseController::class, 'index'])->name('index');
Route::get('/personal', [App\Http\Controllers\Admin\WarehouseController::class, 'personal'])->name('personal');
Route::get('/stock-management', [App\Http\Controllers\Admin\WarehouseController::class, 'stockManagement'])->name('stock-management');
Route::get('/transfers', [App\Http\Controllers\Admin\WarehouseController::class, 'transfers'])->name('transfers');
Route::get('/purchases', [App\Http\Controllers\Admin\WarehouseController::class, 'purchases'])->name('purchases');
Route::get('/replenishments', [App\Http\Controllers\Admin\WarehouseController::class, 'replenishments'])->name('replenishments');
Route::get('/replenishment-records', [App\Http\Controllers\Admin\WarehouseController::class, 'replenishmentRecords'])->name('replenishment-records');
Route::get('/replenishment-records-all', [App\Http\Controllers\Admin\WarehouseController::class, 'replenishmentRecordsAll'])->name('replenishment-records-all');
Route::get('/machine-stock', [App\Http\Controllers\Admin\WarehouseController::class, 'machineStock'])->name('machine-stock');
Route::get('/staff-stock', [App\Http\Controllers\Admin\WarehouseController::class, 'staffStock'])->name('staff-stock');
Route::get('/returns', [App\Http\Controllers\Admin\WarehouseController::class, 'returns'])->name('returns');
});
// 6. 銷售管理
Route::prefix('sales')->name('sales.')->group(function () {
Route::get('/', [App\Http\Controllers\Admin\SalesController::class, 'index'])->name('index');
Route::get('/pickup-codes', [App\Http\Controllers\Admin\SalesController::class, 'pickupCodes'])->name('pickup-codes');
Route::get('/orders', [App\Http\Controllers\Admin\SalesController::class, 'orders'])->name('orders');
Route::get('/promotions', [App\Http\Controllers\Admin\SalesController::class, 'promotions'])->name('promotions');
Route::get('/pass-codes', [App\Http\Controllers\Admin\SalesController::class, 'passCodes'])->name('pass-codes');
Route::get('/store-gifts', [App\Http\Controllers\Admin\SalesController::class, 'storeGifts'])->name('store-gifts');
});
// 7. 分析管理
Route::prefix('analysis')->name('analysis.')->group(function () {
Route::get('/change-stock', [App\Http\Controllers\Admin\AnalysisController::class, 'changeStock'])->name('change-stock');
Route::get('/machine-reports', [App\Http\Controllers\Admin\AnalysisController::class, 'machineReports'])->name('machine-reports');
Route::get('/product-reports', [App\Http\Controllers\Admin\AnalysisController::class, 'productReports'])->name('product-reports');
Route::get('/survey-analysis', [App\Http\Controllers\Admin\AnalysisController::class, 'surveyAnalysis'])->name('survey-analysis');
});
// 8. 稽核管理
Route::prefix('audit')->name('audit.')->group(function () {
Route::get('/purchases', [App\Http\Controllers\Admin\AuditController::class, 'purchases'])->name('purchases');
Route::get('/transfers', [App\Http\Controllers\Admin\AuditController::class, 'transfers'])->name('transfers');
Route::get('/replenishments', [App\Http\Controllers\Admin\AuditController::class, 'replenishments'])->name('replenishments');
});
// 9. 資料設定
Route::prefix('data-config')->name('data-config.')->group(function () {
Route::get('/products', [App\Http\Controllers\Admin\DataConfigController::class, 'products'])->name('products');
Route::get('/advertisements', [App\Http\Controllers\Admin\DataConfigController::class, 'advertisements'])->name('advertisements');
Route::get('/admin-products', [App\Http\Controllers\Admin\DataConfigController::class, 'adminProducts'])->name('admin-products');
Route::get('/accounts', [App\Http\Controllers\Admin\DataConfigController::class, 'accounts'])->name('accounts');
Route::get('/sub-accounts', [App\Http\Controllers\Admin\DataConfigController::class, 'subAccounts'])->name('sub-accounts');
Route::get('/sub-account-roles', [App\Http\Controllers\Admin\DataConfigController::class, 'subAccountRoles'])->name('sub-account-roles');
Route::get('/points', [App\Http\Controllers\Admin\DataConfigController::class, 'points'])->name('points');
Route::get('/badges', [App\Http\Controllers\Admin\DataConfigController::class, 'badges'])->name('badges');
});
// 10. 遠端管理
Route::prefix('remote')->name('remote.')->group(function () {
Route::get('/stock', [App\Http\Controllers\Admin\RemoteController::class, 'stock'])->name('stock');
Route::get('/restart', [App\Http\Controllers\Admin\RemoteController::class, 'restart'])->name('restart');
Route::get('/restart-card-reader', [App\Http\Controllers\Admin\RemoteController::class, 'restartCardReader'])->name('restart-card-reader');
Route::get('/checkout', [App\Http\Controllers\Admin\RemoteController::class, 'checkout'])->name('checkout');
Route::get('/lock', [App\Http\Controllers\Admin\RemoteController::class, 'lock'])->name('lock');
Route::get('/change', [App\Http\Controllers\Admin\RemoteController::class, 'change'])->name('change');
Route::get('/dispense', [App\Http\Controllers\Admin\RemoteController::class, 'dispense'])->name('dispense');
});
// 11. Line管理
Route::prefix('line')->name('line.')->group(function () {
Route::get('/members', [App\Http\Controllers\Admin\LineController::class, 'members'])->name('members');
Route::get('/machines', [App\Http\Controllers\Admin\LineController::class, 'machines'])->name('machines');
Route::get('/products', [App\Http\Controllers\Admin\LineController::class, 'products'])->name('products');
Route::get('/official-account', [App\Http\Controllers\Admin\LineController::class, 'officialAccount'])->name('official-account');
Route::get('/orders', [App\Http\Controllers\Admin\LineController::class, 'orders'])->name('orders');
Route::get('/coupons', [App\Http\Controllers\Admin\LineController::class, 'coupons'])->name('coupons');
});
// 12. 預約系統
Route::prefix('reservation')->name('reservation.')->group(function () {
Route::get('/members', [App\Http\Controllers\Admin\ReservationController::class, 'members'])->name('members');
Route::get('/stores', [App\Http\Controllers\Admin\ReservationController::class, 'stores'])->name('stores');
Route::get('/time-slots', [App\Http\Controllers\Admin\ReservationController::class, 'timeSlots'])->name('time-slots');
Route::get('/venues', [App\Http\Controllers\Admin\ReservationController::class, 'venues'])->name('venues');
Route::get('/coupons', [App\Http\Controllers\Admin\ReservationController::class, 'coupons'])->name('coupons');
Route::get('/reservations', [App\Http\Controllers\Admin\ReservationController::class, 'reservations'])->name('reservations');
Route::get('/orders', [App\Http\Controllers\Admin\ReservationController::class, 'orders'])->name('orders');
});
// 13. 特殊權限管理
Route::prefix('special-permission')->name('special-permission.')->group(function () {
Route::get('/clear-stock', [App\Http\Controllers\Admin\SpecialPermissionController::class, 'clearStock'])->name('clear-stock');
Route::get('/apk-versions', [App\Http\Controllers\Admin\SpecialPermissionController::class, 'apkVersions'])->name('apk-versions');
Route::get('/discord-notifications', [App\Http\Controllers\Admin\SpecialPermissionController::class, 'discordNotifications'])->name('discord-notifications');
});
// 14. 權限設定
Route::prefix('permission')->name('permission.')->group(function () {
Route::get('/app-features', [App\Http\Controllers\Admin\PermissionController::class, 'appFeatures'])->name('app-features');
Route::get('/data-config', [App\Http\Controllers\Admin\PermissionController::class, 'dataConfig'])->name('data-config');
Route::get('/sales', [App\Http\Controllers\Admin\PermissionController::class, 'sales'])->name('sales');
Route::get('/machines', [App\Http\Controllers\Admin\PermissionController::class, 'machines'])->name('machines');
Route::get('/warehouses', [App\Http\Controllers\Admin\PermissionController::class, 'warehouses'])->name('warehouses');
Route::get('/analysis', [App\Http\Controllers\Admin\PermissionController::class, 'analysis'])->name('analysis');
Route::get('/audit', [App\Http\Controllers\Admin\PermissionController::class, 'audit'])->name('audit');
Route::get('/remote', [App\Http\Controllers\Admin\PermissionController::class, 'remote'])->name('remote');
Route::get('/line', [App\Http\Controllers\Admin\PermissionController::class, 'line'])->name('line');
Route::get('/roles', [App\Http\Controllers\Admin\PermissionController::class, 'roles'])->name('roles');
Route::get('/others', [App\Http\Controllers\Admin\PermissionController::class, 'others'])->name('others');
Route::get('/ai-prediction', [App\Http\Controllers\Admin\PermissionController::class, 'aiPrediction'])->name('ai-prediction');
});
// 主題設定
Route::post('/theme', [App\Http\Controllers\Admin\ThemeController::class, 'update'])->name('theme.update'); Route::post('/theme', [App\Http\Controllers\Admin\ThemeController::class, 'update'])->name('theme.update');
}); });