Files
shopdb/printerqrbatch.asp
cproudlock 84c2120652 Add printer QR code printing and Windows name auto-update
- Add printerqrcode.asp for single printer QR code labels (ULINE S-20135)
- Add printerqrbatch.asp for batch printing multiple printers (6 per page)
- Add auto-update of Windows name when changing associated machine
- Windows name follows naming standard: [CSF]-[Machine]-[Vendor][Model]
- Remove UDC integrations from displaymachine.asp
- Add toner_inventory.csv for HP printer toner tracking
- Fix printerqrbatch.asp to show all printers, not just CSF ones

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-19 16:38:38 -05:00

285 lines
12 KiB
Plaintext

<%@ Language=VBScript %>
<%
Option Explicit
Dim objConn, rs
%>
<!DOCTYPE html>
<html>
<head>
<!--#include file="./includes/sql.asp"-->
<title>Batch Print QR Codes</title>
<script src="https://cdn.jsdelivr.net/npm/qrcodejs@1.0.0/qrcode.min.js"></script>
<style>
/* ULINE S-20135: 8.5x11 sheet, 3x3 labels, 2 cols x 3 rows */
/* Measured: top 0.875in, sides 1.1875in, gaps 0.125in */
@page { size: letter; margin: 0; }
body { font-family: Arial, sans-serif; background: #f0f0f0; margin: 0; padding: 20px; }
.no-print { margin-bottom: 20px; }
.controls { background: white; padding: 20px; border-radius: 8px; margin-bottom: 20px; }
.controls h3 { margin-top: 0; }
.print-btn { padding: 10px 30px; font-size: 16px; cursor: pointer; background: #667eea; color: white; border: none; border-radius: 5px; margin-right: 10px; }
.print-btn:disabled { background: #ccc; cursor: not-allowed; }
.clear-btn { padding: 10px 20px; font-size: 14px; cursor: pointer; background: #dc3545; color: white; border: none; border-radius: 5px; margin-right: 10px; }
.select-all-btn { padding: 10px 20px; font-size: 14px; cursor: pointer; background: #28a745; color: white; border: none; border-radius: 5px; }
.printer-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); gap: 10px; max-height: 300px; overflow-y: auto; border: 1px solid #ddd; padding: 10px; background: #fafafa; }
.printer-item { display: flex; align-items: center; padding: 8px; background: white; border: 1px solid #ddd; border-radius: 4px; cursor: pointer; }
.printer-item:hover { background: #f0f0f0; }
.printer-item.selected { background: #e7f1ff; border-color: #667eea; }
.printer-item input { margin-right: 10px; }
.printer-item label { cursor: pointer; flex: 1; }
.printer-item .model { font-size: 11px; color: #666; }
.selected-count { font-weight: bold; margin: 10px 0; }
.selected-count .count { color: #667eea; }
.selected-count .pages { color: #28a745; }
.sheets-container { display: flex; flex-direction: column; gap: 20px; }
.print-sheet { width: 8.5in; height: 11in; background: white; margin: 0 auto; position: relative; border: 1px solid #ccc; page-break-after: always; }
.print-sheet:last-child { page-break-after: auto; }
.sheet-label { position: absolute; top: -25px; left: 0; font-size: 12px; color: #666; }
.label {
width: 3in;
height: 3in;
position: absolute;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 0.1in;
box-sizing: border-box;
border: 1px dashed #ccc;
}
.label.filled { border: 2px solid #667eea; }
.label.empty { background: #fafafa; }
/* Label positions - top: 0.875in, left: 1.1875in, gap: 0.125in */
.pos-1 { top: 0.875in; left: 1.1875in; }
.pos-2 { top: 0.875in; left: 4.3125in; }
.pos-3 { top: 4in; left: 1.1875in; }
.pos-4 { top: 4in; left: 4.3125in; }
.pos-5 { top: 7.125in; left: 1.1875in; }
.pos-6 { top: 7.125in; left: 4.3125in; }
.model-name { font-size: 11pt; font-weight: bold; text-align: center; margin-bottom: 0.1in; color: #000; }
.qr-container { text-align: center; }
.info-section { margin-top: 0.1in; display: flex; flex-direction: column; align-items: center; }
.info-inner { text-align: left; }
.info-row { font-size: 9pt; color: #333; margin: 1px 0; white-space: nowrap; }
.csf-name { font-size: 12pt; font-weight: bold; font-family: monospace; text-align: center; margin-bottom: 2px; }
.empty-label { color: #999; font-size: 14px; }
@media print {
body { padding: 0; margin: 0; background: white; }
.no-print { display: none; }
.sheets-container { gap: 0; }
.print-sheet { border: none; margin: 0; width: 8.5in; height: 11in; overflow: hidden; }
.sheet-label { display: none; }
.label { border: none !important; }
.label.empty { visibility: hidden; }
}
</style>
</head>
<body>
<%
Dim strSQL
strSQL = "SELECT p.printerid, p.printercsfname, p.printerwindowsname, p.ipaddress, m.modelnumber " & _
"FROM printers p LEFT JOIN models m ON p.modelid = m.modelnumberid " & _
"WHERE p.isactive = 1 " & _
"ORDER BY COALESCE(NULLIF(p.printercsfname, ''), p.printerwindowsname, CONCAT('Printer-', p.printerid))"
Set rs = objConn.Execute(strSQL)
%>
<div class="no-print">
<div class="controls">
<h3>Batch Print Printer QR Codes</h3>
<p>Select printers to print (6 per page):</p>
<div class="printer-grid">
<%
Dim displayName
Do While Not rs.EOF
displayName = rs("printercsfname") & ""
If displayName = "" Then
displayName = rs("printerwindowsname") & ""
End If
If displayName = "" Then
displayName = "Printer-" & rs("printerid")
End If
%>
<div class="printer-item" onclick="togglePrinter(this, <%=rs("printerid")%>, '<%=Server.HTMLEncode(Replace(rs("printercsfname") & "", "'", "\'"))%>', '<%=Server.HTMLEncode(Replace(rs("printerwindowsname") & "", "'", "\'"))%>', '<%=Server.HTMLEncode(Replace(rs("ipaddress") & "", "'", "\'"))%>', '<%=Server.HTMLEncode(Replace(rs("modelnumber") & "", "'", "\'"))%>')">
<input type="checkbox" id="printer-<%=rs("printerid")%>">
<label>
<strong><%=Server.HTMLEncode(displayName)%></strong>
<div class="model"><%=Server.HTMLEncode(rs("modelnumber") & "")%></div>
</label>
</div>
<%
rs.MoveNext
Loop
rs.Close
Set rs = Nothing
objConn.Close
%>
</div>
<div class="selected-count">
Selected: <span class="count" id="selectedCount">0</span> printers
(<span class="pages" id="pageCount">0</span> pages)
</div>
<button class="print-btn" id="printBtn" onclick="window.print()" disabled>Print QR Codes</button>
<button class="clear-btn" onclick="clearSelection()">Clear All</button>
<button class="select-all-btn" onclick="selectAll()">Select All</button>
</div>
</div>
<div class="sheets-container" id="sheetsContainer">
<!-- Sheets will be generated dynamically -->
</div>
<script>
var selectedPrinters = [];
var allPrinters = [];
// Store all printer data on load
document.querySelectorAll('.printer-item').forEach(function(el) {
var onclick = el.getAttribute('onclick');
var match = onclick.match(/togglePrinter\(this, (\d+), '([^']*)', '([^']*)', '([^']*)', '([^']*)'\)/);
if (match) {
allPrinters.push({
id: parseInt(match[1]),
csf: match[2].replace(/\\'/g, "'"),
win: match[3].replace(/\\'/g, "'"),
ip: match[4].replace(/\\'/g, "'"),
model: match[5].replace(/\\'/g, "'"),
element: el
});
}
});
function togglePrinter(el, id, csf, win, ip, model) {
var checkbox = el.querySelector('input[type="checkbox"]');
var index = selectedPrinters.findIndex(function(p) { return p.id === id; });
if (index > -1) {
selectedPrinters.splice(index, 1);
checkbox.checked = false;
el.classList.remove('selected');
} else {
selectedPrinters.push({ id: id, csf: csf, win: win, ip: ip, model: model });
checkbox.checked = true;
el.classList.add('selected');
}
updateSheets();
}
function clearSelection() {
selectedPrinters = [];
document.querySelectorAll('.printer-item').forEach(function(el) {
el.classList.remove('selected');
el.querySelector('input[type="checkbox"]').checked = false;
});
updateSheets();
}
function selectAll() {
selectedPrinters = [];
allPrinters.forEach(function(p) {
selectedPrinters.push({ id: p.id, csf: p.csf, win: p.win, ip: p.ip, model: p.model });
p.element.classList.add('selected');
p.element.querySelector('input[type="checkbox"]').checked = true;
});
updateSheets();
}
function updateSheets() {
var numPrinters = selectedPrinters.length;
var numPages = Math.ceil(numPrinters / 6) || 0;
document.getElementById('selectedCount').textContent = numPrinters;
document.getElementById('pageCount').textContent = numPages;
document.getElementById('printBtn').disabled = numPrinters === 0;
var container = document.getElementById('sheetsContainer');
container.innerHTML = '';
if (numPrinters === 0) {
return;
}
for (var page = 0; page < numPages; page++) {
var sheet = document.createElement('div');
sheet.className = 'print-sheet';
sheet.style.position = 'relative';
var sheetLabel = document.createElement('div');
sheetLabel.className = 'sheet-label';
sheetLabel.textContent = 'Page ' + (page + 1) + ' of ' + numPages;
sheet.appendChild(sheetLabel);
for (var pos = 1; pos <= 6; pos++) {
var printerIndex = (page * 6) + (pos - 1);
var printer = selectedPrinters[printerIndex];
var label = document.createElement('div');
label.className = 'label pos-' + pos + (printer ? ' filled' : ' empty');
if (printer) {
var qrId = 'qr-' + page + '-' + pos;
label.innerHTML =
'<div class="model-name">' + escapeHtml(printer.model) + '</div>' +
'<div class="qr-container"><div id="' + qrId + '"></div></div>' +
'<div class="info-section">' +
'<div class="csf-name">' + escapeHtml(printer.csf) + '</div>' +
'<div class="info-inner">' +
(printer.win ? '<div class="info-row">' + escapeHtml(printer.win) + '</div>' : '') +
(printer.ip ? '<div class="info-row">' + escapeHtml(printer.ip) + '</div>' : '') +
'</div>' +
'</div>';
} else {
label.innerHTML = '<span class="empty-label">Empty</span>';
}
sheet.appendChild(label);
}
container.appendChild(sheet);
// Generate QR codes for this sheet
for (var pos = 1; pos <= 6; pos++) {
var printerIndex = (page * 6) + (pos - 1);
var printer = selectedPrinters[printerIndex];
if (printer) {
var qrId = 'qr-' + page + '-' + pos;
var qrEl = document.getElementById(qrId);
if (qrEl) {
var qrUrl = 'https://tsgwp00525.rd.ds.ge.com/shopdb/displayprinter.asp?printerid=' + printer.id;
new QRCode(qrEl, {
text: qrUrl,
width: 144,
height: 144,
correctLevel: QRCode.CorrectLevel.M
});
}
}
}
}
}
function escapeHtml(text) {
if (!text) return '';
var div = document.createElement('div');
div.textContent = text;
return div.innerHTML;
}
</script>
</body>
</html>