基于hiprint的票據定位打印系統開發實踐
在日常的Web開發中,我們經常需要實現打印功能,特別是對于票據、標簽等需要精確排版的打印需求。今天我將分享一個基于hiprint插件實現的票據定位打印系統,重點介紹如何實現單行打印、批量打印以及金額數據動態綁定等功能。
項目背景
傳統的網頁打印往往難以控制精確的布局和格式,特別是對于發票、收據等需要固定格式的票據打印。hiprint 是一個專門用于解決這類問題的JavaScript打印插件,它提供了可視化設計工具和豐富的API,可以輕松實現精確定位打印。
核心功能實現
1. 頁面結構設計
首先,我們構建了一個包含票據列表和操作按鈕的頁面結構:
<table class="table table-bordered" style="margin-top: 20px;"><thead><tr><th>發票編號</th><th>開票日期</th><th>客戶名稱</th><th>金額</th><th>操作</th></tr></thead><tbody><tr><td>INV-001</td><td>2023-10-01</td><td>某某公司</td><td>¥1085.00</td><td><a class="btn hiprint-toolbar-item bill-action"data-action="preview" data-index="1">快速預覽</a><a class="btn hiprint-toolbar-item bill-action"data-action="print" data-index="1">打印</a></td></tr><tr><td>INV-001</td><td>2023-10-01</td><td>某某公司</td><td>¥985.00</td><td><a class="btn hiprint-toolbar-item bill-action"data-action="preview" data-index="2">快速預覽</a><a class="btn hiprint-toolbar-item bill-action"data-action="print" data-index="2">打印</a></td></tr></tbody>
</table>
2. 模板外部化管理
為了提高代碼的可維護性,我們將打印模板存儲在獨立的JSON文件中:
下例為簡單表格的模板(發票的模板此處不展示,請見hiprint資源)
{"panels": [{"index": 0,"height": 210,"width": 297,"paperHeader": 10,"paperFooter": 380,"printElements": [{"options": {"left": 20,"top": 20,"width": 250,"height": 120,"content": "<table border='1' style='width:100%;border-collapse:collapse;text-align:center;'><tr><th>序號</th><th>姓名</th><th>成績</th></tr><tr><td>1</td><td>張三</td><td>90</td></tr><tr><td>2</td><td>李四</td><td>85</td></tr><tr><td>3</td><td>王五</td><td>88</td></tr></table>"},"printElementType": {"title": "表格","type": "table"}}],"paperNumberDisabled": true}]
}
// 從外部JSON文件加載模板
$.getJSON('custom_test/bill-template.json', function (templateData) {hiprintTemplate_bill = new hiprint.PrintTemplate({template: templateData,settingContainer: '#PrintElementOptionSetting'});
});
這樣做的好處是:
- 模板與代碼分離,便于維護
- 可以在多個頁面中復用同一模板
- 支持非技術人員通過可視化工具調整模板
3. 單行打印功能
實現單行打印的關鍵在于從當前行提取金額數據并傳遞給打印函數:
// 動態綁定事件
$(document).on('click', '.bill-action', function () {const action = $(this).data('action'); // 獲取操作類型const index = $(this).data('index'); // 獲取索引// 獲取當前行的金額const amountText = $(this).closest('tr').find('td:eq(3)').text();const amount = parseFloat(amountText.replace(/[¥,]/g, '')); // 去除¥符號和逗號,轉換為數字handleBillAction(action, index, amount);
});// 處理預覽和打印邏輯
function handleBillAction(action, index, amount) {// 創建當前行的數據對象const rowData = {index: index,totalAmount: amount};if (action === 'preview') {$('#myModal .modal-body .prevViewDiv').html(hiprintTemplate_bill.getHtml(rowData));$('#myModal').modal('show');} else if (action === 'print') {if (hiprintTemplate_bill) {hiprintTemplate_bill.print([rowData]);}}
}
4. 批量打印功能
批量打印功能會遍歷表格所有行,提取每行的金額數據:
$('#batchPrint').click(function () {const printData = [];$('.table tbody tr').each(function(index) {const amountText = $(this).find('td:eq(3)').text(); // 獲取金額列文本const amount = parseFloat(amountText.replace(/[¥,]/g, '')); // 去除¥符號和逗號,轉換為數字printData.push({ totalAmount: amount,index: index + 1});});if (hiprintTemplate_bill) {hiprintTemplate_bill.print(printData);}
});
多個發票批量打印:
單個發票打印:
技術要點解析
數據提取與處理
在實現過程中,我們需要注意金額數據的提取和格式化:
const amountText = $(this).closest('tr').find('td:eq(3)').text();
const amount = parseFloat(amountText.replace(/[¥,]/g, ''));
這行代碼完成了以下工作:
- 定位到當前行的金額列(第4列,索引為3)
- 提取文本內容
- 使用正則表達式去除貨幣符號和千位分隔符
- 轉換為浮點數便于后續處理
總結
通過這個項目,我們實現了以下功能:
- 可視化模板設計:使用外部JSON文件管理打印模板
- 單行精確打印:每個打印按鈕綁定對應行的數據
- 批量處理能力:支持一次性打印所有票據
- 數據動態綁定:自動從表格中提取金額等關鍵信息
這個系統可以廣泛應用于各種票據打印場景,如發票、收據、標簽等,為Web應用提供了專業級的打印解決方案。通過合理的設計和實現,我們不僅提高了開發效率,也增強了系統的可維護性和擴展性。
— by agi
附錄:
(1)temp.json
{"panels": [{"index": 0,"height": 148,"width": 210,"paperHeader": -1.5,"paperFooter": 380,"printElements": [{"options": {"left": 540,"top": 10.5,"height": 35,"width": 33,"borderColor": "#f20000"},"printElementType": {"title": "橢圓","type": "oval"}},{"options": {"left": 454.5,"top": 15,"height": 18,"width": 74,"title": "8888888","fontSize": 18,"fontWeight": "600","color": "#2935e3","textAlign": "center","lineHeight": 16},"printElementType": {"title": "文本","type": "text"}},{"options": {"left": 424.5,"top": 15,"height": 19,"width": 24,"title": "NO","fontSize": 18,"color": "#2935e3","textAlign": "center","lineHeight": 15},"printElementType": {"title": "文本","type": "text"}},{"options": {"left": 190.5,"top": 15,"height": 21,"width": 226,"title": "上海增值稅普通發票","fontSize": 18,"fontWeight": "600","letterSpacing": 2.5,"color": "#cc5a5a","textAlign": "center","lineHeight": 18},"printElementType": {"title": "文本","type": "text"}},{"options": {"left": 244.5,"top": 19.5,"height": 51,"width": 112,"borderColor": "#eb1111","borderWidth": "2"},"printElementType": {"title": "橢圓","type": "oval"}},{"options": {"left": 90,"top": 19.5,"height": 21,"width": 96,"title": "8888888","fontSize": 19,"letterSpacing": 1,"color": "#2935e3","textAlign": "center","lineHeight": 18},"printElementType": {"title": "文本","type": "text"}},{"options": {"left": 19.5,"top": 19.5,"height": 61,"width": 65,"title": "031001800204","textType": "qrcode"},"printElementType": {"title": "文本","type": "text"}},{"options": {"left": 250.5,"top": 25.5,"height": 42,"width": 104,"borderColor": "#f00505"},"printElementType": {"title": "橢圓","type": "oval"}},{"options": {"left": 190.5,"top": 45,"height": 10,"width": 228,"borderColor": "#b5a8a8"},"printElementType": {"title": "橫線","type": "hline"}},{"options": {"left": 190.5,"top": 49.5,"height": 10,"width": 228,"borderColor": "#baafaf"},"printElementType": {"title": "橫線","type": "hline"}},{"options": {"left": 244.5,"top": 55.5,"height": 22,"width": 120,"title": "發票聯","fontSize": 18,"fontWeight": "600","letterSpacing": 8,"color": "#cc5a5a","textAlign": "center","lineHeight": 18},"printElementType": {"title": "文本","type": "text"}},{"options": {"left": 510,"top": 55.5,"height": 13,"width": 69,"title": "2019年05月09日","color": "#2935e3"},"printElementType": {"title": "文本","type": "text"}},{"options": {"left": 445.5,"top": 55.5,"height": 15,"width": 57,"title": "開票日期:","color": "#cc5a5a","lineHeight": 13},"printElementType": {"title": "文本","type": "text"}},{"options": {"left": 90,"top": 64.5,"height": 15,"width": 141,"title": "校驗碼:123456 788942 52344","color": "#2935e3","textAlign": "center","lineHeight": 13},"printElementType": {"title": "文本","type": "text"}},{"options": {"left": 400,"top": 90,"height": 60,"width": 10,"borderColor": "#cc5a5a"},"printElementType": {"title": "豎線","type": "vline"}},{"options": {"left": 35,"top": 90,"height": 60,"width": 10,"borderColor": "#cc5a5a"},"printElementType": {"title": "豎線","type": "vline"}},{"options": {"left": 420,"top": 90,"height": 61,"width": 10,"borderColor": "#cc5a5a"},"printElementType": {"title": "豎線","type": "vline"}},{"options": {"left": 10.5,"top": 90,"height": 282,"width": 572,"borderColor": "#cc5a5a"},"printElementType": {"title": "矩形","type": "rect"}},{"options": {"left": 405,"top": 94.5,"height": 55,"width": 13,"title": "密碼區","fontSize": 13,"color": "#cc5a5a","lineHeight": 18},"printElementType": {"title": "文本","type": "text"}},{"options": {"left": 424.5,"top": 94.5,"height": 50,"width": 152,"title": "","color": "#2935e3"},"printElementType": {"title": "文本","type": "text"}},{"options": {"left": 15,"top": 94.5,"height": 53,"width": 15,"title": "購買方","fontSize": 13,"color": "#cc5a5a","lineHeight": 18},"printElementType": {"title": "文本","type": "text"}},{"options": {"left": 45,"top": 100.5,"height": 10,"width": 348,"title": "名稱:北京地鐵稅務局有限公司","color": "#2935e3"},"printElementType": {"title": "文本","type": "text"}},{"options": {"left": 45,"top": 115.5,"height": 10,"width": 347,"title": "納稅人識別號:999999999999999999","color": "#2935e3"},"printElementType": {"title": "文本","type": "text"}},{"options": {"left": 45,"top": 130.5,"height": 10,"width": 347,"title": "地址、電話:18888888888","color": "#2935e3"},"printElementType": {"title": "文本","type": "text"}},{"options": {"left": 345,"top": 150,"height": 190,"width": 10,"borderColor": "#cc5a5a"},"printElementType": {"title": "豎線","type": "vline"}},{"options": {"left": 409.5,"top": 150,"height": 190,"width": 10,"borderColor": "#cc5a5a"},"printElementType": {"title": "豎線","type": "vline"}},{"options": {"left": 295.5,"top": 150,"height": 190,"width": 10,"borderColor": "#cc5a5a"},"printElementType": {"title": "豎線","type": "vline"}},{"options": {"left": 480,"top": 150,"height": 190,"width": 10,"borderColor": "#cc5a5a"},"printElementType": {"title": "豎線","type": "vline"}},{"options": {"left": 215,"top": 150,"height": 224,"width": 10,"borderColor": "#cc5a5a"},"printElementType": {"title": "豎線","type": "vline"}},{"options": {"left": 520.5,"top": 150,"height": 190,"width": 10,"borderColor": "#cc5a5a"},"printElementType": {"title": "豎線","type": "vline"}},{"options": {"left": 10,"top": 150,"height": 10,"width": 574,"borderColor": "#cc5a5a"},"printElementType": {"title": "橫線","type": "hline"}},{"options": {"left": 300,"top": 160.5,"height": 10,"width": 36,"title": "單位","fontSize": 13,"color": "#cc5a5a","textAlign": "center"},"printElementType": {"title": "文本","type": "text"}},{"options": {"left": 349.5,"top": 160.5,"height": 11,"width": 51,"title": "數量","fontSize": 13,"color": "#cc5a5a","textAlign": "center"},"printElementType": {"title": "文本","type": "text"}},{"options": {"left": 225,"top": 160.5,"height": 10,"width": 62,"title": "規格名稱","fontSize": 13,"color": "#cc5a5a","textAlign": "center"},"printElementType": {"title": "文本","type": "text"}},{"options": {"left": 420,"top": 160.5,"height": 10,"width": 53,"title": "單價","fontSize": 13,"color": "#cc5a5a","textAlign": "center"},"printElementType": {"title": "文本","type": "text"}},{"options": {"left": 484.5,"top": 160.5,"height": 10,"width": 32,"title": "稅率","fontSize": 13,"color": "#cc5a5a","textAlign": "center"},"printElementType": {"title": "文本","type": "text"}},{"options": {"left": 525,"top": 160.5,"height": 10,"width": 52,"title": "稅額","fontSize": 13,"color": "#cc5a5a","textAlign": "center"},"printElementType": {"title": "文本","type": "text"}},{"options": {"left": 19.5,"top": 160.5,"height": 10,"width": 184,"title": "貨物或應稅勞務、服務名稱","fontSize": 13,"color": "#cc5a5a","textAlign": "center"},"printElementType": {"title": "文本","type": "text"}},{"options": {"left": 40.5,"top": 175.5,"height": 12,"width": 120,"title": "*餐飲服務*餐費","color": "#2935e3"},"printElementType": {"title": "文本","type": "text"}},{"options": {"left": 10.5,"top": 340.5,"height": 10,"width": 574,"borderColor": "#cc5a5a"},"printElementType": {"title": "橫線","type": "hline"}},{"options": {"left": 225,"top": 349.5,"height": 14,"width": 229,"title": "壹佰貳拾元整","color": "#2935e3"},"printElementType": {"title": "文本","type": "text"}},{"options": {"left": 460.5,"top": 349.5,"height": 13,"width": 58,"title": "(小寫)","fontSize": 13,"color": "#cc5a5a"},"printElementType": {"title": "文本","type": "text"}},{"options": {"left": 520.5,"top": 349.5,"height": 13,"width": 48,"field": "totalAmount","color": "#2935e3"},"printElementType": {"title": "¥","type": "text"}},{"options": {"left": 15,"top": 349.5,"height": 14,"width": 193,"title": "價稅合計(大寫)","fontSize": 13,"color": "#cc5a5a","textAlign": "center"},"printElementType": {"title": "文本","type": "text"}},{"options": {"left": 300,"top": 385.5,"height": 10,"width": 39,"title": "開票人:","color": "#cc5a5a"},"printElementType": {"title": "文本","type": "text"}},{"options": {"left": 190.5,"top": 385.5,"height": 10,"width": 103,"title": "軒大可","color": "#2935e3"},"printElementType": {"title": "文本","type": "text"}},{"options": {"left": 150,"top": 385.5,"height": 10,"width": 33,"title": "復核:","color": "#cc5a5a"},"printElementType": {"title": "文本","type": "text"}},{"options": {"left": 345,"top": 385.5,"height": 10,"width": 86,"title": "張天天","color": "#2935e3"},"printElementType": {"title": "文本","type": "text"}},{"options": {"left": 64.5,"top": 385.5,"height": 10,"width": 78,"title": "軒天天","color": "#2935e3"},"printElementType": {"title": "文本","type": "text"}},{"options": {"left": 439.5,"top": 385.5,"height": 10,"width": 40,"title": "銷售方:","color": "#cc5a5a"},"printElementType": {"title": "文本","type": "text"}},{"options": {"left": 15,"top": 385.5,"height": 10,"width": 44,"title": "收款人:","color": "#cc5a5a"},"printElementType": {"title": "文本","type": "text"}}],"paperNumberLeft": 565.5,"paperNumberTop": 394.5}]
}
(2)index.html
<!DOCTYPE html>
<html><head><meta charset="utf-8" /><title></title><link href="css/hiprint.css" rel="stylesheet" /><link href="css/print-lock.css" rel="stylesheet" /><link href="content/bootstrap.min.css" rel="stylesheet"><script src="https://cdn.staticfile.net/jquery/1.10.2/jquery.min.js"></script><script src="content/bootstrap.min.js"></script><style>.hinnn-layout,.hinnn-layout * {box-sizing: border-box;}.hinnn-layout {display: flex;flex: auto;flex-direction: column;}.hinnn-layout.hinnn-layout-has-sider {flex-direction: row;}.hinnn-layout-sider {display: flex;flex-direction: row;position: relative;}.hinnn-layout-content {flex: auto;}.hinnn-header {position: relative;z-index: 1030;display: block;}.wrapper {min-height: 100%;}.height-100-per {height: 100%;}</style>
</head><body><layout class="layout hinnn-layout hinnn-layout-has-sider height-100-per" style="background:#fff;"><content class="hinnn-layout-content" style="border-left:1px solid #e8e8e8;"><div class="container-fluid height-100-per print-content"><div class="row"><div class="col-sm-12"><div class="row"><div class="col-sm-9 col-md-10"><div class="row"><div class="col-md-12"><div class="hinnn-docs-section"><h1 class="page-header">票據定位打印</h1><button type="button" class="btn btn-danger" id="batchPrint">批量打印</button><table class="table table-bordered" style="margin-top: 20px;"><thead><tr><th>發票編號</th><th>開票日期</th><th>客戶名稱</th><th>金額</th><th>操作</th></tr></thead><tbody><tr><td>INV-001</td><td>2023-10-01</td><td>某某公司</td><td>¥1085.00</td><td><a class="btn hiprint-toolbar-item bill-action"data-action="preview" data-index="1">快速預覽</a><a class="btn hiprint-toolbar-item bill-action"data-action="print" data-index="1">打印</a></td></tr><tr><td>INV-001</td><td>2023-10-01</td><td>某某公司</td><td>¥985.00</td><td><a class="btn hiprint-toolbar-item bill-action"data-action="preview" data-index="2">快速預覽</a><a class="btn hiprint-toolbar-item bill-action"data-action="print" data-index="2">打印</a></td></tr></tbody></table></div></div></div></div></div></div></div></content><sider class="hinnn-layout-sider" style=""><div class="container height-100-per" style="width:250px;"><div class="row"><div class="col-sm-12"><div id="PrintElementOptionSetting" style="margin-top:10px;"></div></div></div></div></sider></layout><div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel"><div class="modal-dialog modal-lg" role="document" style="width: 825px;"><div class="modal-content"><div class="modal-header"><button type="button" class="close" data-dismiss="modal" aria-label="Close"><spanaria-hidden="true">×</span></button><h4 class="modal-title" id="">打印預覽</h4></div><div class="modal-body"><!-- 新增打印按鈕 --><button type="button" class="btn btn-danger" id="printInModal">打印</button><div class="prevViewDiv"></div></div><div class="modal-footer"><button type="button" class="btn btn-default" data-dismiss="modal">Close</button></divmyModalLabel></div></div></div></div><script src="custom_test/custom-etype-provider.js"></script><script src="custom_test/custom-print-json.js"></script><script src="custom_test/print-data.js"></script><script src="polyfill.min.js"></script><script src="plugins/jquery.minicolors.min.js"></script><script src="plugins/JsBarcode.all.min.js"></script><script src="plugins/qrcode.js"></script><script src="hiprint.bundle.js"></script><script src="plugins/jquery.hiwprint.js"></script><script>$(document).ready(function () {var hiprintTemplate_bill;// 修改: 使用 $.getJSON 方法加載模板文件$.getJSON('custom_test/bill-template.json', function (templateData) {hiprintTemplate_bill = new hiprint.PrintTemplate({template: templateData,settingContainer: '#PrintElementOptionSetting'});});// 綁定模態框中的打印按鈕事件$('#printInModal').click(function () {if (hiprintTemplate_bill) {hiprintTemplate_bill.print(printData);}});// 綁定批量打印按鈕事件 - 參考提供的代碼進行修改$('#batchPrint').click(function () {// 修改: 從表格中獲取金額數據const printData = [];$('.table tbody tr').each(function(index) {const amountText = $(this).find('td:eq(3)').text(); // 獲取金額列文本const amount = parseFloat(amountText.replace(/[¥,]/g, '')); // 去除¥符號和逗號,轉換為數字printData.push({ totalAmount: amount,index: index + 1});});if (hiprintTemplate_bill) {hiprintTemplate_bill.print(printData);}});// 修改: 統一處理預覽和打印邏輯,支持單行金額數據function handleBillAction(action, index, amount) {// 創建當前行的數據對象const rowData = {index: index,totalAmount: amount};if (action === 'preview') {$('#myModal .modal-body .prevViewDiv').html(hiprintTemplate_bill.getHtml(rowData));$('#myModal').modal('show');} else if (action === 'print') {if (hiprintTemplate_bill) {hiprintTemplate_bill.print([rowData]);}}}// 動態綁定事件$(document).on('click', '.bill-action', function () {const action = $(this).data('action'); // 獲取操作類型const index = $(this).data('index'); // 獲取索引// 獲取當前行的金額const amountText = $(this).closest('tr').find('td:eq(3)').text();const amount = parseFloat(amountText.replace(/[¥,]/g, '')); // 去除¥符號和逗號,轉換為數字handleBillAction(action, index, amount);});});</script></body></html>