[FEAT] 遠端指令中心 AJAX 化與介面標準化
All checks were successful
star-cloud-deploy-demo / deploy-demo (push) Successful in 2m10s

1. 將遠端指令中心 (Remote Command Center) 兩大分頁 (操作紀錄、新增指令) 改為 AJAX 異步載入,提升切換速度。
2. 建立抽離的 Blade Partials 結構 (partials/tab-history-index.blade.php, tab-machines-index.blade.php) 以利維護。
3. 實作全域 Loading Bar 與 Luxury Spinner 視覺回饋,確保 AJAX 過程中有明確狀態。
4. 修正庫存管理與指令中心在機台圖片不存在時的 `Undefined array key 0` 錯誤。
5. 標準化操作紀錄搜尋行為:文字搜尋改為 Enter 觸發,日期範圍改為手動按下搜尋按鈕觸發,並新增「重設」功能。
6. 設定 Flatpickr 日期時間選擇器預設時間為 `00:00`。
7. 修正 `stock.blade.php` 中的 PHP 語法錯誤 (括號未閉合)。
8. 同步更新多語系翻譯檔案 (zh_TW, en, ja)。
This commit is contained in:
2026-04-15 13:17:25 +08:00
parent ee985abb2e
commit 24553d9b73
10 changed files with 1680 additions and 1161 deletions

View File

@@ -15,19 +15,32 @@ class RemoteController extends Controller
*/
public function index(Request $request)
{
$machines = Machine::withCount(['slots'])->orderBy('last_heartbeat_at', 'desc')->orderBy('id', 'desc')->get();
$selectedMachine = null;
// --- 1. 機台列表處理 (New Command Tab) ---
$machineQuery = Machine::withCount(['slots'])->orderBy('last_heartbeat_at', 'desc')->orderBy('id', 'desc');
if ($request->filled('search') && $request->input('tab') === 'list') {
$search = $request->input('search');
$machineQuery->where(function ($q) use ($search) {
$q->where('name', 'like', "%{$search}%")
->orWhere('serial_no', 'like', "%{$search}%");
});
}
$machines = $machineQuery->paginate($request->input('per_page', 10), ['*'], 'machine_page');
// --- 2. 歷史紀錄處理 (Operation Records Tab) ---
$historyQuery = RemoteCommand::where('command_type', '!=', 'reload_stock')
->with(['machine', 'user']);
if ($request->filled('search')) {
if ($request->filled('search') && ($request->input('tab') === 'history' || !$request->has('tab'))) {
$search = $request->input('search');
$historyQuery->where(function($q) use ($search) {
$q->whereHas('machine', function($mq) use ($search) {
$historyQuery->where(function ($q) use ($search) {
$q->whereHas('machine', function ($mq) use ($search) {
$mq->where('name', 'like', "%{$search}%")
->orWhere('serial_no', 'like', "%{$search}%");
})->orWhereHas('user', function($uq) use ($search) {
->orWhere('serial_no', 'like', "%{$search}%");
})->orWhereHas('user', function ($uq) use ($search) {
$uq->where('name', 'like', "%{$search}%");
});
});
@@ -59,17 +72,35 @@ class RemoteController extends Controller
$historyQuery->where('status', $request->input('status'));
}
$history = $historyQuery->latest()->paginate($request->input('per_page', 10));
$history = $historyQuery->latest()->paginate($request->input('per_page', 10), ['*'], 'history_page');
// --- 3. 特定機台詳情處理 ---
if ($request->has('machine_id')) {
$selectedMachine = Machine::with(['slots.product', 'commands' => function($query) {
$query->where('command_type', '!=', 'reload_stock')
->latest()
->limit(5);
}])->find($request->machine_id);
$selectedMachine = Machine::with([
'slots.product',
'commands' => function ($query) {
$query->where('command_type', '!=', 'reload_stock')
->latest()
->limit(5);
}
])->find($request->machine_id);
}
// --- 4. AJAX 回應處理 ---
if ($request->ajax()) {
if ($request->has('tab')) {
$tab = $request->input('tab');
$viewPath = $tab === 'list' ? 'admin.remote.partials.tab-machines-index' : 'admin.remote.partials.tab-history-index';
return response()->json([
'success' => true,
'html' => view($viewPath, [
'machines' => $machines,
'history' => $history,
])->render()
]);
}
return response()->json([
'success' => true,
'machine' => $selectedMachine,
@@ -142,29 +173,42 @@ class RemoteController extends Controller
*/
public function stock(Request $request)
{
$machines = Machine::withCount([
// 1. 機台查詢與分頁
$machineQuery = Machine::withCount([
'slots as slots_count',
'slots as low_stock_count' => function ($query) {
$query->where('stock', '<=', 5);
$query->where('stock', '<=', 5);
},
'slots as expiring_soon_count' => function ($query) {
$query->whereNotNull('expiry_date')
->where('expiry_date', '<=', now()->addDays(7))
->where('expiry_date', '>=', now()->startOfDay());
->where('expiry_date', '<=', now()->addDays(7))
->where('expiry_date', '>=', now()->startOfDay());
}
])->orderBy('last_heartbeat_at', 'desc')->orderBy('id', 'desc')->get();
$historyQuery = RemoteCommand::with(['machine', 'user']);
]);
if ($request->filled('machine_search')) {
$ms = $request->input('machine_search');
$machineQuery->where(function ($q) use ($ms) {
$q->where('name', 'like', "%{$ms}%")
->orWhere('serial_no', 'like', "%{$ms}%");
});
}
$machines = $machineQuery->orderBy('last_heartbeat_at', 'desc')
->orderBy('id', 'desc')
->paginate($request->input('per_page', 10), ['*'], 'machine_page');
// 2. 歷史紀錄查詢與分頁
$historyQuery = RemoteCommand::with(['machine', 'user']);
$historyQuery->where('command_type', 'reload_stock');
if ($request->filled('search')) {
$search = $request->input('search');
$historyQuery->where(function($q) use ($search) {
$q->whereHas('machine', function($mq) use ($search) {
$historyQuery->where(function ($q) use ($search) {
$q->whereHas('machine', function ($mq) use ($search) {
$mq->where('name', 'like', "%{$search}%")
->orWhere('serial_no', 'like', "%{$search}%");
})->orWhereHas('user', function($uq) use ($search) {
->orWhere('serial_no', 'like', "%{$search}%");
})->orWhereHas('user', function ($uq) use ($search) {
$uq->where('name', 'like', "%{$search}%");
});
});
@@ -191,15 +235,31 @@ class RemoteController extends Controller
$historyQuery->where('status', $request->input('status'));
}
$history = $historyQuery->latest()->paginate($request->input('per_page', 10));
$history = $historyQuery->latest()->paginate($request->input('per_page', 10), ['*'], 'history_page');
// 3. AJAX 回傳處理
if ($request->boolean('_ajax')) {
$tab = $request->input('tab', 'history');
if ($tab === 'machines') {
return response()->view('admin.remote.partials.tab-machines', [
'machines' => $machines,
]);
}
return response()->view('admin.remote.partials.tab-history', [
'history' => $history,
]);
}
$selectedMachine = null;
if ($request->has('machine_id')) {
$selectedMachine = Machine::with(['slots.product', 'commands' => function($query) {
$query->where('command_type', 'reload_stock')
->latest()
->limit(50);
}])->find($request->machine_id);
$selectedMachine = Machine::with([
'slots.product',
'commands' => function ($query) {
$query->where('command_type', 'reload_stock')
->latest()
->limit(50);
}
])->find($request->machine_id);
}
return view('admin.remote.stock', [