Files
42_104/caddy/www/html5_qrcode_invoice_parser.html
2026-06-23 19:33:50 +08:00

202 lines
6.0 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="zh-TW">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<title>QR Code Scanner (固定320x240)</title>
<!-- 載入 HTML5Qrcode 函式庫 -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/html5-qrcode/2.3.8/html5-qrcode.min.js"></script>
<style>
body {
margin: 0;
padding: 0;
font-family: Arial, sans-serif;
display: flex;
flex-direction: column;
align-items: center;
background-color: #f4f4f4;
}
h1 {
margin-top: 20px;
margin-bottom: 10px;
}
#cameraSelector {
margin-bottom: 10px;
font-size: 16px;
padding: 5px;
}
/* 關鍵:固定掃描容器大小,並使用 overflow:hidden; */
#reader-container {
position: relative; /* 讓內部絕對定位有效 */
width: 320px; /* 固定寬度 */
height: 240px; /* 固定高度 */
border: 2px solid #000;
background-color: #ccc; /* 相機讀取前的底色 */
overflow: hidden; /* 超出的部分被裁切 */
margin-bottom: 10px;
}
/* #reader 直接充滿容器,不再撐大容器 */
#reader {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
/* 讓攝影機畫面被裁切到 320x240 之中 */
video {
object-fit: cover; /* cover: 視訊填滿容器,超出部分裁切 */
width: 100%;
height: 100%;
}
/* 顯示掃描 or 解析結果 */
#result {
width: 320px;
max-height: 150px;
margin-bottom: 10px;
border: 1px solid #ccc;
background-color: #fff;
font-size: 16px;
color: #333;
padding: 10px;
overflow-y: auto;
}
#copyResult {
font-size: 16px;
padding: 6px 12px;
cursor: pointer;
margin-bottom: 20px;
}
</style>
</head>
<body>
<h1>QR Code Scanner</h1>
<!-- 下拉式選擇攝影機 -->
<select id="cameraSelector"></select>
<!-- 掃描區(固定 320x240不因手機長比例而變形 -->
<div id="reader-container">
<div id="reader"></div>
</div>
<!-- 顯示掃描或解析結果 -->
<div id="result">請將 QR Code 對準掃描框。</div>
<!-- 複製結果按鈕 -->
<button id="copyResult">複製結果</button>
<script>
document.addEventListener("DOMContentLoaded", async function () {
const resultDiv = document.getElementById("result");
const cameraSelector = document.getElementById("cameraSelector");
const copyButton = document.getElementById("copyResult");
const html5QrCode = new Html5Qrcode("reader");
let currentCameraId = null;
// 取得可用攝影機清單
try {
const cameras = await Html5Qrcode.getCameras();
if (cameras.length === 0) {
resultDiv.textContent = "未找到攝影機。";
return;
}
cameraSelector.innerHTML = cameras
.map((cam, idx) => `<option value="${cam.id}">${cam.label || "相機 " + (idx + 1)}</option>`)
.join("");
// 預設用第一個攝影機
currentCameraId = cameras[0].id;
await startScanner(currentCameraId);
} catch (err) {
resultDiv.textContent = `無法取得攝影機:${err.message}`;
}
// 切換攝影機
cameraSelector.addEventListener("change", async () => {
const selected = cameraSelector.value;
if (selected !== currentCameraId) {
await html5QrCode.stop();
currentCameraId = selected;
startScanner(currentCameraId);
}
});
// 開始掃描
async function startScanner(cameraId) {
try {
await html5QrCode.start(
{ deviceId: cameraId },
{
fps: 20,
qrbox: { width: 200, height: 200 }
},
(decodedText) => {
displayRawResult(decodedText);
parseQRCode(decodedText);
}
);
} catch (err) {
resultDiv.textContent = `無法啟動掃描器:${err.message}`;
}
}
// 顯示「原始掃描」內容
function displayRawResult(decodedText) {
resultDiv.innerHTML = `<strong>識別到的 QR Code</strong><br>${decodedText}`;
resultDiv.scrollTop = 0;
}
// 嘗試解析台灣電子發票
function parseQRCode(data) {
try {
const raw = data.trim();
const invoiceNumber = raw.slice(0, 10);
const issueDate = raw.slice(10, 17);
const year = parseInt(issueDate.slice(0, 3)) + 1911;
const month = issueDate.slice(3, 5);
const day = issueDate.slice(5, 7);
const formattedDate = `${year}-${month}-${day}`;
const randomCode = raw.slice(17, 21);
const untaxedAmount = parseInt(raw.slice(21, 29), 16);
const totalAmount = parseInt(raw.slice(29, 37), 16);
const buyerTaxId = raw.slice(37, 45);
const sellerTaxId = raw.slice(45, 53);
const encryptedCode = raw.slice(53, 77);
resultDiv.innerHTML = `
<strong>發票號碼:</strong> ${invoiceNumber}<br>
<strong>開立日期:</strong> ${formattedDate}<br>
<strong>隨機碼:</strong> ${randomCode}<br>
<strong>未稅金額:</strong> ${untaxedAmount}<br>
<strong>總計金額:</strong> ${totalAmount}<br>
<strong>買方統一編號:</strong> ${buyerTaxId}<br>
<strong>賣方統一編號:</strong> ${sellerTaxId}<br>
<strong>加密驗證資訊:</strong> ${encryptedCode}<br>
`;
} catch (e) {
// 如果不是符合格式,就保持原始掃描訊息
}
}
// 複製結果
copyButton.addEventListener("click", () => {
navigator.clipboard.writeText(resultDiv.innerText).then(
() => alert("結果已複製到剪貼簿!"),
(err) => alert("複製失敗:" + err)
);
});
});
</script>
</body>
</html>