[FEAT] 重構機台狀態判定邏輯並優化全站多語系支援
All checks were successful
star-cloud-deploy-demo / deploy-demo (push) Successful in 1m18s

1. 重構機台在線狀態判定機制:移除資料庫 status 欄位,改由 Model 根據心跳時間動態計算。
2. 修正儀表板 (Dashboard) 與機台管理頁面的多語系顯示問題,解決換行導致翻譯失效的 Bug。
3. 修正個人檔案頁面的麵包屑 (Breadcrumbs) 導航,補齊「個人設定」層級。
4. 更新 IoT API (B010, B600) 的認證機制與日誌處理邏輯。
5. 同步更新繁中、英文、日文語言檔,確保 UI 標籤一致性。
This commit is contained in:
2026-04-07 10:21:07 +08:00
parent 08b6c60d2e
commit bbdc5bad9f
18 changed files with 2476 additions and 1813 deletions

View File

@@ -105,7 +105,6 @@ class MachineSettingController extends AdminController
}
$machine = Machine::create(array_merge($validated, [
'status' => 'offline',
'api_token' => \Illuminate\Support\Str::random(60),
'creator_id' => auth()->id(),
'updater_id' => auth()->id(),

View File

@@ -12,28 +12,31 @@ class DashboardController extends Controller
{
// 每頁顯示筆數限制 (預設為 10)
$perPage = (int) request()->input('per_page', 10);
if ($perPage <= 0) $perPage = 10;
if ($perPage <= 0)
$perPage = 10;
// 從資料庫獲取真實統計數據
$totalRevenue = \App\Models\Member\MemberWallet::sum('balance');
$activeMachines = Machine::where('status', 'online')->count();
$alertsPending = Machine::where('status', 'error')->count();
$totalRevenue = \App\Models\Member\MemberWallet::sum('balance');
$activeMachines = Machine::online()->count();
$offlineMachines = Machine::offline()->count();
$alertsPending = Machine::hasError()->count();
$memberCount = \App\Models\Member\Member::count();
// 獲取機台列表 (分頁)
$machines = Machine::when($request->search, function($query, $search) {
$query->where(function($q) use ($search) {
$q->where('name', 'like', "%{$search}%")
->orWhere('serial_no', 'like', "%{$search}%");
});
})
->latest()
$machines = Machine::when($request->search, function ($query, $search) {
$query->where(function ($q) use ($search) {
$q->where('name', 'like', "%{$search}%")
->orWhere('serial_no', 'like', "%{$search}%");
});
})
->orderByDesc('last_heartbeat_at')
->paginate($perPage)
->withQueryString();
return view('admin.dashboard', compact(
'totalRevenue',
'activeMachines',
'offlineMachines',
'alertsPending',
'memberCount',
'machines'

View File

@@ -9,19 +9,21 @@ use Illuminate\View\View;
class MachineController extends AdminController
{
public function __construct(protected MachineService $machineService) {}
public function __construct(protected MachineService $machineService)
{
}
public function index(Request $request): View
{
$per_page = $request->input('per_page', 10);
$query = Machine::query();
// 搜尋:名稱或序號
if ($search = $request->input('search')) {
$query->where(function ($q) use ($search) {
$q->where('name', 'like', "%{$search}%")
->orWhere('serial_no', 'like', "%{$search}%");
->orWhere('serial_no', 'like', "%{$search}%");
});
}
@@ -34,14 +36,31 @@ class MachineController extends AdminController
return view('admin.machines.index', compact('machines'));
}
/**
* 更新機台基本資訊 (目前僅名稱)
*/
public function update(Request $request, Machine $machine)
{
$validated = $request->validate([
'name' => 'required|string|max:255',
]);
$machine->update($validated);
return redirect()->route('admin.machines.index')
->with('success', __('Machine updated successfully.'));
}
/**
* 顯示特定機台的日誌與詳細資訊
*/
public function show(int $id): View
{
$machine = Machine::with(['logs' => function ($query) {
$query->latest()->limit(50);
}])->findOrFail($id);
$machine = Machine::with([
'logs' => function ($query) {
$query->latest()->limit(50);
}
])->findOrFail($id);
return view('admin.machines.show', compact('machine'));
}
@@ -53,7 +72,7 @@ class MachineController extends AdminController
public function logsAjax(Request $request, Machine $machine)
{
$per_page = $request->input('per_page', 10);
$startDate = $request->get('start_date', now()->format('Y-m-d'));
$endDate = $request->get('end_date', now()->format('Y-m-d'));
@@ -88,7 +107,7 @@ class MachineController extends AdminController
{
// 取得當前使用者有權限的所有機台 (已透過 Global Scope 過濾)
$machines = Machine::all();
$date = $request->get('date', now()->toDateString());
$service = app(\App\Services\Machine\MachineService::class);
$fleetStats = $service->getFleetStats($date);
@@ -111,7 +130,7 @@ class MachineController extends AdminController
public function slotsAjax(Machine $machine)
{
$slots = $machine->slots()->with('product:id,name,image_url')->orderByRaw('CAST(slot_no AS UNSIGNED) ASC')->get();
return response()->json([
'success' => true,
'machine' => $machine->only(['id', 'name', 'serial_no']),

View File

@@ -18,7 +18,7 @@ class MachineController extends Controller
public function heartbeat(Request $request)
{
$machine = $request->get('machine');
$data = $request->all();
$data = $request->except(['machine', 'key']); // 排除 Middleware 注入的 Model 物件與認證 key
// 異步處理狀態更新
ProcessHeartbeat::dispatch($machine->serial_no, $data);
@@ -84,7 +84,7 @@ class MachineController extends Controller
public function recordRestock(Request $request)
{
$machine = $request->get('machine');
$data = $request->all();
$data = $request->except(['machine', 'key']); // 排除 Middleware 注入物件
$data['serial_no'] = $machine->serial_no;
\App\Jobs\Machine\ProcessRestockReport::dispatch($data);
@@ -135,7 +135,7 @@ class MachineController extends Controller
public function syncTimer(Request $request)
{
$machine = $request->get('machine');
$data = $request->all();
$data = $request->except(['machine', 'key']); // 排除 Middleware 注入物件
ProcessTimerStatus::dispatch($machine->serial_no, $data);
@@ -148,7 +148,7 @@ class MachineController extends Controller
public function syncCoinInventory(Request $request)
{
$machine = $request->get('machine');
$data = $request->all();
$data = $request->except(['machine', 'key']); // 排除 Middleware 注入物件
ProcessCoinInventory::dispatch($machine->serial_no, $data);

View File

@@ -16,7 +16,7 @@ class TransactionController extends Controller
public function store(Request $request)
{
$machine = $request->get('machine');
$data = $request->all();
$data = $request->except(['machine', 'key']); // 排除 Middleware 注入物件
$data['serial_no'] = $machine->serial_no;
ProcessTransaction::dispatch($data);
@@ -34,7 +34,7 @@ class TransactionController extends Controller
public function recordInvoice(Request $request)
{
$machine = $request->get('machine');
$data = $request->all();
$data = $request->except(['machine', 'key']); // 排除 Middleware 注入物件
$data['serial_no'] = $machine->serial_no;
ProcessInvoice::dispatch($data);