terminada a falta de revisar textos

master
dev 12 months ago
parent 819851dac7
commit 987d0def0b

@ -4,4 +4,9 @@
export const warningIconB64 = 'iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAABlUlEQVR4nOyVvWtTURjGf+feEOONix9DwEkIiB/EQcE5omCIIKg4OYqDOOomCIpbof07QjukTSDQoXOXtkNKaZZOpe3WoUnTpslb7hfNx7m594ZmKPSBAznvOe/ze/Oec7gGU9Y1IFSJqBulxE0sZpxJi5/qM8eXCsDiH/Dd+90CfkVJU1E2SZksJnXghhc6xSSnCmyH5UY7A5O5PnNbSc68doUo9B9IhdfAsjNJ3XeD7V0/u6CK1CYGyAoJmqwDT+1596XrZa6+9bdskeGZekEnyGN8i5r88M1d51vuuNAj9ryDjwuQGneA32MLwOnBH1niXmwAXf4Dd0MBcBvF31gAWeQJwteRYjuHztDom5TJ6Rb0D81gVrdmbHwJKtT0rvKrUavh6qt8BN7oXCT90BkBykuFD8PBgWsqJZJYbAJZnUPv+QKIYKx9CoLskOaxytP2A4NtsHgfZG7LqI+9kbYecMQ7YF4PEBooh57Spp8chAHa9Gj0B0ZeslTJIH2PK44UdVVkf6LcSXX1P5lTB5wHAAD//0kDVOGS5cmMAAAAAElFTkSuQmCC'; // Imágenes generadas automáticamente
export const precaucionIconB64 = "iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAByUlEQVR4nOxVu4sTQRj/fZMzuUviwXnnq7hCuUY8Ym0364OgMRGUkN5XESwNNoKoKAoBtfZP0MoiCBamswo2ATGNhYUa8n6sMbr7SUYjCftMMIVwPxh29pv5PWZ2hhVYMHYMPLHkd+Kn4+mVSFDPj/r9YfjG5tvn3/6pQTQ0uMeg7KgfCek6gJwfHvmZ1JapLQNmGUBIFRhDQ4jY3jcvP3hxfX0DA/zkr/jvWMEAm3k/XM8V1GTilAC9Vmn2b6ia+bWmngzzzHqx8GpuA5ZyqYnoOwDbo/fVZ49UvXP15njK+7Xu52NUKv1w0nDdohYi18fiKk14WbUJHGntPph103A0aMfjexh0y40MtU243ZHJjZkNjO+77gNY9zIAsPaTcHcmg7qWPArgiiVttw/u9KwE5muNk6mYnZbtRRNsPmaQZaybe+AUNABDHeUTniuoa8mLDDptq3J4UzV7sNbUEhdcDTidDhLzQ6eY4csZrFzKOA2DmfIfpZw6ZlPb0Kjq54loy0mgd+epo/gfHFpF9ByAF7YGQlCFGQMAy3Zss970MhhQQFQmC5abXJVnDwjQtpeSbQBweV+x8GUe7tz4/3+ZCzf4FQAA//8XSHr/N7SpsQAAAABJRU5ErkJggg=="
export const advertenciaIconB64 = "iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAABlUlEQVR4nOyVvWtTURjGf+feEOONix9DwEkIiB/EQcE5omCIIKg4OYqDOOomCIpbof07QjukTSDQoXOXtkNKaZZOpe3WoUnTpslb7hfNx7m594ZmKPSBAznvOe/ze/Oec7gGU9Y1IFSJqBulxE0sZpxJi5/qM8eXCsDiH/Dd+90CfkVJU1E2SZksJnXghhc6xSSnCmyH5UY7A5O5PnNbSc68doUo9B9IhdfAsjNJ3XeD7V0/u6CK1CYGyAoJmqwDT+1596XrZa6+9bdskeGZekEnyGN8i5r88M1d51vuuNAj9ryDjwuQGneA32MLwOnBH1niXmwAXf4Dd0MBcBvF31gAWeQJwteRYjuHztDom5TJ6Rb0D81gVrdmbHwJKtT0rvKrUavh6qt8BN7oXCT90BkBykuFD8PBgWsqJZJYbAJZnUPv+QKIYKx9CoLskOaxytP2A4NtsHgfZG7LqI+9kbYecMQ7YF4PEBooh57Spp8chAHa9Gj0B0ZeslTJIH2PK44UdVVkf6LcSXX1P5lTB5wHAAD//0kDVOGS5cmMAAAAAElFTkSuQmCC"

@ -187,13 +187,13 @@ export const proyecto : Proyecto = {
nombre : 'Viggo Fresno', nombre : 'Viggo Fresno',
value : 'sufr', value : 'sufr',
material: 'suelo_viggo_fresno', material: 'suelo_viggo_fresno',
filtro : 'filterSuelos' filtro : 'suelo'
}, },
{ {
nombre : 'Viggo Roble', nombre : 'Viggo Roble',
value : 'suro', value : 'suro',
material: 'suelo_viggo_roble', material: 'suelo_viggo_roble',
filtro : 'filterSuelos' filtro : 'suelo'
} }
] ]
}, },
@ -273,13 +273,13 @@ export const proyecto : Proyecto = {
{ {
nombre : 'Viggo Fresno', nombre : 'Viggo Fresno',
value : 'sufr', value : 'sufr',
filtro : 'filterSuelos', filtro : 'suelo',
material: 'suelo_viggo_fresno', material: 'suelo_viggo_fresno',
}, },
{ {
nombre : 'Viggo Roble', nombre : 'Viggo Roble',
material: 'suelo_viggo_roble', material: 'suelo_viggo_roble',
filtro : 'filterSuelos', filtro : 'suelo',
value : 'suro' value : 'suro'
} }
] ]

@ -4,13 +4,21 @@
import { jsPDF} from "jspdf"; import { jsPDF} from "jspdf";
import { pdfImages } from "../../data/data_pdfs_b64"; import { pdfImages } from "../../data/data_pdfs_b64";
import { renderImages } from "../../data/data_images.b64"; import { renderImages } from "../../data/data_images.b64";
import {estanciasImagen, getSelecciones, imagesNames} from "../stores/configurador.svelte.js"; import {
type EstanciaImagen, type EstanciaSeleccion,
estanciasImagen,
getSelecciones,
imagesNames,
type Selecciones
} from "../stores/configurador.svelte.js";
import {proyecto} from "../../data/data_proyecto"; import {proyecto} from "../../data/data_proyecto";
import { projectFonts } from "../../data/data_fonts"; import { projectFonts } from "../../data/data_fonts";
import {formatearPrecio} from "../utils/formaters.js"; import {formatearPrecio} from "../utils/formaters.js";
import { warningIconB64 } from "../../data/data_icons_b64"; import { advertenciaIconB64, precaucionIconB64 } from "../../data/data_icons_b64";
import * as JSPdf from "jspdf"; import {filtros} from "../utils/filtros";
import type {Estancia} from "../../data/data_types";
let pdfEstado : PdfEstado = 'idle'; let pdfEstado : PdfEstado = 'idle';
@ -23,271 +31,13 @@
const textNotify = 'Consulte si las opciones seleccionadas estan disponibles para la tipología de su vivienda.'; const textNotify = 'Consulte si las opciones seleccionadas estan disponibles para la tipología de su vivienda.';
const textError = 'El pavimento es diferente al seleccionado en el salón, que es el que determina el pavimento de la vivienda.' const textError = 'El pavimento es diferente al seleccionado en el salón, que es el que determina el pavimento de la vivienda.'
/*
async function generatePdf() {
pdfVisible = true;
pdfEstado = 'creating';
const estancias = estanciasImagen();
const selecciones = getSelecciones();
try {
const pdfDoc = new jsPDF({
orientation: 'landscape',
unit: 'mm',
format: 'a4',
});
// Registrar Didot
const tf = projectFonts['Didot']
pdfDoc.addFileToVFS(tf.filename, tf.base64);
pdfDoc.addFont(tf.filename, tf.name,tf.style);
// Registrar Proxima Nova Regular
const pf = projectFonts['proxima_nova_regular']
pdfDoc.addFileToVFS(pf.filename, pf.base64);
pdfDoc.addFont(pf.filename, pf.name, pf.style);
// Registrar Proxima Nova Bold
const pb = projectFonts['proxima_nova_bold']
pdfDoc.addFileToVFS(pb.filename, pb.base64);
pdfDoc.addFont(pb.filename, pb.name, pb.style);
// Registrar Proxima Nova Light
const pl = projectFonts['proxima_nova_light']
pdfDoc.addFileToVFS(pl.filename, pl.base64);
pdfDoc.addFont(pl.filename, pl.name, pl.style);
const titleFont = tf.name;
const textFont = pf.name;
const textLightFont = pl.name;
const textBoldFont = pb.name;
console.log(pdfDoc.getFontList());
const pageWidth = pdfDoc.internal.pageSize.getWidth();
const pageHeight = pdfDoc.internal.pageSize.getHeight();
const margin = 15;
// === Portada ===
const ini = pdfImages['pdf_quaddro_ini'];
if (ini) {
const iniFormat = ini.includes('jpeg') ? 'JPEG' : 'PNG';
pdfDoc.addImage(ini, iniFormat, 0, 0, pageWidth, pageHeight, '', 'FAST');
pdfDoc.addPage();
}
// === Imágenes del array ===
estancias.forEach((entrada, index) => {
const base64 = renderImages[entrada.imagen];
if (!base64) {
console.log('no existe la imagen ', entrada.imagen)
return;
}
// Datos de la imagen original
const imgPixelWidth = 1500;
const imgPixelHeight = 1500;
const pageRatio = pageWidth / pageHeight;
const imgRatio = imgPixelWidth / imgPixelHeight;
// Calcular tamaño para que mantenga proporción y ajuste a la altura de página
let renderWidth: number;
let renderHeight: number;
if (imgRatio > pageRatio) {
// Imagen más ancha que alta → ajustamos al alto
renderHeight = pageHeight - 2 * margin;
renderWidth = renderHeight * imgRatio;
} else {
// Imagen más alta → también ajustamos al alto
renderHeight = pageHeight - 2 * margin;
renderWidth = renderHeight * imgRatio;
}
// Posición alineada a la izquierda con margen de 15 mm
const x = margin;
const y = (pageHeight - renderHeight) / 2;
pdfDoc.addImage(base64, 'JPEG', x, y, renderWidth, renderHeight, '', 'FAST');
//----------------------------------------
// TEXTO
//----------------------------------------
const estanciaId = entrada.estanciaId;
const estancia = proyecto.estancias[estanciaId];
const seleccion = selecciones?[estanciaId] : {};
const textStartX = margin + renderWidth + 10; // derecha de la imagen + margen
let cursorY = margin + 5; // margen superior
// Función auxiliar para texto multilínea
function addTextBlock(
text: string | string[] | null | undefined,
x: number,
yStart: number,
maxWidth: number,
fontSize: number,
lineHeight: number
) {
// Normalizar entrada
if (text == null) return yStart;
let safeText: string;
if (Array.isArray(text)) safeText = text.join("\n");
else safeText = String(text);
if (safeText.trim().length === 0) return yStart;
// Configurar fuente y tamaño
pdfDoc.setFont(textFont, "normal");
pdfDoc.setFontSize(fontSize);
// Dividir en párrafos respetando CRLF y LF
const paragraphs = safeText.split(/\r?\n/);
let cursorY = yStart;
for (let p = 0; p < paragraphs.length; p++) {
const paragraph = paragraphs[p];
// Si es párrafo vacío, avanzamos una línea (preserva dobles saltos)
if (paragraph.trim().length === 0) {
cursorY += lineHeight;
continue;
}
// splitTextToSize por cada párrafo para respetar maxWidth
const lines = pdfDoc.splitTextToSize(paragraph, maxWidth);
for (let i = 0; i < lines.length; i++) {
pdfDoc.text(lines[i], x, cursorY + i * lineHeight);
}
// avanzar cursorY: todas las líneas del párrafo + 1*lineHeight como espacio entre párrafos
cursorY += lines.length * lineHeight + lineHeight;
}
// devolver la siguiente posición Y disponible
return cursorY;
}
// === Título ===
pdfDoc.setFontSize(18);
pdfDoc.setFont(titleFont, "normal");
pdfDoc.text((estancia.nombre || estanciaId).toUpperCase(), textStartX, cursorY);
// === Descripción ===
pdfDoc.setFont(textLightFont, "normal");
if (estancia.texto) {
cursorY += 8;
cursorY = addTextBlock(estancia.texto, textStartX, cursorY, pageWidth - textStartX - margin, 12, 5);
}
// === Opciones y Add-ons al margen inferior ===
const opciones = seleccion.opciones ?? [];
const adds = seleccion.adds ?? [];
const lineHeightOpc = 5;
const lineHeightAdd = 5;
// --- Calcular altura total de los bloques ---
let totalOpcHeight = 0;
opciones.forEach((grupo: Record<string, any>) => {
const nombreGrupo = Object.keys(grupo)[0];
const opcion = grupo[nombreGrupo];
totalOpcHeight += pdfDoc.splitTextToSize(`${nombreGrupo}: ${opcion.nombre}`, pageWidth - textStartX - margin - 5).length * lineHeightOpc + 2;
});
let totalAddsHeight = 0;
adds.forEach((add: Record<string, any>) => {
const nombreAdd = Object.keys(add)[0];
totalAddsHeight += pdfDoc.splitTextToSize(nombreAdd, pageWidth - textStartX - margin - 5).length * lineHeightAdd + 2;
});
// --- Posicionar el cursorY desde el fondo ---
let cursorBottomY = pageHeight - margin - totalOpcHeight - totalAddsHeight - 10; // 10 mm margen entre bloques
// === Opciones seleccionadas ===
if (opciones.length > 0) {
pdfDoc.setFont(textFont, "normal");
pdfDoc.setFontSize(11);
pdfDoc.text("Opciones seleccionadas:", textStartX, cursorBottomY);
pdfDoc.setFont(textFont, "normal");
pdfDoc.setFontSize(10);
cursorBottomY += 5;
opciones.forEach((grupo: Record<string, any>) => {
const nombreGrupo = Object.keys(grupo)[0];
const opcion = grupo[nombreGrupo];
cursorBottomY = addTextBlock(`${nombreGrupo}: ${opcion.nombre}`, textStartX + 5, cursorBottomY, pageWidth - textStartX - margin - 5, 10, lineHeightOpc);
});
}
// === Add-ons seleccionados ===
if (adds.length > 0) {
cursorBottomY += 5;
pdfDoc.setFont(textFont, "normal");
pdfDoc.setFontSize(11);
pdfDoc.text("Add-ons seleccionados:", textStartX, cursorBottomY);
pdfDoc.setFont(textFont, "normal");
pdfDoc.setFontSize(10);
cursorBottomY += 5;
adds.forEach((add: Record<string, any>) => {
const nombreAdd = Object.keys(add)[0];
cursorBottomY = addTextBlock(nombreAdd, textStartX + 5, cursorBottomY, pageWidth - textStartX - margin - 5, 10, lineHeightAdd);
});
}
//---------------------------------
// NUEVA PAGINA
//---------------------------------
// Añadir nueva página excepto en la última
if (index < estancias.length - 1) pdfDoc.addPage();
});
// === Página final ===
pdfDoc.addPage();
const fin = pdfImages['pdf_quaddro_fin'];
if (fin) {
const finFormat = fin.includes('jpeg') ? 'JPEG' : 'PNG';
pdfDoc.addImage(fin, finFormat, 0, 0, pageWidth, pageHeight, '', 'FAST');
}
await new Promise(r => setTimeout(r, stepTimeout))
pdfEstado = 'downloading';
pdfDoc.save(proyecto.textos.nombre_pdf ?? 'mi_seleccion.pdf');
pdfEstado = 'success'
} catch (err: any) {
pdfEstado = 'error';
pdfMensaje = err?.message || 'Error desconocido';
console.log(err)
} finally {
setTimeout(() => {
pdfVisible = false;
pdfEstado = 'idle';
}, stepTimeout);
}
}
*/
async function generatePdf() { async function generatePdf() {
pdfVisible = true; pdfVisible = true;
pdfEstado = 'creating'; pdfEstado = 'creating';
const estancias = estanciasImagen(); const estancias : EstanciaImagen[] = estanciasImagen();
const selecciones = getSelecciones(); const selecciones : Selecciones | null = getSelecciones();
try { try {
const pdfDoc = new jsPDF({ const pdfDoc = new jsPDF({
@ -412,6 +162,7 @@
const lineHeightAdd = 3; const lineHeightAdd = 3;
let notify = false; let notify = false;
let prohibido = false;
// === Opciones seleccionadas === // === Opciones seleccionadas ===
if (opciones.length > 0) { if (opciones.length > 0) {
@ -427,10 +178,19 @@
for (const grupo of opciones) { for (const grupo of opciones) {
const nombreGrupo = Object.keys(grupo)[0]; const nombreGrupo = Object.keys(grupo)[0];
const opcion = grupo[nombreGrupo]; const opcion = grupo[nombreGrupo];
let icon: string | null = null;
if (opcion.filtro && filtros[opcion.filtro]) {
if (!filtros[opcion.filtro].check(opcion.value)) {
icon = precaucionIconB64;
if (!prohibido) prohibido = true;
}
}
const label = `${nombreGrupo}: ${opcion?.nombre ?? ''}`; const label = `${nombreGrupo}: ${opcion?.nombre ?? ''}`;
// precio puede estar en opcion.precio o opcion.price // precio puede estar en opcion.precio o opcion.price
const priceVal = opcion?.precio ?? opcion?.price ?? null; const priceVal = opcion?.precio ?? opcion?.price ?? null;
cursorBoxY = addOptionLine(pdfDoc,label, priceVal, textBoxX, cursorBoxY, textBoxMaxWidth - 6, textFont, 10, textFont, 10, { r: 30, g: 30, b: 30 }); cursorBoxY = addOptionLine(pdfDoc,label, priceVal, textBoxX, cursorBoxY, textBoxMaxWidth - 6, textFont, 10, textFont, 10, { r: 30, g: 30, b: 30 },icon);
} }
} }
@ -450,7 +210,7 @@
const info = add[Object.keys(add)[0]]; const info = add[Object.keys(add)[0]];
const priceVal = info?.precio ?? info?.price ?? null; const priceVal = info?.precio ?? info?.price ?? null;
let label = info.nombre; let label = info.nombre;
let icon : string | null = info.filtro ? warningIconB64 : null; let icon : string | null = info.filtro ? advertenciaIconB64 : null;
if (info.filtro) { if (info.filtro) {
notify = true; notify = true;
} }
@ -459,8 +219,14 @@
} }
} }
let pieY = 200;
const pieX = 15;
if (prohibido) {
addOptionLine(pdfDoc,textError,null,margin,pieY,1000,textFont,9,null,null,undefined,precaucionIconB64);
pieY += 4;
}
if (notify) { if (notify) {
addOptionLine(pdfDoc,textNotify,null,15,200,1000,textFont,9,null,null,undefined,warningIconB64); addOptionLine(pdfDoc,textNotify,null,margin,pieY,1000,textFont,9,null,null,undefined,advertenciaIconB64);
} }

@ -314,12 +314,12 @@ export function getIncidencias(): IncidenciasEstancia | null {
type EstanciaSeleccion = { export type EstanciaSeleccion = {
opciones: Record<string, Opcion>[]; // { "grupo": "valor seleccionado" } opciones: Record<string, Opcion>[]; // { "grupo": "valor seleccionado" }
adds: Record<string, Add>[]; // { "add": "valor seleccionado" } adds: Record<string, Add>[]; // { "add": "valor seleccionado" }
}; };
type Selecciones = Record<string, EstanciaSeleccion>; // { "estanciaId": {...} } export type Selecciones = Record<string, EstanciaSeleccion>; // { "estanciaId": {...} }
export function getSelecciones (): Selecciones | null { export function getSelecciones (): Selecciones | null {
@ -368,45 +368,3 @@ export function getSelecciones (): Selecciones | null {
} }
/* Deprecated
export function getSelecciones(): Selecciones | null {
const result: Selecciones = {};
for (const estanciaId of Object.keys(proyecto.estancias || {})) {
const estanciaData = proyecto.estancias[estanciaId];
const estanciaSelections = selections[estanciaId];
const estanciaAddOns = selectedAdds[estanciaId];
if (!estanciaData) continue;
const opciones: Record<string, Opcion>[] = [];
const adds: Record<string, Add>[] = [];
// Opciones
if (estanciaData.opciones && estanciaSelections) {
for (const grupo of estanciaData.opciones) {
const selectedValue = estanciaSelections[grupo.nombre];
if (selectedValue && grupo.opciones) {
const opcion = grupo.opciones.find(o => o.value === selectedValue);
if (opcion) opciones.push({ [grupo.nombre]: opcion });
}
}
}
// Add-ons
if (estanciaData.adds && estanciaAddOns) {
for (const [addKey, add] of Object.entries(estanciaData.adds)) {
if (estanciaAddOns[addKey]) adds.push({ [add.nombre]: add });
}
}
if (opciones.length > 0 || adds.length > 0) {
result[estanciaId] = { opciones, adds };
}
}
return Object.keys(result).length > 0 ? result : null;
}
*/

@ -29,7 +29,7 @@ export const navegationState = {
{ id: 'ini', label: 'Inicio', menu: false }, { id: 'ini', label: 'Inicio', menu: false },
{ id: 'cfg', label: 'Personalizar', menu: true }, { id: 'cfg', label: 'Personalizar', menu: true },
{ id: 'sel', label: 'Mi Selección', menu: true }, { id: 'sel', label: 'Mi Selección', menu: true },
{ id: 'at' , label: 'Active Thing', menu: true }, { id: 'at' , label: 'Active Thing', menu: false },
] as PageInfo[], ] as PageInfo[],
} }

Loading…
Cancel
Save

Powered by TurnKey Linux.