cambios finales
This commit is contained in:
parent
5844cfe523
commit
123fdf5d91
21
README.md
21
README.md
@ -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/
|
tar -xzf /opt/saludut/saludut-frontend.tar.gz -C /opt/saludut/
|
||||||
```
|
```
|
||||||
|
|
||||||
### 4) Inicializar esquema y datos
|
### 4) Inicializar esquema minimo
|
||||||
Primero genera el hash del admin y reemplaza `<HASH_BCRYPT>` en `backend/src/comandos.sql`:
|
Ejecuta el script minimo (schema + roles base):
|
||||||
```bash
|
```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):
|
El admin se crea automaticamente al iniciar el backend si defines
|
||||||
```bash
|
`ADMIN_USER` y `ADMIN_PASS` en el `.env`.
|
||||||
psql -U saludut_user -d saludut_db -f /opt/saludut/backend/src/setup.sql
|
|
||||||
```
|
|
||||||
|
|
||||||
Opcional: cargar datos masivos desde archivos:
|
Opcional: cargar datos masivos desde archivos:
|
||||||
```bash
|
```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
|
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)
|
### 5) Backend (.env)
|
||||||
Crear `backend/.env` en el servidor:
|
Crear `backend/.env` en el servidor:
|
||||||
```
|
```
|
||||||
@ -73,7 +78,7 @@ ADMIN_EMAIL=admin@saludut.gov.co
|
|||||||
ADMIN_NAME=Administrador Sistema
|
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.
|
Si defines `ADMIN_USER` y `ADMIN_PASS` en `.env`, el backend crea/actualiza el admin automaticamente al iniciar.
|
||||||
|
|
||||||
### 7) Backend (instalar y correr)
|
### 7) Backend (instalar y correr)
|
||||||
|
|||||||
10
backend/src/insert.sql
Normal file
10
backend/src/insert.sql
Normal 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;
|
||||||
@ -2755,7 +2755,17 @@ async function crearLibroAutorizacion(a) {
|
|||||||
if (nivelTexto) cupInfoParts.push(nivelTexto);
|
if (nivelTexto) cupInfoParts.push(nivelTexto);
|
||||||
const cupInfo = cupInfoParts.join(' - ');
|
const cupInfo = cupInfoParts.join(' - ');
|
||||||
const observacionBase = a.observacion || '';
|
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 => {
|
['H31','R31'].forEach(celda => {
|
||||||
sheet.getCell(celda).value = observacion;
|
sheet.getCell(celda).value = observacion;
|
||||||
});
|
});
|
||||||
|
|||||||
@ -3136,6 +3136,11 @@ app.get('/api/generar-excel-autorizaciones', async (req, res) => {
|
|||||||
|
|
||||||
// Agregar las filas a la hoja de trabajo
|
// Agregar las filas a la hoja de trabajo
|
||||||
rows.forEach(row => {
|
rows.forEach(row => {
|
||||||
|
const tipoServicio = row.tipo_servicio || (
|
||||||
|
String(row.tipo_autorizacion || '').toLowerCase() === 'consultas_externas'
|
||||||
|
? 'consulta externa'
|
||||||
|
: ''
|
||||||
|
);
|
||||||
worksheet.addRow({
|
worksheet.addRow({
|
||||||
numero_autorizacion: row.numero_autorizacion,
|
numero_autorizacion: row.numero_autorizacion,
|
||||||
version: row.version,
|
version: row.version,
|
||||||
@ -3144,7 +3149,7 @@ app.get('/api/generar-excel-autorizaciones', async (req, res) => {
|
|||||||
cup_codigo: row.cup_codigo,
|
cup_codigo: row.cup_codigo,
|
||||||
cup_nivel: row.cup_nivel,
|
cup_nivel: row.cup_nivel,
|
||||||
tipo_autorizacion: row.tipo_autorizacion,
|
tipo_autorizacion: row.tipo_autorizacion,
|
||||||
tipo_servicio: row.tipo_servicio,
|
tipo_servicio: tipoServicio,
|
||||||
nombre_ips: row.nombre_ips,
|
nombre_ips: row.nombre_ips,
|
||||||
fecha_autorizacion: row.fecha_autorizacion,
|
fecha_autorizacion: row.fecha_autorizacion,
|
||||||
observacion: row.observacion,
|
observacion: row.observacion,
|
||||||
|
|||||||
@ -182,49 +182,6 @@
|
|||||||
font-weight: 500;
|
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 {
|
.sede-badge {
|
||||||
background: var(--color-primary-soft);
|
background: var(--color-primary-soft);
|
||||||
|
|||||||
@ -232,39 +232,6 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Sedes asignadas (solo para administrativos) -->
|
<!-- 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>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
|||||||
@ -20,7 +20,6 @@ export class DashboardComponent implements OnInit, OnDestroy {
|
|||||||
currentUser: any = null;
|
currentUser: any = null;
|
||||||
errorMessage: string | null = null;
|
errorMessage: string | null = null;
|
||||||
private subscriptions: Subscription[] = [];
|
private subscriptions: Subscription[] = [];
|
||||||
mostrarTodasSedes = false;
|
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private authService: AuthService,
|
private authService: AuthService,
|
||||||
@ -184,26 +183,6 @@ export class DashboardComponent implements OnInit, OnDestroy {
|
|||||||
return this.authService.isLoggedIn();
|
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 {
|
cerrarMensajeError(): void {
|
||||||
this.errorMessage = null;
|
this.errorMessage = null;
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user