feat(web-client-tpos): add receipt print with thermal 80mm layout
- Create pos-helpers.js with printPosReceipt JS function - Add PrintReceipt method to CafeDesktop.razor (thermal receipt HTML) - Save receipt items/payment data before cart reset - Register pos-helpers.js in index.html - Inject IJSRuntime for print popup
This commit is contained in:
@@ -10,6 +10,7 @@
|
||||
@using WebClientTpos.Client.Services
|
||||
@inject AuthService AuthService
|
||||
@inject PosDataService DataService
|
||||
@inject IJSRuntime JS
|
||||
|
||||
@* ═══════════════ MAIN CONTENT AREA ═══════════════ *@
|
||||
<div class="pos-content-area">
|
||||
@@ -224,7 +225,8 @@
|
||||
<div style="font-size:14px;color:var(--pos-text-tertiary);">@FormatPrice(_lastOrderTotal)</div>
|
||||
<div style="font-size:12px;color:var(--pos-text-tertiary);">Mã: @_lastTransactionId</div>
|
||||
<div style="display:flex;gap:10px;margin-top:8px;">
|
||||
<button style="padding:10px 20px;border-radius:var(--pos-radius);border:1px solid var(--pos-border-default);background:transparent;color:var(--pos-text-primary);cursor:pointer;font-size:13px;font-weight:600;">
|
||||
<button style="padding:10px 20px;border-radius:var(--pos-radius);border:1px solid var(--pos-border-default);background:transparent;color:var(--pos-text-primary);cursor:pointer;font-size:13px;font-weight:600;"
|
||||
@onclick="PrintReceipt">
|
||||
<i data-lucide="printer" style="width:14px;height:14px;vertical-align:middle;margin-right:4px;"></i>In hóa đơn
|
||||
</button>
|
||||
<button style="padding:10px 20px;border-radius:var(--pos-radius);border:none;background:var(--pos-orange-primary);color:#fff;cursor:pointer;font-size:13px;font-weight:600;"
|
||||
@@ -514,6 +516,8 @@
|
||||
private string _customAmountInput = "";
|
||||
private decimal _lastOrderTotal;
|
||||
private string _lastTransactionId = "";
|
||||
private string _lastPaymentMethod = "";
|
||||
private List<(string Name, int Qty, decimal Price)> _lastReceiptItems = new();
|
||||
private decimal ChangeAmount => _receivedAmount - CartTotal;
|
||||
|
||||
private void StartPayment()
|
||||
@@ -581,6 +585,8 @@
|
||||
StateHasChanged();
|
||||
|
||||
_lastOrderTotal = CartTotal;
|
||||
_lastPaymentMethod = _selectedMethod;
|
||||
_lastReceiptItems = _cartItems.Select(i => (i.Name, i.Qty, i.Price)).ToList();
|
||||
var methodLabel = _selectedMethod switch { "cash" => "Tiền mặt", "card" => "Thẻ", "qr" => "QR Code", _ => "Chuyển khoản" };
|
||||
|
||||
// EN: Call API to create real order in DB
|
||||
@@ -633,6 +639,58 @@
|
||||
_customAmountInput = "";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// EN: Print receipt — opens a new window with thermal-style receipt and triggers print dialog.
|
||||
/// VI: In hóa đơn — mở cửa sổ mới với hóa đơn kiểu máy in nhiệt và kích hoạt in.
|
||||
/// </summary>
|
||||
private async Task PrintReceipt()
|
||||
{
|
||||
var payLabel = _lastPaymentMethod switch { "cash" => "Tiền mặt", "card" => "Thẻ", "qr" => "QR Code", _ => "Chuyển khoản" };
|
||||
var now = DateTime.Now;
|
||||
|
||||
// EN: Build item rows HTML / VI: Tạo HTML hàng sản phẩm
|
||||
var sb = new System.Text.StringBuilder();
|
||||
foreach (var item in _lastReceiptItems)
|
||||
{
|
||||
sb.AppendLine($"<tr><td style='text-align:left;padding:3px 0;'>{System.Net.WebUtility.HtmlEncode(item.Name)}</td>");
|
||||
sb.AppendLine($"<td style='text-align:center;padding:3px 4px;'>{item.Qty}</td>");
|
||||
sb.AppendLine($"<td style='text-align:right;padding:3px 0;'>{item.Price:N0}</td>");
|
||||
sb.AppendLine($"<td style='text-align:right;padding:3px 0;font-weight:600;'>{item.Qty * item.Price:N0}</td></tr>");
|
||||
}
|
||||
|
||||
var receiptHtml = "<!DOCTYPE html><html><head><meta charset='utf-8'>" +
|
||||
$"<title>Hóa đơn - {_lastTransactionId}</title>" +
|
||||
"<style>" +
|
||||
"@page { margin: 4mm; size: 80mm auto; }" +
|
||||
"body { font-family: 'Courier New', monospace; font-size: 12px; width: 72mm; margin: 0 auto; color: #000; }" +
|
||||
".c { text-align: center; } .b { font-weight: bold; }" +
|
||||
".d { border-top: 1px dashed #000; margin: 6px 0; }" +
|
||||
"table { width: 100%; border-collapse: collapse; }" +
|
||||
"th { text-align: left; font-size: 11px; border-bottom: 1px solid #000; padding: 2px 0; }" +
|
||||
".f { font-size: 10px; text-align: center; margin-top: 8px; color: #555; }" +
|
||||
"</style></head><body>" +
|
||||
"<div class='c b' style='font-size:16px;'>GoodGo POS</div>" +
|
||||
"<div class='c' style='font-size:10px;margin-bottom:4px;'>Hệ thống quản lý bán hàng thông minh</div>" +
|
||||
"<div class='d'></div>" +
|
||||
$"<div><b>Mã đơn:</b> {_lastTransactionId}</div>" +
|
||||
$"<div><b>Ngày:</b> {now:dd/MM/yyyy} — {now:HH:mm:ss}</div>" +
|
||||
$"<div><b>Thanh toán:</b> {payLabel}</div>" +
|
||||
"<div class='d'></div>" +
|
||||
"<table><tr><th>Sản phẩm</th><th style='text-align:center;'>SL</th><th style='text-align:right;'>Đ.Giá</th><th style='text-align:right;'>T.Tiền</th></tr>" +
|
||||
sb.ToString() +
|
||||
"</table><div class='d'></div>" +
|
||||
$"<div style='display:flex;justify-content:space-between;font-size:14px;font-weight:bold;'><span>TỔNG CỘNG</span><span>{_lastOrderTotal:N0}₫</span></div>" +
|
||||
"<div class='d'></div>" +
|
||||
"<div class='f'>Cảm ơn quý khách! Hẹn gặp lại</div>" +
|
||||
"<div class='f'>Powered by GoodGo Platform</div>" +
|
||||
"<script>window.onload=function(){window.print();window.onafterprint=function(){window.close();}}</script>" +
|
||||
"</body></html>";
|
||||
|
||||
// EN: Open popup window and write receipt HTML / VI: Mở popup và ghi HTML hóa đơn
|
||||
// EN: Call JS helper to open print window / VI: Gọi JS helper mở cửa sổ in
|
||||
await JS.InvokeVoidAsync("printPosReceipt", receiptHtml);
|
||||
}
|
||||
|
||||
// ═══════════════ HISTORY TAB — API-driven ═══════════════
|
||||
private string _historySearch = "";
|
||||
private string _historyFilter = "today";
|
||||
|
||||
@@ -105,6 +105,10 @@
|
||||
<!-- EN: MudBlazor JavaScript -->
|
||||
<!-- VI: JavaScript MudBlazor -->
|
||||
<script src="/_content/MudBlazor/MudBlazor.min.js"></script>
|
||||
|
||||
<!-- EN: POS helpers (receipt printing, etc.) -->
|
||||
<!-- VI: Hàm hỗ trợ POS (in hóa đơn, v.v.) -->
|
||||
<script src="/js/pos-helpers.js"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1,24 @@
|
||||
/**
|
||||
* EN: POS helper functions for Blazor JSInterop.
|
||||
* VI: Các hàm hỗ trợ POS cho Blazor JSInterop.
|
||||
*/
|
||||
|
||||
/**
|
||||
* EN: Print POS receipt — opens new window with receipt HTML and triggers print dialog.
|
||||
* VI: In hóa đơn POS — mở cửa sổ mới với HTML hóa đơn và kích hoạt in.
|
||||
* @param {string} receiptHtml - Full HTML content of the receipt
|
||||
*/
|
||||
window.printPosReceipt = function (receiptHtml) {
|
||||
var w = window.open('', '_blank', 'width=350,height=600');
|
||||
if (w) {
|
||||
w.document.write(receiptHtml);
|
||||
w.document.close();
|
||||
// Give the browser a moment to render before printing
|
||||
setTimeout(function () {
|
||||
w.print();
|
||||
w.onafterprint = function () { w.close(); };
|
||||
}, 300);
|
||||
} else {
|
||||
alert('Trình duyệt đã chặn popup. Vui lòng cho phép popup để in hóa đơn.');
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user