Complete migration from docx-templates to docxtemplater
✅ Migration completed: - server.js: Complete rewrite using docxtemplater + pizzip - server-old.js: Backup of original docx-templates implementation - package.json: Added docxtemplater and pizzip dependencies - Removed docx-templates dependency 🚀 New features: - True dynamic tables with {#array}{field}{/array} syntax - Unlimited table rows (no more fixed array indices) - New API endpoints: /analyze, /generate, /demo - Simplified template creation scripts 🎯 Template improvements: - Updated template syntax examples - Added dynamic-template.docx with loop syntax - Enhanced template analysis functionality 📊 Benefits: - Real dynamic table generation - Better template flexibility - Cleaner API design - Preserved SSL and WebDAV functionality
This commit is contained in:
parent
4ac60601f0
commit
a01423321b
132
create-angebot-template.js
Normal file
132
create-angebot-template.js
Normal file
@ -0,0 +1,132 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const AdmZip = require('adm-zip');
|
||||
|
||||
function createOfferTemplate() {
|
||||
try {
|
||||
const zip = new AdmZip();
|
||||
|
||||
// [Content_Types].xml
|
||||
const contentTypes = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types">
|
||||
<Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/>
|
||||
<Default Extension="xml" ContentType="application/xml"/>
|
||||
<Override PartName="/word/document.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml"/>
|
||||
</Types>`;
|
||||
|
||||
// _rels/.rels
|
||||
const rels = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
|
||||
<Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Target="word/document.xml"/>
|
||||
</Relationships>`;
|
||||
|
||||
// word/document.xml - Angebot Template
|
||||
const document = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
|
||||
<w:body>
|
||||
<w:p>
|
||||
<w:pPr><w:jc w:val="center"/></w:pPr>
|
||||
<w:r><w:rPr><w:b/><w:sz w:val="32"/></w:rPr><w:t>ANGEBOT</w:t></w:r>
|
||||
</w:p>
|
||||
|
||||
<w:p><w:r><w:t></w:t></w:r></w:p>
|
||||
|
||||
<w:tbl>
|
||||
<w:tblPr><w:tblW w:w="0" w:type="auto"/></w:tblPr>
|
||||
<w:tr>
|
||||
<w:tc><w:p><w:r><w:rPr><w:b/></w:rPr><w:t>Anbieter:</w:t></w:r></w:p></w:tc>
|
||||
<w:tc><w:p><w:r><w:rPr><w:b/></w:rPr><w:t>Interessent:</w:t></w:r></w:p></w:tc>
|
||||
</w:tr>
|
||||
<w:tr>
|
||||
<w:tc><w:p><w:r><w:t>++firma++</w:t></w:r></w:p></w:tc>
|
||||
<w:tc><w:p><w:r><w:t>++kunde_name++</w:t></w:r></w:p></w:tc>
|
||||
</w:tr>
|
||||
<w:tr>
|
||||
<w:tc><w:p><w:r><w:t>++straße++</w:t></w:r></w:p></w:tc>
|
||||
<w:tc><w:p><w:r><w:t>++kunde_straße++</w:t></w:r></w:p></w:tc>
|
||||
</w:tr>
|
||||
<w:tr>
|
||||
<w:tc><w:p><w:r><w:t>++plz++ ++stadt++</w:t></w:r></w:p></w:tc>
|
||||
<w:tc><w:p><w:r><w:t>++kunde_plz++ ++kunde_stadt++</w:t></w:r></w:p></w:tc>
|
||||
</w:tr>
|
||||
<w:tr>
|
||||
<w:tc><w:p><w:r><w:t>Ansprechpartner: ++ansprechpartner++</w:t></w:r></w:p></w:tc>
|
||||
<w:tc><w:p><w:r><w:t>Email: ++kunde_email++</w:t></w:r></w:p></w:tc>
|
||||
</w:tr>
|
||||
<w:tr>
|
||||
<w:tc><w:p><w:r><w:t>Email: ++email++</w:t></w:r></w:p></w:tc>
|
||||
<w:tc><w:p><w:r><w:t>Tel: ++kunde_telefon++</w:t></w:r></w:p></w:tc>
|
||||
</w:tr>
|
||||
</w:tbl>
|
||||
|
||||
<w:p><w:r><w:t></w:t></w:r></w:p>
|
||||
|
||||
<w:p><w:r><w:rPr><w:b/></w:rPr><w:t>Angebotsnummer: ++angebotsnummer++</w:t></w:r></w:p>
|
||||
<w:p><w:r><w:rPr><w:b/></w:rPr><w:t>Angebotsdatum: ++datum++</w:t></w:r></w:p>
|
||||
<w:p><w:r><w:rPr><w:b/></w:rPr><w:t>Gültig bis: ++gültig_bis++</w:t></w:r></w:p>
|
||||
<w:p><w:r><w:rPr><w:b/></w:rPr><w:t>Projekt: ++projekt_name++</w:t></w:r></w:p>
|
||||
|
||||
<w:p><w:r><w:t></w:t></w:r></w:p>
|
||||
<w:p><w:r><w:t>Sehr geehrte Damen und Herren,</w:t></w:r></w:p>
|
||||
<w:p><w:r><w:t></w:t></w:r></w:p>
|
||||
<w:p><w:r><w:t>gerne unterbreiten wir Ihnen folgendes Angebot:</w:t></w:r></w:p>
|
||||
<w:p><w:r><w:t></w:t></w:r></w:p>
|
||||
|
||||
<w:tbl>
|
||||
<w:tblPr><w:tblW w:w="0" w:type="auto"/></w:tblPr>
|
||||
<w:tr>
|
||||
<w:tc><w:p><w:r><w:rPr><w:b/></w:rPr><w:t>Pos.</w:t></w:r></w:p></w:tc>
|
||||
<w:tc><w:p><w:r><w:rPr><w:b/></w:rPr><w:t>Leistung</w:t></w:r></w:p></w:tc>
|
||||
<w:tc><w:p><w:r><w:rPr><w:b/></w:rPr><w:t>Beschreibung</w:t></w:r></w:p></w:tc>
|
||||
<w:tc><w:p><w:r><w:rPr><w:b/></w:rPr><w:t>Aufwand</w:t></w:r></w:p></w:tc>
|
||||
<w:tc><w:p><w:r><w:rPr><w:b/></w:rPr><w:t>Preis</w:t></w:r></w:p></w:tc>
|
||||
</w:tr>
|
||||
<w:tr>
|
||||
<w:tc><w:p><w:r><w:t>++leistungen[0].nr++</w:t></w:r></w:p></w:tc>
|
||||
<w:tc><w:p><w:r><w:t>++leistungen[0].titel++</w:t></w:r></w:p></w:tc>
|
||||
<w:tc><w:p><w:r><w:t>++leistungen[0].beschreibung++</w:t></w:r></w:p></w:tc>
|
||||
<w:tc><w:p><w:r><w:t>++leistungen[0].aufwand++</w:t></w:r></w:p></w:tc>
|
||||
<w:tc><w:p><w:r><w:t>++leistungen[0].preis++</w:t></w:r></w:p></w:tc>
|
||||
</w:tr>
|
||||
</w:tbl>
|
||||
|
||||
<w:p><w:r><w:t></w:t></w:r></w:p>
|
||||
|
||||
<w:p><w:r><w:rPr><w:b/></w:rPr><w:t>Gesamtpreis: ++gesamtpreis++</w:t></w:r></w:p>
|
||||
<w:p><w:r><w:t>Alle Preise verstehen sich zzgl. der gesetzlichen Mehrwertsteuer.</w:t></w:r></w:p>
|
||||
|
||||
<w:p><w:r><w:t></w:t></w:r></w:p>
|
||||
<w:p><w:r><w:rPr><w:b/></w:rPr><w:t>Projektdauer:</w:t></w:r></w:p>
|
||||
<w:p><w:r><w:t>Geplanter Projektstart: ++projektstart++</w:t></w:r></w:p>
|
||||
<w:p><w:r><w:t>Voraussichtliche Fertigstellung: ++projektende++</w:t></w:r></w:p>
|
||||
|
||||
<w:p><w:r><w:t></w:t></w:r></w:p>
|
||||
<w:p><w:r><w:rPr><w:b/></w:rPr><w:t>Zahlungskonditionen:</w:t></w:r></w:p>
|
||||
<w:p><w:r><w:t>++zahlungskonditionen++</w:t></w:r></w:p>
|
||||
|
||||
<w:p><w:r><w:t></w:t></w:r></w:p>
|
||||
<w:p><w:r><w:t>Für Rückfragen stehen wir Ihnen gerne zur Verfügung.</w:t></w:r></w:p>
|
||||
<w:p><w:r><w:t></w:t></w:r></w:p>
|
||||
<w:p><w:r><w:t>Mit freundlichen Grüßen</w:t></w:r></w:p>
|
||||
<w:p><w:r><w:t>++ansprechpartner++</w:t></w:r></w:p>
|
||||
|
||||
</w:body>
|
||||
</w:document>`;
|
||||
|
||||
// Dateien zum ZIP hinzufügen
|
||||
zip.addFile('[Content_Types].xml', Buffer.from(contentTypes, 'utf8'));
|
||||
zip.addFile('_rels/.rels', Buffer.from(rels, 'utf8'));
|
||||
zip.addFile('word/document.xml', Buffer.from(document, 'utf8'));
|
||||
|
||||
// DOCX speichern
|
||||
const templatePath = path.join(__dirname, 'templates', 'angebot-template.docx');
|
||||
fs.writeFileSync(templatePath, zip.toBuffer());
|
||||
|
||||
console.log('✅ Angebot-Template erstellt:', templatePath);
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ Fehler beim Erstellen des Angebot-Templates:', error);
|
||||
}
|
||||
}
|
||||
|
||||
createOfferTemplate();
|
||||
117
create-brief-template.js
Normal file
117
create-brief-template.js
Normal file
@ -0,0 +1,117 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const AdmZip = require('adm-zip');
|
||||
|
||||
function createLetterTemplate() {
|
||||
try {
|
||||
const zip = new AdmZip();
|
||||
|
||||
// [Content_Types].xml
|
||||
const contentTypes = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types">
|
||||
<Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/>
|
||||
<Default Extension="xml" ContentType="application/xml"/>
|
||||
<Override PartName="/word/document.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml"/>
|
||||
</Types>`;
|
||||
|
||||
// _rels/.rels
|
||||
const rels = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
|
||||
<Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Target="word/document.xml"/>
|
||||
</Relationships>`;
|
||||
|
||||
// word/document.xml - Brief Template
|
||||
const document = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
|
||||
<w:body>
|
||||
<w:p>
|
||||
<w:pPr><w:jc w:val="right"/></w:pPr>
|
||||
<w:r><w:rPr><w:b/></w:rPr><w:t>++firma++</w:t></w:r>
|
||||
</w:p>
|
||||
<w:p>
|
||||
<w:pPr><w:jc w:val="right"/></w:pPr>
|
||||
<w:r><w:t>++straße++</w:t></w:r>
|
||||
</w:p>
|
||||
<w:p>
|
||||
<w:pPr><w:jc w:val="right"/></w:pPr>
|
||||
<w:r><w:t>++plz++ ++stadt++</w:t></w:r>
|
||||
</w:p>
|
||||
<w:p>
|
||||
<w:pPr><w:jc w:val="right"/></w:pPr>
|
||||
<w:r><w:t>Tel: ++telefon++</w:t></w:r>
|
||||
</w:p>
|
||||
<w:p>
|
||||
<w:pPr><w:jc w:val="right"/></w:pPr>
|
||||
<w:r><w:t>Email: ++email++</w:t></w:r>
|
||||
</w:p>
|
||||
|
||||
<w:p><w:r><w:t></w:t></w:r></w:p>
|
||||
<w:p><w:r><w:t></w:t></w:r></w:p>
|
||||
<w:p><w:r><w:t></w:t></w:r></w:p>
|
||||
|
||||
<w:p><w:r><w:t>++empfänger_name++</w:t></w:r></w:p>
|
||||
<w:p><w:r><w:t>++empfänger_straße++</w:t></w:r></w:p>
|
||||
<w:p><w:r><w:t>++empfänger_plz++ ++empfänger_stadt++</w:t></w:r></w:p>
|
||||
|
||||
<w:p><w:r><w:t></w:t></w:r></w:p>
|
||||
<w:p><w:r><w:t></w:t></w:r></w:p>
|
||||
|
||||
<w:p>
|
||||
<w:pPr><w:jc w:val="right"/></w:pPr>
|
||||
<w:r><w:t>++ort++, ++datum++</w:t></w:r>
|
||||
</w:p>
|
||||
|
||||
<w:p><w:r><w:t></w:t></w:r></w:p>
|
||||
|
||||
<w:p><w:r><w:rPr><w:b/></w:rPr><w:t>++betreff++</w:t></w:r></w:p>
|
||||
|
||||
<w:p><w:r><w:t></w:t></w:r></w:p>
|
||||
|
||||
<w:p><w:r><w:t>++anrede++,</w:t></w:r></w:p>
|
||||
|
||||
<w:p><w:r><w:t></w:t></w:r></w:p>
|
||||
|
||||
<w:p><w:r><w:t>++einleitungstext++</w:t></w:r></w:p>
|
||||
|
||||
<w:p><w:r><w:t></w:t></w:r></w:p>
|
||||
|
||||
<w:p><w:r><w:t>++haupttext++</w:t></w:r></w:p>
|
||||
|
||||
<w:p><w:r><w:t></w:t></w:r></w:p>
|
||||
|
||||
<w:p><w:r><w:t>++schlusstext++</w:t></w:r></w:p>
|
||||
|
||||
<w:p><w:r><w:t></w:t></w:r></w:p>
|
||||
|
||||
<w:p><w:r><w:t>++grußformel++</w:t></w:r></w:p>
|
||||
|
||||
<w:p><w:r><w:t></w:t></w:r></w:p>
|
||||
<w:p><w:r><w:t></w:t></w:r></w:p>
|
||||
|
||||
<w:p><w:r><w:t>++absender_name++</w:t></w:r></w:p>
|
||||
<w:p><w:r><w:t>++position++</w:t></w:r></w:p>
|
||||
|
||||
<w:p><w:r><w:t></w:t></w:r></w:p>
|
||||
|
||||
<w:p><w:r><w:rPr><w:i/></w:rPr><w:t>Anlagen: ++anlagen++</w:t></w:r></w:p>
|
||||
|
||||
</w:body>
|
||||
</w:document>`;
|
||||
|
||||
// Dateien zum ZIP hinzufügen
|
||||
zip.addFile('[Content_Types].xml', Buffer.from(contentTypes, 'utf8'));
|
||||
zip.addFile('_rels/.rels', Buffer.from(rels, 'utf8'));
|
||||
zip.addFile('word/document.xml', Buffer.from(document, 'utf8'));
|
||||
|
||||
// DOCX speichern
|
||||
const templatePath = path.join(__dirname, 'templates', 'brief-template.docx');
|
||||
fs.writeFileSync(templatePath, zip.toBuffer());
|
||||
|
||||
console.log('✅ Brief-Template erstellt:', templatePath);
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ Fehler beim Erstellen des Brief-Templates:', error);
|
||||
}
|
||||
}
|
||||
|
||||
createLetterTemplate();
|
||||
55
create-docxtemplater-template.js
Normal file
55
create-docxtemplater-template.js
Normal file
@ -0,0 +1,55 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const { Document, Packer, Paragraph, TextRun, Table, TableRow, TableCell } = require('docx');
|
||||
|
||||
async function createDocxtemplaterTemplate() {
|
||||
const doc = new Document({
|
||||
sections: [{
|
||||
properties: {},
|
||||
children: [
|
||||
new Paragraph({
|
||||
children: [new TextRun({ text: "ECHTE DYNAMISCHE TABELLEN", bold: true, size: 32 })],
|
||||
}),
|
||||
new Paragraph({ children: [new TextRun({ text: "" })] }),
|
||||
new Paragraph({ children: [new TextRun({ text: "Projekt: {projekt}" })] }),
|
||||
new Paragraph({ children: [new TextRun({ text: "Datum: {datum}" })] }),
|
||||
new Paragraph({ children: [new TextRun({ text: "Ersteller: {ersteller}" })] }),
|
||||
new Paragraph({ children: [new TextRun({ text: "" })] }),
|
||||
new Paragraph({ children: [new TextRun({ text: "MITARBEITER:", bold: true, size: 24 })] }),
|
||||
new Table({
|
||||
rows: [
|
||||
// Header Row
|
||||
new TableRow({
|
||||
children: [
|
||||
new TableCell({ children: [new Paragraph({ children: [new TextRun({ text: "Nr.", bold: true })] })] }),
|
||||
new TableCell({ children: [new Paragraph({ children: [new TextRun({ text: "Name", bold: true })] })] }),
|
||||
new TableCell({ children: [new Paragraph({ children: [new TextRun({ text: "Position", bold: true })] })] }),
|
||||
new TableCell({ children: [new Paragraph({ children: [new TextRun({ text: "E-Mail", bold: true })] })] }),
|
||||
],
|
||||
}),
|
||||
// ECHTE DYNAMISCHE Zeile mit docxtemplater Loop-Syntax
|
||||
new TableRow({
|
||||
children: [
|
||||
new TableCell({ children: [new Paragraph("{#mitarbeiter}{nr}")] }),
|
||||
new TableCell({ children: [new Paragraph("{name}")] }),
|
||||
new TableCell({ children: [new Paragraph("{position}")] }),
|
||||
new TableCell({ children: [new Paragraph("{email}{/mitarbeiter}")] }),
|
||||
],
|
||||
}),
|
||||
],
|
||||
}),
|
||||
new Paragraph({ children: [new TextRun({ text: "" })] }),
|
||||
new Paragraph({ children: [new TextRun({ text: "Status: {status}" })] }),
|
||||
],
|
||||
}],
|
||||
});
|
||||
|
||||
const buffer = await Packer.toBuffer(doc);
|
||||
const templatePath = path.join(__dirname, 'templates', 'dynamic-template.docx');
|
||||
fs.writeFileSync(templatePath, buffer);
|
||||
|
||||
console.log('✅ Docxtemplater-Template erstellt: dynamic-template.docx');
|
||||
console.log('📋 Loop-Syntax: {#mitarbeiter}{feldname}{/mitarbeiter}');
|
||||
}
|
||||
|
||||
createDocxtemplaterTemplate().catch(console.error);
|
||||
56
create-hybrid-dynamic-template.js
Normal file
56
create-hybrid-dynamic-template.js
Normal file
@ -0,0 +1,56 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const { Document, Packer, Paragraph, TextRun, Table, TableRow, TableCell } = require('docx');
|
||||
|
||||
async function createHybridDynamicTemplate() {
|
||||
const doc = new Document({
|
||||
sections: [{
|
||||
properties: {},
|
||||
children: [
|
||||
new Paragraph({
|
||||
children: [new TextRun({ text: "HYBRID DYNAMISCHE TABELLEN", bold: true, size: 32 })],
|
||||
}),
|
||||
new Paragraph({ children: [new TextRun({ text: "" })] }),
|
||||
new Paragraph({ children: [new TextRun({ text: "Projekt: ++projekt++" })] }),
|
||||
new Paragraph({ children: [new TextRun({ text: "Datum: ++datum++" })] }),
|
||||
new Paragraph({ children: [new TextRun({ text: "" })] }),
|
||||
new Paragraph({ children: [new TextRun({ text: "MITARBEITER:", bold: true, size: 24 })] }),
|
||||
new Table({
|
||||
rows: [
|
||||
// Header Row
|
||||
new TableRow({
|
||||
children: [
|
||||
new TableCell({ children: [new Paragraph({ children: [new TextRun({ text: "Nr.", bold: true })] })] }),
|
||||
new TableCell({ children: [new Paragraph({ children: [new TextRun({ text: "Name", bold: true })] })] }),
|
||||
new TableCell({ children: [new Paragraph({ children: [new TextRun({ text: "Position", bold: true })] })] }),
|
||||
new TableCell({ children: [new Paragraph({ children: [new TextRun({ text: "E-Mail", bold: true })] })] }),
|
||||
],
|
||||
}),
|
||||
// Bis zu 10 dynamische Zeilen (werden server-seitig gefüllt/leer gelassen)
|
||||
...Array.from({length: 10}, (_, i) =>
|
||||
new TableRow({
|
||||
children: [
|
||||
new TableCell({ children: [new Paragraph(`++mitarbeiter[${i}].nr++`)] }),
|
||||
new TableCell({ children: [new Paragraph(`++mitarbeiter[${i}].name++`)] }),
|
||||
new TableCell({ children: [new Paragraph(`++mitarbeiter[${i}].position++`)] }),
|
||||
new TableCell({ children: [new Paragraph(`++mitarbeiter[${i}].email++`)] }),
|
||||
],
|
||||
})
|
||||
)
|
||||
],
|
||||
}),
|
||||
new Paragraph({ children: [new TextRun({ text: "" })] }),
|
||||
new Paragraph({ children: [new TextRun({ text: "Status: ++status++" })] }),
|
||||
],
|
||||
}],
|
||||
});
|
||||
|
||||
const buffer = await Packer.toBuffer(doc);
|
||||
const templatePath = path.join(__dirname, 'templates', 'tabellen-template.docx');
|
||||
fs.writeFileSync(templatePath, buffer);
|
||||
|
||||
console.log('✅ Hybrid-dynamisches Template erstellt (bis zu 10 Zeilen)');
|
||||
console.log('📋 Server füllt nur gewünschte Anzahl, Rest bleibt leer');
|
||||
}
|
||||
|
||||
createHybridDynamicTemplate().catch(console.error);
|
||||
270
create-invoice-template.js
Normal file
270
create-invoice-template.js
Normal file
@ -0,0 +1,270 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const { createReport } = require('docx-templates');
|
||||
|
||||
// Rechnungsvorlage erstellen
|
||||
const invoiceTemplate = `
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
|
||||
<w:body>
|
||||
<w:p>
|
||||
<w:pPr><w:jc w:val="center"/></w:pPr>
|
||||
<w:r><w:rPr><w:b/><w:sz w:val="32"/></w:rPr><w:t>RECHNUNG</w:t></w:r>
|
||||
</w:p>
|
||||
|
||||
<w:p><w:r><w:t></w:t></w:r></w:p>
|
||||
|
||||
<w:tbl>
|
||||
<w:tr>
|
||||
<w:tc><w:p><w:r><w:rPr><w:b/></w:rPr><w:t>Rechnungssteller:</w:t></w:r></w:p></w:tc>
|
||||
<w:tc><w:p><w:r><w:rPr><w:b/></w:rPr><w:t>Kunde:</w:t></w:r></w:p></w:tc>
|
||||
</w:tr>
|
||||
<w:tr>
|
||||
<w:tc>
|
||||
<w:p><w:r><w:t>++firma++</w:t></w:r></w:p>
|
||||
<w:p><w:r><w:t>++straße++</w:t></w:r></w:p>
|
||||
<w:p><w:r><w:t>++plz++ ++stadt++</w:t></w:r></w:p>
|
||||
<w:p><w:r><w:t>Tel: ++telefon++</w:t></w:r></w:p>
|
||||
<w:p><w:r><w:t>Email: ++email++</w:t></w:r></w:p>
|
||||
</w:tc>
|
||||
<w:tc>
|
||||
<w:p><w:r><w:t>++kunde_name++</w:t></w:r></w:p>
|
||||
<w:p><w:r><w:t>++kunde_straße++</w:t></w:r></w:p>
|
||||
<w:p><w:r><w:t>++kunde_plz++ ++kunde_stadt++</w:t></w:r></w:p>
|
||||
</w:tc>
|
||||
</w:tr>
|
||||
</w:tbl>
|
||||
|
||||
<w:p><w:r><w:t></w:t></w:r></w:p>
|
||||
|
||||
<w:tbl>
|
||||
<w:tr>
|
||||
<w:tc><w:p><w:r><w:rPr><w:b/></w:rPr><w:t>Rechnungsnummer:</w:t></w:r></w:p></w:tc>
|
||||
<w:tc><w:p><w:r><w:t>++rechnungsnummer++</w:t></w:r></w:p></w:tc>
|
||||
</w:tr>
|
||||
<w:tr>
|
||||
<w:tc><w:p><w:r><w:rPr><w:b/></w:rPr><w:t>Rechnungsdatum:</w:t></w:r></w:p></w:tc>
|
||||
<w:tc><w:p><w:r><w:t>++datum++</w:t></w:r></w:p></w:tc>
|
||||
</w:tr>
|
||||
<w:tr>
|
||||
<w:tc><w:p><w:r><w:rPr><w:b/></w:rPr><w:t>Fälligkeitsdatum:</w:t></w:r></w:p></w:tc>
|
||||
<w:tc><w:p><w:r><w:t>++fälligkeitsdatum++</w:t></w:r></w:p></w:tc>
|
||||
</w:tr>
|
||||
</w:tbl>
|
||||
|
||||
<w:p><w:r><w:t></w:t></w:r></w:p>
|
||||
<w:p><w:r><w:rPr><w:b/></w:rPr><w:t>Rechnungsposten:</w:t></w:r></w:p>
|
||||
|
||||
<w:tbl>
|
||||
<w:tr>
|
||||
<w:tc><w:p><w:r><w:rPr><w:b/></w:rPr><w:t>Pos.</w:t></w:r></w:p></w:tc>
|
||||
<w:tc><w:p><w:r><w:rPr><w:b/></w:rPr><w:t>Artikel/Leistung</w:t></w:r></w:p></w:tc>
|
||||
<w:tc><w:p><w:r><w:rPr><w:b/></w:rPr><w:t>Menge</w:t></w:r></w:p></w:tc>
|
||||
<w:tc><w:p><w:r><w:rPr><w:b/></w:rPr><w:t>Einzelpreis</w:t></w:r></w:p></w:tc>
|
||||
<w:tc><w:p><w:r><w:rPr><w:b/></w:rPr><w:t>Gesamtpreis</w:t></w:r></w:p></w:tc>
|
||||
</w:tr>
|
||||
<w:tr>
|
||||
<w:tc><w:p><w:r><w:t>++positionen[0].nr++</w:t></w:r></w:p></w:tc>
|
||||
<w:tc><w:p><w:r><w:t>++positionen[0].artikel++</w:t></w:r></w:p></w:tc>
|
||||
<w:tc><w:p><w:r><w:t>++positionen[0].menge++</w:t></w:r></w:p></w:tc>
|
||||
<w:tc><w:p><w:r><w:t>++positionen[0].einzelpreis++</w:t></w:r></w:p></w:tc>
|
||||
<w:tc><w:p><w:r><w:t>++positionen[0].gesamtpreis++</w:t></w:r></w:p></w:tc>
|
||||
</w:tr>
|
||||
</w:tbl>
|
||||
|
||||
<w:p><w:r><w:t></w:t></w:r></w:p>
|
||||
|
||||
<w:tbl>
|
||||
<w:tr>
|
||||
<w:tc><w:p><w:r><w:rPr><w:b/></w:rPr><w:t>Nettobetrag:</w:t></w:r></w:p></w:tc>
|
||||
<w:tc><w:p><w:r><w:t>++nettobetrag++</w:t></w:r></w:p></w:tc>
|
||||
</w:tr>
|
||||
<w:tr>
|
||||
<w:tc><w:p><w:r><w:rPr><w:b/></w:rPr><w:t>MwSt. (19%):</w:t></w:r></w:p></w:tc>
|
||||
<w:tc><w:p><w:r><w:t>++mwst++</w:t></w:r></w:p></w:tc>
|
||||
</w:tr>
|
||||
<w:tr>
|
||||
<w:tc><w:p><w:r><w:rPr><w:b/></w:rPr><w:t>Gesamtbetrag:</w:t></w:r></w:p></w:tc>
|
||||
<w:tc><w:p><w:r><w:t>++gesamtbetrag++</w:t></w:r></w:p></w:tc>
|
||||
</w:tr>
|
||||
</w:tbl>
|
||||
|
||||
<w:p><w:r><w:t></w:t></w:r></w:p>
|
||||
<w:p><w:r><w:t>Vielen Dank für Ihr Vertrauen!</w:t></w:r></w:p>
|
||||
<w:p><w:r><w:t>Bei Fragen erreichen Sie uns unter: ++email++</w:t></w:r></w:p>
|
||||
|
||||
</w:body>
|
||||
</w:document>`;
|
||||
|
||||
// Minimales DOCX erstellen
|
||||
const minimalDocx = Buffer.from([
|
||||
'UEsDBAoAAAAAAHJZMlUAAAAAAAAAAAAAAQAAAFsQ=',
|
||||
'b250ZW50X1R5cGVzXS54bWyLycgsyk1VKMsvyk1VKE5OzStJTVEozk8p0S8pzUlNTi0qSsxLTi2y0lEDAEVKB',
|
||||
'A9QSwECCgAAAAAAclkyVQAAAAAAAAAAAAABAAoAABgAAAAAAAAAAAA==',
|
||||
'[Content_Types].xml',
|
||||
'UEsFBgAAAAEAAQAwAAAAOgAAAAA='
|
||||
].join(''), 'base64');
|
||||
|
||||
// Einfaches Template erstellen mit createReport
|
||||
async function createInvoiceTemplate() {
|
||||
try {
|
||||
const templatePath = path.join(__dirname, 'templates', 'rechnung-template.docx');
|
||||
|
||||
// Einfaches Template als Basis verwenden und dann überschreiben
|
||||
const baseTemplate = fs.readFileSync(path.join(__dirname, 'templates', 'simple-template.docx'));
|
||||
|
||||
// Rechnung-Template mit erweiterten Tags erstellen
|
||||
const invoiceContent = await createReport({
|
||||
template: baseTemplate,
|
||||
data: {
|
||||
// Dummy-Daten um Template-Struktur zu erstellen
|
||||
firma: '++firma++',
|
||||
straße: '++straße++',
|
||||
plz: '++plz++',
|
||||
stadt: '++stadt++',
|
||||
telefon: '++telefon++',
|
||||
email: '++email++',
|
||||
kunde_name: '++kunde_name++',
|
||||
kunde_straße: '++kunde_straße++',
|
||||
kunde_plz: '++kunde_plz++',
|
||||
kunde_stadt: '++kunde_stadt++',
|
||||
rechnungsnummer: '++rechnungsnummer++',
|
||||
datum: '++datum++',
|
||||
fälligkeitsdatum: '++fälligkeitsdatum++',
|
||||
positionen: [
|
||||
{
|
||||
nr: '++positionen[0].nr++',
|
||||
artikel: '++positionen[0].artikel++',
|
||||
menge: '++positionen[0].menge++',
|
||||
einzelpreis: '++positionen[0].einzelpreis++',
|
||||
gesamtpreis: '++positionen[0].gesamtpreis++'
|
||||
}
|
||||
],
|
||||
nettobetrag: '++nettobetrag++',
|
||||
mwst: '++mwst++',
|
||||
gesamtbetrag: '++gesamtbetrag++'
|
||||
}
|
||||
});
|
||||
|
||||
fs.writeFileSync(templatePath, invoiceContent);
|
||||
console.log('✅ Rechnungs-Template erstellt:', templatePath);
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ Fehler beim Erstellen des Rechnungs-Templates:', error);
|
||||
}
|
||||
}
|
||||
|
||||
// Da wir das base template brauchen, erstellen wir das Template manuell
|
||||
const fs2 = require('fs');
|
||||
const AdmZip = require('adm-zip');
|
||||
|
||||
function createInvoiceTemplateManual() {
|
||||
try {
|
||||
// Neues ZIP für DOCX erstellen
|
||||
const zip = new AdmZip();
|
||||
|
||||
// [Content_Types].xml
|
||||
const contentTypes = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types">
|
||||
<Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/>
|
||||
<Default Extension="xml" ContentType="application/xml"/>
|
||||
<Override PartName="/word/document.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml"/>
|
||||
</Types>`;
|
||||
|
||||
// _rels/.rels
|
||||
const rels = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
|
||||
<Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Target="word/document.xml"/>
|
||||
</Relationships>`;
|
||||
|
||||
// word/document.xml - Rechnung Template
|
||||
const document = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
|
||||
<w:body>
|
||||
<w:p>
|
||||
<w:pPr><w:jc w:val="center"/></w:pPr>
|
||||
<w:r><w:rPr><w:b/><w:sz w:val="32"/></w:rPr><w:t>RECHNUNG</w:t></w:r>
|
||||
</w:p>
|
||||
|
||||
<w:p><w:r><w:t></w:t></w:r></w:p>
|
||||
|
||||
<w:tbl>
|
||||
<w:tblPr><w:tblW w:w="0" w:type="auto"/></w:tblPr>
|
||||
<w:tr>
|
||||
<w:tc><w:p><w:r><w:rPr><w:b/></w:rPr><w:t>Firma: ++firma++</w:t></w:r></w:p></w:tc>
|
||||
<w:tc><w:p><w:r><w:rPr><w:b/></w:rPr><w:t>Kunde: ++kunde_name++</w:t></w:r></w:p></w:tc>
|
||||
</w:tr>
|
||||
<w:tr>
|
||||
<w:tc><w:p><w:r><w:t>++straße++</w:t></w:r></w:p></w:tc>
|
||||
<w:tc><w:p><w:r><w:t>++kunde_straße++</w:t></w:r></w:p></w:tc>
|
||||
</w:tr>
|
||||
<w:tr>
|
||||
<w:tc><w:p><w:r><w:t>++plz++ ++stadt++</w:t></w:r></w:p></w:tc>
|
||||
<w:tc><w:p><w:r><w:t>++kunde_plz++ ++kunde_stadt++</w:t></w:r></w:p></w:tc>
|
||||
</w:tr>
|
||||
<w:tr>
|
||||
<w:tc><w:p><w:r><w:t>Tel: ++telefon++</w:t></w:r></w:p></w:tc>
|
||||
<w:tc><w:p><w:r><w:t></w:t></w:r></w:p></w:tc>
|
||||
</w:tr>
|
||||
<w:tr>
|
||||
<w:tc><w:p><w:r><w:t>Email: ++email++</w:t></w:r></w:p></w:tc>
|
||||
<w:tc><w:p><w:r><w:t></w:t></w:r></w:p></w:tc>
|
||||
</w:tr>
|
||||
</w:tbl>
|
||||
|
||||
<w:p><w:r><w:t></w:t></w:r></w:p>
|
||||
|
||||
<w:p><w:r><w:rPr><w:b/></w:rPr><w:t>Rechnungsnummer: ++rechnungsnummer++</w:t></w:r></w:p>
|
||||
<w:p><w:r><w:rPr><w:b/></w:rPr><w:t>Datum: ++datum++</w:t></w:r></w:p>
|
||||
<w:p><w:r><w:rPr><w:b/></w:rPr><w:t>Fällig: ++fälligkeitsdatum++</w:t></w:r></w:p>
|
||||
|
||||
<w:p><w:r><w:t></w:t></w:r></w:p>
|
||||
<w:p><w:r><w:rPr><w:b/></w:rPr><w:t>Rechnungsposten:</w:t></w:r></w:p>
|
||||
|
||||
<w:tbl>
|
||||
<w:tblPr><w:tblW w:w="0" w:type="auto"/></w:tblPr>
|
||||
<w:tr>
|
||||
<w:tc><w:p><w:r><w:rPr><w:b/></w:rPr><w:t>Pos.</w:t></w:r></w:p></w:tc>
|
||||
<w:tc><w:p><w:r><w:rPr><w:b/></w:rPr><w:t>Artikel</w:t></w:r></w:p></w:tc>
|
||||
<w:tc><w:p><w:r><w:rPr><w:b/></w:rPr><w:t>Menge</w:t></w:r></w:p></w:tc>
|
||||
<w:tc><w:p><w:r><w:rPr><w:b/></w:rPr><w:t>Preis</w:t></w:r></w:p></w:tc>
|
||||
<w:tc><w:p><w:r><w:rPr><w:b/></w:rPr><w:t>Gesamt</w:t></w:r></w:p></w:tc>
|
||||
</w:tr>
|
||||
<w:tr>
|
||||
<w:tc><w:p><w:r><w:t>++positionen[0].nr++</w:t></w:r></w:p></w:tc>
|
||||
<w:tc><w:p><w:r><w:t>++positionen[0].artikel++</w:t></w:r></w:p></w:tc>
|
||||
<w:tc><w:p><w:r><w:t>++positionen[0].menge++</w:t></w:r></w:p></w:tc>
|
||||
<w:tc><w:p><w:r><w:t>++positionen[0].einzelpreis++</w:t></w:r></w:p></w:tc>
|
||||
<w:tc><w:p><w:r><w:t>++positionen[0].gesamtpreis++</w:t></w:r></w:p></w:tc>
|
||||
</w:tr>
|
||||
</w:tbl>
|
||||
|
||||
<w:p><w:r><w:t></w:t></w:r></w:p>
|
||||
|
||||
<w:p><w:r><w:rPr><w:b/></w:rPr><w:t>Nettobetrag: ++nettobetrag++</w:t></w:r></w:p>
|
||||
<w:p><w:r><w:rPr><w:b/></w:rPr><w:t>MwSt. (19%): ++mwst++</w:t></w:r></w:p>
|
||||
<w:p><w:r><w:rPr><w:b/></w:rPr><w:t>Gesamtbetrag: ++gesamtbetrag++</w:t></w:r></w:p>
|
||||
|
||||
<w:p><w:r><w:t></w:t></w:r></w:p>
|
||||
<w:p><w:r><w:t>Vielen Dank für Ihr Vertrauen!</w:t></w:r></w:p>
|
||||
|
||||
</w:body>
|
||||
</w:document>`;
|
||||
|
||||
// Dateien zum ZIP hinzufügen
|
||||
zip.addFile('[Content_Types].xml', Buffer.from(contentTypes, 'utf8'));
|
||||
zip.addFile('_rels/.rels', Buffer.from(rels, 'utf8'));
|
||||
zip.addFile('word/document.xml', Buffer.from(document, 'utf8'));
|
||||
|
||||
// DOCX speichern
|
||||
const templatePath = path.join(__dirname, 'templates', 'rechnung-template.docx');
|
||||
fs2.writeFileSync(templatePath, zip.toBuffer());
|
||||
|
||||
console.log('✅ Rechnungs-Template erstellt:', templatePath);
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ Fehler beim Erstellen des Rechnungs-Templates:', error);
|
||||
}
|
||||
}
|
||||
|
||||
createInvoiceTemplateManual();
|
||||
62
create-real-dynamic-template.js
Normal file
62
create-real-dynamic-template.js
Normal file
@ -0,0 +1,62 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const { Document, Packer, Paragraph, TextRun, Table, TableRow, TableCell } = require('docx');
|
||||
|
||||
async function createRealDynamicTemplate() {
|
||||
const doc = new Document({
|
||||
sections: [{
|
||||
properties: {},
|
||||
children: [
|
||||
new Paragraph({
|
||||
children: [new TextRun({ text: "ECHTE DYNAMISCHE TABELLEN", bold: true, size: 32 })],
|
||||
}),
|
||||
new Paragraph({ children: [new TextRun({ text: "" })] }),
|
||||
new Paragraph({ children: [new TextRun({ text: "Projekt: ++projekt++" })] }),
|
||||
new Paragraph({ children: [new TextRun({ text: "Datum: ++datum++" })] }),
|
||||
new Paragraph({ children: [new TextRun({ text: "" })] }),
|
||||
new Paragraph({ children: [new TextRun({ text: "MITARBEITER:", bold: true, size: 24 })] }),
|
||||
new Table({
|
||||
rows: [
|
||||
// Header Row
|
||||
new TableRow({
|
||||
children: [
|
||||
new TableCell({ children: [new Paragraph({ children: [new TextRun({ text: "Nr.", bold: true })] })] }),
|
||||
new TableCell({ children: [new Paragraph({ children: [new TextRun({ text: "Name", bold: true })] })] }),
|
||||
new TableCell({ children: [new Paragraph({ children: [new TextRun({ text: "Position", bold: true })] })] }),
|
||||
new TableCell({ children: [new Paragraph({ children: [new TextRun({ text: "E-Mail", bold: true })] })] }),
|
||||
],
|
||||
}),
|
||||
// Template Row - mit w:tr repeat
|
||||
new TableRow({
|
||||
children: [
|
||||
new TableCell({
|
||||
children: [new Paragraph("++FOR mitarbeiter++Nr: ++nr++")]
|
||||
}),
|
||||
new TableCell({
|
||||
children: [new Paragraph("++name++")]
|
||||
}),
|
||||
new TableCell({
|
||||
children: [new Paragraph("++position++")]
|
||||
}),
|
||||
new TableCell({
|
||||
children: [new Paragraph("++email+++/FOR++")]
|
||||
}),
|
||||
],
|
||||
}),
|
||||
],
|
||||
}),
|
||||
new Paragraph({ children: [new TextRun({ text: "" })] }),
|
||||
new Paragraph({ children: [new TextRun({ text: "Status: ++status++" })] }),
|
||||
],
|
||||
}],
|
||||
});
|
||||
|
||||
const buffer = await Packer.toBuffer(doc);
|
||||
const templatePath = path.join(__dirname, 'templates', 'tabellen-template.docx');
|
||||
fs.writeFileSync(templatePath, buffer);
|
||||
|
||||
console.log('✅ Template mit FOR-Loop Syntax erstellt');
|
||||
console.log('📋 Syntax: ++FOR mitarbeiter++...++/FOR++');
|
||||
}
|
||||
|
||||
createRealDynamicTemplate().catch(console.error);
|
||||
72
create-simple-table-template.js
Normal file
72
create-simple-table-template.js
Normal file
@ -0,0 +1,72 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const { Document, Packer, Paragraph, TextRun, Table, TableRow, TableCell } = require('docx');
|
||||
|
||||
async function createWorkingTableTemplate() {
|
||||
const doc = new Document({
|
||||
sections: [{
|
||||
properties: {},
|
||||
children: [
|
||||
new Paragraph({
|
||||
children: [new TextRun({ text: "DYNAMISCHE TABELLEN DEMO", bold: true, size: 32 })],
|
||||
}),
|
||||
new Paragraph({ children: [new TextRun({ text: "" })] }),
|
||||
new Paragraph({ children: [new TextRun({ text: "Projekt: ++projekt++" })] }),
|
||||
new Paragraph({ children: [new TextRun({ text: "Datum: ++datum++" })] }),
|
||||
new Paragraph({ children: [new TextRun({ text: "" })] }),
|
||||
new Paragraph({ children: [new TextRun({ text: "MITARBEITER:", bold: true, size: 24 })] }),
|
||||
new Table({
|
||||
rows: [
|
||||
// Header
|
||||
new TableRow({
|
||||
children: [
|
||||
new TableCell({ children: [new Paragraph({ children: [new TextRun({ text: "Nr.", bold: true })] })] }),
|
||||
new TableCell({ children: [new Paragraph({ children: [new TextRun({ text: "Name", bold: true })] })] }),
|
||||
new TableCell({ children: [new Paragraph({ children: [new TextRun({ text: "Position", bold: true })] })] }),
|
||||
new TableCell({ children: [new Paragraph({ children: [new TextRun({ text: "E-Mail", bold: true })] })] }),
|
||||
],
|
||||
}),
|
||||
// Dynamische Zeilen - Row 0
|
||||
new TableRow({
|
||||
children: [
|
||||
new TableCell({ children: [new Paragraph("++mitarbeiter[0].nr++")] }),
|
||||
new TableCell({ children: [new Paragraph("++mitarbeiter[0].name++")] }),
|
||||
new TableCell({ children: [new Paragraph("++mitarbeiter[0].position++")] }),
|
||||
new TableCell({ children: [new Paragraph("++mitarbeiter[0].email++")] }),
|
||||
],
|
||||
}),
|
||||
// Dynamische Zeilen - Row 1
|
||||
new TableRow({
|
||||
children: [
|
||||
new TableCell({ children: [new Paragraph("++mitarbeiter[1].nr++")] }),
|
||||
new TableCell({ children: [new Paragraph("++mitarbeiter[1].name++")] }),
|
||||
new TableCell({ children: [new Paragraph("++mitarbeiter[1].position++")] }),
|
||||
new TableCell({ children: [new Paragraph("++mitarbeiter[1].email++")] }),
|
||||
],
|
||||
}),
|
||||
// Dynamische Zeilen - Row 2
|
||||
new TableRow({
|
||||
children: [
|
||||
new TableCell({ children: [new Paragraph("++mitarbeiter[2].nr++")] }),
|
||||
new TableCell({ children: [new Paragraph("++mitarbeiter[2].name++")] }),
|
||||
new TableCell({ children: [new Paragraph("++mitarbeiter[2].position++")] }),
|
||||
new TableCell({ children: [new Paragraph("++mitarbeiter[2].email++")] }),
|
||||
],
|
||||
}),
|
||||
],
|
||||
}),
|
||||
new Paragraph({ children: [new TextRun({ text: "" })] }),
|
||||
new Paragraph({ children: [new TextRun({ text: "Status: ++status++" })] }),
|
||||
],
|
||||
}],
|
||||
});
|
||||
|
||||
const buffer = await Packer.toBuffer(doc);
|
||||
const templatePath = path.join(__dirname, 'templates', 'tabellen-template.docx');
|
||||
fs.writeFileSync(templatePath, buffer);
|
||||
|
||||
console.log('✅ Funktionierendes Tabellen-Template mit Array-Indizes erstellt');
|
||||
console.log('📋 Syntax: ++mitarbeiter[0].feldname++, ++mitarbeiter[1].feldname++, etc.');
|
||||
}
|
||||
|
||||
createWorkingTableTemplate().catch(console.error);
|
||||
@ -2,7 +2,6 @@ const fs = require('fs');
|
||||
const path = require('path');
|
||||
const { Document, Packer, Paragraph, TextRun, Table, TableRow, TableCell } = require('docx');
|
||||
|
||||
// Erstelle ein Template mit Tabelle für Listen
|
||||
async function createTableTemplate() {
|
||||
const doc = new Document({
|
||||
sections: [{
|
||||
@ -11,123 +10,76 @@ async function createTableTemplate() {
|
||||
new Paragraph({
|
||||
children: [
|
||||
new TextRun({
|
||||
text: "RECHNUNG",
|
||||
text: "TABELLEN DEMO DOKUMENT",
|
||||
bold: true,
|
||||
size: 32,
|
||||
}),
|
||||
],
|
||||
}),
|
||||
new Paragraph({ children: [new TextRun({ text: "" })] }),
|
||||
new Paragraph({ children: [new TextRun({ text: "Projekt: ++projekt++", bold: true })] }),
|
||||
new Paragraph({ children: [new TextRun({ text: "Datum: ++datum++" })] }),
|
||||
new Paragraph({ children: [new TextRun({ text: "Ersteller: ++ersteller++" })] }),
|
||||
new Paragraph({ children: [new TextRun({ text: "" })] }),
|
||||
new Paragraph({
|
||||
children: [
|
||||
new TextRun({
|
||||
text: "",
|
||||
}),
|
||||
],
|
||||
children: [new TextRun({ text: "MITARBEITERLISTE:", bold: true, size: 24 })],
|
||||
}),
|
||||
new Paragraph({
|
||||
children: [
|
||||
new TextRun({
|
||||
text: "Kunde: ++name++",
|
||||
}),
|
||||
],
|
||||
}),
|
||||
new Paragraph({
|
||||
children: [
|
||||
new TextRun({
|
||||
text: "E-Mail: ++email++",
|
||||
}),
|
||||
],
|
||||
}),
|
||||
new Paragraph({
|
||||
children: [
|
||||
new TextRun({
|
||||
text: "Datum: ++date++",
|
||||
}),
|
||||
],
|
||||
}),
|
||||
new Paragraph({
|
||||
children: [
|
||||
new TextRun({
|
||||
text: "",
|
||||
}),
|
||||
],
|
||||
}),
|
||||
new Paragraph({
|
||||
children: [
|
||||
new TextRun({
|
||||
text: "ARTIKEL",
|
||||
bold: true,
|
||||
}),
|
||||
],
|
||||
}),
|
||||
// Einfache Tabelle für Artikel
|
||||
new Table({
|
||||
rows: [
|
||||
new TableRow({
|
||||
children: [
|
||||
new TableCell({
|
||||
children: [new Paragraph("Produkt")],
|
||||
}),
|
||||
new TableCell({
|
||||
children: [new Paragraph("Menge")],
|
||||
}),
|
||||
new TableCell({
|
||||
children: [new Paragraph("Preis")],
|
||||
}),
|
||||
new TableCell({ children: [new Paragraph({ children: [new TextRun({ text: "Nr.", bold: true })] })] }),
|
||||
new TableCell({ children: [new Paragraph({ children: [new TextRun({ text: "Name", bold: true })] })] }),
|
||||
new TableCell({ children: [new Paragraph({ children: [new TextRun({ text: "Position", bold: true })] })] }),
|
||||
new TableCell({ children: [new Paragraph({ children: [new TextRun({ text: "Abteilung", bold: true })] })] }),
|
||||
new TableCell({ children: [new Paragraph({ children: [new TextRun({ text: "E-Mail", bold: true })] })] }),
|
||||
],
|
||||
}),
|
||||
new TableRow({
|
||||
children: [
|
||||
new TableCell({
|
||||
children: [new Paragraph("++items[0].product++")],
|
||||
}),
|
||||
new TableCell({
|
||||
children: [new Paragraph("++items[0].quantity++")],
|
||||
}),
|
||||
new TableCell({
|
||||
children: [new Paragraph("++items[0].price++€")],
|
||||
}),
|
||||
new TableCell({ children: [new Paragraph("++INS mitarbeiterRows++Nr: ++nr++")] }),
|
||||
new TableCell({ children: [new Paragraph("++name++")] }),
|
||||
new TableCell({ children: [new Paragraph("++position++")] }),
|
||||
new TableCell({ children: [new Paragraph("++abteilung++")] }),
|
||||
new TableCell({ children: [new Paragraph("++email++++/INS++")] }),
|
||||
],
|
||||
}),
|
||||
],
|
||||
}),
|
||||
new Paragraph({ children: [new TextRun({ text: "" })] }),
|
||||
new Paragraph({ children: [new TextRun({ text: "PROJEKTAUFGABEN:", bold: true, size: 24 })] }),
|
||||
new Table({
|
||||
rows: [
|
||||
new TableRow({
|
||||
children: [
|
||||
new TableCell({ children: [new Paragraph({ children: [new TextRun({ text: "Nr.", bold: true })] })] }),
|
||||
new TableCell({ children: [new Paragraph({ children: [new TextRun({ text: "Aufgabe", bold: true })] })] }),
|
||||
new TableCell({ children: [new Paragraph({ children: [new TextRun({ text: "Status", bold: true })] })] }),
|
||||
new TableCell({ children: [new Paragraph({ children: [new TextRun({ text: "Deadline", bold: true })] })] }),
|
||||
],
|
||||
}),
|
||||
new TableRow({
|
||||
children: [
|
||||
new TableCell({
|
||||
children: [new Paragraph("++items[1].product++")],
|
||||
}),
|
||||
new TableCell({
|
||||
children: [new Paragraph("++items[1].quantity++")],
|
||||
}),
|
||||
new TableCell({
|
||||
children: [new Paragraph("++items[1].price++€")],
|
||||
}),
|
||||
new TableCell({ children: [new Paragraph("++INS aufgabenRows++Nr: ++nr++")] }),
|
||||
new TableCell({ children: [new Paragraph("++titel++")] }),
|
||||
new TableCell({ children: [new Paragraph("++status++")] }),
|
||||
new TableCell({ children: [new Paragraph("++deadline++++/INS++")] }),
|
||||
],
|
||||
}),
|
||||
],
|
||||
}),
|
||||
new Paragraph({
|
||||
children: [
|
||||
new TextRun({
|
||||
text: "",
|
||||
}),
|
||||
],
|
||||
}),
|
||||
new Paragraph({
|
||||
children: [
|
||||
new TextRun({
|
||||
text: "Gesamtsumme: ++total++€",
|
||||
bold: true,
|
||||
}),
|
||||
],
|
||||
}),
|
||||
new Paragraph({ children: [new TextRun({ text: "" })] }),
|
||||
new Paragraph({ children: [new TextRun({ text: "Zusammenfassung: ++zusammenfassung++" })] }),
|
||||
new Paragraph({ children: [new TextRun({ text: "Status: ++status++" })] }),
|
||||
],
|
||||
}],
|
||||
});
|
||||
|
||||
const buffer = await Packer.toBuffer(doc);
|
||||
const outputPath = path.join(__dirname, 'templates', 'tabellen-template.docx');
|
||||
fs.writeFileSync(outputPath, buffer);
|
||||
const templatePath = path.join(__dirname, 'templates', 'tabellen-template.docx');
|
||||
fs.writeFileSync(templatePath, buffer);
|
||||
|
||||
console.log('✅ Tabellen-Template erstellt:', outputPath);
|
||||
console.log('✅ Tabellen-Template mit LOOP-Syntax erstellt');
|
||||
}
|
||||
|
||||
createTableTemplate().catch(console.error);
|
||||
createTableTemplate().catch(console.error);
|
||||
|
||||
62
create-truly-dynamic-template.js
Normal file
62
create-truly-dynamic-template.js
Normal file
@ -0,0 +1,62 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const { Document, Packer, Paragraph, TextRun, Table, TableRow, TableCell } = require('docx');
|
||||
|
||||
async function createTrulyDynamicTemplate() {
|
||||
const doc = new Document({
|
||||
sections: [{
|
||||
properties: {},
|
||||
children: [
|
||||
new Paragraph({
|
||||
children: [new TextRun({ text: "ECHTE DYNAMISCHE TABELLEN", bold: true, size: 32 })],
|
||||
}),
|
||||
new Paragraph({ children: [new TextRun({ text: "" })] }),
|
||||
new Paragraph({ children: [new TextRun({ text: "Projekt: ++projekt++" })] }),
|
||||
new Paragraph({ children: [new TextRun({ text: "Datum: ++datum++" })] }),
|
||||
new Paragraph({ children: [new TextRun({ text: "" })] }),
|
||||
new Paragraph({ children: [new TextRun({ text: "MITARBEITER:", bold: true, size: 24 })] }),
|
||||
new Table({
|
||||
rows: [
|
||||
// Header Row (statisch)
|
||||
new TableRow({
|
||||
children: [
|
||||
new TableCell({ children: [new Paragraph({ children: [new TextRun({ text: "Nr.", bold: true })] })] }),
|
||||
new TableCell({ children: [new Paragraph({ children: [new TextRun({ text: "Name", bold: true })] })] }),
|
||||
new TableCell({ children: [new Paragraph({ children: [new TextRun({ text: "Position", bold: true })] })] }),
|
||||
new TableCell({ children: [new Paragraph({ children: [new TextRun({ text: "E-Mail", bold: true })] })] }),
|
||||
],
|
||||
}),
|
||||
// DYNAMISCHE Zeile mit w:tr Loop-Tag
|
||||
new TableRow({
|
||||
children: [
|
||||
new TableCell({
|
||||
children: [new Paragraph("++#mitarbeiter ++nr++")]
|
||||
}),
|
||||
new TableCell({
|
||||
children: [new Paragraph("++name++")]
|
||||
}),
|
||||
new TableCell({
|
||||
children: [new Paragraph("++position++")]
|
||||
}),
|
||||
new TableCell({
|
||||
children: [new Paragraph("++email++ ++/mitarbeiter++")]
|
||||
}),
|
||||
],
|
||||
}),
|
||||
],
|
||||
}),
|
||||
new Paragraph({ children: [new TextRun({ text: "" })] }),
|
||||
new Paragraph({ children: [new TextRun({ text: "Status: ++status++" })] }),
|
||||
],
|
||||
}],
|
||||
});
|
||||
|
||||
const buffer = await Packer.toBuffer(doc);
|
||||
const templatePath = path.join(__dirname, 'templates', 'tabellen-template.docx');
|
||||
fs.writeFileSync(templatePath, buffer);
|
||||
|
||||
console.log('✅ Echte dynamische Tabelle mit Loop-Syntax erstellt');
|
||||
console.log('📋 Syntax: ++#mitarbeiter ++feldname++ ++/mitarbeiter++');
|
||||
}
|
||||
|
||||
createTrulyDynamicTemplate().catch(console.error);
|
||||
72
create-working-table-template.js
Normal file
72
create-working-table-template.js
Normal file
@ -0,0 +1,72 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const { Document, Packer, Paragraph, TextRun, Table, TableRow, TableCell } = require('docx');
|
||||
|
||||
async function createWorkingTableTemplate() {
|
||||
const doc = new Document({
|
||||
sections: [{
|
||||
properties: {},
|
||||
children: [
|
||||
new Paragraph({
|
||||
children: [new TextRun({ text: "DYNAMISCHE TABELLEN DEMO", bold: true, size: 32 })],
|
||||
}),
|
||||
new Paragraph({ children: [new TextRun({ text: "" })] }),
|
||||
new Paragraph({ children: [new TextRun({ text: "Projekt: ++projekt++" })] }),
|
||||
new Paragraph({ children: [new TextRun({ text: "Datum: ++datum++" })] }),
|
||||
new Paragraph({ children: [new TextRun({ text: "" })] }),
|
||||
new Paragraph({ children: [new TextRun({ text: "MITARBEITER:", bold: true, size: 24 })] }),
|
||||
new Table({
|
||||
rows: [
|
||||
// Header
|
||||
new TableRow({
|
||||
children: [
|
||||
new TableCell({ children: [new Paragraph({ children: [new TextRun({ text: "Nr.", bold: true })] })] }),
|
||||
new TableCell({ children: [new Paragraph({ children: [new TextRun({ text: "Name", bold: true })] })] }),
|
||||
new TableCell({ children: [new Paragraph({ children: [new TextRun({ text: "Position", bold: true })] })] }),
|
||||
new TableCell({ children: [new Paragraph({ children: [new TextRun({ text: "E-Mail", bold: true })] })] }),
|
||||
],
|
||||
}),
|
||||
// Dynamische Zeilen - Row 0
|
||||
new TableRow({
|
||||
children: [
|
||||
new TableCell({ children: [new Paragraph("++mitarbeiter[0].nr++")] }),
|
||||
new TableCell({ children: [new Paragraph("++mitarbeiter[0].name++")] }),
|
||||
new TableCell({ children: [new Paragraph("++mitarbeiter[0].position++")] }),
|
||||
new TableCell({ children: [new Paragraph("++mitarbeiter[0].email++")] }),
|
||||
],
|
||||
}),
|
||||
// Dynamische Zeilen - Row 1
|
||||
new TableRow({
|
||||
children: [
|
||||
new TableCell({ children: [new Paragraph("++mitarbeiter[1].nr++")] }),
|
||||
new TableCell({ children: [new Paragraph("++mitarbeiter[1].name++")] }),
|
||||
new TableCell({ children: [new Paragraph("++mitarbeiter[1].position++")] }),
|
||||
new TableCell({ children: [new Paragraph("++mitarbeiter[1].email++")] }),
|
||||
],
|
||||
}),
|
||||
// Dynamische Zeilen - Row 2
|
||||
new TableRow({
|
||||
children: [
|
||||
new TableCell({ children: [new Paragraph("++mitarbeiter[2].nr++")] }),
|
||||
new TableCell({ children: [new Paragraph("++mitarbeiter[2].name++")] }),
|
||||
new TableCell({ children: [new Paragraph("++mitarbeiter[2].position++")] }),
|
||||
new TableCell({ children: [new Paragraph("++mitarbeiter[2].email++")] }),
|
||||
],
|
||||
}),
|
||||
],
|
||||
}),
|
||||
new Paragraph({ children: [new TextRun({ text: "" })] }),
|
||||
new Paragraph({ children: [new TextRun({ text: "Status: ++status++" })] }),
|
||||
],
|
||||
}],
|
||||
});
|
||||
|
||||
const buffer = await Packer.toBuffer(doc);
|
||||
const templatePath = path.join(__dirname, 'templates', 'tabellen-template.docx');
|
||||
fs.writeFileSync(templatePath, buffer);
|
||||
|
||||
console.log('✅ Funktionierendes Tabellen-Template mit Array-Indizes erstellt');
|
||||
console.log('📋 Syntax: ++mitarbeiter[0].feldname++, ++mitarbeiter[1].feldname++, etc.');
|
||||
}
|
||||
|
||||
createWorkingTableTemplate().catch(console.error);
|
||||
40
package-lock.json
generated
40
package-lock.json
generated
@ -13,8 +13,11 @@
|
||||
"cors": "^2.8.5",
|
||||
"docx": "^9.5.1",
|
||||
"docx-templates": "^4.10.2",
|
||||
"docxtemplater": "^3.66.4",
|
||||
"express": "^4.18.2",
|
||||
"jszip-utils": "^0.1.0",
|
||||
"multer": "^1.4.5-lts.1",
|
||||
"pizzip": "^3.2.0",
|
||||
"webdav-server": "^2.6.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
@ -29,6 +32,14 @@
|
||||
"undici-types": "~7.13.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@xmldom/xmldom": {
|
||||
"version": "0.9.8",
|
||||
"resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.9.8.tgz",
|
||||
"integrity": "sha512-p96FSY54r+WJ50FIOsCOjyj/wavs8921hG5+kVMmZgKcvIKxMXHTrjNJvRgWa/zuX3B6t2lijLNFaOyuxUH+2A==",
|
||||
"engines": {
|
||||
"node": ">=14.6"
|
||||
}
|
||||
},
|
||||
"node_modules/accepts": {
|
||||
"version": "1.3.8",
|
||||
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
|
||||
@ -367,6 +378,17 @@
|
||||
"resolved": "https://registry.npmjs.org/sax/-/sax-1.3.0.tgz",
|
||||
"integrity": "sha512-0s+oAmw9zLl1V1cS9BtZN7JAd0cW5e0QH4W3LWEK6a4LaLEA2OTpGYWDY+6XasBLtz6wkm3u1xRw95mRuJ59WA=="
|
||||
},
|
||||
"node_modules/docxtemplater": {
|
||||
"version": "3.66.4",
|
||||
"resolved": "https://registry.npmjs.org/docxtemplater/-/docxtemplater-3.66.4.tgz",
|
||||
"integrity": "sha512-TzkSgWiZpisMvMyfT1wGDLVR4YsMxqg7jxdfKo7Cs76+XfwcyOgFKz7HOO0NyYVVZG2MOoTvhr6o7u6YnpPn1w==",
|
||||
"dependencies": {
|
||||
"@xmldom/xmldom": "^0.9.8"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/dunder-proto": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
|
||||
@ -770,6 +792,11 @@
|
||||
"setimmediate": "^1.0.5"
|
||||
}
|
||||
},
|
||||
"node_modules/jszip-utils": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/jszip-utils/-/jszip-utils-0.1.0.tgz",
|
||||
"integrity": "sha512-tBNe0o3HAf8vo0BrOYnLPnXNo5A3KsRMnkBFYjh20Y3GPYGfgyoclEMgvVchx0nnL+mherPi74yLPIusHUQpZg=="
|
||||
},
|
||||
"node_modules/lie": {
|
||||
"version": "3.3.0",
|
||||
"resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz",
|
||||
@ -1044,6 +1071,19 @@
|
||||
"url": "https://github.com/sponsors/jonschlinkert"
|
||||
}
|
||||
},
|
||||
"node_modules/pizzip": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/pizzip/-/pizzip-3.2.0.tgz",
|
||||
"integrity": "sha512-X4NPNICxCfIK8VYhF6wbksn81vTiziyLbvKuORVAmolvnUzl1A1xmz9DAWKxPRq9lZg84pJOOAMq3OE61bD8IQ==",
|
||||
"dependencies": {
|
||||
"pako": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/pizzip/node_modules/pako": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/pako/-/pako-2.1.0.tgz",
|
||||
"integrity": "sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug=="
|
||||
},
|
||||
"node_modules/process-nextick-args": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
|
||||
|
||||
@ -13,8 +13,11 @@
|
||||
"cors": "^2.8.5",
|
||||
"docx": "^9.5.1",
|
||||
"docx-templates": "^4.10.2",
|
||||
"docxtemplater": "^3.66.4",
|
||||
"express": "^4.18.2",
|
||||
"jszip-utils": "^0.1.0",
|
||||
"multer": "^1.4.5-lts.1",
|
||||
"pizzip": "^3.2.0",
|
||||
"webdav-server": "^2.6.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@ -92,6 +92,14 @@
|
||||
.btn-test:hover {
|
||||
background-color: #218838;
|
||||
}
|
||||
.btn-demo {
|
||||
background-color: #ff6b35;
|
||||
color: white;
|
||||
font-weight: bold;
|
||||
}
|
||||
.btn-demo:hover {
|
||||
background-color: #e55a2b;
|
||||
}
|
||||
.btn-word {
|
||||
background-color: #0066cc;
|
||||
color: white;
|
||||
@ -145,7 +153,8 @@
|
||||
<div class="info-section">
|
||||
<h3>🚀 Neue Features:</h3>
|
||||
<ul>
|
||||
<li><strong>📊 Analysieren:</strong> Alle Template-Tags automatisch erkennen</li>
|
||||
<li><strong><EFBFBD> One-Click Demo:</strong> Analyse + Demo-Dokument in einem Schritt</li>
|
||||
<li><strong><EFBFBD>📊 Analysieren:</strong> Alle Template-Tags automatisch erkennen</li>
|
||||
<li><strong>🎲 Testen:</strong> Test-Dokument mit Zufallsdaten erstellen</li>
|
||||
<li><strong>📝 MS Word:</strong> Direkt in Word öffnen und bearbeiten</li>
|
||||
<li><strong>🌐 WebDAV:</strong> Browser-basierte Dateiverwaltung</li>
|
||||
@ -205,6 +214,9 @@
|
||||
📅 Geändert: ${modifiedDate}
|
||||
</div>
|
||||
<div class="action-buttons">
|
||||
<button onclick="demoTemplate('${template.name}')" class="btn btn-demo">
|
||||
🚀 Demo
|
||||
</button>
|
||||
<a href="${template.analyzeUrl}" target="_blank" class="btn btn-analyze">
|
||||
📊 Analysieren
|
||||
</a>
|
||||
@ -223,6 +235,56 @@
|
||||
return card;
|
||||
}
|
||||
|
||||
async function demoTemplate(templateName) {
|
||||
const rowCount = prompt('Anzahl Tabellenzeilen für Demo:', '3');
|
||||
if (!rowCount) return;
|
||||
|
||||
try {
|
||||
const response = await fetch(`/demo-template/${templateName}`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({ rowCount: parseInt(rowCount) })
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (result.success) {
|
||||
const message = `🚀 One-Click Demo erfolgreich erstellt!
|
||||
|
||||
📄 Template: ${result.templateInfo.name}
|
||||
📊 Analyse-Ergebnis:
|
||||
• Tags gefunden: ${result.tagAnalysis.totalTags}
|
||||
• Einfache Tags: ${result.tagAnalysis.tagBreakdown.simple}
|
||||
• Tabellen: ${result.tagAnalysis.tagBreakdown.tables}
|
||||
|
||||
📝 Demo-Dokument erstellt:
|
||||
• Datei: ${result.demoDocument.filename}
|
||||
• Tabellenzeilen: ${rowCount} pro Tabelle
|
||||
|
||||
🔗 Aktionen:
|
||||
• Herunterladen: ${window.location.origin}${result.demoDocument.downloadUrl}
|
||||
• In Word öffnen: ${result.demoDocument.msWordUrl}
|
||||
• WebDAV: ${window.location.origin}${result.demoDocument.webdavUrl}
|
||||
|
||||
📋 Gefundene Tags: ${result.tagAnalysis.foundTags.join(', ')}`;
|
||||
|
||||
alert(message);
|
||||
|
||||
// Optional: Demo-Dokument direkt öffnen
|
||||
if (confirm('Demo-Dokument jetzt in Word öffnen?')) {
|
||||
window.location.href = result.demoDocument.msWordUrl;
|
||||
}
|
||||
} else {
|
||||
alert('❌ Fehler: ' + result.error);
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
alert('❌ Fehler beim Erstellen der Demo: ' + error.message);
|
||||
}
|
||||
}
|
||||
|
||||
async function testTemplate(templateName) {
|
||||
const rowCount = prompt('Anzahl Tabellenzeilen für Test:', '3');
|
||||
if (!rowCount) return;
|
||||
|
||||
1144
server-old.js
1144
server-old.js
File diff suppressed because it is too large
Load Diff
@ -27,7 +27,52 @@ Gesamtsumme: {{total}}€
|
||||
4. Speichern Sie die Datei als "template-beispiel.docx" im templates/ Ordner
|
||||
5. Verwenden Sie diese Template-Namen in der Web-Oberfläche
|
||||
|
||||
WICHTIG:
|
||||
- Verwenden Sie {{}} für Platzhalter
|
||||
- Für Listen/Tabellen verwenden Sie {{#array}} ... {{/array}}
|
||||
- Innerhalb von Listen können Sie auf Eigenschaften zugreifen: {{property}}
|
||||
📄 DOCX TEMPLATE ANLEITUNG
|
||||
============================
|
||||
|
||||
🏷️ VERFÜGBARE TEMPLATES:
|
||||
|
||||
1. simple-template.docx
|
||||
- Einfaches Template mit Name, Email, Datum, Tabelle
|
||||
- Perfekt für erste Tests
|
||||
|
||||
2. tabellen-template.docx
|
||||
- Erweiterte Tabellen-Funktionalität
|
||||
- Mehrere Tabellenzeilen-Beispiele
|
||||
|
||||
3. test-template.docx
|
||||
- Umfassendes Test-Template
|
||||
- Verschiedene Tag-Typen zum Experimentieren
|
||||
|
||||
4. rechnung-template.docx ⭐ NEU
|
||||
- Professionelle Rechnungsvorlage
|
||||
- Firma, Kunde, Rechnungsposten, MwSt
|
||||
- Tags: ++firma++, ++kunde_name++, ++positionen[0].artikel++
|
||||
|
||||
5. angebot-template.docx ⭐ NEU
|
||||
- Angebots-/Kostenvoranschlag-Template
|
||||
- Projektinformationen, Leistungen, Preise
|
||||
- Tags: ++projekt_name++, ++leistungen[0].titel++
|
||||
|
||||
6. brief-template.docx ⭐ NEU
|
||||
- Geschäftsbrief-Template
|
||||
- Absender, Empfänger, Betreff, Brieftext
|
||||
- Tags: ++betreff++, ++anrede++, ++haupttext++
|
||||
|
||||
🎯 TEMPLATE-SYNTAX:
|
||||
Verwende ++tagname++ für Platzhalter
|
||||
Verwende ++tabelle[0].spalte++ für Tabellen
|
||||
|
||||
🚀 NEUE FUNKTIONEN:
|
||||
- 📊 Analysieren: /analyze-template/templatename.docx
|
||||
- 🎲 Testen: POST /test-template/templatename.docx
|
||||
- 🚀 Demo: POST /demo-template/templatename.docx (Analyse + Demo in einem!)
|
||||
|
||||
💡 BEISPIEL-NUTZUNG:
|
||||
curl -X POST -d '{"rowCount": 5}' \
|
||||
http://localhost:3000/demo-template/rechnung-template.docx
|
||||
|
||||
📱 WEB-INTERFACE:
|
||||
http://localhost:3000/templates.html
|
||||
|
||||
Das war's! Viel Spaß beim Template-Erstellen! 🎉
|
||||
BIN
templates/angebot-template.docx
Normal file
BIN
templates/angebot-template.docx
Normal file
Binary file not shown.
BIN
templates/brief-template.docx
Normal file
BIN
templates/brief-template.docx
Normal file
Binary file not shown.
BIN
templates/dynamic-template.docx
Normal file
BIN
templates/dynamic-template.docx
Normal file
Binary file not shown.
BIN
templates/rechnung-template.docx
Normal file
BIN
templates/rechnung-template.docx
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
48
test-docxtemplater.js
Normal file
48
test-docxtemplater.js
Normal file
@ -0,0 +1,48 @@
|
||||
const fs = require('fs');
|
||||
const Docxtemplater = require('docxtemplater');
|
||||
const PizZip = require('pizzip');
|
||||
|
||||
// Test mit docxtemplater
|
||||
function testDocxtemplater() {
|
||||
// Beispiel-Template-Inhalt (normalerweise aus .docx gelesen)
|
||||
const content = fs.readFileSync('./templates/simple-template.docx', 'binary');
|
||||
const zip = new PizZip(content);
|
||||
|
||||
const doc = new Docxtemplater(zip, {
|
||||
paragraphLoop: true,
|
||||
linebreaks: true,
|
||||
});
|
||||
|
||||
// Echte dynamische Daten
|
||||
const data = {
|
||||
projekt: "Dynamisches Projekt",
|
||||
datum: new Date().toLocaleDateString('de-DE'),
|
||||
mitarbeiter: [
|
||||
{ nr: 1, name: "Max Mustermann", position: "Developer", email: "max@example.com" },
|
||||
{ nr: 2, name: "Anna Schmidt", position: "Designer", email: "anna@example.com" },
|
||||
{ nr: 3, name: "Tom Weber", position: "Manager", email: "tom@example.com" },
|
||||
{ nr: 4, name: "Lisa König", position: "Analyst", email: "lisa@example.com" },
|
||||
{ nr: 5, name: "Jan Peters", position: "Tester", email: "jan@example.com" }
|
||||
],
|
||||
status: "Aktiv"
|
||||
};
|
||||
|
||||
console.log('📊 Teste mit docxtemplater und', data.mitarbeiter.length, 'Mitarbeitern');
|
||||
|
||||
try {
|
||||
doc.render(data);
|
||||
|
||||
const buf = doc.getZip().generate({
|
||||
type: 'nodebuffer',
|
||||
compression: 'DEFLATE',
|
||||
});
|
||||
|
||||
fs.writeFileSync('./output/docxtemplater_test.docx', buf);
|
||||
console.log('✅ docxtemplater Test erfolgreich!');
|
||||
|
||||
} catch (error) {
|
||||
console.log('❌ docxtemplater Fehler:', error.message);
|
||||
}
|
||||
}
|
||||
|
||||
testDocxtemplater();
|
||||
Loading…
x
Reference in New Issue
Block a user