[FEAT] 交易訂單與電子發票列表新增可編輯備註欄位
1. 新增共用元件 x-remark-cell:列表內嵌備註編輯,點擊文字進入編輯,儲存走 AJAX PATCH 並以 toast 提示,不重整頁面;空白時顯示淡色「新增備註」提示。 2. 交易訂單列表(tab-orders)桌面表格於「發票號碼」與「操作」間新增備註欄,手機卡片於操作鈕上方新增備註區塊,接 order.remark,並同步調整空狀態 colspan。 3. 電子發票列表(tab-invoices)桌面表格於「關聯訂單」與「操作」間新增備註欄,手機卡片新增備註區塊,接 invoice.remark,並同步調整空狀態 colspan。 4. 列表與訂單詳情面板共用同一 remark 欄位,任一處編輯皆同步。 5. 新增三語系 key「Add Remark(新增備註)」,zh_TW/en/ja 對齊排序至 2573 鍵。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
4766ec6939
commit
ae4c9fb93a
@ -63,6 +63,7 @@
|
|||||||
"Add Pass Code": "Add Pass Code",
|
"Add Pass Code": "Add Pass Code",
|
||||||
"Add Pickup Code": "Add Pickup Code",
|
"Add Pickup Code": "Add Pickup Code",
|
||||||
"Add Product": "Add Product",
|
"Add Product": "Add Product",
|
||||||
|
"Add Remark": "Add Remark",
|
||||||
"Add Role": "Add Role",
|
"Add Role": "Add Role",
|
||||||
"Add Staff Card": "Add Staff Card",
|
"Add Staff Card": "Add Staff Card",
|
||||||
"Add Warehouse": "Add Warehouse",
|
"Add Warehouse": "Add Warehouse",
|
||||||
|
|||||||
@ -63,6 +63,7 @@
|
|||||||
"Add Pass Code": "パスコード追加",
|
"Add Pass Code": "パスコード追加",
|
||||||
"Add Pickup Code": "受取コード追加",
|
"Add Pickup Code": "受取コード追加",
|
||||||
"Add Product": "商品追加",
|
"Add Product": "商品追加",
|
||||||
|
"Add Remark": "備考を追加",
|
||||||
"Add Role": "ロール追加",
|
"Add Role": "ロール追加",
|
||||||
"Add Staff Card": "スタッフカード追加",
|
"Add Staff Card": "スタッフカード追加",
|
||||||
"Add Warehouse": "倉庫追加",
|
"Add Warehouse": "倉庫追加",
|
||||||
|
|||||||
@ -63,6 +63,7 @@
|
|||||||
"Add Pass Code": "新增通行碼",
|
"Add Pass Code": "新增通行碼",
|
||||||
"Add Pickup Code": "新增取貨碼",
|
"Add Pickup Code": "新增取貨碼",
|
||||||
"Add Product": "新增商品",
|
"Add Product": "新增商品",
|
||||||
|
"Add Remark": "新增備註",
|
||||||
"Add Role": "新增角色",
|
"Add Role": "新增角色",
|
||||||
"Add Staff Card": "新增員工識別卡",
|
"Add Staff Card": "新增員工識別卡",
|
||||||
"Add Warehouse": "新增倉庫",
|
"Add Warehouse": "新增倉庫",
|
||||||
|
|||||||
@ -175,6 +175,10 @@
|
|||||||
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">
|
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">
|
||||||
{{ __('Associated Order') }}
|
{{ __('Associated Order') }}
|
||||||
</th>
|
</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">
|
||||||
|
{{ __('Remark') }}
|
||||||
|
</th>
|
||||||
<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">
|
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">
|
||||||
{{ __('Action') }}
|
{{ __('Action') }}
|
||||||
@ -235,6 +239,9 @@
|
|||||||
{{ $invoice->order->order_no ?? '---' }}
|
{{ $invoice->order->order_no ?? '---' }}
|
||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
|
<td class="px-6 py-6">
|
||||||
|
<x-remark-cell :url="route('admin.sales.invoices.remark', $invoice)" :value="$invoice->remark" />
|
||||||
|
</td>
|
||||||
<td class="px-6 py-6 text-right" @click.stop>
|
<td class="px-6 py-6 text-right" @click.stop>
|
||||||
<div class="flex items-center justify-end gap-1.5">
|
<div class="flex items-center justify-end gap-1.5">
|
||||||
@if(in_array($st, ['pending', 'failed']))
|
@if(in_array($st, ['pending', 'failed']))
|
||||||
@ -275,8 +282,8 @@
|
|||||||
</tr>
|
</tr>
|
||||||
@empty
|
@empty
|
||||||
<tr>
|
<tr>
|
||||||
<td colspan="6" class="py-20 text-center">
|
<td colspan="8" class="py-20 text-center">
|
||||||
<x-empty-state mode="table" colspan="6" :message="__('No invoices found')" />
|
<x-empty-state mode="table" colspan="8" :message="__('No invoices found')" />
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
@endforelse
|
@endforelse
|
||||||
@ -364,6 +371,12 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{{-- Remark --}}
|
||||||
|
<div class="mb-6">
|
||||||
|
<p class="text-[10px] font-black text-slate-400 dark:text-slate-500 uppercase tracking-widest mb-1">{{ __('Remark') }}</p>
|
||||||
|
<x-remark-cell :url="route('admin.sales.invoices.remark', $invoice)" :value="$invoice->remark" />
|
||||||
|
</div>
|
||||||
|
|
||||||
{{-- Action Buttons --}}
|
{{-- Action Buttons --}}
|
||||||
<div class="flex flex-col gap-3">
|
<div class="flex flex-col gap-3">
|
||||||
<button @click="openDetail({{ $invoice->order_id }})"
|
<button @click="openDetail({{ $invoice->order_id }})"
|
||||||
|
|||||||
@ -179,6 +179,10 @@
|
|||||||
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">
|
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">
|
||||||
{{ __('Invoice Number') }}
|
{{ __('Invoice Number') }}
|
||||||
</th>
|
</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">
|
||||||
|
{{ __('Remark') }}
|
||||||
|
</th>
|
||||||
<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">
|
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">
|
||||||
{{ __('Action') }}
|
{{ __('Action') }}
|
||||||
@ -308,6 +312,9 @@
|
|||||||
<span class="text-xs font-bold text-slate-300 dark:text-slate-700 tracking-widest">---</span>
|
<span class="text-xs font-bold text-slate-300 dark:text-slate-700 tracking-widest">---</span>
|
||||||
@endif
|
@endif
|
||||||
</td>
|
</td>
|
||||||
|
<td class="px-6 py-6">
|
||||||
|
<x-remark-cell :url="route('admin.sales.orders.remark', $order)" :value="$order->remark" />
|
||||||
|
</td>
|
||||||
<td class="px-6 py-6 text-right">
|
<td class="px-6 py-6 text-right">
|
||||||
<button @click.stop="openDetail({{ $order->id }})"
|
<button @click.stop="openDetail({{ $order->id }})"
|
||||||
class="p-2.5 rounded-xl text-slate-400 hover:text-cyan-500 hover:bg-cyan-500/5 dark:hover:bg-cyan-500/10 border border-transparent hover:border-cyan-500/20 transition-all group/btn"
|
class="p-2.5 rounded-xl text-slate-400 hover:text-cyan-500 hover:bg-cyan-500/5 dark:hover:bg-cyan-500/10 border border-transparent hover:border-cyan-500/20 transition-all group/btn"
|
||||||
@ -324,8 +331,8 @@
|
|||||||
</tr>
|
</tr>
|
||||||
@empty
|
@empty
|
||||||
<tr>
|
<tr>
|
||||||
<td colspan="8" class="py-20 text-center">
|
<td colspan="9" class="py-20 text-center">
|
||||||
<x-empty-state mode="table" colspan="8" :message="__('No transaction orders found')" />
|
<x-empty-state mode="table" colspan="9" :message="__('No transaction orders found')" />
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
@endforelse
|
@endforelse
|
||||||
@ -456,6 +463,12 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{{-- Remark --}}
|
||||||
|
<div class="mb-6">
|
||||||
|
<p class="text-[10px] font-black text-slate-400 dark:text-slate-500 uppercase tracking-widest mb-1">{{ __('Remark') }}</p>
|
||||||
|
<x-remark-cell :url="route('admin.sales.orders.remark', $order)" :value="$order->remark" />
|
||||||
|
</div>
|
||||||
|
|
||||||
{{-- Action Buttons --}}
|
{{-- Action Buttons --}}
|
||||||
<div class="flex items-center gap-3">
|
<div class="flex items-center gap-3">
|
||||||
<button @click="openDetail({{ $order->id }})"
|
<button @click="openDetail({{ $order->id }})"
|
||||||
|
|||||||
50
resources/views/components/remark-cell.blade.php
Normal file
50
resources/views/components/remark-cell.blade.php
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
@props([
|
||||||
|
'url', // PATCH 端點(更新 remark)
|
||||||
|
'value' => null, // 目前備註內容
|
||||||
|
])
|
||||||
|
|
||||||
|
{{-- 列表內嵌備註編輯:點擊文字進入編輯,fetch 儲存後 toast。@click.stop 避免觸發整列的開啟詳情。 --}}
|
||||||
|
<div @click.stop class="min-w-[150px] max-w-[220px]"
|
||||||
|
x-data="{
|
||||||
|
editing: false,
|
||||||
|
saving: false,
|
||||||
|
value: @js($value ?? ''),
|
||||||
|
original: @js($value ?? ''),
|
||||||
|
cancel() { this.value = this.original; this.editing = false; },
|
||||||
|
save() {
|
||||||
|
this.saving = true;
|
||||||
|
fetch(@js($url), {
|
||||||
|
method: 'PATCH',
|
||||||
|
headers: { 'Content-Type': 'application/json', 'Accept': 'application/json', 'X-CSRF-TOKEN': @js(csrf_token()), 'X-Requested-With': 'XMLHttpRequest' },
|
||||||
|
body: JSON.stringify({ remark: this.value })
|
||||||
|
}).then(r => { if (!r.ok) throw 0; return r.json(); })
|
||||||
|
.then(d => { this.original = this.value; this.editing = false; window.showToast?.((d && d.message) || @js(__('Remark updated')), 'success'); })
|
||||||
|
.catch(() => window.showToast?.(@js(__('Operation failed')), 'error'))
|
||||||
|
.finally(() => this.saving = false);
|
||||||
|
}
|
||||||
|
}">
|
||||||
|
<template x-if="!editing">
|
||||||
|
<button type="button" @click="editing = true" class="group/rm flex items-start gap-1.5 text-left w-full">
|
||||||
|
<span class="text-sm font-bold whitespace-pre-wrap break-words line-clamp-2"
|
||||||
|
:class="value ? 'text-slate-600 dark:text-slate-300' : 'text-slate-300 dark:text-slate-600'"
|
||||||
|
x-text="value || @js(__('Add Remark'))"></span>
|
||||||
|
<svg class="w-3.5 h-3.5 shrink-0 mt-0.5 text-slate-300 dark:text-slate-600 opacity-0 group-hover/rm:opacity-100 transition-opacity"
|
||||||
|
fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="2">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M16.862 4.487l1.687-1.688a1.875 1.875 0 112.652 2.652L10.582 16.07a4.5 4.5 0 01-1.897 1.13L6 18l.8-2.685a4.5 4.5 0 011.13-1.897l8.932-8.931z" />
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</template>
|
||||||
|
<template x-if="editing">
|
||||||
|
<div class="space-y-2">
|
||||||
|
<textarea x-model="value" rows="2" maxlength="1000"
|
||||||
|
placeholder="{{ __('Enter remark (optional)') }}"
|
||||||
|
class="luxury-input w-full text-xs py-2 px-3 resize-none"></textarea>
|
||||||
|
<div class="flex items-center gap-1.5">
|
||||||
|
<button type="button" @click="save()" :disabled="saving"
|
||||||
|
class="px-3 py-1.5 rounded-lg bg-cyan-500 hover:bg-cyan-600 text-white font-black text-[10px] uppercase tracking-widest disabled:opacity-60">{{ __('Save') }}</button>
|
||||||
|
<button type="button" @click="cancel()" :disabled="saving"
|
||||||
|
class="px-3 py-1.5 rounded-lg bg-slate-100 dark:bg-slate-800 text-slate-600 dark:text-slate-300 font-black text-[10px] uppercase tracking-widest disabled:opacity-60">{{ __('Cancel') }}</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
Loading…
Reference in New Issue
Block a user