cambios finales

This commit is contained in:
Jhonathan Guevara 2025-12-28 10:11:42 -05:00
parent 5844cfe523
commit 123fdf5d91
Signed by: jhonathan_guevara
GPG Key ID: 619239F12DCBE55B
7 changed files with 40 additions and 107 deletions

View File

@ -36,16 +36,14 @@ tar -xzf /opt/saludut/saludut-backend.tar.gz -C /opt/saludut/
tar -xzf /opt/saludut/saludut-frontend.tar.gz -C /opt/saludut/
```
### 4) Inicializar esquema y datos
Primero genera el hash del admin y reemplaza `<HASH_BCRYPT>` en `backend/src/comandos.sql`:
### 4) Inicializar esquema minimo
Ejecuta el script minimo (schema + roles base):
```bash
node /opt/saludut/backend/src/generate-hash.js
psql -U saludut_user -d saludut_db -f /opt/saludut/backend/src/insert.sql
```
Luego ejecuta el setup unico (esquema + CUPS + roles/admin):
```bash
psql -U saludut_user -d saludut_db -f /opt/saludut/backend/src/setup.sql
```
El admin se crea automaticamente al iniciar el backend si defines
`ADMIN_USER` y `ADMIN_PASS` en el `.env`.
Opcional: cargar datos masivos desde archivos:
```bash
@ -54,6 +52,13 @@ psql -U saludut_user -d saludut_db -f /opt/saludut/backend/src/paciente.sql
psql -U saludut_user -d saludut_db -f /opt/saludut/backend/src/ingreso.sql
```
Opcional (solo si quieres cargar CUPS por SQL y no por la UI):
```bash
psql -U saludut_user -d saludut_db -f /opt/saludut/backend/src/cups_schema.sql
psql -U saludut_user -d saludut_db -f /opt/saludut/backend/src/cups_referencia.sql
psql -U saludut_user -d saludut_db -f /opt/saludut/backend/src/cups_cubiertos.sql
```
### 5) Backend (.env)
Crear `backend/.env` en el servidor:
```
@ -73,7 +78,7 @@ ADMIN_EMAIL=admin@saludut.gov.co
ADMIN_NAME=Administrador Sistema
```
### 6) Crear usuario admin (manual)
### 6) Crear usuario admin (automatico)
Si defines `ADMIN_USER` y `ADMIN_PASS` en `.env`, el backend crea/actualiza el admin automaticamente al iniciar.
### 7) Backend (instalar y correr)

10
backend/src/insert.sql Normal file
View File

@ -0,0 +1,10 @@
\\set ON_ERROR_STOP on
\\i schema.sql
-- Roles base (minimo para funcionar)
INSERT INTO rol (nombre_rol, descripcion)
VALUES
('administrador', 'Puede cargar pacientes, descargar PDFs y ver todas las autorizaciones'),
('administrativo_sede', 'Solo puede generar autorizaciones para su sede')
ON CONFLICT (nombre_rol) DO NOTHING;

View File

@ -2755,7 +2755,17 @@ async function crearLibroAutorizacion(a) {
if (nivelTexto) cupInfoParts.push(nivelTexto);
const cupInfo = cupInfoParts.join(' - ');
const observacionBase = a.observacion || '';
const observacion = [cupInfo, observacionBase].filter(Boolean).join(' | ');
const tipoAutorizacion = (a.tipo_autorizacion || 'consultas_externas').toLowerCase();
const tipoServicioRaw = String(a.tipo_servicio || '').trim();
let tipoServicioTexto = '';
if (tipoServicioRaw) {
tipoServicioTexto = `Tipo servicio: ${tipoServicioRaw}`;
} else if (tipoAutorizacion === 'consultas_externas') {
tipoServicioTexto = 'Tipo servicio: Consulta externa';
}
const observacion = [cupInfo, tipoServicioTexto, observacionBase]
.filter(Boolean)
.join(' | ');
['H31','R31'].forEach(celda => {
sheet.getCell(celda).value = observacion;
});

View File

@ -3136,6 +3136,11 @@ app.get('/api/generar-excel-autorizaciones', async (req, res) => {
// Agregar las filas a la hoja de trabajo
rows.forEach(row => {
const tipoServicio = row.tipo_servicio || (
String(row.tipo_autorizacion || '').toLowerCase() === 'consultas_externas'
? 'consulta externa'
: ''
);
worksheet.addRow({
numero_autorizacion: row.numero_autorizacion,
version: row.version,
@ -3144,7 +3149,7 @@ app.get('/api/generar-excel-autorizaciones', async (req, res) => {
cup_codigo: row.cup_codigo,
cup_nivel: row.cup_nivel,
tipo_autorizacion: row.tipo_autorizacion,
tipo_servicio: row.tipo_servicio,
tipo_servicio: tipoServicio,
nombre_ips: row.nombre_ips,
fecha_autorizacion: row.fecha_autorizacion,
observacion: row.observacion,

View File

@ -182,49 +182,6 @@
font-weight: 500;
}
.sedes-list {
display: flex;
flex-wrap: wrap;
gap: 8px;
}
.sedes-info {
display: flex;
flex-direction: column;
gap: 8px;
width: 100%;
}
.sedes-meta {
display: flex;
align-items: center;
gap: 12px;
flex-wrap: wrap;
}
.sedes-count {
font-size: 0.85rem;
color: var(--color-text-muted);
font-weight: 500;
}
.sedes-toggle {
border: none;
background: transparent;
color: var(--color-primary);
font-weight: 600;
cursor: pointer;
padding: 0;
}
.sedes-toggle:hover {
text-decoration: underline;
}
.sedes-empty {
font-size: 0.85rem;
color: var(--color-text-muted);
}
.sede-badge {
background: var(--color-primary-soft);

View File

@ -232,39 +232,6 @@
</div>
<!-- Sedes asignadas (solo para administrativos) -->
<div
class="role-item"
*ngIf="currentUser.nombre_rol === 'administrativo_sede'"
>
<span class="role-label">Sedes asignadas:</span>
<div class="sedes-info">
<div class="sedes-meta" *ngIf="getSedesUsuario().length > 0">
<span class="sedes-count">
{{ getSedesUsuario().length }} sedes
</span>
<button
class="sedes-toggle"
*ngIf="getSedesUsuario().length > 8"
(click)="toggleSedesAsignadas()"
type="button"
>
{{ getTextoToggleSedes() }}
</button>
</div>
<div class="sedes-list" *ngIf="getSedesUsuario().length > 0; else sinSedes">
<span
class="sede-badge"
*ngFor="let sede of getSedesMostradas()"
[title]="sede.nombre_establecimiento"
>
{{ sede.nombre_establecimiento }}
</span>
</div>
<ng-template #sinSedes>
<span class="sedes-empty">Sin sedes asignadas</span>
</ng-template>
</div>
</div>
</div>
</section>

View File

@ -20,7 +20,6 @@ export class DashboardComponent implements OnInit, OnDestroy {
currentUser: any = null;
errorMessage: string | null = null;
private subscriptions: Subscription[] = [];
mostrarTodasSedes = false;
constructor(
private authService: AuthService,
@ -184,26 +183,6 @@ export class DashboardComponent implements OnInit, OnDestroy {
return this.authService.isLoggedIn();
}
getSedesUsuario(): any[] {
return this.currentUser?.sedes || [];
}
getSedesMostradas(): any[] {
const sedes = this.getSedesUsuario();
if (this.mostrarTodasSedes || sedes.length <= 8) {
return sedes;
}
return sedes.slice(0, 8);
}
toggleSedesAsignadas(): void {
this.mostrarTodasSedes = !this.mostrarTodasSedes;
}
getTextoToggleSedes(): string {
return this.mostrarTodasSedes ? 'Ocultar' : 'Ver todas';
}
cerrarMensajeError(): void {
this.errorMessage = null;
}