Generieren von Dokumenten mit ONLYOFFICE DocumentBuilder


Hallo Habr.


Ich möchte ĂŒber ein Dienstprogramm namens DocumentBuilder sprechen, mit dem Sie Dokumente, Tabellen und PrĂ€sentationen erstellen und anhand des Beispiels zum Erstellen eines Lebenslaufs aus Vorlagen zeigen können, wie Sie damit Ihre Probleme lösen können.


Der Builder funktioniert wie folgt: Sie schreiben Code in js mit speziellen Methoden aus der Dokumentation, geben ihn an das Dienstprogramm weiter und sammeln das Dokument. Oder sammelt nicht, wenn es Fehler gibt.


Die Verwendung eines Builders ist ratsam, wenn Sie Aufgaben des folgenden Typs lösen möchten:


  • Sie mĂŒssen viele Dokumente mit kleinen Abweichungen oder Dokumente erstellen, die auf vielen Daten basieren.
  • Sie mĂŒssen die Generierung von Dokumenten in jeden Dienst integrieren.

Es gibt Dienste, mit denen Sie einen Lebenslauf erstellen können: Der Benutzer fĂŒllt die erforderlichen Felder aus, und das System generiert ein Dokument und gibt es dem Benutzer. Dies ist ein Beispiel fĂŒr die Verwendung des Builders.


Als Werkzeuge werde ich Node.js (Express) verwenden.


Plan:


  1. Der Benutzer gibt Daten in das Formular auf der Seite im Browser ein, das Formular wird an den Server gesendet.
  2. Auf dem Node.js-Server wird basierend auf Benutzerdaten ein Skript fĂŒr den Builder erstellt.
  3. Node.js gibt das Skript an den Builder weiter.
  4. Der Builder erstellt ein Dokument mithilfe eines Skripts.
  5. Node.js gibt den Link zum Dokument an den Benutzer zurĂŒck.

Formularerstellung


Erstellen Sie zunÀchst ein Formular, in das der Benutzer seine Daten eingibt. Das Formular enthÀlt 8 Felder: "VollstÀndiger Name", "Telefonnummer", "E-Mail", "Profil", "Abschluss", "UniversitÀt", "Ort", "Jahr", "FÀhigkeit". Das Fertigkeitsfeld kann geklont werden.


Erstellen Sie eine index.html-Datei und fĂŒgen Sie den Vorlagencode hinzu.


<div class="fill-name"> <input type="text" id="fill-name" placeholder="full name"> </div> <div class="phone-number"> <input type="number" id="phone-number" placeholder="phone number"> </div> <div class="email"> <input type="text" id="email" placeholder="email"> </div> <div class="profile"> <textarea id="profile" placeholder="Insert a brief description of yourself"></textarea> </div> <div class="education"> <input type="text" id="degree" placeholder="degree"> <input type="text" id="university" placeholder="university"> <input type="text" id="location" placeholder="location"> <input type="date" id="year" placeholder="year"> </div> <div class="skills"> <div class="skill"> <input type="text" id="new-skill" placeholder="skill" onkeyup="add_skill_by_enter(event)"> <button onclick="add_skill()">+</button> </div> </div> 

Hier benutze ich zwei Funktionen: add_skill_by_enter (event) und add_skill (). Sie werden benötigt, um mehrere Felder durch DrĂŒcken der Taste + oder Enter hinzuzufĂŒgen. Ich werde diese Funktionen etwas spĂ€ter beschreiben.


FĂŒgen Sie eine SchaltflĂ€che hinzu, um das Formular an den Server zu senden:


 <button onclick="sendForm()">Send</button> 

Jetzt werden wir Funktionen fĂŒr die Arbeit mit dem Formular schreiben.


Die erste Funktion ist add_skill ()


 add_skill = () => { const newSkill = document.getElementById("new-skill"); if (newSkill.value === '') {return; } //   ,       const div = document.createElement("div"); .// div const span = document.createElement("span"); //   const button = document.createElement("button"); //    span.innerText += newSkill.value; //   span   newSkill.value = ''; //      newSkill.focus(); //        button.innerText += "-"; button.onclick = () => { //      div.remove(); }; div.appendChild(span); //  span  div div.appendChild(button); //   document.getElementsByClassName('skills')[0].appendChild(div); //     }; add_skill_by_enter() add_skill_by_enter = (event) => { if (event.code === "Enter") { //  ,      enter add_skill(); } }; 

Wir fĂŒgen eine einfache Funktion hinzu, um Daten aus den Feldern zu sammeln und an den Server zu senden.


  get_skill_values = () => { const skills = []; if (document.getElementById('new-skill').value !== '') { skills.push(document.getElementById('new-skill').value); } Array.from(document.getElementsByClassName('skillfield')).forEach(current_element => { skills.push(current_element.innerHTML); }); return skills; }; sendForm() sendForm = () => { fetch('/', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ userData: { fillName: document.getElementById('fill-name').value, phoneNumber: document.getElementById('phone-number').value, email: document.getElementById('email').value, profile: document.getElementById('profile').value, education: { degree: document.getElementById('degree').value, university: document.getElementById('university').value, location: document.getElementById('location').value, year: document.getElementById('year').value, }, skills: get_skill_values() } }) }).then(res => res.json()) .then(response => { location.replace('/' + response.filename); //  ,       }) .catch(error => console.error('Error:', error)); }; 

Die Serverseite fĂŒr die Arbeit mit dem Formular


Ich schreibe den Serverteil auf Express. Die Verbindung aller Bibliotheken, die Serverkonfiguration und die Beschreibung der Get- und Post-Methoden sehen folgendermaßen aus:


 const path = require('path'); const express = require('express'); const bodyParser = require('body-parser'); const app = express(); app.use(bodyParser.json()); app.get('/', (req, res) => { res.sendFile(path.join(__dirname + '/index.html')); }); app.post('/', (req, res) => { //        }); app.listen(3000, () => console.log(`Example app listening on port ${3000}!`)); 

Express ausfĂŒhren:
node main.js


Öffnen Sie die Adresse im Browser:
http:localhost:3000


Wir sehen das erstellte Formular. Wir fĂŒllen es mit beliebigen Daten:


Wir bekommen folgendes json:


 {"userData":{"fillName":"Rotatyy Dmitryi","phoneNumber":"89879879898","email":"flamine@list.ru","profile":"Hi, my name is Joe\nAnd I work in a button factory\nI got a wife and two kids\nOne day, my boss says, “Joe, are you busy?”\nI said, “no”\n“Then push this button with your right hand”","country":"Russia","city":"Nizhniy Novgorod","education":{"degree":"Master of Pupets","university":"Nizhny novgorod state technical university","location":"Nizhniy Novgorod","year":"2015-05-02"},"skills":["apple.js","vintage.js","zerg.js","css","html","linux"]}}; 

Jetzt mĂŒssen Sie ein Skript fĂŒr den Builder schreiben. Ich habe die Vorlage verwendet, die Google Text & Tabellen anbietet (Lebenslaufvorlage).


Diese Vorlage sieht folgendermaßen aus:
Bild


Mit diesen Daten und der Vorlage mĂŒssen Sie ein Skript erstellen, mit dem der Builder das Dokument erstellt.


HierfĂŒr gibt es verschiedene Möglichkeiten. Am einfachsten ist es, die Desktop-Version der ONLYOFFICE-Editoren herunterzuladen und ein Makro zu schreiben, mit dem das Dokument anhand der Daten erstellt wird. FĂŒgen Sie dann dem Makro das Erstellen und Speichern der Datei hinzu - Sie erhalten ein Skript fĂŒr den Builder. Dies funktioniert, da Makros und der Builder dieselbe API verwenden.


Erstellen eines Skripts fĂŒr einen Builder


Wir beginnen mit der Initialisierung des Seitenobjekts und dem HinzufĂŒgen der vom Benutzer stammenden Daten:


 const Document = Api.GetDocument(); const data = {"userData":{"fillName":"Rotatyy Dmitryi","phoneNumber":"89879879898","email":"flamine@list.ru","profile":"Hi, my name is Joe\nAnd I work in a button factory\nI got a wife and two kids\nOne day, my boss says, “Joe, are you busy?”\nI said, “no”\n“Then push this button with your right hand”","country":"Russia","city":"Nizhniy Novgorod","education":{"degree":"Master of Pupets","university":"Nizhny novgorod state technical university","location":"Nizhniy Novgorod","year":"2015-05-02"},"skills":["apple.js","vintage.js","zerg.js","css","html","linux"]}}; 

Jetzt mĂŒssen Sie den Absatz mit dem vollstĂ€ndigen Benutzernamen hinzufĂŒgen. Es ist fett geschrieben und dieser Absatz hat einen Zeilenabstand von 1,15.


 let paragraph = document.GetElement(0); //       FullName_style = Document.CreateStyle("FullName"); //    FullName_style.GetTextPr().SetFontSize(28); //    FullName_style.GetTextPr().SetBold(true); //  bold paragraph.SetStyle(FullName_style); //      paragraph.SetSpacingLine(1.15 * 240, "auto"); //    paragraph.AddText(data.userData.fillName); //     

Wir fĂŒgen auch die restlichen AbsĂ€tze hinzu:
 // Country and city const CountryCity_style = Document.CreateStyle("CountryCity"); CountryCity_style.GetTextPr().SetFontSize(20); CountryCity_style.GetTextPr().SetCaps(true); CountryCity_style.GetTextPr().SetBold(true); paragraph = Api.CreateParagraph(); paragraph.AddText(data.userData.country + ', ' + data.userData.city); paragraph.SetStyle(CountryCity_style); paragraph.SetSpacingAfter(0); Document.Push(paragraph); // phone number const PhoneNumber_style = Document.CreateStyle("PhoneNumber"); PhoneNumber_style.GetTextPr().SetFontSize(20); PhoneNumber_style.GetParaPr().SetSpacingAfter(0); PhoneNumber_style.GetTextPr().SetBold(true); paragraph = Api.CreateParagraph(); paragraph.AddText(data.userData.phoneNumber); paragraph.SetStyle(PhoneNumber_style); Document.Push(paragraph); // email const Email_style = Document.CreateStyle("Email"); Email_style.GetTextPr().SetFontSize(18); Email_style.GetParaPr().SetSpacingAfter(0); Email_style.GetTextPr().SetBold(true); paragraph = Api.CreateParagraph(); paragraph.AddText(data.userData.email); paragraph.SetStyle(Email_style); Document.Push(paragraph); // SectionHeader style const SectionHeader = Document.CreateStyle("SectionHeader"); SectionHeader.GetTextPr().SetBold(true); SectionHeader.GetTextPr().SetColor(247, 93, 93, false); SectionHeader.GetTextPr().SetFontSize(28); SectionHeader.GetParaPr().SetSpacingBefore(1.33 * 240); SectionHeader.GetParaPr().SetSpacingLine(1 * 240, "auto"); // add header Profile: paragraph = Api.CreateParagraph(); paragraph.AddText("Profile:") paragraph.SetStyle(SectionHeader); Document.Push(paragraph); // add profile text: paragraph = Api.CreateParagraph(); paragraph.AddText(data.userData.profile) Document.Push(paragraph); // add header Education: paragraph = Api.CreateParagraph(); paragraph.AddText("Education:") paragraph.SetStyle(SectionHeader); Document.Push(paragraph); // add education year: const EducationYear_style = Document.CreateStyle("EducationYear"); EducationYear_style.GetTextPr().SetColor(102, 102, 102); EducationYear_style.GetTextPr().SetFontSize(18); EducationYear_style.GetParaPr().SetSpacingAfter(0); paragraph = Api.CreateParagraph(); paragraph.SetStyle(EducationYear_style); paragraph.AddText(data.userData.education.year) Document.Push(paragraph); // add education university: paragraph = Api.CreateParagraph(); run = Api.CreateRun(); run.AddText(data.userData.education.university) run.AddText(', ') run.AddText(data.userData.education.location) run.SetBold(true); paragraph.AddElement(run); run = Api.CreateRun(); run.AddText(' – ' + data.userData.education.degree) paragraph.AddElement(run); Document.Push(paragraph); // add header Skills: paragraph = Api.CreateParagraph(); paragraph.AddText("Skills:") paragraph.SetStyle(SectionHeader); Document.Push(paragraph); // add skills text: paragraph = Api.CreateParagraph(); const skills = data.userData.skills.map(x => ' ' + x).toString(); paragraph.AddText(skills) Document.Push(paragraph); 

Durch AusfĂŒhren dieses Skripts erhalten wir das folgende Dokument:


Jetzt ist es Zeit, Funktionen hinzuzufĂŒgen, um Skriptcode in eine Datei zu schreiben und ein Dokument zu generieren.


Wir generieren das Skript -> schreiben in die Datei -> geben die Datei an den Builder weiter -> geben den Link zur Datei an den Benutzer zurĂŒck.


Wir fĂŒgen eine Verbindung von Add-Ons hinzu, um mit Dateien zu arbeiten und Befehle mit Node.js auszufĂŒhren. Außerdem erstellen wir einen "öffentlichen" Ordner und machen ihn öffentlich:


 const {exec} = require('child_process'); const fs = require('fs'); app.use(express.static('public')); 

Die Funktion zum Generieren von Text mit einem Skript ist sehr einfach: Sie gibt einfach eine Zeichenfolge mit dem gesamten Code fĂŒr den Builder zurĂŒck, wĂ€hrend Benutzerdaten hinzugefĂŒgt werden. Es ist wichtig, am Ende jeder Zeile ein Zeilenumbruchzeichen einzufĂŒgen, da sonst nichts funktioniert.


 generate_script = (data) => { let first_template = 'builder.CreateFile("docx");\n' + 'const Document = Api.GetDocument();\n'; first_template += 'const data = ' + JSON.stringify(data) + ';\n'; first_template += 'let paragraph = Document.GetElement(0);\n' + 'FullName_style = Document.CreateStyle("FullName");\n' + ....   ~~~~~~~~~~~ return first_template; }; 

Jetzt mĂŒssen Sie das Skript in eine Datei schreiben und dem Builder ĂŒbergeben. TatsĂ€chlich wird die gesamte Arbeit mit dem Builder auf die Tatsache reduziert, dass der Befehl documentbuilder path/script.js Node.js


Wir schreiben eine Build-Funktion, die dies erledigt:


 build = (data, res) => { const filename = Math.random().toString(36).substring(7) + '.docx'; //    let script = generate_script(data); script += 'builder.SaveFile("docx", "' + __dirname + '/public/' + filename + '");\n' + 'builder.CloseFile();'; fs.writeFile('public/' + filename + 'js', script, () => { exec('documentbuilder ' + 'public/' + filename + 'js', () => { res.send({'filename': filename }); }); }); }; 

FĂŒgen Sie der Erstellungsmethode einen Aufruf hinzu (req.body, res); bei post Anfrage


 app.post('/', (req, res) => { build(req.body, res); }); 

Und du bist fertig. FĂŒr alle FĂ€lle habe ich hier den vollstĂ€ndigen Beispielcode gepostet.


So können Sie ONLYOFFICE DocumentBuilder in eine Webanwendung einbetten.


Ich hoffe, dass trotz zahlreicher Vereinfachungen alles klar ist. Ich habe nur den erforderlichen Mindestcode verwendet, um zu zeigen, wie alles funktioniert.


Im Moment gibt es Gedanken, das Dienstprogramm zu beenden und das Spektrum der zu lösenden Probleme zu erweitern. Ich wĂ€re Ihnen dankbar, wenn Sie die tatsĂ€chlichen FĂ€lle der Erstellung von Dokumenten (natĂŒrlich auch von Tabellen mit PrĂ€sentationen) in den Kommentaren oder in PM teilen wĂŒrden.

Source: https://habr.com/ru/post/de466217/


All Articles