feat(sales): 升級銷售紀錄高奢翡翠綠導出下拉選單與修復進度條卡死

This commit is contained in:
sky121113 2026-05-19 12:33:06 +08:00
parent b5259a5b28
commit 1aa5aed72e
7 changed files with 499 additions and 2 deletions

View File

@ -125,6 +125,12 @@ class SalesController extends Controller
if ($status) $ordersQuery->where('status', $status);
}
// 匯出功能攔截
if ($request->filled('export')) {
$exportType = $request->input('export');
return $this->handleExport($tab, $exportType, $ordersQuery, $invoicesQuery, $dispenseQuery);
}
// 3. 執行分頁 (使用獨立的 pageName)
$perPage = $request->input('per_page', 10);
$data['orders'] = $ordersQuery->latest()->paginate($perPage, ['*'], 'orders_page')->withQueryString();
@ -597,4 +603,272 @@ class SalesController extends Controller
'description' => '來店優惠活動設定',
]);
}
/**
* 處理銷售中心資料匯出 (CSV 串流下載)
*/
private function handleExport($tab, $type, $ordersQuery, $invoicesQuery, $dispenseQuery)
{
$isExcel = ($type === 'excel');
$ext = $isExcel ? 'xls' : 'csv';
$contentType = $isExcel ? 'application/vnd.ms-excel; charset=utf-8' : 'text/csv; charset=utf-8';
$filename = '';
$headers = [];
$callback = null;
if ($tab === 'orders') {
$filename = '交易紀錄_' . now()->format('YmdHis') . '.' . $ext;
$headers = [
__('Order Number'),
__('Transaction Time'),
__('Machine Name'),
__('Machine Serial No'),
__('Product Items'),
__('Quantity'),
__('Original Amount'),
__('Discount Amount'),
__('Payment Amount'),
__('Payment Type'),
__('Status'),
__('Invoice Number'),
__('Staff Name'),
__('Staff ID'),
__('Card UID'),
];
// 預先載入關聯以防 N+1
$ordersQuery->with([
'machine:id,name,serial_no',
'invoice:id,order_id,invoice_no',
'items:id,order_id,product_name,quantity',
'staffCardLog:id,order_id,staff_card_id',
'staffCardLog.staffCard:id,employee_id,name,card_uid'
]);
$callback = function () use ($ordersQuery, $headers, $isExcel) {
$file = fopen('php://output', 'w');
if ($isExcel) {
fwrite($file, '<html xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:x="urn:schemas-microsoft-com:office:excel" xmlns="http://www.w3.org/TR/REC-html40">');
fwrite($file, '<head><meta charset="utf-8"/><style>table { border-collapse: collapse; } th, td { border: 1px solid #cbd5e1; padding: 8px 12px; text-align: left; } th { background-color: #f1f5f9; font-weight: bold; }</style></head><body>');
fwrite($file, '<table><thead><tr>');
foreach ($headers as $header) {
fwrite($file, '<th>' . htmlspecialchars($header) . '</th>');
}
fwrite($file, '</tr></thead><tbody>');
} else {
fwrite($file, "\xEF\xBB\xBF"); // 注入 UTF-8 BOM
fputcsv($file, $headers);
}
// 分批 (Chunk) 查詢,每次 500 筆,確保常數記憶體用量
$ordersQuery->latest()->chunk(500, function ($orders) use ($file, $isExcel) {
foreach ($orders as $order) {
$productSummary = $order->items->map(function ($item) {
return $item->product_name . ' x' . number_format($item->quantity, 0);
})->implode(', ');
$totalQty = $order->items->sum('quantity');
$row = [
$order->order_no,
$order->created_at->format('Y-m-d H:i:s'),
$order->machine->name ?? 'Unknown',
$order->machine->serial_no ?? '---',
$productSummary ?: '---',
$totalQty,
number_format($order->total_amount, 2, '.', ''),
number_format($order->discount_amount, 2, '.', ''),
number_format($order->pay_amount, 2, '.', ''),
$order->payment_type_label,
__($order->status),
$order->invoice->invoice_no ?? '---',
$order->staffCardLog->staffCard->name ?? '---',
$order->staffCardLog->staffCard->employee_id ?? '---',
$order->staffCardLog->staffCard->card_uid ?? '---',
];
if ($isExcel) {
fwrite($file, '<tr>');
foreach ($row as $val) {
fwrite($file, '<td>' . htmlspecialchars($val) . '</td>');
}
fwrite($file, '</tr>');
} else {
fputcsv($file, $row);
}
}
});
if ($isExcel) {
fwrite($file, '</tbody></table></body></html>');
}
fclose($file);
};
} elseif ($tab === 'invoices') {
$filename = '電子發票紀錄_' . now()->format('YmdHis') . '.' . $ext;
$headers = [
__('Invoice Number'),
__('Invoice Date'),
__('Flow ID'),
__('Machine Name'),
__('Machine Serial No'),
__('Associated Order'),
__('Amount'),
__('Status'),
];
// 預先載入關聯
$invoicesQuery->with([
'machine:id,name,serial_no',
'order:id,order_no'
]);
$callback = function () use ($invoicesQuery, $headers, $isExcel) {
$file = fopen('php://output', 'w');
if ($isExcel) {
fwrite($file, '<html xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:x="urn:schemas-microsoft-com:office:excel" xmlns="http://www.w3.org/TR/REC-html40">');
fwrite($file, '<head><meta charset="utf-8"/><style>table { border-collapse: collapse; } th, td { border: 1px solid #cbd5e1; padding: 8px 12px; text-align: left; } th { background-color: #f1f5f9; font-weight: bold; }</style></head><body>');
fwrite($file, '<table><thead><tr>');
foreach ($headers as $header) {
fwrite($file, '<th>' . htmlspecialchars($header) . '</th>');
}
fwrite($file, '</tr></thead><tbody>');
} else {
fwrite($file, "\xEF\xBB\xBF");
fputcsv($file, $headers);
}
$invoicesQuery->latest()->chunk(500, function ($invoices) use ($file, $isExcel) {
foreach ($invoices as $inv) {
// 狀態判斷邏輯需與 tab-invoices.blade.php 完全一致
$status = 'valid';
if (empty($inv->invoice_no)) $status = 'failed';
if ($inv->rtn_code === 'void') $status = 'void';
$statusMap = [
'valid' => __('Valid'),
'void' => __('Void'),
'failed' => __('Failed'),
'refunded' => __('Refunded'),
];
$statusLabel = $statusMap[$status] ?? $status;
$row = [
$inv->invoice_no ?: '---',
$inv->invoice_date ?: '---',
$inv->flow_id ?: '---',
$inv->machine->name ?? ($inv->order->machine->name ?? 'Unknown'),
$inv->machine->serial_no ?? ($inv->order->machine->serial_no ?? '---'),
$inv->order->order_no ?? '---',
number_format($inv->amount, 2, '.', ''),
$statusLabel,
];
if ($isExcel) {
fwrite($file, '<tr>');
foreach ($row as $val) {
fwrite($file, '<td>' . htmlspecialchars($val) . '</td>');
}
fwrite($file, '</tr>');
} else {
fputcsv($file, $row);
}
}
});
if ($isExcel) {
fwrite($file, '</tbody></table></body></html>');
}
fclose($file);
};
} elseif ($tab === 'dispense') {
$filename = '遠端出貨紀錄_' . now()->format('YmdHis') . '.' . $ext;
$headers = [
__('Machine'),
__('Machine Serial No'),
__('Product Name'),
__('Slot No'),
__('Amount'),
__('Dispense Status'),
__('Dispense Time'),
__('Associated Order'),
];
// 預先載入關聯
$dispenseQuery->with([
'machine:id,name,serial_no',
'product:id,name',
'order:id,order_no'
]);
$callback = function () use ($dispenseQuery, $headers, $isExcel) {
$file = fopen('php://output', 'w');
if ($isExcel) {
fwrite($file, '<html xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:x="urn:schemas-microsoft-com:office:excel" xmlns="http://www.w3.org/TR/REC-html40">');
fwrite($file, '<head><meta charset="utf-8"/><style>table { border-collapse: collapse; } th, td { border: 1px solid #cbd5e1; padding: 8px 12px; text-align: left; } th { background-color: #f1f5f9; font-weight: bold; }</style></head><body>');
fwrite($file, '<table><thead><tr>');
foreach ($headers as $header) {
fwrite($file, '<th>' . htmlspecialchars($header) . '</th>');
}
fwrite($file, '</tr></thead><tbody>');
} else {
fwrite($file, "\xEF\xBB\xBF");
fputcsv($file, $headers);
}
$dispenseQuery->latest()->chunk(500, function ($logs) use ($file, $isExcel) {
foreach ($logs as $log) {
// 出貨狀態對照,需與 tab-dispense.blade.php 完全一致
$statusMap = [
'success' => __('Dispense Success'),
'failed' => __('Dispense Failed'),
'pending' => __('Dispense Pending'),
'1' => __('Dispense Success'),
'0' => __('Dispense Failed'),
];
$statusKey = (string)($log->dispense_status ?? 'pending');
$statusLabel = $statusMap[$statusKey] ?? $statusKey;
$row = [
$log->machine->name ?? 'Unknown',
$log->machine->serial_no ?? '---',
$log->product->name ?? 'Unknown Product',
$log->slot_no,
number_format($log->amount, 2, '.', ''),
$statusLabel,
$log->machine_time ? $log->machine_time->format('Y-m-d H:i:s') : '---',
$log->order->order_no ?? '---',
];
if ($isExcel) {
fwrite($file, '<tr>');
foreach ($row as $val) {
fwrite($file, '<td>' . htmlspecialchars($val) . '</td>');
}
fwrite($file, '</tr>');
} else {
fputcsv($file, $row);
}
}
});
if ($isExcel) {
fwrite($file, '</tbody></table></body></html>');
}
fclose($file);
};
}
if ($callback) {
return response()->streamDownload($callback, $filename, [
'Content-Type' => $contentType,
'Cache-Control' => 'no-cache, must-revalidate',
'Pragma' => 'no-cache',
'Expires' => '0',
]);
}
return redirect()->back();
}
}

View File

@ -2085,5 +2085,9 @@
"Total Net Profit": "總淨利潤",
"Gross Margin": "毛利率",
"No product data matching search criteria": "沒有符合搜尋條件的商品資料",
"Analyze Solely": "單獨分析"
"Analyze Solely": "單獨分析",
"Order Number": "訂單編號",
"Product Items": "商品品項",
"Original Amount": "應付金額",
"Discount Amount": "折扣金額"
}

View File

@ -140,7 +140,8 @@
<p class="text-xs text-slate-400 mb-4 leading-relaxed">
{{ __('Please use our standard template to ensure data compatibility.') }}
</p>
<a href="{{ route('admin.data-config.staff-cards.template') }}"
<a href="{{ route('admin.data-config.staff-cards.template') }}" download
@click="setTimeout(() => { const bar = document.getElementById('top-loading-bar'); if(bar) bar.classList.remove('loading'); }, 1000);"
class="inline-flex items-center gap-2 text-sm font-bold text-cyan-600 hover:text-cyan-700 transition-colors group">
<span>{{ __('Download Template') }}</span>
<svg class="w-4 h-4 transition-transform group-hover:translate-y-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">

View File

@ -196,6 +196,131 @@ function salesCenter() {
console.error('Failed to load order detail:', err);
this.showPanel = false;
});
},
exportData(type) {
const container = document.getElementById('tab-' + this.activeTab + '-container');
let params = new URLSearchParams();
params.set('tab', this.activeTab);
params.set('export', type);
if (container) {
const form = container.querySelector('form');
if (form) {
const formData = new FormData(form);
formData.forEach((value, key) => {
if (value && value.trim() !== '') {
if (key !== 'tab' && key !== 'export') {
params.append(key, value);
}
}
});
}
}
// 使用隱藏的 iframe 進行下載,避免觸發主視窗的 beforeunload 事件,
// 從而防止全域的頂部進度條 (top-loading-bar) 被觸發並卡在 95% 的位置。
let iframe = document.getElementById('export-download-iframe');
if (!iframe) {
iframe = document.createElement('iframe');
iframe.id = 'export-download-iframe';
iframe.style.display = 'none';
document.body.appendChild(iframe);
}
iframe.src = `${window.location.pathname}?${params.toString()}`;
// 顯示成功提示訊息,與商品報表保持一致
if (type === 'csv') {
window.showToast?.('CSV 報表導出成功', 'success');
} else if (type === 'excel') {
window.showToast?.('Excel 報表導出成功', 'success');
}
},
copyTableData() {
const container = document.getElementById('tab-' + this.activeTab + '-container');
if (!container) return;
const table = container.querySelector('table');
if (!table) return;
let headers = [];
table.querySelectorAll('thead th').forEach((th, idx, arr) => {
if (idx < arr.length - 1) {
headers.push(th.innerText.trim().replace(/\s+/g, ' '));
}
});
let rows = [headers.join('\t')];
table.querySelectorAll('tbody tr').forEach(tr => {
if (tr.querySelector('td.colspan') || tr.querySelector('td[colspan]')) return;
let cells = [];
tr.querySelectorAll('td').forEach((td, idx, arr) => {
if (idx < arr.length - 1) {
let text = td.innerText.trim().replace(/\r?\n/g, ' ').replace(/\s+/g, ' ');
cells.push(text);
}
});
if (cells.length > 0) {
rows.push(cells.join('\t'));
}
});
navigator.clipboard.writeText(rows.join('\n')).then(() => {
window.showToast?.('已成功將明細複製至剪貼簿', 'success');
}).catch(err => {
console.error('Clipboard copy failed:', err);
window.showToast?.('複製失敗,瀏覽器權限可能不足', 'error');
});
},
printTable() {
const container = document.getElementById('tab-' + this.activeTab + '-container');
if (!container) return;
const table = container.querySelector('table');
if (!table) return;
const clonedTable = table.cloneNode(true);
// 移除所有 SVG 圖標,防止列印或 PDF 輸出時因為沒有載入 Tailwind 樣式而顯示巨大黑色區塊
clonedTable.querySelectorAll('svg').forEach(svg => svg.remove());
clonedTable.querySelectorAll('tr').forEach(tr => {
const cells = tr.querySelectorAll('th, td');
if (cells.length > 0) {
cells[cells.length - 1].remove();
}
});
let tabTitle = '';
if (this.activeTab === 'orders') tabTitle = '交易紀錄';
else if (this.activeTab === 'invoices') tabTitle = '電子發票';
else if (this.activeTab === 'dispense') tabTitle = '遠端出貨紀錄';
const printWindow = window.open('', '_blank');
let html = `<html><head><title>${tabTitle}</title>`;
html += `<style>
body { font-family: system-ui, -apple-system, sans-serif; padding: 30px; color: #1e293b; }
h1 { font-size: 24px; font-weight: 800; margin-bottom: 5px; }
.subtitle { font-size: 13px; font-weight: 600; color: #64748b; margin-bottom: 25px; }
table { width: 100%; border-collapse: collapse; margin-top: 20px; font-size: 12px; }
th, td { border: 1px solid #cbd5e1; padding: 10px 12px; text-align: left; }
th { background-color: #f1f5f9; font-weight: bold; color: #334155; }
@media print {
body { padding: 0; }
}
</style></head><body>`;
html += `<h1>${tabTitle}</h1>`;
html += `<div class="subtitle">列印時間:${new Date().toLocaleString()}</div>`;
html += clonedTable.outerHTML;
html += `</body></html>`;
printWindow.document.write(html);
printWindow.document.close();
printWindow.focus();
setTimeout(() => {
printWindow.print();
printWindow.close();
}, 250);
}
}
}

View File

@ -100,6 +100,37 @@
d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15" />
</svg>
</button>
<!-- Exporters Dropdown -->
<div class="relative flex items-center gap-2" x-data="{ exportOpen: false }">
<button type="button" @click="exportOpen = !exportOpen" @click.away="exportOpen = false"
class="p-2.5 rounded-xl bg-emerald-500 text-white hover:bg-emerald-600 shadow-lg shadow-emerald-500/25 transition-all active:scale-95 flex items-center gap-2 text-xs font-bold"
title="{{ __('Export Report') }}">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="2.5">
<path stroke-linecap="round" stroke-linejoin="round" d="M3 16.5v2.25A2.25 2.25 0 0 0 5.25 21h13.5A2.25 2.25 0 0 0 21 18.75V16.5M16.5 12 12 16.5m0 0L7.5 12m4.5 4.5V3" />
</svg>
<svg class="w-3 h-3 text-white/80 transition-transform duration-200" :class="exportOpen ? 'rotate-180' : ''" fill="none" stroke="currentColor" stroke-width="2.5" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" d="m19.5 8.25-7.5 7.5-7.5-7.5" />
</svg>
</button>
<!-- Exporter Menu -->
<div x-show="exportOpen" x-transition
class="absolute right-0 top-full mt-2 bg-white dark:bg-slate-900 border border-slate-100 dark:border-slate-800 shadow-xl rounded-2xl p-2 z-30 min-w-[160px]"
x-cloak>
<button type="button" @click="copyTableData(); exportOpen = false" class="w-full text-left py-2 px-3 hover:bg-slate-50 dark:hover:bg-slate-800 text-xs font-bold text-slate-700 dark:text-slate-300 rounded-xl transition-all flex items-center gap-2">
📋 {{ __('Copy to Clipboard') }}
</button>
<button type="button" @click="exportData('csv'); exportOpen = false" class="w-full text-left py-2 px-3 hover:bg-slate-50 dark:hover:bg-slate-800 text-xs font-bold text-slate-700 dark:text-slate-300 rounded-xl transition-all flex items-center gap-2">
📄 {{ __('Export to CSV') }}
</button>
<button type="button" @click="exportData('excel'); exportOpen = false" class="w-full text-left py-2 px-3 hover:bg-slate-50 dark:hover:bg-slate-800 text-xs font-bold text-slate-700 dark:text-slate-300 rounded-xl transition-all flex items-center gap-2">
📊 {{ __('Export to Excel') }}
</button>
<button type="button" @click="printTable(); exportOpen = false" class="w-full text-left py-2 px-3 hover:bg-slate-50 dark:hover:bg-slate-800 text-xs font-bold text-slate-700 dark:text-slate-300 rounded-xl transition-all flex items-center gap-2">
🖨️ {{ __('Print & PDF') }}
</button>
</div>
</div>
</div>
</form>

View File

@ -101,6 +101,37 @@
d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15" />
</svg>
</button>
<!-- Exporters Dropdown -->
<div class="relative flex items-center gap-2" x-data="{ exportOpen: false }">
<button type="button" @click="exportOpen = !exportOpen" @click.away="exportOpen = false"
class="p-2.5 rounded-xl bg-emerald-500 text-white hover:bg-emerald-600 shadow-lg shadow-emerald-500/25 transition-all active:scale-95 flex items-center gap-2 text-xs font-bold"
title="{{ __('Export Report') }}">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="2.5">
<path stroke-linecap="round" stroke-linejoin="round" d="M3 16.5v2.25A2.25 2.25 0 0 0 5.25 21h13.5A2.25 2.25 0 0 0 21 18.75V16.5M16.5 12 12 16.5m0 0L7.5 12m4.5 4.5V3" />
</svg>
<svg class="w-3 h-3 text-white/80 transition-transform duration-200" :class="exportOpen ? 'rotate-180' : ''" fill="none" stroke="currentColor" stroke-width="2.5" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" d="m19.5 8.25-7.5 7.5-7.5-7.5" />
</svg>
</button>
<!-- Exporter Menu -->
<div x-show="exportOpen" x-transition
class="absolute right-0 top-full mt-2 bg-white dark:bg-slate-900 border border-slate-100 dark:border-slate-800 shadow-xl rounded-2xl p-2 z-30 min-w-[160px]"
x-cloak>
<button type="button" @click="copyTableData(); exportOpen = false" class="w-full text-left py-2 px-3 hover:bg-slate-50 dark:hover:bg-slate-800 text-xs font-bold text-slate-700 dark:text-slate-300 rounded-xl transition-all flex items-center gap-2">
📋 {{ __('Copy to Clipboard') }}
</button>
<button type="button" @click="exportData('csv'); exportOpen = false" class="w-full text-left py-2 px-3 hover:bg-slate-50 dark:hover:bg-slate-800 text-xs font-bold text-slate-700 dark:text-slate-300 rounded-xl transition-all flex items-center gap-2">
📄 {{ __('Export to CSV') }}
</button>
<button type="button" @click="exportData('excel'); exportOpen = false" class="w-full text-left py-2 px-3 hover:bg-slate-50 dark:hover:bg-slate-800 text-xs font-bold text-slate-700 dark:text-slate-300 rounded-xl transition-all flex items-center gap-2">
📊 {{ __('Export to Excel') }}
</button>
<button type="button" @click="printTable(); exportOpen = false" class="w-full text-left py-2 px-3 hover:bg-slate-50 dark:hover:bg-slate-800 text-xs font-bold text-slate-700 dark:text-slate-300 rounded-xl transition-all flex items-center gap-2">
🖨️ {{ __('Print & PDF') }}
</button>
</div>
</div>
</div>
</form>

View File

@ -101,6 +101,37 @@
d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15" />
</svg>
</button>
<!-- Exporters Dropdown -->
<div class="relative flex items-center gap-2" x-data="{ exportOpen: false }">
<button type="button" @click="exportOpen = !exportOpen" @click.away="exportOpen = false"
class="p-2.5 rounded-xl bg-emerald-500 text-white hover:bg-emerald-600 shadow-lg shadow-emerald-500/25 transition-all active:scale-95 flex items-center gap-2 text-xs font-bold"
title="{{ __('Export Report') }}">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="2.5">
<path stroke-linecap="round" stroke-linejoin="round" d="M3 16.5v2.25A2.25 2.25 0 0 0 5.25 21h13.5A2.25 2.25 0 0 0 21 18.75V16.5M16.5 12 12 16.5m0 0L7.5 12m4.5 4.5V3" />
</svg>
<svg class="w-3 h-3 text-white/80 transition-transform duration-200" :class="exportOpen ? 'rotate-180' : ''" fill="none" stroke="currentColor" stroke-width="2.5" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" d="m19.5 8.25-7.5 7.5-7.5-7.5" />
</svg>
</button>
<!-- Exporter Menu -->
<div x-show="exportOpen" x-transition
class="absolute right-0 top-full mt-2 bg-white dark:bg-slate-900 border border-slate-100 dark:border-slate-800 shadow-xl rounded-2xl p-2 z-30 min-w-[160px]"
x-cloak>
<button type="button" @click="copyTableData(); exportOpen = false" class="w-full text-left py-2 px-3 hover:bg-slate-50 dark:hover:bg-slate-800 text-xs font-bold text-slate-700 dark:text-slate-300 rounded-xl transition-all flex items-center gap-2">
📋 {{ __('Copy to Clipboard') }}
</button>
<button type="button" @click="exportData('csv'); exportOpen = false" class="w-full text-left py-2 px-3 hover:bg-slate-50 dark:hover:bg-slate-800 text-xs font-bold text-slate-700 dark:text-slate-300 rounded-xl transition-all flex items-center gap-2">
📄 {{ __('Export to CSV') }}
</button>
<button type="button" @click="exportData('excel'); exportOpen = false" class="w-full text-left py-2 px-3 hover:bg-slate-50 dark:hover:bg-slate-800 text-xs font-bold text-slate-700 dark:text-slate-300 rounded-xl transition-all flex items-center gap-2">
📊 {{ __('Export to Excel') }}
</button>
<button type="button" @click="printTable(); exportOpen = false" class="w-full text-left py-2 px-3 hover:bg-slate-50 dark:hover:bg-slate-800 text-xs font-bold text-slate-700 dark:text-slate-300 rounded-xl transition-all flex items-center gap-2">
🖨️ {{ __('Print & PDF') }}
</button>
</div>
</div>
</div>
</form>