@golstats/gsc-reports 1.0.75 → 1.0.76

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 (30) hide show
  1. package/README.md +2 -2
  2. package/dist/{FilterConditions-55d68355-DMqzcKBO-D-F7eebx-B2f4vldh.js → FilterConditions-55d68355-DMqzcKBO-LoDZzMFx-BnRBGncA.js} +1 -1
  3. package/dist/{FilterField-59a73e38-CNaE03Ge-BSjrLEv7-BA50MIOk.js → FilterField-59a73e38-CNaE03Ge-CQDCuDcF-D41LgF38.js} +1 -1
  4. package/dist/{FilterSubcategories-a9b32cc9-_h5FCZ4r-BXbLe1Ix-aBIaeKxy.js → FilterSubcategories-a9b32cc9-_h5FCZ4r-B4SJzQzA-DXEQISeO.js} +1 -1
  5. package/dist/css/fonts.css +83 -83
  6. package/dist/gsc-reports.css +1 -1
  7. package/dist/gsc-reports.es.js +1 -1
  8. package/dist/gsc-reports.umd.js +225 -225
  9. package/dist/{index-BdUpXZsm.js → index-DWidkeeO.js} +54646 -54564
  10. package/package.json +2 -2
  11. package/src/components/TemplatesSection.vue +29 -2
  12. package/src/components/elementsTemplates/ModalConfigurarContenido.vue +1250 -1229
  13. package/src/components/elementsTemplates/ModalDeleteTemplate.vue +249 -249
  14. package/src/components/elementsTemplates/ModalGenerarReporte.vue +22 -1
  15. package/src/components/elementsTemplates/ModalSoloEscritorio.vue +83 -83
  16. package/src/components/elementsTemplates/ModalduplicateTemplate.vue +300 -300
  17. package/src/components/elementsTemplates/TooltipReportOptions.vue +97 -97
  18. package/src/components/elementsTemplates/TooltipTemplateOptions.vue +168 -168
  19. package/src/components/filters.vue +935 -935
  20. package/src/components/template-report-maker/CoverSelector.vue +165 -165
  21. package/src/components/template-report-maker/ReportView.vue +66 -66
  22. package/src/components/thumbnails-reports/AnalisisPostMatchType1.vue +741 -741
  23. package/src/components/thumbnails-reports/AnalisisPostMatchType2.vue +743 -743
  24. package/src/components/thumbnails-reports/AnalisisPrematchType3.vue +173 -173
  25. package/src/components/thumbnails-reports/AnalisisPrematchType4.vue +173 -173
  26. package/src/index.js +4 -4
  27. package/src/types.d.ts +45 -45
  28. package/src/utils/dateUtils.js +52 -52
  29. package/dist/images/cancha-horizontal.jpg +0 -0
  30. package/dist/images/canchaRPH.svg +0 -30
@@ -1,1229 +1,1250 @@
1
- <template>
2
- <div class="modal-overlay">
3
- <div class="modal-content">
4
- <!-- Botón de cerrar removido -->
5
-
6
- <div class="modal-header">
7
- <div class="header-left">
8
- <img
9
- src="https://golstatsimages.blob.core.windows.net/reports-images/icn-report-white.svg"
10
- class="icon-title"
11
- alt="icono reporte blanco"
12
- />
13
- <span class="modal-title"
14
- >Generar reporte&nbsp; - &nbsp; <span class="prepartido-text">Prepartido</span></span
15
- >
16
- </div>
17
- <div class="step-counter">
18
- Paso {{ currentStep === 0 ? 1 : currentStep }} de {{ totalSteps }}
19
- </div>
20
- </div>
21
- <div class="header-separator"></div>
22
- <div class="modal-body" :class="{ transitioning: isTransitioning }">
23
- <!-- Paso 0: Configuración inicial de opciones -->
24
- <div v-if="currentStep === 0" class="step-content">
25
- <!-- Sección Fortalezas - Solo se muestra si existen Fortalezas en el template -->
26
- <div v-if="hasFortalezas" class="content-section">
27
- <h3 class="section-title">Fortalezas</h3>
28
- <div class="title-separator"></div>
29
- <p class="section-description">
30
- Este template contiene {{ fortalezasCounts.equipo }} visualizaciones de Fortalezas de
31
- tu equipo y {{ fortalezasCounts.rival }} de tu rival. ¿Cómo prefieres que se agregue
32
- este contenido?
33
- </p>
34
- <div class="content-separator"></div>
35
- <div class="radio-group">
36
- <label class="radio-option">
37
- <input
38
- type="radio"
39
- name="fortalezas"
40
- value="automatico"
41
- v-model="fortalezasOption"
42
- />
43
- <span class="radio-custom"></span>
44
- <span class="radio-label">Automáticamente</span>
45
- </label>
46
- <label class="radio-option">
47
- <input type="radio" name="fortalezas" value="manual" v-model="fortalezasOption" />
48
- <span class="radio-custom"></span>
49
- <span class="radio-label">Manualmente</span>
50
- </label>
51
- </div>
52
- </div>
53
-
54
- <!-- Separador removido -->
55
-
56
- <!-- Sección Tiros de esquina - OCULTA POR EL MOMENTO -->
57
- <!-- <div v-if="hasCorners" class="content-section">
58
- <h3 class="section-title">Tiros de esquina</h3>
59
- <div class="title-separator"></div>
60
- <p class="section-description">
61
- Este template contiene 10 visualizaciones de Tiros de esquina de tu equipo. ¿Cómo
62
- prefieres que se agregue este contenido?
63
- </p>
64
- <div class="content-separator"></div>
65
- <div class="radio-group">
66
- <label class="radio-option">
67
- <input
68
- type="radio"
69
- name="tiros-esquina"
70
- value="automatico"
71
- v-model="tirosEsquinaOption"
72
- />
73
- <span class="radio-custom"></span>
74
- <span class="radio-label">Automáticamente</span>
75
- </label>
76
- <label class="radio-option">
77
- <input
78
- type="radio"
79
- name="tiros-esquina"
80
- value="manual"
81
- v-model="tirosEsquinaOption"
82
- />
83
- <span class="radio-custom"></span>
84
- <span class="radio-label">Manualmente</span>
85
- </label>
86
- </div>
87
- </div> -->
88
- </div>
89
-
90
- <!-- Pasos dinámicos renderizados por clave -->
91
- <!-- Usamos v-show en lugar de v-if para mantener los componentes montados y preservar el estado -->
92
- <template v-if="fortalezasCounts.equipo > 0">
93
- <div v-show="buildStepMap()[currentStep] === 'fortalezasEquipo'" class="step-content">
94
- <FortalezasView
95
- key="fortalezas-equipo"
96
- v-model="selectedFortalezasEquipo"
97
- team-initials="AME"
98
- :season-id="1772"
99
- :team-id="props.partido?.local || props.partido?.home_team"
100
- :rival-team-id="props.partido?.visita || props.partido?.visiting_team"
101
- :token="props.token"
102
- title="Fortalezas a favor de mi equipo"
103
- :total-fortalezas="fortalezasCounts.equipo"
104
- ref="fortalezasEquipoRef"
105
- />
106
- </div>
107
- </template>
108
-
109
- <template v-if="fortalezasCounts.rival > 0">
110
- <div v-show="buildStepMap()[currentStep] === 'fortalezasRival'" class="step-content">
111
- <FortalezasView
112
- key="fortalezas-rival"
113
- v-model="selectedFortalezasRival"
114
- team-initials="RIV"
115
- :season-id="1772"
116
- :team-id="props.partido?.visita || props.partido?.visiting_team"
117
- :rival-team-id="props.partido?.local || props.partido?.home_team"
118
- :token="props.token"
119
- title="Fortalezas a favor del rival"
120
- :total-fortalezas="fortalezasCounts.rival"
121
- ref="fortalezasRivalRef"
122
- />
123
- </div>
124
- </template>
125
-
126
- <div v-if="buildStepMap()[currentStep] === 'cornersEquipo'" class="step-content">
127
- <TirosEsquinaView
128
- v-model="selectedCornersEquipo"
129
- :rival="false"
130
- team-initials="AME"
131
- title="Tiros de esquina en contra de mi equipo"
132
- team-logo-url="https://golstatsimages.blob.core.windows.net/teams-80/2.png"
133
- ref="cornersEquipoRef"
134
- />
135
- </div>
136
-
137
- <div v-if="buildStepMap()[currentStep] === 'cornersRival'" class="step-content">
138
- <TirosEsquinaView
139
- v-model="selectedCornersRival"
140
- :rival="true"
141
- team-initials="RIV"
142
- title="Tiros de esquina en contra del rival"
143
- team-logo-url="https://golstatsimages.blob.core.windows.net/teams-80/1.png"
144
- ref="cornersRivalRef"
145
- />
146
- </div>
147
- </div>
148
- <div class="header-separator"></div>
149
- <div class="modal-footer">
150
- <button class="back-btn" @click="goBack">
151
- <svg
152
- width="16"
153
- height="16"
154
- viewBox="0 0 16 16"
155
- fill="none"
156
- xmlns="http://www.w3.org/2000/svg"
157
- >
158
- <path
159
- d="M10 12L6 8L10 4"
160
- stroke="white"
161
- stroke-width="2"
162
- stroke-linecap="round"
163
- stroke-linejoin="round"
164
- />
165
- </svg>
166
- Regresar
167
- </button>
168
- <div class="footer-actions">
169
- <button v-if="currentStep === 0" class="cancel-btn" @click="closeModal">Cancelar</button>
170
- <button
171
- v-if="currentStep === 1 || currentStep === 2"
172
- class="cancel-btn"
173
- @click="autocompletar"
174
- >
175
- Autocompletar
176
- </button>
177
- <button
178
- class="next-btn"
179
- :class="{ disabled: !canContinue }"
180
- :disabled="!canContinue"
181
- @click="continueToNext"
182
- >
183
- {{
184
- currentStep === 0
185
- ? fortalezasOption === 'automatico'
186
- ? 'Finalizar'
187
- : 'Siguiente'
188
- : currentStep === totalSteps
189
- ? 'Finalizar'
190
- : 'Siguiente'
191
- }}
192
- </button>
193
- </div>
194
- </div>
195
- </div>
196
- </div>
197
-
198
- <!-- Modal de confirmación para regresar al paso 0 -->
199
- <div v-if="showConfirmDialog" class="modal-overlay" @click.self="cancelGoBack">
200
- <div class="modal-content confirm-dialog">
201
- <div class="modal-header">
202
- <div class="header-left">
203
- <span class="modal-title">Confirmación</span>
204
- </div>
205
- </div>
206
- <div class="header-separator"></div>
207
- <div class="modal-body">
208
- <div class="step-content">
209
- <h3 class="confirm-dialog-title">¿Estás seguro de regresar?</h3>
210
- <p class="confirm-dialog-message">Se perderá la información seleccionada</p>
211
- </div>
212
- </div>
213
- <div class="modal-footer">
214
- <div class="footer-actions">
215
- <button class="cancel-btn" @click="cancelGoBack">Cancelar</button>
216
- <button class="next-btn" @click="confirmGoBackToStep0">Confirmar</button>
217
- </div>
218
- </div>
219
- </div>
220
- </div>
221
- </template>
222
-
223
- <script setup>
224
- import { ref, defineEmits, computed, nextTick } from 'vue'
225
- import FortalezasView from './FortalezasView.vue'
226
- import TirosEsquinaView from './TirosEsquinaView.vue'
227
-
228
- const emit = defineEmits(['close', 'back', 'next'])
229
-
230
- // Props para controlar el número de pasos
231
- const props = defineProps({
232
- hasRival: {
233
- type: Boolean,
234
- default: true,
235
- },
236
- token: {
237
- type: String,
238
- required: true,
239
- },
240
- template: {
241
- type: Object,
242
- required: false,
243
- default: null,
244
- },
245
- team: {
246
- type: Number,
247
- required: false,
248
- default: null,
249
- },
250
- partido: {
251
- type: Object,
252
- required: false,
253
- default: null,
254
- },
255
- })
256
-
257
- // Función para verificar si existe un componente Fortalezas en el template
258
- function tieneComponenteFortalezas() {
259
- if (!props.template || !props.template.pages) {
260
- return false
261
- }
262
-
263
- // Iterar sobre todas las pages del template
264
- for (const page of props.template.pages) {
265
- // Verificar si la page tiene components
266
- if (page.components && Array.isArray(page.components)) {
267
- // Buscar si existe algún componente con name === 'Fortalezas' o id === 15
268
- const tieneFortalezas = page.components.some(
269
- (component) => component.name === 'Fortalezas' || component.id === 15,
270
- )
271
- if (tieneFortalezas) {
272
- return true
273
- }
274
- }
275
- }
276
-
277
- return false
278
- }
279
-
280
- // Función para contar Fortalezas del equipo propio y del rival
281
- function contarFortalezas() {
282
- if (!props.template || !props.template.pages) {
283
- return { equipo: 0, rival: 0, total: 0 }
284
- }
285
-
286
- let countEquipo = 0
287
- let countRival = 0
288
-
289
- // Iterar sobre todas las pages del template
290
- for (const page of props.template.pages) {
291
- // Verificar si la page tiene components
292
- if (page.components && Array.isArray(page.components)) {
293
- // Filtrar componentes Fortalezas
294
- const componentesFortalezas = page.components.filter(
295
- (component) => component.name === 'Fortalezas' || component.id === 15,
296
- )
297
-
298
- // Para cada componente Fortalezas, verificar dynamicFilters
299
- for (const component of componentesFortalezas) {
300
- // Verificar si tiene dynamicFilters y es un array
301
- if (component.dynamicFilters && Array.isArray(component.dynamicFilters)) {
302
- // Verificar la posición 1 (que es un array)
303
- if (component.dynamicFilters[1]) {
304
- // Consultar la posición 0 para determinar si es equipo propio (1) o rival (2)
305
- if (component.dynamicFilters[0] === 1) {
306
- countEquipo += component.dynamicFilters[1]
307
- } else if (component.dynamicFilters[0] === 2) {
308
- countRival += component.dynamicFilters[1]
309
- }
310
- }
311
- }
312
- }
313
- }
314
- }
315
-
316
- return {
317
- equipo: countEquipo,
318
- rival: countRival,
319
- total: countEquipo + countRival,
320
- }
321
- }
322
-
323
- // Computed para verificar si tiene Fortalezas
324
- const hasFortalezas = computed(() => tieneComponenteFortalezas())
325
-
326
- // Computed para obtener los conteos de Fortalezas
327
- const fortalezasCounts = computed(() => contarFortalezas())
328
-
329
- // const hasCorners = false // OCULTO POR EL MOMENTO
330
- // Estado del modal
331
- const currentStep = ref(0) // 0 = configuración inicial, luego pasos dinámicos
332
- const isTransitioning = ref(false)
333
-
334
- // Modal de confirmación para regresar al paso 0
335
- const showConfirmDialog = ref(false)
336
-
337
- // Opciones seleccionadas para cada sección
338
- const fortalezasOption = ref('manual')
339
- const tirosEsquinaOption = ref('manual')
340
-
341
- // Selecciones por vista
342
- const selectedFortalezasEquipo = ref([])
343
- const selectedFortalezasRival = ref([])
344
- const selectedCornersEquipo = ref([])
345
- const selectedCornersRival = ref([])
346
-
347
- // Calcular el número total de pasos
348
- const totalSteps = computed(() => {
349
- let steps = 0
350
-
351
- // Pasos de Fortalezas
352
- if (hasFortalezas.value && fortalezasOption.value === 'manual') {
353
- // Si hay fortalezas de equipo, agregar paso 1
354
- if (fortalezasCounts.value.equipo > 0) {
355
- steps += 1
356
- }
357
- // Si hay fortalezas de rival, agregar paso (será 2 si hay equipo, 1 si no hay)
358
- if (fortalezasCounts.value.rival > 0) {
359
- steps += 1
360
- }
361
- }
362
-
363
- // Pasos de Tiros de esquina - OCULTOS POR EL MOMENTO
364
- // if (tirosEsquinaOption.value === 'manual') {
365
- // steps += props.hasRival ? 2 : 1
366
- // }
367
-
368
- return Math.max(steps, 1)
369
- })
370
-
371
- // Verificar si se puede continuar al siguiente paso
372
- const canContinue = computed(() => {
373
- if (currentStep.value === 0) {
374
- // Si no hay Fortalezas, no se puede continuar (tirosEsquina está oculto)
375
- if (!hasFortalezas.value) {
376
- return false
377
- }
378
- // Puede continuar si está en automático o en manual
379
- return fortalezasOption.value === 'automatico' || fortalezasOption.value === 'manual'
380
- }
381
- const stepMap = buildStepMap()
382
- const key = stepMap[currentStep.value]
383
-
384
- if (key === 'fortalezasEquipo') {
385
- const ref = fortalezasEquipoRef.value
386
- if (!ref) return false
387
- const selected = selectedFortalezasEquipo.value.length
388
- const totalRequerido = fortalezasCounts.value.equipo
389
- // Obtener el total de fortalezas disponibles del componente
390
- const totalDisponibles = ref.fortalezasData?.length || 0
391
-
392
- // Puede continuar si:
393
- // 1. Selecciona el total exacto requerido
394
- // 2. O si no hay suficientes disponibles, selecciona todos los disponibles
395
- return (
396
- selected === totalRequerido ||
397
- (totalDisponibles > 0 && totalDisponibles < totalRequerido && selected === totalDisponibles)
398
- )
399
- }
400
-
401
- if (key === 'fortalezasRival') {
402
- const ref = fortalezasRivalRef.value
403
- if (!ref) return false
404
- const selected = selectedFortalezasRival.value.length
405
- const totalRequerido = fortalezasCounts.value.rival
406
- // Obtener el total de fortalezas disponibles del componente
407
- const totalDisponibles = ref.fortalezasData?.length || 0
408
-
409
- // Puede continuar si:
410
- // 1. Selecciona el total exacto requerido
411
- // 2. O si no hay suficientes disponibles, selecciona todos los disponibles
412
- return (
413
- selected === totalRequerido ||
414
- (totalDisponibles > 0 && totalDisponibles < totalRequerido && selected === totalDisponibles)
415
- )
416
- }
417
-
418
- // Pasos de corners ocultos
419
- // if (key === 'cornersEquipo') return selectedCornersEquipo.value.length > 0
420
- // if (key === 'cornersRival') return selectedCornersRival.value.length > 0
421
- return false
422
- })
423
-
424
- function buildStepMap() {
425
- const order = []
426
-
427
- // Solo agregar pasos de Fortalezas si existen en el template y está en modo manual
428
- if (hasFortalezas.value && fortalezasOption.value === 'manual') {
429
- // Si hay fortalezas de equipo, agregar paso de equipo
430
- if (fortalezasCounts.value.equipo > 0) {
431
- order.push('fortalezasEquipo')
432
- }
433
- // Si hay fortalezas de rival, agregar paso de rival
434
- if (fortalezasCounts.value.rival > 0) {
435
- order.push('fortalezasRival')
436
- }
437
- }
438
-
439
- // Pasos de Tiros de esquina - OCULTOS POR EL MOMENTO
440
- // if (tirosEsquinaOption.value === 'manual') {
441
- // order.push('cornersEquipo')
442
- // if (props.hasRival) order.push('cornersRival')
443
- // }
444
-
445
- const map = {}
446
- order.forEach((k, idx) => {
447
- map[idx + 1] = k // pasos empiezan en 1
448
- })
449
- return map
450
- }
451
-
452
- // Referencias a los componentes
453
- const fortalezasEquipoRef = ref(null)
454
- const fortalezasRivalRef = ref(null)
455
- const cornersEquipoRef = ref(null)
456
- const cornersRivalRef = ref(null)
457
-
458
- function closeModal() {
459
- emit('close')
460
- }
461
-
462
- function goBack() {
463
- if (currentStep.value > 1) {
464
- // Si estamos en paso 2 o superior, solo regresar sin borrar selecciones
465
- currentStep.value--
466
- } else if (currentStep.value === 1) {
467
- // Si estamos en paso 1 y vamos al paso 0, mostrar modal de confirmación
468
- // Verificar si hay selecciones antes de mostrar el modal
469
- const tieneSelecciones =
470
- selectedFortalezasEquipo.value.length > 0 || selectedFortalezasRival.value.length > 0
471
-
472
- if (tieneSelecciones) {
473
- showConfirmDialog.value = true
474
- } else {
475
- // Si no hay selecciones, regresar directamente
476
- currentStep.value--
477
- }
478
- } else {
479
- // Si estamos en paso 0, emitir evento back
480
- emit('back')
481
- }
482
- }
483
-
484
- function confirmGoBackToStep0() {
485
- // Limpiar todas las selecciones
486
- selectedFortalezasEquipo.value = []
487
- selectedFortalezasRival.value = []
488
- selectedCornersEquipo.value = []
489
- selectedCornersRival.value = []
490
-
491
- // Cerrar el modal de confirmación
492
- showConfirmDialog.value = false
493
-
494
- // Regresar al paso 0
495
- currentStep.value--
496
- }
497
-
498
- function cancelGoBack() {
499
- // Cerrar el modal de confirmación sin hacer nada
500
- showConfirmDialog.value = false
501
- }
502
-
503
- async function continueToNext() {
504
- if (currentStep.value === 0) {
505
- // Validar que al menos una opción esté seleccionada
506
- if (!canContinue.value) {
507
- return
508
- }
509
-
510
- // Si está en automático, finalizar directamente sin construir payload
511
- if (fortalezasOption.value === 'automatico') {
512
- // Emitir evento sin payload de strengths (se generarán automáticamente)
513
- emit('next', {
514
- fortalezas: fortalezasOption.value,
515
- tirosEsquina: tirosEsquinaOption.value,
516
- selectedFortalezasEquipo: [],
517
- selectedFortalezasRival: [],
518
- strengthsPayload: {}, // Payload vacío para modo automático
519
- })
520
- return
521
- }
522
-
523
- // Si es manual, avanzar al siguiente paso
524
- // Animar transición
525
- isTransitioning.value = true
526
- setTimeout(() => {
527
- currentStep.value++
528
- isTransitioning.value = false
529
- }, 300)
530
- } else if (currentStep.value < totalSteps.value) {
531
- // Avanzar al siguiente paso
532
- isTransitioning.value = true
533
- setTimeout(() => {
534
- currentStep.value++
535
- isTransitioning.value = false
536
- }, 300)
537
- } else {
538
- // Esperar un tick para asegurar que los refs estén disponibles
539
- await nextTick()
540
-
541
- // Construir el payload de fortalezas antes de emitir
542
- const strengthsPayload = buildStrengthsPayload()
543
- console.log('Estructura de strengths emitida:', JSON.stringify(strengthsPayload, null, 2))
544
-
545
- // Emitir evento con las opciones seleccionadas y el payload de fortalezas
546
- emit('next', {
547
- fortalezas: fortalezasOption.value,
548
- tirosEsquina: tirosEsquinaOption.value,
549
- selectedFortalezasEquipo: selectedFortalezasEquipo.value,
550
- selectedFortalezasRival: selectedFortalezasRival.value,
551
- strengthsPayload,
552
- })
553
- }
554
- }
555
-
556
- // Función para construir el payload de fortalezas según la estructura requerida
557
- function buildStrengthsPayload() {
558
- console.log('=== INICIANDO buildStrengthsPayload ===')
559
- console.log('Template:', props.template)
560
- console.log('Template pages:', props.template?.pages)
561
-
562
- if (!props.template || !props.template.pages) {
563
- console.warn('No hay template o pages')
564
- return {}
565
- }
566
-
567
- const payload = {}
568
-
569
- console.log('selectedFortalezasEquipo:', selectedFortalezasEquipo.value)
570
- console.log('selectedFortalezasRival:', selectedFortalezasRival.value)
571
- console.log('fortalezasEquipoRef:', fortalezasEquipoRef.value)
572
- console.log('fortalezasRivalRef:', fortalezasRivalRef.value)
573
-
574
- // Verificar si los refs están disponibles
575
- let equipoRef = fortalezasEquipoRef.value
576
- let rivalRef = fortalezasRivalRef.value
577
-
578
- // Debug detallado de los refs
579
- if (equipoRef) {
580
- console.log('equipoRef keys:', Object.keys(equipoRef))
581
- console.log('equipoRef.fortalezasRawData:', equipoRef.fortalezasRawData)
582
- console.log('equipoRef.fortalezasRawData type:', typeof equipoRef.fortalezasRawData)
583
-
584
- // Verificar si es un ref (tiene .value)
585
- let rawDataEquipo = equipoRef.fortalezasRawData
586
- if (rawDataEquipo && typeof rawDataEquipo === 'object' && 'value' in rawDataEquipo) {
587
- console.log('⚠️ fortalezasRawData es un ref, usando .value')
588
- rawDataEquipo = rawDataEquipo.value
589
- }
590
-
591
- console.log('rawDataEquipo después de verificar ref:', rawDataEquipo)
592
- console.log('rawDataEquipo is array:', Array.isArray(rawDataEquipo))
593
- if (Array.isArray(rawDataEquipo)) {
594
- console.log('rawDataEquipo length:', rawDataEquipo.length)
595
- if (rawDataEquipo.length > 0) {
596
- console.log('Primer elemento equipoRef:', rawDataEquipo[0])
597
- }
598
- }
599
- } else {
600
- console.error('❌ equipoRef NO está disponible')
601
- }
602
-
603
- if (rivalRef) {
604
- console.log('rivalRef keys:', Object.keys(rivalRef))
605
- console.log('rivalRef.fortalezasRawData:', rivalRef.fortalezasRawData)
606
- console.log('rivalRef.fortalezasRawData type:', typeof rivalRef.fortalezasRawData)
607
-
608
- // Verificar si es un ref (tiene .value)
609
- let rawDataRival = rivalRef.fortalezasRawData
610
- if (rawDataRival && typeof rawDataRival === 'object' && 'value' in rawDataRival) {
611
- console.log('⚠️ fortalezasRawData es un ref, usando .value')
612
- rawDataRival = rawDataRival.value
613
- }
614
-
615
- console.log('rawDataRival después de verificar ref:', rawDataRival)
616
- console.log('rawDataRival is array:', Array.isArray(rawDataRival))
617
- if (Array.isArray(rawDataRival)) {
618
- console.log('rawDataRival length:', rawDataRival.length)
619
- if (rawDataRival.length > 0) {
620
- console.log('Primer elemento rivalRef:', rawDataRival[0])
621
- }
622
- }
623
- } else {
624
- console.error('❌ rivalRef NO está disponible')
625
- }
626
-
627
- // Si los refs no están disponibles, podría ser que los componentes estén ocultos con v-show
628
- if (!equipoRef && selectedFortalezasEquipo.value.length > 0) {
629
- console.warn('⚠️ Ref de equipo no disponible, pero hay selecciones')
630
- }
631
- if (!rivalRef && selectedFortalezasRival.value.length > 0) {
632
- console.warn('⚠️ Ref de rival no disponible, pero hay selecciones')
633
- }
634
-
635
- // Obtener todas las fortalezas seleccionadas ordenadas por su orden de selección
636
- const fortalezasEquipoOrdenadas = getOrderedStrengths(selectedFortalezasEquipo.value, equipoRef)
637
- const fortalezasRivalOrdenadas = getOrderedStrengths(selectedFortalezasRival.value, rivalRef)
638
-
639
- console.log('fortalezasEquipoOrdenadas:', fortalezasEquipoOrdenadas)
640
- console.log('fortalezasRivalOrdenadas:', fortalezasRivalOrdenadas)
641
-
642
- // Contadores para rastrear qué fortalezas ya se han asignado
643
- let indexEquipo = 0
644
- let indexRival = 0
645
-
646
- // Iterar sobre todas las páginas del template
647
- props.template.pages.forEach((page, pageIndex) => {
648
- const pageNumber = pageIndex + 1 // Los índices de página empiezan en 1
649
- console.log(`\n=== Página ${pageNumber} ===`)
650
- console.log('Page components:', page.components)
651
-
652
- // Verificar si la página tiene components
653
- if (page.components && Array.isArray(page.components)) {
654
- // Buscar componentes Fortalezas
655
- page.components.forEach((component, componentIndex) => {
656
- if (component.name === 'Fortalezas' || component.id === 15) {
657
- const componentNumber = componentIndex + 1 // Los índices de componente empiezan en 1
658
- console.log(`\n--- Componente ${componentNumber} (Fortalezas) ---`)
659
- console.log('Component:', component)
660
- console.log('dynamicFilters:', component.dynamicFilters)
661
-
662
- // Verificar dynamicFilters para determinar tipo y cantidad
663
- if (component.dynamicFilters && Array.isArray(component.dynamicFilters)) {
664
- const teamType = component.dynamicFilters[0] // 1 = equipo, 2 = rival
665
- const cantidadRequerida = component.dynamicFilters[1] || 0 // Cantidad de fortalezas necesarias
666
-
667
- console.log(
668
- `Tipo: ${teamType === 1 ? 'Equipo' : 'Rival'}, Cantidad requerida: ${cantidadRequerida}`,
669
- )
670
-
671
- // Obtener las fortalezas según el tipo
672
- let fortalezasAsignar = []
673
- let fortalezasOrdenadas = []
674
- let teamId = props.team
675
-
676
- if (teamType === 1) {
677
- // Fortalezas de equipo
678
- fortalezasOrdenadas = fortalezasEquipoOrdenadas
679
- console.log(
680
- `Equipo: Total ordenadas=${fortalezasOrdenadas.length}, index=${indexEquipo}, cantidad requerida=${cantidadRequerida}`,
681
- )
682
- // Tomar las siguientes N fortalezas (donde N = cantidadRequerida)
683
- if (fortalezasOrdenadas.length > indexEquipo) {
684
- fortalezasAsignar = fortalezasOrdenadas.slice(
685
- indexEquipo,
686
- indexEquipo + cantidadRequerida,
687
- )
688
- console.log(
689
- `Index equipo: ${indexEquipo}, tomando ${fortalezasAsignar.length} fortalezas de ${fortalezasOrdenadas.length} disponibles`,
690
- )
691
- } else {
692
- console.warn(
693
- `No hay suficientes fortalezas de equipo. Disponibles: ${fortalezasOrdenadas.length}, Necesarias desde índice: ${indexEquipo}`,
694
- )
695
- }
696
- indexEquipo += cantidadRequerida
697
- teamId = props.partido?.local || props.partido?.home_team || props.team
698
- } else if (teamType === 2) {
699
- // Fortalezas de rival
700
- fortalezasOrdenadas = fortalezasRivalOrdenadas
701
- console.log(
702
- `Rival: Total ordenadas=${fortalezasOrdenadas.length}, index=${indexRival}, cantidad requerida=${cantidadRequerida}`,
703
- )
704
- // Tomar las siguientes N fortalezas (donde N = cantidadRequerida)
705
- if (fortalezasOrdenadas.length > indexRival) {
706
- fortalezasAsignar = fortalezasOrdenadas.slice(
707
- indexRival,
708
- indexRival + cantidadRequerida,
709
- )
710
- console.log(
711
- `Index rival: ${indexRival}, tomando ${fortalezasAsignar.length} fortalezas de ${fortalezasOrdenadas.length} disponibles`,
712
- )
713
- } else {
714
- console.warn(
715
- `No hay suficientes fortalezas de rival. Disponibles: ${fortalezasOrdenadas.length}, Necesarias desde índice: ${indexRival}`,
716
- )
717
- }
718
- indexRival += cantidadRequerida
719
- teamId = props.partido?.visita || props.partido?.visiting_team
720
- }
721
-
722
- console.log('fortalezasAsignar:', fortalezasAsignar)
723
-
724
- // Si hay fortalezas para asignar, agregarlas al payload
725
- if (fortalezasAsignar.length > 0) {
726
- // Inicializar la estructura si no existe
727
- if (!payload[pageNumber]) {
728
- payload[pageNumber] = {}
729
- }
730
- if (!payload[pageNumber][componentNumber]) {
731
- payload[pageNumber][componentNumber] = []
732
- }
733
-
734
- // Agregar las fortalezas con su información completa
735
- fortalezasAsignar.forEach((strength, index) => {
736
- payload[pageNumber][componentNumber].push({
737
- team_id: teamId,
738
- ranking_type: strength.ranking_type || 1,
739
- precondition_id: strength.precondition_id || null,
740
- order: index + 1,
741
- name: strength.name,
742
- category_type: strength.category_type || 1,
743
- total: strength.total || 0,
744
- is_relevant: strength.is_relevant || 0,
745
- league_ranking: strength.league_ranking || 0,
746
- categories: Array.isArray(strength.categories)
747
- ? strength.categories
748
- : [strength.categories],
749
- team_contribution: strength.team_contribution || 0,
750
- })
751
- })
752
- console.log(`✓ Agregadas ${fortalezasAsignar.length} fortalezas al payload`)
753
- } else {
754
- console.warn('No hay fortalezas para asignar a este componente')
755
- }
756
- } else {
757
- console.warn('Componente no tiene dynamicFilters válido')
758
- }
759
- }
760
- })
761
- }
762
- })
763
-
764
- console.log('\n=== PAYLOAD FINAL ===')
765
- console.log(JSON.stringify(payload, null, 2))
766
- return payload
767
- }
768
-
769
- // Función auxiliar para obtener las fortalezas en el mismo orden que fueron seleccionadas
770
- // Los IDs ya vienen en el orden correcto, solo necesitamos obtener los objetos completos
771
- function getOrderedStrengths(selectedIds, fortalezasViewRef) {
772
- console.log('=== getOrderedStrengths INICIO ===')
773
- console.log('selectedIds (orden de selección):', selectedIds)
774
- console.log('fortalezasViewRef existe?:', !!fortalezasViewRef)
775
-
776
- if (!selectedIds || selectedIds.length === 0) {
777
- console.warn('No hay IDs seleccionados')
778
- return []
779
- }
780
-
781
- if (!fortalezasViewRef) {
782
- console.warn('Ref no disponible')
783
- return []
784
- }
785
-
786
- // Obtener fortalezasRawData, verificando si es un ref
787
- let fortalezasRawData = fortalezasViewRef.fortalezasRawData
788
- if (!fortalezasRawData) {
789
- console.warn('fortalezasRawData no está disponible en el ref')
790
- return []
791
- }
792
-
793
- // Si es un ref, acceder a su .value
794
- if (fortalezasRawData && typeof fortalezasRawData === 'object' && 'value' in fortalezasRawData) {
795
- console.log('⚠️ fortalezasRawData es un ref, accediendo a .value')
796
- fortalezasRawData = fortalezasRawData.value
797
- }
798
-
799
- if (!Array.isArray(fortalezasRawData)) {
800
- console.warn('fortalezasRawData no es un array:', typeof fortalezasRawData, fortalezasRawData)
801
- return []
802
- }
803
-
804
- if (fortalezasRawData.length === 0) {
805
- console.warn('fortalezasRawData está vacío')
806
- return []
807
- }
808
-
809
- console.log('fortalezasRawData length:', fortalezasRawData.length)
810
- console.log('Primeras 2 fortalezas raw:', fortalezasRawData.slice(0, 2))
811
-
812
- // Obtener las fortalezas en el mismo orden que fueron seleccionadas (sin reordenar)
813
- // El orden ya está dado por selectedIds, solo necesitamos buscar y devolver el objeto completo
814
- const selectedStrengths = selectedIds
815
- .map((id) => {
816
- console.log(`Buscando ID: ${id} (tipo: ${typeof id})`)
817
-
818
- // Buscar en los datos raw por categories (que es el id que usamos)
819
- const strength = fortalezasRawData.find((item) => {
820
- // Comparar tanto como número como string
821
- const match =
822
- item.categories === id ||
823
- item.categories === Number(id) ||
824
- String(item.categories) === String(id)
825
- if (!match && fortalezasRawData.indexOf(item) < 3) {
826
- console.log(
827
- ` Comparando: item.categories=${item.categories} (${typeof item.categories}) vs id=${id} (${typeof id})`,
828
- )
829
- }
830
- return match
831
- })
832
-
833
- if (strength) {
834
- console.log(`✓ Encontrada: ${strength.name} (categories: ${strength.categories})`)
835
- return strength
836
- }
837
-
838
- console.warn(`✗ No encontrada con categories = ${id}, intentando por id`)
839
- // Intentar buscar también por id si categories no funciona
840
- const strengthById = fortalezasRawData.find(
841
- (item) => item.id === id || item.id === Number(id) || String(item.id) === String(id),
842
- )
843
- if (strengthById) {
844
- console.log(`✓ Encontrada por id: ${strengthById.name}`)
845
- return strengthById
846
- }
847
-
848
- console.error(`✗✗ No se encontró fortaleza con id/categories = ${id}`)
849
- return null
850
- })
851
- .filter(Boolean) // Filtrar los que no se encontraron
852
-
853
- console.log(
854
- `selectedStrengths (${selectedStrengths.length} de ${selectedIds.length} encontradas):`,
855
- selectedStrengths,
856
- )
857
- console.log('=== getOrderedStrengths FIN ===')
858
- return selectedStrengths
859
- }
860
-
861
- function autocompletar() {
862
- const stepMap = buildStepMap()
863
- const key = stepMap[currentStep.value]
864
- if (key === 'fortalezasEquipo' && fortalezasEquipoRef.value)
865
- return fortalezasEquipoRef.value.autocompletar()
866
- if (key === 'fortalezasRival' && fortalezasRivalRef.value)
867
- return fortalezasRivalRef.value.autocompletar()
868
- if (key === 'cornersEquipo' && cornersEquipoRef.value)
869
- return cornersEquipoRef.value.autocompletar()
870
- if (key === 'cornersRival' && cornersRivalRef.value) return cornersRivalRef.value.autocompletar()
871
- }
872
- </script>
873
-
874
- <style scoped>
875
- .modal-overlay {
876
- position: fixed;
877
- top: 0;
878
- left: 0;
879
- width: 100vw;
880
- height: 100vh;
881
- background: rgba(0, 0, 0, 0.45);
882
- display: flex;
883
- align-items: center;
884
- justify-content: center;
885
- z-index: 3300;
886
- }
887
-
888
- .modal-content {
889
- width: 464px;
890
- background: #2e3b46;
891
- border-radius: 10px;
892
- box-shadow: 0 2px 16px 0 rgba(0, 0, 0, 0.18);
893
- padding: 0;
894
- position: relative;
895
- display: flex;
896
- flex-direction: column;
897
- font-family: 'Poppins-Medium', 'Montserrat', sans-serif;
898
- }
899
-
900
- /* Estilos del botón de cerrar removidos */
901
-
902
- .header-separator {
903
- width: 100%;
904
- height: 1px;
905
- border-bottom: dashed 1px #58626b;
906
- margin: 12px 0 0 0;
907
- }
908
-
909
- .modal-header {
910
- display: flex;
911
- align-items: center;
912
- justify-content: space-between;
913
- padding: 20px 24px 0 24px;
914
- }
915
-
916
- .header-left {
917
- display: flex;
918
- align-items: center;
919
- gap: 8px;
920
- }
921
-
922
- .step-counter {
923
- font-family: Poppins-Medium;
924
- font-size: 12px;
925
- font-weight: 500;
926
- color: rgba(255, 255, 255, 0.7);
927
- }
928
-
929
- .icon-title {
930
- width: 16px;
931
- height: 16px;
932
- }
933
-
934
- .modal-title {
935
- font-family: Poppins-Medium;
936
- font-size: 14px;
937
- font-weight: 500;
938
- font-stretch: normal;
939
- font-style: normal;
940
- line-height: 1.5;
941
- letter-spacing: normal;
942
- text-align: left;
943
- color: #fff;
944
- }
945
-
946
- .prepartido-text {
947
- font-family: 'Poppins-Regular', 'BebasNeue', sans-serif;
948
- font-weight: 400;
949
- opacity: 0.7;
950
- letter-spacing: 1px;
951
- }
952
-
953
- .modal-body {
954
- flex: 1;
955
- display: flex;
956
- flex-direction: column;
957
- padding: 12px 24px 0 24px;
958
- margin-bottom: 17px;
959
- margin-top: 5px;
960
- gap: 0;
961
- position: relative;
962
- overflow: hidden;
963
- }
964
-
965
- .step-content {
966
- transition: transform 0.3s ease-in-out;
967
- }
968
-
969
- .modal-body.transitioning .step-content {
970
- transform: translateX(-100%);
971
- }
972
-
973
- .fortalezas-view {
974
- transform: translateX(100%);
975
- animation: slideIn 0.3s ease-in-out forwards;
976
- }
977
-
978
- @keyframes slideIn {
979
- from {
980
- transform: translateX(100%);
981
- }
982
- to {
983
- transform: translateX(0);
984
- }
985
- }
986
-
987
- .content-section {
988
- background: none;
989
- border: solid 1px rgba(255, 255, 255, 0.4);
990
- padding: 12px 20px 20px 20px;
991
- margin-bottom: 0;
992
- border-radius: 8px;
993
- }
994
-
995
- .content-section:first-child {
996
- margin-bottom: 20px;
997
- }
998
-
999
- .title-separator {
1000
- width: 100%;
1001
- height: 1px;
1002
- border-top: 1px dashed rgba(255, 255, 255, 0.3);
1003
- margin: 8px 0 12px 0;
1004
- margin-left: -20px;
1005
- margin-right: -20px;
1006
- width: calc(100% + 40px);
1007
- }
1008
-
1009
- .content-separator {
1010
- width: 100%;
1011
- height: 1px;
1012
- border-top: 1px dashed rgba(255, 255, 255, 0.3);
1013
- margin: 12px 0 16px 0;
1014
- margin-left: -20px;
1015
- margin-right: -20px;
1016
- width: calc(100% + 40px);
1017
- }
1018
-
1019
- .section-title {
1020
- font-family: Poppins-Medium;
1021
- font-size: 14px;
1022
- font-weight: 600;
1023
- opacity: 0.9;
1024
- color: #fff;
1025
- margin: 0 0 12px 0;
1026
- }
1027
-
1028
- .section-description {
1029
- font-family: Poppins-Regular;
1030
- font-size: 12px;
1031
- line-height: 1.4;
1032
- opacity: 0.7;
1033
- color: #fff;
1034
- margin: 0 0 13px 0;
1035
- }
1036
-
1037
- .radio-group {
1038
- display: flex;
1039
- gap: 24px;
1040
- justify-content: center;
1041
- }
1042
-
1043
- .radio-option {
1044
- display: flex;
1045
- align-items: center;
1046
- gap: 8px;
1047
- cursor: pointer;
1048
- user-select: none;
1049
- }
1050
-
1051
- .radio-option input[type='radio'] {
1052
- display: none;
1053
- }
1054
-
1055
- .radio-custom {
1056
- width: 20px;
1057
- height: 20px;
1058
- border: 1px solid #fff;
1059
- border-radius: 50%;
1060
- position: relative;
1061
- transition: all 0.2s ease;
1062
- flex-shrink: 0;
1063
- }
1064
-
1065
- .radio-option input[type='radio']:checked + .radio-custom {
1066
- border-color: #fff; /* mantiene el aro blanco */
1067
- background-color: transparent; /* sin relleno, solo punto central */
1068
- }
1069
-
1070
- .radio-option input[type='radio']:checked + .radio-custom::after {
1071
- content: '';
1072
- position: absolute;
1073
- top: 50%;
1074
- left: 50%;
1075
- transform: translate(-50%, -50%);
1076
- width: 10px;
1077
- height: 10px;
1078
- background-color: #cbee6b; /* punto verde */
1079
- border-radius: 50%;
1080
- }
1081
-
1082
- /* Cuando el radio está seleccionado, la etiqueta pierde la opacidad */
1083
- .radio-option input[type='radio']:checked + .radio-custom + .radio-label {
1084
- opacity: 0.9;
1085
- }
1086
-
1087
- .radio-label {
1088
- font-family: Poppins-Regular;
1089
- font-size: 13px;
1090
- color: #fff;
1091
- opacity: 0.7;
1092
- }
1093
-
1094
- /* Estilos del separador removidos */
1095
-
1096
- .modal-footer {
1097
- display: flex;
1098
- justify-content: space-between;
1099
- align-items: center;
1100
- padding: 0 24px 12px 24px;
1101
- margin-top: 13px;
1102
- }
1103
-
1104
- .footer-actions {
1105
- display: flex;
1106
- align-items: center;
1107
- }
1108
-
1109
- .back-btn {
1110
- background: none;
1111
- border: none;
1112
- color: #fff;
1113
- font-size: 14px;
1114
- font-family: Poppins-Medium;
1115
- display: flex;
1116
- align-items: center;
1117
- gap: 4px;
1118
- cursor: pointer;
1119
- opacity: 0.7;
1120
- padding: 8px 0;
1121
- transition: opacity 0.2s;
1122
- }
1123
-
1124
- .back-btn:hover {
1125
- opacity: 1;
1126
- }
1127
-
1128
- .cancel-btn {
1129
- background: none;
1130
- border: none;
1131
- color: #b0bec5;
1132
- font-size: 14.9px;
1133
- font-family: Poppins-Medium;
1134
- height: 30px;
1135
- border-radius: 64px;
1136
- display: flex;
1137
- align-items: center;
1138
- justify-content: center;
1139
- cursor: pointer;
1140
- padding: 0 18px;
1141
- transition: color 0.2s;
1142
- text-decoration: underline;
1143
- }
1144
-
1145
- .cancel-btn:hover {
1146
- color: #fff;
1147
- }
1148
-
1149
- .next-btn {
1150
- width: 107px;
1151
- height: 30px;
1152
- border-radius: 79.2px;
1153
- -webkit-backdrop-filter: blur(19.8px);
1154
- backdrop-filter: blur(19.8px);
1155
- border: solid 1px #cbee6b;
1156
- background-color: rgba(255, 255, 255, 0.06);
1157
- font-family: Poppins-Medium;
1158
- font-size: 14.9px;
1159
- font-weight: 500;
1160
- color: #fff;
1161
- cursor: pointer;
1162
- transition: background 0.2s;
1163
- display: flex;
1164
- align-items: center;
1165
- justify-content: center;
1166
- }
1167
-
1168
- .next-btn:hover {
1169
- background-color: rgba(255, 255, 255, 0.12);
1170
- }
1171
-
1172
- .next-btn.disabled {
1173
- opacity: 0.5;
1174
- cursor: not-allowed;
1175
- }
1176
-
1177
- .next-btn.disabled:hover {
1178
- background-color: rgba(255, 255, 255, 0.06);
1179
- }
1180
-
1181
- /* Estilos para el modal de confirmación */
1182
- .confirm-dialog {
1183
- width: 380px;
1184
- max-width: 90%;
1185
- }
1186
-
1187
- /* Asegurar que el overlay del modal de confirmación esté por encima del modal principal */
1188
- .modal-overlay:has(.confirm-dialog) {
1189
- z-index: 3400;
1190
- }
1191
-
1192
- .confirm-dialog .modal-header {
1193
- justify-content: center;
1194
- }
1195
-
1196
- .confirm-dialog .modal-body {
1197
- text-align: center;
1198
- }
1199
-
1200
- .confirm-dialog-title {
1201
- font-family: Poppins-Medium;
1202
- font-size: 16px;
1203
- font-weight: 500;
1204
- color: #fff;
1205
- margin: 0 0 12px 0;
1206
- text-align: center;
1207
- }
1208
-
1209
- .confirm-dialog-message {
1210
- font-family: Poppins-Regular;
1211
- font-size: 14px;
1212
- color: rgba(255, 255, 255, 0.7);
1213
- margin: 0;
1214
- text-align: center;
1215
- line-height: 1.5;
1216
- }
1217
-
1218
- .confirm-dialog .modal-footer {
1219
- justify-content: center;
1220
- }
1221
-
1222
- .confirm-dialog .footer-actions {
1223
- width: 100%;
1224
- justify-content: center;
1225
- gap: 12px;
1226
- }
1227
-
1228
- /* Estilos para la vista de fortalezas movidos al componente FortalezasView.vue */
1229
- </style>
1
+ <template>
2
+ <div class="modal-overlay">
3
+ <div class="modal-content">
4
+ <!-- Botón de cerrar removido -->
5
+
6
+ <div class="modal-header">
7
+ <div class="header-left">
8
+ <img
9
+ src="https://golstatsimages.blob.core.windows.net/reports-images/icn-report-white.svg"
10
+ class="icon-title"
11
+ alt="icono reporte blanco"
12
+ />
13
+ <span class="modal-title"
14
+ >Generar reporte&nbsp; - &nbsp; <span class="prepartido-text">Prepartido</span></span
15
+ >
16
+ </div>
17
+ <div class="step-counter">
18
+ Paso {{ currentStep === 0 ? 1 : currentStep }} de {{ totalSteps }}
19
+ </div>
20
+ </div>
21
+ <div class="header-separator"></div>
22
+ <div class="modal-body" :class="{ transitioning: isTransitioning }">
23
+ <!-- Paso 0: Configuración inicial de opciones -->
24
+ <div v-if="currentStep === 0" class="step-content">
25
+ <!-- Sección Fortalezas - Solo se muestra si existen Fortalezas en el template -->
26
+ <div v-if="hasFortalezas" class="content-section">
27
+ <h3 class="section-title">Fortalezas</h3>
28
+ <div class="title-separator"></div>
29
+ <p class="section-description">
30
+ Este template contiene {{ fortalezasCounts.equipo }} visualizaciones de Fortalezas de
31
+ tu equipo y {{ fortalezasCounts.rival }} de tu rival. ¿Cómo prefieres que se agregue
32
+ este contenido?
33
+ </p>
34
+ <div class="content-separator"></div>
35
+ <div class="radio-group">
36
+ <label class="radio-option">
37
+ <input
38
+ type="radio"
39
+ name="fortalezas"
40
+ value="automatico"
41
+ v-model="fortalezasOption"
42
+ />
43
+ <span class="radio-custom"></span>
44
+ <span class="radio-label">Automáticamente</span>
45
+ </label>
46
+ <label class="radio-option">
47
+ <input type="radio" name="fortalezas" value="manual" v-model="fortalezasOption" />
48
+ <span class="radio-custom"></span>
49
+ <span class="radio-label">Manualmente</span>
50
+ </label>
51
+ </div>
52
+ </div>
53
+
54
+ <!-- Separador removido -->
55
+
56
+ <!-- Sección Tiros de esquina - OCULTA POR EL MOMENTO -->
57
+ <!-- <div v-if="hasCorners" class="content-section">
58
+ <h3 class="section-title">Tiros de esquina</h3>
59
+ <div class="title-separator"></div>
60
+ <p class="section-description">
61
+ Este template contiene 10 visualizaciones de Tiros de esquina de tu equipo. ¿Cómo
62
+ prefieres que se agregue este contenido?
63
+ </p>
64
+ <div class="content-separator"></div>
65
+ <div class="radio-group">
66
+ <label class="radio-option">
67
+ <input
68
+ type="radio"
69
+ name="tiros-esquina"
70
+ value="automatico"
71
+ v-model="tirosEsquinaOption"
72
+ />
73
+ <span class="radio-custom"></span>
74
+ <span class="radio-label">Automáticamente</span>
75
+ </label>
76
+ <label class="radio-option">
77
+ <input
78
+ type="radio"
79
+ name="tiros-esquina"
80
+ value="manual"
81
+ v-model="tirosEsquinaOption"
82
+ />
83
+ <span class="radio-custom"></span>
84
+ <span class="radio-label">Manualmente</span>
85
+ </label>
86
+ </div>
87
+ </div> -->
88
+ </div>
89
+
90
+ <!-- Pasos dinámicos renderizados por clave -->
91
+ <!-- Usamos v-show en lugar de v-if para mantener los componentes montados y preservar el estado -->
92
+ <template v-if="fortalezasCounts.equipo > 0">
93
+ <div v-show="buildStepMap()[currentStep] === 'fortalezasEquipo'" class="step-content">
94
+ <FortalezasView
95
+ key="fortalezas-equipo"
96
+ v-model="selectedFortalezasEquipo"
97
+ team-initials="AME"
98
+ :season-id="1772"
99
+ :team-id="props.partido?.local || props.partido?.home_team"
100
+ :rival-team-id="props.partido?.visita || props.partido?.visiting_team"
101
+ :token="props.token"
102
+ title="Fortalezas a favor de mi equipo"
103
+ :total-fortalezas="fortalezasCounts.equipo"
104
+ ref="fortalezasEquipoRef"
105
+ />
106
+ </div>
107
+ </template>
108
+
109
+ <template v-if="fortalezasCounts.rival > 0">
110
+ <div v-show="buildStepMap()[currentStep] === 'fortalezasRival'" class="step-content">
111
+ <FortalezasView
112
+ key="fortalezas-rival"
113
+ v-model="selectedFortalezasRival"
114
+ team-initials="RIV"
115
+ :season-id="1772"
116
+ :team-id="props.partido?.visita || props.partido?.visiting_team"
117
+ :rival-team-id="props.partido?.local || props.partido?.home_team"
118
+ :token="props.token"
119
+ title="Fortalezas a favor del rival"
120
+ :total-fortalezas="fortalezasCounts.rival"
121
+ ref="fortalezasRivalRef"
122
+ />
123
+ </div>
124
+ </template>
125
+
126
+ <div v-if="buildStepMap()[currentStep] === 'cornersEquipo'" class="step-content">
127
+ <TirosEsquinaView
128
+ v-model="selectedCornersEquipo"
129
+ :rival="false"
130
+ team-initials="AME"
131
+ title="Tiros de esquina en contra de mi equipo"
132
+ team-logo-url="https://golstatsimages.blob.core.windows.net/teams-80/2.png"
133
+ ref="cornersEquipoRef"
134
+ />
135
+ </div>
136
+
137
+ <div v-if="buildStepMap()[currentStep] === 'cornersRival'" class="step-content">
138
+ <TirosEsquinaView
139
+ v-model="selectedCornersRival"
140
+ :rival="true"
141
+ team-initials="RIV"
142
+ title="Tiros de esquina en contra del rival"
143
+ team-logo-url="https://golstatsimages.blob.core.windows.net/teams-80/1.png"
144
+ ref="cornersRivalRef"
145
+ />
146
+ </div>
147
+ </div>
148
+ <div class="header-separator"></div>
149
+ <div class="modal-footer">
150
+ <button class="back-btn" @click="goBack">
151
+ <svg
152
+ width="16"
153
+ height="16"
154
+ viewBox="0 0 16 16"
155
+ fill="none"
156
+ xmlns="http://www.w3.org/2000/svg"
157
+ >
158
+ <path
159
+ d="M10 12L6 8L10 4"
160
+ stroke="white"
161
+ stroke-width="2"
162
+ stroke-linecap="round"
163
+ stroke-linejoin="round"
164
+ />
165
+ </svg>
166
+ Regresar
167
+ </button>
168
+ <div class="footer-actions">
169
+ <button v-if="currentStep === 0" class="cancel-btn" @click="closeModal">Cancelar</button>
170
+ <button
171
+ v-if="currentStep === 1 || currentStep === 2"
172
+ class="cancel-btn"
173
+ @click="autocompletar"
174
+ >
175
+ Autocompletar
176
+ </button>
177
+ <button
178
+ class="next-btn"
179
+ :class="{ disabled: !canContinue }"
180
+ :disabled="!canContinue"
181
+ @click="continueToNext"
182
+ >
183
+ {{
184
+ currentStep === 0
185
+ ? fortalezasOption === 'automatico'
186
+ ? 'Finalizar'
187
+ : 'Siguiente'
188
+ : currentStep === totalSteps
189
+ ? 'Finalizar'
190
+ : 'Siguiente'
191
+ }}
192
+ </button>
193
+ </div>
194
+ </div>
195
+ </div>
196
+ </div>
197
+
198
+ <!-- Modal de confirmación para regresar al paso 0 -->
199
+ <div v-if="showConfirmDialog" class="modal-overlay" @click.self="cancelGoBack">
200
+ <div class="modal-content confirm-dialog">
201
+ <div class="modal-header">
202
+ <div class="header-left">
203
+ <span class="modal-title">Confirmación</span>
204
+ </div>
205
+ </div>
206
+ <div class="header-separator"></div>
207
+ <div class="modal-body">
208
+ <div class="step-content">
209
+ <h3 class="confirm-dialog-title">¿Estás seguro de regresar?</h3>
210
+ <p class="confirm-dialog-message">Se perderá la información seleccionada</p>
211
+ </div>
212
+ </div>
213
+ <div class="modal-footer">
214
+ <div class="footer-actions">
215
+ <button class="cancel-btn" @click="cancelGoBack">Cancelar</button>
216
+ <button class="next-btn" @click="confirmGoBackToStep0">Confirmar</button>
217
+ </div>
218
+ </div>
219
+ </div>
220
+ </div>
221
+ </template>
222
+
223
+ <script setup>
224
+ import { ref, defineEmits, computed, nextTick } from 'vue'
225
+ import FortalezasView from './FortalezasView.vue'
226
+ import TirosEsquinaView from './TirosEsquinaView.vue'
227
+
228
+ const emit = defineEmits(['close', 'back', 'next'])
229
+
230
+ // Props para controlar el número de pasos
231
+ const props = defineProps({
232
+ hasRival: {
233
+ type: Boolean,
234
+ default: true,
235
+ },
236
+ token: {
237
+ type: String,
238
+ required: true,
239
+ },
240
+ template: {
241
+ type: Object,
242
+ required: false,
243
+ default: null,
244
+ },
245
+ team: {
246
+ type: Number,
247
+ required: false,
248
+ default: null,
249
+ },
250
+ partido: {
251
+ type: Object,
252
+ required: false,
253
+ default: null,
254
+ },
255
+ })
256
+
257
+ // Función para verificar si existe un componente Fortalezas en el template
258
+ function tieneComponenteFortalezas() {
259
+ if (!props.template || !props.template.pages) {
260
+ return false
261
+ }
262
+
263
+ // Iterar sobre todas las pages del template
264
+ for (const page of props.template.pages) {
265
+ // Verificar si la page tiene components
266
+ if (page.components && Array.isArray(page.components)) {
267
+ // Buscar si existe algún componente con name === 'Fortalezas' o id === 15
268
+ const tieneFortalezas = page.components.some(
269
+ (component) => component.name === 'Fortalezas' || component.id === 15,
270
+ )
271
+ if (tieneFortalezas) {
272
+ return true
273
+ }
274
+ }
275
+ }
276
+
277
+ return false
278
+ }
279
+
280
+ // Función para contar Fortalezas del equipo propio y del rival
281
+ function contarFortalezas() {
282
+ console.log(
283
+ '5555555555555555 Nuevo Valor al crear fortalezas:: : : :: : : : :: : : :',
284
+ props.template,
285
+ )
286
+ if (!props.template || !props.template.pages) {
287
+ return { equipo: 0, rival: 0, total: 0 }
288
+ }
289
+ console.log('Nuevo Valor al crear fortalezas:: : : :: : : : :: : : :', props.template)
290
+
291
+ let countEquipo = 0
292
+ let countRival = 0
293
+
294
+ // Iterar sobre todas las pages del template
295
+ for (const page of props.template.pages) {
296
+ console.log('page 11 5555555555555555555555555555555555 ', page)
297
+ // Verificar si la page tiene components
298
+ if (page.components && Array.isArray(page.components)) {
299
+ console.log('page entro')
300
+ // Filtrar componentes Fortalezas
301
+ const componentesFortalezas = page.components.filter(
302
+ (component) =>
303
+ component.componentName === 'GSCStrengths' ||
304
+ component.id === 15 ||
305
+ component.name === 'Fortalezas',
306
+ )
307
+ console.log(
308
+ 'componentesFortalezas componentesFortalezas componentesFortalezas',
309
+ componentesFortalezas,
310
+ )
311
+ // Para cada componente Fortalezas, verificar dynamicFilters
312
+ for (const component of componentesFortalezas) {
313
+ // Verificar si tiene dynamicFilters y es un array
314
+ if (component.dynamicFilters && Array.isArray(component.dynamicFilters)) {
315
+ // Verificar la posición 1 (que es un array)
316
+ if (component.dynamicFilters[1]) {
317
+ // Consultar la posición 0 para determinar si es equipo propio (1) o rival (2)
318
+ if (component.dynamicFilters[0] === 1) {
319
+ countEquipo += component.dynamicFilters[1]
320
+ } else if (component.dynamicFilters[0] === 2) {
321
+ countRival += component.dynamicFilters[1]
322
+ } else {
323
+ if (component.dynamicFilters[0] === 3) {
324
+ if (component.filterMultiple.isHomeTeam) {
325
+ countEquipo += component.dynamicFilters[1]
326
+ } else {
327
+ countRival += component.dynamicFilters[1]
328
+ }
329
+ }
330
+ }
331
+ }
332
+ }
333
+ }
334
+ }
335
+ }
336
+
337
+ return {
338
+ equipo: countEquipo,
339
+ rival: countRival,
340
+ total: countEquipo + countRival,
341
+ }
342
+ }
343
+
344
+ // Computed para verificar si tiene Fortalezas
345
+ const hasFortalezas = computed(() => tieneComponenteFortalezas())
346
+
347
+ // Computed para obtener los conteos de Fortalezas
348
+ const fortalezasCounts = computed(() => contarFortalezas())
349
+
350
+ // const hasCorners = false // OCULTO POR EL MOMENTO
351
+ // Estado del modal
352
+ const currentStep = ref(0) // 0 = configuración inicial, luego pasos dinámicos
353
+ const isTransitioning = ref(false)
354
+
355
+ // Modal de confirmación para regresar al paso 0
356
+ const showConfirmDialog = ref(false)
357
+
358
+ // Opciones seleccionadas para cada sección
359
+ const fortalezasOption = ref('manual')
360
+ const tirosEsquinaOption = ref('manual')
361
+
362
+ // Selecciones por vista
363
+ const selectedFortalezasEquipo = ref([])
364
+ const selectedFortalezasRival = ref([])
365
+ const selectedCornersEquipo = ref([])
366
+ const selectedCornersRival = ref([])
367
+
368
+ // Calcular el número total de pasos
369
+ const totalSteps = computed(() => {
370
+ let steps = 0
371
+
372
+ // Pasos de Fortalezas
373
+ if (hasFortalezas.value && fortalezasOption.value === 'manual') {
374
+ // Si hay fortalezas de equipo, agregar paso 1
375
+ if (fortalezasCounts.value.equipo > 0) {
376
+ steps += 1
377
+ }
378
+ // Si hay fortalezas de rival, agregar paso (será 2 si hay equipo, 1 si no hay)
379
+ if (fortalezasCounts.value.rival > 0) {
380
+ steps += 1
381
+ }
382
+ }
383
+
384
+ // Pasos de Tiros de esquina - OCULTOS POR EL MOMENTO
385
+ // if (tirosEsquinaOption.value === 'manual') {
386
+ // steps += props.hasRival ? 2 : 1
387
+ // }
388
+
389
+ return Math.max(steps, 1)
390
+ })
391
+
392
+ // Verificar si se puede continuar al siguiente paso
393
+ const canContinue = computed(() => {
394
+ if (currentStep.value === 0) {
395
+ // Si no hay Fortalezas, no se puede continuar (tirosEsquina está oculto)
396
+ if (!hasFortalezas.value) {
397
+ return false
398
+ }
399
+ // Puede continuar si está en automático o en manual
400
+ return fortalezasOption.value === 'automatico' || fortalezasOption.value === 'manual'
401
+ }
402
+ const stepMap = buildStepMap()
403
+ const key = stepMap[currentStep.value]
404
+
405
+ if (key === 'fortalezasEquipo') {
406
+ const ref = fortalezasEquipoRef.value
407
+ if (!ref) return false
408
+ const selected = selectedFortalezasEquipo.value.length
409
+ const totalRequerido = fortalezasCounts.value.equipo
410
+ // Obtener el total de fortalezas disponibles del componente
411
+ const totalDisponibles = ref.fortalezasData?.length || 0
412
+
413
+ // Puede continuar si:
414
+ // 1. Selecciona el total exacto requerido
415
+ // 2. O si no hay suficientes disponibles, selecciona todos los disponibles
416
+ return (
417
+ selected === totalRequerido ||
418
+ (totalDisponibles > 0 && totalDisponibles < totalRequerido && selected === totalDisponibles)
419
+ )
420
+ }
421
+
422
+ if (key === 'fortalezasRival') {
423
+ const ref = fortalezasRivalRef.value
424
+ if (!ref) return false
425
+ const selected = selectedFortalezasRival.value.length
426
+ const totalRequerido = fortalezasCounts.value.rival
427
+ // Obtener el total de fortalezas disponibles del componente
428
+ const totalDisponibles = ref.fortalezasData?.length || 0
429
+
430
+ // Puede continuar si:
431
+ // 1. Selecciona el total exacto requerido
432
+ // 2. O si no hay suficientes disponibles, selecciona todos los disponibles
433
+ return (
434
+ selected === totalRequerido ||
435
+ (totalDisponibles > 0 && totalDisponibles < totalRequerido && selected === totalDisponibles)
436
+ )
437
+ }
438
+
439
+ // Pasos de corners ocultos
440
+ // if (key === 'cornersEquipo') return selectedCornersEquipo.value.length > 0
441
+ // if (key === 'cornersRival') return selectedCornersRival.value.length > 0
442
+ return false
443
+ })
444
+
445
+ function buildStepMap() {
446
+ const order = []
447
+
448
+ // Solo agregar pasos de Fortalezas si existen en el template y está en modo manual
449
+ if (hasFortalezas.value && fortalezasOption.value === 'manual') {
450
+ // Si hay fortalezas de equipo, agregar paso de equipo
451
+ if (fortalezasCounts.value.equipo > 0) {
452
+ order.push('fortalezasEquipo')
453
+ }
454
+ // Si hay fortalezas de rival, agregar paso de rival
455
+ if (fortalezasCounts.value.rival > 0) {
456
+ order.push('fortalezasRival')
457
+ }
458
+ }
459
+
460
+ // Pasos de Tiros de esquina - OCULTOS POR EL MOMENTO
461
+ // if (tirosEsquinaOption.value === 'manual') {
462
+ // order.push('cornersEquipo')
463
+ // if (props.hasRival) order.push('cornersRival')
464
+ // }
465
+
466
+ const map = {}
467
+ order.forEach((k, idx) => {
468
+ map[idx + 1] = k // pasos empiezan en 1
469
+ })
470
+ return map
471
+ }
472
+
473
+ // Referencias a los componentes
474
+ const fortalezasEquipoRef = ref(null)
475
+ const fortalezasRivalRef = ref(null)
476
+ const cornersEquipoRef = ref(null)
477
+ const cornersRivalRef = ref(null)
478
+
479
+ function closeModal() {
480
+ emit('close')
481
+ }
482
+
483
+ function goBack() {
484
+ if (currentStep.value > 1) {
485
+ // Si estamos en paso 2 o superior, solo regresar sin borrar selecciones
486
+ currentStep.value--
487
+ } else if (currentStep.value === 1) {
488
+ // Si estamos en paso 1 y vamos al paso 0, mostrar modal de confirmación
489
+ // Verificar si hay selecciones antes de mostrar el modal
490
+ const tieneSelecciones =
491
+ selectedFortalezasEquipo.value.length > 0 || selectedFortalezasRival.value.length > 0
492
+
493
+ if (tieneSelecciones) {
494
+ showConfirmDialog.value = true
495
+ } else {
496
+ // Si no hay selecciones, regresar directamente
497
+ currentStep.value--
498
+ }
499
+ } else {
500
+ // Si estamos en paso 0, emitir evento back
501
+ emit('back')
502
+ }
503
+ }
504
+
505
+ function confirmGoBackToStep0() {
506
+ // Limpiar todas las selecciones
507
+ selectedFortalezasEquipo.value = []
508
+ selectedFortalezasRival.value = []
509
+ selectedCornersEquipo.value = []
510
+ selectedCornersRival.value = []
511
+
512
+ // Cerrar el modal de confirmación
513
+ showConfirmDialog.value = false
514
+
515
+ // Regresar al paso 0
516
+ currentStep.value--
517
+ }
518
+
519
+ function cancelGoBack() {
520
+ // Cerrar el modal de confirmación sin hacer nada
521
+ showConfirmDialog.value = false
522
+ }
523
+
524
+ async function continueToNext() {
525
+ if (currentStep.value === 0) {
526
+ // Validar que al menos una opción esté seleccionada
527
+ if (!canContinue.value) {
528
+ return
529
+ }
530
+
531
+ // Si está en automático, finalizar directamente sin construir payload
532
+ if (fortalezasOption.value === 'automatico') {
533
+ // Emitir evento sin payload de strengths (se generarán automáticamente)
534
+ emit('next', {
535
+ fortalezas: fortalezasOption.value,
536
+ tirosEsquina: tirosEsquinaOption.value,
537
+ selectedFortalezasEquipo: [],
538
+ selectedFortalezasRival: [],
539
+ strengthsPayload: {}, // Payload vacío para modo automático
540
+ })
541
+ return
542
+ }
543
+
544
+ // Si es manual, avanzar al siguiente paso
545
+ // Animar transición
546
+ isTransitioning.value = true
547
+ setTimeout(() => {
548
+ currentStep.value++
549
+ isTransitioning.value = false
550
+ }, 300)
551
+ } else if (currentStep.value < totalSteps.value) {
552
+ // Avanzar al siguiente paso
553
+ isTransitioning.value = true
554
+ setTimeout(() => {
555
+ currentStep.value++
556
+ isTransitioning.value = false
557
+ }, 300)
558
+ } else {
559
+ // Esperar un tick para asegurar que los refs estén disponibles
560
+ await nextTick()
561
+
562
+ // Construir el payload de fortalezas antes de emitir
563
+ const strengthsPayload = buildStrengthsPayload()
564
+ console.log('Estructura de strengths emitida:', JSON.stringify(strengthsPayload, null, 2))
565
+
566
+ // Emitir evento con las opciones seleccionadas y el payload de fortalezas
567
+ emit('next', {
568
+ fortalezas: fortalezasOption.value,
569
+ tirosEsquina: tirosEsquinaOption.value,
570
+ selectedFortalezasEquipo: selectedFortalezasEquipo.value,
571
+ selectedFortalezasRival: selectedFortalezasRival.value,
572
+ strengthsPayload,
573
+ })
574
+ }
575
+ }
576
+
577
+ // Función para construir el payload de fortalezas según la estructura requerida
578
+ function buildStrengthsPayload() {
579
+ console.log('=== INICIANDO buildStrengthsPayload ===')
580
+ console.log('Template:', props.template)
581
+ console.log('Template pages:', props.template?.pages)
582
+
583
+ if (!props.template || !props.template.pages) {
584
+ console.warn('No hay template o pages')
585
+ return {}
586
+ }
587
+
588
+ const payload = {}
589
+
590
+ console.log('selectedFortalezasEquipo:', selectedFortalezasEquipo.value)
591
+ console.log('selectedFortalezasRival:', selectedFortalezasRival.value)
592
+ console.log('fortalezasEquipoRef:', fortalezasEquipoRef.value)
593
+ console.log('fortalezasRivalRef:', fortalezasRivalRef.value)
594
+
595
+ // Verificar si los refs están disponibles
596
+ let equipoRef = fortalezasEquipoRef.value
597
+ let rivalRef = fortalezasRivalRef.value
598
+
599
+ // Debug detallado de los refs
600
+ if (equipoRef) {
601
+ console.log('equipoRef keys:', Object.keys(equipoRef))
602
+ console.log('equipoRef.fortalezasRawData:', equipoRef.fortalezasRawData)
603
+ console.log('equipoRef.fortalezasRawData type:', typeof equipoRef.fortalezasRawData)
604
+
605
+ // Verificar si es un ref (tiene .value)
606
+ let rawDataEquipo = equipoRef.fortalezasRawData
607
+ if (rawDataEquipo && typeof rawDataEquipo === 'object' && 'value' in rawDataEquipo) {
608
+ console.log('⚠️ fortalezasRawData es un ref, usando .value')
609
+ rawDataEquipo = rawDataEquipo.value
610
+ }
611
+
612
+ console.log('rawDataEquipo después de verificar ref:', rawDataEquipo)
613
+ console.log('rawDataEquipo is array:', Array.isArray(rawDataEquipo))
614
+ if (Array.isArray(rawDataEquipo)) {
615
+ console.log('rawDataEquipo length:', rawDataEquipo.length)
616
+ if (rawDataEquipo.length > 0) {
617
+ console.log('Primer elemento equipoRef:', rawDataEquipo[0])
618
+ }
619
+ }
620
+ } else {
621
+ console.error('❌ equipoRef NO está disponible')
622
+ }
623
+
624
+ if (rivalRef) {
625
+ console.log('rivalRef keys:', Object.keys(rivalRef))
626
+ console.log('rivalRef.fortalezasRawData:', rivalRef.fortalezasRawData)
627
+ console.log('rivalRef.fortalezasRawData type:', typeof rivalRef.fortalezasRawData)
628
+
629
+ // Verificar si es un ref (tiene .value)
630
+ let rawDataRival = rivalRef.fortalezasRawData
631
+ if (rawDataRival && typeof rawDataRival === 'object' && 'value' in rawDataRival) {
632
+ console.log('⚠️ fortalezasRawData es un ref, usando .value')
633
+ rawDataRival = rawDataRival.value
634
+ }
635
+
636
+ console.log('rawDataRival después de verificar ref:', rawDataRival)
637
+ console.log('rawDataRival is array:', Array.isArray(rawDataRival))
638
+ if (Array.isArray(rawDataRival)) {
639
+ console.log('rawDataRival length:', rawDataRival.length)
640
+ if (rawDataRival.length > 0) {
641
+ console.log('Primer elemento rivalRef:', rawDataRival[0])
642
+ }
643
+ }
644
+ } else {
645
+ console.error('❌ rivalRef NO está disponible')
646
+ }
647
+
648
+ // Si los refs no están disponibles, podría ser que los componentes estén ocultos con v-show
649
+ if (!equipoRef && selectedFortalezasEquipo.value.length > 0) {
650
+ console.warn('⚠️ Ref de equipo no disponible, pero hay selecciones')
651
+ }
652
+ if (!rivalRef && selectedFortalezasRival.value.length > 0) {
653
+ console.warn('⚠️ Ref de rival no disponible, pero hay selecciones')
654
+ }
655
+
656
+ // Obtener todas las fortalezas seleccionadas ordenadas por su orden de selección
657
+ const fortalezasEquipoOrdenadas = getOrderedStrengths(selectedFortalezasEquipo.value, equipoRef)
658
+ const fortalezasRivalOrdenadas = getOrderedStrengths(selectedFortalezasRival.value, rivalRef)
659
+
660
+ console.log('fortalezasEquipoOrdenadas:', fortalezasEquipoOrdenadas)
661
+ console.log('fortalezasRivalOrdenadas:', fortalezasRivalOrdenadas)
662
+
663
+ // Contadores para rastrear qué fortalezas ya se han asignado
664
+ let indexEquipo = 0
665
+ let indexRival = 0
666
+
667
+ // Iterar sobre todas las páginas del template
668
+ props.template.pages.forEach((page, pageIndex) => {
669
+ const pageNumber = pageIndex + 1 // Los índices de página empiezan en 1
670
+ console.log(`\n=== Página ${pageNumber} ===`)
671
+ console.log('Page components:', page.components)
672
+
673
+ // Verificar si la página tiene components
674
+ if (page.components && Array.isArray(page.components)) {
675
+ // Buscar componentes Fortalezas
676
+ page.components.forEach((component, componentIndex) => {
677
+ if (component.name === 'Fortalezas' || component.id === 15) {
678
+ const componentNumber = componentIndex + 1 // Los índices de componente empiezan en 1
679
+ console.log(`\n--- Componente ${componentNumber} (Fortalezas) ---`)
680
+ console.log('Component:', component)
681
+ console.log('dynamicFilters:', component.dynamicFilters)
682
+
683
+ // Verificar dynamicFilters para determinar tipo y cantidad
684
+ if (component.dynamicFilters && Array.isArray(component.dynamicFilters)) {
685
+ const teamType = component.dynamicFilters[0] // 1 = equipo, 2 = rival
686
+ const cantidadRequerida = component.dynamicFilters[1] || 0 // Cantidad de fortalezas necesarias
687
+
688
+ console.log(
689
+ `Tipo: ${teamType === 1 ? 'Equipo' : 'Rival'}, Cantidad requerida: ${cantidadRequerida}`,
690
+ )
691
+
692
+ // Obtener las fortalezas según el tipo
693
+ let fortalezasAsignar = []
694
+ let fortalezasOrdenadas = []
695
+ let teamId = props.team
696
+
697
+ if (teamType === 1) {
698
+ // Fortalezas de equipo
699
+ fortalezasOrdenadas = fortalezasEquipoOrdenadas
700
+ console.log(
701
+ `Equipo: Total ordenadas=${fortalezasOrdenadas.length}, index=${indexEquipo}, cantidad requerida=${cantidadRequerida}`,
702
+ )
703
+ // Tomar las siguientes N fortalezas (donde N = cantidadRequerida)
704
+ if (fortalezasOrdenadas.length > indexEquipo) {
705
+ fortalezasAsignar = fortalezasOrdenadas.slice(
706
+ indexEquipo,
707
+ indexEquipo + cantidadRequerida,
708
+ )
709
+ console.log(
710
+ `Index equipo: ${indexEquipo}, tomando ${fortalezasAsignar.length} fortalezas de ${fortalezasOrdenadas.length} disponibles`,
711
+ )
712
+ } else {
713
+ console.warn(
714
+ `No hay suficientes fortalezas de equipo. Disponibles: ${fortalezasOrdenadas.length}, Necesarias desde índice: ${indexEquipo}`,
715
+ )
716
+ }
717
+ indexEquipo += cantidadRequerida
718
+ teamId = props.partido?.local || props.partido?.home_team || props.team
719
+ } else if (teamType === 2) {
720
+ // Fortalezas de rival
721
+ fortalezasOrdenadas = fortalezasRivalOrdenadas
722
+ console.log(
723
+ `Rival: Total ordenadas=${fortalezasOrdenadas.length}, index=${indexRival}, cantidad requerida=${cantidadRequerida}`,
724
+ )
725
+ // Tomar las siguientes N fortalezas (donde N = cantidadRequerida)
726
+ if (fortalezasOrdenadas.length > indexRival) {
727
+ fortalezasAsignar = fortalezasOrdenadas.slice(
728
+ indexRival,
729
+ indexRival + cantidadRequerida,
730
+ )
731
+ console.log(
732
+ `Index rival: ${indexRival}, tomando ${fortalezasAsignar.length} fortalezas de ${fortalezasOrdenadas.length} disponibles`,
733
+ )
734
+ } else {
735
+ console.warn(
736
+ `No hay suficientes fortalezas de rival. Disponibles: ${fortalezasOrdenadas.length}, Necesarias desde índice: ${indexRival}`,
737
+ )
738
+ }
739
+ indexRival += cantidadRequerida
740
+ teamId = props.partido?.visita || props.partido?.visiting_team
741
+ }
742
+
743
+ console.log('fortalezasAsignar:', fortalezasAsignar)
744
+
745
+ // Si hay fortalezas para asignar, agregarlas al payload
746
+ if (fortalezasAsignar.length > 0) {
747
+ // Inicializar la estructura si no existe
748
+ if (!payload[pageNumber]) {
749
+ payload[pageNumber] = {}
750
+ }
751
+ if (!payload[pageNumber][componentNumber]) {
752
+ payload[pageNumber][componentNumber] = []
753
+ }
754
+
755
+ // Agregar las fortalezas con su información completa
756
+ fortalezasAsignar.forEach((strength, index) => {
757
+ payload[pageNumber][componentNumber].push({
758
+ team_id: teamId,
759
+ ranking_type: strength.ranking_type || 1,
760
+ precondition_id: strength.precondition_id || null,
761
+ order: index + 1,
762
+ name: strength.name,
763
+ category_type: strength.category_type || 1,
764
+ total: strength.total || 0,
765
+ is_relevant: strength.is_relevant || 0,
766
+ league_ranking: strength.league_ranking || 0,
767
+ categories: Array.isArray(strength.categories)
768
+ ? strength.categories
769
+ : [strength.categories],
770
+ team_contribution: strength.team_contribution || 0,
771
+ })
772
+ })
773
+ console.log(`✓ Agregadas ${fortalezasAsignar.length} fortalezas al payload`)
774
+ } else {
775
+ console.warn('No hay fortalezas para asignar a este componente')
776
+ }
777
+ } else {
778
+ console.warn('Componente no tiene dynamicFilters válido')
779
+ }
780
+ }
781
+ })
782
+ }
783
+ })
784
+
785
+ console.log('\n=== PAYLOAD FINAL ===')
786
+ console.log(JSON.stringify(payload, null, 2))
787
+ return payload
788
+ }
789
+
790
+ // Función auxiliar para obtener las fortalezas en el mismo orden que fueron seleccionadas
791
+ // Los IDs ya vienen en el orden correcto, solo necesitamos obtener los objetos completos
792
+ function getOrderedStrengths(selectedIds, fortalezasViewRef) {
793
+ console.log('=== getOrderedStrengths INICIO ===')
794
+ console.log('selectedIds (orden de selección):', selectedIds)
795
+ console.log('fortalezasViewRef existe?:', !!fortalezasViewRef)
796
+
797
+ if (!selectedIds || selectedIds.length === 0) {
798
+ console.warn('No hay IDs seleccionados')
799
+ return []
800
+ }
801
+
802
+ if (!fortalezasViewRef) {
803
+ console.warn('Ref no disponible')
804
+ return []
805
+ }
806
+
807
+ // Obtener fortalezasRawData, verificando si es un ref
808
+ let fortalezasRawData = fortalezasViewRef.fortalezasRawData
809
+ if (!fortalezasRawData) {
810
+ console.warn('fortalezasRawData no está disponible en el ref')
811
+ return []
812
+ }
813
+
814
+ // Si es un ref, acceder a su .value
815
+ if (fortalezasRawData && typeof fortalezasRawData === 'object' && 'value' in fortalezasRawData) {
816
+ console.log('⚠️ fortalezasRawData es un ref, accediendo a .value')
817
+ fortalezasRawData = fortalezasRawData.value
818
+ }
819
+
820
+ if (!Array.isArray(fortalezasRawData)) {
821
+ console.warn('fortalezasRawData no es un array:', typeof fortalezasRawData, fortalezasRawData)
822
+ return []
823
+ }
824
+
825
+ if (fortalezasRawData.length === 0) {
826
+ console.warn('fortalezasRawData está vacío')
827
+ return []
828
+ }
829
+
830
+ console.log('fortalezasRawData length:', fortalezasRawData.length)
831
+ console.log('Primeras 2 fortalezas raw:', fortalezasRawData.slice(0, 2))
832
+
833
+ // Obtener las fortalezas en el mismo orden que fueron seleccionadas (sin reordenar)
834
+ // El orden ya está dado por selectedIds, solo necesitamos buscar y devolver el objeto completo
835
+ const selectedStrengths = selectedIds
836
+ .map((id) => {
837
+ console.log(`Buscando ID: ${id} (tipo: ${typeof id})`)
838
+
839
+ // Buscar en los datos raw por categories (que es el id que usamos)
840
+ const strength = fortalezasRawData.find((item) => {
841
+ // Comparar tanto como número como string
842
+ const match =
843
+ item.categories === id ||
844
+ item.categories === Number(id) ||
845
+ String(item.categories) === String(id)
846
+ if (!match && fortalezasRawData.indexOf(item) < 3) {
847
+ console.log(
848
+ ` Comparando: item.categories=${item.categories} (${typeof item.categories}) vs id=${id} (${typeof id})`,
849
+ )
850
+ }
851
+ return match
852
+ })
853
+
854
+ if (strength) {
855
+ console.log(`✓ Encontrada: ${strength.name} (categories: ${strength.categories})`)
856
+ return strength
857
+ }
858
+
859
+ console.warn(`✗ No encontrada con categories = ${id}, intentando por id`)
860
+ // Intentar buscar también por id si categories no funciona
861
+ const strengthById = fortalezasRawData.find(
862
+ (item) => item.id === id || item.id === Number(id) || String(item.id) === String(id),
863
+ )
864
+ if (strengthById) {
865
+ console.log(`✓ Encontrada por id: ${strengthById.name}`)
866
+ return strengthById
867
+ }
868
+
869
+ console.error(`✗✗ No se encontró fortaleza con id/categories = ${id}`)
870
+ return null
871
+ })
872
+ .filter(Boolean) // Filtrar los que no se encontraron
873
+
874
+ console.log(
875
+ `selectedStrengths (${selectedStrengths.length} de ${selectedIds.length} encontradas):`,
876
+ selectedStrengths,
877
+ )
878
+ console.log('=== getOrderedStrengths FIN ===')
879
+ return selectedStrengths
880
+ }
881
+
882
+ function autocompletar() {
883
+ const stepMap = buildStepMap()
884
+ const key = stepMap[currentStep.value]
885
+ if (key === 'fortalezasEquipo' && fortalezasEquipoRef.value)
886
+ return fortalezasEquipoRef.value.autocompletar()
887
+ if (key === 'fortalezasRival' && fortalezasRivalRef.value)
888
+ return fortalezasRivalRef.value.autocompletar()
889
+ if (key === 'cornersEquipo' && cornersEquipoRef.value)
890
+ return cornersEquipoRef.value.autocompletar()
891
+ if (key === 'cornersRival' && cornersRivalRef.value) return cornersRivalRef.value.autocompletar()
892
+ }
893
+ </script>
894
+
895
+ <style scoped>
896
+ .modal-overlay {
897
+ position: fixed;
898
+ top: 0;
899
+ left: 0;
900
+ width: 100vw;
901
+ height: 100vh;
902
+ background: rgba(0, 0, 0, 0.45);
903
+ display: flex;
904
+ align-items: center;
905
+ justify-content: center;
906
+ z-index: 3300;
907
+ }
908
+
909
+ .modal-content {
910
+ width: 464px;
911
+ background: #2e3b46;
912
+ border-radius: 10px;
913
+ box-shadow: 0 2px 16px 0 rgba(0, 0, 0, 0.18);
914
+ padding: 0;
915
+ position: relative;
916
+ display: flex;
917
+ flex-direction: column;
918
+ font-family: 'Poppins-Medium', 'Montserrat', sans-serif;
919
+ }
920
+
921
+ /* Estilos del botón de cerrar removidos */
922
+
923
+ .header-separator {
924
+ width: 100%;
925
+ height: 1px;
926
+ border-bottom: dashed 1px #58626b;
927
+ margin: 12px 0 0 0;
928
+ }
929
+
930
+ .modal-header {
931
+ display: flex;
932
+ align-items: center;
933
+ justify-content: space-between;
934
+ padding: 20px 24px 0 24px;
935
+ }
936
+
937
+ .header-left {
938
+ display: flex;
939
+ align-items: center;
940
+ gap: 8px;
941
+ }
942
+
943
+ .step-counter {
944
+ font-family: Poppins-Medium;
945
+ font-size: 12px;
946
+ font-weight: 500;
947
+ color: rgba(255, 255, 255, 0.7);
948
+ }
949
+
950
+ .icon-title {
951
+ width: 16px;
952
+ height: 16px;
953
+ }
954
+
955
+ .modal-title {
956
+ font-family: Poppins-Medium;
957
+ font-size: 14px;
958
+ font-weight: 500;
959
+ font-stretch: normal;
960
+ font-style: normal;
961
+ line-height: 1.5;
962
+ letter-spacing: normal;
963
+ text-align: left;
964
+ color: #fff;
965
+ }
966
+
967
+ .prepartido-text {
968
+ font-family: 'Poppins-Regular', 'BebasNeue', sans-serif;
969
+ font-weight: 400;
970
+ opacity: 0.7;
971
+ letter-spacing: 1px;
972
+ }
973
+
974
+ .modal-body {
975
+ flex: 1;
976
+ display: flex;
977
+ flex-direction: column;
978
+ padding: 12px 24px 0 24px;
979
+ margin-bottom: 17px;
980
+ margin-top: 5px;
981
+ gap: 0;
982
+ position: relative;
983
+ overflow: hidden;
984
+ }
985
+
986
+ .step-content {
987
+ transition: transform 0.3s ease-in-out;
988
+ }
989
+
990
+ .modal-body.transitioning .step-content {
991
+ transform: translateX(-100%);
992
+ }
993
+
994
+ .fortalezas-view {
995
+ transform: translateX(100%);
996
+ animation: slideIn 0.3s ease-in-out forwards;
997
+ }
998
+
999
+ @keyframes slideIn {
1000
+ from {
1001
+ transform: translateX(100%);
1002
+ }
1003
+ to {
1004
+ transform: translateX(0);
1005
+ }
1006
+ }
1007
+
1008
+ .content-section {
1009
+ background: none;
1010
+ border: solid 1px rgba(255, 255, 255, 0.4);
1011
+ padding: 12px 20px 20px 20px;
1012
+ margin-bottom: 0;
1013
+ border-radius: 8px;
1014
+ }
1015
+
1016
+ .content-section:first-child {
1017
+ margin-bottom: 20px;
1018
+ }
1019
+
1020
+ .title-separator {
1021
+ width: 100%;
1022
+ height: 1px;
1023
+ border-top: 1px dashed rgba(255, 255, 255, 0.3);
1024
+ margin: 8px 0 12px 0;
1025
+ margin-left: -20px;
1026
+ margin-right: -20px;
1027
+ width: calc(100% + 40px);
1028
+ }
1029
+
1030
+ .content-separator {
1031
+ width: 100%;
1032
+ height: 1px;
1033
+ border-top: 1px dashed rgba(255, 255, 255, 0.3);
1034
+ margin: 12px 0 16px 0;
1035
+ margin-left: -20px;
1036
+ margin-right: -20px;
1037
+ width: calc(100% + 40px);
1038
+ }
1039
+
1040
+ .section-title {
1041
+ font-family: Poppins-Medium;
1042
+ font-size: 14px;
1043
+ font-weight: 600;
1044
+ opacity: 0.9;
1045
+ color: #fff;
1046
+ margin: 0 0 12px 0;
1047
+ }
1048
+
1049
+ .section-description {
1050
+ font-family: Poppins-Regular;
1051
+ font-size: 12px;
1052
+ line-height: 1.4;
1053
+ opacity: 0.7;
1054
+ color: #fff;
1055
+ margin: 0 0 13px 0;
1056
+ }
1057
+
1058
+ .radio-group {
1059
+ display: flex;
1060
+ gap: 24px;
1061
+ justify-content: center;
1062
+ }
1063
+
1064
+ .radio-option {
1065
+ display: flex;
1066
+ align-items: center;
1067
+ gap: 8px;
1068
+ cursor: pointer;
1069
+ user-select: none;
1070
+ }
1071
+
1072
+ .radio-option input[type='radio'] {
1073
+ display: none;
1074
+ }
1075
+
1076
+ .radio-custom {
1077
+ width: 20px;
1078
+ height: 20px;
1079
+ border: 1px solid #fff;
1080
+ border-radius: 50%;
1081
+ position: relative;
1082
+ transition: all 0.2s ease;
1083
+ flex-shrink: 0;
1084
+ }
1085
+
1086
+ .radio-option input[type='radio']:checked + .radio-custom {
1087
+ border-color: #fff; /* mantiene el aro blanco */
1088
+ background-color: transparent; /* sin relleno, solo punto central */
1089
+ }
1090
+
1091
+ .radio-option input[type='radio']:checked + .radio-custom::after {
1092
+ content: '';
1093
+ position: absolute;
1094
+ top: 50%;
1095
+ left: 50%;
1096
+ transform: translate(-50%, -50%);
1097
+ width: 10px;
1098
+ height: 10px;
1099
+ background-color: #cbee6b; /* punto verde */
1100
+ border-radius: 50%;
1101
+ }
1102
+
1103
+ /* Cuando el radio está seleccionado, la etiqueta pierde la opacidad */
1104
+ .radio-option input[type='radio']:checked + .radio-custom + .radio-label {
1105
+ opacity: 0.9;
1106
+ }
1107
+
1108
+ .radio-label {
1109
+ font-family: Poppins-Regular;
1110
+ font-size: 13px;
1111
+ color: #fff;
1112
+ opacity: 0.7;
1113
+ }
1114
+
1115
+ /* Estilos del separador removidos */
1116
+
1117
+ .modal-footer {
1118
+ display: flex;
1119
+ justify-content: space-between;
1120
+ align-items: center;
1121
+ padding: 0 24px 12px 24px;
1122
+ margin-top: 13px;
1123
+ }
1124
+
1125
+ .footer-actions {
1126
+ display: flex;
1127
+ align-items: center;
1128
+ }
1129
+
1130
+ .back-btn {
1131
+ background: none;
1132
+ border: none;
1133
+ color: #fff;
1134
+ font-size: 14px;
1135
+ font-family: Poppins-Medium;
1136
+ display: flex;
1137
+ align-items: center;
1138
+ gap: 4px;
1139
+ cursor: pointer;
1140
+ opacity: 0.7;
1141
+ padding: 8px 0;
1142
+ transition: opacity 0.2s;
1143
+ }
1144
+
1145
+ .back-btn:hover {
1146
+ opacity: 1;
1147
+ }
1148
+
1149
+ .cancel-btn {
1150
+ background: none;
1151
+ border: none;
1152
+ color: #b0bec5;
1153
+ font-size: 14.9px;
1154
+ font-family: Poppins-Medium;
1155
+ height: 30px;
1156
+ border-radius: 64px;
1157
+ display: flex;
1158
+ align-items: center;
1159
+ justify-content: center;
1160
+ cursor: pointer;
1161
+ padding: 0 18px;
1162
+ transition: color 0.2s;
1163
+ text-decoration: underline;
1164
+ }
1165
+
1166
+ .cancel-btn:hover {
1167
+ color: #fff;
1168
+ }
1169
+
1170
+ .next-btn {
1171
+ width: 107px;
1172
+ height: 30px;
1173
+ border-radius: 79.2px;
1174
+ -webkit-backdrop-filter: blur(19.8px);
1175
+ backdrop-filter: blur(19.8px);
1176
+ border: solid 1px #cbee6b;
1177
+ background-color: rgba(255, 255, 255, 0.06);
1178
+ font-family: Poppins-Medium;
1179
+ font-size: 14.9px;
1180
+ font-weight: 500;
1181
+ color: #fff;
1182
+ cursor: pointer;
1183
+ transition: background 0.2s;
1184
+ display: flex;
1185
+ align-items: center;
1186
+ justify-content: center;
1187
+ }
1188
+
1189
+ .next-btn:hover {
1190
+ background-color: rgba(255, 255, 255, 0.12);
1191
+ }
1192
+
1193
+ .next-btn.disabled {
1194
+ opacity: 0.5;
1195
+ cursor: not-allowed;
1196
+ }
1197
+
1198
+ .next-btn.disabled:hover {
1199
+ background-color: rgba(255, 255, 255, 0.06);
1200
+ }
1201
+
1202
+ /* Estilos para el modal de confirmación */
1203
+ .confirm-dialog {
1204
+ width: 380px;
1205
+ max-width: 90%;
1206
+ }
1207
+
1208
+ /* Asegurar que el overlay del modal de confirmación esté por encima del modal principal */
1209
+ .modal-overlay:has(.confirm-dialog) {
1210
+ z-index: 3400;
1211
+ }
1212
+
1213
+ .confirm-dialog .modal-header {
1214
+ justify-content: center;
1215
+ }
1216
+
1217
+ .confirm-dialog .modal-body {
1218
+ text-align: center;
1219
+ }
1220
+
1221
+ .confirm-dialog-title {
1222
+ font-family: Poppins-Medium;
1223
+ font-size: 16px;
1224
+ font-weight: 500;
1225
+ color: #fff;
1226
+ margin: 0 0 12px 0;
1227
+ text-align: center;
1228
+ }
1229
+
1230
+ .confirm-dialog-message {
1231
+ font-family: Poppins-Regular;
1232
+ font-size: 14px;
1233
+ color: rgba(255, 255, 255, 0.7);
1234
+ margin: 0;
1235
+ text-align: center;
1236
+ line-height: 1.5;
1237
+ }
1238
+
1239
+ .confirm-dialog .modal-footer {
1240
+ justify-content: center;
1241
+ }
1242
+
1243
+ .confirm-dialog .footer-actions {
1244
+ width: 100%;
1245
+ justify-content: center;
1246
+ gap: 12px;
1247
+ }
1248
+
1249
+ /* Estilos para la vista de fortalezas movidos al componente FortalezasView.vue */
1250
+ </style>