@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.
Files changed (96) hide show
  1. package/README.md +95 -2
  2. package/dist-lib/chunks/AppLayout-COCPfLWo.js +303 -0
  3. package/dist-lib/chunks/AuditoriaView-Bcf_kOqI.js +643 -0
  4. package/dist-lib/chunks/CarnetView-BsdUtYeu.js +450 -0
  5. package/dist-lib/chunks/CarteleraView-CRnVjt-S.js +996 -0
  6. package/dist-lib/chunks/CertificadosView-DvHDflcN.js +549 -0
  7. package/dist-lib/chunks/ChatBandejaView-HqhdSw7G.js +274 -0
  8. package/dist-lib/chunks/ChatConfiguracionView-BdH5gDdR.js +716 -0
  9. package/dist-lib/chunks/ChatConocimientoView-nKTAKxFa.js +263 -0
  10. package/dist-lib/chunks/ChatConversacionView-Do74V09l.js +477 -0
  11. package/dist-lib/chunks/ChatInformeView-BIiAH9L_.js +280 -0
  12. package/dist-lib/chunks/ChatRespuestasView-QFXbyg8U.js +183 -0
  13. package/dist-lib/chunks/EmpleadosView-BtqrO5-8.js +311 -0
  14. package/dist-lib/chunks/HomologacionView-UCZk4u6R.js +949 -0
  15. package/dist-lib/chunks/IngresoSsoView-BKkcnrYO.js +98 -0
  16. package/dist-lib/chunks/SolicitudesView-CYPD2A1s.js +900 -0
  17. package/dist-lib/chunks/TiposSolicitudView-CrWTVizl.js +168 -0
  18. package/dist-lib/chunks/ToggleSwitch-BYrIyheq.js +55 -0
  19. package/dist-lib/chunks/_plugin-vue_export-helper-BOaGB7Aw.js +8 -0
  20. package/dist-lib/chunks/api-M7D1c3IT.js +97 -0
  21. package/dist-lib/chunks/apiError-BHGbwz97.js +15 -0
  22. package/dist-lib/chunks/auth.store-BrGKZg-7.js +220 -0
  23. package/dist-lib/chunks/chat.service-C7ZQf4w3.js +241 -0
  24. package/dist-lib/chunks/cliente-interno.store-De39VsEE.js +203 -0
  25. package/dist-lib/chunks/homologacion-CoeHD7cB.js +131 -0
  26. package/dist-lib/chunks/portal-empleado-6KQrnsQJ.js +120 -0
  27. package/dist-lib/chunks/tipos-D93bLfFC.js +22 -0
  28. package/dist-lib/portal-admin.js +196 -0
  29. package/dist-lib/style.css +4813 -0
  30. package/dist-lib/types/App.vue.d.ts +3 -0
  31. package/dist-lib/types/components/AppLayout.vue.d.ts +3 -0
  32. package/dist-lib/types/components/CarnetClientesInternos.vue.d.ts +11 -0
  33. package/dist-lib/types/components/InvitacionPortalModal.vue.d.ts +20 -0
  34. package/dist-lib/types/components/MenuUsuario.vue.d.ts +3 -0
  35. package/dist-lib/types/components/VistoBuenoPortalModal.vue.d.ts +23 -0
  36. package/dist-lib/types/components/auditoria/AuditoriaFila.vue.d.ts +16 -0
  37. package/dist-lib/types/components/auditoria/AuditoriaFiltros.vue.d.ts +30 -0
  38. package/dist-lib/types/components/auditoria/AuditoriaPaginador.vue.d.ts +14 -0
  39. package/dist-lib/types/components/cartelera/PaginaCarteleraImagen.vue.d.ts +14 -0
  40. package/dist-lib/types/components/cartelera/PublicacionFormModal.vue.d.ts +27 -0
  41. package/dist-lib/types/components/cartelera/VistaCelularCartelera.vue.d.ts +34 -0
  42. package/dist-lib/types/components/certificados/AtenderCertificadoModal.vue.d.ts +22 -0
  43. package/dist-lib/types/components/certificados/RechazarCertificadoModal.vue.d.ts +18 -0
  44. package/dist-lib/types/components/certificados/ResumenSolicitudCertificado.vue.d.ts +8 -0
  45. package/dist-lib/types/components/chat/ChatClientesInternos.vue.d.ts +21 -0
  46. package/dist-lib/types/components/chat/ChatHorarioCampos.vue.d.ts +21 -0
  47. package/dist-lib/types/components/forms/ExportExcelButton.vue.d.ts +30 -0
  48. package/dist-lib/types/components/forms/ToggleSwitch.vue.d.ts +17 -0
  49. package/dist-lib/types/components/homologacion/HomologacionFila.vue.d.ts +30 -0
  50. package/dist-lib/types/components/homologacion/TipoPermisoFormModal.vue.d.ts +26 -0
  51. package/dist-lib/types/components/homologacion/TipoSolicitudFormModal.vue.d.ts +27 -0
  52. package/dist-lib/types/lib/auditoria.d.ts +25 -0
  53. package/dist-lib/types/lib/cartelera-paginas.d.ts +26 -0
  54. package/dist-lib/types/lib/cartelera-vigencia.d.ts +3 -0
  55. package/dist-lib/types/lib/export-excel-csv.d.ts +4 -0
  56. package/dist-lib/types/lib/export-excel.d.ts +9 -0
  57. package/dist-lib/types/lib/exportar-listado.d.ts +68 -0
  58. package/dist-lib/types/lib/homologacion.d.ts +41 -0
  59. package/dist-lib/types/lib/portal-empleado.d.ts +32 -0
  60. package/dist-lib/types/modulo.d.ts +31 -0
  61. package/dist-lib/types/portal-admin/config.d.ts +17 -0
  62. package/dist-lib/types/portal-admin/rutas.d.ts +17 -0
  63. package/dist-lib/types/portal-admin/tipos.d.ts +68 -0
  64. package/dist-lib/types/router/index.d.ts +7 -0
  65. package/dist-lib/types/services/api.d.ts +29 -0
  66. package/dist-lib/types/services/auditoria.service.d.ts +63 -0
  67. package/dist-lib/types/services/auth.service.d.ts +61 -0
  68. package/dist-lib/types/services/carnet.service.d.ts +56 -0
  69. package/dist-lib/types/services/cartelera.service.d.ts +69 -0
  70. package/dist-lib/types/services/chat.service.d.ts +279 -0
  71. package/dist-lib/types/services/configuracion-cliente-interno.service.d.ts +23 -0
  72. package/dist-lib/types/services/homologacion.service.d.ts +105 -0
  73. package/dist-lib/types/services/portal-empleado.service.d.ts +112 -0
  74. package/dist-lib/types/services/solicitudes-certificado.service.d.ts +59 -0
  75. package/dist-lib/types/stores/auth.store.d.ts +125 -0
  76. package/dist-lib/types/stores/cliente-interno.store.d.ts +65 -0
  77. package/dist-lib/types/utils/apiError.d.ts +4 -0
  78. package/dist-lib/types/views/AuditoriaView.vue.d.ts +3 -0
  79. package/dist-lib/types/views/CarnetView.vue.d.ts +3 -0
  80. package/dist-lib/types/views/CarteleraView.vue.d.ts +3 -0
  81. package/dist-lib/types/views/CertificadosView.vue.d.ts +3 -0
  82. package/dist-lib/types/views/EmpleadosView.vue.d.ts +3 -0
  83. package/dist-lib/types/views/HomologacionView.vue.d.ts +4 -0
  84. package/dist-lib/types/views/IngresoSsoView.vue.d.ts +3 -0
  85. package/dist-lib/types/views/LoginView.vue.d.ts +3 -0
  86. package/dist-lib/types/views/OlvideView.vue.d.ts +3 -0
  87. package/dist-lib/types/views/RestablecerView.vue.d.ts +3 -0
  88. package/dist-lib/types/views/SolicitudesView.vue.d.ts +3 -0
  89. package/dist-lib/types/views/TiposSolicitudView.vue.d.ts +3 -0
  90. package/dist-lib/types/views/chat/ChatBandejaView.vue.d.ts +3 -0
  91. package/dist-lib/types/views/chat/ChatConfiguracionView.vue.d.ts +3 -0
  92. package/dist-lib/types/views/chat/ChatConocimientoView.vue.d.ts +3 -0
  93. package/dist-lib/types/views/chat/ChatConversacionView.vue.d.ts +11 -0
  94. package/dist-lib/types/views/chat/ChatInformeView.vue.d.ts +3 -0
  95. package/dist-lib/types/views/chat/ChatRespuestasView.vue.d.ts +3 -0
  96. package/package.json +66 -4
@@ -0,0 +1,280 @@
1
+ import { t as useClienteInternoStore } from "./cliente-interno.store-De39VsEE.js";
2
+ import { t as RUTAS_PORTAL } from "./tipos-D93bLfFC.js";
3
+ import { t as _plugin_vue_export_helper_default } from "./_plugin-vue_export-helper-BOaGB7Aw.js";
4
+ import { a as duracion, i as chatService, r as MOTIVOS_ESCALAMIENTO } from "./chat.service-C7ZQf4w3.js";
5
+ import { t as mensajeError } from "./apiError-BHGbwz97.js";
6
+ import { Fragment, computed, createCommentVNode, createElementBlock, createElementVNode, createTextVNode, createVNode, defineComponent, onMounted, openBlock, ref, renderList, toDisplayString, unref, vModelText, watch, withCtx, withDirectives, withModifiers } from "vue";
7
+ import { RouterLink } from "vue-router";
8
+ //#region src/views/chat/ChatInformeView.vue?vue&type=script&setup=true&lang.ts
9
+ var _hoisted_1 = { class: "page-shell" };
10
+ var _hoisted_2 = { class: "page-subtitle" };
11
+ var _hoisted_3 = ["disabled"];
12
+ var _hoisted_4 = {
13
+ key: 0,
14
+ class: "panel-error",
15
+ role: "alert"
16
+ };
17
+ var _hoisted_5 = {
18
+ key: 1,
19
+ class: "panel-muted"
20
+ };
21
+ var _hoisted_6 = { class: "cifras" };
22
+ var _hoisted_7 = { class: "cifra-titulo" };
23
+ var _hoisted_8 = { class: "cifra-valor" };
24
+ var _hoisted_9 = { class: "panel-muted" };
25
+ var _hoisted_10 = {
26
+ key: 0,
27
+ class: "panel-error",
28
+ role: "alert"
29
+ };
30
+ var _hoisted_11 = { class: "columnas" };
31
+ var _hoisted_12 = { class: "panel" };
32
+ var _hoisted_13 = { class: "data-table" };
33
+ var _hoisted_14 = { class: "panel" };
34
+ var _hoisted_15 = {
35
+ key: 0,
36
+ class: "panel-muted"
37
+ };
38
+ var _hoisted_16 = {
39
+ key: 1,
40
+ class: "data-table"
41
+ };
42
+ var _hoisted_17 = { scope: "row" };
43
+ var _hoisted_18 = { class: "num" };
44
+ var _hoisted_19 = { class: "num" };
45
+ var _hoisted_20 = { class: "panel" };
46
+ var _hoisted_21 = { class: "table-wrap" };
47
+ var _hoisted_22 = { class: "data-table" };
48
+ var _hoisted_23 = { scope: "row" };
49
+ var _hoisted_24 = { class: "num" };
50
+ var _hoisted_25 = { class: "num" };
51
+ var _hoisted_26 = { class: "num" };
52
+ var _hoisted_27 = { class: "num" };
53
+ var _hoisted_28 = { key: 0 };
54
+ var _hoisted_29 = {
55
+ key: 1,
56
+ class: "panel"
57
+ };
58
+ var _hoisted_30 = { class: "table-wrap" };
59
+ var _hoisted_31 = { class: "data-table" };
60
+ var _hoisted_32 = { scope: "row" };
61
+ var _hoisted_33 = { class: "num" };
62
+ var _hoisted_34 = { class: "num" };
63
+ var _hoisted_35 = { class: "num" };
64
+ var _hoisted_36 = { class: "num" };
65
+ var _hoisted_37 = { key: 0 };
66
+ var _hoisted_38 = { class: "columnas" };
67
+ var _hoisted_39 = { class: "panel" };
68
+ var _hoisted_40 = { class: "data-table" };
69
+ var _hoisted_41 = { scope: "row" };
70
+ var _hoisted_42 = { class: "num" };
71
+ var _hoisted_43 = { class: "num" };
72
+ var _hoisted_44 = { class: "panel" };
73
+ var _hoisted_45 = { class: "data-table" };
74
+ var _hoisted_46 = { class: "num" };
75
+ var _hoisted_47 = { class: "num" };
76
+ var _hoisted_48 = { class: "num" };
77
+ var _hoisted_49 = { class: "num" };
78
+ //#endregion
79
+ //#region src/views/chat/ChatInformeView.vue
80
+ var ChatInformeView_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE__ */ defineComponent({
81
+ __name: "ChatInformeView",
82
+ setup(__props) {
83
+ const clientesInternos = useClienteInternoStore();
84
+ const hoy = /* @__PURE__ */ new Date();
85
+ const iso = (d) => `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}-${String(d.getDate()).padStart(2, "0")}`;
86
+ const hasta = ref(iso(hoy));
87
+ const desde = ref(iso(new Date(hoy.getFullYear(), hoy.getMonth(), hoy.getDate() - 29)));
88
+ const informe = ref(null);
89
+ const cargando = ref(true);
90
+ const error = ref(null);
91
+ const pct = (n, total) => total ? `${Math.round(n * 100 / total)} %` : "—";
92
+ const nota = (n) => n === null ? "—" : n.toLocaleString("es-CO", { maximumFractionDigits: 2 });
93
+ const tarjetas = computed(() => {
94
+ const i = informe.value;
95
+ if (!i) return [];
96
+ return [
97
+ {
98
+ titulo: "Conversaciones",
99
+ valor: String(i.total),
100
+ detalle: `${i.escaladas} pasaron a RRHH`
101
+ },
102
+ {
103
+ titulo: "Resueltas por el asistente",
104
+ valor: String(i.resueltas_por_ia),
105
+ detalle: pct(i.resueltas_por_ia, i.total) + " del total"
106
+ },
107
+ {
108
+ titulo: "Primera respuesta (mediana)",
109
+ valor: duracion(i.primera_respuesta.mediana),
110
+ detalle: i.primera_respuesta.dentro_del_plazo === null ? "sin respuestas en el rango" : `${i.primera_respuesta.dentro_del_plazo} % dentro del plazo`
111
+ },
112
+ {
113
+ titulo: "Calificación",
114
+ valor: i.calificacion.promedio === null ? "—" : `${nota(i.calificacion.promedio)} / 5`,
115
+ detalle: `${i.calificacion.respuestas} ${i.calificacion.respuestas === 1 ? "respuesta" : "respuestas"}`
116
+ }
117
+ ];
118
+ });
119
+ async function cargar() {
120
+ cargando.value = true;
121
+ error.value = null;
122
+ try {
123
+ informe.value = await chatService.informe(desde.value, hasta.value, clientesInternos.seleccionado);
124
+ } catch (e) {
125
+ error.value = mensajeError(e, "No se pudo calcular el informe.");
126
+ } finally {
127
+ cargando.value = false;
128
+ }
129
+ }
130
+ watch(() => clientesInternos.seleccionado, () => void cargar());
131
+ onMounted(() => void cargar());
132
+ return (_ctx, _cache) => {
133
+ return openBlock(), createElementBlock("section", _hoisted_1, [
134
+ createVNode(unref(RouterLink), {
135
+ to: { name: unref(RUTAS_PORTAL).chat },
136
+ class: "volver"
137
+ }, {
138
+ default: withCtx(() => [..._cache[2] || (_cache[2] = [createTextVNode("← Bandeja", -1)])]),
139
+ _: 1
140
+ }, 8, ["to"]),
141
+ createElementVNode("header", null, [_cache[5] || (_cache[5] = createElementVNode("h1", { class: "page-title" }, "Informe del chat", -1)), createElementVNode("p", _hoisted_2, [
142
+ _cache[3] || (_cache[3] = createTextVNode(" Conversaciones creadas en el rango, de los temas que usted ve", -1)),
143
+ unref(clientesInternos).seleccionado !== null ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [createTextVNode(" y de los empleados de " + toDisplayString(unref(clientesInternos).nombre(unref(clientesInternos).seleccionado)), 1)], 64)) : createCommentVNode("", true),
144
+ _cache[4] || (_cache[4] = createTextVNode(". Los tiempos se cuentan en horas hábiles, con el horario de atención y sin festivos. ", -1))
145
+ ])]),
146
+ createElementVNode("form", {
147
+ class: "toolbar",
148
+ onSubmit: withModifiers(cargar, ["prevent"])
149
+ }, [
150
+ _cache[6] || (_cache[6] = createElementVNode("label", {
151
+ for: "inf-desde",
152
+ class: "label"
153
+ }, "Desde", -1)),
154
+ withDirectives(createElementVNode("input", {
155
+ id: "inf-desde",
156
+ "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => desde.value = $event),
157
+ type: "date",
158
+ class: "input"
159
+ }, null, 512), [[vModelText, desde.value]]),
160
+ _cache[7] || (_cache[7] = createElementVNode("label", {
161
+ for: "inf-hasta",
162
+ class: "label"
163
+ }, "hasta", -1)),
164
+ withDirectives(createElementVNode("input", {
165
+ id: "inf-hasta",
166
+ "onUpdate:modelValue": _cache[1] || (_cache[1] = ($event) => hasta.value = $event),
167
+ type: "date",
168
+ class: "input"
169
+ }, null, 512), [[vModelText, hasta.value]]),
170
+ createElementVNode("button", {
171
+ type: "submit",
172
+ class: "btn-primary",
173
+ disabled: cargando.value
174
+ }, "Calcular", 8, _hoisted_3)
175
+ ], 32),
176
+ error.value ? (openBlock(), createElementBlock("p", _hoisted_4, toDisplayString(error.value), 1)) : cargando.value ? (openBlock(), createElementBlock("p", _hoisted_5, "Calculando…")) : informe.value ? (openBlock(), createElementBlock(Fragment, { key: 2 }, [
177
+ createElementVNode("div", _hoisted_6, [(openBlock(true), createElementBlock(Fragment, null, renderList(tarjetas.value, (t) => {
178
+ return openBlock(), createElementBlock("div", {
179
+ key: t.titulo,
180
+ class: "panel cifra"
181
+ }, [
182
+ createElementVNode("p", _hoisted_7, toDisplayString(t.titulo), 1),
183
+ createElementVNode("p", _hoisted_8, toDisplayString(t.valor), 1),
184
+ createElementVNode("p", _hoisted_9, toDisplayString(t.detalle), 1)
185
+ ]);
186
+ }), 128))]),
187
+ informe.value.sin_respuesta_vencidas > 0 ? (openBlock(), createElementBlock("p", _hoisted_10, " ⚠ " + toDisplayString(informe.value.sin_respuesta_vencidas) + " " + toDisplayString(informe.value.sin_respuesta_vencidas === 1 ? "conversación sigue" : "conversaciones siguen") + " sin primera respuesta con el plazo vencido. ", 1)) : createCommentVNode("", true),
188
+ createElementVNode("div", _hoisted_11, [createElementVNode("div", _hoisted_12, [_cache[13] || (_cache[13] = createElementVNode("p", { class: "panel-title" }, "Tiempos de RRHH", -1)), createElementVNode("table", _hoisted_13, [_cache[12] || (_cache[12] = createElementVNode("thead", null, [createElementVNode("tr", null, [
189
+ createElementVNode("th"),
190
+ createElementVNode("th", null, "Primera respuesta"),
191
+ createElementVNode("th", null, "Resolución")
192
+ ])], -1)), createElementVNode("tbody", null, [
193
+ createElementVNode("tr", null, [
194
+ _cache[8] || (_cache[8] = createElementVNode("th", { scope: "row" }, "Mediana", -1)),
195
+ createElementVNode("td", null, toDisplayString(unref(duracion)(informe.value.primera_respuesta.mediana)), 1),
196
+ createElementVNode("td", null, toDisplayString(unref(duracion)(informe.value.resolucion.mediana)), 1)
197
+ ]),
198
+ createElementVNode("tr", null, [
199
+ _cache[9] || (_cache[9] = createElementVNode("th", { scope: "row" }, "Promedio", -1)),
200
+ createElementVNode("td", null, toDisplayString(unref(duracion)(informe.value.primera_respuesta.promedio)), 1),
201
+ createElementVNode("td", null, toDisplayString(unref(duracion)(informe.value.resolucion.promedio)), 1)
202
+ ]),
203
+ createElementVNode("tr", null, [
204
+ _cache[10] || (_cache[10] = createElementVNode("th", { scope: "row" }, "Dentro del plazo", -1)),
205
+ createElementVNode("td", null, [createTextVNode(toDisplayString(informe.value.primera_respuesta.dentro_del_plazo ?? "—"), 1), informe.value.primera_respuesta.dentro_del_plazo !== null ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [createTextVNode(" %")], 64)) : createCommentVNode("", true)]),
206
+ createElementVNode("td", null, [createTextVNode(toDisplayString(informe.value.resolucion.dentro_del_plazo ?? "—"), 1), informe.value.resolucion.dentro_del_plazo !== null ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [createTextVNode(" %")], 64)) : createCommentVNode("", true)])
207
+ ]),
208
+ createElementVNode("tr", null, [
209
+ _cache[11] || (_cache[11] = createElementVNode("th", { scope: "row" }, "Medidas", -1)),
210
+ createElementVNode("td", null, toDisplayString(informe.value.primera_respuesta.medidas), 1),
211
+ createElementVNode("td", null, toDisplayString(informe.value.resolucion.medidas), 1)
212
+ ])
213
+ ])])]), createElementVNode("div", _hoisted_14, [_cache[14] || (_cache[14] = createElementVNode("p", { class: "panel-title" }, "Por qué pasaron a RRHH", -1)), !informe.value.escaladas ? (openBlock(), createElementBlock("p", _hoisted_15, "Ninguna pasó a RRHH en el rango.")) : (openBlock(), createElementBlock("table", _hoisted_16, [createElementVNode("tbody", null, [(openBlock(true), createElementBlock(Fragment, null, renderList(informe.value.por_motivo, (n, motivo) => {
214
+ return openBlock(), createElementBlock("tr", { key: motivo }, [
215
+ createElementVNode("th", _hoisted_17, toDisplayString(unref(MOTIVOS_ESCALAMIENTO)[motivo] ?? motivo), 1),
216
+ createElementVNode("td", _hoisted_18, toDisplayString(n), 1),
217
+ createElementVNode("td", _hoisted_19, toDisplayString(pct(n, informe.value.escaladas)), 1)
218
+ ]);
219
+ }), 128))])]))])]),
220
+ createElementVNode("div", _hoisted_20, [_cache[17] || (_cache[17] = createElementVNode("p", { class: "panel-title" }, "Por tema", -1)), createElementVNode("div", _hoisted_21, [createElementVNode("table", _hoisted_22, [_cache[16] || (_cache[16] = createElementVNode("thead", null, [createElementVNode("tr", null, [
221
+ createElementVNode("th", null, "Tema"),
222
+ createElementVNode("th", { class: "num" }, "Conversaciones"),
223
+ createElementVNode("th", { class: "num" }, "Pasaron a RRHH"),
224
+ createElementVNode("th", { class: "num" }, "Primera respuesta (prom.)"),
225
+ createElementVNode("th", { class: "num" }, "Calificación")
226
+ ])], -1)), createElementVNode("tbody", null, [(openBlock(true), createElementBlock(Fragment, null, renderList(informe.value.por_tema, (t) => {
227
+ return openBlock(), createElementBlock("tr", { key: t.tema }, [
228
+ createElementVNode("th", _hoisted_23, toDisplayString(t.tema), 1),
229
+ createElementVNode("td", _hoisted_24, toDisplayString(t.total), 1),
230
+ createElementVNode("td", _hoisted_25, toDisplayString(t.escaladas), 1),
231
+ createElementVNode("td", _hoisted_26, toDisplayString(unref(duracion)(t.primera_respuesta_promedio)), 1),
232
+ createElementVNode("td", _hoisted_27, toDisplayString(nota(t.calificacion_promedio)), 1)
233
+ ]);
234
+ }), 128)), !informe.value.por_tema.length ? (openBlock(), createElementBlock("tr", _hoisted_28, [..._cache[15] || (_cache[15] = [createElementVNode("td", {
235
+ colspan: "5",
236
+ class: "panel-muted"
237
+ }, "Sin conversaciones en el rango.", -1)])])) : createCommentVNode("", true)])])])]),
238
+ informe.value.por_persona ? (openBlock(), createElementBlock("div", _hoisted_29, [_cache[20] || (_cache[20] = createElementVNode("p", { class: "panel-title" }, "Por persona", -1)), createElementVNode("div", _hoisted_30, [createElementVNode("table", _hoisted_31, [_cache[19] || (_cache[19] = createElementVNode("thead", null, [createElementVNode("tr", null, [
239
+ createElementVNode("th", null, "Persona"),
240
+ createElementVNode("th", { class: "num" }, "Atendidas"),
241
+ createElementVNode("th", { class: "num" }, "Resueltas"),
242
+ createElementVNode("th", { class: "num" }, "Primera respuesta (prom.)"),
243
+ createElementVNode("th", { class: "num" }, "Calificación")
244
+ ])], -1)), createElementVNode("tbody", null, [(openBlock(true), createElementBlock(Fragment, null, renderList(informe.value.por_persona, (p) => {
245
+ return openBlock(), createElementBlock("tr", { key: p.usuario }, [
246
+ createElementVNode("th", _hoisted_32, toDisplayString(p.usuario), 1),
247
+ createElementVNode("td", _hoisted_33, toDisplayString(p.atendidas), 1),
248
+ createElementVNode("td", _hoisted_34, toDisplayString(p.resueltas), 1),
249
+ createElementVNode("td", _hoisted_35, toDisplayString(unref(duracion)(p.primera_respuesta_promedio)), 1),
250
+ createElementVNode("td", _hoisted_36, toDisplayString(nota(p.calificacion_promedio)), 1)
251
+ ]);
252
+ }), 128)), !informe.value.por_persona.length ? (openBlock(), createElementBlock("tr", _hoisted_37, [..._cache[18] || (_cache[18] = [createElementVNode("td", {
253
+ colspan: "5",
254
+ class: "panel-muted"
255
+ }, "Nadie atendió conversaciones en el rango.", -1)])])) : createCommentVNode("", true)])])])])) : createCommentVNode("", true),
256
+ createElementVNode("div", _hoisted_38, [createElementVNode("div", _hoisted_39, [_cache[21] || (_cache[21] = createElementVNode("p", { class: "panel-title" }, "Calificaciones (1 a 5)", -1)), createElementVNode("table", _hoisted_40, [createElementVNode("tbody", null, [(openBlock(), createElementBlock(Fragment, null, renderList([
257
+ 5,
258
+ 4,
259
+ 3,
260
+ 2,
261
+ 1
262
+ ], (n) => {
263
+ return createElementVNode("tr", { key: n }, [
264
+ createElementVNode("th", _hoisted_41, toDisplayString(n), 1),
265
+ createElementVNode("td", _hoisted_42, toDisplayString(informe.value.calificacion.distribucion[n] ?? 0), 1),
266
+ createElementVNode("td", _hoisted_43, toDisplayString(pct(informe.value.calificacion.distribucion[n] ?? 0, informe.value.calificacion.respuestas)), 1)
267
+ ]);
268
+ }), 64))])])]), createElementVNode("div", _hoisted_44, [_cache[26] || (_cache[26] = createElementVNode("p", { class: "panel-title" }, "Uso del asistente", -1)), createElementVNode("table", _hoisted_45, [createElementVNode("tbody", null, [
269
+ createElementVNode("tr", null, [_cache[22] || (_cache[22] = createElementVNode("th", { scope: "row" }, "Respuestas", -1)), createElementVNode("td", _hoisted_46, toDisplayString(informe.value.uso_ia.mensajes.toLocaleString("es-CO")), 1)]),
270
+ createElementVNode("tr", null, [_cache[23] || (_cache[23] = createElementVNode("th", { scope: "row" }, "Consultas al proveedor", -1)), createElementVNode("td", _hoisted_47, toDisplayString(informe.value.uso_ia.llamadas.toLocaleString("es-CO")), 1)]),
271
+ createElementVNode("tr", null, [_cache[24] || (_cache[24] = createElementVNode("th", { scope: "row" }, "Tokens de entrada", -1)), createElementVNode("td", _hoisted_48, toDisplayString(informe.value.uso_ia.tokens_entrada.toLocaleString("es-CO")), 1)]),
272
+ createElementVNode("tr", null, [_cache[25] || (_cache[25] = createElementVNode("th", { scope: "row" }, "Tokens de salida", -1)), createElementVNode("td", _hoisted_49, toDisplayString(informe.value.uso_ia.tokens_salida.toLocaleString("es-CO")), 1)])
273
+ ])])])])
274
+ ], 64)) : createCommentVNode("", true)
275
+ ]);
276
+ };
277
+ }
278
+ }), [["__scopeId", "data-v-fa114240"]]);
279
+ //#endregion
280
+ export { ChatInformeView_default as default };
@@ -0,0 +1,183 @@
1
+ import { t as RUTAS_PORTAL } from "./tipos-D93bLfFC.js";
2
+ import { t as _plugin_vue_export_helper_default } from "./_plugin-vue_export-helper-BOaGB7Aw.js";
3
+ import { i as chatService } from "./chat.service-C7ZQf4w3.js";
4
+ import { t as mensajeError } from "./apiError-BHGbwz97.js";
5
+ import { Fragment, createCommentVNode, createElementBlock, createElementVNode, createTextVNode, createVNode, defineComponent, onMounted, openBlock, ref, renderList, toDisplayString, unref, vModelSelect, vModelText, withCtx, withDirectives, withModifiers } from "vue";
6
+ import { RouterLink } from "vue-router";
7
+ //#region src/views/chat/ChatRespuestasView.vue?vue&type=script&setup=true&lang.ts
8
+ var _hoisted_1 = { class: "page-shell" };
9
+ var _hoisted_2 = { class: "page-header" };
10
+ var _hoisted_3 = {
11
+ key: 0,
12
+ class: "panel-error",
13
+ role: "alert"
14
+ };
15
+ var _hoisted_4 = {
16
+ key: 1,
17
+ class: "panel-muted"
18
+ };
19
+ var _hoisted_5 = { class: "campo" };
20
+ var _hoisted_6 = { class: "campo" };
21
+ var _hoisted_7 = { class: "toolbar" };
22
+ var _hoisted_8 = ["value"];
23
+ var _hoisted_9 = ["disabled"];
24
+ var _hoisted_10 = ["disabled"];
25
+ var _hoisted_11 = {
26
+ key: 0,
27
+ class: "panel-muted"
28
+ };
29
+ var _hoisted_12 = { class: "page-header" };
30
+ var _hoisted_13 = { class: "panel-title" };
31
+ var _hoisted_14 = { class: "panel-muted" };
32
+ var _hoisted_15 = {
33
+ key: 0,
34
+ class: "toolbar"
35
+ };
36
+ var _hoisted_16 = ["disabled", "onClick"];
37
+ var _hoisted_17 = ["disabled", "onClick"];
38
+ var _hoisted_18 = { class: "texto" };
39
+ //#endregion
40
+ //#region src/views/chat/ChatRespuestasView.vue
41
+ var ChatRespuestasView_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE__ */ defineComponent({
42
+ __name: "ChatRespuestasView",
43
+ setup(__props) {
44
+ const respuestas = ref([]);
45
+ const temas = ref([]);
46
+ const cargando = ref(true);
47
+ const ocupado = ref(false);
48
+ const error = ref(null);
49
+ const editando = ref(null);
50
+ const nombreTema = (id) => temas.value.find((t) => t.id === id)?.nombre ?? "Todos los temas";
51
+ async function cargar() {
52
+ cargando.value = true;
53
+ error.value = null;
54
+ try {
55
+ [respuestas.value, temas.value] = await Promise.all([chatService.respuestas(), chatService.temas()]);
56
+ } catch (e) {
57
+ error.value = mensajeError(e, "No se pudieron cargar las respuestas guardadas.");
58
+ } finally {
59
+ cargando.value = false;
60
+ }
61
+ }
62
+ async function guardar() {
63
+ if (!editando.value) return;
64
+ ocupado.value = true;
65
+ error.value = null;
66
+ try {
67
+ await chatService.guardarRespuesta(editando.value);
68
+ editando.value = null;
69
+ respuestas.value = await chatService.respuestas();
70
+ } catch (e) {
71
+ error.value = mensajeError(e, "No se pudo guardar la respuesta.");
72
+ } finally {
73
+ ocupado.value = false;
74
+ }
75
+ }
76
+ async function borrar(r) {
77
+ if (!window.confirm(`¿Borrar «${r.titulo}»?`)) return;
78
+ ocupado.value = true;
79
+ try {
80
+ await chatService.borrarRespuesta(r.id);
81
+ respuestas.value = respuestas.value.filter((x) => x.id !== r.id);
82
+ } catch (e) {
83
+ error.value = mensajeError(e, "No se pudo borrar la respuesta.");
84
+ } finally {
85
+ ocupado.value = false;
86
+ }
87
+ }
88
+ onMounted(() => void cargar());
89
+ return (_ctx, _cache) => {
90
+ return openBlock(), createElementBlock("section", _hoisted_1, [
91
+ createVNode(unref(RouterLink), {
92
+ to: { name: unref(RUTAS_PORTAL).chat },
93
+ class: "volver"
94
+ }, {
95
+ default: withCtx(() => [..._cache[5] || (_cache[5] = [createTextVNode("← Bandeja", -1)])]),
96
+ _: 1
97
+ }, 8, ["to"]),
98
+ createElementVNode("header", _hoisted_2, [_cache[6] || (_cache[6] = createElementVNode("div", null, [createElementVNode("h1", { class: "page-title" }, "Respuestas guardadas"), createElementVNode("p", { class: "page-subtitle" }, [
99
+ createTextVNode(" Textos que el equipo reusa al contestar. Escriba "),
100
+ createElementVNode("code", null, "{nombre}"),
101
+ createTextVNode(" donde vaya el primer nombre del empleado. ")
102
+ ])], -1)), !editando.value ? (openBlock(), createElementBlock("button", {
103
+ key: 0,
104
+ type: "button",
105
+ class: "btn-primary",
106
+ onClick: _cache[0] || (_cache[0] = ($event) => editando.value = {
107
+ titulo: "",
108
+ cuerpo: "",
109
+ tema_id: null
110
+ })
111
+ }, " Nueva respuesta ")) : createCommentVNode("", true)]),
112
+ error.value ? (openBlock(), createElementBlock("p", _hoisted_3, toDisplayString(error.value), 1)) : createCommentVNode("", true),
113
+ cargando.value ? (openBlock(), createElementBlock("p", _hoisted_4, "Cargando…")) : createCommentVNode("", true),
114
+ editando.value ? (openBlock(), createElementBlock("form", {
115
+ key: 2,
116
+ class: "panel",
117
+ onSubmit: withModifiers(guardar, ["prevent"])
118
+ }, [
119
+ createElementVNode("label", _hoisted_5, [_cache[7] || (_cache[7] = createElementVNode("span", { class: "label" }, "Título (para encontrarla)", -1)), withDirectives(createElementVNode("input", {
120
+ "onUpdate:modelValue": _cache[1] || (_cache[1] = ($event) => editando.value.titulo = $event),
121
+ class: "input",
122
+ maxlength: "120",
123
+ required: "",
124
+ placeholder: "Fecha de pago de la prima"
125
+ }, null, 512), [[vModelText, editando.value.titulo]])]),
126
+ createElementVNode("label", _hoisted_6, [_cache[8] || (_cache[8] = createElementVNode("span", { class: "label" }, "Texto", -1)), withDirectives(createElementVNode("textarea", {
127
+ "onUpdate:modelValue": _cache[2] || (_cache[2] = ($event) => editando.value.cuerpo = $event),
128
+ class: "input",
129
+ rows: "5",
130
+ maxlength: "4000",
131
+ required: "",
132
+ placeholder: "Hola {nombre}, la prima se paga…"
133
+ }, null, 512), [[vModelText, editando.value.cuerpo]])]),
134
+ createElementVNode("div", _hoisted_7, [
135
+ _cache[10] || (_cache[10] = createElementVNode("label", {
136
+ for: "resp-tema",
137
+ class: "label"
138
+ }, "Tema", -1)),
139
+ withDirectives(createElementVNode("select", {
140
+ id: "resp-tema",
141
+ "onUpdate:modelValue": _cache[3] || (_cache[3] = ($event) => editando.value.tema_id = $event),
142
+ class: "input"
143
+ }, [_cache[9] || (_cache[9] = createElementVNode("option", { value: null }, "Todos los temas", -1)), (openBlock(true), createElementBlock(Fragment, null, renderList(temas.value, (t) => {
144
+ return openBlock(), createElementBlock("option", {
145
+ key: t.id,
146
+ value: t.id
147
+ }, toDisplayString(t.nombre), 9, _hoisted_8);
148
+ }), 128))], 512), [[vModelSelect, editando.value.tema_id]]),
149
+ createElementVNode("button", {
150
+ type: "submit",
151
+ class: "btn-primary",
152
+ disabled: ocupado.value
153
+ }, "Guardar", 8, _hoisted_9),
154
+ createElementVNode("button", {
155
+ type: "button",
156
+ class: "btn-secondary",
157
+ disabled: ocupado.value,
158
+ onClick: _cache[4] || (_cache[4] = ($event) => editando.value = null)
159
+ }, "Cancelar", 8, _hoisted_10)
160
+ ])
161
+ ], 32)) : createCommentVNode("", true),
162
+ !cargando.value ? (openBlock(), createElementBlock(Fragment, { key: 3 }, [!respuestas.value.length ? (openBlock(), createElementBlock("p", _hoisted_11, "Todavía no hay respuestas guardadas.")) : createCommentVNode("", true), (openBlock(true), createElementBlock(Fragment, null, renderList(respuestas.value, (r) => {
163
+ return openBlock(), createElementBlock("article", {
164
+ key: r.id,
165
+ class: "panel"
166
+ }, [createElementVNode("div", _hoisted_12, [createElementVNode("div", null, [createElementVNode("p", _hoisted_13, toDisplayString(r.titulo), 1), createElementVNode("p", _hoisted_14, [createTextVNode(toDisplayString(nombreTema(r.tema_id)), 1), r.propia ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [createTextVNode(" · Suya")], 64)) : createCommentVNode("", true)])]), r.editable ? (openBlock(), createElementBlock("div", _hoisted_15, [createElementVNode("button", {
167
+ type: "button",
168
+ class: "btn-secondary",
169
+ disabled: ocupado.value,
170
+ onClick: ($event) => editando.value = { ...r }
171
+ }, "Editar", 8, _hoisted_16), createElementVNode("button", {
172
+ type: "button",
173
+ class: "btn-danger",
174
+ disabled: ocupado.value,
175
+ onClick: ($event) => borrar(r)
176
+ }, "Borrar", 8, _hoisted_17)])) : createCommentVNode("", true)]), createElementVNode("p", _hoisted_18, toDisplayString(r.cuerpo), 1)]);
177
+ }), 128))], 64)) : createCommentVNode("", true)
178
+ ]);
179
+ };
180
+ }
181
+ }), [["__scopeId", "data-v-d7451ca3"]]);
182
+ //#endregion
183
+ export { ChatRespuestasView_default as default };