1<#-- ACTUALIZACIÓN DE ESTADOS 06/07/2026 -->
2<#-- ACTUALIZACIÓN DE SOLICITUD 05/08/2026 -->
3<#-- ACTUALIZACIÓN Y MODIFICACIÓN DE SOLICITUD 10/08/2026 -->
4<#-- ACTUALIZACIÓN Y MODIFICACIÓN DE SOLICITUD CERTIFICADO 10/08/2026 -->
5
6<#macro renderizarPorExtension docField={} tipoPermitido="todos"> 7 <#assign tieneArchivosValidos = false />
8 <div class="repac-documents-grid">
9 <#if docField?? && docField?has_content && docField.getSiblings?? && docField.getSiblings()?has_content>
10 <#list docField.getSiblings() as cur_doc>
11 <#if cur_doc?? && cur_doc.getData()?has_content && cur_doc.getData()?trim != "">
12 <#assign docRaw = cur_doc.getData()?trim />
13 <#assign docUrl = "" />
14 <#assign docName = "Ver Archivo" />
15
16 <#-- Extracción de URL y Nombre desde JSON -->
17 <#attempt>
18 <#if docRaw?starts_with("{") && docRaw?ends_with("}")> 19 <#assign docJson = jsonFactoryUtil.createJSONObject(docRaw) />
20 <#if docJson.getString("title")?has_content> 21 <#assign docName = docJson.getString("title") /> 22 </#if>
23 <#if docJson.getString("url")?has_content> 24 <#assign docUrl = docJson.getString("url") /> 25 <#elseif docJson.getString("uuid")?has_content && docJson.getString("groupId")?has_content> 26 <#assign docUrl = "/documents/" + docJson.getString("groupId") + "/0/" + (docName?url) + "/" + docJson.getString("uuid") /> 27 </#if>
28 <#else>
29 <#assign docUrl = (docRaw?starts_with("/") || docRaw?starts_with("http"))?then(docRaw, "/documents/" + groupId + "/" + docRaw) /> 30 </#if>
31 <#recover>
32 <#assign docUrl = docRaw />
33 </#attempt>
34
35 <#-- Limpieza del nombre desde la URL decodificando UTF-8 y tildes -->
36<#attempt>
37 <#if docName == "Ver Archivo" && docUrl?contains("/")> 38 <#list docUrl?split("/") as segmento> 39 <#if segmento?contains(".") && !segmento?starts_with("?")> 40 <#-- Decodificar caracteres -->
41 <#assign segmentoDecodificado = httpUtil.decodeURL(segmento) />
42 <#assign nombreLimpio = segmentoDecodificado?replace("+", " ") /> 43 <#assign docName = nombreLimpio?contains("?")?then(nombreLimpio?keep_before("?"), nombreLimpio) /> 44 </#if>
45 </#list>
46 </#if>
47<#recover>
48 <#assign docName = "Ver Archivo" />
49</#attempt>
50
51 <#-- Extracción de extensión -->
52 <#assign ext = docName?keep_after_last(".")?lower_case /> 53
54 <#-- EVALUACIÓN DE FILTRO E ÍCONO -->
55 <#assign esValido = false />
56 <#assign docIcon = "fa-file-pdf" />
57
58 <#if tipoPermitido == "pdf" && (ext == "pdf" || ext == "")>
59 <#assign esValido = true />
60 <#assign docIcon = "fa-file-pdf" />
61 <#elseif tipoPermitido == "csv" && (ext == "csv" || ext == "xls" || ext == "xlsx" || ext == "")>
62 <#assign esValido = true />
63 <#assign docIcon = (ext == "csv")?then("fa-file-csv", "fa-file-excel") /> 64 <#elseif tipoPermitido == "todos">
65 <#assign esValido = true />
66 <#if ext == "pdf"><#assign docIcon = "fa-file-pdf" />
67 <#elseif ext == "csv"><#assign docIcon = "fa-file-csv" />
68 <#elseif ext == "xls" || ext == "xlsx"><#assign docIcon = "fa-file-excel" />
69 <#else><#assign docIcon = "fa-file-alt" />
70 </#if>
71 </#if>
72
73 <#-- RENDERIZADO DEL BOTÓN -->
74 <#if esValido>
75 <#assign tieneArchivosValidos = true />
76 <div class="grid-document-card">
77 <a href="${docUrl}" class="btn-recap-grid-item" target="_blank" title="${docName}"> 78 <i class="fas ${docIcon}"></i> <span class="grid-doc-text">${docName}</span> 79 </a>
80 <div class="grid-doc-date-sub" style="font-size: 0.72rem; color: #666666; display: flex; align-items: center; justify-content: center; gap: 4px; font-style: italic; margin-top: 4px;">
81 <i class="far fa-calendar-check" style="color: #003366; font-size: 0.85rem;"></i> Act: ${dateUtil.getDate(fechaModObj, "dd MMM yyyy", locale)} 82 </div>
83 </div>
84 </#if>
85 </#if>
86 </#list>
87 </#if>
88 </div>
89
90 <#if !tieneArchivosValidos>
91 <div class="repac-no-files-msg">No se han subido o cargado archivos del proceso de consulta.</div>
92 </#if>
93</#macro>
94
95<#assign dlAppService = serviceLocator.findService("com.liferay.document.library.kernel.service.DLAppService") /> 96<#assign fechaModificacion = .vars['reserved-article-modified-date'].getData()>
97<#assign fechaModObj = dateUtil.parseDate("EEE, dd MMM yyyy HH:mm:ss Z", fechaModificacion, locale)> 98
99<#assign estadoActual = "" />
100<#if Estado?? && Estado.getData()?has_content>
101 <#assign estadoActual = Estado.getData()?trim?lower_case />
102</#if>
103
104<#-- EXTRAER URL DEL FORMULARIO DESDE ENLACEFORMULARIO -->
105<#assign urlFormularioEmbed = "" />
106<#if EnlaceFormulario?? && EnlaceFormulario.getData()?has_content>
107 <#assign urlFormularioEmbed = EnlaceFormulario.getData()?trim />
108</#if>
109
110<#-- VALIDA EL CIERRE SI EL ESTADO ACTUAL ES ABIERTO -->
111<#assign valorFechaFin = FechaFin.getData()!"" />
112<#if valorFechaFin?has_content && estadoActual == "abierto">
113 <#attempt>
114 <#assign diaInt = 0 />
115 <#assign mesInt = 0 />
116 <#assign anioInt = 0 />
117
118 <#if valorFechaFin?contains("-")> 119 <#assign partes = valorFechaFin?split("-") /> 120 <#if (partes?size >= 3)>
121 <#assign anioInt = partes[0]?number />
122 <#assign mesInt = partes[1]?number />
123 <#assign diaInt = partes[2]?number />
124 </#if>
125 <#elseif valorFechaFin?contains("/")> 126 <#assign partes = valorFechaFin?split("/") /> 127 <#if (partes?size >= 3)>
128 <#assign diaInt = partes[0]?number />
129 <#assign mesInt = partes[1]?number />
130 <#assign anioInt = partes[2]?number />
131 </#if>
132 </#if>
133
134 <#assign anioActual = .now?string("yyyy")?number /> 135 <#assign mesActual = .now?string("MM")?number /> 136 <#assign diaActual = .now?string("dd")?number /> 137
138 <#if (anioInt > 0)>
139 <#if (anioActual > anioInt)>
140 <#assign estadoActual = "cerrado" />
141 <#elseif (anioActual == anioInt && mesActual > mesInt)>
142 <#assign estadoActual = "cerrado" />
143 <#elseif (anioActual == anioInt && mesActual == mesInt && diaActual > diaInt)>
144 <#assign estadoActual = "cerrado" />
145 </#if>
146 </#if>
147 <#recover>
148 </#attempt>
149</#if>
150
151<#-- ESTILOS Y MENSAJES SEGÚN ESTADO -->
152<#assign stClass = "st-Finalizado">
153<#assign stLabel = "Finalizado">
154<#assign stColorBold = "#dc3545">
155<#assign stColorLight = "#fdf2f2">
156<#assign stMsg = "Esta consulta se encuentra Finalizada. Puede consultar el análisis de observaciones y los soportes en la sección de documentos del proceso.">
157
158<#if estadoActual == "abierto">
159 <#assign stClass = "st-Abierto">
160 <#assign stLabel = "Abierto">
161 <#assign stColorBold = "#28a745">
162 <#assign stColorLight = "#e6f4ea">
163 <#assign stLink = "Aquí">
164
165 <#if urlFormularioEmbed?has_content>
166 <#assign stUrl = "#formulario-repac-${.vars['reserved-article-id'].getData()}" /> 167 <#assign stMsg = "Esta consulta se encuentra Abierta desde el <b>${FechaInicio.getData()}</b> hasta el <b>${FechaFin.getData()}</b>, puede ingresar sus observaciones y comentarios haciendo clic <a href='${stUrl}' class='scroll-suave-repac' style='color:${stColorBold}; font-weight:bold;'><b>${stLink}</b></a> para diligenciar el formulario embebido."> 168 <#else>
169 <#assign stMsg = "Esta consulta se encuentra Abierta desde el <b>${FechaInicio.getData()}</b> hasta el <b>${FechaFin.getData()}</b>."> 170 </#if>
171
172<#elseif estadoActual == "cerrado">
173 <#assign stClass = "st-Cerrado">
174 <#assign stLabel = "Cerrado">
175 <#assign stColorBold = "#f57f17">
176 <#assign stColorLight = "#fff9e6">
177 <#assign stMsg = "Esta consulta se encuentra en proceso de revisión de observaciones por parte de la unidad responsable.">
178</#if>
179
180<div class="recap-card">
181
182 <div class="recap-top-header">
183 <h2 class="recap-title-text">${(NombreProyecto.getData())!"Proyecto sin nombre"}</h2> 184 <div class="status-badge">
185 <span class="dot"></span> ${stLabel} 186 </div>
187 </div>
188
189 <div class="recap-alert-msg">
190 <i class="fas fa-info-circle" style="color: ${stColorBold}; margin-right: 8px;"></i> ${stMsg} 191 </div>
192
193 <#-- BARRA DE INTERACCIÓN Y CERTIFICADO PDF -->
194 <#if estadoActual == "finalizado">
195 <#assign fechaActual = .now />
196 <#assign fechaImpresion = fechaActual?string["dd 'de' MMMM 'de' yyyy"] />
197 <#assign horaImpresion = fechaActual?string["hh:mm:ss a"] />
198
199 <div class="recap-social-bar">
200 <button onclick="descargarCertificadoInmediato('${.vars['reserved-article-id'].getData()}')" class="social-item btn-interaction" style="background: none; border: none; cursor: pointer; padding: 0;"> 201 <i class="fa-solid fa-certificate"></i> <span>Generar Certificado</span>
202 </button>
203 <button onclick="abrirModalCompartirURL()" class="social-item btn-interaction">
204 <i class="fas fa-share-alt"></i> <span>Compartir</span>
205 </button>
206 </div>
207
208 <#-- MODAL COMPARTIR -->
209 <div id="modal-compartir-repac" class="repac-mini-modal-overlay" style="display: none;">
210 <div class="repac-mini-modal-box">
211 <div class="repac-mini-modal-header">
212 <strong style="color:#003366;">Compartir Proyecto Normativo</strong>
213 <button onclick="cerrarModalCompartirURL()" class="repac-modal-close-btn">×</button>
214 </div>
215 <div class="repac-mini-modal-body">
216 <p style="color:#003366;">Copia el enlace permanente para compartir el estado final del proyecto:</p>
217
218 <div class="repac-url-container">
219 <input type="text" id="input-url-actual-repac" readonly>
220 <button onclick="copiarUrlAlPortapapeles()" id="btn-copiar-repac">
221 <i class="fa-regular fa-copy" style="color:#fff;"></i> Copiar
222 </button>
223 </div>
224
225 <div class="repac-modal-social-icons">
226 <a id="share-wa" target="_blank" title="Compartir en WhatsApp"><i class="fa-brands fa-whatsapp"></i></a>
227 <a id="share-fb" target="_blank" title="Compartir en Facebook"><i class="fa-brands fa-facebook-f"></i></a>
228 <a id="share-tw" target="_blank" title="Compartir en X (Twitter)"><i class="fa-brands fa-x-twitter"></i></a>
229 </div>
230 </div>
231 </div>
232 </div>
233
234 <#-- LÓGICA DE DETECCIÓN DE ENLACES PARA EL CERTIFICADO PDF -->
235 <#global htmlEnlacesComentarios = "" />
236 <#global cantidadComentarios = 0 />
237
238 <#macro procesarEnlaceParaPDF docField>
239 <#if docField?? && docField?has_content && docField.getSiblings?? && docField.getSiblings()?has_content>
240 <#list docField.getSiblings() as cur_doc>
241 <#if cur_doc?? && cur_doc.getData()?has_content && cur_doc.getData()?trim != "">
242 <#assign docRaw = cur_doc.getData()?trim />
243 <#assign docUrl = "" />
244 <#assign docName = "Ver Archivo" />
245 <#attempt>
246 <#if docRaw?starts_with("{") && docRaw?ends_with("}")> 247 <#assign docJson = jsonFactoryUtil.createJSONObject(docRaw) />
248 <#if docJson.getString("title")?has_content><#assign docName = docJson.getString("title") /></#if> 249 <#if docJson.getString("url")?has_content> 250 <#assign docUrl = docJson.getString("url") /> 251 <#elseif docJson.getString("uuid")?has_content && docJson.getString("groupId")?has_content> 252 <#assign docUrl = "/documents/" + docJson.getString("groupId") + "/0/" + (docName?url) + "/" + docJson.getString("uuid") /> 253 </#if>
254 <#else>
255 <#assign docUrl = (docRaw?starts_with("/") || docRaw?starts_with("http"))?then(docRaw, "/documents/" + groupId + "/" + docRaw) /> 256 </#if>
257 <#recover>
258 <#assign docUrl = docRaw />
259 </#attempt>
260
261 <#if docUrl != "">
262 <#assign urlAbsoluta = docUrl />
263 <#attempt>
264 <#if docUrl?starts_with("/") && themeDisplay??> 265 <#assign urlAbsoluta = themeDisplay.getPortalURL() + docUrl />
266 </#if>
267 <#recover></#attempt>
268
269 <#global htmlEnlacesComentarios = htmlEnlacesComentarios + "<div style='margin-bottom: 5px;'><a href='" + urlAbsoluta + "' style='color:#0151a1; font-size: 12px; font-weight: bold; text-decoration: none; word-break: break-all;'> " + docName + "</a></div>" />
270 <#global cantidadComentarios = cantidadComentarios + 1 />
271 </#if>
272 </#if>
273 </#list>
274 </#if>
275 </#macro>
276
277 <#if DocumentosDelProcesoDeConsultaPDF??><@procesarEnlaceParaPDF docField=DocumentosDelProcesoDeConsultaPDF!{} /></#if> 278 <#if DocumentosDelProcesoDeConsultaPdf??><@procesarEnlaceParaPDF docField=DocumentosDelProcesoDeConsultaPdf!{} /></#if> 279 <#if DocumentosDelProcesoDeConsultaCsv??><@procesarEnlaceParaPDF docField=DocumentosDelProcesoDeConsultaCsv!{} /></#if> 280 <#if DocumentosDelProcesoDeConsultaExcel??><@procesarEnlaceParaPDF docField=DocumentosDelProcesoDeConsultaExcel!{} /></#if> 281 <#if DocumentosDelProcesoDeConsulta??><@procesarEnlaceParaPDF docField=DocumentosDelProcesoDeConsulta!{} /></#if> 282 <#if DocumentosDelProceso??><@procesarEnlaceParaPDF docField=DocumentosDelProceso!{} /></#if> 283
284 <#-- CONTENEDOR CERTIFICADO PDF -->
285 <#assign colorPrincipal = "#0151a1">
286 <#assign colorTexto = "#4b4b4b">
287 <#assign colorFooter = "#374151">
288 <#assign tituloPrincipal = "EL CONSEJO SUPERIOR DE LA JUDICATURA">
289 <#assign textoUnidad = "Certifica que la unidad">
290 <#assign textoParticipacion = "dispuso para conocimiento y participación de los ciudadanos entre las fechas:">
291 <#assign textoProyecto = "el proyecto">
292 <#assign textoURL = "El proyecto fue publicado en la siguiente enlace:">
293 <#assign textoFirma = "Cordialmente,">
294 <#assign firmaEntidad = "PRESIDENCIA CONSEJO SUPERIOR DE LA JUDICATURA">
295 <#assign unidadResponsable = UnidadResponsable.getData()!"">
296 <#assign nombreProyecto = NombreProyecto.getData()!.vars['reserved-article-title'].getData()>
297 <#assign urlProyecto = (EnlaceFinalDelProyecto.getData())!"" />
298 <#assign fechaInicioFormat = FechaInicio.getData()?date("yyyy-MM-dd")?string("dd 'de' MMMM 'de' yyyy")> 299 <#assign fechaFinFormat = FechaFin.getData()?date("yyyy-MM-dd")?string("dd 'de' MMMM 'de' yyyy")> 300
301 <div style="position:absolute; left:-9999px; top:0;">
302 <div id="certificado-documento-${.vars['reserved-article-id'].getData()}" class="certificado-pdf"> 303 <div class="pdf-header">
304 <div class="header-left">
305 <img src="/o/csj-main-theme/images/color_schemes/default/rama-judicial/logo-rama_judicial.png" alt="Rama Judicial">
306 </div>
307 <div class="header-center">
308 <h1>RAMA JUDICIAL DE COLOMBIA</h1>
309 <h2>CONSEJO SUPERIOR DE LA JUDICATURA</h2>
310 </div>
311 <div class="header-right">
312 <div class="badge-repac">${.vars['reserved-article-id'].getData()}</div> 313 </div>
314 </div>
315 <div class="header-line"></div>
316 <div style="text-align:center; margin-top:10px;">
317 <p style="color:#4b5563; font-size:20px; font-weight:700; margin:0; text-transform:uppercase;">CERTIFICADO DE PARTICIPACIÓN CIUDADANA</p>
318 <p style="color:#6b7280; font-size:12px; font-weight:600; margin-top:6px; margin-bottom:0; text-transform:uppercase;">Id del Sistema: ${.vars['reserved-article-id'].getData()}</p> 319 </div>
320 <div class="certificado-header">
321 <h1>${tituloPrincipal}</h1> 322 </div>
323 <div class="certificado-body">
324 <p class="label-bold">${textoUnidad}</p> 325 <p class="unidad">${unidadResponsable}</p> 326 <p class="label-bold">${textoParticipacion}</p> 327 <p class="fechas">(${fechaInicioFormat} - ${fechaFinFormat})</p> 328 <p class="label-bold">${textoProyecto}</p> 329 <div class="proyecto">${nombreProyecto}</div> 330
331 <#if (cantidadComentarios > 0)>
332 <p class="label-bold" style="margin-top: 15px; margin-bottom: 10px;">junto con la publicación del informe de comentarios y respuestas en los siguientes enlaces:</p>
333 <div style="margin-bottom: 25px; padding: 10px; background-color: #f8fafc; border: 1px solid #e2e8f0; border-radius: 6px;">
334 ${htmlEnlacesComentarios} 335 </div>
336 <#else>
337 <p class="label-bold" style="margin-top: 15px; margin-bottom: 25px; font-style: italic; color: #6b7280;">No se recibió comentarios a través de la plataforma</p>
338 </#if>
339
340 <p class="label-bold">${textoURL}</p> 341 <p class="url-proyecto">${urlProyecto}</p> 342 </div>
343 <div class="footer-certificado">
344 <p>${textoFirma}</p> 345 <p class="footer-firma">${firmaEntidad}</p> 346 <p class="fecha-generacion">Certificado generado el ${fechaImpresion}</p> 347 <p class="label-bold">Registro electrónico automático del sitio web de participación ciudadana</p>
348 <div class="linea-final"></div>
349 </div>
350 </div>
351 </div>
352
353 <script src="https://cdnjs.cloudflare.com/ajax/libs/html2pdf.js/0.10.1/html2pdf.bundle.min.js"></script>
354 <script>
355 function abrirModalCompartirURL() { 356 const urlActual = window.location.href;
357 document.getElementById('input-url-actual-repac').value = urlActual; 358 document.getElementById('share-wa').href = "https://api.whatsapp.com/send?text=" + encodeURIComponent("Consulte el Proyecto Normativo en la Rama Judicial: " + urlActual); 359 document.getElementById('share-fb').href = "https://www.facebook.com/sharer/sharer.php?u=" + encodeURIComponent(urlActual); 360 document.getElementById('share-tw').href = "https://twitter.com/intent/tweet?url=" + encodeURIComponent(urlActual) + "&text=" + encodeURIComponent("Proyecto Normativo - Consulta Ciudadana REPAC"); 361 document.getElementById('modal-compartir-repac').style.display = 'flex'; 362 }
363
364 function cerrarModalCompartirURL() { 365 document.getElementById('modal-compartir-repac').style.display = 'none'; 366 const btn = document.getElementById('btn-copiar-repac'); 367 btn.innerHTML = '<i class="fa-regular fa-copy"></i> Copiar';
368 btn.style.background = '#003399';
369 }
370
371 function copiarUrlAlPortapapeles() { 372 const inputUrl = document.getElementById('input-url-actual-repac'); 373 inputUrl.select();
374 inputUrl.setSelectionRange(0, 99999);
375 navigator.clipboard.writeText(inputUrl.value).then(() => { 376 const btn = document.getElementById('btn-copiar-repac'); 377 btn.innerHTML = '<i class="fa-solid fa-check"></i> ¡Copiado!';
378 btn.style.background = '#2e7d32';
379 }).catch(err => console.error('Error al copiar:', err)); 380 }
381
382 function descargarCertificadoInmediato(articleId){ 383 const elemento = document.getElementById('certificado-documento-' + articleId); 384 const opciones = { 385 margin: 0,
386 filename: 'Certificado_' + articleId + '.pdf',
387 image: { type: 'jpeg', quality: 1 }, 388 html2canvas: { scale: 2, useCORS: true, logging: false, scrollY: 0, backgroundColor: '#ffffff' }, 389 jsPDF: { unit: 'mm', format: 'a4', orientation: 'portrait' } 390 };
391 html2pdf().set(opciones).from(elemento).save();
392 }
393
394 window.onclick = function(event) { 395 const modal = document.getElementById('modal-compartir-repac'); 396 if (event.target == modal) cerrarModalCompartirURL();
397 }
398 </script>
399 </#if>
400
401 <div style="height: 15px; background: transparent;"></div>
402 <div class="recap-body">
403
404 <div class="recap-grid">
405 <div class="info-box">
406 <strong>Fecha Inicio:</strong>
407 <span>
408 <#if FechaInicio?? && FechaInicio.getData() != "">
409 <#assign fI_Data = getterUtil.getString(FechaInicio.getData())>
410 <#assign fI_Obj = dateUtil.parseDate("yyyy-MM-dd", fI_Data, locale)> 411 ${dateUtil.getDate(fI_Obj, "dd MMM yyyy", locale)} 412 <#else>No definida</#if>
413 </span>
414 </div>
415 <div class="info-box">
416 <strong>Fecha Fin:</strong>
417 <span>
418 <#if FechaFin?? && FechaFin.getData() != "">
419 <#assign fF_Data = getterUtil.getString(FechaFin.getData())>
420 <#assign fF_Obj = dateUtil.parseDate("yyyy-MM-dd", fF_Data, locale)> 421 ${dateUtil.getDate(fF_Obj, "dd MMM yyyy", locale)} 422 <#else>No definida</#if>
423 </span>
424 </div>
425 <div class="info-box"><strong>Contacto:</strong> <span>${(Contacto.getData())!"N/A"}</span></div> 426 <div class="info-box"><strong>Unidad Responsable:</strong> <span>${(UnidadResponsable.getData())!"N/A"}</span></div> 427 <div class="info-box" style="grid-column: span 2;"><strong>Tema:</strong> <span>${(Tema.getData())!"Sin descripción"}</span></div> 428 <div class="info-box" style="grid-column: span 2;"><strong>Tipo de Proyecto:</strong> <span>${(TipoDeDocumento.getData())!"Sin descripción"}</span></div> 429 <div class="info-box" style="grid-column: span 2;"><strong>Competencia Legal:</strong> <span>${(CompetenciaLegal.getData())!"Sin descripción"}</span></div> 430
431 <div class="info-box"><strong>Norma a Modificar:</strong> <span>${(NormaAModificar.getData())!"N/A"}</span></div> 432 <div class="info-box"><strong>Origen de Iniciativa:</strong> <span>${(OrigenDeLaIniciativa.getData())!"N/A"}</span></div> 433 </div>
434
435 <#-- SECCIÓN DE DOCUMENTOS SEGÚN ESTADO -->
436 <#if estadoActual == "abierto" || estadoActual == "cerrado" || estadoActual == "finalizado">
437
438 <#-- 1. DOCUMENTOS ANEXOS -->
439 <div class="doc-footer-section">
440 <strong class="section-title-custom">DOCUMENTOS ANEXOS:</strong>
441 <@renderizarPorExtension docField=(DocumentosAnexos!{}) tipoPermitido="todos" /> 442 </div>
443
444 <#-- 2. DOCUMENTOS DEL PROCESO DE CONSULTA .PDF -->
445 <div class="doc-footer-section" style="margin-top: 25px;">
446 <strong class="section-title-custom">DOCUMENTOS DEL PROCESO DE CONSULTA .PDF:</strong>
447 <#if DocumentosDelProcesoDeConsultaPDF?? && DocumentosDelProcesoDeConsultaPDF.getData()?has_content>
448 <@renderizarPorExtension docField=DocumentosDelProcesoDeConsultaPDF!{} tipoPermitido="pdf" /> 449 <#elseif DocumentosDelProcesoDeConsultaPdf?? && DocumentosDelProcesoDeConsultaPdf.getData()?has_content>
450 <@renderizarPorExtension docField=DocumentosDelProcesoDeConsultaPdf!{} tipoPermitido="pdf" /> 451 <#elseif DocumentosDelProcesoDeConsulta?? && DocumentosDelProcesoDeConsulta.getData()?has_content>
452 <@renderizarPorExtension docField=DocumentosDelProcesoDeConsulta!{} tipoPermitido="pdf" /> 453 <#else>
454 <@renderizarPorExtension docField=(DocumentosDelProceso!{}) tipoPermitido="pdf" /> 455 </#if>
456 </div>
457
458 <#-- 3. RESPUESTA A COMENTARIOS RECIBIDOS (.CSV) -->
459 <div class="doc-footer-section" style="margin-top: 25px;">
460 <strong class="section-title-custom">RESPUESTA A COMENTARIOS RECIBIDOS(.CSV):</strong>
461 <#if DocumentosDelProcesoDeConsultaCsv?? && DocumentosDelProcesoDeConsultaCsv.getData()?has_content>
462 <@renderizarPorExtension docField=DocumentosDelProcesoDeConsultaCsv!{} tipoPermitido="csv" /> 463 <#elseif DocumentosDelProcesoDeConsultaExcel?? && DocumentosDelProcesoDeConsultaExcel.getData()?has_content>
464 <@renderizarPorExtension docField=DocumentosDelProcesoDeConsultaExcel!{} tipoPermitido="csv" /> 465 <#else>
466 <@renderizarPorExtension docField=(DocumentosDelProceso!{}) tipoPermitido="csv" /> 467 </#if>
468 </div>
469
470 <#-- 4. IFRAME EMBEBIDO DEL FORMULARIO (ANCLAJE DIRECTO PARA EL CLICK EN "AQUÍ") -->
471 <#if estadoActual == "abierto" && urlFormularioEmbed?has_content>
472 <div id="formulario-repac-${.vars['reserved-article-id'].getData()}" class="doc-footer-section" style="margin-top: 25px; scroll-margin-top: 20px;"> 473 <strong class="section-title-custom">FORMULARIO DE REGISTRO DE OBSERVACIONES:</strong>
474 <div class="repac-iframe-container">
475 <iframe src="${urlFormularioEmbed}" width="100%" height="700" frameborder="0" marginheight="0" marginwidth="0" style="border: 1px solid #e2e8f0; border-radius: 8px; width: 100%; background: #ffffff;">Cargando formulario...</iframe> 476 </div>
477 </div>
478 </#if>
479
480 <#-- 5. LINK DEL PROYECTO FINALIZADO -->
481 <div class="doc-footer-section" style="margin-top: 25px;">
482 <strong class="section-title-custom">LINK DEL PROYECTO:</strong>
483 <#if EnlaceFinalDelProyecto?? && EnlaceFinalDelProyecto.getData()?has_content>
484 <div style="background: #f8fafc; border: 1px solid #e2e8f0; padding: 12px 16px; border-radius: 6px; font-size: 0.9rem; color: #003366; font-weight: bold; word-break: break-all;">
485 <i class="fas fa-link" style="margin-right: 6px;"></i> <a href="${EnlaceFinalDelProyecto.getData()?trim}" target="_blank" style="color: #003366; text-decoration: underline;">${EnlaceFinalDelProyecto.getData()}</a> 486 </div>
487 <#else>
488 <div style="border: 1px dashed #b4c6e7; background-color: #f8fafc; border-radius: 8px; padding: 20px; text-align: center;">
489 <p style="margin: 0; font-style: italic; color: #64748b; font-size: 14px;">No se ha registrado la URL final del proyecto.</p>
490 </div>
491 </#if>
492 </div>
493 </#if>
494
495 </div>
496</div>
497
498<style>
499 * { font-family: "Montserrat", sans-serif; } 500
501 .recap-card { 502 background-color: #FFFFFF;
503 border-radius: 12px;
504 box-shadow: 0 8px 30px rgba(0, 0, 0, 0.08);
505 max-width: 900px;
506 border-left: 6px solid ${stColorBold}; 507 font-family: 'Segoe UI', Arial, sans-serif;
508 margin: 20px auto;
509 overflow: hidden;
510 }
511
512 .recap-top-header { 513 display: flex;
514 justify-content: space-between;
515 align-items: center;
516 background: #ffffff;
517 padding: 20px 25px;
518 }
519
520 .recap-title-text { 521 color: #003366;
522 margin: 0;
523 font-size: 1.4rem;
524 font-weight: 700;
525 flex: 1;
526 }
527
528 .recap-alert-msg { 529 padding: 15px 25px;
530 background-color: ${stColorLight}; 531 border-top: 1px solid rgba(0,0,0,0.03);
532 border-bottom: 1px solid rgba(0,0,0,0.03);
533 font-size: 0.95rem;
534 color: #444;
535 line-height: 1.4;
536 }
537
538 .recap-body { padding: 10px 25px 25px 25px; } 539 .recap-grid { display: grid; grid-template-columns: 1fr 1fr; } 540 .info-box { padding: 15px 0; border-bottom: 1px solid #f2f2f2; } 541 .info-box:nth-last-child(1), .info-box:nth-last-child(2) { border-bottom: none; } 542
543 .info-box strong { 544 color: #003366;
545 display: block;
546 font-size: 1rem;
547 text-transform: uppercase;
548 margin-bottom: 4px;
549 letter-spacing: 0.5px;
550 }
551
552 .info-box span { color: #333; font-size: 0.95rem; } 553
554 .status-badge { 555 padding: 8px 16px;
556 border-radius: 30px;
557 font-size: 0.85rem;
558 font-weight: bold;
559 display: flex;
560 align-items: center;
561 background-color: ${stColorLight}; 562 color: ${stColorBold}; 563 border: 1px solid ${stColorBold}44; 564 }
565
566 .dot { height: 8px; width: 8px; border-radius: 50%; margin-right: 10px; background-color: ${stColorBold}; } 567 .doc-footer-section { margin-top: 10px; padding-top: 20px; border-top: 2px solid #F2F2F2; } 568
569 .section-title-custom { 570 color: #003366;
571 font-size: 0.85rem;
572 display: block;
573 margin-bottom: 16px;
574 letter-spacing: 0.5px;
575 font-weight: 700;
576 }
577
578 .repac-documents-grid { 579 display: grid;
580 grid-template-columns: repeat(2, 1fr);
581 gap: 20px;
582 margin-bottom: 10px;
583 }
584
585 .grid-document-card { 586 display: flex;
587 flex-direction: column;
588 gap: 6px;
589 }
590
591 .btn-recap-grid-item { 592 display: flex;
593 align-items: center;
594 justify-content: center;
595 background: #003366;
596 color: #ffffff !important;
597 padding: 10px 15px;
598 border-radius: 6px;
599 text-decoration: none !important;
600 transition: background 0.2s, transform 0.2s;
601 box-sizing: border-box;
602 width: 100%;
603 text-align: center;
604 }
605
606 .btn-recap-grid-item:hover { 607 background: #002244;
608 transform: translateY(-2px);
609 }
610
611 .btn-recap-grid-item i { 612 font-size: 1.1rem;
613 color: #ffffff;
614 margin-right: 8px;
615 }
616
617 .grid-doc-text { 618 font-size: 0.8rem;
619 font-weight: 700;
620 white-space: nowrap;
621 overflow: hidden;
622 text-overflow: ellipsis;
623 color: #ffffff;
624 }
625
626 .grid-doc-date-sub { 627 font-size: 0.72rem;
628 color: #666666;
629 display: flex;
630 align-items: center;
631 justify-content: center;
632 gap: 4px;
633 font-style: italic;
634 }
635
636 .grid-doc-date-sub i { 637 color: #003366;
638 font-size: 0.85rem;
639 }
640
641 .repac-no-files-msg { 642 background: #f8fafc;
643 border: 1px dashed #cbd5e1;
644 border-radius: 6px;
645 padding: 14px;
646 text-align: center;
647 font-size: 0.85rem;
648 color: #64748b;
649 font-style: italic;
650 }
651
652 .recap-social-bar { 653 display: flex;
654 justify-content: space-between;
655 align-items: center;
656 padding: 15px 25px;
657 background-color: #ffffff;
658 border-top: 1px solid #f2f2f2;
659 border-bottom: 1px solid #f2f2f2;
660 font-family: 'Segoe UI', Arial, sans-serif;
661 }
662
663 .recap-social-bar .social-item { 664 flex: 1;
665 display: inline-flex;
666 align-items: center;
667 justify-content: center;
668 gap: 10px;
669 font-size: 0.9rem;
670 color: #003366;
671 font-weight: 700 !important;
672 background: none;
673 border: none;
674 padding: 10px 16px;
675 border-radius: 6px;
676 cursor: pointer;
677 transition: all 0.2s ease;
678 text-align: center;
679 }
680
681 .recap-social-bar .social-item i { 682 font-size: 1.25rem !important;
683 color: #003366;
684 }
685
686 .recap-social-bar .social-item:hover { 687 background-color: #F2F2F2;
688 color: #002244;
689 }
690
691 .repac-iframe-container { 692 width: 100%;
693 overflow: hidden;
694 box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
695 border-radius: 8px;
696 }
697
698 .repac-mini-modal-overlay { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0, 0, 0, 0.4); display: flex; justify-content: center; align-items: center; z-index: 99999; } 699 .repac-mini-modal-box { background: #ffffff; border-radius: 8px; width: 420px; box-shadow: 0 4px 20px rgba(0,0,0,0.15); animation: repacFadeIn 0.2s ease-out; font-family: Arial, sans-serif; } 700 .repac-mini-modal-header { display: flex; justify-content: space-between; align-items: center; padding: 12px 16px; border-bottom: 1px solid #19326b; color: #fff; } 701 .repac-modal-close-btn { background: none; border: none; font-size: 30px; cursor: pointer; color: #64748b; line-height: 1; } 702 .repac-modal-close-btn:hover { color: #000; } 703 .repac-mini-modal-body { padding: 16px; } 704 .repac-mini-modal-body p { font-size: 12px; color: #475569; margin: 0 0 10px 0; text-align: left; } 705 .repac-url-container { display: flex; gap: 6px; margin-bottom: 15px; } 706 #input-url-actual-repac { flex: 1; padding: 6px 10px; border: 1px solid #cbd5e1; border-radius: 4px; font-size: 11px; color: #334155; background: #f8fafc; font-family: monospace; } 707 #btn-copiar-repac { background: #003399; color: white; border: none; padding: 6px 12px; border-radius: 4px; font-size: 11px; font-weight: bold; cursor: pointer; display: flex; align-items: center; gap: 4px; } 708 #btn-copiar-repac:hover { background: #002266; } 709 .repac-modal-social-icons { display: flex; justify-content: center; gap: 15px; border-top: 1px solid #f1f5f9; padding-top: 12px; } 710 .repac-modal-social-icons a { font-size: 22px; color: #64748b; cursor: pointer; transition: color 0.2s; text-decoration: none !important; } 711 .repac-modal-social-icons #share-wa:hover { color: #25D366!important; } 712 .repac-modal-social-icons #share-fb:hover { color: #1877F2!important; } 713 .repac-modal-social-icons #share-tw:hover { color: #000000!important; } 714
715 .pdf-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 18px; gap: 12px; } 716 .header-left { width: 25%; } 717 .header-left img { width: 180px; height: auto; } 718 .header-center { width: 50%; text-align: center; } 719 .header-center h1 { color: #003DA5; font-size: 22px; font-weight: 700; margin: 0; text-transform: uppercase; } 720 .header-center h2 { color: #4b5563; font-size: 14px; font-weight: 600; margin: 10px 0; text-transform: uppercase; } 721 .header-right { width: 25%; display: flex; justify-content: flex-end; } 722 .badge-repac { border: 1px solid #cbd5e1; border-radius: 8px; padding: 8px 12px; font-size: 12px; font-weight: 700; color: #003DA5; background: #f8fafc; } 723 .header-line { width: 100%; height: 4px; background: #003DA5; margin-bottom: 28px; } 724 .certificado-pdf { width: 794px; padding: 45px 55px; background: #fff; font-family: Arial, sans-serif; color: #4b4b4b; box-sizing: border-box; position: relative; } 725 .certificado-header { text-align: center; margin-bottom: 35px; } 726 .certificado-header h1 { color: #0151a1; font-size: 18px; font-weight: 700; text-transform: uppercase; margin: 0; line-height: 1.1; } 727 .certificado-body { text-align: center; } 728 .certificado-body p { margin: 10px 0; line-height: 1.2; } 729 .label-bold { margin-top: 25px; font-weight: bold; font-size: 12px; } 730 .unidad, .fechas, .proyecto { color: #0151a1; } 731 .unidad { font-size: 24px; font-weight: 700; text-transform: uppercase; } 732 .fechas { font-size: 16px; font-weight: 700; } 733 .proyecto { font-size: 20px; font-weight: 700; line-height: 1.15; margin: 25px 0; text-transform: uppercase; word-break: break-word; } 734 .url-proyecto { color: #0151a1; font-size: 12px; font-weight: bold; word-break: break-all; } 735 .footer-certificado { margin-top: 45px; } 736 .footer-firma { color: #4b4b4b; font-size: 20px; font-weight: 700; text-transform: uppercase; } 737 .fecha-generacion { margin-top: 20px; font-size: 12px; color: #374151; } 738 .linea-final { width: 120px; height: 6px; margin-left: auto; margin-top: 40px; border-radius: 20px; background: linear-gradient(to right, #fcd116 33%, #003893 33%, #003893 66%, #ce1126 66%); } 739
740 @keyframes repacFadeIn { from { opacity: 0; transform: scale(0.95); } to { opacity: 1; transform: scale(1); } } 741
742 @media (max-width: 768px) { 743 .repac-documents-grid { grid-template-columns: 1fr; gap: 12px; } 744 .recap-social-bar { flex-direction: column; gap: 10px; padding: 10px 25px; } 745 .recap-social-bar .social-item { width: 100%; } 746 .recap-grid { grid-template-columns: 1fr; } 747 }
748
749 html { scroll-behavior: smooth; } 750 .scroll-suave-repac { transition: color 0.2s ease; text-decoration: underline !important; } 751 .scroll-suave-repac:hover { opacity: 0.8; } 752</style>