Cambios
This commit is contained in:
@@ -0,0 +1,65 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* API: Historial de envíos masivos (broadcasts)
|
||||||
|
* GET ?page=1&per_page=20
|
||||||
|
*/
|
||||||
|
require_once '../config/config.php';
|
||||||
|
requireAuthentication();
|
||||||
|
|
||||||
|
header('Content-Type: application/json; charset=utf-8');
|
||||||
|
header('X-Content-Type-Options: nosniff');
|
||||||
|
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] !== 'GET') {
|
||||||
|
http_response_code(405);
|
||||||
|
echo json_encode(['success' => false, 'error' => 'Método no permitido']);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$db = Database::getInstance();
|
||||||
|
|
||||||
|
// Crear tabla si no existe todavía
|
||||||
|
$db->getConnection()->exec("
|
||||||
|
CREATE TABLE IF NOT EXISTS broadcast_history (
|
||||||
|
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
sent_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
message_type VARCHAR(20) NOT NULL DEFAULT 'text',
|
||||||
|
selection_type VARCHAR(20) NOT NULL DEFAULT 'filter',
|
||||||
|
filter_used VARCHAR(50) NULL,
|
||||||
|
template_name VARCHAR(120) NULL,
|
||||||
|
message_preview TEXT NULL,
|
||||||
|
total_users INT UNSIGNED NOT NULL DEFAULT 0,
|
||||||
|
sent_count INT UNSIGNED NOT NULL DEFAULT 0,
|
||||||
|
error_count INT UNSIGNED NOT NULL DEFAULT 0,
|
||||||
|
sent_by INT UNSIGNED NULL,
|
||||||
|
sent_by_name VARCHAR(120) NULL,
|
||||||
|
INDEX idx_sent_at (sent_at)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
|
||||||
|
");
|
||||||
|
|
||||||
|
$page = max(1, (int)($_GET['page'] ?? 1));
|
||||||
|
$perPage = min(100, max(5, (int)($_GET['per_page'] ?? 20)));
|
||||||
|
$offset = ($page - 1) * $perPage;
|
||||||
|
|
||||||
|
try {
|
||||||
|
$total = (int)$db->getConnection()
|
||||||
|
->query("SELECT COUNT(*) FROM broadcast_history")
|
||||||
|
->fetchColumn();
|
||||||
|
|
||||||
|
$rows = $db->fetchAll(
|
||||||
|
"SELECT * FROM broadcast_history ORDER BY sent_at DESC LIMIT ? OFFSET ?",
|
||||||
|
[$perPage, $offset]
|
||||||
|
);
|
||||||
|
|
||||||
|
echo json_encode([
|
||||||
|
'success' => true,
|
||||||
|
'data' => $rows,
|
||||||
|
'total' => $total,
|
||||||
|
'page' => $page,
|
||||||
|
'per_page' => $perPage,
|
||||||
|
'pages' => (int)ceil($total / $perPage),
|
||||||
|
]);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
error_log('get_broadcast_history.php: ' . $e->getMessage());
|
||||||
|
http_response_code(500);
|
||||||
|
echo json_encode(['success' => false, 'error' => 'Error interno del servidor']);
|
||||||
|
}
|
||||||
@@ -9,6 +9,27 @@ require_once '../config/config.php';
|
|||||||
// Verificar autenticación
|
// Verificar autenticación
|
||||||
requireAuthentication();
|
requireAuthentication();
|
||||||
|
|
||||||
|
// Asegurar que la tabla de historial existe
|
||||||
|
try {
|
||||||
|
Database::getInstance()->getConnection()->exec("
|
||||||
|
CREATE TABLE IF NOT EXISTS broadcast_history (
|
||||||
|
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
sent_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
message_type VARCHAR(20) NOT NULL DEFAULT 'text',
|
||||||
|
selection_type VARCHAR(20) NOT NULL DEFAULT 'filter',
|
||||||
|
filter_used VARCHAR(50) NULL,
|
||||||
|
template_name VARCHAR(120) NULL,
|
||||||
|
message_preview TEXT NULL,
|
||||||
|
total_users INT UNSIGNED NOT NULL DEFAULT 0,
|
||||||
|
sent_count INT UNSIGNED NOT NULL DEFAULT 0,
|
||||||
|
error_count INT UNSIGNED NOT NULL DEFAULT 0,
|
||||||
|
sent_by INT UNSIGNED NULL,
|
||||||
|
sent_by_name VARCHAR(120) NULL,
|
||||||
|
INDEX idx_sent_at (sent_at)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
|
||||||
|
");
|
||||||
|
} catch (Exception $_e) { /* silencioso si ya existe */ }
|
||||||
|
|
||||||
header('Content-Type: application/json; charset=utf-8');
|
header('Content-Type: application/json; charset=utf-8');
|
||||||
header('Access-Control-Allow-Origin: *');
|
header('Access-Control-Allow-Origin: *');
|
||||||
header('Access-Control-Allow-Methods: POST');
|
header('Access-Control-Allow-Methods: POST');
|
||||||
@@ -271,6 +292,38 @@ try {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --- Guardar historial de broadcast ---
|
||||||
|
try {
|
||||||
|
$adminId = (int)($_SESSION['admin_user']['id'] ?? $_SESSION['user_id'] ?? 0);
|
||||||
|
$adminName = $_SESSION['admin_user']['name'] ?? $_SESSION['username'] ?? 'Sistema';
|
||||||
|
|
||||||
|
$tplName = null;
|
||||||
|
$preview = '';
|
||||||
|
if ($messageType === 'template' && isset($template)) {
|
||||||
|
$tplName = $template['template_name'] ?? $template['name'] ?? null;
|
||||||
|
$preview = mb_substr($template['body'] ?? $tplName ?? '', 0, 200);
|
||||||
|
} else {
|
||||||
|
$preview = mb_substr($input['message'] ?? '', 0, 200);
|
||||||
|
}
|
||||||
|
|
||||||
|
$db->insert('broadcast_history', [
|
||||||
|
'sent_at' => date('Y-m-d H:i:s'),
|
||||||
|
'message_type' => $messageType,
|
||||||
|
'selection_type' => $selectionType,
|
||||||
|
'filter_used' => ($selectionType === 'filter') ? ($input['filter'] ?? 'all') : null,
|
||||||
|
'template_name' => $tplName,
|
||||||
|
'message_preview' => $preview,
|
||||||
|
'total_users' => count($users),
|
||||||
|
'sent_count' => $sentCount,
|
||||||
|
'error_count' => $errorCount,
|
||||||
|
'sent_by' => $adminId ?: null,
|
||||||
|
'sent_by_name' => $adminName ?: null,
|
||||||
|
]);
|
||||||
|
} catch (Exception $eHist) {
|
||||||
|
error_log('broadcast_history insert failed: ' . $eHist->getMessage());
|
||||||
|
}
|
||||||
|
// --- Fin historial ---
|
||||||
|
|
||||||
echo json_encode([
|
echo json_encode([
|
||||||
'success' => true,
|
'success' => true,
|
||||||
'sent_count' => $sentCount,
|
'sent_count' => $sentCount,
|
||||||
|
|||||||
@@ -1947,6 +1947,10 @@ class SimpleWhatsAppManager {
|
|||||||
$('#broadcast-users').val(null).trigger('change');
|
$('#broadcast-users').val(null).trigger('change');
|
||||||
document.getElementById('broadcast-template-variables').style.display = 'none';
|
document.getElementById('broadcast-template-variables').style.display = 'none';
|
||||||
document.getElementById('broadcast-template-preview').style.display = 'none';
|
document.getElementById('broadcast-template-preview').style.display = 'none';
|
||||||
|
// Refrescar historial automáticamente
|
||||||
|
if (typeof window.loadBroadcastHistory === 'function') {
|
||||||
|
setTimeout(() => window.loadBroadcastHistory(1), 800);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
this.showError(result.error || 'Error enviando broadcast');
|
this.showError(result.error || 'Error enviando broadcast');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -118,6 +118,7 @@ class Domicilio {
|
|||||||
p.direccion AS paciente_direccion,
|
p.direccion AS paciente_direccion,
|
||||||
o.examenes_solicitados,
|
o.examenes_solicitados,
|
||||||
o.indicaciones AS indicaciones_orden,
|
o.indicaciones AS indicaciones_orden,
|
||||||
|
o.local_file AS orden_local_file,
|
||||||
e.nombre_completo AS enfermera_nombre,
|
e.nombre_completo AS enfermera_nombre,
|
||||||
e.telefono AS enfermera_telefono,
|
e.telefono AS enfermera_telefono,
|
||||||
a.id AS asignacion_id,
|
a.id AS asignacion_id,
|
||||||
|
|||||||
@@ -663,6 +663,44 @@ try {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Historial de Envíos Masivos -->
|
||||||
|
<div class="card mt-4">
|
||||||
|
<div class="card-header d-flex justify-content-between align-items-center">
|
||||||
|
<h5 class="mb-0"><i class="fas fa-history me-2 text-secondary"></i>Historial de Envíos Masivos</h5>
|
||||||
|
<button class="btn btn-sm btn-outline-secondary" onclick="loadBroadcastHistory(1)">
|
||||||
|
<i class="fas fa-sync-alt"></i> Actualizar
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="card-body p-0">
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table class="table table-hover table-sm mb-0">
|
||||||
|
<thead class="table-light">
|
||||||
|
<tr>
|
||||||
|
<th>Fecha</th>
|
||||||
|
<th>Tipo</th>
|
||||||
|
<th>Mensaje / Plantilla</th>
|
||||||
|
<th class="text-center">Total</th>
|
||||||
|
<th class="text-center text-success">Enviados</th>
|
||||||
|
<th class="text-center text-danger">Errores</th>
|
||||||
|
<th>Enviado por</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody id="broadcast-history-tbody">
|
||||||
|
<tr>
|
||||||
|
<td colspan="7" class="text-center text-muted py-4">
|
||||||
|
<i class="fas fa-spinner fa-spin me-1"></i> Cargando historial...
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<div id="bh-pagination-row" class="d-flex justify-content-between align-items-center px-3 py-2 border-top" style="display:none!important">
|
||||||
|
<small class="text-muted" id="bh-pagination-info"></small>
|
||||||
|
<div class="d-flex gap-1" id="bh-pagination-btns"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- WhatsApp Profile Tab -->
|
<!-- WhatsApp Profile Tab -->
|
||||||
@@ -2191,6 +2229,88 @@ try {
|
|||||||
})();
|
})();
|
||||||
</script>
|
</script>
|
||||||
<!-- ── / T&C Aceptaciones JS ─────────────────────────────────────────── -->
|
<!-- ── / T&C Aceptaciones JS ─────────────────────────────────────────── -->
|
||||||
|
|
||||||
|
<!-- ── Historial Envíos Masivos JS ──────────────────────────────────── -->
|
||||||
|
<script>
|
||||||
|
(function () {
|
||||||
|
let _currentPage = 1;
|
||||||
|
|
||||||
|
window.loadBroadcastHistory = function (page) {
|
||||||
|
page = page || 1;
|
||||||
|
_currentPage = page;
|
||||||
|
|
||||||
|
const tbody = document.getElementById('broadcast-history-tbody');
|
||||||
|
if (!tbody) return;
|
||||||
|
tbody.innerHTML = '<tr><td colspan="7" class="text-center text-muted py-3"><i class="fas fa-spinner fa-spin me-1"></i> Cargando...</td></tr>';
|
||||||
|
|
||||||
|
fetch('api/get_broadcast_history.php?page=' + page + '&per_page=10')
|
||||||
|
.then(r => r.json())
|
||||||
|
.then(res => {
|
||||||
|
if (!res.success || !res.data) {
|
||||||
|
tbody.innerHTML = '<tr><td colspan="7" class="text-center text-muted py-3">Sin registros</td></tr>';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (res.data.length === 0) {
|
||||||
|
tbody.innerHTML = '<tr><td colspan="7" class="text-center text-muted py-3"><i class="fas fa-inbox me-1"></i> Aún no hay envíos masivos registrados</td></tr>';
|
||||||
|
} else {
|
||||||
|
const typeLabels = { text: 'Texto', template: 'Plantilla', image: 'Imagen', document: 'Documento' };
|
||||||
|
const filterLabels = { all: 'Todos', active: 'Activos', recent: 'Recientes', null: '—' };
|
||||||
|
tbody.innerHTML = res.data.map(r => {
|
||||||
|
const fecha = r.sent_at ? r.sent_at.replace('T', ' ').substring(0, 16) : '—';
|
||||||
|
const tipo = typeLabels[r.message_type] || r.message_type || '—';
|
||||||
|
const msg = r.template_name
|
||||||
|
? '<span class="badge bg-success-subtle text-success border border-success-subtle me-1">Plantilla</span>' + htmlEsc(r.template_name)
|
||||||
|
: (r.message_preview ? htmlEsc(r.message_preview.substring(0, 60)) + (r.message_preview.length > 60 ? '…' : '') : '—');
|
||||||
|
const pct = r.total_users > 0 ? Math.round(r.sent_count / r.total_users * 100) : 0;
|
||||||
|
return `<tr>
|
||||||
|
<td class="small text-nowrap">${fecha}</td>
|
||||||
|
<td><span class="badge bg-secondary-subtle text-secondary border">${tipo}</span></td>
|
||||||
|
<td class="small">${msg}</td>
|
||||||
|
<td class="text-center fw-bold">${r.total_users}</td>
|
||||||
|
<td class="text-center text-success fw-bold">${r.sent_count} <small class="text-muted">(${pct}%)</small></td>
|
||||||
|
<td class="text-center ${r.error_count > 0 ? 'text-danger fw-bold' : 'text-muted'}">${r.error_count}</td>
|
||||||
|
<td class="small text-muted">${htmlEsc(r.sent_by_name || 'Sistema')}</td>
|
||||||
|
</tr>`;
|
||||||
|
}).join('');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Paginación
|
||||||
|
const pagRow = document.getElementById('bh-pagination-row');
|
||||||
|
const pagInfo = document.getElementById('bh-pagination-info');
|
||||||
|
const pagBtns = document.getElementById('bh-pagination-btns');
|
||||||
|
if (pagRow && res.pages > 1) {
|
||||||
|
pagRow.style.display = '';
|
||||||
|
pagInfo.textContent = 'Página ' + res.page + ' de ' + res.pages + ' (' + res.total + ' registros)';
|
||||||
|
let btns = '';
|
||||||
|
for (let p = 1; p <= res.pages; p++) {
|
||||||
|
btns += `<button class="btn btn-sm ${p === res.page ? 'btn-secondary' : 'btn-outline-secondary'}" onclick="loadBroadcastHistory(${p})">${p}</button>`;
|
||||||
|
}
|
||||||
|
pagBtns.innerHTML = btns;
|
||||||
|
} else if (pagRow) {
|
||||||
|
pagRow.style.display = 'none';
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
if (tbody) tbody.innerHTML = '<tr><td colspan="7" class="text-center text-danger py-3">Error al cargar el historial</td></tr>';
|
||||||
|
console.error('loadBroadcastHistory error:', err);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
function htmlEsc(str) {
|
||||||
|
return String(str).replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>').replace(/"/g,'"');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cargar al activar el tab de broadcast
|
||||||
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
|
const broadcastLinks = document.querySelectorAll('.nav-link[data-tab="broadcast"], [data-tab="broadcast"]');
|
||||||
|
broadcastLinks.forEach(link => {
|
||||||
|
link.addEventListener('click', () => setTimeout(() => loadBroadcastHistory(1), 100));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
<!-- ── / Historial Envíos Masivos JS ─────────────────────────────────── -->
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
+173
-5
@@ -148,7 +148,7 @@ $domIdParam = (int)($_GET['id'] ?? 0);
|
|||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<form id="form-domicilio">
|
<form id="form-domicilio">
|
||||||
<input type="hidden" name="id" id="dom-id">
|
<input type="hidden" name="id" id="dom-id">
|
||||||
<input type="hidden" name="orden_id" id="dom-orden-id" value="<?= $ordenIdParam ?>">
|
<input type="hidden" name="orden_id_url" id="dom-orden-id" value="<?= $ordenIdParam ?>">
|
||||||
|
|
||||||
<!-- ── Paciente ── -->
|
<!-- ── Paciente ── -->
|
||||||
<h6 class="text-muted text-uppercase small fw-semibold border-bottom pb-1 mb-3">
|
<h6 class="text-muted text-uppercase small fw-semibold border-bottom pb-1 mb-3">
|
||||||
@@ -251,6 +251,44 @@ $domIdParam = (int)($_GET['id'] ?? 0);
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- ── Orden Médica ── -->
|
||||||
|
<h6 class="text-muted text-uppercase small fw-semibold border-bottom pb-1 mb-3">
|
||||||
|
<i class="fas fa-file-medical me-1"></i> Orden Médica Adjunta
|
||||||
|
</h6>
|
||||||
|
<div class="mb-3">
|
||||||
|
<input type="hidden" name="orden_id" id="dom-orden-id-form">
|
||||||
|
<!-- Preview archivo actual o pendiente -->
|
||||||
|
<div id="dom-orden-preview" class="d-flex align-items-center gap-3 p-2 rounded border bg-light mb-2 d-none">
|
||||||
|
<div id="dom-orden-thumb-wrap">
|
||||||
|
<img id="dom-orden-img" src="" alt="Orden" style="max-height:80px;max-width:100px;object-fit:contain;border-radius:4px;display:none">
|
||||||
|
<div id="dom-orden-icon" class="d-none">
|
||||||
|
<i class="fas fa-file-alt fa-3x text-secondary"></i>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex-grow-1 overflow-hidden">
|
||||||
|
<div id="dom-orden-fname" class="small fw-semibold text-truncate"></div>
|
||||||
|
<div id="dom-orden-fsize" class="small text-muted"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="dom-orden-empty" class="small text-muted mb-2">
|
||||||
|
<i class="fas fa-paperclip me-1"></i> Sin orden adjunta
|
||||||
|
</div>
|
||||||
|
<div class="d-flex gap-2 flex-wrap align-items-center">
|
||||||
|
<label class="btn btn-sm btn-outline-primary mb-0" for="dom-orden-input">
|
||||||
|
<i class="fas fa-upload me-1"></i>
|
||||||
|
<span id="dom-orden-btn-lbl">Adjuntar orden</span>
|
||||||
|
</label>
|
||||||
|
<button type="button" class="btn btn-sm btn-outline-danger d-none" id="dom-orden-quitar"
|
||||||
|
onclick="domQuitarOrden()">
|
||||||
|
<i class="fas fa-times me-1"></i> Quitar
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<input type="file" id="dom-orden-input" class="d-none"
|
||||||
|
accept="image/jpeg,image/png,image/gif,image/webp,application/pdf,.pdf,.doc,.docx"
|
||||||
|
onchange="domSeleccionarOrdenFile(this)">
|
||||||
|
<small class="text-muted d-block mt-1">Imagen, PDF o DOC — máx. 10 MB</small>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- ── Notas ── -->
|
<!-- ── Notas ── -->
|
||||||
<div class="mb-2">
|
<div class="mb-2">
|
||||||
<label class="form-label">Notas internas</label>
|
<label class="form-label">Notas internas</label>
|
||||||
@@ -270,6 +308,93 @@ $domIdParam = (int)($_GET['id'] ?? 0);
|
|||||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
||||||
<script>
|
<script>
|
||||||
const modal = new bootstrap.Modal('#modalDomicilio');
|
const modal = new bootstrap.Modal('#modalDomicilio');
|
||||||
|
|
||||||
|
// ── Estado orden en el modal ───────────────────────────────────────────────
|
||||||
|
let _domOrderFile = null; // File pendiente de subir
|
||||||
|
let _domCurrentLocalFile = null; // local_file actual de la orden
|
||||||
|
let _domRemoveOrder = false; // el usuario quiere desvincularse de la orden
|
||||||
|
|
||||||
|
function _domResetOrden() {
|
||||||
|
_domOrderFile = null;
|
||||||
|
_domCurrentLocalFile = null;
|
||||||
|
_domRemoveOrder = false;
|
||||||
|
document.getElementById('dom-orden-id-form').value = '';
|
||||||
|
document.getElementById('dom-orden-input').value = '';
|
||||||
|
_domRenderOrdenPreview();
|
||||||
|
}
|
||||||
|
|
||||||
|
function _domRenderOrdenPreview() {
|
||||||
|
const preview = document.getElementById('dom-orden-preview');
|
||||||
|
const empty = document.getElementById('dom-orden-empty');
|
||||||
|
const img = document.getElementById('dom-orden-img');
|
||||||
|
const icon = document.getElementById('dom-orden-icon');
|
||||||
|
const fname = document.getElementById('dom-orden-fname');
|
||||||
|
const fsize = document.getElementById('dom-orden-fsize');
|
||||||
|
const btnQuitar = document.getElementById('dom-orden-quitar');
|
||||||
|
const btnLbl = document.getElementById('dom-orden-btn-lbl');
|
||||||
|
|
||||||
|
if (_domOrderFile) {
|
||||||
|
// Archivo local seleccionado aún no subido
|
||||||
|
const isImg = _domOrderFile.type.startsWith('image/');
|
||||||
|
if (isImg) {
|
||||||
|
img.src = URL.createObjectURL(_domOrderFile);
|
||||||
|
img.style.display = '';
|
||||||
|
icon.classList.add('d-none');
|
||||||
|
} else {
|
||||||
|
img.style.display = 'none';
|
||||||
|
icon.classList.remove('d-none');
|
||||||
|
}
|
||||||
|
fname.textContent = _domOrderFile.name;
|
||||||
|
fsize.textContent = (_domOrderFile.size / 1024).toFixed(1) + ' KB — pendiente de guardar';
|
||||||
|
preview.classList.remove('d-none');
|
||||||
|
empty.classList.add('d-none');
|
||||||
|
btnQuitar.classList.remove('d-none');
|
||||||
|
btnLbl.textContent = 'Cambiar archivo';
|
||||||
|
} else if (_domCurrentLocalFile && !_domRemoveOrder) {
|
||||||
|
// Archivo ya guardado en servidor
|
||||||
|
const isImg = /\.(jpe?g|png|gif|webp)$/i.test(_domCurrentLocalFile);
|
||||||
|
if (isImg) {
|
||||||
|
img.src = 'uploads/media/' + encodeURIComponent(_domCurrentLocalFile);
|
||||||
|
img.style.display = '';
|
||||||
|
icon.classList.add('d-none');
|
||||||
|
} else {
|
||||||
|
img.style.display = 'none';
|
||||||
|
icon.classList.remove('d-none');
|
||||||
|
}
|
||||||
|
fname.textContent = _domCurrentLocalFile;
|
||||||
|
fsize.textContent = 'Archivo guardado';
|
||||||
|
preview.classList.remove('d-none');
|
||||||
|
empty.classList.add('d-none');
|
||||||
|
btnQuitar.classList.remove('d-none');
|
||||||
|
btnLbl.textContent = 'Cambiar archivo';
|
||||||
|
} else {
|
||||||
|
preview.classList.add('d-none');
|
||||||
|
empty.classList.remove('d-none');
|
||||||
|
btnQuitar.classList.add('d-none');
|
||||||
|
btnLbl.textContent = 'Adjuntar orden';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function domSeleccionarOrdenFile(input) {
|
||||||
|
const file = input.files[0];
|
||||||
|
if (!file) return;
|
||||||
|
if (file.size > 10 * 1024 * 1024) {
|
||||||
|
alert('El archivo supera los 10 MB permitidos');
|
||||||
|
input.value = '';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_domOrderFile = file;
|
||||||
|
_domRemoveOrder = false;
|
||||||
|
_domRenderOrdenPreview();
|
||||||
|
}
|
||||||
|
|
||||||
|
function domQuitarOrden() {
|
||||||
|
_domOrderFile = null;
|
||||||
|
_domRemoveOrder = true;
|
||||||
|
document.getElementById('dom-orden-id-form').value = '';
|
||||||
|
document.getElementById('dom-orden-input').value = '';
|
||||||
|
_domRenderOrdenPreview();
|
||||||
|
}
|
||||||
const COLOR_DOM = { programado:'secondary', confirmado:'info', en_camino:'primary', en_domicilio:'warning', completado:'success', cancelado:'danger', reprogramado:'dark' };
|
const COLOR_DOM = { programado:'secondary', confirmado:'info', en_camino:'primary', en_domicilio:'warning', completado:'success', cancelado:'danger', reprogramado:'dark' };
|
||||||
let domSeleccionado = <?= $domIdParam ?: 'null' ?>;
|
let domSeleccionado = <?= $domIdParam ?: 'null' ?>;
|
||||||
let paginaActual = 1;
|
let paginaActual = 1;
|
||||||
@@ -547,6 +672,7 @@ function abrirFormulario() {
|
|||||||
document.getElementById('dom-fecha').value = document.getElementById('filtro-fecha').value || '<?= date('Y-m-d') ?>';
|
document.getElementById('dom-fecha').value = document.getElementById('filtro-fecha').value || '<?= date('Y-m-d') ?>';
|
||||||
document.getElementById('dom-tipo-cliente').value = 'particular';
|
document.getElementById('dom-tipo-cliente').value = 'particular';
|
||||||
toggleSeguro('particular');
|
toggleSeguro('particular');
|
||||||
|
_domResetOrden();
|
||||||
document.getElementById('modal-titulo').textContent = 'Nuevo Domicilio';
|
document.getElementById('modal-titulo').textContent = 'Nuevo Domicilio';
|
||||||
modal.show();
|
modal.show();
|
||||||
|
|
||||||
@@ -585,6 +711,13 @@ async function editarDomicilio(id) {
|
|||||||
document.getElementById('dom-valor-cop').value = dom.valor_copago || '';
|
document.getElementById('dom-valor-cop').value = dom.valor_copago || '';
|
||||||
document.getElementById('dom-copago-lab').value = dom.copago_laboratorio || '';
|
document.getElementById('dom-copago-lab').value = dom.copago_laboratorio || '';
|
||||||
document.getElementById('dom-notas').value = dom.notas_admin || '';
|
document.getElementById('dom-notas').value = dom.notas_admin || '';
|
||||||
|
|
||||||
|
// Orden médica adjunta
|
||||||
|
_domResetOrden();
|
||||||
|
document.getElementById('dom-orden-id-form').value = dom.orden_id || '';
|
||||||
|
_domCurrentLocalFile = dom.orden_local_file || null;
|
||||||
|
_domRenderOrdenPreview();
|
||||||
|
|
||||||
modal.show();
|
modal.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -596,11 +729,45 @@ function toggleSeguro(val) {
|
|||||||
async function guardarDomicilio() {
|
async function guardarDomicilio() {
|
||||||
const form = document.getElementById('form-domicilio');
|
const form = document.getElementById('form-domicilio');
|
||||||
if (!form.checkValidity()) { form.reportValidity(); return; }
|
if (!form.checkValidity()) { form.reportValidity(); return; }
|
||||||
if (!document.getElementById('dom-paciente-id').value) {
|
const pacienteId = document.getElementById('dom-paciente-id').value;
|
||||||
alert('Debes seleccionar un paciente'); return;
|
if (!pacienteId) { alert('Debes seleccionar un paciente'); return; }
|
||||||
}
|
|
||||||
const datos = Object.fromEntries(new FormData(form).entries());
|
const datos = Object.fromEntries(new FormData(form).entries());
|
||||||
if (!datos.id) delete datos.id;
|
if (!datos.id) delete datos.id;
|
||||||
|
// Tomar orden_id del campo oculto real (no el parámetro URL)
|
||||||
|
datos.orden_id = document.getElementById('dom-orden-id-form').value || null;
|
||||||
|
delete datos.orden_id_url;
|
||||||
|
|
||||||
|
// ── Gestión del archivo de orden médica ──────────────────────────────
|
||||||
|
if (_domRemoveOrder) {
|
||||||
|
datos.orden_id = null;
|
||||||
|
} else if (_domOrderFile) {
|
||||||
|
// Subir el archivo primero
|
||||||
|
const fd = new FormData();
|
||||||
|
fd.append('file', _domOrderFile);
|
||||||
|
const upR = await fetch('api/lab/upload_orden.php', { method:'POST', body: fd });
|
||||||
|
const upD = await upR.json();
|
||||||
|
if (!upD.success) {
|
||||||
|
mostrarToast('Error subiendo el archivo: ' + (upD.error || 'desconocido'), 'danger');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Actualizar o crear la orden médica
|
||||||
|
const orId = document.getElementById('dom-orden-id-form').value;
|
||||||
|
const orPayload = orId
|
||||||
|
? { id: parseInt(orId), local_file: upD.local_file }
|
||||||
|
: { paciente_id: parseInt(pacienteId), local_file: upD.local_file };
|
||||||
|
const orR = await fetch('api/lab/save_orden.php', {
|
||||||
|
method:'POST', headers:{'Content-Type':'application/json'},
|
||||||
|
body: JSON.stringify(orPayload),
|
||||||
|
});
|
||||||
|
const orD = await orR.json();
|
||||||
|
if (!orD.success) {
|
||||||
|
mostrarToast('Error guardando la orden: ' + (orD.error || 'desconocido'), 'danger');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
datos.orden_id = orD.id ?? orD.data?.id ?? (parseInt(orId) || null);
|
||||||
|
}
|
||||||
|
// ── Guardar domicilio ────────────────────────────────────────────────
|
||||||
if (!datos.orden_id) delete datos.orden_id;
|
if (!datos.orden_id) delete datos.orden_id;
|
||||||
|
|
||||||
const r = await fetch('api/lab/save_domicilio.php', {
|
const r = await fetch('api/lab/save_domicilio.php', {
|
||||||
@@ -611,7 +778,8 @@ async function guardarDomicilio() {
|
|||||||
if (d.success) {
|
if (d.success) {
|
||||||
modal.hide();
|
modal.hide();
|
||||||
mostrarToast(d.message, 'success');
|
mostrarToast(d.message, 'success');
|
||||||
const editadoId = datos.id ? parseInt(datos.id) : null;
|
const editadoId = datos.id ? parseInt(datos.id) : (d.id || null);
|
||||||
|
_domResetOrden();
|
||||||
await cargarLista(paginaActual);
|
await cargarLista(paginaActual);
|
||||||
if (editadoId) verDomicilio(editadoId);
|
if (editadoId) verDomicilio(editadoId);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
Reference in New Issue
Block a user