[RELEASE] 晉升銷售紀錄員工卡資訊功能至正式生產環境

1. 新增 Order 模型中的 `staffCardLog` 一對一關聯關係。
2. 於 SalesController 列表與詳情查詢中進行 Eager Loading 欄位限定優化,完全避免 N+1 查詢。
3. 擴充銷售紀錄模糊搜尋,支援依員工姓名、工號(Employee ID)與感應卡號(Card UID)進行即時篩選。
4. 調整桌面版表格、手機 RWD 卡片,於員工卡支付之訂單下方呈現感應卡圖示與 `姓名 (工號)`。
5. 於訂單詳情側滑面板中新增專屬「員工卡資訊」網格區塊。
6. 補齊 Traditional Chinese(zh_TW)、English(en)、Japanese(ja)三語系之相關翻譯與搜尋框 Placeholder 提示詞。
This commit is contained in:
sky121113 2026-05-19 11:10:13 +08:00
commit cfbe4655da
7 changed files with 79 additions and 4 deletions

View File

@ -62,7 +62,13 @@ class SalesController extends Controller
];
// 1. 建立基本查詢 (套用共用過濾器:機台、日期)
$ordersQuery = Order::with(['machine:id,name,serial_no', 'invoice:id,order_id,invoice_no', 'items']);
$ordersQuery = Order::with([
'machine:id,name,serial_no',
'invoice:id,order_id,invoice_no',
'items',
'staffCardLog:id,order_id,staff_card_id',
'staffCardLog.staffCard:id,employee_id,name,card_uid'
]);
$invoicesQuery = Invoice::with(['machine:id,name,serial_no', 'order:id,order_no,flow_id,payment_type']);
$dispenseQuery = DispenseRecord::with(['order:id,order_no,flow_id', 'machine:id,name,serial_no', 'product:id,name']);
@ -88,7 +94,12 @@ class SalesController extends Controller
$q->where('order_no', 'like', "%{$search}%")
->orWhere('flow_id', 'like', "%{$search}%")
->orWhere('invoice_info', 'like', "%{$search}%")
->orWhere('member_barcode', 'like', "%{$search}%");
->orWhere('member_barcode', 'like', "%{$search}%")
->orWhereHas('staffCardLog.staffCard', function($sq) use ($search) {
$sq->where('name', 'like', "%{$search}%")
->orWhere('employee_id', 'like', "%{$search}%")
->orWhere('card_uid', 'like', "%{$search}%");
});
});
} elseif ($tab === 'invoices') {
$invoicesQuery->where(function($q) use ($search) {
@ -136,7 +147,14 @@ class SalesController extends Controller
*/
public function show(Order $order)
{
$order->load(['machine', 'invoice', 'items', 'dispenseRecords.product']);
$order->load([
'machine',
'invoice',
'items',
'dispenseRecords.product',
'staffCardLog:id,order_id,staff_card_id',
'staffCardLog.staffCard:id,employee_id,name,card_uid'
]);
return response()->json([
'success' => true,

View File

@ -136,4 +136,9 @@ class Order extends Model
{
return $this->hasMany(DispenseRecord::class);
}
public function staffCardLog()
{
return $this->hasOne(\App\Models\StaffCardLog::class);
}
}

View File

@ -1388,6 +1388,7 @@
"Search Invoice No / Flow ID...": "Search Invoice No / Flow ID...",
"Search Machine...": "Search Machine...",
"Search Order No / Flow ID / Invoice...": "Search Order No / Flow ID / Invoice...",
"Search Order No / Cards & Codes...": "Search Order No / Cards & Codes...",
"Search Product": "Search Product",
"Search Product / Slot...": "Search Product / Slot...",
"Search accounts...": "Search accounts...",
@ -1511,6 +1512,7 @@
"Spring Limit": "Spring Limit",
"Staff": "Staff",
"Staff Card": "Staff Card",
"Staff Card Info": "Staff Card Info",
"Staff Identification Management": "Staff Identification Management",
"Staff List": "Staff List",
"Staff Name": "Staff Name",

View File

@ -1388,6 +1388,7 @@
"Search Invoice No / Flow ID...": "領収書番号 / フローIDを検索...",
"Search Machine...": "機器を検索...",
"Search Order No / Flow ID / Invoice...": "注文番号 / フローID / 領収書を検索...",
"Search Order No / Cards & Codes...": "注文番号 / カード・コードを検索...",
"Search Product": "商品を検索",
"Search Product / Slot...": "商品名 / スロットを検索...",
"Search accounts...": "アカウントを検索...",
@ -1511,6 +1512,7 @@
"Spring Limit": "スプリング上限",
"Staff": "スタッフ",
"Staff Card": "スタッフカード",
"Staff Card Info": "スタッフカード情報",
"Staff Identification Management": "スタッフ識別管理",
"Staff List": "スタッフ一覧",
"Staff Name": "スタッフ名",

View File

@ -1407,6 +1407,7 @@
"Search Invoice No / Flow ID...": "搜尋 發票號碼 / 流水號...",
"Search Machine...": "搜尋機台...",
"Search Order No / Flow ID / Invoice...": "搜尋 訂單號 / 流水號 / 發票號碼...",
"Search Order No / Cards & Codes...": "搜尋 訂單號 / 卡號與代碼...",
"Search Product": "搜尋商品",
"Search Product / Slot...": "搜尋商品名稱 / 貨道...",
"Search accounts...": "搜尋帳號...",
@ -1531,6 +1532,7 @@
"Spring Limit": "彈簧貨道上限",
"Staff": "員工",
"Staff Card": "員工卡",
"Staff Card Info": "員工卡資訊",
"Staff Identification Management": "員工識別管理",
"Staff List": "員工列表",
"Staff Name": "員工姓名",

View File

@ -84,6 +84,36 @@
</div>
</section>
{{-- 員工卡資訊 --}}
@if($order->payment_type == 41 && $order->staffCardLog && $order->staffCardLog->staffCard)
<section class="space-y-4">
<div class="flex items-center gap-2 px-1">
<div class="w-1.5 h-4 bg-cyan-500 rounded-full"></div>
<h3 class="text-sm font-black text-slate-800 dark:text-white uppercase tracking-widest">{{ __('Staff Card Info') }}</h3>
</div>
<div class="grid grid-cols-2 gap-8 p-8 bg-slate-50/50 dark:bg-slate-800/30 rounded-[2rem] border border-slate-100 dark:border-slate-800">
<div class="space-y-1">
<p class="text-[10px] font-black text-slate-400 dark:text-slate-500 uppercase tracking-widest">{{ __('Staff Name') }}</p>
<p class="text-sm font-extrabold text-slate-700 dark:text-slate-200">{{ $order->staffCardLog->staffCard->name }}</p>
</div>
<div class="space-y-1">
<p class="text-[10px] font-black text-slate-400 dark:text-slate-500 uppercase tracking-widest">{{ __('Employee ID') }}</p>
<p class="text-sm font-bold text-slate-700 dark:text-slate-300 font-mono tracking-tight">{{ $order->staffCardLog->staffCard->employee_id }}</p>
</div>
<div class="space-y-1 col-span-2">
<p class="text-[10px] font-black text-slate-400 dark:text-slate-500 uppercase tracking-widest">{{ __('Card UID') }}</p>
<p class="text-xs font-black text-slate-400 dark:text-slate-500 font-mono uppercase tracking-widest">{{ $order->staffCardLog->staffCard->card_uid }}</p>
</div>
@if($order->staffCardLog->staffCard->notes)
<div class="space-y-1 col-span-2">
<p class="text-[10px] font-black text-slate-400 dark:text-slate-500 uppercase tracking-widest">{{ __('Notes') }}</p>
<p class="text-xs font-bold text-slate-500 dark:text-slate-400">{{ $order->staffCardLog->staffCard->notes }}</p>
</div>
@endif
</div>
</section>
@endif
{{-- 商品明細 --}}
<section class="space-y-4">
<div class="flex items-center justify-between px-1">

View File

@ -14,7 +14,7 @@
</span>
<input type="text" name="search" value="{{ $tab === 'orders' ? $filters['search'] : '' }}"
class="py-2.5 pl-12 pr-6 block w-full luxury-input"
placeholder="{{ __('Search Order No / Flow ID / Invoice...') }}">
placeholder="{{ __('Search Order No / Cards & Codes...') }}">
</div>
<div class="w-full lg:w-48">
@ -202,6 +202,14 @@
{{ __('Discounted') }} ${{ number_format($order->discount_amount, 0) }}
</span>
@endif
@if($order->payment_type == 41 && $order->staffCardLog && $order->staffCardLog->staffCard)
<span class="text-[10px] text-cyan-600 dark:text-cyan-400 font-extrabold mt-1.5 flex items-center gap-1">
<svg class="w-3.5 h-3.5 shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="2.5">
<path stroke-linecap="round" stroke-linejoin="round" d="M15 9h3.75M15 12h3.75M15 15h3.75M4.5 19.5h15a2.25 2.25 0 002.25-2.25V6.75A2.25 2.25 0 0019.5 4.5h-15a2.25 2.25 0 00-2.25 2.25v10.5A2.25 2.25 0 004.5 19.5zm6-10.125a1.875 1.875 0 11-3.75 0 1.875 1.875 0 013.75 0zm1.294 6.336a6.721 6.721 0 01-3.17.789 6.721 6.721 0 01-3.168-.789 3.376 3.376 0 016.338 0z" />
</svg>
{{ $order->staffCardLog->staffCard->name }} ({{ $order->staffCardLog->staffCard->employee_id }})
</span>
@endif
</div>
</td>
<td class="px-6 py-6 whitespace-nowrap">
@ -331,6 +339,14 @@
<span class="text-[10px] px-1.5 py-0.5 rounded bg-slate-100 dark:bg-slate-800/50 text-slate-500">{{
$paymentTypes[$order->payment_type] ?? '??' }}</span>
</p>
@if($order->payment_type == 41 && $order->staffCardLog && $order->staffCardLog->staffCard)
<div class="text-[10px] text-cyan-600 dark:text-cyan-400 font-extrabold mt-1 flex items-center gap-1">
<svg class="w-3.5 h-3.5 shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="2.5">
<path stroke-linecap="round" stroke-linejoin="round" d="M15 9h3.75M15 12h3.75M15 15h3.75M4.5 19.5h15a2.25 2.25 0 002.25-2.25V6.75A2.25 2.25 0 0019.5 4.5h-15a2.25 2.25 0 00-2.25 2.25v10.5A2.25 2.25 0 004.5 19.5zm6-10.125a1.875 1.875 0 11-3.75 0 1.875 1.875 0 013.75 0zm1.294 6.336a6.721 6.721 0 01-3.17.789 6.721 6.721 0 01-3.168-.789 3.376 3.376 0 016.338 0z" />
</svg>
{{ $order->staffCardLog->staffCard->name }} ({{ $order->staffCardLog->staffCard->employee_id }})
</div>
@endif
</div>
<div>
<p class="text-[10px] font-black text-slate-400 dark:text-slate-500 uppercase tracking-widest mb-1">{{