Compare commits
23 Commits
2362bc3233
...
dev/no_doc
| Author | SHA1 | Date | |
|---|---|---|---|
| f1c3f711c4 | |||
| ce89e67181 | |||
| ab5c0e6d54 | |||
|
|
4ff8888472 | ||
|
|
0ff577e8b1 | ||
| 96eb619a95 | |||
| ccaaca4b4e | |||
| ff4dcd2834 | |||
| 423a904d7e | |||
|
|
69dc786cac | ||
|
|
8f64d2abdb | ||
|
|
3817618208 | ||
|
|
f867cac9c1 | ||
|
|
79debe5f46 | ||
|
|
70460b3310 | ||
|
|
e31ab73c05 | ||
|
|
b6e8dca365 | ||
|
|
e9402ecb4a | ||
|
|
6005691b5b | ||
|
|
af738c165b | ||
|
|
e53e6b3906 | ||
|
|
43834e9ee3 | ||
|
|
b44f9f4198 |
90
README.md
90
README.md
@@ -1,88 +1,6 @@
|
|||||||
# exportPDF
|
# exportPDF dev/no_docker
|
||||||
|
> **Precaución:**
|
||||||
|
> Para instalar en modo producción, utlize la rama main
|
||||||
|
|
||||||
Funcionalidad para implementar la capacidad de exportar los datos de un recurso a formato PDF.
|
Funcionalidad para implementar la capacidad de exportar los datos de un recurso a formato PDF.
|
||||||
Los modelos de recursos habilitados para la función son los siguientes:
|
esta rama es para el caso de un entorno de desarrollo clásico, es decir sin utilizar contenedores
|
||||||
|
|
||||||
* Patrimonio material - Bienes inmuebles
|
|
||||||
* Patrimonio material - Bienes muebles
|
|
||||||
* Patrimonio inmaterial
|
|
||||||
* Organización o persona
|
|
||||||
|
|
||||||
# Para agregar la funcionalidad ExportPDF a un proyecto de Arches puede seguir el siguiente procedimiento.
|
|
||||||
Procedimiento válido para un proyecto en modo desarrollo implementado con un enfoque tradicional sin contenedores.
|
|
||||||
Para el caso de un enfoque utilizando contenedores o en modo Producción, el proceso varía levemente.
|
|
||||||
|
|
||||||
### 0. Instalar dependencias y librerias de python (servidor Ubuntu)
|
|
||||||
Solo en caso de que su proyecto de arches resida en una implementación según la guía oficial de archesproject
|
|
||||||
|
|
||||||
```shell
|
|
||||||
sudo apt install build-essential python3.12-dev python3.12-pip python3.12-setuptools python3.12-wheel python3.12-cffi
|
|
||||||
sudo apt install build-essential python3-dev python3-pip python3-setuptools python3-wheel python3-cffi libcairo2 libpango-1.0-0 libpangocairo-1.0-0 libgdk-pixbuf2.0-0 libffi-dev shared-mime-info
|
|
||||||
```
|
|
||||||
y en el entorno de (arches) python:
|
|
||||||
|
|
||||||
```python
|
|
||||||
pip install django-weasyprint
|
|
||||||
pip install pypdf
|
|
||||||
pip install folium # provisional, se estan evaluando otras librerias como py-staticmaps y selenium
|
|
||||||
```
|
|
||||||
|
|
||||||
### 1. Clonar este repositorio en alguna carpeta de su servidor.
|
|
||||||
|
|
||||||
```shell
|
|
||||||
# puede ser en el home del servidor
|
|
||||||
git clone https://gitea.patrimonio.org.bo/sysadmin/sprpcb-exportpdf-func.git
|
|
||||||
```
|
|
||||||
|
|
||||||
### 2. Agregar la vista personalizada creando (copiando) las carpetas indicadas y luego los contenidos respectivos:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
# en caso de que el repo clonado esté en el home y desde la 1er carpeta mi_proyecto
|
|
||||||
cp -r ../sprpcb-exportpdf-func/pdf ./mi_proyecto/pdf # copia la carpeta incluida la vista
|
|
||||||
cp -r ../sprpcb-exportpdf-func/report-templates ./mi_proyecto/templates/views/report-templates # copia la carpeta incluida la plantilla
|
|
||||||
# o si prefiere crea la carpetas primero y luego copia los contenidos
|
|
||||||
```
|
|
||||||
### 3. Agregar la entrada de ruta en el archivo urls.py del proyecto:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
# ...
|
|
||||||
urlpatterns = [
|
|
||||||
# ...
|
|
||||||
path('export/pdf/<str:resourceid>/<str:printubic>/<str:printimgs>/<str:printpdfs>/', export_resource_pdf, name='export_resource_pdf'),
|
|
||||||
# project-level urls
|
|
||||||
]
|
|
||||||
# ...
|
|
||||||
```
|
|
||||||
|
|
||||||
### 4. Copiar las plantillas de la funcionalidad correspondientes a los modelos de recursos:
|
|
||||||
```shell
|
|
||||||
# en caso de que el repo clonado esté en el home y desde la 1er carpeta mi_proyecto
|
|
||||||
cp -r ../sprpcb-exportpdf-func/pdf_reports ./mi_proyecto/templates/reports # copia la carpeta incluida la plantilla
|
|
||||||
# o si prefiere crea la carpetas primero y luego copia los contenidos
|
|
||||||
```
|
|
||||||
|
|
||||||
### 5. Copiar los archivos necesarios para una nueva plantilla de reporte:
|
|
||||||
```shell
|
|
||||||
cp -r ../sprpcb-exportpdf-func/reportes ./mi_proyecto/reportes
|
|
||||||
```
|
|
||||||
|
|
||||||
### 6. Registrar la plantilla personalizada de proyecto que agrega los botones necesarios:
|
|
||||||
```python
|
|
||||||
python manage.py report register -s mi_proyecto/reports/export-pdf-report.json
|
|
||||||
```
|
|
||||||
|
|
||||||
### 7. A continuación, asegúrese de reconstruir la interfaz de su proyecto para habilitar los cambios:
|
|
||||||
|
|
||||||
```
|
|
||||||
npm run build_development
|
|
||||||
```
|
|
||||||
|
|
||||||
### 8. Cuando haya terminado, debería ver los botones de exportar en la ventana de vista de reporte de su modelo de recursos:
|
|
||||||

|
|
||||||
|
|
||||||
### 9. Forma de uso:
|
|
||||||
|
|
||||||
El botón "Exportar a PDF", de manera predeterminada, crea el reporte PDF incluyendo casi todos los datos del recurso. Y de manera opcional se pueden incluir 3 características adicionales a través de los botones adyacentes que controlan los siguientes parámetros:
|
|
||||||
* Incluir ubicación detallada: Se puede incluir datos de ubicación (geo-localización) que podrían estar contraindicados en algunos tipos de recursos.
|
|
||||||
* Incluir imágenes adjuntas: Una galería de imágenes distribuida en mosaicos de 2x6 imágenes por hoja a manera de Anexo al informe (existen recursos que tienen más de 20 imágenes relacionadas)
|
|
||||||
* Incluir documentos (pdf) adjuntos: se ajuntan los documentos relacionados en el mismo archivo pdf del informe
|
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 23 KiB |
26
copy2proyfolder.sh
Executable file
26
copy2proyfolder.sh
Executable file
@@ -0,0 +1,26 @@
|
|||||||
|
#!bin/bash
|
||||||
|
|
||||||
|
#Script demostrativo para copiar del repo clonado a las carpetas de proyecto
|
||||||
|
#Utilize con precaución
|
||||||
|
|
||||||
|
echo -e "\n\t Script para copiar a carpeta de proyecto"
|
||||||
|
read -p "Escribe la carpeta de proyecto ( ejem: ~/mi_proy/miproy ): " destino
|
||||||
|
|
||||||
|
echo $destino
|
||||||
|
if [ ! -d "$destino" ]; then
|
||||||
|
echo "La carpeta de destino no existe. Intente nuevamente!"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
mkdir -p $destino/pdf
|
||||||
|
cp ./pdf/views.py $destino/pdf/
|
||||||
|
|
||||||
|
cp ./media_js_reports/export-pdf-report.js $destino/media/js/reports/
|
||||||
|
|
||||||
|
cp -r ./reportes $destino/
|
||||||
|
|
||||||
|
mkdir -p $destino/templates/views/report-templates
|
||||||
|
cp ./templates_views_report-templates/export-pdf-report.htm $destino/templates/views/report-templates/
|
||||||
|
|
||||||
|
mkdir -p $destino/templates/reports
|
||||||
|
cp ./templates_reports/* $destino/templates/reports/
|
||||||
37
media_js_reports/export-pdf-report.js
Normal file
37
media_js_reports/export-pdf-report.js
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
define([
|
||||||
|
'knockout',
|
||||||
|
'viewmodels/report',
|
||||||
|
'templates/views/report-templates/export-pdf-report.htm'
|
||||||
|
], function(ko, ReportViewModel, exportPdfReportTemplate) {
|
||||||
|
return ko.components.register('export-pdf-report', {
|
||||||
|
viewModel: function(params) {
|
||||||
|
params.configKeys = [];
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
ReportViewModel.apply(this, [params]);
|
||||||
|
|
||||||
|
//console.log('Params:', params);
|
||||||
|
this.anexarUbic = ko.observable(false);
|
||||||
|
this.satMap = ko.observable(false);
|
||||||
|
this.anexarImagenes = ko.observable(false);
|
||||||
|
this.anexarPdfs = ko.observable(false);
|
||||||
|
|
||||||
|
const boolToStr = (bool) => bool ? "1" : "0";
|
||||||
|
|
||||||
|
self.resourceId = ko.observable(
|
||||||
|
params.report?.report_json?.resourceinstanceid || null
|
||||||
|
);
|
||||||
|
|
||||||
|
self.exportPDF = function() {
|
||||||
|
var id = self.resourceId();
|
||||||
|
if (id) {
|
||||||
|
var url = '/export/pdf/' + id + '/' + boolToStr(self.anexarUbic()) + '/' + boolToStr(self.satMap()) + '/' + boolToStr(self.anexarImagenes()) + '/' + boolToStr(self.anexarPdfs()) + '/';
|
||||||
|
window.open(url, '_blank');
|
||||||
|
} else {
|
||||||
|
alert('No se encontró el ID del recurso.');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
},
|
||||||
|
template: exportPdfReportTemplate,
|
||||||
|
});
|
||||||
|
});
|
||||||
95
pdf/views.py
95
pdf/views.py
@@ -1,10 +1,11 @@
|
|||||||
# mi_proyecto/pdf/views.py
|
# mi_proyecto/pdf/views.py
|
||||||
# dpsk - 2026
|
|
||||||
import io
|
import io
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from django.http import HttpResponse
|
from django.http import HttpResponse
|
||||||
from django.template.loader import render_to_string
|
from django.template.loader import render_to_string
|
||||||
from weasyprint import HTML
|
from weasyprint import HTML
|
||||||
|
from arches.app.models.models import GraphModel
|
||||||
from arches.app.models.resource import Resource
|
from arches.app.models.resource import Resource
|
||||||
from django.contrib.auth.models import Group
|
from django.contrib.auth.models import Group
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
@@ -12,9 +13,61 @@ from zoneinfo import ZoneInfo
|
|||||||
from functools import reduce
|
from functools import reduce
|
||||||
from operator import getitem
|
from operator import getitem
|
||||||
from pypdf import PdfReader, PdfWriter
|
from pypdf import PdfReader, PdfWriter
|
||||||
|
import urllib.parse
|
||||||
|
import requests
|
||||||
|
import base64
|
||||||
import json
|
import json
|
||||||
import ast
|
import ast
|
||||||
|
|
||||||
|
def static_map_view(geojson_colec, sat_map):
|
||||||
|
g_sys_cfg=GraphModel.objects.get(name='{"en": "Arches System Settings"}')
|
||||||
|
r_sys_cfg=Resource.objects.get(graph=g_sys_cfg)
|
||||||
|
r_sys_cfg_data=r_sys_cfg.to_json()
|
||||||
|
access_token = r_sys_cfg_data['Map Settings']['Mapbox']['MAPBOX_API_KEY']
|
||||||
|
|
||||||
|
geojson_dict = ast.literal_eval(geojson_colec)
|
||||||
|
if sat_map:
|
||||||
|
style_id = "satellite-streets-v12" # streets-v12 | outdoors-v11 | satellite-streets-v12
|
||||||
|
for geo in geojson_dict['features'] :
|
||||||
|
if geo['geometry'].get('type') == 'Polygon':
|
||||||
|
geo['properties'] = {
|
||||||
|
"stroke": "#00ffff",
|
||||||
|
"stroke-width": 2,
|
||||||
|
"stroke-opacity": 0.8,
|
||||||
|
"fill": "#00ffff",
|
||||||
|
"fill-opacity": 0.3
|
||||||
|
}
|
||||||
|
elif geo['geometry'].get('type') == 'Point':
|
||||||
|
geo['properties'] = {
|
||||||
|
"marker-color": "#ff0000",
|
||||||
|
"marker-size": "small"
|
||||||
|
}
|
||||||
|
elif geo['geometry'].get('type') == 'LineString':
|
||||||
|
geo['properties'] = {
|
||||||
|
"stroke": "#0000ff",
|
||||||
|
"stroke-width": 2,
|
||||||
|
"stroke-opacity": 0.8
|
||||||
|
}
|
||||||
|
else:
|
||||||
|
style_id = "light-v11"
|
||||||
|
|
||||||
|
geojson_string = json.dumps(geojson_dict, separators=(',', ':'))
|
||||||
|
encoded_geojson = urllib.parse.quote(geojson_string)
|
||||||
|
|
||||||
|
username = "mapbox"
|
||||||
|
width, height = 400, 400
|
||||||
|
padding = 100
|
||||||
|
|
||||||
|
mapbox_url = (
|
||||||
|
f"https://api.mapbox.com/styles/v1/{username}/{style_id}/static/"
|
||||||
|
f"geojson({encoded_geojson})/auto/{width}x{height}"
|
||||||
|
f"?padding={padding}&access_token={access_token}"
|
||||||
|
)
|
||||||
|
|
||||||
|
response = requests.get(mapbox_url)
|
||||||
|
|
||||||
|
return base64.b64encode(response.content).decode('utf-8')
|
||||||
|
|
||||||
def ajustar_medios(resource_media_rel, medios_list):
|
def ajustar_medios(resource_media_rel, medios_list):
|
||||||
medios = []
|
medios = []
|
||||||
img=["image/bmp", "image/gif", "image/jpg", "image/jpeg", "image/png", "image/tif", "image/tiff"]
|
img=["image/bmp", "image/gif", "image/jpg", "image/jpeg", "image/png", "image/tif", "image/tiff"]
|
||||||
@@ -83,12 +136,13 @@ def strdict_to_dict(strdict):
|
|||||||
pass
|
pass
|
||||||
return value
|
return value
|
||||||
|
|
||||||
def export_resource_pdf(request, resourceid, printubic, printimgs, printpdfs):
|
def export_resource_pdf(request, resourceid, printubic, satmap, printimgs, printpdfs):
|
||||||
resource = Resource.objects.get(pk=resourceid)
|
resource = Resource.objects.get(pk=resourceid)
|
||||||
resource_data = resource.to_json()
|
resource_data = resource.to_json()
|
||||||
|
|
||||||
# Corrección de medios relacionados, se normalizan claves y se adicionan propiedades
|
# Corrección de medios relacionados, se normalizan claves y se adicionan propiedades
|
||||||
ruta_medios = find_key_path( resource_data, "Medio de información")
|
ruta_medios = find_key_path( resource_data, "Medio de información")
|
||||||
|
|
||||||
if ruta_medios is not None:
|
if ruta_medios is not None:
|
||||||
valor_medios=reduce(lambda dict_layer, key: dict_layer[key], ruta_medios, resource_data)
|
valor_medios=reduce(lambda dict_layer, key: dict_layer[key], ruta_medios, resource_data)
|
||||||
resource_rel=resource.get_related_resources(user=request.user,resourceinstance_graphid='6afc4e9e-727e-4152-8084-309267752650')
|
resource_rel=resource.get_related_resources(user=request.user,resourceinstance_graphid='6afc4e9e-727e-4152-8084-309267752650')
|
||||||
@@ -96,6 +150,7 @@ def export_resource_pdf(request, resourceid, printubic, printimgs, printpdfs):
|
|||||||
reduce(getitem, ruta_medios[:-1], resource_data)[ruta_medios[-1]] = ajustar_medios(resource_rel,valor_medios)
|
reduce(getitem, ruta_medios[:-1], resource_data)[ruta_medios[-1]] = ajustar_medios(resource_rel,valor_medios)
|
||||||
|
|
||||||
# Cambio de datos gis en texto a formato json
|
# Cambio de datos gis en texto a formato json
|
||||||
|
|
||||||
ruta_gis = find_key_path( resource_data, "Coordenadas / Geometría")
|
ruta_gis = find_key_path( resource_data, "Coordenadas / Geometría")
|
||||||
if ruta_gis is not None:
|
if ruta_gis is not None:
|
||||||
valor_gis=reduce(lambda dict_layer, key: dict_layer[key], ruta_gis, resource_data)["@value"]
|
valor_gis=reduce(lambda dict_layer, key: dict_layer[key], ruta_gis, resource_data)["@value"]
|
||||||
@@ -112,6 +167,12 @@ def export_resource_pdf(request, resourceid, printubic, printimgs, printpdfs):
|
|||||||
sprpcb_url=request.build_absolute_uri('/')[:-1]
|
sprpcb_url=request.build_absolute_uri('/')[:-1]
|
||||||
fecha=datetime.now(ZoneInfo("America/La_Paz"))
|
fecha=datetime.now(ZoneInfo("America/La_Paz"))
|
||||||
|
|
||||||
|
map_img = None
|
||||||
|
|
||||||
|
if ruta_gis is not None and bool(int(printubic)) :
|
||||||
|
if reduce(getitem, ruta_gis[:-1], resource_data)[ruta_gis[-1]]["@value"] :
|
||||||
|
map_img = static_map_view(reduce(getitem, ruta_gis[:-1], resource_data)[ruta_gis[-1]]["@value"], bool(int(satmap)))
|
||||||
|
|
||||||
resources = [{
|
resources = [{
|
||||||
'resourceinstanceid': str(resource.resourceinstanceid),
|
'resourceinstanceid': str(resource.resourceinstanceid),
|
||||||
'graph_id': str(resource.graph_id),
|
'graph_id': str(resource.graph_id),
|
||||||
@@ -120,8 +181,10 @@ def export_resource_pdf(request, resourceid, printubic, printimgs, printpdfs):
|
|||||||
'sprpcb_url': sprpcb_url,
|
'sprpcb_url': sprpcb_url,
|
||||||
'fecha': fecha,
|
'fecha': fecha,
|
||||||
'eta_group': eta_group,
|
'eta_group': eta_group,
|
||||||
|
'print_ubic': bool(int(printubic)),
|
||||||
'print_imgs': bool(int(printimgs)),
|
'print_imgs': bool(int(printimgs)),
|
||||||
'print_pdfs': bool(int(printpdfs))
|
'print_pdfs': bool(int(printpdfs)),
|
||||||
|
'map_img': map_img
|
||||||
}]
|
}]
|
||||||
|
|
||||||
context = {'resources': resources}
|
context = {'resources': resources}
|
||||||
@@ -151,16 +214,20 @@ def export_resource_pdf(request, resourceid, printubic, printimgs, printpdfs):
|
|||||||
|
|
||||||
root_path = Path(__file__).resolve().parent.parent
|
root_path = Path(__file__).resolve().parent.parent
|
||||||
|
|
||||||
for medio in reduce(getitem, ruta_medios[:-1], resource_data)[ruta_medios[-1]] :
|
if ruta_medios is not None and bool(int(printpdfs)) :
|
||||||
if medio['formato'] == 'application/pdf' and bool(int(printpdfs)) :
|
for medio in reduce(getitem, ruta_medios[:-1], resource_data)[ruta_medios[-1]] :
|
||||||
merger.append(PdfReader(f'{root_path}/uploadedfiles/{medio["file"]}'))
|
if medio['formato'] == 'application/pdf' :
|
||||||
output_buffer = io.BytesIO()
|
medio_file = f'{root_path}/uploadedfiles/{medio["file"]}'
|
||||||
merger.write(output_buffer)
|
with open(medio_file,'rb') as pdf_file :
|
||||||
merger.close()
|
merger.append(pdf_file)
|
||||||
else:
|
output_buffer = io.BytesIO()
|
||||||
output_buffer = io.BytesIO()
|
merger.write(output_buffer)
|
||||||
merger.write(output_buffer)
|
merger.close()
|
||||||
merger.close()
|
else:
|
||||||
response = HttpResponse(output_buffer.getvalue(), content_type='application/pdf')
|
output_buffer = io.BytesIO()
|
||||||
|
merger.write(output_buffer)
|
||||||
|
merger.close()
|
||||||
|
output_buffer.seek(0)
|
||||||
|
response = HttpResponse(output_buffer.read(), content_type='application/pdf')
|
||||||
response['Content-Disposition'] = f'attachment; filename="{nombre_pdf}.pdf"'
|
response['Content-Disposition'] = f'attachment; filename="{nombre_pdf}.pdf"'
|
||||||
return response
|
return response
|
||||||
@@ -1,183 +0,0 @@
|
|||||||
{% load i18n %}
|
|
||||||
<!-- ko if: !$data.configForm -->
|
|
||||||
<!-- ko if: !$data.summary -->
|
|
||||||
{% block report %}
|
|
||||||
|
|
||||||
|
|
||||||
{% block report_title_bar %}
|
|
||||||
<!-- Report Title Bar -->
|
|
||||||
<div class="relative report-title-bar">
|
|
||||||
|
|
||||||
<!-- Title Block -->
|
|
||||||
<div class="report-toolbar-preview ep-form-toolbar">
|
|
||||||
<div class="h4 report-toolbar-title"><span data-bind="text: report.get('name')"></span> - <span data-bind="text: report.get('displayname') "></span></div>
|
|
||||||
|
|
||||||
<!-- Tools -->
|
|
||||||
<div class="ep-form-toolbar-tools mar-no flex">
|
|
||||||
<p class="report-print-date">
|
|
||||||
<span data-bind="text: $root.translations.reportDate"></span>
|
|
||||||
<span data-bind="text: reportDate"></span>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<div
|
|
||||||
class="report-print-date"
|
|
||||||
data-bind="component: {
|
|
||||||
name: 'views/components/simple-switch',
|
|
||||||
params: {
|
|
||||||
value: hideEmptyNodes,
|
|
||||||
config:{ label: $root.translations.hideNullValues, subtitle: ''}
|
|
||||||
}
|
|
||||||
}"
|
|
||||||
></div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endblock report_title_bar %}
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Report Content -->
|
|
||||||
<div class="rp-report-container-preview">
|
|
||||||
|
|
||||||
{% block header %}
|
|
||||||
{% endblock header %}
|
|
||||||
|
|
||||||
{% block body %}
|
|
||||||
<!--ko if: hasProvisionalData() && (editorContext === false) -->
|
|
||||||
<div class="report-provisional-flag"><span data-bind="text: $root.translations.pendingProvisionalEditsNotDisplayed"></span></div>
|
|
||||||
<!--/ko-->
|
|
||||||
<!--ko if: hasProvisionalData() && (editorContext === true && report.userisreviewer === true) -->
|
|
||||||
<div class="report-provisional-flag"><span data-bind="text: $root.translations.pendingProvisionalEditsNotDisplayed"></span></div>
|
|
||||||
<!--/ko-->
|
|
||||||
<!--ko if: hasProvisionalData() && (editorContext === true && report.userisreviewer === false) -->
|
|
||||||
<div class="report-provisional-flag"><span data-bind="text: $root.translations.pendingProvisionalEdits"></div>
|
|
||||||
<!--/ko-->
|
|
||||||
|
|
||||||
<div class="rp-report-section relative rp-report-section-root">
|
|
||||||
<div class="rp-report-section-title">
|
|
||||||
<!-- ko foreach: { data: report.cards, as: 'card' } -->
|
|
||||||
<!-- ko if: ($parent.hideEmptyNodes() === false || card.tiles().length > 0) && ko.unwrap(card.model.visible) -->
|
|
||||||
<!-- ko if: $index() !== 0 --><hr class="rp-tile-separator"><!-- /ko -->
|
|
||||||
<div class="rp-card-section">
|
|
||||||
<!-- ko component: {
|
|
||||||
name: card.model.cardComponentLookup[card.model.component_id()].componentname,
|
|
||||||
params: {
|
|
||||||
state: 'report',
|
|
||||||
preview: $parent.report.preview,
|
|
||||||
card: card,
|
|
||||||
pageVm: {...$root, report: $parent.report},
|
|
||||||
hideEmptyNodes: $parent.hideEmptyNodes
|
|
||||||
}
|
|
||||||
} --> <!-- /ko -->
|
|
||||||
</div>
|
|
||||||
<!-- /ko -->
|
|
||||||
<!-- /ko -->
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endblock body %}
|
|
||||||
|
|
||||||
|
|
||||||
{% block related_resources %}
|
|
||||||
<div class="rp-report-section relative report-related-resources">
|
|
||||||
<div class="rp-report-section-title">
|
|
||||||
<div class="h4 rp-section-title"><span data-bind="text: $root.translations.relatedResources"></span></div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- ko foreach: { data: Object.values(report.relatedResourcesLookup()), as: 'resourceData' } -->
|
|
||||||
<!-- ko if: resourceData.totalRelatedResources > 0 || !$parent.hideEmptyNodes() -->
|
|
||||||
<div class="h5 rp-tile-title">
|
|
||||||
<span class="rp-tile-title-float" data-bind="text: resourceData.name"></span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="rp-card-section">
|
|
||||||
<!-- ko foreach: { data: resourceData.loadedRelatedResources(), as: 'relatedResource' } -->
|
|
||||||
<div class="rp-report-container-tile">
|
|
||||||
<div class="row rp-report-tile">
|
|
||||||
<dl class="dl-horizontal">
|
|
||||||
<dt><a data-bind="text: relatedResource.displayName, attr: {href: relatedResource.link}"></a></dt>
|
|
||||||
<!-- ko if: relatedResource.relationship -->
|
|
||||||
<dd data-bind="text: '( ' + relatedResource.relationship + ' )'"></dd>
|
|
||||||
<!-- /ko -->
|
|
||||||
</dl>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<!-- /ko -->
|
|
||||||
|
|
||||||
<!-- ko if: resourceData.paginator() && resourceData.paginator().has_next -->
|
|
||||||
<button class="btn btn-primary" data-bind="click: $parent.report.getRelatedResources.bind($parent.report, false)">
|
|
||||||
<span data-bind="text: $root.translations.loadMore" ></span>
|
|
||||||
<span data-bind="text: '(' + resourceData.remainingResources() + ')'"></span>
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<button class="btn btn-primary" data-bind="click: $parent.report.getRelatedResources.bind($parent.report, true)">
|
|
||||||
<span data-bind="text: $root.translations.loadAll" ></span>
|
|
||||||
<span data-bind="text: '(' + (resourceData.totalRelatedResources - resourceData.loadedRelatedResources().length) + ')'"></span>
|
|
||||||
</button>
|
|
||||||
<!-- /ko -->
|
|
||||||
|
|
||||||
<!--ko if: resourceData.totalRelatedResources === 0 -->
|
|
||||||
<div class="rp-report-container-tile">
|
|
||||||
<div class="row rp-report-tile rp-no-data"><span data-bind="text: $root.translations.noRelationshipsAdded"></span></div>
|
|
||||||
</div>
|
|
||||||
<!--/ko-->
|
|
||||||
</div>
|
|
||||||
<!-- /ko -->
|
|
||||||
<!-- /ko -->
|
|
||||||
</div>
|
|
||||||
{% endblock related_resources %}
|
|
||||||
|
|
||||||
{% block footer %}
|
|
||||||
{% endblock footer %}
|
|
||||||
</div>
|
|
||||||
{% endblock report %}
|
|
||||||
<!-- /ko -->
|
|
||||||
|
|
||||||
<!-- ko if: $data.summary -->
|
|
||||||
{% block summary %}
|
|
||||||
<div class="relative report-title-bar">
|
|
||||||
|
|
||||||
<!-- Title Block -->
|
|
||||||
<div class="report-toolbar-preview ep-form-toolbar">
|
|
||||||
<h4 class="report-toolbar-title"><span data-bind="text: report.get('name')"></span> - <span data-bind="text: report.get('displayname') "></span></h4>
|
|
||||||
|
|
||||||
<!-- Tools -->
|
|
||||||
<div class="ep-form-toolbar-tools mar-no flex">
|
|
||||||
<p class="report-print-date">
|
|
||||||
<span data-bind="text: $root.translations.reportDate"></span>
|
|
||||||
<span data-bind="text: reportDate"></span>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="rp-report-container-preview">
|
|
||||||
<div class="rp-report-section relative rp-report-section-root">
|
|
||||||
<div class="rp-report-section-title">
|
|
||||||
<!-- ko if: report.cards.length > 0 -->
|
|
||||||
<!--ko let: { card: report.cards[0] }-->
|
|
||||||
<div class="rp-card-section">
|
|
||||||
<!-- ko component: {
|
|
||||||
name: card.model.cardComponentLookup[card.model.component_id()].componentname,
|
|
||||||
params: {
|
|
||||||
state: 'report',
|
|
||||||
preview: report.preview,
|
|
||||||
card: card,
|
|
||||||
pageVm: $root
|
|
||||||
}
|
|
||||||
} --> <!-- /ko -->
|
|
||||||
</div>
|
|
||||||
<!--/ko-->
|
|
||||||
<!-- /ko -->
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endblock summary %}
|
|
||||||
<!-- /ko -->
|
|
||||||
<!-- end of not configForm -->
|
|
||||||
<!-- /ko -->
|
|
||||||
|
|
||||||
|
|
||||||
<!-- ko if: $data.configForm && ($data.configType === 'header') -->
|
|
||||||
{% block header_form %}
|
|
||||||
{% endblock header_form %}
|
|
||||||
<!-- /ko -->
|
|
||||||
@@ -16,14 +16,15 @@
|
|||||||
h3 { font-size: 12pt;}
|
h3 { font-size: 12pt;}
|
||||||
h4 { font-size: 11pt;}
|
h4 { font-size: 11pt;}
|
||||||
|
|
||||||
.tiles-grid-grp { display: grid; grid-template-columns: 3fr 2fr; grid-template-rows: auto auto; gap: 2px;}
|
.tiles-grid-grp { display: grid; grid-template-columns: 1fr 1fr; grid-template-rows: auto auto; gap: 2px;}
|
||||||
.tiles-grid-grp-col { grid-column: 2; grid-row: 1 / span 2; }
|
.tiles-grid-grp-col { grid-column: 2; grid-row: 1 / span 2; }
|
||||||
.tile-block { border: 1px solid var(--ceniza); border-radius: 4px; padding: 2px; margin: 2px 0; background-color: var(--claro);}
|
.tile-block { border: 1px solid var(--ceniza); border-radius: 4px; padding: 2px; margin: 2px 0; background-color: var(--claro);}
|
||||||
.tile-title { font-size: 11pt; font-weight: bold; color: var(--oscuro); border-bottom: 1px solid var(--ceniza); padding-bottom: 2px; margin-bottom: 5px;}
|
.tile-title { font-size: 11pt; font-weight: bold; color: var(--oscuro); border-bottom: 1px solid var(--ceniza); padding-bottom: 2px; margin-bottom: 5px;}
|
||||||
.data-row { display: flex; padding: 2px 0; border-bottom: 1px solid var(--claro);}
|
.data-row { display: flex; padding: 2px 0; border-bottom: 1px solid var(--claro);}
|
||||||
.data-label { font-weight: 600; letter-spacing: -0.05em; width: 40%; color: var(--oscuro);}
|
.data-label { font-weight: 600; letter-spacing: -0.05em; width: 40%; color: var(--oscuro);}
|
||||||
.data-value { width: 40%; letter-spacing: -0.05em; word-wrap: break-word;}
|
.data-value { width: 60%; font-size:.9em; word-wrap: break-word;}
|
||||||
.no-data { color: var(--ceniza); font-style: italic;}
|
.no-data { color: var(--ceniza); font-style: italic;}
|
||||||
|
.tiles-grid-grp-col .tile-block img { object-fit: cover; width: 330px; max-height: 230px;}
|
||||||
|
|
||||||
@page {
|
@page {
|
||||||
@top-left { background: var(--resaltado); content: counter(page); height: 1cm; text-align: center; width: 1cm;}
|
@top-left { background: var(--resaltado); content: counter(page); height: 1cm; text-align: center; width: 1cm;}
|
||||||
@@ -117,7 +118,7 @@
|
|||||||
{% with gis_vector=resource_data|val_from_key:"Ubicación simple"|val_from_key:"Coordenadas / Geometría"|val_from_key:"@value"|json_to_obj %}
|
{% with gis_vector=resource_data|val_from_key:"Ubicación simple"|val_from_key:"Coordenadas / Geometría"|val_from_key:"@value"|json_to_obj %}
|
||||||
{% for gis in gis_vector.features %}
|
{% for gis in gis_vector.features %}
|
||||||
<div class="data-row">
|
<div class="data-row">
|
||||||
<span class="data-value" style="width: 100%;">{{ gis.geometry }}</span>
|
<span class="data-value" style="width: 100%; font-size: .72em;">{{ gis.geometry|truncatewords:24 }}</span>
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% endwith %}
|
{% endwith %}
|
||||||
@@ -131,6 +132,7 @@
|
|||||||
<div class="tiles-grid-grp-col">
|
<div class="tiles-grid-grp-col">
|
||||||
<div class="tile-block">
|
<div class="tile-block">
|
||||||
<div class="data-label">Mapa de referencia</div>
|
<div class="data-label">Mapa de referencia</div>
|
||||||
|
<img src="data:image/png;base64,{{ resource.map_img }}">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -162,7 +162,7 @@
|
|||||||
{% with gis_vector=resource_data|val_from_key:"Ubicación BIM"|val_from_key:"Coordenadas / Geometría"|val_from_key:"@value"|json_to_obj %}
|
{% with gis_vector=resource_data|val_from_key:"Ubicación BIM"|val_from_key:"Coordenadas / Geometría"|val_from_key:"@value"|json_to_obj %}
|
||||||
{% for gis in gis_vector.features %}
|
{% for gis in gis_vector.features %}
|
||||||
<div class="data-row">
|
<div class="data-row">
|
||||||
<span class="data-value" style="width: 100%;">{{ gis.geometry }}</span>
|
<span class="data-value" style="width: 100%; font-size: .72em;">{{ gis.geometry|truncatewords:24 }}</span>
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% endwith %}
|
{% endwith %}
|
||||||
@@ -175,6 +175,7 @@
|
|||||||
<div class="tiles-grid-grp-col">
|
<div class="tiles-grid-grp-col">
|
||||||
<div class="tile-block">
|
<div class="tile-block">
|
||||||
<div class="tile-title">Mapa de referencia</div>
|
<div class="tile-title">Mapa de referencia</div>
|
||||||
|
<img src="data:image/png;base64,{{ resource.map_img }}">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -152,15 +152,17 @@
|
|||||||
<span class="data-label">Espacio: </span>
|
<span class="data-label">Espacio: </span>
|
||||||
<span class="data-value">{{ resource_data|val_from_key:"Localización"|val_from_key:"Espacio" }}</span>
|
<span class="data-value">{{ resource_data|val_from_key:"Localización"|val_from_key:"Espacio" }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="data-row">
|
{% if resource.print_ubic %}
|
||||||
<span class="data-label">Inmueble: </span>
|
<div class="data-row">
|
||||||
<span class="data-value">{{ resource_data|val_from_key:"Localización"|val_from_key:"Inmueble" }}</span>
|
<span class="data-label">Inmueble: </span>
|
||||||
</div>
|
<span class="data-value">{{ resource_data|val_from_key:"Localización"|val_from_key:"Inmueble" }}</span>
|
||||||
<div class="data-row">
|
</div>
|
||||||
<span class="data-label">Colección: </span>
|
<div class="data-row">
|
||||||
<span class="data-value">{{ resource_data|val_from_key:"Localización"|val_from_key:"Colección" }}</span>
|
<span class="data-label">Colección: </span>
|
||||||
</div>
|
<span class="data-value">{{ resource_data|val_from_key:"Localización"|val_from_key:"Colección" }}</span>
|
||||||
{% if resource_data|val_from_key:"Localización"|has_key:"Ubicación" %}
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
{% if resource_data|val_from_key:"Localización"|has_key:"Ubicación" and resource.print_ubic %}
|
||||||
<div class="data-row" style="margin-left: 15px;">
|
<div class="data-row" style="margin-left: 15px;">
|
||||||
<span class="data-value" style="width: 100%;"><b>Ambiente : </b> {{resource_data|val_from_key:"Localización"|val_from_key:"Ubicación"|val_from_key:"Ambiente" }}</span>
|
<span class="data-value" style="width: 100%;"><b>Ambiente : </b> {{resource_data|val_from_key:"Localización"|val_from_key:"Ubicación"|val_from_key:"Ambiente" }}</span>
|
||||||
</div>
|
</div>
|
||||||
@@ -180,11 +182,11 @@
|
|||||||
<div class="data-row">
|
<div class="data-row">
|
||||||
<span class="data-label" style="width: 100%;">Coordenadas / Geometría: </span>
|
<span class="data-label" style="width: 100%;">Coordenadas / Geometría: </span>
|
||||||
</div>
|
</div>
|
||||||
{% if resource_data|val_from_key:"Localización"|has_key:"Coordenadas / Geometría" %}
|
{% if resource_data|val_from_key:"Localización"|has_key:"Coordenadas / Geometría" and resource.print_ubic %}
|
||||||
{% with gis_vector=resource_data|val_from_key:"Localización"|val_from_key:"Coordenadas / Geometría"|val_from_key:"@value"|json_to_obj %}
|
{% with gis_vector=resource_data|val_from_key:"Localización"|val_from_key:"Coordenadas / Geometría"|val_from_key:"@value"|json_to_obj %}
|
||||||
{% for gis in gis_vector.features %}
|
{% for gis in gis_vector.features %}
|
||||||
<div class="data-row">
|
<div class="data-row">
|
||||||
<span class="data-value" style="width: 100%;">{{ gis.geometry }}</span>
|
<span class="data-value" style="width: 100%; font-size: .72em;">{{ gis.geometry|truncatewords:24 }}</span>
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% endwith %}
|
{% endwith %}
|
||||||
@@ -197,6 +199,7 @@
|
|||||||
<div class="tiles-grid-grp-col">
|
<div class="tiles-grid-grp-col">
|
||||||
<div class="tile-block">
|
<div class="tile-block">
|
||||||
<div class="tile-title">Mapa de referencia</div>
|
<div class="tile-title">Mapa de referencia</div>
|
||||||
|
<img src="data:image/png;base64,{{ resource.map_img }}">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -126,7 +126,7 @@
|
|||||||
{% with gis_vector=resource_data|val_from_key:"Ubicación 2"|val_from_key:"Coordenadas / Geometría"|val_from_key:"@value"|json_to_obj %}
|
{% with gis_vector=resource_data|val_from_key:"Ubicación 2"|val_from_key:"Coordenadas / Geometría"|val_from_key:"@value"|json_to_obj %}
|
||||||
{% for gis in gis_vector.features %}
|
{% for gis in gis_vector.features %}
|
||||||
<div class="data-row">
|
<div class="data-row">
|
||||||
<span class="data-value" style="width: 100%;">{{ gis.geometry }}</span>
|
<span class="data-value" style="width: 100%; font-size: .72em;">{{ gis.geometry|truncatewords:24 }}</span>
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% endwith %}
|
{% endwith %}
|
||||||
@@ -140,6 +140,7 @@
|
|||||||
<div class="tiles-grid-grp-col">
|
<div class="tiles-grid-grp-col">
|
||||||
<div class="tile-block">
|
<div class="tile-block">
|
||||||
<div class="tile-title">Mapa de referencia</div>
|
<div class="tile-title">Mapa de referencia</div>
|
||||||
|
<img src="data:image/png;base64,{{ resource.map_img }}">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -15,11 +15,15 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="report-print-date" data-bind="component: {
|
<div class="report-print-date" data-bind="component: {
|
||||||
name: 'views/components/simple-switch',
|
name: 'views/components/simple-switch',
|
||||||
params: { value: anexarImagenes, config:{ label: 'Incluir imágenes adjuntas'}}}">
|
params: { value: satMap, config:{ label: 'Mapa satelital'}}}">
|
||||||
</div>
|
</div>
|
||||||
<div class="report-print-date" data-bind="component: {
|
<div class="report-print-date" data-bind="component: {
|
||||||
name: 'views/components/simple-switch',
|
name: 'views/components/simple-switch',
|
||||||
params: { value: anexarPdfs, config:{ label: 'Incluir documentos (pdf) adjuntos'}}}">
|
params: { value: anexarImagenes, config:{ label: 'Adjuntar imágenes'}}}">
|
||||||
|
</div>
|
||||||
|
<div class="report-print-date" data-bind="component: {
|
||||||
|
name: 'views/components/simple-switch',
|
||||||
|
params: { value: anexarPdfs, config:{ label: 'Adjuntar documentos (pdf)'}}}">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
Reference in New Issue
Block a user