Add WebDAV integration and template improvements
✅ Frontend-Verbesserungen: - WebDAV-Integration für direktes Template-Bearbeiten - 'In Word öffnen' Button für ms-word: URLs - Verbesserte Template-Karten mit Tag-Informationen - WebDAV-Info-Sektion mit Anleitungen - Korrigierte API-Endpunkte für docxtemplater 🔧 Template-Updates: - Alle Templates auf docxtemplater-Syntax aktualisiert - create-*-fixed.js Scripts für korrekte {tag} Syntax - Entfernt alte ++tag++ und ++INS++ Syntax - Neue create-new-table-template.js für echte Loops 🌐 WebDAV-Features: - Direkter Template-Download über /webdav/templates/ - Template-Bearbeitung in Word möglich - Automatische Speicherung über WebDAV - Fallback auf Download bei Word-Problemen 📊 Template-Syntax-Migration: - {variable} statt ++variable++ - {#array}{field}{/array} statt ++INS array++ - Echte dynamische Tabellen ohne fixe Indizes - Verbesserte Tag-Erkennung und Analyse
This commit is contained in:
parent
a01423321b
commit
5371d5e479
107
create-angebot-fixed.js
Normal file
107
create-angebot-fixed.js
Normal file
@ -0,0 +1,107 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const AdmZip = require('adm-zip');
|
||||
|
||||
function createAngebotTemplate() {
|
||||
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 mit docxtemplater Syntax
|
||||
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>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: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>{strasse}</w:t></w:r></w:p></w:tc>
|
||||
<w:tc><w:p><w:r><w:t>{kunde_strasse}</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>E-Mail: {email}</w:t></w:r></w:p></w:tc>
|
||||
<w:tc><w:p><w:r><w:t>E-Mail: {kunde_email}</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>Projekt: {projekt}</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>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:tr>
|
||||
<w:tr>
|
||||
<w:tc><w:p><w:r><w:t>{#positionen}{nr}</w:t></w:r></w:p></w:tc>
|
||||
<w:tc><w:p><w:r><w:t>{leistung}</w:t></w:r></w:p></w:tc>
|
||||
<w:tc><w:p><w:r><w:t>{menge}</w:t></w:r></w:p></w:tc>
|
||||
<w:tc><w:p><w:r><w:t>{preis}{/positionen}</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>Gesamtsumme: {gesamtsumme}€</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>`;
|
||||
|
||||
// Füge Dateien zum ZIP hinzu
|
||||
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'));
|
||||
|
||||
// Speichere die Datei
|
||||
const outputPath = path.join(__dirname, 'templates', 'angebot-template.docx');
|
||||
zip.writeZip(outputPath);
|
||||
|
||||
console.log('✅ Angebot-Template mit docxtemplater-Syntax erstellt:', outputPath);
|
||||
}
|
||||
|
||||
createAngebotTemplate();
|
||||
91
create-brief-fixed.js
Normal file
91
create-brief-fixed.js
Normal file
@ -0,0 +1,91 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const AdmZip = require('adm-zip');
|
||||
|
||||
function createBriefTemplate() {
|
||||
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:t>{firma}</w:t></w:r>
|
||||
</w:p>
|
||||
<w:p>
|
||||
<w:pPr><w:jc w:val="right"/></w:pPr>
|
||||
<w:r><w:t>{strasse}</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: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>{empfaenger_name}</w:t></w:r></w:p>
|
||||
<w:p><w:r><w:t>{empfaenger_strasse}</w:t></w:r></w:p>
|
||||
<w:p><w:r><w:t>{empfaenger_plz} {empfaenger_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>{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: {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>{nachricht}</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></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:body>
|
||||
</w:document>`;
|
||||
|
||||
// Füge Dateien zum ZIP hinzu
|
||||
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'));
|
||||
|
||||
// Speichere die Datei
|
||||
const outputPath = path.join(__dirname, 'templates', 'brief-template.docx');
|
||||
zip.writeZip(outputPath);
|
||||
|
||||
console.log('✅ Brief-Template mit docxtemplater-Syntax erstellt:', outputPath);
|
||||
}
|
||||
|
||||
createBriefTemplate();
|
||||
67
create-new-table-template.js
Normal file
67
create-new-table-template.js
Normal file
@ -0,0 +1,67 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const { Document, Packer, Paragraph, TextRun, Table, TableRow, TableCell } = require('docx');
|
||||
|
||||
async function createTableTemplate() {
|
||||
const doc = new Document({
|
||||
sections: [{
|
||||
properties: {},
|
||||
children: [
|
||||
new Paragraph({
|
||||
children: [
|
||||
new TextRun({
|
||||
text: "DYNAMISCHES TABELLEN-TEMPLATE",
|
||||
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: "MITARBEITERLISTE:", 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: "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 })] })] }),
|
||||
],
|
||||
}),
|
||||
new TableRow({
|
||||
children: [
|
||||
new TableCell({ children: [new Paragraph({ children: [new TextRun({ text: "{#mitarbeiter}{nr}" })] })] }),
|
||||
new TableCell({ children: [new Paragraph({ children: [new TextRun({ text: "{name}" })] })] }),
|
||||
new TableCell({ children: [new Paragraph({ children: [new TextRun({ text: "{position}" })] })] }),
|
||||
new TableCell({ children: [new Paragraph({ children: [new TextRun({ text: "{email}{/mitarbeiter}" })] })] }),
|
||||
],
|
||||
}),
|
||||
],
|
||||
}),
|
||||
new Paragraph({ children: [new TextRun({ text: "" })] }),
|
||||
new Paragraph({
|
||||
children: [
|
||||
new TextRun({
|
||||
text: "Status: {status}",
|
||||
bold: true
|
||||
})
|
||||
]
|
||||
}),
|
||||
],
|
||||
}],
|
||||
});
|
||||
|
||||
const buffer = await Packer.toBuffer(doc);
|
||||
const outputPath = path.join(__dirname, 'templates', 'tabellen-template.docx');
|
||||
fs.writeFileSync(outputPath, buffer);
|
||||
|
||||
console.log('✅ Tabellen-Template mit docxtemplater Loop-Syntax erstellt');
|
||||
}
|
||||
|
||||
createTableTemplate().catch(console.error);
|
||||
104
create-rechnung-fixed.js
Normal file
104
create-rechnung-fixed.js
Normal file
@ -0,0 +1,104 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const AdmZip = require('adm-zip');
|
||||
|
||||
function createRechnungTemplate() {
|
||||
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 - Rechnungs 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="36"/></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>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: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>{strasse}</w:t></w:r></w:p></w:tc>
|
||||
<w:tc><w:p><w:r><w:t>{kunde_strasse}</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: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>Rechnungsdatum: {datum}</w:t></w:r></w:p>
|
||||
<w:p><w:r><w:rPr><w:b/></w:rPr><w:t>Leistungszeitraum: {leistungszeitraum}</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>Beschreibung</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}{nr}</w:t></w:r></w:p></w:tc>
|
||||
<w:tc><w:p><w:r><w:t>{beschreibung}</w:t></w:r></w:p></w:tc>
|
||||
<w:tc><w:p><w:r><w:t>{menge}</w:t></w:r></w:p></w:tc>
|
||||
<w:tc><w:p><w:r><w:t>{einzelpreis}</w:t></w:r></w:p></w:tc>
|
||||
<w:tc><w:p><w:r><w:t>{gesamtpreis}{/positionen}</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>Mehrwertsteuer (19%): {mwst}€</w:t></w:r></w:p>
|
||||
<w:p><w:r><w:rPr><w:b/><w:sz w:val="24"/></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>Zahlbar bis: {zahlbar_bis}</w:t></w:r></w:p>
|
||||
<w:p><w:r><w:t>Verwendungszweck: {rechnungsnummer}</w:t></w:r></w:p>
|
||||
|
||||
</w:body>
|
||||
</w:document>`;
|
||||
|
||||
// Füge Dateien zum ZIP hinzu
|
||||
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'));
|
||||
|
||||
// Speichere die Datei
|
||||
const outputPath = path.join(__dirname, 'templates', 'rechnung-template.docx');
|
||||
zip.writeZip(outputPath);
|
||||
|
||||
console.log('✅ Rechnungs-Template mit docxtemplater-Syntax erstellt:', outputPath);
|
||||
}
|
||||
|
||||
createRechnungTemplate();
|
||||
@ -20,21 +20,21 @@ async function createTestTemplate() {
|
||||
new Paragraph({
|
||||
children: [
|
||||
new TextRun({
|
||||
text: "Kunde: ++name++",
|
||||
text: "Kunde: {name}",
|
||||
}),
|
||||
],
|
||||
}),
|
||||
new Paragraph({
|
||||
children: [
|
||||
new TextRun({
|
||||
text: "E-Mail: ++email++",
|
||||
text: "E-Mail: {email}",
|
||||
}),
|
||||
],
|
||||
}),
|
||||
new Paragraph({
|
||||
children: [
|
||||
new TextRun({
|
||||
text: "Datum: ++date++",
|
||||
text: "Datum: {datum}",
|
||||
}),
|
||||
],
|
||||
}),
|
||||
@ -56,7 +56,14 @@ async function createTestTemplate() {
|
||||
new Paragraph({
|
||||
children: [
|
||||
new TextRun({
|
||||
text: "Artikel 1: ++items[0].product++ (++items[0].quantity++x) - ++items[0].price++€",
|
||||
text: "Projekt: {projekt}",
|
||||
}),
|
||||
],
|
||||
}),
|
||||
new Paragraph({
|
||||
children: [
|
||||
new TextRun({
|
||||
text: "Status: {status}",
|
||||
}),
|
||||
],
|
||||
}),
|
||||
@ -70,7 +77,7 @@ async function createTestTemplate() {
|
||||
new Paragraph({
|
||||
children: [
|
||||
new TextRun({
|
||||
text: "Gesamtsumme: ++total++€",
|
||||
text: "Gesamtsumme: {betrag}€",
|
||||
bold: true,
|
||||
}),
|
||||
],
|
||||
|
||||
@ -33,6 +33,23 @@
|
||||
margin: 10px 0 0 0;
|
||||
opacity: 0.9;
|
||||
}
|
||||
.webdav-info {
|
||||
background: #e3f2fd;
|
||||
border: 1px solid #1976d2;
|
||||
border-radius: 5px;
|
||||
padding: 15px;
|
||||
margin: 20px 0;
|
||||
}
|
||||
.webdav-info h3 {
|
||||
margin: 0 0 10px 0;
|
||||
color: #1976d2;
|
||||
}
|
||||
.webdav-info code {
|
||||
background: #fff;
|
||||
padding: 2px 5px;
|
||||
border-radius: 3px;
|
||||
font-family: monospace;
|
||||
}
|
||||
.content {
|
||||
padding: 30px;
|
||||
}
|
||||
@ -150,6 +167,22 @@
|
||||
<div class="content">
|
||||
<button class="refresh-btn" onclick="loadTemplates()">🔄 Templates neu laden</button>
|
||||
|
||||
<div class="webdav-info">
|
||||
<h3>🌐 WebDAV Template-Bearbeitung</h3>
|
||||
<p><strong>Template direkt in Word bearbeiten:</strong></p>
|
||||
<ul>
|
||||
<li>Klicken Sie auf <strong>"📝 In Word öffnen"</strong> bei einem Template</li>
|
||||
<li>Word öffnet das Template direkt vom Server</li>
|
||||
<li>Änderungen werden automatisch gespeichert</li>
|
||||
</ul>
|
||||
<p><strong>WebDAV-URLs:</strong></p>
|
||||
<ul>
|
||||
<li>Templates: <code>${window.location.origin}/webdav/templates/</code></li>
|
||||
<li>Generierte Dateien: <code>${window.location.origin}/webdav/output/</code></li>
|
||||
</ul>
|
||||
<p><em>💡 Tipp: Sie können diese URLs auch als Netzlaufwerk in Windows einbinden!</em></p>
|
||||
</div>
|
||||
|
||||
<div class="info-section">
|
||||
<h3>🚀 Neue Features:</h3>
|
||||
<ul>
|
||||
@ -211,7 +244,8 @@
|
||||
<div class="template-name">📄 ${template.name}</div>
|
||||
<div class="template-info">
|
||||
📊 Größe: ${sizeKB} KB<br>
|
||||
📅 Geändert: ${modifiedDate}
|
||||
📅 Geändert: ${modifiedDate}<br>
|
||||
🏷️ Tags: ${template.tags} (${template.simpleTags} einfach, ${template.tables} Tabellen)
|
||||
</div>
|
||||
<div class="action-buttons">
|
||||
<button onclick="demoTemplate('${template.name}')" class="btn btn-demo">
|
||||
@ -223,12 +257,12 @@
|
||||
<button onclick="testTemplate('${template.name}')" class="btn btn-test">
|
||||
🎲 Testen
|
||||
</button>
|
||||
<a href="${template.msWordUrl}" class="btn btn-word">
|
||||
<a href="/webdav/templates/${template.name}" class="btn btn-webdav">
|
||||
📁 Download
|
||||
</a>
|
||||
<button onclick="openInWord('${template.name}')" class="btn btn-word">
|
||||
📝 In Word öffnen
|
||||
</a>
|
||||
<a href="${template.webdavUrl}" target="_blank" class="btn btn-webdav">
|
||||
🌐 WebDAV
|
||||
</a>
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
|
||||
@ -240,41 +274,38 @@
|
||||
if (!rowCount) return;
|
||||
|
||||
try {
|
||||
const response = await fetch(`/demo-template/${templateName}`, {
|
||||
const response = await fetch(`/demo/${templateName}`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({ rowCount: parseInt(rowCount) })
|
||||
body: JSON.stringify({ tables: { mitarbeiter: parseInt(rowCount), positionen: parseInt(rowCount) } })
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (result.success) {
|
||||
const message = `🚀 One-Click Demo erfolgreich erstellt!
|
||||
const message = `🚀 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}
|
||||
📄 Template: ${templateName}
|
||||
<EFBFBD> Demo-Dokument erstellt: ${result.file}
|
||||
🎉 ${result.message}
|
||||
|
||||
📝 Demo-Dokument erstellt:
|
||||
• Datei: ${result.demoDocument.filename}
|
||||
• Tabellenzeilen: ${rowCount} pro Tabelle
|
||||
📊 Analyse:
|
||||
• Einfache Tags: ${result.analysis.simpleTags.length}
|
||||
• Tabellen: ${result.analysis.tables.length}
|
||||
|
||||
🔗 Aktionen:
|
||||
• Herunterladen: ${window.location.origin}${result.demoDocument.downloadUrl}
|
||||
• In Word öffnen: ${result.demoDocument.msWordUrl}
|
||||
• WebDAV: ${window.location.origin}${result.demoDocument.webdavUrl}
|
||||
• Herunterladen: ${window.location.origin}${result.download}
|
||||
|
||||
📋 Gefundene Tags: ${result.tagAnalysis.foundTags.join(', ')}`;
|
||||
📋 Gefundene Tags: ${result.analysis.simpleTags.join(', ')}
|
||||
<EFBFBD> Tabellen: ${result.analysis.tables.join(', ')}`;
|
||||
|
||||
alert(message);
|
||||
|
||||
// Optional: Demo-Dokument direkt öffnen
|
||||
if (confirm('Demo-Dokument jetzt in Word öffnen?')) {
|
||||
window.location.href = result.demoDocument.msWordUrl;
|
||||
// Optional: Demo-Dokument direkt herunterladen
|
||||
if (confirm('Demo-Dokument jetzt herunterladen?')) {
|
||||
window.location.href = result.download;
|
||||
}
|
||||
} else {
|
||||
alert('❌ Fehler: ' + result.error);
|
||||
@ -290,12 +321,12 @@
|
||||
if (!rowCount) return;
|
||||
|
||||
try {
|
||||
const response = await fetch(`/test-template/${templateName}`, {
|
||||
const response = await fetch(`/demo/${templateName}`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({ rowCount: parseInt(rowCount) })
|
||||
body: JSON.stringify({ tables: { mitarbeiter: parseInt(rowCount), positionen: parseInt(rowCount) } })
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
@ -303,20 +334,19 @@
|
||||
if (result.success) {
|
||||
const message = `✅ Test-Dokument erstellt!
|
||||
|
||||
📄 Datei: ${result.templateName}
|
||||
🏷️ Tags gefunden: ${result.foundTags.length}
|
||||
📊 Tabellen: ${result.tableNames.length}
|
||||
📄 Datei: ${result.file}
|
||||
<EFBFBD> ${result.message}
|
||||
|
||||
🔗 Aktionen:
|
||||
• Herunterladen: ${window.location.origin}${result.downloadUrl}
|
||||
• In Word öffnen: ${result.msWordUrl}
|
||||
• WebDAV: ${window.location.origin}${result.webdavUrl}`;
|
||||
• Herunterladen: ${window.location.origin}${result.download}
|
||||
|
||||
📊 Analyse: ${result.analysis.simpleTags.length} Tags, ${result.analysis.tables.length} Tabellen`;
|
||||
|
||||
alert(message);
|
||||
|
||||
// Optional: Test-Dokument direkt öffnen
|
||||
if (confirm('Test-Dokument jetzt in Word öffnen?')) {
|
||||
window.location.href = result.msWordUrl;
|
||||
// Optional: Test-Dokument direkt herunterladen
|
||||
if (confirm('Test-Dokument jetzt herunterladen?')) {
|
||||
window.location.href = result.download;
|
||||
}
|
||||
} else {
|
||||
alert('❌ Fehler: ' + result.error);
|
||||
@ -327,6 +357,28 @@
|
||||
}
|
||||
}
|
||||
|
||||
function openInWord(templateName) {
|
||||
// WebDAV-URL für direktes Öffnen in Word
|
||||
const webdavUrl = `${window.location.protocol}//${window.location.host}/webdav/templates/${templateName}`;
|
||||
const msWordUrl = `ms-word:ofe|u|${webdavUrl}`;
|
||||
|
||||
// Versuche Word zu öffnen
|
||||
try {
|
||||
window.location.href = msWordUrl;
|
||||
|
||||
// Fallback-Information für den Benutzer
|
||||
setTimeout(() => {
|
||||
if (confirm(`Word konnte nicht automatisch geöffnet werden.\n\nMöchten Sie die Datei stattdessen herunterladen?\n\nWebDAV-URL: ${webdavUrl}`)) {
|
||||
window.open(webdavUrl, '_blank');
|
||||
}
|
||||
}, 2000);
|
||||
|
||||
} catch (error) {
|
||||
// Fallback: Datei herunterladen
|
||||
window.open(webdavUrl, '_blank');
|
||||
}
|
||||
}
|
||||
|
||||
// Templates beim Laden der Seite laden
|
||||
document.addEventListener('DOMContentLoaded', loadTemplates);
|
||||
</script>
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user