grales
This commit is contained in:
790
views/templates_rapidos/crear.php
Normal file
790
views/templates_rapidos/crear.php
Normal file
@@ -0,0 +1,790 @@
|
||||
<?php include __DIR__ . '/../partials/sidebar_importador.php'; ?>
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="es">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>➕ Nuevo Template Rápido</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/choices.js/public/assets/styles/choices.min.css"/>
|
||||
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
|
||||
<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
|
||||
<style>
|
||||
body { font-family: 'Segoe UI', sans-serif; background-color: #f4f6f9; }
|
||||
.sidebar { width: 220px; height: 100vh; background-color: #343a40; position: fixed; top: 0; left: 0; padding-top: 56px; z-index: 1040; }
|
||||
.sidebar .nav-link { font-weight: bold; color: white; transition: all 0.3s ease; }
|
||||
.sidebar .nav-link:hover, .sidebar .nav-link.active { background-color: #495057; color: #fff; }
|
||||
.content { margin-top: 56px; padding: 40px 20px; position: relative; z-index: 1; background-color: #f4f6f9; transition: margin-left 0.3s ease; }
|
||||
@media (min-width: 768px) { .content { margin-left: 250px; } }
|
||||
@media (max-width: 767.98px) {
|
||||
.content { margin-left: 0; }
|
||||
.sidebar .nav-link { font-weight: normal; color: #343a40; background-color: transparent; }
|
||||
.sidebar .nav-link:hover, .sidebar .nav-link.active { background-color: #e9ecef; color: #212529; }
|
||||
}
|
||||
.card {
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 4px 12px rgba(0,0,0,0.1);
|
||||
border: none;
|
||||
}
|
||||
.btn-animated {
|
||||
transition: all 0.3s ease;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
.btn-animated:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
.form-control:focus, .form-select:focus {
|
||||
border-color: #0d6efd;
|
||||
box-shadow: 0 0 0 0.2rem rgba(13, 110, 253, 0.25);
|
||||
}
|
||||
.emoji-picker {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(8, 1fr);
|
||||
gap: 8px;
|
||||
padding: 15px;
|
||||
max-height: 250px;
|
||||
overflow-y: auto;
|
||||
border: 1px solid #dee2e6;
|
||||
border-radius: 8px;
|
||||
background: white;
|
||||
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
|
||||
}
|
||||
.emoji-item {
|
||||
padding: 10px;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
border-radius: 6px;
|
||||
transition: all 0.2s ease;
|
||||
font-size: 20px;
|
||||
border: 2px solid transparent;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-height: 40px;
|
||||
}
|
||||
.emoji-item:hover {
|
||||
background-color: #e3f2fd;
|
||||
border-color: #2196f3;
|
||||
transform: scale(1.1);
|
||||
}
|
||||
.emoji-item.selected {
|
||||
background-color: #1976d2;
|
||||
color: white;
|
||||
border-color: #0d47a1;
|
||||
}
|
||||
.preview-card {
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
color: white;
|
||||
border-radius: 12px;
|
||||
padding: 20px;
|
||||
margin-top: 10px;
|
||||
box-shadow: 0 4px 15px rgba(0,0,0,0.2);
|
||||
}
|
||||
.template-preview-item {
|
||||
background: rgba(255,255,255,0.2);
|
||||
border: 1px solid rgba(255,255,255,0.3);
|
||||
color: white;
|
||||
padding: 8px 14px;
|
||||
border-radius: 25px;
|
||||
font-size: 11px;
|
||||
font-weight: 500;
|
||||
margin: 3px;
|
||||
display: inline-block;
|
||||
backdrop-filter: blur(10px);
|
||||
}
|
||||
.section-header {
|
||||
background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
|
||||
padding: 15px 20px;
|
||||
margin: -15px -15px 20px -15px;
|
||||
border-radius: 8px 8px 0 0;
|
||||
border-bottom: 1px solid #dee2e6;
|
||||
}
|
||||
.section-header h6 {
|
||||
margin: 0;
|
||||
color: #495057;
|
||||
font-weight: 600;
|
||||
}
|
||||
.icon-preview {
|
||||
font-size: 24px;
|
||||
margin-right: 8px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
background: rgba(255,255,255,0.1);
|
||||
border-radius: 8px;
|
||||
border: 1px solid rgba(255,255,255,0.2);
|
||||
}
|
||||
.form-label {
|
||||
font-weight: 600;
|
||||
color: #495057;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
.choices__inner {
|
||||
min-height: 42px !important;
|
||||
border: 1px solid #ced4da !important;
|
||||
border-radius: 6px !important;
|
||||
}
|
||||
.choices__inner:focus {
|
||||
border-color: #0d6efd !important;
|
||||
box-shadow: 0 0 0 0.2rem rgba(13, 110, 253, 0.25) !important;
|
||||
}
|
||||
.loading-spinner {
|
||||
display: inline-block;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
border: 3px solid rgba(255,255,255,.3);
|
||||
border-radius: 50%;
|
||||
border-top-color: #fff;
|
||||
animation: spin 1s ease-in-out infinite;
|
||||
}
|
||||
@keyframes spin {
|
||||
to { transform: rotate(360deg); }
|
||||
}
|
||||
.tips-section {
|
||||
background: linear-gradient(135deg, #e3f2fd 0%, #bbdefb 100%);
|
||||
border-radius: 8px;
|
||||
padding: 15px;
|
||||
margin-top: 15px;
|
||||
}
|
||||
.tip-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 8px;
|
||||
font-size: 13px;
|
||||
color: #1565c0;
|
||||
}
|
||||
.tip-item:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.tip-item i {
|
||||
margin-right: 8px;
|
||||
width: 16px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="content">
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<h4 class="mb-0">➕ Nuevo Template Rápido</h4>
|
||||
<a href="/IMPORTADORES/templates_rapidos/lista" class="btn btn-secondary btn-animated">
|
||||
<i class="fas fa-arrow-left me-1"></i>Volver a Lista
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<!-- Formulario Principal -->
|
||||
<div class="col-lg-8">
|
||||
<div class="card">
|
||||
<div class="card-body p-4">
|
||||
<form id="templateForm" action="/IMPORTADORES/templates_rapidos/guardar" method="POST">
|
||||
|
||||
<!-- Información Básica -->
|
||||
<div class="section-header">
|
||||
<h6 class="mb-0"><i class="fas fa-info-circle me-2"></i>Información Básica</h6>
|
||||
</div>
|
||||
|
||||
<div class="row mb-4">
|
||||
<div class="col-md-6">
|
||||
<label for="nombre" class="form-label">Nombre del Template *</label>
|
||||
<input id="nombre" name="nombre" type="text" class="form-control" required
|
||||
placeholder="ej. Importación China" maxlength="100">
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label for="icono" class="form-label">Icono</label>
|
||||
<div class="input-group">
|
||||
<span class="input-group-text" id="icon-display" style="font-size: 20px;">🏢</span>
|
||||
<input id="icono" name="icono" type="text" class="form-control" value="🏢" readonly>
|
||||
<button type="button" class="btn btn-outline-secondary dropdown-toggle"
|
||||
data-bs-toggle="dropdown" aria-expanded="false">
|
||||
<i class="fas fa-palette"></i>
|
||||
</button>
|
||||
<div class="dropdown-menu dropdown-menu-end p-0" style="width: 320px;">
|
||||
<div class="p-2">
|
||||
<h6 class="dropdown-header">🌍 Países</h6>
|
||||
<div class="emoji-picker" style="max-height: 120px;">
|
||||
<div class="emoji-item" data-emoji="🇨🇳">🇨🇳</div>
|
||||
<div class="emoji-item" data-emoji="🇺🇸">🇺🇸</div>
|
||||
<div class="emoji-item" data-emoji="🇪🇺">🇪🇺</div>
|
||||
<div class="emoji-item" data-emoji="🇩🇪">🇩🇪</div>
|
||||
<div class="emoji-item" data-emoji="🇯🇵">🇯🇵</div>
|
||||
<div class="emoji-item" data-emoji="🇰🇷">🇰🇷</div>
|
||||
<div class="emoji-item" data-emoji="🇮🇹">🇮🇹</div>
|
||||
<div class="emoji-item" data-emoji="🇫🇷">🇫🇷</div>
|
||||
<div class="emoji-item" data-emoji="🇨🇦">🇨🇦</div>
|
||||
<div class="emoji-item" data-emoji="🇧🇷">🇧🇷</div>
|
||||
<div class="emoji-item" data-emoji="🇮🇳">🇮🇳</div>
|
||||
<div class="emoji-item" data-emoji="🇹🇼">🇹🇼</div>
|
||||
</div>
|
||||
|
||||
<h6 class="dropdown-header mt-3">🏢 Empresas & Logística</h6>
|
||||
<div class="emoji-picker" style="max-height: 120px;">
|
||||
<div class="emoji-item" data-emoji="🏢">🏢</div>
|
||||
<div class="emoji-item" data-emoji="🏭">🏭</div>
|
||||
<div class="emoji-item" data-emoji="🏪">🏪</div>
|
||||
<div class="emoji-item" data-emoji="🏬">🏬</div>
|
||||
<div class="emoji-item" data-emoji="🚢">🚢</div>
|
||||
<div class="emoji-item" data-emoji="✈️">✈️</div>
|
||||
<div class="emoji-item" data-emoji="🚛">🚛</div>
|
||||
<div class="emoji-item" data-emoji="🚚">🚚</div>
|
||||
<div class="emoji-item" data-emoji="📦">📦</div>
|
||||
<div class="emoji-item" data-emoji="📋">📋</div>
|
||||
<div class="emoji-item" data-emoji="💼">💼</div>
|
||||
<div class="emoji-item" data-emoji="📊">📊</div>
|
||||
</div>
|
||||
|
||||
<h6 class="dropdown-header mt-3">⭐ Destacados</h6>
|
||||
<div class="emoji-picker" style="max-height: 80px;">
|
||||
<div class="emoji-item" data-emoji="⚡">⚡</div>
|
||||
<div class="emoji-item" data-emoji="🔥">🔥</div>
|
||||
<div class="emoji-item" data-emoji="⭐">⭐</div>
|
||||
<div class="emoji-item" data-emoji="🎯">🎯</div>
|
||||
<div class="emoji-item" data-emoji="🚀">🚀</div>
|
||||
<div class="emoji-item" data-emoji="💎">💎</div>
|
||||
<div class="emoji-item" data-emoji="🔧">🔧</div>
|
||||
<div class="emoji-item" data-emoji="⚙️">⚙️</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mb-4">
|
||||
<div class="col-md-12">
|
||||
<label for="descripcion" class="form-label">Descripción</label>
|
||||
<textarea id="descripcion" name="descripcion" class="form-control" rows="2"
|
||||
placeholder="Descripción breve del template (opcional)" maxlength="255"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Configuración Principal -->
|
||||
<div class="section-header">
|
||||
<h6 class="mb-0"><i class="fas fa-cog me-2"></i>Configuración Principal</h6>
|
||||
</div>
|
||||
|
||||
<div class="row mb-3">
|
||||
<div class="col-md-3">
|
||||
<label for="tipo_moneda" class="form-label">Moneda</label>
|
||||
<select id="tipo_moneda" name="tipo_moneda" class="form-select searchable">
|
||||
<option value="">-- Sin especificar --</option>
|
||||
<option value="MXN">Peso Mexicano (MXN)</option>
|
||||
<option value="USD">Dólar USD (USD)</option>
|
||||
<option value="EUR">Euro (EUR)</option>
|
||||
<option value="CNY">Yuan (CNY)</option>
|
||||
<option value="GBP">Libra GBP (GBP)</option>
|
||||
<option value="JPY">Yen (JPY)</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<label for="incoterm" class="form-label">INCOTERM</label>
|
||||
<select id="incoterm" name="incoterm" class="form-select searchable">
|
||||
<option value="">-- Sin especificar --</option>
|
||||
<?php foreach($incoterms as $inc): ?>
|
||||
<option value="<?= htmlspecialchars($inc['INCOTERM']) ?>">
|
||||
<?= htmlspecialchars($inc['INCOTERM'].' - '.$inc['DESCESPANOL']) ?>
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<label for="vinculacion" class="form-label">Vinculación</label>
|
||||
<select id="vinculacion" name="vinculacion" class="form-select">
|
||||
<option value="">-- Sin especificar --</option>
|
||||
<option value="0">No existe</option>
|
||||
<option value="1">Existe, no afecta</option>
|
||||
<option value="2">Existe y afecta</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<label for="tasa_preferencial" class="form-label">Tasa Preferencial</label>
|
||||
<select id="tasa_preferencial" name="tasa_preferencial" class="form-select">
|
||||
<option value="">-- Sin especificar --</option>
|
||||
<option value="General">General</option>
|
||||
<option value="TLC">TLC</option>
|
||||
<option value="PROSEC">PROSEC</option>
|
||||
<option value="ALADI">ALADI</option>
|
||||
<option value="COMERCIALIZADORA">COMERCIALIZADORA</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mb-3">
|
||||
<div class="col-md-6">
|
||||
<label for="pais_proveedor" class="form-label">País Proveedor</label>
|
||||
<select id="pais_proveedor" name="pais_proveedor" class="form-select searchable">
|
||||
<option value="">-- Sin especificar --</option>
|
||||
<?php foreach($paises as $p): ?>
|
||||
<option value="<?= htmlspecialchars($p['id_pais']) ?>"><?= htmlspecialchars($p['nombre']) ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
<input type="hidden" id="pais_proveedor_texto" name="pais_proveedor_texto">
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label for="unidad_comercial_id" class="form-label">Unidad de Medida</label>
|
||||
<select id="unidad_comercial_id" name="unidad_comercial_id" class="form-select searchable">
|
||||
<option value="">-- Sin especificar --</option>
|
||||
<?php foreach($unidades_medida as $um): ?>
|
||||
<option value="<?= htmlspecialchars($um['id']) ?>"><?= htmlspecialchars($um['descripcion']) ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Configuración Avanzada -->
|
||||
<div class="section-header">
|
||||
<h6 class="mb-0"><i class="fas fa-tools me-2"></i>Configuración Avanzada</h6>
|
||||
</div>
|
||||
|
||||
<div class="row mb-3">
|
||||
<div class="col-md-6">
|
||||
<label for="anexo22_apendice" class="form-label">Aduana</label>
|
||||
<select id="anexo22_apendice" name="anexo22_apendice" class="form-select searchable">
|
||||
<option value="">-- Sin especificar --</option>
|
||||
<?php foreach($aduanas as $a): ?>
|
||||
<option value="<?= htmlspecialchars($a['aduana_seccion']) ?>">
|
||||
<?= htmlspecialchars($a['aduana_seccion'].' – '.$a['nombre']) ?>
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label for="patente" class="form-label">Patente Aduanal</label>
|
||||
<select id="patente" name="patente" class="form-select searchable">
|
||||
<option value="">-- Sin especificar --</option>
|
||||
<?php foreach($patentes as $pt): ?>
|
||||
<option value="<?= htmlspecialchars($pt['id_agente']) ?>">
|
||||
<?= htmlspecialchars($pt['patente'].' - '.$pt['agente_aduanal']) ?>
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mb-4">
|
||||
<div class="col-md-6">
|
||||
<label for="transportista_id" class="form-label">Transportista</label>
|
||||
<select id="transportista_id" name="transportista_id" class="form-select searchable">
|
||||
<option value="">-- Sin especificar --</option>
|
||||
<?php foreach($transportistas as $t): ?>
|
||||
<option value="<?= htmlspecialchars($t['id_transportista']) ?>">
|
||||
<?= htmlspecialchars($t['clave_identificador'] . ' - ' . $t['nombre']) ?>
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label for="chofer_id" class="form-label">Chofer</label>
|
||||
<select id="chofer_id" name="chofer_id" class="form-select searchable">
|
||||
<option value="">-- Sin especificar --</option>
|
||||
<?php foreach($choferes as $c): ?>
|
||||
<option value="<?= htmlspecialchars($c['id_chofer']) ?>">
|
||||
<?= htmlspecialchars($c['nombre']) ?>
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Botones -->
|
||||
<div class="text-end">
|
||||
<button type="submit" class="btn btn-success btn-animated me-2">
|
||||
<i class="fas fa-save me-1"></i>Guardar Template
|
||||
</button>
|
||||
<a href="/IMPORTADORES/templates_rapidos/lista" class="btn btn-secondary btn-animated">
|
||||
<i class="fas fa-times me-1"></i>Cancelar
|
||||
</a>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Vista Previa -->
|
||||
<div class="col-lg-4">
|
||||
<div class="card sticky-top" style="top: 20px;">
|
||||
<div class="card-header bg-primary text-white">
|
||||
<h6 class="mb-0"><i class="fas fa-eye me-2"></i>Vista Previa</h6>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div id="template-preview">
|
||||
<div class="preview-card">
|
||||
<div class="d-flex align-items-center mb-2">
|
||||
<span id="preview-icono" class="fs-4 me-2">🏢</span>
|
||||
<span id="preview-nombre" class="fw-bold">Nuevo Template</span>
|
||||
</div>
|
||||
<div id="preview-descripcion" class="small mb-3 opacity-75">
|
||||
Descripción del template...
|
||||
</div>
|
||||
<div id="preview-config" class="d-flex flex-wrap">
|
||||
<!-- Configuración se mostrará aquí dinámicamente -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tips-section">
|
||||
<h6 class="small text-primary mb-3 fw-bold">💡 Consejos para Templates Efectivos</h6>
|
||||
<div class="tip-item">
|
||||
<i class="fas fa-lightbulb text-warning"></i>
|
||||
<span>Usa nombres descriptivos que identifiquen fácilmente el template</span>
|
||||
</div>
|
||||
<div class="tip-item">
|
||||
<i class="fas fa-flag text-info"></i>
|
||||
<span>Elige iconos de países o símbolos representativos</span>
|
||||
</div>
|
||||
<div class="tip-item">
|
||||
<i class="fas fa-filter text-success"></i>
|
||||
<span>Solo llena campos que sean comunes en todas las importaciones</span>
|
||||
</div>
|
||||
<div class="tip-item">
|
||||
<i class="fas fa-clock text-danger"></i>
|
||||
<span>Deja vacíos los campos que cambien frecuentemente</span>
|
||||
</div>
|
||||
<div class="tip-item">
|
||||
<i class="fas fa-save text-primary"></i>
|
||||
<span>Los templates te ahorrarán tiempo en futuras importaciones</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Botón adicional para resetear -->
|
||||
<div class="d-grid mt-3">
|
||||
<button type="button" class="btn btn-outline-secondary btn-sm" onclick="resetForm()">
|
||||
<i class="fas fa-refresh me-1"></i>Limpiar Formulario
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/choices.js/public/assets/scripts/choices.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
|
||||
<script>
|
||||
// Variables globales
|
||||
let choicesInstances = {};
|
||||
|
||||
// Inicializar cuando el DOM esté listo
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
initializeChoices();
|
||||
initializeEmojiPicker();
|
||||
initializePreview();
|
||||
initializeValidation();
|
||||
initializeDynamicUpdates();
|
||||
});
|
||||
|
||||
// Inicializar Choices.js para selects con búsqueda
|
||||
function initializeChoices() {
|
||||
document.querySelectorAll('.searchable').forEach(element => {
|
||||
choicesInstances[element.id] = new Choices(element, {
|
||||
searchEnabled: true,
|
||||
itemSelectText: '',
|
||||
shouldSort: false,
|
||||
searchPlaceholderValue: 'Buscar...',
|
||||
noResultsText: 'No se encontraron resultados',
|
||||
noChoicesText: 'No hay opciones disponibles'
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Inicializar selector de emojis
|
||||
function initializeEmojiPicker() {
|
||||
// Manejar clicks en emojis
|
||||
document.addEventListener('click', function(e) {
|
||||
if (e.target.classList.contains('emoji-item')) {
|
||||
const emoji = e.target.getAttribute('data-emoji') || e.target.textContent;
|
||||
selectEmoji(emoji);
|
||||
|
||||
// Cerrar dropdown
|
||||
const dropdown = bootstrap.Dropdown.getInstance(document.querySelector('[data-bs-toggle="dropdown"]'));
|
||||
if (dropdown) {
|
||||
dropdown.hide();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Mostrar emoji seleccionado visualmente
|
||||
document.addEventListener('mouseenter', function(e) {
|
||||
if (e.target.classList.contains('emoji-item')) {
|
||||
// Quitar selección anterior
|
||||
document.querySelectorAll('.emoji-item.selected').forEach(item => {
|
||||
item.classList.remove('selected');
|
||||
});
|
||||
|
||||
// Agregar efecto hover mejorado
|
||||
e.target.style.transform = 'scale(1.2)';
|
||||
e.target.style.background = 'linear-gradient(135deg, #4CAF50, #45a049)';
|
||||
e.target.style.color = 'white';
|
||||
e.target.style.borderRadius = '8px';
|
||||
}
|
||||
});
|
||||
|
||||
document.addEventListener('mouseleave', function(e) {
|
||||
if (e.target.classList.contains('emoji-item')) {
|
||||
e.target.style.transform = '';
|
||||
e.target.style.background = '';
|
||||
e.target.style.color = '';
|
||||
e.target.style.borderRadius = '';
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Función para seleccionar emoji (mejorada)
|
||||
function selectEmoji(emoji) {
|
||||
const iconInput = document.getElementById('icono');
|
||||
const iconDisplay = document.getElementById('icon-display');
|
||||
|
||||
// Actualizar valor e interfaz
|
||||
iconInput.value = emoji;
|
||||
iconDisplay.textContent = emoji;
|
||||
|
||||
// Efecto visual en el display
|
||||
iconDisplay.style.transform = 'scale(1.3)';
|
||||
iconDisplay.style.transition = 'transform 0.3s ease';
|
||||
|
||||
setTimeout(() => {
|
||||
iconDisplay.style.transform = 'scale(1)';
|
||||
}, 300);
|
||||
|
||||
updatePreview();
|
||||
|
||||
// Mostrar feedback visual
|
||||
showToast('✅ Icono actualizado', 'success');
|
||||
}
|
||||
|
||||
// Inicializar vista previa
|
||||
function initializePreview() {
|
||||
updatePreview();
|
||||
|
||||
// Eventos para actualizar vista previa en tiempo real
|
||||
document.querySelectorAll('#templateForm input, #templateForm select, #templateForm textarea').forEach(element => {
|
||||
element.addEventListener('input', debounce(updatePreview, 300));
|
||||
element.addEventListener('change', updatePreview);
|
||||
});
|
||||
}
|
||||
|
||||
// Función para actualizar vista previa (mejorada)
|
||||
function updatePreview() {
|
||||
const nombre = document.getElementById('nombre').value.trim() || 'Nuevo Template';
|
||||
const descripcion = document.getElementById('descripcion').value.trim() || 'Descripción del template...';
|
||||
const icono = document.getElementById('icono').value;
|
||||
|
||||
// Actualizar elementos de vista previa con animación
|
||||
const previewNombre = document.getElementById('preview-nombre');
|
||||
const previewDescripcion = document.getElementById('preview-descripcion');
|
||||
const previewIcono = document.getElementById('preview-icono');
|
||||
|
||||
if (previewNombre.textContent !== nombre) {
|
||||
previewNombre.style.opacity = '0.5';
|
||||
setTimeout(() => {
|
||||
previewNombre.textContent = nombre;
|
||||
previewNombre.style.opacity = '1';
|
||||
}, 150);
|
||||
}
|
||||
|
||||
if (previewDescripcion.textContent !== descripcion) {
|
||||
previewDescripcion.style.opacity = '0.5';
|
||||
setTimeout(() => {
|
||||
previewDescripcion.textContent = descripcion;
|
||||
previewDescripcion.style.opacity = '1';
|
||||
}, 150);
|
||||
}
|
||||
|
||||
previewIcono.textContent = icono;
|
||||
|
||||
// Actualizar configuración con más campos
|
||||
const config = [];
|
||||
const fields = [
|
||||
{ id: 'tipo_moneda', label: '💰 Moneda' },
|
||||
{ id: 'incoterm', label: '📋 INCOTERM', getValue: (el) => el.value ? el.options[el.selectedIndex].text.split(' - ')[0] : '' },
|
||||
{ id: 'vinculacion', label: '🔗 Vinculación', map: {'0':'Sin Vinc.', '1':'No Afecta', '2':'Afecta'} },
|
||||
{ id: 'tasa_preferencial', label: '📊 Tasa' },
|
||||
{ id: 'pais_proveedor', label: '🌍 País', getValue: (el) => el.value ? el.options[el.selectedIndex].text : '' },
|
||||
{ id: 'anexo22_apendice', label: '🏢 Aduana', getValue: (el) => el.value ? el.options[el.selectedIndex].text.split(' –')[0] : '' },
|
||||
{ id: 'transportista_id', label: '🚛 Transportista', getValue: (el) => el.value ? el.options[el.selectedIndex].text.split(' - ')[0] : '' }
|
||||
];
|
||||
|
||||
fields.forEach(field => {
|
||||
const element = document.getElementById(field.id);
|
||||
let value = '';
|
||||
|
||||
if (field.getValue) {
|
||||
value = field.getValue(element);
|
||||
} else {
|
||||
value = element.value;
|
||||
}
|
||||
|
||||
if (value) {
|
||||
const displayValue = field.map && field.map[value] ? field.map[value] : value;
|
||||
config.push(`<span class="template-preview-item">${field.label}: ${displayValue}</span>`);
|
||||
}
|
||||
});
|
||||
|
||||
const configContainer = document.getElementById('preview-config');
|
||||
configContainer.style.opacity = '0.5';
|
||||
setTimeout(() => {
|
||||
configContainer.innerHTML = config.join('');
|
||||
configContainer.style.opacity = '1';
|
||||
}, 150);
|
||||
}
|
||||
|
||||
// Inicializar actualizaciones dinámicas
|
||||
function initializeDynamicUpdates() {
|
||||
// Actualizar texto del país cuando cambie
|
||||
const paisSelect = document.getElementById('pais_proveedor');
|
||||
if (paisSelect && choicesInstances[paisSelect.id]) {
|
||||
paisSelect.addEventListener('change', function() {
|
||||
const selectedOption = this.options[this.selectedIndex];
|
||||
document.getElementById('pais_proveedor_texto').value = selectedOption ? selectedOption.text : '';
|
||||
updatePreview();
|
||||
});
|
||||
}
|
||||
|
||||
// Filtrar choferes según transportista seleccionado
|
||||
const transportistaSelect = document.getElementById('transportista_id');
|
||||
const choferSelect = document.getElementById('chofer_id');
|
||||
|
||||
if (transportistaSelect && choferSelect) {
|
||||
transportistaSelect.addEventListener('change', function() {
|
||||
const transportistaId = this.value;
|
||||
const choferChoices = choicesInstances[choferSelect.id];
|
||||
|
||||
if (choferChoices) {
|
||||
// Aquí podrías hacer una llamada AJAX para filtrar choferes
|
||||
// Por ahora simplemente reseteamos la selección
|
||||
choferChoices.setChoiceByValue('');
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Inicializar validación del formulario
|
||||
function initializeValidation() {
|
||||
const form = document.getElementById('templateForm');
|
||||
|
||||
form.addEventListener('submit', function(e) {
|
||||
if (!validateForm()) {
|
||||
e.preventDefault();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Mostrar loading mejorado
|
||||
Swal.fire({
|
||||
title: 'Guardando template...',
|
||||
html: '<div class="loading-spinner"></div><br>Por favor espera...',
|
||||
allowOutsideClick: false,
|
||||
allowEscapeKey: false,
|
||||
showConfirmButton: false,
|
||||
customClass: {
|
||||
popup: 'swal2-noanimation'
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Validación en tiempo real del nombre
|
||||
const nombreInput = document.getElementById('nombre');
|
||||
nombreInput.addEventListener('input', function() {
|
||||
validateField(this);
|
||||
});
|
||||
}
|
||||
|
||||
// Función de validación del formulario
|
||||
function validateForm() {
|
||||
const nombre = document.getElementById('nombre').value.trim();
|
||||
|
||||
if (!nombre) {
|
||||
showErrorAlert('Campo requerido', 'El nombre del template es obligatorio');
|
||||
document.getElementById('nombre').focus();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (nombre.length > 100) {
|
||||
showErrorAlert('Nombre muy largo', 'El nombre no puede exceder 100 caracteres');
|
||||
document.getElementById('nombre').focus();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Validar campo individual
|
||||
function validateField(field) {
|
||||
const value = field.value.trim();
|
||||
|
||||
if (field.id === 'nombre') {
|
||||
if (value.length > 100) {
|
||||
field.classList.add('is-invalid');
|
||||
field.classList.remove('is-valid');
|
||||
} else if (value.length > 0) {
|
||||
field.classList.add('is-valid');
|
||||
field.classList.remove('is-invalid');
|
||||
} else {
|
||||
field.classList.remove('is-valid', 'is-invalid');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Funciones de utilidad
|
||||
function debounce(func, wait) {
|
||||
let timeout;
|
||||
return function executedFunction(...args) {
|
||||
const later = () => {
|
||||
clearTimeout(timeout);
|
||||
func(...args);
|
||||
};
|
||||
clearTimeout(timeout);
|
||||
timeout = setTimeout(later, wait);
|
||||
};
|
||||
}
|
||||
|
||||
function showErrorAlert(title, text) {
|
||||
Swal.fire({
|
||||
icon: 'error',
|
||||
title: title,
|
||||
text: text,
|
||||
confirmButtonColor: '#dc3545',
|
||||
confirmButtonText: 'Entendido'
|
||||
});
|
||||
}
|
||||
|
||||
function showToast(message, type = 'info') {
|
||||
const Toast = Swal.mixin({
|
||||
toast: true,
|
||||
position: 'top-end',
|
||||
showConfirmButton: false,
|
||||
timer: 2000,
|
||||
timerProgressBar: true
|
||||
});
|
||||
|
||||
Toast.fire({
|
||||
icon: type,
|
||||
title: message
|
||||
});
|
||||
}
|
||||
|
||||
// Función para resetear el formulario
|
||||
function resetForm() {
|
||||
document.getElementById('templateForm').reset();
|
||||
|
||||
// Resetear Choices.js
|
||||
Object.values(choicesInstances).forEach(choice => {
|
||||
choice.setChoiceByValue('');
|
||||
});
|
||||
|
||||
// Resetear icono
|
||||
document.getElementById('icono').value = '🏢';
|
||||
document.getElementById('icon-display').textContent = '🏢';
|
||||
|
||||
updatePreview();
|
||||
showToast('Formulario reiniciado', 'info');
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
494
views/templates_rapidos/editar.php
Normal file
494
views/templates_rapidos/editar.php
Normal file
@@ -0,0 +1,494 @@
|
||||
<?php include __DIR__ . '/../partials/sidebar_importador.php'; ?>
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="es">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>✏️ Editar Template Rápido</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/choices.js/public/assets/styles/choices.min.css"/>
|
||||
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
|
||||
<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
|
||||
<style>
|
||||
body { font-family: 'Segoe UI', sans-serif; background-color: #f4f6f9; }
|
||||
.sidebar { width: 220px; height: 100vh; background-color: #343a40; position: fixed; top: 0; left: 0; padding-top: 56px; z-index: 1040; }
|
||||
.sidebar .nav-link { font-weight: bold; color: white; transition: all 0.3s ease; }
|
||||
.sidebar .nav-link:hover, .sidebar .nav-link.active { background-color: #495057; color: #fff; }
|
||||
.content { margin-top: 56px; padding: 40px 20px; position: relative; z-index: 1; background-color: #f4f6f9; transition: margin-left 0.3s ease; }
|
||||
@media (min-width: 768px) { .content { margin-left: 250px; } }
|
||||
@media (max-width: 767.98px) {
|
||||
.content { margin-left: 0; }
|
||||
.sidebar .nav-link { font-weight: normal; color: #343a40; background-color: transparent; }
|
||||
.sidebar .nav-link:hover, .sidebar .nav-link.active { background-color: #e9ecef; color: #212529; }
|
||||
}
|
||||
.card { border-radius: 12px; box-shadow: 0 4px 12px rgba(0,0,0,0.1); }
|
||||
.btn-animated { transition: all 0.3s ease; position: relative; overflow: hidden; }
|
||||
.btn-animated:hover { transform: translateY(-2px); box-shadow: 0 5px 15px rgba(0, 0, 0, 0.2); }
|
||||
.form-control:focus, .form-select:focus {
|
||||
border-color: #0d6efd;
|
||||
box-shadow: 0 0 0 0.2rem rgba(13, 110, 253, 0.25);
|
||||
}
|
||||
.emoji-picker {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(8, 1fr);
|
||||
gap: 5px;
|
||||
padding: 10px;
|
||||
max-height: 200px;
|
||||
overflow-y: auto;
|
||||
border: 1px solid #dee2e6;
|
||||
border-radius: 5px;
|
||||
background: white;
|
||||
}
|
||||
.emoji-item {
|
||||
padding: 8px;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
border-radius: 3px;
|
||||
transition: background-color 0.2s;
|
||||
}
|
||||
.emoji-item:hover {
|
||||
background-color: #f8f9fa;
|
||||
}
|
||||
.preview-card {
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
color: white;
|
||||
border-radius: 8px;
|
||||
padding: 15px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
.template-preview-item {
|
||||
background: rgba(255,255,255,0.2);
|
||||
border: 1px solid rgba(255,255,255,0.3);
|
||||
color: white;
|
||||
padding: 6px 12px;
|
||||
border-radius: 20px;
|
||||
font-size: 12px;
|
||||
margin: 2px;
|
||||
display: inline-block;
|
||||
}
|
||||
.choices.required .choices__inner { border: 1px solid #ced4da; }
|
||||
.choices.is-invalid .choices__inner { border: 1px solid #dc3545; background-color: #fff5f5; }
|
||||
.choices.is-valid .choices__inner { border: 1px solid #28a745; background-color: #f5fff5; }
|
||||
.section-header {
|
||||
background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
|
||||
padding: 15px;
|
||||
margin: -15px -15px 15px -15px;
|
||||
border-radius: 8px 8px 0 0;
|
||||
border-bottom: 1px solid #dee2e6;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="content">
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<h4 class="mb-0">✏️ Editar Template: <?= htmlspecialchars($template['icono']) ?> <?= htmlspecialchars($template['nombre']) ?></h4>
|
||||
<div>
|
||||
<a href="/IMPORTADORES/templates_rapidos/lista" class="btn btn-secondary btn-animated me-2">
|
||||
<i class="fas fa-list me-1"></i>Volver a Lista
|
||||
</a>
|
||||
<a href="/IMPORTADORES/templates_rapidos/crear" class="btn btn-success btn-animated">
|
||||
<i class="fas fa-plus me-1"></i>Nuevo Template
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Info del template -->
|
||||
<div class="row mb-3">
|
||||
<div class="col-md-12">
|
||||
<div class="card bg-info text-white">
|
||||
<div class="card-body py-3">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-md-8">
|
||||
<h6 class="mb-1"><i class="fas fa-info-circle me-2"></i>Información del Template</h6>
|
||||
<p class="mb-0 small">
|
||||
Creado el: <?= $template['fecha_creacion'] ? $template['fecha_creacion']->format('d/m/Y H:i') : 'N/A' ?> |
|
||||
Usado: <?= $template['veces_usado'] ?> veces |
|
||||
Última modificación: <?= $template['fecha_modificacion'] ? $template['fecha_modificacion']->format('d/m/Y H:i') : 'N/A' ?>
|
||||
</p>
|
||||
</div>
|
||||
<div class="col-md-4 text-end">
|
||||
<span class="h4"><?= htmlspecialchars($template['icono']) ?></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<!-- Formulario Principal -->
|
||||
<div class="col-lg-8">
|
||||
<div class="card">
|
||||
<div class="card-body p-4">
|
||||
<form id="templateForm" action="/IMPORTADORES/templates_rapidos/actualizar" method="POST">
|
||||
<input type="hidden" name="id" value="<?= htmlspecialchars($template['id']) ?>">
|
||||
|
||||
<!-- Información Básica -->
|
||||
<div class="section-header">
|
||||
<h6 class="mb-0"><i class="fas fa-info-circle me-2"></i>Información Básica</h6>
|
||||
</div>
|
||||
|
||||
<div class="row mb-4">
|
||||
<div class="col-md-6">
|
||||
<label for="nombre" class="form-label">Nombre del Template *</label>
|
||||
<input id="nombre" name="nombre" type="text" class="form-control" required
|
||||
placeholder="ej. Importación China" maxlength="100"
|
||||
value="<?= htmlspecialchars($template['nombre']) ?>">
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label for="icono" class="form-label">Icono</label>
|
||||
<div class="input-group">
|
||||
<input id="icono" name="icono" type="text" class="form-control" readonly
|
||||
value="<?= htmlspecialchars($template['icono']) ?>">
|
||||
<button type="button" class="btn btn-outline-secondary" data-bs-toggle="dropdown">
|
||||
<i class="fas fa-smile"></i>
|
||||
</button>
|
||||
<ul class="dropdown-menu dropdown-menu-end p-0" style="width: 300px;">
|
||||
<li>
|
||||
<div class="emoji-picker">
|
||||
<div class="emoji-item" onclick="selectEmoji('🇨🇳')">🇨🇳</div>
|
||||
<div class="emoji-item" onclick="selectEmoji('🇺🇸')">🇺🇸</div>
|
||||
<div class="emoji-item" onclick="selectEmoji('🇪🇺')">🇪🇺</div>
|
||||
<div class="emoji-item" onclick="selectEmoji('🇩🇪')">🇩🇪</div>
|
||||
<div class="emoji-item" onclick="selectEmoji('🇯🇵')">🇯🇵</div>
|
||||
<div class="emoji-item" onclick="selectEmoji('🇰🇷')">🇰🇷</div>
|
||||
<div class="emoji-item" onclick="selectEmoji('🇮🇹')">🇮🇹</div>
|
||||
<div class="emoji-item" onclick="selectEmoji('🇫🇷')">🇫🇷</div>
|
||||
<div class="emoji-item" onclick="selectEmoji('🏢')">🏢</div>
|
||||
<div class="emoji-item" onclick="selectEmoji('🏭')">🏭</div>
|
||||
<div class="emoji-item" onclick="selectEmoji('🚢')">🚢</div>
|
||||
<div class="emoji-item" onclick="selectEmoji('✈️')">✈️</div>
|
||||
<div class="emoji-item" onclick="selectEmoji('🚛')">🚛</div>
|
||||
<div class="emoji-item" onclick="selectEmoji('📦')">📦</div>
|
||||
<div class="emoji-item" onclick="selectEmoji('💼')">💼</div>
|
||||
<div class="emoji-item" onclick="selectEmoji('⚡')">⚡</div>
|
||||
<div class="emoji-item" onclick="selectEmoji('🔥')">🔥</div>
|
||||
<div class="emoji-item" onclick="selectEmoji('⭐')">⭐</div>
|
||||
<div class="emoji-item" onclick="selectEmoji('🎯')">🎯</div>
|
||||
<div class="emoji-item" onclick="selectEmoji('🚀')">🚀</div>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mb-4">
|
||||
<div class="col-md-12">
|
||||
<label for="descripcion" class="form-label">Descripción</label>
|
||||
<textarea id="descripcion" name="descripcion" class="form-control" rows="2"
|
||||
placeholder="Descripción breve del template (opcional)" maxlength="255"><?= htmlspecialchars($template['descripcion']) ?></textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Configuración Principal -->
|
||||
<div class="section-header">
|
||||
<h6 class="mb-0"><i class="fas fa-cog me-2"></i>Configuración Principal</h6>
|
||||
</div>
|
||||
|
||||
<?php $config = $template['config']; ?>
|
||||
|
||||
<div class="row mb-3">
|
||||
<div class="col-md-3">
|
||||
<label for="tipo_moneda" class="form-label">Moneda</label>
|
||||
<select id="tipo_moneda" name="tipo_moneda" class="form-select searchable">
|
||||
<option value="">-- Sin especificar --</option>
|
||||
<option value="MXN" <?= ($config['tipo_moneda'] ?? '') === 'MXN' ? 'selected' : '' ?>>Peso Mexicano (MXN)</option>
|
||||
<option value="USD" <?= ($config['tipo_moneda'] ?? '') === 'USD' ? 'selected' : '' ?>>Dólar USD (USD)</option>
|
||||
<option value="EUR" <?= ($config['tipo_moneda'] ?? '') === 'EUR' ? 'selected' : '' ?>>Euro (EUR)</option>
|
||||
<option value="CNY" <?= ($config['tipo_moneda'] ?? '') === 'CNY' ? 'selected' : '' ?>>Yuan (CNY)</option>
|
||||
<option value="GBP" <?= ($config['tipo_moneda'] ?? '') === 'GBP' ? 'selected' : '' ?>>Libra GBP (GBP)</option>
|
||||
<option value="JPY" <?= ($config['tipo_moneda'] ?? '') === 'JPY' ? 'selected' : '' ?>>Yen (JPY)</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<label for="incoterm" class="form-label">INCOTERM</label>
|
||||
<select id="incoterm" name="incoterm" class="form-select searchable">
|
||||
<option value="">-- Sin especificar --</option>
|
||||
<?php foreach($incoterms as $inc): ?>
|
||||
<option value="<?= htmlspecialchars($inc['INCOTERM']) ?>"
|
||||
<?= ($config['incoterm'] ?? '') === $inc['INCOTERM'] ? 'selected' : '' ?>>
|
||||
<?= htmlspecialchars($inc['INCOTERM'].' - '.$inc['DESCESPANOL']) ?>
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<label for="vinculacion" class="form-label">Vinculación</label>
|
||||
<select id="vinculacion" name="vinculacion" class="form-select">
|
||||
<option value="">-- Sin especificar --</option>
|
||||
<option value="0" <?= ($config['vinculacion'] ?? '') === '0' ? 'selected' : '' ?>>No existe</option>
|
||||
<option value="1" <?= ($config['vinculacion'] ?? '') === '1' ? 'selected' : '' ?>>Existe, no afecta</option>
|
||||
<option value="2" <?= ($config['vinculacion'] ?? '') === '2' ? 'selected' : '' ?>>Existe y afecta</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<label for="tasa_preferencial" class="form-label">Tasa Preferencial</label>
|
||||
<select id="tasa_preferencial" name="tasa_preferencial" class="form-select">
|
||||
<option value="">-- Sin especificar --</option>
|
||||
<option value="General" <?= ($config['tasa_preferencial'] ?? '') === 'General' ? 'selected' : '' ?>>General</option>
|
||||
<option value="TLC" <?= ($config['tasa_preferencial'] ?? '') === 'TLC' ? 'selected' : '' ?>>TLC</option>
|
||||
<option value="PROSEC" <?= ($config['tasa_preferencial'] ?? '') === 'PROSEC' ? 'selected' : '' ?>>PROSEC</option>
|
||||
<option value="ALADI" <?= ($config['tasa_preferencial'] ?? '') === 'ALADI' ? 'selected' : '' ?>>ALADI</option>
|
||||
<option value="COMERCIALIZADORA" <?= ($config['tasa_preferencial'] ?? '') === 'COMERCIALIZADORA' ? 'selected' : '' ?>>COMERCIALIZADORA</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mb-3">
|
||||
<div class="col-md-6">
|
||||
<label for="pais_proveedor" class="form-label">País Proveedor</label>
|
||||
<select id="pais_proveedor" name="pais_proveedor" class="form-select searchable">
|
||||
<option value="">-- Sin especificar --</option>
|
||||
<?php foreach($paises as $p): ?>
|
||||
<option value="<?= htmlspecialchars($p['id_pais']) ?>"
|
||||
<?= ($config['pais_proveedor'] ?? '') === $p['id_pais'] ? 'selected' : '' ?>>
|
||||
<?= htmlspecialchars($p['nombre']) ?>
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
<input type="hidden" id="pais_proveedor_texto" name="pais_proveedor_texto"
|
||||
value="<?= htmlspecialchars($config['pais_proveedor_texto'] ?? '') ?>">
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label for="unidad_comercial_id" class="form-label">Unidad de Medida</label>
|
||||
<select id="unidad_comercial_id" name="unidad_comercial_id" class="form-select searchable">
|
||||
<option value="">-- Sin especificar --</option>
|
||||
<?php foreach($unidades_medida as $um): ?>
|
||||
<option value="<?= htmlspecialchars($um['id']) ?>"
|
||||
<?= ($config['unidad_comercial_id'] ?? '') === $um['id'] ? 'selected' : '' ?>>
|
||||
<?= htmlspecialchars($um['descripcion']) ?>
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Configuración Avanzada -->
|
||||
<div class="section-header">
|
||||
<h6 class="mb-0"><i class="fas fa-tools me-2"></i>Configuración Avanzada</h6>
|
||||
</div>
|
||||
|
||||
<div class="row mb-3">
|
||||
<div class="col-md-6">
|
||||
<label for="anexo22_apendice" class="form-label">Aduana</label>
|
||||
<select id="anexo22_apendice" name="anexo22_apendice" class="form-select searchable">
|
||||
<option value="">-- Sin especificar --</option>
|
||||
<?php foreach($aduanas as $a): ?>
|
||||
<option value="<?= htmlspecialchars($a['aduana_seccion']) ?>"
|
||||
<?= ($config['anexo22_apendice'] ?? '') === $a['aduana_seccion'] ? 'selected' : '' ?>>
|
||||
<?= htmlspecialchars($a['aduana_seccion'].' – '.$a['nombre']) ?>
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label for="patente" class="form-label">Patente Aduanal</label>
|
||||
<select id="patente" name="patente" class="form-select searchable">
|
||||
<option value="">-- Sin especificar --</option>
|
||||
<?php foreach($patentes as $pt): ?>
|
||||
<option value="<?= htmlspecialchars($pt['id_agente']) ?>"
|
||||
<?= ($config['patente'] ?? '') === $pt['id_agente'] ? 'selected' : '' ?>>
|
||||
<?= htmlspecialchars($pt['patente'].' - '.$pt['agente_aduanal']) ?>
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mb-4">
|
||||
<div class="col-md-6">
|
||||
<label for="transportista_id" class="form-label">Transportista</label>
|
||||
<select id="transportista_id" name="transportista_id" class="form-select searchable">
|
||||
<option value="">-- Sin especificar --</option>
|
||||
<?php foreach($transportistas as $t): ?>
|
||||
<option value="<?= htmlspecialchars($t['id_transportista']) ?>"
|
||||
<?= ($config['transportista_id'] ?? '') === $t['id_transportista'] ? 'selected' : '' ?>>
|
||||
<?= htmlspecialchars($t['clave_identificador'] . ' - ' . $t['nombre']) ?>
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label for="chofer_id" class="form-label">Chofer</label>
|
||||
<select id="chofer_id" name="chofer_id" class="form-select searchable">
|
||||
<option value="">-- Sin especificar --</option>
|
||||
<?php foreach($choferes as $c): ?>
|
||||
<option value="<?= htmlspecialchars($c['id_chofer']) ?>"
|
||||
<?= ($config['chofer_id'] ?? '') === $c['id_chofer'] ? 'selected' : '' ?>>
|
||||
<?= htmlspecialchars($c['nombre']) ?>
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Botones -->
|
||||
<div class="text-end">
|
||||
<button type="submit" class="btn btn-primary btn-animated me-2">
|
||||
<i class="fas fa-save me-1"></i>Actualizar Template
|
||||
</button>
|
||||
<a href="/IMPORTADORES/templates_rapidos/lista" class="btn btn-secondary btn-animated">
|
||||
<i class="fas fa-times me-1"></i>Cancelar
|
||||
</a>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Vista Previa -->
|
||||
<div class="col-lg-4">
|
||||
<div class="card sticky-top" style="top: 20px;">
|
||||
<div class="card-header bg-warning text-dark">
|
||||
<h6 class="mb-0"><i class="fas fa-eye me-2"></i>Vista Previa</h6>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div id="template-preview">
|
||||
<div class="preview-card">
|
||||
<div class="d-flex align-items-center mb-2">
|
||||
<span id="preview-icono" class="fs-4 me-2"><?= htmlspecialchars($template['icono']) ?></span>
|
||||
<span id="preview-nombre" class="fw-bold"><?= htmlspecialchars($template['nombre']) ?></span>
|
||||
</div>
|
||||
<div id="preview-descripcion" class="small mb-3 opacity-75">
|
||||
<?= htmlspecialchars($template['descripcion']) ?>
|
||||
</div>
|
||||
<div id="preview-config" class="d-flex flex-wrap">
|
||||
<!-- Configuración se mostrará aquí dinámicamente -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-3">
|
||||
<h6 class="small text-muted mb-2">📊 Estadísticas de Uso:</h6>
|
||||
<div class="small text-muted">
|
||||
<div><i class="fas fa-mouse-pointer text-primary me-1"></i>Usado: <?= $template['veces_usado'] ?> veces</div>
|
||||
<div><i class="fas fa-clock text-info me-1"></i>Última vez: <?= $template['ultima_vez_usado'] ? $template['ultima_vez_usado']->format('d/m/Y H:i') : 'Nunca' ?></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-3">
|
||||
<h6 class="small text-muted mb-2">💡 Consejos:</h6>
|
||||
<ul class="list-unstyled small text-muted">
|
||||
<li><i class="fas fa-check text-success me-1"></i> Usa nombres descriptivos</li>
|
||||
<li><i class="fas fa-check text-success me-1"></i> Elige iconos representativos</li>
|
||||
<li><i class="fas fa-check text-success me-1"></i> Solo llena campos comunes</li>
|
||||
<li><i class="fas fa-check text-success me-1"></i> Deja vacío lo que varía</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/choices.js/public/assets/scripts/choices.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
|
||||
<script>
|
||||
// Inicializar Choices.js
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
document.querySelectorAll('.searchable').forEach(element => {
|
||||
new Choices(element, {
|
||||
searchEnabled: true,
|
||||
itemSelectText: '',
|
||||
shouldSort: false
|
||||
});
|
||||
});
|
||||
|
||||
// Inicializar vista previa
|
||||
updatePreview();
|
||||
|
||||
// Eventos para actualizar vista previa
|
||||
document.querySelectorAll('#templateForm input, #templateForm select, #templateForm textarea').forEach(element => {
|
||||
element.addEventListener('input', updatePreview);
|
||||
element.addEventListener('change', updatePreview);
|
||||
});
|
||||
});
|
||||
|
||||
// Función para seleccionar emoji
|
||||
function selectEmoji(emoji) {
|
||||
document.getElementById('icono').value = emoji;
|
||||
updatePreview();
|
||||
}
|
||||
|
||||
// Función para actualizar vista previa
|
||||
function updatePreview() {
|
||||
const nombre = document.getElementById('nombre').value || 'Template sin nombre';
|
||||
const descripcion = document.getElementById('descripcion').value || 'Sin descripción';
|
||||
const icono = document.getElementById('icono').value;
|
||||
|
||||
document.getElementById('preview-nombre').textContent = nombre;
|
||||
document.getElementById('preview-descripcion').textContent = descripcion;
|
||||
document.getElementById('preview-icono').textContent = icono;
|
||||
|
||||
// Actualizar configuración
|
||||
const config = [];
|
||||
const fields = [
|
||||
{ id: 'tipo_moneda', label: 'Moneda' },
|
||||
{ id: 'incoterm', label: 'INCOTERM' },
|
||||
{ id: 'vinculacion', label: 'Vinculación', map: {'0':'Sin Vinc.', '1':'No Afecta', '2':'Afecta'} },
|
||||
{ id: 'tasa_preferencial', label: 'Tasa' }
|
||||
];
|
||||
|
||||
fields.forEach(field => {
|
||||
const value = document.getElementById(field.id).value;
|
||||
if (value) {
|
||||
const displayValue = field.map && field.map[value] ? field.map[value] : value;
|
||||
config.push(`<span class="template-preview-item">${field.label}: ${displayValue}</span>`);
|
||||
}
|
||||
});
|
||||
|
||||
document.getElementById('preview-config').innerHTML = config.join('');
|
||||
}
|
||||
|
||||
// Actualizar texto del país cuando cambie
|
||||
document.getElementById('pais_proveedor').addEventListener('change', function() {
|
||||
const selectedOption = this.options[this.selectedIndex];
|
||||
document.getElementById('pais_proveedor_texto').value = selectedOption ? selectedOption.text : '';
|
||||
updatePreview();
|
||||
});
|
||||
|
||||
// Validación del formulario
|
||||
document.getElementById('templateForm').addEventListener('submit', function(e) {
|
||||
const nombre = document.getElementById('nombre').value.trim();
|
||||
|
||||
if (!nombre) {
|
||||
e.preventDefault();
|
||||
Swal.fire({
|
||||
icon: 'error',
|
||||
title: 'Campo requerido',
|
||||
text: 'El nombre del template es obligatorio',
|
||||
confirmButtonColor: '#3085d6'
|
||||
});
|
||||
document.getElementById('nombre').focus();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (nombre.length > 100) {
|
||||
e.preventDefault();
|
||||
Swal.fire({
|
||||
icon: 'error',
|
||||
title: 'Nombre muy largo',
|
||||
text: 'El nombre no puede exceder 100 caracteres',
|
||||
confirmButtonColor: '#3085d6'
|
||||
});
|
||||
document.getElementById('nombre').focus();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Mostrar loading
|
||||
Swal.fire({
|
||||
title: 'Actualizando template...',
|
||||
allowOutsideClick: false,
|
||||
didOpen: () => {
|
||||
Swal.showLoading();
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
948
views/templates_rapidos/lista.php
Normal file
948
views/templates_rapidos/lista.php
Normal file
@@ -0,0 +1,948 @@
|
||||
<?php include __DIR__ . '/../partials/sidebar_importador.php'; ?>
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="es">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>📋 Templates Rápidos</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link href="https://cdn.datatables.net/1.13.4/css/jquery.dataTables.min.css" rel="stylesheet">
|
||||
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
|
||||
<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
|
||||
<script src="https://cdn.datatables.net/1.13.4/js/jquery.dataTables.min.js"></script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
|
||||
<style>
|
||||
body { font-family: 'Segoe UI', sans-serif; background-color: #f4f6f9; }
|
||||
.sidebar { width: 220px; height: 100vh; background-color: #343a40; position: fixed; top: 0; left: 0; padding-top: 56px; z-index: 1040; }
|
||||
.sidebar .nav-link { font-weight: bold; color: white; transition: all 0.3s ease; }
|
||||
.sidebar .nav-link:hover, .sidebar .nav-link.active { background-color: #495057; color: #fff; }
|
||||
.content { margin-top: 56px; padding: 40px 20px; position: relative; z-index: 1; background-color: #f4f6f9; transition: margin-left 0.3s ease; }
|
||||
@media (min-width: 768px) { .content { margin-left: 250px; } }
|
||||
@media (max-width: 767.98px) {
|
||||
.content { margin-left: 0; }
|
||||
.sidebar .nav-link { font-weight: normal; color: #343a40; background-color: transparent; }
|
||||
.sidebar .nav-link:hover, .sidebar .nav-link.active { background-color: #e9ecef; color: #212529; }
|
||||
}
|
||||
.card { border-radius: 12px; box-shadow: 0 4px 12px rgba(0,0,0,0.1); }
|
||||
.btn-animated { transition: all 0.3s ease; position: relative; overflow: hidden; }
|
||||
.btn-animated:hover { transform: translateY(-2px); box-shadow: 0 5px 15px rgba(0, 0, 0, 0.2); }
|
||||
.table-responsive { border-radius: 8px; overflow: hidden; }
|
||||
.dataTables_wrapper .dataTables_paginate .paginate_button { padding: 0.375rem 0.75rem; }
|
||||
.alert { border-radius: 8px; }
|
||||
.fade-in { animation: fadeIn 0.5s ease-in; }
|
||||
@keyframes fadeIn { from { opacity: 0; transform: translateY(20px); } to { opacity: 1; transform: translateY(0); } }
|
||||
|
||||
/* ✅ NUEVO: Estilos para filtros de templates */
|
||||
.template-filters {
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
border-radius: 12px;
|
||||
padding: 20px;
|
||||
margin-bottom: 25px;
|
||||
color: white;
|
||||
}
|
||||
.filter-btn {
|
||||
background: rgba(255,255,255,0.1);
|
||||
border: 1px solid rgba(255,255,255,0.2);
|
||||
color: white;
|
||||
border-radius: 20px;
|
||||
padding: 8px 16px;
|
||||
margin: 0 5px 10px 0;
|
||||
transition: all 0.3s ease;
|
||||
font-size: 13px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.filter-btn:hover, .filter-btn.active {
|
||||
background: rgba(255,255,255,0.2);
|
||||
border-color: rgba(255,255,255,0.4);
|
||||
transform: translateY(-2px);
|
||||
color: white;
|
||||
}
|
||||
.filter-btn.active {
|
||||
background: rgba(255,255,255,0.25);
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* ✅ NUEVO: Botón flotante de ayuda */
|
||||
.help-float-btn {
|
||||
position: fixed;
|
||||
bottom: 30px;
|
||||
right: 30px;
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
border: none;
|
||||
border-radius: 50%;
|
||||
color: white;
|
||||
font-size: 24px;
|
||||
cursor: pointer;
|
||||
box-shadow: 0 8px 25px rgba(102, 126, 234, 0.4);
|
||||
transition: all 0.3s ease;
|
||||
z-index: 1060;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.help-float-btn:hover {
|
||||
transform: translateY(-3px) scale(1.1);
|
||||
box-shadow: 0 12px 35px rgba(102, 126, 234, 0.6);
|
||||
color: white;
|
||||
}
|
||||
.help-float-btn:active {
|
||||
transform: translateY(-1px) scale(1.05);
|
||||
}
|
||||
|
||||
/* ✅ NUEVO: Mini-modal de ayuda */
|
||||
.shortcuts-modal {
|
||||
position: fixed;
|
||||
bottom: 100px;
|
||||
right: 30px;
|
||||
width: 320px;
|
||||
background: white;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 15px 40px rgba(0,0,0,0.2);
|
||||
z-index: 1070;
|
||||
display: none;
|
||||
animation: slideInUp 0.3s ease;
|
||||
}
|
||||
@keyframes slideInUp {
|
||||
from { opacity: 0; transform: translateY(20px); }
|
||||
to { opacity: 1; transform: translateY(0); }
|
||||
}
|
||||
.shortcuts-header {
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
color: white;
|
||||
padding: 15px 20px;
|
||||
border-radius: 12px 12px 0 0;
|
||||
font-weight: bold;
|
||||
}
|
||||
.shortcuts-content {
|
||||
padding: 20px;
|
||||
max-height: 400px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
.shortcut-item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 10px 0;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
.shortcut-item:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
.shortcut-key {
|
||||
background: #f1f3f4;
|
||||
border: 1px solid #dadce0;
|
||||
border-radius: 4px;
|
||||
padding: 4px 8px;
|
||||
font-size: 12px;
|
||||
font-weight: bold;
|
||||
color: #5f6368;
|
||||
min-width: 50px;
|
||||
text-align: center;
|
||||
}
|
||||
.shortcut-desc {
|
||||
flex: 1;
|
||||
margin-right: 10px;
|
||||
font-size: 13px;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
/* ✅ NUEVO: Templates colapsados por defecto */
|
||||
.templates-section {
|
||||
margin-bottom: 25px;
|
||||
}
|
||||
.section-header {
|
||||
background: white;
|
||||
border: 1px solid #dee2e6;
|
||||
border-radius: 8px 8px 0 0;
|
||||
padding: 15px 20px;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
.section-header:hover {
|
||||
background: #f8f9fa;
|
||||
}
|
||||
.section-content {
|
||||
border: 1px solid #dee2e6;
|
||||
border-top: none;
|
||||
border-radius: 0 0 8px 8px;
|
||||
display: none;
|
||||
}
|
||||
.section-content.show {
|
||||
display: block;
|
||||
}
|
||||
.toggle-icon {
|
||||
transition: transform 0.2s ease;
|
||||
}
|
||||
.section-header.active .toggle-icon {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
/* Mejorar badges */
|
||||
.scope-badge {
|
||||
font-size: 11px;
|
||||
padding: 4px 8px;
|
||||
border-radius: 12px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="content">
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<h4 class="mb-0">📋 Templates Rápidos</h4>
|
||||
<div>
|
||||
<a href="/IMPORTADORES/templates_rapidos/crear" class="btn btn-success btn-animated">
|
||||
<i class="fas fa-plus me-1"></i>Nuevo Template
|
||||
</a>
|
||||
<a href="/IMPORTADORES/home" class="btn btn-secondary btn-animated ms-2">
|
||||
<i class="fas fa-arrow-left me-1"></i>Volver
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Alertas -->
|
||||
<?php if (isset($_GET['created'])): ?>
|
||||
<div class="alert alert-success alert-dismissible fade show fade-in" role="alert">
|
||||
<i class="fas fa-check-circle me-2"></i>
|
||||
<strong>¡Éxito!</strong> Template creado correctamente.
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (isset($_GET['updated'])): ?>
|
||||
<div class="alert alert-info alert-dismissible fade show fade-in" role="alert">
|
||||
<i class="fas fa-info-circle me-2"></i>
|
||||
<strong>¡Actualizado!</strong> Template modificado correctamente.
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (isset($_GET['deleted'])): ?>
|
||||
<div class="alert alert-warning alert-dismissible fade show fade-in" role="alert">
|
||||
<i class="fas fa-exclamation-circle me-2"></i>
|
||||
<strong>¡Eliminado!</strong> Template desactivado correctamente.
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<!-- ✅ NUEVO: Filtros mejorados -->
|
||||
<div class="template-filters">
|
||||
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||
<h6 class="mb-0"><i class="fas fa-filter me-2"></i>Filtrar Templates</h6>
|
||||
<small id="template-count" class="opacity-75">Cargando...</small>
|
||||
</div>
|
||||
<div class="d-flex flex-wrap">
|
||||
<button class="filter-btn active" data-filter="all">
|
||||
<i class="fas fa-th-list me-1"></i>Todos
|
||||
</button>
|
||||
<button class="filter-btn" data-filter="personal">
|
||||
<i class="fas fa-user me-1"></i>Mis Templates
|
||||
</button>
|
||||
<button class="filter-btn" data-filter="agencia">
|
||||
<i class="fas fa-building me-1"></i>De mi Agencia
|
||||
</button>
|
||||
<button class="filter-btn" data-filter="mas-usados">
|
||||
<i class="fas fa-fire me-1"></i>Más Usados
|
||||
</button>
|
||||
<button class="filter-btn" data-filter="recientes">
|
||||
<i class="fas fa-clock me-1"></i>Recientes
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ✅ MODIFICADO: Templates organizados por secciones colapsables -->
|
||||
<div class="templates-section">
|
||||
<div class="section-header" data-toggle="personal">
|
||||
<div>
|
||||
<h6 class="mb-0"><i class="fas fa-user text-primary me-2"></i>Mis Templates Personalizados</h6>
|
||||
<small class="text-muted">Templates que has creado</small>
|
||||
</div>
|
||||
<i class="fas fa-chevron-down toggle-icon"></i>
|
||||
</div>
|
||||
<div class="section-content show" id="personal-templates">
|
||||
<div class="card-body p-0">
|
||||
<div class="table-responsive">
|
||||
<table id="personalTemplatesTable" class="table table-hover mb-0" style="width:100%">
|
||||
<thead class="bg-light">
|
||||
<tr>
|
||||
<th width="60">ID</th>
|
||||
<th width="200">Nombre</th>
|
||||
<th>Descripción</th>
|
||||
<th width="80">Usos</th>
|
||||
<th width="100">Creado</th>
|
||||
<th width="120">Acciones</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody></tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="templates-section">
|
||||
<div class="section-header" data-toggle="agencia">
|
||||
<div>
|
||||
<h6 class="mb-0"><i class="fas fa-building text-info me-2"></i>Templates de Agencia</h6>
|
||||
<small class="text-muted">Compartidos en tu agencia</small>
|
||||
</div>
|
||||
<i class="fas fa-chevron-down toggle-icon"></i>
|
||||
</div>
|
||||
<div class="section-content" id="agencia-templates">
|
||||
<div class="card-body p-0">
|
||||
<div class="table-responsive">
|
||||
<table id="agenciaTemplatesTable" class="table table-hover mb-0" style="width:100%">
|
||||
<thead class="bg-light">
|
||||
<tr>
|
||||
<th width="60">ID</th>
|
||||
<th width="200">Nombre</th>
|
||||
<th>Descripción</th>
|
||||
<th width="80">Usos</th>
|
||||
<th width="100">Creado</th>
|
||||
<th width="120">Acciones</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody></tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Templates globales solo se muestran si se solicita explícitamente -->
|
||||
<div class="templates-section" style="display: none;" id="global-section">
|
||||
<div class="section-header" data-toggle="global">
|
||||
<div>
|
||||
<h6 class="mb-0"><i class="fas fa-globe text-secondary me-2"></i>Templates Globales</h6>
|
||||
<small class="text-muted">Predeterminados del sistema</small>
|
||||
</div>
|
||||
<i class="fas fa-chevron-down toggle-icon"></i>
|
||||
</div>
|
||||
<div class="section-content" id="global-templates">
|
||||
<div class="card-body p-0">
|
||||
<div class="table-responsive">
|
||||
<table id="globalTemplatesTable" class="table table-hover mb-0" style="width:100%">
|
||||
<thead class="bg-light">
|
||||
<tr>
|
||||
<th width="60">ID</th>
|
||||
<th width="200">Nombre</th>
|
||||
<th>Descripción</th>
|
||||
<th width="80">Usos</th>
|
||||
<th width="100">Creado</th>
|
||||
<th width="80">Ver</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody></tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ✅ NUEVO: Botón flotante de ayuda -->
|
||||
<button class="help-float-btn" id="helpBtn" title="Atajos rápidos">
|
||||
<i class="fas fa-question"></i>
|
||||
</button>
|
||||
|
||||
<!-- ✅ NUEVO: Mini-modal de atajos -->
|
||||
<div class="shortcuts-modal" id="shortcutsModal">
|
||||
<div class="shortcuts-header">
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
<span><i class="fas fa-keyboard me-2"></i>Atajos Rápidos</span>
|
||||
<button type="button" class="btn-close btn-close-white" id="closeShortcuts"></button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="shortcuts-content">
|
||||
<div class="mb-3">
|
||||
<strong class="text-primary">🎯 Templates</strong>
|
||||
</div>
|
||||
<div class="shortcut-item">
|
||||
<div class="shortcut-desc">Crear nuevo template</div>
|
||||
<div class="shortcut-key">Ctrl+N</div>
|
||||
</div>
|
||||
<div class="shortcut-item">
|
||||
<div class="shortcut-desc">Filtrar personal</div>
|
||||
<div class="shortcut-key">Alt+P</div>
|
||||
</div>
|
||||
<div class="shortcut-item">
|
||||
<div class="shortcut-desc">Filtrar agencia</div>
|
||||
<div class="shortcut-key">Alt+A</div>
|
||||
</div>
|
||||
<div class="shortcut-item">
|
||||
<div class="shortcut-desc">Más usados</div>
|
||||
<div class="shortcut-key">Alt+U</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-4 mb-3">
|
||||
<strong class="text-primary">⚡ Navegación</strong>
|
||||
</div>
|
||||
<div class="shortcut-item">
|
||||
<div class="shortcut-desc">Buscar en tabla</div>
|
||||
<div class="shortcut-key">Ctrl+F</div>
|
||||
</div>
|
||||
<div class="shortcut-item">
|
||||
<div class="shortcut-desc">Actualizar datos</div>
|
||||
<div class="shortcut-key">F5</div>
|
||||
</div>
|
||||
<div class="shortcut-item">
|
||||
<div class="shortcut-desc">Expandir/Colapsar</div>
|
||||
<div class="shortcut-key">Space</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-4 mb-3">
|
||||
<strong class="text-primary">📋 Pedimentos</strong>
|
||||
</div>
|
||||
<div class="shortcut-item">
|
||||
<div class="shortcut-desc">Nueva solicitud</div>
|
||||
<div class="shortcut-key">Ctrl+I</div>
|
||||
</div>
|
||||
<div class="shortcut-item">
|
||||
<div class="shortcut-desc">Aplicar template</div>
|
||||
<div class="shortcut-key">Enter</div>
|
||||
</div>
|
||||
<div class="shortcut-item">
|
||||
<div class="shortcut-desc">Guardar rápido</div>
|
||||
<div class="shortcut-key">Ctrl+S</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-3 text-center">
|
||||
<small class="text-muted">
|
||||
<i class="fas fa-info-circle me-1"></i>
|
||||
Presiona <kbd>F1</kbd> para mostrar/ocultar esta ayuda
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
// ✅ CONFIGURAR DATATABLES POR SECCIÓN
|
||||
const personalTable = initDataTable('#personalTemplatesTable', 'personal');
|
||||
const agenciaTable = initDataTable('#agenciaTemplatesTable', 'agencia');
|
||||
const globalTable = initDataTable('#globalTemplatesTable', 'global');
|
||||
|
||||
// ✅ MANEJO DE SECCIONES COLAPSABLES
|
||||
$('.section-header').click(function() {
|
||||
const $this = $(this);
|
||||
const $content = $this.next('.section-content');
|
||||
const $icon = $this.find('.toggle-icon');
|
||||
|
||||
$content.slideToggle(300);
|
||||
$this.toggleClass('active');
|
||||
|
||||
// Si se está abriendo y la tabla no se ha cargado
|
||||
if ($content.is(':visible') && !$content.data('loaded')) {
|
||||
const section = $this.data('toggle');
|
||||
loadSectionData(section);
|
||||
$content.data('loaded', true);
|
||||
}
|
||||
});
|
||||
|
||||
// ✅ FILTROS MEJORADOS
|
||||
$('.filter-btn').click(function() {
|
||||
$('.filter-btn').removeClass('active');
|
||||
$(this).addClass('active');
|
||||
|
||||
const filter = $(this).data('filter');
|
||||
applyFilter(filter);
|
||||
});
|
||||
|
||||
// ✅ BOTÓN FLOTANTE DE AYUDA
|
||||
$('#helpBtn').click(function() {
|
||||
$('#shortcutsModal').toggle();
|
||||
});
|
||||
|
||||
$('#closeShortcuts').click(function() {
|
||||
$('#shortcutsModal').hide();
|
||||
});
|
||||
|
||||
// Cerrar modal al hacer clic fuera
|
||||
$(document).click(function(e) {
|
||||
if (!$(e.target).closest('#shortcutsModal, #helpBtn').length) {
|
||||
$('#shortcutsModal').hide();
|
||||
}
|
||||
});
|
||||
|
||||
// ✅ ATAJOS DE TECLADO
|
||||
$(document).keydown(function(e) {
|
||||
// Ctrl+N: Nuevo template
|
||||
if (e.ctrlKey && e.key === 'n') {
|
||||
e.preventDefault();
|
||||
window.location.href = '/IMPORTADORES/templates_rapidos/crear';
|
||||
}
|
||||
|
||||
// Ctrl+I: Nueva solicitud
|
||||
if (e.ctrlKey && e.key === 'i') {
|
||||
e.preventDefault();
|
||||
window.location.href = '/IMPORTADORES/solicitud_importacion/crear';
|
||||
}
|
||||
|
||||
// Alt+P: Filtrar personal
|
||||
if (e.altKey && e.key === 'p') {
|
||||
e.preventDefault();
|
||||
$('.filter-btn[data-filter="personal"]').click();
|
||||
}
|
||||
|
||||
// Alt+A: Filtrar agencia
|
||||
if (e.altKey && e.key === 'a') {
|
||||
e.preventDefault();
|
||||
$('.filter-btn[data-filter="agencia"]').click();
|
||||
}
|
||||
|
||||
// Alt+U: Más usados
|
||||
if (e.altKey && e.key === 'u') {
|
||||
e.preventDefault();
|
||||
$('.filter-btn[data-filter="mas-usados"]').click();
|
||||
}
|
||||
|
||||
// F1: Toggle ayuda
|
||||
if (e.key === 'F1') {
|
||||
e.preventDefault();
|
||||
$('#shortcutsModal').toggle();
|
||||
}
|
||||
|
||||
// F5: Actualizar
|
||||
if (e.key === 'F5') {
|
||||
e.preventDefault();
|
||||
location.reload();
|
||||
}
|
||||
|
||||
// Space: Toggle sección activa
|
||||
if (e.key === ' ' && !$(e.target).is('input, textarea, select')) {
|
||||
e.preventDefault();
|
||||
$('.section-header.active').click();
|
||||
}
|
||||
});
|
||||
|
||||
// Auto-refresh cada 30 segundos
|
||||
setInterval(() => {
|
||||
refreshActiveTables();
|
||||
}, 30000);
|
||||
|
||||
// Auto-dismiss alerts
|
||||
setTimeout(() => {
|
||||
$('.alert').fadeOut('slow');
|
||||
}, 5000);
|
||||
|
||||
// Cargar sección personal por defecto
|
||||
loadSectionData('personal');
|
||||
$('#personal-templates').data('loaded', true);
|
||||
});
|
||||
|
||||
// ✅ FUNCIÓN PARA INICIALIZAR DATATABLES
|
||||
function initDataTable(selector, scope) {
|
||||
return $(selector).DataTable({
|
||||
processing: true,
|
||||
serverSide: false,
|
||||
data: [],
|
||||
columns: [
|
||||
{ data: 0 }, // ID
|
||||
{ data: 1 }, // Nombre con icono
|
||||
{ data: 2 }, // Descripción
|
||||
{ data: 3 }, // Veces usado
|
||||
{ data: 4 }, // Fecha creación
|
||||
{ data: 5, orderable: false } // Acciones
|
||||
],
|
||||
order: [[3, 'desc']], // Ordenar por usos descendente
|
||||
language: {
|
||||
processing: "Procesando...",
|
||||
search: "Buscar:",
|
||||
lengthMenu: "Mostrar _MENU_ registros",
|
||||
info: "Mostrando de _START_ a _END_ de _TOTAL_ registros",
|
||||
infoEmpty: "Mostrando 0 a 0 de 0 registros",
|
||||
infoFiltered: "(filtrado de _MAX_ registros totales)",
|
||||
loadingRecords: "Cargando...",
|
||||
zeroRecords: "No se encontraron templates " + (scope === 'personal' ? 'personalizados' : scope === 'agencia' ? 'de agencia' : 'globales'),
|
||||
emptyTable: "No hay templates " + (scope === 'personal' ? 'personalizados' : scope === 'agencia' ? 'de agencia' : 'globales'),
|
||||
paginate: {
|
||||
first: "Primero",
|
||||
previous: "Anterior",
|
||||
next: "Siguiente",
|
||||
last: "Último"
|
||||
}
|
||||
},
|
||||
pageLength: 10,
|
||||
responsive: true,
|
||||
drawCallback: function() {
|
||||
$(selector + ' tbody tr').addClass('fade-in');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// ✅ FUNCIÓN PARA CARGAR DATOS POR SECCIÓN
|
||||
function loadSectionData(section) {
|
||||
$.ajax({
|
||||
url: '/IMPORTADORES/templates_rapidos/ajax_lista_por_seccion',
|
||||
method: 'GET',
|
||||
data: { seccion: section },
|
||||
dataType: 'json',
|
||||
success: function(response) {
|
||||
let table;
|
||||
switch(section) {
|
||||
case 'personal':
|
||||
table = $('#personalTemplatesTable').DataTable();
|
||||
break;
|
||||
case 'agencia':
|
||||
table = $('#agenciaTemplatesTable').DataTable();
|
||||
break;
|
||||
case 'global':
|
||||
table = $('#globalTemplatesTable').DataTable();
|
||||
break;
|
||||
}
|
||||
|
||||
if (table) {
|
||||
table.clear().rows.add(response.data || []).draw();
|
||||
}
|
||||
|
||||
updateTemplateCount();
|
||||
},
|
||||
error: function() {
|
||||
console.error('Error cargando templates de sección:', section);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// ✅ FUNCIÓN PARA APLICAR FILTROS
|
||||
function applyFilter(filter) {
|
||||
switch(filter) {
|
||||
case 'all':
|
||||
$('.templates-section').show();
|
||||
$('.section-content.show').each(function() {
|
||||
if (!$(this).data('loaded')) {
|
||||
const section = $(this).prev().data('toggle');
|
||||
loadSectionData(section);
|
||||
$(this).data('loaded', true);
|
||||
}
|
||||
});
|
||||
break;
|
||||
|
||||
case 'personal':
|
||||
$('.templates-section').hide();
|
||||
$('.templates-section').first().show();
|
||||
if (!$('#personal-templates').hasClass('show')) {
|
||||
$('.section-header').first().click();
|
||||
}
|
||||
break;
|
||||
|
||||
case 'agencia':
|
||||
$('.templates-section').hide();
|
||||
$('.templates-section').eq(1).show();
|
||||
if (!$('#agencia-templates').hasClass('show')) {
|
||||
$('.section-header').eq(1).click();
|
||||
}
|
||||
break;
|
||||
|
||||
case 'mas-usados':
|
||||
// Mostrar todos pero filtrar por más de 5 usos
|
||||
$('.templates-section').show();
|
||||
$('.section-content.show').each(function() {
|
||||
const table = $(this).find('table').DataTable();
|
||||
table.search('').columns().search('').draw();
|
||||
table.column(3).search('^([5-9]|[1-9][0-9]+)$', true, false).draw();
|
||||
});
|
||||
break;
|
||||
|
||||
case 'recientes':
|
||||
// Mostrar todos pero filtrar por últimos 7 días
|
||||
$('.templates-section').show();
|
||||
const weekAgo = new Date();
|
||||
weekAgo.setDate(weekAgo.getDate() - 7);
|
||||
$('.section-content.show').each(function() {
|
||||
const table = $(this).find('table').DataTable();
|
||||
table.search('').columns().search('').draw();
|
||||
// Filtrar por fecha en columna 4
|
||||
});
|
||||
break;
|
||||
}
|
||||
updateTemplateCount();
|
||||
}
|
||||
|
||||
// ✅ FUNCIÓN PARA ACTUALIZAR CONTADOR DE TEMPLATES
|
||||
function updateTemplateCount() {
|
||||
let total = 0;
|
||||
$('.section-content:visible').each(function() {
|
||||
const table = $(this).find('table').DataTable();
|
||||
if (table) {
|
||||
total += table.rows({search: 'applied'}).count();
|
||||
}
|
||||
});
|
||||
|
||||
$('#template-count').text(`${total} templates disponibles`);
|
||||
}
|
||||
|
||||
// ✅ FUNCIÓN PARA REFRESCAR TABLAS ACTIVAS
|
||||
function refreshActiveTables() {
|
||||
$('.section-content:visible').each(function() {
|
||||
if ($(this).data('loaded')) {
|
||||
const section = $(this).prev().data('toggle');
|
||||
loadSectionData(section);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// ✅ FUNCIONES DE ACCIONES
|
||||
function aplicarTemplate(id, nombre) {
|
||||
Swal.fire({
|
||||
title: '🚀 Aplicar Template',
|
||||
text: `¿Crear nueva solicitud con el template "${nombre}"?`,
|
||||
icon: 'question',
|
||||
showCancelButton: true,
|
||||
confirmButtonText: '<i class="fas fa-rocket me-1"></i>Aplicar',
|
||||
cancelButtonText: 'Cancelar',
|
||||
confirmButtonColor: '#28a745',
|
||||
cancelButtonColor: '#6c757d'
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
window.location.href = `/IMPORTADORES/solicitud_importacion/crear?template=${id}`;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function editarTemplate(id) {
|
||||
window.location.href = `/IMPORTADORES/templates_rapidos/editar/${id}`;
|
||||
}
|
||||
|
||||
function duplicarTemplate(id, nombre) {
|
||||
Swal.fire({
|
||||
title: '📋 Duplicar Template',
|
||||
text: `¿Crear una copia de "${nombre}"?`,
|
||||
icon: 'question',
|
||||
showCancelButton: true,
|
||||
confirmButtonText: '<i class="fas fa-copy me-1"></i>Duplicar',
|
||||
cancelButtonText: 'Cancelar',
|
||||
confirmButtonColor: '#17a2b8',
|
||||
cancelButtonColor: '#6c757d'
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
$.ajax({
|
||||
url: '/IMPORTADORES/templates_rapidos/duplicar',
|
||||
method: 'POST',
|
||||
data: { id: id },
|
||||
success: function(response) {
|
||||
if (response.success) {
|
||||
Swal.fire({
|
||||
title: '✅ ¡Duplicado!',
|
||||
text: 'Template duplicado exitosamente',
|
||||
icon: 'success',
|
||||
timer: 2000,
|
||||
showConfirmButton: false
|
||||
}).then(() => {
|
||||
location.reload();
|
||||
});
|
||||
} else {
|
||||
Swal.fire('Error', response.message || 'No se pudo duplicar', 'error');
|
||||
}
|
||||
},
|
||||
error: function() {
|
||||
Swal.fire('Error', 'Error de conexión', 'error');
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function eliminarTemplate(id, nombre) {
|
||||
Swal.fire({
|
||||
title: '⚠️ Eliminar Template',
|
||||
html: `¿Estás seguro de eliminar "<strong>${nombre}</strong>"?<br><small class="text-muted">Esta acción no se puede deshacer</small>`,
|
||||
icon: 'warning',
|
||||
showCancelButton: true,
|
||||
confirmButtonText: '<i class="fas fa-trash me-1"></i>Eliminar',
|
||||
cancelButtonText: 'Cancelar',
|
||||
confirmButtonColor: '#dc3545',
|
||||
cancelButtonColor: '#6c757d',
|
||||
focusCancel: true
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
$.ajax({
|
||||
url: '/IMPORTADORES/templates_rapidos/eliminar',
|
||||
method: 'POST',
|
||||
data: { id: id },
|
||||
success: function(response) {
|
||||
if (response.success) {
|
||||
Swal.fire({
|
||||
title: '✅ ¡Eliminado!',
|
||||
text: 'Template eliminado exitosamente',
|
||||
icon: 'success',
|
||||
timer: 2000,
|
||||
showConfirmButton: false
|
||||
}).then(() => {
|
||||
location.reload();
|
||||
});
|
||||
} else {
|
||||
Swal.fire('Error', response.message || 'No se pudo eliminar', 'error');
|
||||
}
|
||||
},
|
||||
error: function() {
|
||||
Swal.fire('Error', 'Error de conexión', 'error');
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function verTemplate(id) {
|
||||
// Abrir modal con detalles del template
|
||||
$.ajax({
|
||||
url: `/IMPORTADORES/templates_rapidos/ver/${id}`,
|
||||
method: 'GET',
|
||||
success: function(response) {
|
||||
Swal.fire({
|
||||
title: '📄 Detalles del Template',
|
||||
html: response,
|
||||
width: '80%',
|
||||
showCloseButton: true,
|
||||
showConfirmButton: false,
|
||||
customClass: {
|
||||
container: 'template-preview-modal'
|
||||
}
|
||||
});
|
||||
},
|
||||
error: function() {
|
||||
Swal.fire('Error', 'No se pudo cargar el template', 'error');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// ✅ MANEJO DE EVENTOS GLOBALES
|
||||
$(document).on('click', '.btn-aplicar', function(e) {
|
||||
e.preventDefault();
|
||||
const id = $(this).data('id');
|
||||
const nombre = $(this).data('nombre');
|
||||
aplicarTemplate(id, nombre);
|
||||
});
|
||||
|
||||
$(document).on('click', '.btn-editar', function(e) {
|
||||
e.preventDefault();
|
||||
const id = $(this).data('id');
|
||||
editarTemplate(id);
|
||||
});
|
||||
|
||||
$(document).on('click', '.btn-duplicar', function(e) {
|
||||
e.preventDefault();
|
||||
const id = $(this).data('id');
|
||||
const nombre = $(this).data('nombre');
|
||||
duplicarTemplate(id, nombre);
|
||||
});
|
||||
|
||||
$(document).on('click', '.btn-eliminar', function(e) {
|
||||
e.preventDefault();
|
||||
const id = $(this).data('id');
|
||||
const nombre = $(this).data('nombre');
|
||||
eliminarTemplate(id, nombre);
|
||||
});
|
||||
|
||||
$(document).on('click', '.btn-ver', function(e) {
|
||||
e.preventDefault();
|
||||
const id = $(this).data('id');
|
||||
verTemplate(id);
|
||||
});
|
||||
|
||||
// ✅ TOOLTIPS MEJORADOS
|
||||
$(document).on('mouseenter', '[title]', function() {
|
||||
$(this).tooltip('show');
|
||||
});
|
||||
|
||||
// ✅ ANIMACIONES DE HOVER EN FILAS
|
||||
$(document).on('mouseenter', 'tbody tr', function() {
|
||||
$(this).addClass('table-active');
|
||||
}).on('mouseleave', 'tbody tr', function() {
|
||||
$(this).removeClass('table-active');
|
||||
});
|
||||
|
||||
// ✅ NOTIFICACIONES DE ACTUALIZACIÓN
|
||||
function showUpdateNotification() {
|
||||
const toast = $(`
|
||||
<div class="toast-notification">
|
||||
<div class="d-flex align-items-center">
|
||||
<i class="fas fa-sync-alt me-2 text-primary"></i>
|
||||
<span>Templates actualizados</span>
|
||||
<button type="button" class="btn-close btn-close-sm ms-auto"></button>
|
||||
</div>
|
||||
</div>
|
||||
`);
|
||||
|
||||
$('body').append(toast);
|
||||
toast.fadeIn();
|
||||
|
||||
setTimeout(() => {
|
||||
toast.fadeOut(() => toast.remove());
|
||||
}, 3000);
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
/* ✅ ESTILOS ADICIONALES */
|
||||
.toast-notification {
|
||||
position: fixed;
|
||||
bottom: 100px;
|
||||
left: 30px;
|
||||
background: white;
|
||||
border: 1px solid #dee2e6;
|
||||
border-radius: 8px;
|
||||
padding: 15px;
|
||||
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
|
||||
z-index: 1050;
|
||||
display: none;
|
||||
min-width: 250px;
|
||||
}
|
||||
|
||||
.template-preview-modal {
|
||||
font-family: inherit;
|
||||
}
|
||||
|
||||
.template-preview-modal .swal2-html-container {
|
||||
max-height: 70vh;
|
||||
overflow-y: auto;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
/* Mejorar responsive de tablas */
|
||||
@media (max-width: 768px) {
|
||||
.template-filters {
|
||||
padding: 15px;
|
||||
}
|
||||
|
||||
.filter-btn {
|
||||
font-size: 12px;
|
||||
padding: 6px 12px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.help-float-btn {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
font-size: 20px;
|
||||
bottom: 20px;
|
||||
right: 20px;
|
||||
}
|
||||
|
||||
.shortcuts-modal {
|
||||
width: 280px;
|
||||
right: 20px;
|
||||
bottom: 80px;
|
||||
}
|
||||
}
|
||||
|
||||
/* Estados de carga */
|
||||
.loading-row {
|
||||
background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);
|
||||
background-size: 200% 100%;
|
||||
animation: shimmer 1.5s infinite;
|
||||
}
|
||||
|
||||
@keyframes shimmer {
|
||||
0% { background-position: -200% 0; }
|
||||
100% { background-position: 200% 0; }
|
||||
}
|
||||
</style>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user