[FEAT] 遠端指令中心 AJAX 化與介面標準化
All checks were successful
star-cloud-deploy-demo / deploy-demo (push) Successful in 2m10s
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:
@@ -0,0 +1,152 @@
|
||||
<!-- Loading Overlay -->
|
||||
<div x-show="tabLoading === 'list'" x-transition:enter="transition ease-out duration-300"
|
||||
x-transition:enter-start="opacity-0" x-transition:enter-end="opacity-100"
|
||||
x-transition:leave="transition ease-in duration-200" x-transition:leave-start="opacity-100"
|
||||
x-transition:leave-end="opacity-0"
|
||||
class="absolute inset-0 z-20 bg-white/40 dark:bg-slate-900/40 backdrop-blur-[1px] flex flex-col items-center justify-center"
|
||||
x-cloak>
|
||||
<div class="relative w-16 h-16 mb-4 flex items-center justify-center">
|
||||
<div class="absolute inset-0 rounded-full border-2 border-transparent border-t-cyan-500 border-r-cyan-500/30 animate-spin"></div>
|
||||
<div class="absolute inset-2 rounded-full border border-cyan-500/10 animate-spin" style="animation-duration: 3s; direction: reverse;"></div>
|
||||
<div class="relative w-8 h-8 flex items-center justify-center">
|
||||
<svg class="w-6 h-6 text-cyan-500 animate-pulse" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2.5" d="M19.428 15.428a2 2 0 00-1.022-.547l-2.387-.477a6 6 0 00-3.86.517l-.318.158a6 6 0 01-3.86.517L6.05 15.21a2 2 0 00-1.806.547M8 4h8l-1 1v5.172a2 2 0 00.586 1.414l5 5c1.26 1.26.367 3.414-1.415 3.414H4.828c-1.782 0-2.674-2.154-1.414-3.414l5-5A2 2 0 009 10.172V5L8 4z" />
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<p class="text-[10px] font-black text-cyan-600 dark:text-cyan-400 uppercase tracking-[0.4em] animate-pulse">
|
||||
{{ __('Loading Data') }}...</p>
|
||||
</div>
|
||||
|
||||
<!-- Filters Area -->
|
||||
<div class="flex items-center justify-between mb-8">
|
||||
<form @submit.prevent="searchInTab('list')" class="relative group">
|
||||
<span class="absolute inset-y-0 left-0 flex items-center pl-4 pointer-events-none z-10">
|
||||
<svg class="h-4 w-4 text-slate-400 group-focus-within:text-cyan-500 transition-colors"
|
||||
viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"
|
||||
stroke-linecap="round" stroke-linejoin="round">
|
||||
<circle cx="11" cy="11" r="8"></circle>
|
||||
<line x1="21" y1="21" x2="16.65" y2="16.65"></line>
|
||||
</svg>
|
||||
</span>
|
||||
<input type="text" name="search" value="{{ request('search') }}" placeholder="{{ __('Search machines...') }}"
|
||||
class="luxury-input py-2.5 pl-12 pr-6 block w-72">
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="overflow-x-auto pb-4">
|
||||
<table class="w-full text-left border-separate border-spacing-y-0 text-sm whitespace-nowrap">
|
||||
<thead>
|
||||
<tr class="bg-slate-50/50 dark:bg-slate-900/10">
|
||||
<th
|
||||
class="px-6 py-4 text-xs font-bold text-slate-500 dark:text-slate-400 uppercase tracking-[0.15em] border-b border-slate-100 dark:border-slate-800">
|
||||
{{ __('Machine Information') }}</th>
|
||||
<th
|
||||
class="px-6 py-4 text-xs font-bold text-slate-500 dark:text-slate-400 uppercase tracking-[0.15em] border-b border-slate-100 dark:border-slate-800 text-center">
|
||||
{{ __('Status') }}</th>
|
||||
<th
|
||||
class="px-6 py-4 text-xs font-bold text-slate-500 dark:text-slate-400 uppercase tracking-[0.15em] border-b border-slate-100 dark:border-slate-800 text-center">
|
||||
{{ __('Last Communication') }}</th>
|
||||
<th
|
||||
class="px-6 py-4 text-xs font-bold text-slate-500 dark:text-slate-400 uppercase tracking-[0.15em] border-b border-slate-100 dark:border-slate-800 text-right">
|
||||
{{ __('Actions') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="divide-y divide-slate-50 dark:divide-slate-800/80">
|
||||
@foreach($machines as $machine)
|
||||
<tr
|
||||
class="group hover:bg-slate-50/80 dark:hover:bg-slate-800/40 transition-all duration-300">
|
||||
<td class="px-6 py-6 cursor-pointer" @click="selectMachine({{ Js::from($machine) }})">
|
||||
<div class="flex items-center gap-4">
|
||||
<div
|
||||
class="w-12 h-12 rounded-2xl bg-slate-100 dark:bg-slate-800 flex items-center justify-center text-slate-400 border border-slate-200 dark:border-slate-700 group-hover:bg-cyan-500 group-hover:text-white transition-all duration-300 overflow-hidden shadow-sm shrink-0">
|
||||
@if(!empty($machine->image_urls) && isset($machine->image_urls[0]))
|
||||
<img src="{{ $machine->image_urls[0] }}"
|
||||
class="w-full h-full object-cover">
|
||||
@else
|
||||
<svg class="w-6 h-6 shrink-0" fill="none" stroke="currentColor"
|
||||
viewBox="0 0 24 24" stroke-width="1.5">
|
||||
<path stroke-linecap="round" stroke-linejoin="round"
|
||||
d="M21 7.5l-9-5.25L3 7.5m18 0l-9 5.25m9-5.25v9l-9 5.25M3 7.5l9 5.25M3 7.5v9l9 5.25m0-5.25v9" />
|
||||
</svg>
|
||||
@endif
|
||||
</div>
|
||||
<div>
|
||||
<div class="text-[17px] font-black text-slate-800 dark:text-slate-100 group-hover:text-cyan-600 dark:group-hover:text-cyan-400 transition-colors tracking-tight">
|
||||
{{ $machine->name }}</div>
|
||||
<div class="text-[11px] font-mono font-bold text-slate-400 dark:text-slate-500 uppercase tracking-widest mt-0.5">
|
||||
{{ $machine->serial_no }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td class="px-6 py-6 text-center">
|
||||
<div class="flex items-center justify-center">
|
||||
@if($machine->status === 'online' || !$machine->status)
|
||||
<div
|
||||
class="flex items-center gap-1.5 px-3 py-1.5 rounded-full bg-emerald-500/10 border border-emerald-500/20">
|
||||
<div class="relative flex h-2 w-2">
|
||||
<span
|
||||
class="animate-ping absolute inline-flex h-full w-full rounded-full bg-emerald-400 opacity-75"></span>
|
||||
<span
|
||||
class="relative inline-flex rounded-full h-2 w-2 bg-emerald-500"></span>
|
||||
</div>
|
||||
<span
|
||||
class="text-[10px] font-black text-emerald-600 dark:text-emerald-400 tracking-[0.1em] uppercase">{{
|
||||
__('Online') }}</span>
|
||||
</div>
|
||||
@elseif($machine->status === 'offline')
|
||||
<div
|
||||
class="flex items-center gap-1.5 px-3 py-1.5 rounded-full bg-slate-500/10 border border-slate-500/20">
|
||||
<div class="h-2 w-2 rounded-full bg-slate-400"></div>
|
||||
<span
|
||||
class="text-[10px] font-black text-slate-500 dark:text-slate-400 tracking-[0.1em] uppercase">{{
|
||||
__('Offline') }}</span>
|
||||
</div>
|
||||
@else
|
||||
<div
|
||||
class="flex items-center justify-center gap-1.5 px-3 py-1.5 rounded-full bg-rose-500/10 border border-rose-500/20">
|
||||
<div class="relative flex h-2 w-2">
|
||||
<span
|
||||
class="animate-ping absolute inline-flex h-full w-full rounded-full bg-rose-400 opacity-75"></span>
|
||||
<span
|
||||
class="relative inline-flex rounded-full h-2 w-2 bg-rose-500"></span>
|
||||
</div>
|
||||
<span
|
||||
class="text-[10px] font-black text-rose-600 dark:text-rose-400 tracking-[0.1em] uppercase">{{
|
||||
__('Abnormal') }}</span>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
</td>
|
||||
<td class="px-6 py-6 text-center">
|
||||
<template x-data="{ heartbeat: {{ Js::from($machine->last_heartbeat_at) }} }">
|
||||
<div class="flex flex-col items-center">
|
||||
<span class="text-sm font-black text-slate-700 dark:text-slate-200"
|
||||
x-text="formatTime(heartbeat)"></span>
|
||||
<span
|
||||
class="text-[10px] font-bold text-slate-400 dark:text-slate-500 uppercase tracking-widest mt-0.5"
|
||||
x-text="heartbeat ? heartbeat.split('T')[0] : '--'"></span>
|
||||
</div>
|
||||
</template>
|
||||
</td>
|
||||
<td class="px-6 py-6 text-right">
|
||||
<button @click="selectMachine({{ Js::from($machine) }})"
|
||||
class="p-2.5 rounded-lg bg-slate-50 dark:bg-slate-800 text-slate-400 hover:text-cyan-500 hover:bg-cyan-500/5 transition-all border border-transparent hover:border-cyan-500/20"
|
||||
title="{{ __('Manage') }}">
|
||||
<svg class="size-4" fill="none" stroke="currentColor"
|
||||
viewBox="0 0 24 24" stroke-width="2.5">
|
||||
<path stroke-linecap="round" stroke-linejoin="round"
|
||||
d="m16.862 4.487 1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L10.582 16.07a4.5 4.5 0 0 1-1.897 1.13L6 18l.8-2.685a4.5 4.5 0 0 1 1.13-1.897l8.932-8.931Zm0 0L19.5 7.125M18 14v4.75A2.25 2.25 0 0 1 15.75 21H5.25A2.25 2.25 0 0 1 3 18.75V8.25A2.25 2.25 0 0 1 5.25 6H10" />
|
||||
</svg>
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- Pagination Area -->
|
||||
<div class="mt-8">
|
||||
{{ $machines->appends(request()->query())->links('vendor.pagination.luxury') }}
|
||||
</div>
|
||||
Reference in New Issue
Block a user