@softdin/portal-admin 0.0.0-stage → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +95 -2
- package/dist-lib/chunks/AppLayout-COCPfLWo.js +303 -0
- package/dist-lib/chunks/AuditoriaView-Bcf_kOqI.js +643 -0
- package/dist-lib/chunks/CarnetView-BsdUtYeu.js +450 -0
- package/dist-lib/chunks/CarteleraView-CRnVjt-S.js +996 -0
- package/dist-lib/chunks/CertificadosView-DvHDflcN.js +549 -0
- package/dist-lib/chunks/ChatBandejaView-HqhdSw7G.js +274 -0
- package/dist-lib/chunks/ChatConfiguracionView-BdH5gDdR.js +716 -0
- package/dist-lib/chunks/ChatConocimientoView-nKTAKxFa.js +263 -0
- package/dist-lib/chunks/ChatConversacionView-Do74V09l.js +477 -0
- package/dist-lib/chunks/ChatInformeView-BIiAH9L_.js +280 -0
- package/dist-lib/chunks/ChatRespuestasView-QFXbyg8U.js +183 -0
- package/dist-lib/chunks/EmpleadosView-BtqrO5-8.js +311 -0
- package/dist-lib/chunks/HomologacionView-UCZk4u6R.js +949 -0
- package/dist-lib/chunks/IngresoSsoView-BKkcnrYO.js +98 -0
- package/dist-lib/chunks/SolicitudesView-CYPD2A1s.js +900 -0
- package/dist-lib/chunks/TiposSolicitudView-CrWTVizl.js +168 -0
- package/dist-lib/chunks/ToggleSwitch-BYrIyheq.js +55 -0
- package/dist-lib/chunks/_plugin-vue_export-helper-BOaGB7Aw.js +8 -0
- package/dist-lib/chunks/api-M7D1c3IT.js +97 -0
- package/dist-lib/chunks/apiError-BHGbwz97.js +15 -0
- package/dist-lib/chunks/auth.store-BrGKZg-7.js +220 -0
- package/dist-lib/chunks/chat.service-C7ZQf4w3.js +241 -0
- package/dist-lib/chunks/cliente-interno.store-De39VsEE.js +203 -0
- package/dist-lib/chunks/homologacion-CoeHD7cB.js +131 -0
- package/dist-lib/chunks/portal-empleado-6KQrnsQJ.js +120 -0
- package/dist-lib/chunks/tipos-D93bLfFC.js +22 -0
- package/dist-lib/portal-admin.js +196 -0
- package/dist-lib/style.css +4813 -0
- package/dist-lib/types/App.vue.d.ts +3 -0
- package/dist-lib/types/components/AppLayout.vue.d.ts +3 -0
- package/dist-lib/types/components/CarnetClientesInternos.vue.d.ts +11 -0
- package/dist-lib/types/components/InvitacionPortalModal.vue.d.ts +20 -0
- package/dist-lib/types/components/MenuUsuario.vue.d.ts +3 -0
- package/dist-lib/types/components/VistoBuenoPortalModal.vue.d.ts +23 -0
- package/dist-lib/types/components/auditoria/AuditoriaFila.vue.d.ts +16 -0
- package/dist-lib/types/components/auditoria/AuditoriaFiltros.vue.d.ts +30 -0
- package/dist-lib/types/components/auditoria/AuditoriaPaginador.vue.d.ts +14 -0
- package/dist-lib/types/components/cartelera/PaginaCarteleraImagen.vue.d.ts +14 -0
- package/dist-lib/types/components/cartelera/PublicacionFormModal.vue.d.ts +27 -0
- package/dist-lib/types/components/cartelera/VistaCelularCartelera.vue.d.ts +34 -0
- package/dist-lib/types/components/certificados/AtenderCertificadoModal.vue.d.ts +22 -0
- package/dist-lib/types/components/certificados/RechazarCertificadoModal.vue.d.ts +18 -0
- package/dist-lib/types/components/certificados/ResumenSolicitudCertificado.vue.d.ts +8 -0
- package/dist-lib/types/components/chat/ChatClientesInternos.vue.d.ts +21 -0
- package/dist-lib/types/components/chat/ChatHorarioCampos.vue.d.ts +21 -0
- package/dist-lib/types/components/forms/ExportExcelButton.vue.d.ts +30 -0
- package/dist-lib/types/components/forms/ToggleSwitch.vue.d.ts +17 -0
- package/dist-lib/types/components/homologacion/HomologacionFila.vue.d.ts +30 -0
- package/dist-lib/types/components/homologacion/TipoPermisoFormModal.vue.d.ts +26 -0
- package/dist-lib/types/components/homologacion/TipoSolicitudFormModal.vue.d.ts +27 -0
- package/dist-lib/types/lib/auditoria.d.ts +25 -0
- package/dist-lib/types/lib/cartelera-paginas.d.ts +26 -0
- package/dist-lib/types/lib/cartelera-vigencia.d.ts +3 -0
- package/dist-lib/types/lib/export-excel-csv.d.ts +4 -0
- package/dist-lib/types/lib/export-excel.d.ts +9 -0
- package/dist-lib/types/lib/exportar-listado.d.ts +68 -0
- package/dist-lib/types/lib/homologacion.d.ts +41 -0
- package/dist-lib/types/lib/portal-empleado.d.ts +32 -0
- package/dist-lib/types/modulo.d.ts +31 -0
- package/dist-lib/types/portal-admin/config.d.ts +17 -0
- package/dist-lib/types/portal-admin/rutas.d.ts +17 -0
- package/dist-lib/types/portal-admin/tipos.d.ts +68 -0
- package/dist-lib/types/router/index.d.ts +7 -0
- package/dist-lib/types/services/api.d.ts +29 -0
- package/dist-lib/types/services/auditoria.service.d.ts +63 -0
- package/dist-lib/types/services/auth.service.d.ts +61 -0
- package/dist-lib/types/services/carnet.service.d.ts +56 -0
- package/dist-lib/types/services/cartelera.service.d.ts +69 -0
- package/dist-lib/types/services/chat.service.d.ts +279 -0
- package/dist-lib/types/services/configuracion-cliente-interno.service.d.ts +23 -0
- package/dist-lib/types/services/homologacion.service.d.ts +105 -0
- package/dist-lib/types/services/portal-empleado.service.d.ts +112 -0
- package/dist-lib/types/services/solicitudes-certificado.service.d.ts +59 -0
- package/dist-lib/types/stores/auth.store.d.ts +125 -0
- package/dist-lib/types/stores/cliente-interno.store.d.ts +65 -0
- package/dist-lib/types/utils/apiError.d.ts +4 -0
- package/dist-lib/types/views/AuditoriaView.vue.d.ts +3 -0
- package/dist-lib/types/views/CarnetView.vue.d.ts +3 -0
- package/dist-lib/types/views/CarteleraView.vue.d.ts +3 -0
- package/dist-lib/types/views/CertificadosView.vue.d.ts +3 -0
- package/dist-lib/types/views/EmpleadosView.vue.d.ts +3 -0
- package/dist-lib/types/views/HomologacionView.vue.d.ts +4 -0
- package/dist-lib/types/views/IngresoSsoView.vue.d.ts +3 -0
- package/dist-lib/types/views/LoginView.vue.d.ts +3 -0
- package/dist-lib/types/views/OlvideView.vue.d.ts +3 -0
- package/dist-lib/types/views/RestablecerView.vue.d.ts +3 -0
- package/dist-lib/types/views/SolicitudesView.vue.d.ts +3 -0
- package/dist-lib/types/views/TiposSolicitudView.vue.d.ts +3 -0
- package/dist-lib/types/views/chat/ChatBandejaView.vue.d.ts +3 -0
- package/dist-lib/types/views/chat/ChatConfiguracionView.vue.d.ts +3 -0
- package/dist-lib/types/views/chat/ChatConocimientoView.vue.d.ts +3 -0
- package/dist-lib/types/views/chat/ChatConversacionView.vue.d.ts +11 -0
- package/dist-lib/types/views/chat/ChatInformeView.vue.d.ts +3 -0
- package/dist-lib/types/views/chat/ChatRespuestasView.vue.d.ts +3 -0
- package/package.json +66 -4
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
import { t as api } from "./api-M7D1c3IT.js";
|
|
2
|
+
//#region src/services/chat.service.ts
|
|
3
|
+
/** Minutos hábiles → «45 min», «3 h 20 min». */
|
|
4
|
+
function duracion(min) {
|
|
5
|
+
if (min === null) return "—";
|
|
6
|
+
if (min < 60) return `${min} min`;
|
|
7
|
+
const h = Math.floor(min / 60);
|
|
8
|
+
const m = min % 60;
|
|
9
|
+
return m ? `${h} h ${m} min` : `${h} h`;
|
|
10
|
+
}
|
|
11
|
+
var chatService = {
|
|
12
|
+
async resumen() {
|
|
13
|
+
const { data } = await api.get("/chat/resumen");
|
|
14
|
+
return data.data;
|
|
15
|
+
},
|
|
16
|
+
async conversaciones(vista, temaId, clienteInternoId = null) {
|
|
17
|
+
const { data } = await api.get("/chat/conversaciones", { params: {
|
|
18
|
+
vista,
|
|
19
|
+
tema_id: temaId ?? void 0,
|
|
20
|
+
cliente_interno_id: clienteInternoId ?? void 0
|
|
21
|
+
} });
|
|
22
|
+
return data.data;
|
|
23
|
+
},
|
|
24
|
+
async conversacion(id) {
|
|
25
|
+
const { data } = await api.get(`/chat/conversaciones/${id}`);
|
|
26
|
+
return data.data;
|
|
27
|
+
},
|
|
28
|
+
async responder(id, cuerpo, interno) {
|
|
29
|
+
const { data } = await api.post(`/chat/conversaciones/${id}/mensajes`, {
|
|
30
|
+
cuerpo,
|
|
31
|
+
interno
|
|
32
|
+
});
|
|
33
|
+
return data.data;
|
|
34
|
+
},
|
|
35
|
+
async tomar(id) {
|
|
36
|
+
const { data } = await api.post(`/chat/conversaciones/${id}/tomar`);
|
|
37
|
+
return data.data;
|
|
38
|
+
},
|
|
39
|
+
async asignar(id, usuarioId) {
|
|
40
|
+
const { data } = await api.post(`/chat/conversaciones/${id}/asignar`, { usuario_id: usuarioId });
|
|
41
|
+
return data.data;
|
|
42
|
+
},
|
|
43
|
+
/** Devuelve null si, tras pasarla a otro tema, el usuario ya no la ve. */
|
|
44
|
+
async reasignar(id, cambio) {
|
|
45
|
+
const { data } = await api.post(`/chat/conversaciones/${id}/reasignar`, cambio);
|
|
46
|
+
return data.data;
|
|
47
|
+
},
|
|
48
|
+
async esperando(id) {
|
|
49
|
+
const { data } = await api.post(`/chat/conversaciones/${id}/esperando`);
|
|
50
|
+
return data.data;
|
|
51
|
+
},
|
|
52
|
+
async resolver(id, comentario) {
|
|
53
|
+
const { data } = await api.post(`/chat/conversaciones/${id}/resolver`, { comentario });
|
|
54
|
+
return data.data;
|
|
55
|
+
},
|
|
56
|
+
async configuracion() {
|
|
57
|
+
const { data } = await api.get("/chat/configuracion");
|
|
58
|
+
return data.data;
|
|
59
|
+
},
|
|
60
|
+
async guardarConfiguracion(c) {
|
|
61
|
+
const { clientes_internos: _, ...cuerpo } = c;
|
|
62
|
+
const { data } = await api.put("/chat/configuracion", cuerpo);
|
|
63
|
+
return data.data;
|
|
64
|
+
},
|
|
65
|
+
/** Ajuste propio de un cliente interno (solo admin). Responde la configuración completa. */
|
|
66
|
+
async ajustarClienteInterno(clienteInternoId, ajuste) {
|
|
67
|
+
const { data } = await api.put(`/chat/configuracion/clientes-internos/${clienteInternoId}`, {
|
|
68
|
+
activo: ajuste.activo,
|
|
69
|
+
horario: ajuste.horario,
|
|
70
|
+
mensaje_fuera_horario: ajuste.mensaje_fuera_horario
|
|
71
|
+
});
|
|
72
|
+
return data.data;
|
|
73
|
+
},
|
|
74
|
+
/** Quita el ajuste: el cliente interno vuelve a lo general. */
|
|
75
|
+
async heredarClienteInterno(clienteInternoId) {
|
|
76
|
+
const { data } = await api.delete(`/chat/configuracion/clientes-internos/${clienteInternoId}`);
|
|
77
|
+
return data.data;
|
|
78
|
+
},
|
|
79
|
+
async temas() {
|
|
80
|
+
const { data } = await api.get("/chat/temas");
|
|
81
|
+
return data.data;
|
|
82
|
+
},
|
|
83
|
+
async crearTema(t) {
|
|
84
|
+
const { data } = await api.post("/chat/temas", t);
|
|
85
|
+
return data.data;
|
|
86
|
+
},
|
|
87
|
+
async actualizarTema(id, t) {
|
|
88
|
+
const { data } = await api.patch(`/chat/temas/${id}`, t);
|
|
89
|
+
return data.data;
|
|
90
|
+
},
|
|
91
|
+
async personas() {
|
|
92
|
+
const { data } = await api.get("/chat/personas");
|
|
93
|
+
return data.data;
|
|
94
|
+
},
|
|
95
|
+
async actualizarPersona(id, p) {
|
|
96
|
+
const { data } = await api.put(`/chat/personas/${id}`, p);
|
|
97
|
+
return data.data;
|
|
98
|
+
},
|
|
99
|
+
/** El propio usuario: disponible o no para la asignación automática. */
|
|
100
|
+
async marcarDisponible(disponible) {
|
|
101
|
+
await api.put("/chat/disponible", { disponible });
|
|
102
|
+
},
|
|
103
|
+
async respuestas() {
|
|
104
|
+
const { data } = await api.get("/chat/respuestas");
|
|
105
|
+
return data.data;
|
|
106
|
+
},
|
|
107
|
+
async guardarRespuesta(r) {
|
|
108
|
+
const cuerpo = {
|
|
109
|
+
titulo: r.titulo,
|
|
110
|
+
cuerpo: r.cuerpo,
|
|
111
|
+
tema_id: r.tema_id ?? null
|
|
112
|
+
};
|
|
113
|
+
const { data } = r.id ? await api.patch(`/chat/respuestas/${r.id}`, cuerpo) : await api.post("/chat/respuestas", cuerpo);
|
|
114
|
+
return data.data;
|
|
115
|
+
},
|
|
116
|
+
async borrarRespuesta(id) {
|
|
117
|
+
await api.delete(`/chat/respuestas/${id}`);
|
|
118
|
+
},
|
|
119
|
+
/** Con `clienteInternoId`, solo las conversaciones de los empleados de ese cliente interno. */
|
|
120
|
+
async informe(desde, hasta, clienteInternoId = null) {
|
|
121
|
+
const { data } = await api.get("/chat/informe", { params: {
|
|
122
|
+
desde,
|
|
123
|
+
hasta,
|
|
124
|
+
cliente_interno_id: clienteInternoId ?? void 0
|
|
125
|
+
} });
|
|
126
|
+
return data.data;
|
|
127
|
+
},
|
|
128
|
+
/** Con `clienteInternoId`, los generales más los de ese cliente; sin él, todos. */
|
|
129
|
+
async conocimiento(clienteInternoId = null) {
|
|
130
|
+
const { data } = await api.get("/chat/conocimiento", { params: { cliente_interno_id: clienteInternoId ?? void 0 } });
|
|
131
|
+
return data.data;
|
|
132
|
+
},
|
|
133
|
+
async guardarArticulo(a) {
|
|
134
|
+
const cuerpo = {
|
|
135
|
+
titulo: a.titulo,
|
|
136
|
+
contenido: a.contenido,
|
|
137
|
+
tema_id: a.tema_id ?? null,
|
|
138
|
+
cliente_interno_id: a.cliente_interno_id ?? null,
|
|
139
|
+
visible_en_faq: a.visible_en_faq,
|
|
140
|
+
activo: a.activo
|
|
141
|
+
};
|
|
142
|
+
const { data } = a.id ? await api.patch(`/chat/conocimiento/${a.id}`, cuerpo) : await api.post("/chat/conocimiento", cuerpo);
|
|
143
|
+
return data.data;
|
|
144
|
+
},
|
|
145
|
+
async borrarArticulo(id) {
|
|
146
|
+
await api.delete(`/chat/conocimiento/${id}`);
|
|
147
|
+
}
|
|
148
|
+
};
|
|
149
|
+
var ESTADOS_CONVERSACION = {
|
|
150
|
+
ia: {
|
|
151
|
+
texto: "Con el asistente",
|
|
152
|
+
clase: "estado-info"
|
|
153
|
+
},
|
|
154
|
+
resuelta_ia: {
|
|
155
|
+
texto: "Resuelta por el asistente",
|
|
156
|
+
clase: "estado-ok"
|
|
157
|
+
},
|
|
158
|
+
sin_asignar: {
|
|
159
|
+
texto: "Sin asignar",
|
|
160
|
+
clase: "estado-alerta"
|
|
161
|
+
},
|
|
162
|
+
asignada: {
|
|
163
|
+
texto: "Asignada",
|
|
164
|
+
clase: "estado-info"
|
|
165
|
+
},
|
|
166
|
+
esperando_empleado: {
|
|
167
|
+
texto: "Esperando al empleado",
|
|
168
|
+
clase: "estado-neutro"
|
|
169
|
+
},
|
|
170
|
+
resuelta: {
|
|
171
|
+
texto: "Resuelta",
|
|
172
|
+
clase: "estado-ok"
|
|
173
|
+
},
|
|
174
|
+
cerrada: {
|
|
175
|
+
texto: "Cerrada",
|
|
176
|
+
clase: "estado-neutro"
|
|
177
|
+
}
|
|
178
|
+
};
|
|
179
|
+
var MOTIVOS_ESCALAMIENTO = {
|
|
180
|
+
empleado_pidio: "El empleado pidió hablar con una persona",
|
|
181
|
+
ia_no_sabe: "El asistente no tenía la respuesta",
|
|
182
|
+
insatisfaccion: "El empleado no quedó satisfecho con el asistente",
|
|
183
|
+
tema_sensible: "Tema sensible: el asistente no leyó el mensaje",
|
|
184
|
+
decision: "Pide algo que una persona debe decidir",
|
|
185
|
+
ia_no_disponible: "Consulta directa a RRHH"
|
|
186
|
+
};
|
|
187
|
+
/** Días del horario de atención: 1 = lunes … 7 = domingo. */
|
|
188
|
+
var DIAS_SEMANA = [
|
|
189
|
+
{
|
|
190
|
+
n: 1,
|
|
191
|
+
texto: "Lun"
|
|
192
|
+
},
|
|
193
|
+
{
|
|
194
|
+
n: 2,
|
|
195
|
+
texto: "Mar"
|
|
196
|
+
},
|
|
197
|
+
{
|
|
198
|
+
n: 3,
|
|
199
|
+
texto: "Mié"
|
|
200
|
+
},
|
|
201
|
+
{
|
|
202
|
+
n: 4,
|
|
203
|
+
texto: "Jue"
|
|
204
|
+
},
|
|
205
|
+
{
|
|
206
|
+
n: 5,
|
|
207
|
+
texto: "Vie"
|
|
208
|
+
},
|
|
209
|
+
{
|
|
210
|
+
n: 6,
|
|
211
|
+
texto: "Sáb"
|
|
212
|
+
},
|
|
213
|
+
{
|
|
214
|
+
n: 7,
|
|
215
|
+
texto: "Dom"
|
|
216
|
+
}
|
|
217
|
+
];
|
|
218
|
+
/** «Lun, Mar, Mié · 08:00–17:00». */
|
|
219
|
+
function textoHorario(h) {
|
|
220
|
+
return `${DIAS_SEMANA.filter((d) => h.dias.includes(d.n)).map((d) => d.texto).join(", ") || "Ningún día"} · ${h.desde}–${h.hasta}`;
|
|
221
|
+
}
|
|
222
|
+
/** Fecha y hora cortas en la zona del navegador. */
|
|
223
|
+
function fechaHora(iso) {
|
|
224
|
+
if (!iso) return "—";
|
|
225
|
+
return new Date(iso).toLocaleString("es-CO", {
|
|
226
|
+
day: "numeric",
|
|
227
|
+
month: "short",
|
|
228
|
+
hour: "numeric",
|
|
229
|
+
minute: "2-digit"
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
/** «en 2 h», «hace 35 min»: para el plazo de respuesta. */
|
|
233
|
+
function relativo(iso, ahora = Date.now()) {
|
|
234
|
+
if (!iso) return "—";
|
|
235
|
+
const min = Math.round((new Date(iso).getTime() - ahora) / 6e4);
|
|
236
|
+
const abs = Math.abs(min);
|
|
237
|
+
const texto = abs < 60 ? `${abs} min` : abs < 2880 ? `${Math.round(abs / 60)} h` : `${Math.round(abs / 1440)} días`;
|
|
238
|
+
return min >= 0 ? `en ${texto}` : `hace ${texto}`;
|
|
239
|
+
}
|
|
240
|
+
//#endregion
|
|
241
|
+
export { duracion as a, textoHorario as c, chatService as i, ESTADOS_CONVERSACION as n, fechaHora as o, MOTIVOS_ESCALAMIENTO as r, relativo as s, DIAS_SEMANA as t };
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
import { t as api } from "./api-M7D1c3IT.js";
|
|
2
|
+
import { t as useAuthStore } from "./auth.store-BrGKZg-7.js";
|
|
3
|
+
import { defineStore } from "pinia";
|
|
4
|
+
import { computed, ref, watch } from "vue";
|
|
5
|
+
//#region src/services/portal-empleado.service.ts
|
|
6
|
+
var portalSolicitudesService = {
|
|
7
|
+
/** Con `clienteInterno`, solo las de los empleados de ese cliente interno; sin él, todo el tenant. */
|
|
8
|
+
async listar(estado, clienteInterno = null) {
|
|
9
|
+
const params = {};
|
|
10
|
+
if (estado) params.estado = estado;
|
|
11
|
+
if (clienteInterno !== null) params.cliente_interno_id = clienteInterno;
|
|
12
|
+
const { data } = await api.get("/solicitudes", { params });
|
|
13
|
+
return data.data;
|
|
14
|
+
},
|
|
15
|
+
/**
|
|
16
|
+
* Viaja firmado a SoftDIN, donde vive la novedad: al aprobar se activa; al no
|
|
17
|
+
* aprobar queda inactiva y el comentario le llega al empleado.
|
|
18
|
+
*/
|
|
19
|
+
async vistoBueno(id, aprueba, comentario) {
|
|
20
|
+
await api.post(`/solicitudes/${id}/visto-bueno`, {
|
|
21
|
+
aprueba,
|
|
22
|
+
comentario
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* `id` es siempre el del tipo del tenant. Con `clienteInterno`, se ve y se cambia lo de los
|
|
28
|
+
* empleados de ese cliente interno: cambiarlo le crea su propia configuración, que prevalece.
|
|
29
|
+
*/
|
|
30
|
+
var portalTiposService = {
|
|
31
|
+
async listar(clienteInterno = null) {
|
|
32
|
+
const params = clienteInterno === null ? {} : { cliente_interno_id: clienteInterno };
|
|
33
|
+
const { data } = await api.get("/tipos-solicitud", { params });
|
|
34
|
+
return data.data;
|
|
35
|
+
},
|
|
36
|
+
async actualizar(id, cambios, clienteInterno = null) {
|
|
37
|
+
const cuerpo = clienteInterno === null ? cambios : {
|
|
38
|
+
...cambios,
|
|
39
|
+
cliente_interno_id: clienteInterno
|
|
40
|
+
};
|
|
41
|
+
const { data } = await api.patch(`/tipos-solicitud/${id}`, cuerpo);
|
|
42
|
+
return data.data;
|
|
43
|
+
},
|
|
44
|
+
/** El cliente interno vuelve a usar lo de todo el tenant para este tipo. */
|
|
45
|
+
async heredar(id, clienteInterno) {
|
|
46
|
+
const { data } = await api.delete(`/tipos-solicitud/${id}/cliente-interno/${clienteInterno}`);
|
|
47
|
+
return data.data;
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
var portalEmpleadosService = {
|
|
51
|
+
/** Empleados que SoftDIN publicó al portal; busca por nombre o documento (máximo 100). */
|
|
52
|
+
async buscar(buscar, clienteInterno = null) {
|
|
53
|
+
const params = {};
|
|
54
|
+
if (buscar.trim()) params.buscar = buscar.trim();
|
|
55
|
+
if (clienteInterno !== null) params.cliente_interno = clienteInterno;
|
|
56
|
+
const { data } = await api.get("/empleados", { params });
|
|
57
|
+
return data.data;
|
|
58
|
+
},
|
|
59
|
+
/** Catálogo de clientes internos del tenant que envió SoftDIN (también los que aún no tienen empleados). */
|
|
60
|
+
async clientesInternos() {
|
|
61
|
+
const { data } = await api.get("/clientes-internos");
|
|
62
|
+
return data.data;
|
|
63
|
+
},
|
|
64
|
+
async invitar(empleoId, canal) {
|
|
65
|
+
const { data } = await api.post(`/empleados/${empleoId}/invitacion`, { canal });
|
|
66
|
+
return data.data;
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
//#endregion
|
|
70
|
+
//#region src/stores/cliente-interno.store.ts
|
|
71
|
+
/**
|
|
72
|
+
* Cliente interno elegido en la barra superior: un solo selector para todas las pestañas.
|
|
73
|
+
* `null` = «Todo el tenant». La lista es el catálogo de clientes internos que SoftDIN envió
|
|
74
|
+
* al tenant (también los que aún no tienen empleados). La elección se recuerda por tenant en
|
|
75
|
+
* este navegador; si el cliente guardado ya no está en la lista, se vuelve a todo el tenant.
|
|
76
|
+
*
|
|
77
|
+
* Con alcance por cliente (SSO desde softdin-tenant, `auth.clientesInternos` con lista) el
|
|
78
|
+
* selector ofrece solo los permitidos y no «Todo el tenant»: la elección es siempre uno de
|
|
79
|
+
* ellos. `lista` sigue siendo el catálogo completo, para poner nombre a lo que se consulta.
|
|
80
|
+
*/
|
|
81
|
+
var PREFIJO = "softdin_portal_tenant_cliente_interno_";
|
|
82
|
+
function leerGuardado(tenant) {
|
|
83
|
+
try {
|
|
84
|
+
const crudo = localStorage.getItem(PREFIJO + tenant);
|
|
85
|
+
const id = crudo === null ? NaN : Number(crudo);
|
|
86
|
+
return Number.isInteger(id) && id > 0 ? id : null;
|
|
87
|
+
} catch {
|
|
88
|
+
return null;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
function guardar(tenant, id) {
|
|
92
|
+
try {
|
|
93
|
+
if (id === null) localStorage.removeItem(PREFIJO + tenant);
|
|
94
|
+
else localStorage.setItem(PREFIJO + tenant, String(id));
|
|
95
|
+
} catch {}
|
|
96
|
+
}
|
|
97
|
+
var useClienteInternoStore = defineStore("portal-cliente-interno", () => {
|
|
98
|
+
const auth = useAuthStore();
|
|
99
|
+
const lista = ref([]);
|
|
100
|
+
const cargada = ref(false);
|
|
101
|
+
/** Ids permitidos, o `null` sin restricción. */
|
|
102
|
+
const permitidos = computed(() => auth.clientesInternos ?? null);
|
|
103
|
+
/** Si el usuario solo puede trabajar en algunos clientes internos. */
|
|
104
|
+
const restringido = computed(() => permitidos.value !== null);
|
|
105
|
+
/**
|
|
106
|
+
* Restringido a ninguno (`clientes_internos: []`): puede consultar todo el tenant, pero no
|
|
107
|
+
* escribir en ningún cliente interno. El selector ofrece solo «Todo el tenant».
|
|
108
|
+
*/
|
|
109
|
+
const ninguno = computed(() => permitidos.value !== null && permitidos.value.length === 0);
|
|
110
|
+
/**
|
|
111
|
+
* Lo que ofrece el selector de la barra (sin «Todo el tenant», que lo pone la vista): los de
|
|
112
|
+
* `clientes_internos` y, además, ninguno que `GET rrhh/clientes-internos` marque `permitido: false`.
|
|
113
|
+
*/
|
|
114
|
+
const opciones = computed(() => {
|
|
115
|
+
const ids = permitidos.value;
|
|
116
|
+
return lista.value.filter((c) => c.permitido !== false && (ids === null || ids.includes(c.id)));
|
|
117
|
+
});
|
|
118
|
+
/**
|
|
119
|
+
* La elección válida más parecida a `id`: sin restricción, `id` si está en la lista (o
|
|
120
|
+
* mientras la lista no llega) y si no `null`; con restricción, `id` si es de los permitidos
|
|
121
|
+
* y si no el primero de ellos.
|
|
122
|
+
*/
|
|
123
|
+
function validar(id) {
|
|
124
|
+
const ids = permitidos.value;
|
|
125
|
+
if (ids === null) {
|
|
126
|
+
if (id === null) return null;
|
|
127
|
+
return !cargada.value || opciones.value.some((c) => c.id === id) ? id : null;
|
|
128
|
+
}
|
|
129
|
+
const candidatos = cargada.value ? opciones.value.map((c) => c.id) : ids;
|
|
130
|
+
return id !== null && candidatos.includes(id) ? id : candidatos[0] ?? null;
|
|
131
|
+
}
|
|
132
|
+
const seleccionado = ref(validar(auth.cliente ? leerGuardado(auth.cliente.id) : null));
|
|
133
|
+
/** Tenant de la lista cargada (o en camino). */
|
|
134
|
+
let tenantCargado = null;
|
|
135
|
+
let enCurso = null;
|
|
136
|
+
/** Carga la lista del tenant de la sesión; una sola vez por tenant salvo `forzar`. */
|
|
137
|
+
function cargar(forzar = false) {
|
|
138
|
+
const tenant = auth.cliente?.id ?? null;
|
|
139
|
+
if (tenant === null) {
|
|
140
|
+
reiniciar();
|
|
141
|
+
return Promise.resolve();
|
|
142
|
+
}
|
|
143
|
+
if (!forzar && tenantCargado === tenant) return enCurso ?? Promise.resolve();
|
|
144
|
+
tenantCargado = tenant;
|
|
145
|
+
const promesa = (async () => {
|
|
146
|
+
let nueva = [];
|
|
147
|
+
try {
|
|
148
|
+
nueva = await portalEmpleadosService.clientesInternos();
|
|
149
|
+
} catch {}
|
|
150
|
+
if (auth.cliente?.id !== tenant) return;
|
|
151
|
+
lista.value = nueva;
|
|
152
|
+
cargada.value = true;
|
|
153
|
+
seleccionado.value = validar(leerGuardado(tenant));
|
|
154
|
+
})();
|
|
155
|
+
enCurso = promesa;
|
|
156
|
+
promesa.finally(() => {
|
|
157
|
+
if (enCurso === promesa) enCurso = null;
|
|
158
|
+
});
|
|
159
|
+
return promesa;
|
|
160
|
+
}
|
|
161
|
+
/** Cambia la elección (null = todo el tenant) y la recuerda para este tenant. */
|
|
162
|
+
function elegir(id) {
|
|
163
|
+
const valido = validar(id !== null && lista.value.some((c) => c.id === id) ? id : null);
|
|
164
|
+
seleccionado.value = valido;
|
|
165
|
+
if (auth.cliente) guardar(auth.cliente.id, valido);
|
|
166
|
+
}
|
|
167
|
+
function nombre(id) {
|
|
168
|
+
if (id == null) return "Todo el tenant";
|
|
169
|
+
return lista.value.find((c) => c.id === id)?.nombre ?? `Cliente ${id}`;
|
|
170
|
+
}
|
|
171
|
+
function reiniciar() {
|
|
172
|
+
lista.value = [];
|
|
173
|
+
seleccionado.value = null;
|
|
174
|
+
cargada.value = false;
|
|
175
|
+
tenantCargado = null;
|
|
176
|
+
enCurso = null;
|
|
177
|
+
}
|
|
178
|
+
watch(() => auth.cliente?.id ?? null, (tenant, antes) => {
|
|
179
|
+
if (tenant === antes) return;
|
|
180
|
+
reiniciar();
|
|
181
|
+
if (tenant !== null) {
|
|
182
|
+
seleccionado.value = validar(leerGuardado(tenant));
|
|
183
|
+
cargar();
|
|
184
|
+
}
|
|
185
|
+
});
|
|
186
|
+
watch(() => permitidos.value === null ? null : permitidos.value.join(","), () => {
|
|
187
|
+
if (auth.cliente) seleccionado.value = validar(seleccionado.value);
|
|
188
|
+
});
|
|
189
|
+
return {
|
|
190
|
+
lista,
|
|
191
|
+
opciones,
|
|
192
|
+
restringido,
|
|
193
|
+
ninguno,
|
|
194
|
+
seleccionado,
|
|
195
|
+
cargada,
|
|
196
|
+
cargar,
|
|
197
|
+
elegir,
|
|
198
|
+
nombre,
|
|
199
|
+
reiniciar
|
|
200
|
+
};
|
|
201
|
+
});
|
|
202
|
+
//#endregion
|
|
203
|
+
export { portalTiposService as i, portalEmpleadosService as n, portalSolicitudesService as r, useClienteInternoStore as t };
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
//#region src/lib/homologacion.ts
|
|
2
|
+
/** Grupos de la pantalla «Homologación», en el orden en que se muestran. */
|
|
3
|
+
var GRUPOS_HOMOLOGACION = [
|
|
4
|
+
{
|
|
5
|
+
grupo: "incapacidad",
|
|
6
|
+
titulo: "Incapacidad"
|
|
7
|
+
},
|
|
8
|
+
{
|
|
9
|
+
grupo: "licencia",
|
|
10
|
+
titulo: "Licencias"
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
grupo: "vacaciones",
|
|
14
|
+
titulo: "Vacaciones"
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
grupo: "permiso",
|
|
18
|
+
titulo: "Permisos"
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
grupo: "tipo",
|
|
22
|
+
titulo: "Tipos de solicitud nuevos"
|
|
23
|
+
}
|
|
24
|
+
];
|
|
25
|
+
/** Siglas de las variables que exige la PILA para lo del portal (softdin/servicio, `EnumVariablesSistema`). */
|
|
26
|
+
var SIGLAS_VARIABLE = {
|
|
27
|
+
45: "IGE",
|
|
28
|
+
46: "IRP",
|
|
29
|
+
47: "LMA",
|
|
30
|
+
48: "SLN",
|
|
31
|
+
106: "LRM",
|
|
32
|
+
134: "LPA"
|
|
33
|
+
};
|
|
34
|
+
/** `IGE (45)`; si no es una de las conocidas, el nombre que mande SoftDIN con algún concepto de esa variable. */
|
|
35
|
+
function nombreVariable(variable, conceptos = []) {
|
|
36
|
+
if (variable === null || variable === void 0) return "—";
|
|
37
|
+
const sigla = SIGLAS_VARIABLE[variable] ?? conceptos.find((c) => c.variable === variable)?.variable_nombre;
|
|
38
|
+
return sigla ? `${sigla} (${variable})` : `Variable ${variable}`;
|
|
39
|
+
}
|
|
40
|
+
/** Texto del concepto en el combo: código – nombre – variable. */
|
|
41
|
+
function textoConcepto(c, conceptos = []) {
|
|
42
|
+
const variable = c.variable_nombre ?? (c.variable !== null ? nombreVariable(c.variable, conceptos) : null);
|
|
43
|
+
return [
|
|
44
|
+
c.codigo,
|
|
45
|
+
c.nombre,
|
|
46
|
+
variable
|
|
47
|
+
].filter((x) => x !== null && x !== "").join(" – ");
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Aviso (no bloquea) cuando el concepto elegido no liquida con la variable que exige la PILA para la fila, p. ej. una
|
|
51
|
+
* incapacidad laboral (IRP) homologada con un concepto IGE. SoftDIN guarda la misma advertencia al guardar.
|
|
52
|
+
*/
|
|
53
|
+
function avisoVariable(fila, concepto, conceptos = []) {
|
|
54
|
+
if (!concepto || fila.variable_esperada === null || fila.variable_esperada === void 0) return null;
|
|
55
|
+
if (concepto.variable !== null && Number(concepto.variable) === Number(fila.variable_esperada)) return null;
|
|
56
|
+
const tiene = concepto.variable === null ? "no tiene variable de la PILA" : `liquida como ${nombreVariable(concepto.variable, conceptos)}`;
|
|
57
|
+
return `«${concepto.codigo} – ${concepto.nombre}» ${tiene}, pero la PILA espera ${nombreVariable(fila.variable_esperada, conceptos)} para «${fila.nombre}». Se puede guardar: queda la advertencia en SoftDIN.`;
|
|
58
|
+
}
|
|
59
|
+
/** Los tipos de solicitud que crea el administrador del portal llevan el prefijo `t_`. */
|
|
60
|
+
function esTipoNuevo(tipo) {
|
|
61
|
+
return tipo.startsWith("t_");
|
|
62
|
+
}
|
|
63
|
+
function tipoDeClave(clave) {
|
|
64
|
+
return clave.startsWith("tipo:") ? clave.slice(5) : null;
|
|
65
|
+
}
|
|
66
|
+
/** Cuándo pide soporte un tipo de solicitud nuevo, para las tablas. */
|
|
67
|
+
function soporteDeTipoNuevo(t) {
|
|
68
|
+
if (!t.requiere_soporte) return "Sin soporte";
|
|
69
|
+
if (t.plazo_soporte_dias === null || t.plazo_soporte_dias === void 0) return "Soporte obligatorio al radicar";
|
|
70
|
+
return `Soporte: al radicar o dentro de los ${t.plazo_soporte_dias} días siguientes`;
|
|
71
|
+
}
|
|
72
|
+
var UNIDADES_PERMISO = [
|
|
73
|
+
{
|
|
74
|
+
valor: "horas",
|
|
75
|
+
texto: "Horas"
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
valor: "dias_habiles",
|
|
79
|
+
texto: "Días hábiles"
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
valor: "dias_calendario",
|
|
83
|
+
texto: "Días calendario"
|
|
84
|
+
}
|
|
85
|
+
];
|
|
86
|
+
var PERIODOS_TOPE = [
|
|
87
|
+
{
|
|
88
|
+
valor: "evento",
|
|
89
|
+
texto: "Por cada permiso"
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
valor: "dia",
|
|
93
|
+
texto: "Por día"
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
valor: "semestre",
|
|
97
|
+
texto: "Por semestre"
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
valor: "anio",
|
|
101
|
+
texto: "Por año"
|
|
102
|
+
}
|
|
103
|
+
];
|
|
104
|
+
/** Líneas de parentesco (Código Civil, arts. 35 a 50) y el grado máximo que se puede pedir en cada una. */
|
|
105
|
+
var LINEAS_PARENTESCO = [
|
|
106
|
+
{
|
|
107
|
+
linea: "consanguinidad",
|
|
108
|
+
texto: "Consanguinidad",
|
|
109
|
+
maximo: 4
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
linea: "afinidad",
|
|
113
|
+
texto: "Afinidad",
|
|
114
|
+
maximo: 2
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
linea: "civil",
|
|
118
|
+
texto: "Civil (adopción, crianza)",
|
|
119
|
+
maximo: 2
|
|
120
|
+
}
|
|
121
|
+
];
|
|
122
|
+
/**
|
|
123
|
+
* El permiso sale de la plantilla de la ley (tal cual o ajustado): se mejora, no se empeora, y solo se ajustan
|
|
124
|
+
* nombre, tope, soporte y si está activo. Los propios (del cliente o creados en el portal) se cambian completos.
|
|
125
|
+
*/
|
|
126
|
+
function esPermisoDeLey(p) {
|
|
127
|
+
if (p.origen) return p.origen !== "propio";
|
|
128
|
+
return p.legal === true;
|
|
129
|
+
}
|
|
130
|
+
//#endregion
|
|
131
|
+
export { avisoVariable as a, nombreVariable as c, tipoDeClave as d, UNIDADES_PERMISO as i, soporteDeTipoNuevo as l, LINEAS_PARENTESCO as n, esPermisoDeLey as o, PERIODOS_TOPE as r, esTipoNuevo as s, GRUPOS_HOMOLOGACION as t, textoConcepto as u };
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
//#region src/lib/portal-empleado.ts
|
|
2
|
+
/** Estado de una solicitud del portal, como lo ve nómina. */
|
|
3
|
+
var ESTADOS_SOLICITUD_PORTAL = {
|
|
4
|
+
recibida: {
|
|
5
|
+
texto: "Recibida",
|
|
6
|
+
clase: "estado-neutro"
|
|
7
|
+
},
|
|
8
|
+
en_aprobacion: {
|
|
9
|
+
texto: "En aprobación",
|
|
10
|
+
clase: "estado-espera"
|
|
11
|
+
},
|
|
12
|
+
pendiente_visto_bueno: {
|
|
13
|
+
texto: "Pendiente de visto bueno",
|
|
14
|
+
clase: "estado-espera"
|
|
15
|
+
},
|
|
16
|
+
aprobada: {
|
|
17
|
+
texto: "Aprobada",
|
|
18
|
+
clase: "estado-ok"
|
|
19
|
+
},
|
|
20
|
+
rechazada: {
|
|
21
|
+
texto: "Rechazada",
|
|
22
|
+
clase: "estado-error"
|
|
23
|
+
},
|
|
24
|
+
rechazada_nomina: {
|
|
25
|
+
texto: "Sin visto bueno de nómina",
|
|
26
|
+
clase: "estado-error"
|
|
27
|
+
},
|
|
28
|
+
cancelada: {
|
|
29
|
+
texto: "Cancelada por el empleado",
|
|
30
|
+
clase: "estado-neutro"
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
/** `2026-11-10` o `2026-11-10 00:00:00` → `10/11/2026`. */
|
|
34
|
+
function fechaCorta(valor) {
|
|
35
|
+
if (!valor) return "—";
|
|
36
|
+
const [a, m, d] = valor.slice(0, 10).split("-");
|
|
37
|
+
return a && m && d ? `${d}/${m}/${a}` : valor;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Novedad que SoftDIN crea al aprobar, por tipo. Es informativo: el empleado
|
|
41
|
+
* elige el concepto entre los que SoftDIN tiene configurados para su grupo de
|
|
42
|
+
* nómina, y la configuración vive allá.
|
|
43
|
+
*/
|
|
44
|
+
function conceptoDeTipo(tipo) {
|
|
45
|
+
switch (tipo) {
|
|
46
|
+
case "permiso": return "La del concepto que elige el empleado: licencia remunerada (LRM) o no remunerada (SLN) de su grupo de nómina";
|
|
47
|
+
case "licencia": return "Licencia no remunerada (SLN)";
|
|
48
|
+
case "vacaciones": return "Ninguna: se liquida en su propio formulario, con el concepto que eligió el empleado";
|
|
49
|
+
case "certificado": return "Ninguna: Recursos Humanos la atiende en Certificados adjuntando el PDF";
|
|
50
|
+
case "incapacidad": return "Incapacidad de origen común (IGE) o laboral (IRP), según indique el empleado; se crea al radicar, inactiva hasta el visto bueno";
|
|
51
|
+
case "licencia_maternidad": return "Licencia de maternidad (LMA); se crea al radicar, inactiva hasta el visto bueno";
|
|
52
|
+
case "licencia_paternidad": return "Licencia de paternidad (LPA); se crea al radicar, inactiva hasta el visto bueno";
|
|
53
|
+
default: return "—";
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
/** Nombre legible del tipo (el que trae el portal en minúsculas y con guion bajo). */
|
|
57
|
+
var NOMBRES_TIPO_SOLICITUD = {
|
|
58
|
+
vacaciones: "Vacaciones",
|
|
59
|
+
permiso: "Permiso",
|
|
60
|
+
licencia: "Licencia",
|
|
61
|
+
certificado: "Certificado",
|
|
62
|
+
incapacidad: "Incapacidad",
|
|
63
|
+
licencia_maternidad: "Licencia de maternidad",
|
|
64
|
+
licencia_paternidad: "Licencia de paternidad"
|
|
65
|
+
};
|
|
66
|
+
function nombreTipoSolicitud(tipo) {
|
|
67
|
+
return NOMBRES_TIPO_SOLICITUD[tipo] ?? tipo.charAt(0).toUpperCase() + tipo.slice(1).replace(/_/g, " ");
|
|
68
|
+
}
|
|
69
|
+
/** Incapacidad y licencias: llevan soporte (certificado médico, registro civil) que nómina revisa en SoftDIN. */
|
|
70
|
+
var TIPOS_CON_SOPORTE = [
|
|
71
|
+
"incapacidad",
|
|
72
|
+
"licencia_maternidad",
|
|
73
|
+
"licencia_paternidad"
|
|
74
|
+
];
|
|
75
|
+
function esTipoConSoporte(tipo) {
|
|
76
|
+
return TIPOS_CON_SOPORTE.includes(tipo);
|
|
77
|
+
}
|
|
78
|
+
/** Cuándo pide soporte el tipo, para la tabla de tipos (la regla vive en SoftDIN). */
|
|
79
|
+
function soporteDeTipo(tipo) {
|
|
80
|
+
if (tipo === "incapacidad") return "Certificado de incapacidad obligatorio al radicar";
|
|
81
|
+
if (tipo === "licencia_maternidad") return "Soporte obligatorio al radicar";
|
|
82
|
+
if (tipo === "licencia_paternidad") return "Registro civil: al radicar o dentro de los 30 días siguientes";
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Estado del soporte de una solicitud. El documento (dato de salud) está solo en SoftDIN, reservado en el
|
|
87
|
+
* expediente del empleado: aquí no se muestra ni se descarga.
|
|
88
|
+
*/
|
|
89
|
+
function estadoSoporte(s) {
|
|
90
|
+
if (!esTipoConSoporte(s.tipo)) return null;
|
|
91
|
+
if (s.tiene_soporte) return {
|
|
92
|
+
texto: "Soporte adjunto — ábralo en el expediente de SoftDIN",
|
|
93
|
+
pendiente: false
|
|
94
|
+
};
|
|
95
|
+
if (s.soporte_en_envio) return {
|
|
96
|
+
texto: "Enviando el soporte… llegará al expediente de SoftDIN",
|
|
97
|
+
pendiente: false
|
|
98
|
+
};
|
|
99
|
+
const dias = s.soporte_pendiente?.dias_restantes;
|
|
100
|
+
if (dias === null || dias === void 0) return {
|
|
101
|
+
texto: "Soporte pendiente",
|
|
102
|
+
pendiente: true
|
|
103
|
+
};
|
|
104
|
+
if (dias < 0) return {
|
|
105
|
+
texto: `Soporte pendiente (plazo vencido hace ${-dias} ${-dias === 1 ? "día" : "días"})`,
|
|
106
|
+
pendiente: true
|
|
107
|
+
};
|
|
108
|
+
return {
|
|
109
|
+
texto: `Soporte pendiente (${dias} ${dias === 1 ? "día" : "días"})`,
|
|
110
|
+
pendiente: true
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
/** Datos no clínicos de la incapacidad o licencia, en una línea. */
|
|
114
|
+
function datosNoClinicos(s) {
|
|
115
|
+
if (s.origen) return [s.origen === "laboral" ? "Origen laboral" : "Origen común", s.es_prorroga ? "Prórroga" : null].filter(Boolean).join(" · ");
|
|
116
|
+
if (s.fecha_parto) return `Parto: ${fechaCorta(s.fecha_parto)}`;
|
|
117
|
+
return null;
|
|
118
|
+
}
|
|
119
|
+
//#endregion
|
|
120
|
+
export { estadoSoporte as a, soporteDeTipo as c, esTipoConSoporte as i, conceptoDeTipo as n, fechaCorta as o, datosNoClinicos as r, nombreTipoSolicitud as s, ESTADOS_SOLICITUD_PORTAL as t };
|