feat(herramientas): impresion de etiquetas QR y manifiesto HTML responsive para escaneo de cajas de herramientas

This commit is contained in:
2026-11-01 09:13:39 -05:00
parent 83cbfcefa8
commit e71e531b51
15 changed files with 1252 additions and 22 deletions
+44
View File
@@ -9,6 +9,8 @@ const Herramienta = require('../models/Herramienta');
const HerramientaSet = require('../models/HerramientaSet');
const HerramientaAsignacion = require('../models/HerramientaAsignacion');
const { guardarFoto } = require('../config/uploader');
const db = require('../config/db');
const QRCode = require('qrcode');
router.get('/dashboard', isCompanyAdmin, async (req, res) => {
try {
@@ -401,4 +403,46 @@ router.post('/herramientas/devolver/:id', isCompanyAdmin, async (req, res) => {
}
});
// Imprimir Etiqueta QR de Set / Caja de Herramientas
router.get('/herramientas/sets/:id/etiqueta', isCompanyAdmin, async (req, res) => {
try {
const companyId = req.session.user.company_id;
const set = await HerramientaSet.findById(req.params.id, companyId);
if (!set) {
req.flash('error_msg', 'Kit de herramientas no encontrado');
return res.redirect('/admin/herramientas#tab-sets');
}
const proto = req.headers['x-forwarded-proto'] || req.protocol;
const host = req.headers['x-forwarded-host'] || req.get('host');
const baseUrl = process.env.APP_URL || `${proto}://${host}`;
const scanUrl = `${baseUrl}/qr/set/${set.qr_token}`;
const qrDataUrl = await QRCode.toDataURL(scanUrl, {
width: 260,
margin: 1,
color: {
dark: '#000000',
light: '#ffffff'
},
errorCorrectionLevel: 'H'
});
const [companyRows] = await db.query('SELECT name FROM companies WHERE id = ?', [companyId]);
set.company_name = companyRows[0]?.name || 'Telcotronics';
res.render('admin/etiqueta_qr', {
title: `Etiqueta QR: ${set.nombre}`,
set,
herramientas: set.herramientas || [],
scanUrl,
qrDataUrl
});
} catch (error) {
console.error('Error al generar etiqueta QR de kit:', error);
req.flash('error_msg', 'Error al generar etiqueta QR: ' + error.message);
res.redirect('/admin/herramientas#tab-sets');
}
});
module.exports = router;
+61
View File
@@ -0,0 +1,61 @@
const express = require('express');
const router = express.Router();
const HerramientaSet = require('../models/HerramientaSet');
const HerramientaAsignacion = require('../models/HerramientaAsignacion');
// Escaneo público de Set / Caja de herramientas
router.get('/set/:token', async (req, res) => {
try {
const { token } = req.params;
const set = await HerramientaSet.findByToken(token);
if (!set) {
return res.status(404).render('public/qr_error', {
title: 'Caja o Kit no encontrado',
mensaje: 'El código QR escaneado no corresponde a ninguna caja de herramientas registrada en el sistema.'
});
}
res.render('public/qr_set', {
title: `Caja de Herramientas: ${set.nombre}`,
set,
herramientas: set.herramientas || [],
custodia: set.custodia
});
} catch (error) {
console.error('Error al consultar QR de Set:', error);
res.status(500).render('public/qr_error', {
title: 'Error de Consulta',
mensaje: 'Ocurrió un error al cargar la información del kit de herramientas.'
});
}
});
// Escaneo público de Asignación de custodia
router.get('/asignacion/:token', async (req, res) => {
try {
const { token } = req.params;
const asig = await HerramientaAsignacion.findByToken(token);
if (!asig) {
return res.status(404).render('public/qr_error', {
title: 'Asignación no encontrada',
mensaje: 'El código QR escaneado no corresponde a ninguna asignación de equipamiento activa.'
});
}
res.render('public/qr_asignacion', {
title: `Custodia: ${asig.set_nombre || asig.herramienta_nombre}`,
asig,
herramientas: asig.herramientas || []
});
} catch (error) {
console.error('Error al consultar QR de Asignación:', error);
res.status(500).render('public/qr_error', {
title: 'Error de Consulta',
mensaje: 'Ocurrió un error al cargar la información de la asignación.'
});
}
});
module.exports = router;