labels: one module knows how to draw a code, seven views stop guessing

Three core pages and four plugin pages each imported qrcode and jsbarcode
directly, and each carried its own answer to the same questions: what margin,
what width, which error correction, how big a module must be before a scanner
can read it. The answers had already drifted - margin 0 in one place and 2 in
another, width 150 against 160 - and on a label that is the difference between
a sticker that scans and one that does not.

frontend/src/utils/codes.js owns it now: the label-stock presets, the quiet-zone
and margin defaults, CODE128 with no printed value, and the printer-resolution
arithmetic that only the Tech Tools generator had. A view passes what is
specific to its own label and nothing else - MachineBadge still asks for CODE39,
because the badge readers predate the shop-floor scanners and decode nothing
else, and that is exactly the kind of thing a call site should say out loud.

views/print/qrLogo.js is folded in rather than left as a second half-shared
helper that only some of the pages reached into.

The check script now fails a build that imports either library outside that
module. Without it this re-forks within a month: the next label page starts by
copying the nearest existing one, which is how it happened the first time.

Tests cover the part no amount of looking at a screen verifies - a QR that
looks fine at 96 dpi on a monitor can be unreadable at 203 dpi on half-inch
stock.
This commit is contained in:
cproudlock
2026-08-14 14:03:49 -04:00
parent b37c08eb5b
commit c648bdf560
12 changed files with 836 additions and 633 deletions

View File

@@ -83,8 +83,7 @@
<script setup>
import { ref, computed, onMounted, watch, nextTick } from 'vue'
import { usbApi } from '@/api'
import JsBarcode from 'jsbarcode'
import QRCode from 'qrcode'
import { barcodeInto, qrPngDataUrl } from '@/utils/codes'
import { getSetting } from '@/utils/siteSettings'
import { buildQrUrl } from '@/utils/qrTarget'
@@ -180,11 +179,8 @@ async function generateQrImages() {
serialnumber: item.device_id || '',
alias: item.device_desc || '',
})
next[`${pageIdx}-${cellIdx + 1}-${miniIdx}`] = await QRCode.toDataURL(url, {
margin: 0,
width: 150,
errorCorrectionLevel: 'M',
})
next[`${pageIdx}-${cellIdx + 1}-${miniIdx}`] =
await qrPngDataUrl(url, { width: 150 })
} catch (e) {
console.error('QR error:', item.device_id, e)
}
@@ -210,13 +206,8 @@ function generateBarcodes() {
const el = barcodeRefs.value[`${pageIdx}-${cellNum}-${miniIdx}`]
if (!el) return
try {
JsBarcode(el, item.device_id, {
format: 'CODE128',
width: 1,
height: 22,
displayValue: false,
margin: 0,
background: 'transparent'
barcodeInto(el, item.device_id, {
width: 1, height: 22, background: 'transparent',
})
} catch (e) {
console.error('Barcode error:', item.device_id, e)