Files
help_desk/views/admin/herramientas.ejs
T

902 lines
63 KiB
Plaintext

<%- include('../partials/header') %>
<% title = 'Herramientas & Sets'; %>
<!-- Alertas Flash -->
<% if (success_msg && success_msg.length > 0) { %>
<% success_msg.forEach(msg => { %>
<div class="alert alert-success alert-dismissible fade show rounded-3 border-0 shadow-sm mb-3" role="alert">
<div class="d-flex align-items-center">
<i class="fas fa-check-circle me-2 fs-5 text-success"></i>
<div><%= msg %></div>
</div>
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
</div>
<% }) %>
<% } %>
<% if (error_msg && error_msg.length > 0) { %>
<% error_msg.forEach(msg => { %>
<div class="alert alert-danger alert-dismissible fade show rounded-3 border-0 shadow-sm mb-3" role="alert">
<div class="d-flex align-items-center">
<i class="fas fa-exclamation-triangle me-2 fs-5 text-danger"></i>
<div><%= msg %></div>
</div>
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
</div>
<% }) %>
<% } %>
<!-- Cabecera de Página -->
<div class="page-header d-flex flex-wrap justify-content-between align-items-center gap-3 mb-4">
<div>
<div class="d-flex align-items-center gap-2 mb-1">
<h1 class="page-title h3 mb-0">Herramientas & Sets de Campo (FSM)</h1>
<span class="badge bg-warning-subtle text-dark border px-2.5 py-1" style="font-size: 0.75rem;">
<i class="fas fa-toolbox text-warning me-1"></i> Control de Equipamiento
</span>
</div>
<p class="text-muted small mb-0">Administra el inventario de instrumental, kits especializados y asignaciones fijas o por visita presencial a técnicos.</p>
</div>
<div class="d-flex align-items-center gap-2">
<button type="button" class="btn btn-outline-primary btn-sm d-inline-flex align-items-center gap-1.5 shadow-sm" data-bs-toggle="modal" data-bs-target="#modalNuevaHerramienta">
<i class="fas fa-plus"></i>
<span>Nueva Herramienta</span>
</button>
<button type="button" class="btn btn-warning btn-sm fw-bold d-inline-flex align-items-center gap-1.5 shadow-sm text-dark" data-bs-toggle="modal" data-bs-target="#modalNuevoSet">
<i class="fas fa-layer-group"></i>
<span>Nuevo Set / Kit</span>
</button>
<button type="button" class="btn btn-primary btn-sm d-inline-flex align-items-center gap-1.5 shadow-sm" data-bs-toggle="modal" data-bs-target="#modalAsignar">
<i class="fas fa-user-tag"></i>
<span>Asignar a Técnico</span>
</button>
</div>
</div>
<!-- Tarjetas KPI -->
<div class="row g-3 mb-4">
<div class="col-sm-6 col-xl-3">
<div class="app-card p-3 d-flex align-items-center gap-3">
<div class="icon-circle bg-primary-subtle text-primary" style="width: 48px; height: 48px; border-radius: 12px; display: flex; align-items: center; justify-content: center; font-size: 1.25rem;">
<i class="fas fa-tools"></i>
</div>
<div>
<div class="text-muted small text-uppercase fw-semibold" style="font-size: 0.7rem; letter-spacing: 0.5px;">Total Instrumentos</div>
<div class="fs-4 fw-bold text-dark"><%= stats.total %></div>
</div>
</div>
</div>
<div class="col-sm-6 col-xl-3">
<div class="app-card p-3 d-flex align-items-center gap-3">
<div class="icon-circle bg-success-subtle text-success" style="width: 48px; height: 48px; border-radius: 12px; display: flex; align-items: center; justify-content: center; font-size: 1.25rem;">
<i class="fas fa-check-double"></i>
</div>
<div>
<div class="text-muted small text-uppercase fw-semibold" style="font-size: 0.7rem; letter-spacing: 0.5px;">Operativas</div>
<div class="fs-4 fw-bold text-success"><%= stats.operativo %></div>
</div>
</div>
</div>
<div class="col-sm-6 col-xl-3">
<div class="app-card p-3 d-flex align-items-center gap-3">
<div class="icon-circle bg-warning-subtle text-warning" style="width: 48px; height: 48px; border-radius: 12px; display: flex; align-items: center; justify-content: center; font-size: 1.25rem;">
<i class="fas fa-wrench"></i>
</div>
<div>
<div class="text-muted small text-uppercase fw-semibold" style="font-size: 0.7rem; letter-spacing: 0.5px;">Mantenimiento / Baja</div>
<div class="fs-4 fw-bold text-warning"><%= (stats.en_mantenimiento || 0) + (stats.danado || 0) + (stats.baja || 0) %></div>
</div>
</div>
</div>
<div class="col-sm-6 col-xl-3">
<div class="app-card p-3 d-flex align-items-center gap-3">
<div class="icon-circle bg-info-subtle text-info" style="width: 48px; height: 48px; border-radius: 12px; display: flex; align-items: center; justify-content: center; font-size: 1.25rem;">
<i class="fas fa-boxes-stacked"></i>
</div>
<div>
<div class="text-muted small text-uppercase fw-semibold" style="font-size: 0.7rem; letter-spacing: 0.5px;">Sets / Kits Configurados</div>
<div class="fs-4 fw-bold text-info"><%= sets.length %></div>
</div>
</div>
</div>
</div>
<!-- Pestañas de Navegación -->
<ul class="nav nav-pills custom-pills mb-3 gap-2" id="herramientasTabs" role="tablist">
<li class="nav-item" role="presentation">
<button class="nav-link active px-3 py-2 fw-semibold d-flex align-items-center gap-2" id="tab-sets-btn" data-bs-toggle="pill" data-bs-target="#tab-sets" type="button" role="tab">
<i class="fas fa-layer-group"></i>
<span>Sets / Kits de Herramientas (<%= sets.length %>)</span>
</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link px-3 py-2 fw-semibold d-flex align-items-center gap-2" id="tab-herramientas-btn" data-bs-toggle="pill" data-bs-target="#tab-herramientas" type="button" role="tab">
<i class="fas fa-toolbox"></i>
<span>Inventario Detallado (<%= herramientas.length %>)</span>
</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link px-3 py-2 fw-semibold d-flex align-items-center gap-2" id="tab-asignaciones-btn" data-bs-toggle="pill" data-bs-target="#tab-asignaciones" type="button" role="tab">
<i class="fas fa-user-check"></i>
<span>Asignaciones a Técnicos (<%= asignaciones.length %>)</span>
</button>
</li>
</ul>
<div class="tab-content" id="herramientasTabsContent">
<!-- ============================================== -->
<!-- TAB 1: SETS / KITS DE HERRAMIENTAS -->
<!-- ============================================== -->
<div class="tab-pane fade show active" id="tab-sets" role="tabpanel">
<div class="row g-3">
<% if (sets.length === 0) { %>
<div class="col-12">
<div class="app-card p-5 text-center">
<i class="fas fa-toolbox text-muted fs-1 mb-2"></i>
<h5 class="fw-bold text-dark">No hay Sets o Kits creados</h5>
<p class="text-muted small mb-3">Agrupa herramientas físicas en sets reutilizables para despacharlos rápidamente en terreno.</p>
<button type="button" class="btn btn-warning btn-sm px-3 fw-bold" data-bs-toggle="modal" data-bs-target="#modalNuevoSet">
<i class="fas fa-plus me-1"></i> Crear primer Kit de Herramientas
</button>
</div>
</div>
<% } %>
<% sets.forEach(s => { %>
<div class="col-md-6 col-xl-4">
<div class="app-card h-100 p-3.5 d-flex flex-column justify-content-between border shadow-sm rounded-3">
<div>
<% if (s.foto_url) { %>
<div class="mb-3 rounded overflow-hidden border shadow-sm position-relative" style="height: 140px; background-color: #f8fafc;">
<a href="<%= s.foto_url %>" target="_blank" title="Ver foto ampliada">
<img src="<%= s.foto_url %>" alt="<%= s.nombre %>" style="width: 100%; height: 100%; object-fit: cover;">
</a>
</div>
<% } %>
<div class="d-flex align-items-center justify-content-between mb-2">
<div class="d-flex align-items-center gap-1.5">
<span class="badge bg-dark text-white font-monospace" style="font-size: 0.7rem;">
<%= s.codigo || 'KIT-' + s.id %>
</span>
<a href="/admin/herramientas/sets/<%= s.id %>/etiqueta" target="_blank" class="badge bg-light text-dark border text-decoration-none d-inline-flex align-items-center gap-1" style="font-size: 0.68rem;" title="Ver e Imprimir Etiqueta QR">
<i class="fas fa-qrcode text-primary"></i> <span>QR</span>
</a>
</div>
<span class="badge <%= s.is_active ? 'bg-success' : 'bg-secondary' %>" style="font-size: 0.68rem;">
<%= s.is_active ? 'Activo' : 'Inactivo' %>
</span>
</div>
<h5 class="fw-bold text-dark mb-1"><%= s.nombre %></h5>
<p class="text-muted small mb-3" style="font-size: 0.8rem;"><%= s.descripcion || 'Sin descripción detallada.' %></p>
<div class="border-top pt-2.5 mb-3">
<div class="d-flex align-items-center justify-content-between mb-2">
<span class="small fw-bold text-dark" style="font-size: 0.75rem;">
<i class="fas fa-tools text-primary me-1"></i> Herramientas incluidas (<%= s.herramientas ? s.herramientas.length : 0 %>)
</span>
<span class="badge bg-light text-muted border" style="font-size: 0.65rem;">
Cat: <%= s.categoria %>
</span>
</div>
<% if (s.herramientas && s.herramientas.length > 0) { %>
<ul class="list-unstyled mb-0 small" style="font-size: 0.78rem;">
<% s.herramientas.forEach(h => { %>
<li class="d-flex align-items-center justify-content-between py-1 border-bottom border-light">
<div class="text-truncate me-2 d-flex align-items-center gap-1.5">
<% if (h.foto_url) { %>
<img src="<%= h.foto_url %>" alt="Foto" class="rounded flex-shrink-0" style="width: 22px; height: 22px; object-fit: cover;">
<% } else { %>
<i class="fas fa-check text-success" style="font-size: 0.7rem;"></i>
<% } %>
<strong><%= h.nombre %></strong>
<% if (h.marca) { %><span class="text-muted">(<%= h.marca %>)</span><% } %>
</div>
<span class="badge bg-light text-muted border font-monospace" style="font-size: 0.68rem;">
<%= h.codigo || h.numero_serie || 'SN-N/D' %>
</span>
</li>
<% }) %>
</ul>
<% } else { %>
<div class="small text-muted fst-italic">No tiene herramientas asociadas aún.</div>
<% } %>
</div>
</div>
<div class="border-top pt-3 d-flex flex-wrap align-items-center justify-content-between gap-2 mt-auto">
<div class="d-flex align-items-center gap-1.5">
<button type="button" class="btn btn-sm btn-outline-primary d-inline-flex align-items-center gap-1" data-bs-toggle="modal" data-bs-target="#modalAsignarDirecto<%= s.id %>">
<i class="fas fa-user-plus"></i>
<span>Asignar</span>
</button>
<a href="/admin/herramientas/sets/<%= s.id %>/etiqueta" target="_blank" class="btn btn-sm btn-outline-dark d-inline-flex align-items-center gap-1" title="Imprimir Etiqueta QR para Caja">
<i class="fas fa-qrcode"></i>
<span>Etiqueta QR</span>
</a>
</div>
<div class="d-flex align-items-center gap-1">
<button type="button" class="btn btn-sm btn-light border" data-bs-toggle="modal" data-bs-target="#modalEditarSet<%= s.id %>" title="Editar Kit">
<i class="fas fa-edit text-secondary"></i>
</button>
<form action="/admin/herramientas/sets/delete/<%= s.id %>" method="POST" onsubmit="return confirm('¿Eliminar este kit de herramientas?');" class="d-inline">
<button type="submit" class="btn btn-sm btn-light border text-danger" title="Eliminar Kit">
<i class="fas fa-trash-alt"></i>
</button>
</form>
</div>
</div>
</div>
</div>
<!-- MODAL EDITAR SET -->
<div class="modal fade" id="modalEditarSet<%= s.id %>" tabindex="-1" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content rounded-3 border-0 shadow">
<form action="/admin/herramientas/sets/edit/<%= s.id %>" method="POST" enctype="multipart/form-data">
<div class="modal-header">
<h5 class="modal-title fw-bold">Editar Kit: <%= s.nombre %></h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<div class="row g-3">
<div class="col-md-8">
<label class="form-label small fw-bold">Nombre del Set / Kit *</label>
<input type="text" name="nombre" class="form-control" value="<%= s.nombre %>" required>
</div>
<div class="col-md-4">
<label class="form-label small fw-bold">Código Identificador</label>
<input type="text" name="codigo" class="form-control font-monospace" value="<%= s.codigo || '' %>">
</div>
<div class="col-md-6">
<label class="form-label small fw-bold">Categoría Operativa</label>
<select name="categoria" class="form-select">
<option value="cctv" <%= s.categoria === 'cctv' ? 'selected' : '' %>>Seguridad Electrónica & CCTV</option>
<option value="fibra_optica" <%= s.categoria === 'fibra_optica' ? 'selected' : '' %>>Fibra Óptica & Enlaces</option>
<option value="redes" <%= s.categoria === 'redes' ? 'selected' : '' %>>Redes & Cableado Estructurado</option>
<option value="electricidad" <%= s.categoria === 'electricidad' ? 'selected' : '' %>>Electricidad & Potencia</option>
<option value="general" <%= s.categoria === 'general' ? 'selected' : '' %>>Herramientas Generales</option>
</select>
</div>
<div class="col-md-6">
<label class="form-label small fw-bold">Estado del Kit</label>
<select name="is_active" class="form-select">
<option value="1" <%= s.is_active ? 'selected' : '' %>>Activo (Disponible para despacho)</option>
<option value="0" <%= !s.is_active ? 'selected' : '' %>>Inactivo (Bloqueado temporalmente)</option>
</select>
</div>
<div class="col-12">
<label class="form-label small fw-bold">Descripción / Alcance</label>
<textarea name="descripcion" class="form-control" rows="2"><%= s.descripcion || '' %></textarea>
</div>
<div class="col-12">
<label class="form-label small fw-bold"><i class="fas fa-camera text-primary me-1"></i> Fotografía del Set / Maletín</label>
<% if (s.foto_url) { %>
<div class="d-flex align-items-center gap-2 mb-2 p-2 border rounded bg-light">
<img src="<%= s.foto_url %>" alt="Foto" class="rounded border" style="width: 50px; height: 50px; object-fit: cover;">
<span class="small text-muted">Fotografía actual del kit registrada. Selecciona una nueva imagen para reemplazarla.</span>
</div>
<% } %>
<input type="file" name="foto" accept="image/*" class="form-control">
</div>
<div class="col-12">
<label class="form-label small fw-bold mb-1">Seleccionar Herramientas del Inventario</label>
<div class="border rounded p-2.5" style="max-height: 200px; overflow-y: auto;">
<% const currentItemIds = (s.herramientas || []).map(item => item.id); %>
<% herramientas.forEach(h => { %>
<div class="form-check py-1">
<input class="form-check-input" type="checkbox" name="herramientas_ids" value="<%= h.id %>" id="checkSet<%= s.id %>_<%= h.id %>" <%= currentItemIds.includes(h.id) ? 'checked' : '' %>>
<label class="form-check-label small d-flex align-items-center justify-content-between" for="checkSet<%= s.id %>_<%= h.id %>">
<span><strong><%= h.nombre %></strong> <% if (h.marca) { %><span class="text-muted">(<%= h.marca %>)</span><% } %></span>
<span class="badge bg-light text-muted border font-monospace ms-2"><%= h.codigo || h.numero_serie || 'SN-N/D' %></span>
</label>
</div>
<% }) %>
</div>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-light border" data-bs-dismiss="modal">Cancelar</button>
<button type="submit" class="btn btn-primary">Guardar Cambios</button>
</div>
</form>
</div>
</div>
</div>
<!-- MODAL ASIGNAR DIRECTO -->
<div class="modal fade" id="modalAsignarDirecto<%= s.id %>" tabindex="-1" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content rounded-3 border-0 shadow">
<form action="/admin/herramientas/asignar" method="POST" enctype="multipart/form-data">
<input type="hidden" name="set_id" value="<%= s.id %>">
<div class="modal-header bg-primary text-white">
<h5 class="modal-title fw-bold">Asignar Kit: <%= s.nombre %></h5>
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<div class="mb-3">
<label class="form-label small fw-bold">Técnico Responsable *</label>
<select name="tecnico_id" class="form-select" required>
<option value="">-- Seleccionar Técnico --</option>
<% tecnicos.forEach(t => { %>
<option value="<%= t.id %>"><%= t.nombre %> (<%= t.email %>)</option>
<% }) %>
</select>
</div>
<div class="mb-3">
<label class="form-label small fw-bold">Tipo de Asignación</label>
<select name="tipo_asignacion" class="form-select">
<option value="dotacion_fija">Dotación Fija (Custodia permanente del técnico)</option>
<option value="visita_fsm">Asignación Temporal de Turno / Visita</option>
</select>
</div>
<div class="mb-3">
<label class="form-label small fw-bold">Observaciones de Entrega</label>
<textarea name="observaciones_entrega" class="form-control" rows="2" placeholder="Ej: Entregado completo con estuche y cargadores en buen estado"></textarea>
</div>
<div class="mb-3">
<label class="form-label small fw-bold"><i class="fas fa-camera text-primary me-1"></i> Foto de Evidencia / Entrega (Opcional)</label>
<input type="file" name="foto_entrega" accept="image/*" class="form-control">
<small class="text-muted" style="font-size: 0.72rem;">Respaldo fotográfico del estado del kit entregado en custodia.</small>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-light border" data-bs-dismiss="modal">Cancelar</button>
<button type="submit" class="btn btn-primary fw-bold">Confirmar Asignación</button>
</div>
</form>
</div>
</div>
</div>
<% }) %>
</div>
</div>
<!-- ============================================== -->
<!-- TAB 2: INVENTARIO DETALLADO DE HERRAMIENTAS -->
<!-- ============================================== -->
<div class="tab-pane fade" id="tab-herramientas" role="tabpanel">
<div class="app-card border shadow-sm rounded-3 overflow-hidden">
<div class="table-responsive">
<table class="table table-hover align-middle mb-0" style="font-size: 0.85rem;">
<thead class="table-light text-muted small text-uppercase">
<tr>
<th class="ps-3">Código</th>
<th>Herramienta / Instrumento</th>
<th>Categoría</th>
<th>Marca & Modelo</th>
<th>Nº Serie</th>
<th>Ubicación</th>
<th>Estado</th>
<th class="text-end pe-3">Acciones</th>
</tr>
</thead>
<tbody>
<% if (herramientas.length === 0) { %>
<tr>
<td colspan="8" class="text-center py-4 text-muted">No hay herramientas registradas en el catálogo.</td>
</tr>
<% } %>
<% herramientas.forEach(h => { %>
<tr>
<td class="ps-3 font-monospace fw-bold text-dark"><%= h.codigo || 'HERR-' + h.id %></td>
<td>
<div class="d-flex align-items-center gap-2.5">
<% if (h.foto_url) { %>
<a href="<%= h.foto_url %>" target="_blank" class="flex-shrink-0" title="Ver foto ampliada">
<img src="<%= h.foto_url %>" alt="<%= h.nombre %>" class="rounded border shadow-sm" style="width: 42px; height: 42px; object-fit: cover;">
</a>
<% } else { %>
<div class="icon-circle bg-light text-muted border flex-shrink-0" style="width: 42px; height: 42px; border-radius: 8px; display: flex; align-items: center; justify-content: center; font-size: 0.95rem;">
<i class="fas fa-tools"></i>
</div>
<% } %>
<div>
<strong class="text-dark"><%= h.nombre %></strong>
<% if (h.notas) { %><div class="small text-muted text-truncate" style="max-width: 250px;"><%= h.notas %></div><% } %>
</div>
</div>
</td>
<td>
<span class="badge bg-light text-dark border"><%= h.categoria %></span>
</td>
<td>
<%= h.marca || '-' %> <%= h.modelo ? `(${h.modelo})` : '' %>
</td>
<td class="font-monospace text-muted"><%= h.numero_serie || 'N/D' %></td>
<td>
<i class="fas fa-warehouse text-muted me-1"></i> <%= h.ubicacion_bodega || 'Bodega Central' %>
</td>
<td>
<% if (h.estado === 'operativo') { %>
<span class="badge bg-success-subtle text-success border border-success-subtle"><i class="fas fa-check-circle me-1"></i> Operativo</span>
<% } else if (h.estado === 'en_mantenimiento') { %>
<span class="badge bg-warning-subtle text-warning border border-warning-subtle"><i class="fas fa-wrench me-1"></i> Mantenimiento</span>
<% } else if (h.estado === 'danado') { %>
<span class="badge bg-danger-subtle text-danger border border-danger-subtle"><i class="fas fa-times-circle me-1"></i> Dañado</span>
<% } else { %>
<span class="badge bg-secondary"><%= h.estado %></span>
<% } %>
</td>
<td class="text-end pe-3">
<button type="button" class="btn btn-sm btn-light border" data-bs-toggle="modal" data-bs-target="#modalEditarHerramienta<%= h.id %>" title="Editar">
<i class="fas fa-edit text-secondary"></i>
</button>
<form action="/admin/herramientas/delete/<%= h.id %>" method="POST" onsubmit="return confirm('¿Eliminar esta herramienta?');" class="d-inline">
<button type="submit" class="btn btn-sm btn-light border text-danger" title="Eliminar">
<i class="fas fa-trash-alt"></i>
</button>
</form>
</td>
</tr>
<!-- MODAL EDITAR HERRAMIENTA -->
<div class="modal fade" id="modalEditarHerramienta<%= h.id %>" tabindex="-1" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content rounded-3 border-0 shadow">
<form action="/admin/herramientas/edit/<%= h.id %>" method="POST" enctype="multipart/form-data">
<div class="modal-header">
<h5 class="modal-title fw-bold">Editar Herramienta: <%= h.nombre %></h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<div class="row g-3">
<div class="col-md-8">
<label class="form-label small fw-bold">Nombre *</label>
<input type="text" name="nombre" class="form-control" value="<%= h.nombre %>" required>
</div>
<div class="col-md-4">
<label class="form-label small fw-bold">Código</label>
<input type="text" name="codigo" class="form-control font-monospace" value="<%= h.codigo || '' %>">
</div>
<div class="col-md-4">
<label class="form-label small fw-bold">Categoría</label>
<select name="categoria" class="form-select">
<option value="fibra_optica" <%= h.categoria === 'fibra_optica' ? 'selected' : '' %>>Fibra Óptica</option>
<option value="cctv" <%= h.categoria === 'cctv' ? 'selected' : '' %>>Seguridad & CCTV</option>
<option value="redes" <%= h.categoria === 'redes' ? 'selected' : '' %>>Redes & Cableado</option>
<option value="electricidad" <%= h.categoria === 'electricidad' ? 'selected' : '' %>>Electricidad</option>
<option value="medicion" <%= h.categoria === 'medicion' ? 'selected' : '' %>>Instrumento de Medición</option>
<option value="mano" <%= h.categoria === 'mano' ? 'selected' : '' %>>Herramienta Manual/Poder</option>
<option value="general" <%= h.categoria === 'general' ? 'selected' : '' %>>General</option>
</select>
</div>
<div class="col-md-4">
<label class="form-label small fw-bold">Marca</label>
<input type="text" name="marca" class="form-control" value="<%= h.marca || '' %>">
</div>
<div class="col-md-4">
<label class="form-label small fw-bold">Modelo</label>
<input type="text" name="modelo" class="form-control" value="<%= h.modelo || '' %>">
</div>
<div class="col-md-6">
<label class="form-label small fw-bold">Número de Serie</label>
<input type="text" name="numero_serie" class="form-control font-monospace" value="<%= h.numero_serie || '' %>">
</div>
<div class="col-md-6">
<label class="form-label small fw-bold">Estado Físico / Operativo</label>
<select name="estado" class="form-select">
<option value="operativo" <%= h.estado === 'operativo' ? 'selected' : '' %>>Operativo (Listo para uso)</option>
<option value="en_mantenimiento" <%= h.estado === 'en_mantenimiento' ? 'selected' : '' %>>En Mantenimiento / Calibración</option>
<option value="danado" <%= h.estado === 'danado' ? 'selected' : '' %>>Dañado / Requiere Reparación</option>
<option value="baja" <%= h.estado === 'baja' ? 'selected' : '' %>>Dado de Baja</option>
</select>
</div>
<div class="col-12">
<label class="form-label small fw-bold">Ubicación en Bodega / Almacén</label>
<input type="text" name="ubicacion_bodega" class="form-control" value="<%= h.ubicacion_bodega || '' %>">
</div>
<div class="col-12">
<label class="form-label small fw-bold">Notas Adicionales</label>
<textarea name="notas" class="form-control" rows="2"><%= h.notas || '' %></textarea>
</div>
<div class="col-12">
<label class="form-label small fw-bold"><i class="fas fa-camera text-primary me-1"></i> Fotografía del Instrumento / Placa</label>
<% if (h.foto_url) { %>
<div class="d-flex align-items-center gap-2 mb-2 p-2 border rounded bg-light">
<img src="<%= h.foto_url %>" alt="Foto" class="rounded border" style="width: 50px; height: 50px; object-fit: cover;">
<span class="small text-muted">Fotografía actual registrada. Selecciona una nueva imagen si deseas actualizarla.</span>
</div>
<% } %>
<input type="file" name="foto" accept="image/*" class="form-control">
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-light border" data-bs-dismiss="modal">Cancelar</button>
<button type="submit" class="btn btn-primary">Guardar Cambios</button>
</div>
</form>
</div>
</div>
</div>
<% }) %>
</tbody>
</table>
</div>
</div>
</div>
<!-- ============================================== -->
<!-- TAB 3: ASIGNACIONES A TÉCNICOS -->
<!-- ============================================== -->
<div class="tab-pane fade" id="tab-asignaciones" role="tabpanel">
<div class="app-card border shadow-sm rounded-3 overflow-hidden">
<div class="table-responsive">
<table class="table table-hover align-middle mb-0" style="font-size: 0.85rem;">
<thead class="table-light text-muted small text-uppercase">
<tr>
<th class="ps-3">Técnico</th>
<th>Kit / Herramienta Asignada</th>
<th>Modalidad</th>
<th>Fecha Asignación</th>
<th>Contexto / Visita</th>
<th>Evidencia Fotográfica</th>
<th>Estado</th>
<th class="text-end pe-3">Acciones</th>
</tr>
</thead>
<tbody>
<% if (asignaciones.length === 0) { %>
<tr>
<td colspan="8" class="text-center py-4 text-muted">No hay asignaciones registradas actualmente.</td>
</tr>
<% } %>
<% asignaciones.forEach(a => { %>
<tr>
<td class="ps-3">
<div class="fw-bold text-dark"><%= a.tecnico_nombre %></div>
<div class="text-muted small" style="font-size: 0.75rem;"><%= a.tecnico_email %></div>
</td>
<td>
<% if (a.set_nombre) { %>
<div class="fw-bold text-primary"><i class="fas fa-layer-group me-1"></i> <%= a.set_nombre %></div>
<% if (a.set_codigo) { %><span class="badge bg-light text-muted border font-monospace" style="font-size: 0.65rem;"><%= a.set_codigo %></span><% } %>
<% } else if (a.herramienta_nombre) { %>
<div class="fw-bold text-dark"><i class="fas fa-wrench me-1"></i> <%= a.herramienta_nombre %></div>
<% if (a.herramienta_codigo) { %><span class="badge bg-light text-muted border font-monospace" style="font-size: 0.65rem;"><%= a.herramienta_codigo %></span><% } %>
<% } else { %>
<span class="text-muted">Equipamiento general</span>
<% } %>
</td>
<td>
<% if (a.tipo_asignacion === 'dotacion_fija') { %>
<span class="badge bg-info-subtle text-info border border-info-subtle"><i class="fas fa-id-badge me-1"></i> Dotación Fija</span>
<% } else { %>
<span class="badge bg-warning-subtle text-dark border border-warning-subtle"><i class="fas fa-truck-pickup me-1"></i> Visita Terreno</span>
<% } %>
</td>
<td>
<div><%= new Date(a.fecha_asignacion).toLocaleDateString('es-EC') %></div>
<div class="text-muted small" style="font-size: 0.72rem;"><%= new Date(a.fecha_asignacion).toLocaleTimeString('es-EC') %></div>
</td>
<td>
<% if (a.ticket_id) { %>
<a href="/agent/ticket/<%= a.ticket_id %>" class="text-decoration-none fw-semibold">
Ticket #<%= a.ticket_id %>
</a>
<div class="text-muted small text-truncate" style="max-width: 180px;"><%= a.visita_titulo || a.ticket_asunto || '' %></div>
<% } else { %>
<span class="text-muted small"><%= a.observaciones_entrega || 'Sin observaciones' %></span>
<% } %>
</td>
<td>
<div class="d-flex flex-column gap-1">
<% if (a.qr_token) { %>
<a href="/qr/asignacion/<%= a.qr_token %>" target="_blank" class="badge bg-dark-subtle text-dark border text-decoration-none d-inline-flex align-items-center gap-1" style="font-size: 0.7rem;" title="Ver Manifiesto Digital QR">
<i class="fas fa-qrcode"></i> <span>Manifiesto QR</span>
</a>
<% } %>
<% if (a.foto_entrega_url) { %>
<a href="<%= a.foto_entrega_url %>" target="_blank" class="badge bg-primary-subtle text-primary border border-primary-subtle text-decoration-none d-inline-flex align-items-center gap-1" style="font-size: 0.7rem;">
<i class="fas fa-camera"></i> <span>Foto Entrega</span>
</a>
<% } %>
<% if (a.foto_devolucion_url) { %>
<a href="<%= a.foto_devolucion_url %>" target="_blank" class="badge bg-success-subtle text-success border border-success-subtle text-decoration-none d-inline-flex align-items-center gap-1" style="font-size: 0.7rem;">
<i class="fas fa-camera"></i> <span>Foto Devolución</span>
</a>
<% } %>
<% if (!a.foto_entrega_url && !a.foto_devolucion_url && !a.qr_token) { %>
<span class="text-muted small" style="font-size: 0.72rem;">Sin datos</span>
<% } %>
</div>
</td>
<td>
<% if (a.estado === 'asignado') { %>
<span class="badge bg-success"><i class="fas fa-user-check me-1"></i> En Custodia</span>
<% } else if (a.estado === 'devuelto') { %>
<span class="badge bg-secondary"><i class="fas fa-undo me-1"></i> Devuelto</span>
<% if (a.fecha_devolucion) { %>
<div class="text-muted" style="font-size: 0.68rem;"><%= new Date(a.fecha_devolucion).toLocaleDateString('es-EC') %></div>
<% } %>
<% } else { %>
<span class="badge bg-warning text-dark"><%= a.estado %></span>
<% } %>
</td>
<td class="text-end pe-3">
<% if (a.estado === 'asignado') { %>
<button type="button" class="btn btn-sm btn-outline-success d-inline-flex align-items-center gap-1" data-bs-toggle="modal" data-bs-target="#modalDevolver<%= a.id %>">
<i class="fas fa-undo-alt"></i>
<span>Devolver</span>
</button>
<% } else { %>
<span class="text-muted small" style="font-size: 0.75rem;"><%= a.observaciones_devolucion || 'Finalizado' %></span>
<% } %>
</td>
</tr>
<!-- MODAL DEVOLVER -->
<div class="modal fade" id="modalDevolver<%= a.id %>" tabindex="-1" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content rounded-3 border-0 shadow">
<form action="/admin/herramientas/devolver/<%= a.id %>" method="POST" enctype="multipart/form-data">
<div class="modal-header bg-success text-white">
<h5 class="modal-title fw-bold">Registrar Devolución a Bodega</h5>
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<p class="small text-muted mb-3">
Confirmar el reingreso del kit <strong><%= a.set_nombre || a.herramienta_nombre %></strong> retornado por <strong><%= a.tecnico_nombre %></strong>.
</p>
<div class="mb-3">
<label class="form-label small fw-bold">Condición al Reingreso</label>
<select name="estado" class="form-select">
<option value="devuelto">Devuelto en Buen Estado / Operativo</option>
<option value="observado">Con Observaciones / Ítem Dañado o Faltante</option>
</select>
</div>
<div class="mb-3">
<label class="form-label small fw-bold">Observaciones de Devolución</label>
<textarea name="observaciones_devolucion" class="form-control" rows="2" placeholder="Ej: Kit revisado e ingresado completo al estante A1 sin novedades"></textarea>
</div>
<div class="mb-3">
<label class="form-label small fw-bold"><i class="fas fa-camera text-success me-1"></i> Foto de Evidencia de Retorno (Opcional)</label>
<input type="file" name="foto_devolucion" accept="image/*" class="form-control">
<small class="text-muted" style="font-size: 0.72rem;">Constancia fotográfica del estado físico al reingreso en bodega.</small>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-light border" data-bs-dismiss="modal">Cancelar</button>
<button type="submit" class="btn btn-success fw-bold">Confirmar Devolución</button>
</div>
</form>
</div>
</div>
</div>
<% }) %>
</tbody>
</table>
</div>
</div>
</div>
</div>
<!-- ============================================== -->
<!-- MODALES GLOBALES DE CREACIÓN -->
<!-- ============================================== -->
<!-- MODAL NUEVA HERRAMIENTA -->
<div class="modal fade" id="modalNuevaHerramienta" tabindex="-1" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content rounded-3 border-0 shadow">
<form action="/admin/herramientas/create" method="POST" enctype="multipart/form-data">
<div class="modal-header bg-primary text-white">
<h5 class="modal-title fw-bold"><i class="fas fa-plus-circle me-1"></i> Registrar Nueva Herramienta / Instrumento</h5>
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body p-4">
<div class="row g-3">
<div class="col-md-8">
<label class="form-label small fw-bold">Nombre de la Herramienta *</label>
<input type="text" name="nombre" class="form-control" placeholder="Ej: Fusionadora de Fibra Óptica" required>
</div>
<div class="col-md-4">
<label class="form-label small fw-bold">Código / Placa Interna</label>
<input type="text" name="codigo" class="form-control font-monospace" placeholder="Ej: TOOL-FIB-02">
</div>
<div class="col-md-4">
<label class="form-label small fw-bold">Categoría</label>
<select name="categoria" class="form-select">
<option value="cctv">Seguridad Electrónica & CCTV</option>
<option value="fibra_optica">Fibra Óptica & Enlaces</option>
<option value="redes">Redes & Cableado Estructurado</option>
<option value="electricidad">Electricidad & Tableros</option>
<option value="medicion">Instrumento de Medición</option>
<option value="mano">Herramienta Manual / Eléctrica</option>
<option value="general" selected>General</option>
</select>
</div>
<div class="col-md-4">
<label class="form-label small fw-bold">Marca</label>
<input type="text" name="marca" class="form-control" placeholder="Ej: Fluke, DeWalt, Fujikura">
</div>
<div class="col-md-4">
<label class="form-label small fw-bold">Modelo</label>
<input type="text" name="modelo" class="form-control" placeholder="Ej: 70S Pro">
</div>
<div class="col-md-6">
<label class="form-label small fw-bold">Número de Serie del Fabricante</label>
<input type="text" name="numero_serie" class="form-control font-monospace" placeholder="Ej: SN-998241A">
</div>
<div class="col-md-6">
<label class="form-label small fw-bold">Estado Inicial</label>
<select name="estado" class="form-select">
<option value="operativo" selected>Operativo (Listo para asignación)</option>
<option value="en_mantenimiento">En Mantenimiento</option>
<option value="danado">Dañado</option>
</select>
</div>
<div class="col-12">
<label class="form-label small fw-bold">Ubicación en Bodega</label>
<input type="text" name="ubicacion_bodega" class="form-control" placeholder="Ej: Bodega Central - Gaveta 4, Estante B">
</div>
<div class="col-12">
<label class="form-label small fw-bold">Observaciones / Especificaciones</label>
<textarea name="notas" class="form-control" rows="2" placeholder="Detalles de calibración, accesorios incluidos o precauciones"></textarea>
</div>
<div class="col-12">
<label class="form-label small fw-bold"><i class="fas fa-camera text-primary me-1"></i> Fotografía del Instrumento / Placa (Opcional)</label>
<input type="file" name="foto" accept="image/*" class="form-control">
<small class="text-muted" style="font-size: 0.72rem;">Sube una foto del equipo o su número de serie para reconocimiento visual en bodega y campo (JPG, PNG o WEBP).</small>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-light border" data-bs-dismiss="modal">Cancelar</button>
<button type="submit" class="btn btn-primary fw-bold">Guardar en Inventario</button>
</div>
</form>
</div>
</div>
</div>
<!-- MODAL NUEVO SET / KIT -->
<div class="modal fade" id="modalNuevoSet" tabindex="-1" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content rounded-3 border-0 shadow">
<form action="/admin/herramientas/sets/create" method="POST" enctype="multipart/form-data">
<div class="modal-header bg-warning text-dark">
<h5 class="modal-title fw-bold"><i class="fas fa-layer-group me-1"></i> Crear Set / Kit de Herramientas</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body p-4">
<div class="row g-3">
<div class="col-md-8">
<label class="form-label small fw-bold">Nombre del Set / Kit *</label>
<input type="text" name="nombre" class="form-control" placeholder="Ej: Kit Seguridad CCTV & Control de Accesos" required>
</div>
<div class="col-md-4">
<label class="form-label small fw-bold">Código del Kit</label>
<input type="text" name="codigo" class="form-control font-monospace" placeholder="Ej: SET-CCTV-02">
</div>
<div class="col-md-6">
<label class="form-label small fw-bold">Categoría de Especialidad</label>
<select name="categoria" class="form-select">
<option value="cctv">Seguridad Electrónica & CCTV</option>
<option value="fibra_optica">Fibra Óptica & Enlaces</option>
<option value="redes">Redes & Cableado Estructurado</option>
<option value="electricidad">Electricidad & Potencia</option>
<option value="general" selected>General / Multiuso</option>
</select>
</div>
<div class="col-md-6">
<label class="form-label small fw-bold">Descripción del Kit</label>
<input type="text" name="descripcion" class="form-control" placeholder="Ej: Kit completo para instalación y certificación en campo">
</div>
<div class="col-12">
<label class="form-label small fw-bold"><i class="fas fa-camera text-warning me-1"></i> Fotografía del Set / Maletín (Opcional)</label>
<input type="file" name="foto" accept="image/*" class="form-control">
<small class="text-muted" style="font-size: 0.72rem;">Foto general del kit o maletín con sus componentes organizados.</small>
</div>
<div class="col-12">
<label class="form-label small fw-bold mb-1">Seleccionar Herramientas a Integrar en este Set</label>
<div class="border rounded p-2.5 bg-light" style="max-height: 220px; overflow-y: auto;">
<% if (herramientas.length === 0) { %>
<div class="small text-muted p-2">No hay herramientas disponibles en el catálogo. Registra herramientas primero.</div>
<% } %>
<% herramientas.forEach(h => { %>
<div class="form-check py-1 border-bottom border-light">
<input class="form-check-input" type="checkbox" name="herramientas_ids" value="<%= h.id %>" id="checkNewSet_<%= h.id %>">
<label class="form-check-label small d-flex align-items-center justify-content-between" for="checkNewSet_<%= h.id %>">
<span class="d-flex align-items-center gap-1.5">
<% if (h.foto_url) { %>
<img src="<%= h.foto_url %>" alt="Foto" class="rounded" style="width: 22px; height: 22px; object-fit: cover;">
<% } %>
<strong><%= h.nombre %></strong>
<% if (h.marca) { %><span class="text-muted">(<%= h.marca %>)</span><% } %>
</span>
<span class="badge bg-white text-muted border font-monospace ms-2">
<%= h.codigo || h.numero_serie || 'SN-N/D' %>
</span>
</label>
</div>
<% }) %>
</div>
<small class="text-muted" style="font-size: 0.72rem;">Podrás marcar los instrumentos que conforman el equipamiento estándar de este kit.</small>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-light border" data-bs-dismiss="modal">Cancelar</button>
<button type="submit" class="btn btn-warning fw-bold text-dark">Crear Kit</button>
</div>
</form>
</div>
</div>
</div>
<!-- MODAL ASIGNAR GENERAL -->
<div class="modal fade" id="modalAsignar" tabindex="-1" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content rounded-3 border-0 shadow">
<form action="/admin/herramientas/asignar" method="POST" enctype="multipart/form-data">
<div class="modal-header bg-primary text-white">
<h5 class="modal-title fw-bold"><i class="fas fa-user-tag me-1"></i> Asignar Set de Herramientas a Técnico</h5>
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body p-4">
<div class="mb-3">
<label class="form-label small fw-bold">Técnico Receptor *</label>
<select name="tecnico_id" class="form-select" required>
<option value="">-- Seleccionar Técnico --</option>
<% tecnicos.forEach(t => { %>
<option value="<%= t.id %>"><%= t.nombre %> (<%= t.email %>)</option>
<% }) %>
</select>
</div>
<div class="mb-3">
<label class="form-label small fw-bold">Set / Kit a Asignar *</label>
<select name="set_id" class="form-select" required>
<option value="">-- Seleccionar Set / Kit --</option>
<% sets.forEach(s => { %>
<option value="<%= s.id %>"><%= s.nombre %> <%= s.codigo ? `(${s.codigo})` : '' %> — <%= s.total_herramientas || (s.herramientas ? s.herramientas.length : 0) %> herramientas</option>
<% }) %>
</select>
</div>
<div class="mb-3">
<label class="form-label small fw-bold">Tipo de Asignación</label>
<select name="tipo_asignacion" class="form-select">
<option value="dotacion_fija">Dotación Fija (Custodia permanente del técnico)</option>
<option value="visita_fsm">Asignación Temporal para Turno / Proyecto</option>
</select>
</div>
<div class="mb-3">
<label class="form-label small fw-bold">Observaciones de Entrega</label>
<textarea name="observaciones_entrega" class="form-control" rows="2" placeholder="Ej: Entregado maletín completo con precintos y cargadores"></textarea>
</div>
<div class="mb-3">
<label class="form-label small fw-bold"><i class="fas fa-camera text-primary me-1"></i> Foto de Evidencia / Entrega (Opcional)</label>
<input type="file" name="foto_entrega" accept="image/*" class="form-control">
<small class="text-muted" style="font-size: 0.72rem;">Respaldo fotográfico del estado del kit entregado al técnico.</small>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-light border" data-bs-dismiss="modal">Cancelar</button>
<button type="submit" class="btn btn-primary fw-bold">Confirmar Asignación</button>
</div>
</form>
</div>
</div>
</div>
<script>
// Activar pestaña según el hash de URL (#tab-herramientas, #tab-sets, #tab-asignaciones)
document.addEventListener('DOMContentLoaded', function() {
const hash = window.location.hash;
if (hash) {
const btn = document.querySelector(`button[data-bs-target="${hash}"]`);
if (btn) {
const tab = new bootstrap.Tab(btn);
tab.show();
}
}
});
</script>
<%- include('../partials/footer') %>