Support TS, swagger,Template(xls,docx),PDF convert
This commit is contained in:
parent
b221deb1cf
commit
8d7654423a
84 changed files with 3604 additions and 1 deletions
94
libs/convert-libs.ts
Normal file
94
libs/convert-libs.ts
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
import express from 'express'
|
||||
export const convertTemplateRoute = express.Router();
|
||||
import {mimeToExtension} from './report-template'
|
||||
import { LibreOfficeFileConverter } from 'libreoffice-file-converter';
|
||||
|
||||
/** javascript-obfuscator:disable
|
||||
* @swagger
|
||||
* tags:
|
||||
* name: office-convert
|
||||
* description: ใช้แปลงไฟล์จากเอกสารที่ libreoffice แปลงได้ x
|
||||
*/
|
||||
|
||||
/** javascript-obfuscator:disable
|
||||
* @swagger
|
||||
* /api/v1/report-template/convert:
|
||||
* post:
|
||||
* summary: Create document from template
|
||||
* tags: [office-convert]
|
||||
* parameters:
|
||||
* - name: report_name
|
||||
* in: header
|
||||
* description: นามสกุลไฟล์ที่อัปโหลดเข้ามา(ตอนนี้ไม่จำเป็นต้องใช้เพราะ soffice ตรวจสอบเอง)
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* example: report
|
||||
* requestBody:
|
||||
* required: true
|
||||
* content:
|
||||
* application/octet-stream:
|
||||
* schema:
|
||||
* type: string
|
||||
* format: binary
|
||||
* responses:
|
||||
* 201:
|
||||
* description: file was converted.
|
||||
* content:
|
||||
* application/pdf:
|
||||
* schema:
|
||||
* type: string
|
||||
* format: binary
|
||||
* application/vnd.oasis.opendocument.text:
|
||||
* schema:
|
||||
* type: string
|
||||
* format: binary
|
||||
* application/vnd.openxmlformats-officedocument.wordprocessingml.document:
|
||||
* schema:
|
||||
* type: string
|
||||
* format: binary
|
||||
* application/msword:
|
||||
* schema:
|
||||
* type: string
|
||||
* format: binary
|
||||
* text/html:
|
||||
* schema:
|
||||
* type: string
|
||||
* 500:
|
||||
* description: Server error
|
||||
*
|
||||
*/
|
||||
convertTemplateRoute.post("/convert", async function (req, res) {
|
||||
try {
|
||||
if (!req.headers['content-type'] ||
|
||||
!req.headers['accept'] ||
|
||||
!req.headers['report_name'] ||
|
||||
req.headers['content-type'] !== "application/octet-stream") {
|
||||
res.statusCode = 400;
|
||||
res.statusMessage = 'Require header: content-type(application/octet-stream) accept, report_name';
|
||||
res.end(res.statusMessage);
|
||||
console.log(req.headers['content-type'],req.headers['accept'],req.headers['report_name'])
|
||||
return
|
||||
}
|
||||
let outputMediaType = mimeToExtension(req.headers['accept']);
|
||||
let reportName = req.headers['report_name']
|
||||
console.log('output: ' + outputMediaType);
|
||||
const libreOfficeFileConverter = new LibreOfficeFileConverter({
|
||||
childProcessOptions: {
|
||||
timeout: 60 * 1000,
|
||||
},
|
||||
});
|
||||
const buffer = await libreOfficeFileConverter.convertBuffer(req.body, outputMediaType);
|
||||
res.statusCode = 201;
|
||||
res.setHeader('Content-Type', req.headers['accept']);
|
||||
res.setHeader('Content-Disposition', `attachment;filename=${reportName}.${outputMediaType}`);
|
||||
res.setHeader('Content-Length', buffer.length);
|
||||
res.end(buffer);
|
||||
} catch (ex) {
|
||||
res.statusCode = 500;
|
||||
res.statusMessage = 'Internal Server Error';
|
||||
res.end(res.statusMessage);
|
||||
console.error(`Error during convert with soffice:`, ex);
|
||||
}
|
||||
})
|
||||
|
||||
36
libs/create-swagger-spec.ts
Normal file
36
libs/create-swagger-spec.ts
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
// https://swagger.io/docs/specification/about/
|
||||
import swaggerJsdoc from "swagger-jsdoc"
|
||||
import fs from 'fs'
|
||||
const swaggerOptions = {
|
||||
definition: {
|
||||
openapi: "3.1.0",
|
||||
info: {
|
||||
title: "Report Server",
|
||||
version: "0.1.0",
|
||||
description:
|
||||
"Advance Create and convert document API for microservice.",
|
||||
license: {
|
||||
name: "by Frappet",
|
||||
url: "https://frappet.com",
|
||||
},
|
||||
},
|
||||
servers: [
|
||||
{
|
||||
url: "https://report-server.frappet.synology.me",
|
||||
},
|
||||
{
|
||||
url: "http://localhost:3000",
|
||||
},
|
||||
{
|
||||
url: "http://192.168.2.100:3000",
|
||||
},
|
||||
],
|
||||
},
|
||||
apis: ["./libs/*.ts"],
|
||||
};
|
||||
export function createSpec(){
|
||||
const swaggerSpecs = swaggerJsdoc(swaggerOptions);
|
||||
fs.promises.writeFile("libs/swagger-specs.json",JSON.stringify(swaggerSpecs,null,2))
|
||||
}
|
||||
createSpec()
|
||||
|
||||
147
libs/docx-templates-lib.ts
Normal file
147
libs/docx-templates-lib.ts
Normal file
|
|
@ -0,0 +1,147 @@
|
|||
|
||||
import express from 'express'
|
||||
export const docxTemplateRoute = express.Router();
|
||||
|
||||
import {mimeToExtension,templateData} from './report-template'
|
||||
import fs from 'fs'
|
||||
import { createReport } from 'docx-templates';
|
||||
import qrcode from 'yaqrcode'
|
||||
// แก้ package.json ของ LibreOfficeFileConverter
|
||||
// https://github.com/microsoft/TypeScript/issues/52363#issuecomment-1659179354
|
||||
import { LibreOfficeFileConverter } from 'libreoffice-file-converter';
|
||||
const TEMPLATE_FOLDER_NAME = "templates/docx"
|
||||
|
||||
/**
|
||||
* docxTemplate Uses docx-template to convert input data and template to output buffer.
|
||||
* You have to handle exception throw by function
|
||||
* template keep in folder templates
|
||||
* @param {String} base base path of caller relate to template-docx foler (no trail slash)
|
||||
* @param {templateData} tdata Template Information in JSON format
|
||||
* @param {String} outputMediaType output extension
|
||||
* @return {Promise<Uint8Array>} output buffer after apply template.
|
||||
*/
|
||||
export async function docxTemplateX(base: string=".", tdata: templateData, outputMediaType: string="docx"): Promise<Uint8Array> {
|
||||
try {
|
||||
let template = await fs.promises.readFile(`${base}/${TEMPLATE_FOLDER_NAME}/${tdata.template}.docx`)
|
||||
const buffer = await createReport({
|
||||
template,
|
||||
data: tdata.data,
|
||||
additionalJsContext: {
|
||||
qrCode: (contents: string, caption: string, size: number, width: number, height: number) => {
|
||||
const dataUrl = qrcode(contents, { size: size });
|
||||
const data = dataUrl.slice('data:image/gif;base64,'.length);
|
||||
return { width, height, data, extension: '.gif', caption };
|
||||
},
|
||||
}
|
||||
});
|
||||
if (outputMediaType === "docx")
|
||||
return buffer
|
||||
const libreOfficeFileConverter = new LibreOfficeFileConverter({
|
||||
childProcessOptions: {
|
||||
timeout: 60 * 1000,
|
||||
},
|
||||
});
|
||||
const lbuffer = await libreOfficeFileConverter.convertBuffer(Buffer.from(buffer), outputMediaType);
|
||||
return lbuffer
|
||||
|
||||
} catch (e) {
|
||||
throw (e)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** javascript-obfuscator:disable
|
||||
* @swagger
|
||||
* /api/v1/report-template/docx:
|
||||
* get:
|
||||
* summary: list docx template
|
||||
* tags: [report-template]
|
||||
* responses:
|
||||
* 200:
|
||||
* description: array of template
|
||||
* content:
|
||||
* applicatin/json:
|
||||
* schema:
|
||||
* type: array
|
||||
* items:
|
||||
* type: string
|
||||
* example: ["hello"]
|
||||
* 500:
|
||||
* description: Server error
|
||||
*/
|
||||
docxTemplateRoute.get("/", async function (req, res) {
|
||||
try {
|
||||
const fileList = await fs.promises.readdir(`./${TEMPLATE_FOLDER_NAME}`)
|
||||
const templateList = fileList.map((f) => f.split('.docx')[0])
|
||||
res.send(templateList)
|
||||
} catch (ex) {
|
||||
res.statusCode = 500;
|
||||
res.statusMessage = 'Internal Server Error';
|
||||
res.end(res.statusMessage);
|
||||
console.error('Error during get template list: ', ex);
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
/** javascript-obfuscator:disable
|
||||
* @swagger
|
||||
* /api/v1/report-template/docx:
|
||||
* post:
|
||||
* summary: Create document from docx template output can be docx pdf odt
|
||||
* tags: [report-template]
|
||||
* requestBody:
|
||||
* required: true
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* $ref: '#/components/schemas/templateData'
|
||||
* example:
|
||||
* template: hello
|
||||
* reportName: docx-report
|
||||
* data: {"docNo":"๑๒๓๔๕","me": "กระผม","prefix": "นาย","name": "สรวิชญ์","surname": "พลสิทธิ์","position": "Chief Technology Officer","org": {"type": "บริษัท","name": "เฟรปเป้ที","url": "https://frappet.com"},"employees": [{"name": "ภาวิชญ์","surname": "พลสิทธิ์"},{"name": "วิชญาภา","surname": "พลสิทธิ์"}]}
|
||||
* responses:
|
||||
* 201:
|
||||
* description: เอกสารถูกสร้างขึ้น
|
||||
* content:
|
||||
* application/vnd.openxmlformats-officedocument.wordprocessingml.document:
|
||||
* schema:
|
||||
* type: string
|
||||
* format: binary
|
||||
* application/pdf:
|
||||
* schema:
|
||||
* type: string
|
||||
* format: binary
|
||||
* application/vnd.oasis.opendocument.text:
|
||||
* schema:
|
||||
* type: string
|
||||
* format: binary
|
||||
* 500:
|
||||
* description: Server error
|
||||
*
|
||||
*/
|
||||
docxTemplateRoute.post("/", async function (req, res) {
|
||||
try {
|
||||
if (!req.headers['content-type'] || !req.headers['accept'])
|
||||
throw new Error("Require header content-type, accept")
|
||||
let inputType = mimeToExtension(req.headers['content-type']);
|
||||
let outputMediaType = mimeToExtension(req.headers['accept']);
|
||||
console.log('content-type: ', inputType);
|
||||
console.log('accept: ', outputMediaType);
|
||||
let buffer = await docxTemplateX('.', req.body, outputMediaType)
|
||||
res.statusCode = 201;
|
||||
res.setHeader('Content-Type', req.headers['accept']);
|
||||
res.setHeader('Content-Disposition', `attachment;filename=${req.body.reportName}.${outputMediaType}`);
|
||||
res.setHeader('Content-Length', buffer.length);
|
||||
res.end(buffer);
|
||||
} catch (ex) {
|
||||
res.statusCode = 500;
|
||||
res.statusMessage = 'Internal Server Error during get docx template list';
|
||||
res.end(res.statusMessage);
|
||||
console.error('Error during apply template: ', ex);
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
|
||||
67
libs/report-template.ts
Normal file
67
libs/report-template.ts
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
export interface templateData {
|
||||
template: string;
|
||||
reportName: string;
|
||||
data: object
|
||||
}
|
||||
export interface IDictionary<TValue> {
|
||||
[key: string]: TValue;
|
||||
}
|
||||
export function mimeToExtension(mime: string): string {
|
||||
const mimeList: IDictionary<string> = {
|
||||
"application/pdf": "pdf",
|
||||
"application/vnd.openxmlformats-officedocument.wordprocessingml.document": "docx",
|
||||
"application/msword": "doc",
|
||||
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": "xlsx",
|
||||
"application/vnd.ms-excel": "xls",
|
||||
"application/vnd.ms-powerpoint": "ppt",
|
||||
"application/vnd.openxmlformats-officedocument.presentationml.presentation": "pptx",
|
||||
"application/vnd.oasis.opendocument.text": "odt",
|
||||
"application/vnd.oasis.opendocument.spreadsheet":"ods",
|
||||
"application/vnd.oasis.opendocument.presentation":"odp",
|
||||
"text/html": "html",
|
||||
"application/json": "json",
|
||||
"text/csv": "csv",
|
||||
"text/markdown": "md",
|
||||
"text/plain": "txt",
|
||||
"application/rtf": "rtf"
|
||||
}
|
||||
if (mimeList[mime]) {
|
||||
return mimeList[mime]
|
||||
} else if (mime.match(/^application\/x\./)) {
|
||||
return mime.substr(mime.indexOf('.') + 1);
|
||||
} else {
|
||||
return mime
|
||||
}
|
||||
|
||||
}
|
||||
/** javascript-obfuscator:disable
|
||||
* @swagger
|
||||
* tags:
|
||||
* name: report-template
|
||||
* description: API สำหรับสร้างเอกสารจาก Template docx หรือ xlsx การทำงานคล้ายการทำ Mail Merge ทำให้ยูสเซอร์ทั่วไปแก้ Template ได้ง่าย สามารถแปลงไฟล์นามสกุลอื่นๆที่ soffice รองรับ
|
||||
*/
|
||||
|
||||
|
||||
/** javascript-obfuscator:disable
|
||||
* @swagger
|
||||
* components:
|
||||
* schemas:
|
||||
* templateData:
|
||||
* type: object
|
||||
* required:
|
||||
* - template
|
||||
* - reportName
|
||||
* - data
|
||||
* - finished
|
||||
* properties:
|
||||
* template:
|
||||
* type: string
|
||||
* description: name of template
|
||||
* reportName:
|
||||
* type: string
|
||||
* description: name of report for download
|
||||
* data:
|
||||
* type: object
|
||||
* description: value for template
|
||||
*/
|
||||
|
||||
348
libs/swagger-specs.json
Normal file
348
libs/swagger-specs.json
Normal file
|
|
@ -0,0 +1,348 @@
|
|||
{
|
||||
"openapi": "3.1.0",
|
||||
"info": {
|
||||
"title": "Report Server",
|
||||
"version": "0.1.0",
|
||||
"description": "Advance Create and convert document API for microservice.",
|
||||
"license": {
|
||||
"name": "by Frappet",
|
||||
"url": "https://frappet.com"
|
||||
}
|
||||
},
|
||||
"servers": [
|
||||
{
|
||||
"url": "https://report-server.frappet.synology.me"
|
||||
},
|
||||
{
|
||||
"url": "http://localhost:3000"
|
||||
},
|
||||
{
|
||||
"url": "http://192.168.2.100:3000"
|
||||
}
|
||||
],
|
||||
"paths": {
|
||||
"/api/v1/report-template/convert": {
|
||||
"post": {
|
||||
"summary": "Create document from template",
|
||||
"tags": [
|
||||
"office-convert"
|
||||
],
|
||||
"parameters": [
|
||||
{
|
||||
"name": "report_name",
|
||||
"in": "header",
|
||||
"description": "นามสกุลไฟล์ที่อัปโหลดเข้ามา(ตอนนี้ไม่จำเป็นต้องใช้เพราะ soffice ตรวจสอบเอง)",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"example": "report"
|
||||
}
|
||||
}
|
||||
],
|
||||
"requestBody": {
|
||||
"required": true,
|
||||
"content": {
|
||||
"application/octet-stream": {
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"format": "binary"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"responses": {
|
||||
"201": {
|
||||
"description": "file was converted.",
|
||||
"content": {
|
||||
"application/pdf": {
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"format": "binary"
|
||||
}
|
||||
},
|
||||
"application/vnd.oasis.opendocument.text": {
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"format": "binary"
|
||||
}
|
||||
},
|
||||
"application/vnd.openxmlformats-officedocument.wordprocessingml.document": {
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"format": "binary"
|
||||
}
|
||||
},
|
||||
"application/msword": {
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"format": "binary"
|
||||
}
|
||||
},
|
||||
"text/html": {
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Server error"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/v1/report-template/docx": {
|
||||
"get": {
|
||||
"summary": "list docx template",
|
||||
"tags": [
|
||||
"report-template"
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "array of template",
|
||||
"content": {
|
||||
"applicatin/json": {
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"example": [
|
||||
"hello"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Server error"
|
||||
}
|
||||
}
|
||||
},
|
||||
"post": {
|
||||
"summary": "Create document from docx template output can be docx pdf odt",
|
||||
"tags": [
|
||||
"report-template"
|
||||
],
|
||||
"requestBody": {
|
||||
"required": true,
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/templateData"
|
||||
},
|
||||
"example": {
|
||||
"template": "hello",
|
||||
"reportName": "docx-report",
|
||||
"data": {
|
||||
"docNo": "๑๒๓๔๕",
|
||||
"me": "กระผม",
|
||||
"prefix": "นาย",
|
||||
"name": "สรวิชญ์",
|
||||
"surname": "พลสิทธิ์",
|
||||
"position": "Chief Technology Officer",
|
||||
"org": {
|
||||
"type": "บริษัท",
|
||||
"name": "เฟรปเป้ที",
|
||||
"url": "https://frappet.com"
|
||||
},
|
||||
"employees": [
|
||||
{
|
||||
"name": "ภาวิชญ์",
|
||||
"surname": "พลสิทธิ์"
|
||||
},
|
||||
{
|
||||
"name": "วิชญาภา",
|
||||
"surname": "พลสิทธิ์"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"responses": {
|
||||
"201": {
|
||||
"description": "เอกสารถูกสร้างขึ้น",
|
||||
"content": {
|
||||
"application/vnd.openxmlformats-officedocument.wordprocessingml.document": {
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"format": "binary"
|
||||
}
|
||||
},
|
||||
"application/pdf": {
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"format": "binary"
|
||||
}
|
||||
},
|
||||
"application/vnd.oasis.opendocument.text": {
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"format": "binary"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Server error"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/v1/report-template/xlsx": {
|
||||
"get": {
|
||||
"summary": "แสดงรายการ xlsx template",
|
||||
"tags": [
|
||||
"report-template"
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "array of template",
|
||||
"content": {
|
||||
"applicatin/json": {
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"example": [
|
||||
"hello"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Server error"
|
||||
}
|
||||
}
|
||||
},
|
||||
"post": {
|
||||
"summary": "สร้าองเอกสารจาก xlsx template แล้วส่งกลับมาเป็น xlsx pdf odt",
|
||||
"tags": [
|
||||
"report-template"
|
||||
],
|
||||
"requestBody": {
|
||||
"required": true,
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/templateData"
|
||||
},
|
||||
"example": {
|
||||
"template": "hello",
|
||||
"reportName": "xlsx-report",
|
||||
"data": {
|
||||
"docNo": "๑๒๓๔๕",
|
||||
"me": "กระผม",
|
||||
"prefix": "นาย",
|
||||
"name": "สรวิชญ์",
|
||||
"surname": "พลสิทธิ์",
|
||||
"position": "Chief Technology Officer",
|
||||
"org": {
|
||||
"type": "บริษัท",
|
||||
"name": "เฟรปเป้ที",
|
||||
"url": "https://frappet.com"
|
||||
},
|
||||
"employees": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "ภาวิชญ์",
|
||||
"surname": "พลสิทธิ์",
|
||||
"score": 80
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "วิชญาภา",
|
||||
"surname": "พลสิทธิ์",
|
||||
"score": 50
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"name": "ฐิตาภา",
|
||||
"surname": "พลสิทธิ์",
|
||||
"score": 90
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"name": "สรวิชญ์ พลสิทธิ์",
|
||||
"surname": "พลสิทธิ์",
|
||||
"score": 99
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"responses": {
|
||||
"201": {
|
||||
"description": "เอกสารถูกสร้างขึ้น created.",
|
||||
"content": {
|
||||
"application/vnd.openxmlformats-officedocument.wordprocessingml.document": {
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"format": "binary"
|
||||
}
|
||||
},
|
||||
"application/pdf": {
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"format": "binary"
|
||||
}
|
||||
},
|
||||
"application/vnd.oasis.opendocument.text": {
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"format": "binary"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Server error"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"components": {
|
||||
"schemas": {
|
||||
"templateData": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"template",
|
||||
"reportName",
|
||||
"data",
|
||||
"finished"
|
||||
],
|
||||
"properties": {
|
||||
"template": {
|
||||
"type": "string",
|
||||
"description": "name of template"
|
||||
},
|
||||
"reportName": {
|
||||
"type": "string",
|
||||
"description": "name of report for download"
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"description": "value for template"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"tags": [
|
||||
{
|
||||
"name": "office-convert",
|
||||
"description": "ใช้แปลงไฟล์จากเอกสารที่ libreoffice แปลงได้ x"
|
||||
},
|
||||
{
|
||||
"name": "report-template",
|
||||
"description": "API สำหรับสร้างเอกสารจาก Template docx หรือ xlsx การทำงานคล้ายการทำ Mail Merge ทำให้ยูสเซอร์ทั่วไปแก้ Template ได้ง่าย สามารถแปลงไฟล์นามสกุลอื่นๆที่ soffice รองรับ"
|
||||
}
|
||||
]
|
||||
}
|
||||
134
libs/xlsx-template-lib.ts
Normal file
134
libs/xlsx-template-lib.ts
Normal file
|
|
@ -0,0 +1,134 @@
|
|||
import express from 'express'
|
||||
export const xlsxTemplateRoute = express.Router();
|
||||
|
||||
import {mimeToExtension,templateData} from './report-template'
|
||||
import { ExcelTemplate } from 'xlsx-template-next'
|
||||
import fs from 'fs'
|
||||
import { LibreOfficeFileConverter } from 'libreoffice-file-converter';
|
||||
const TEMPLATE_FOLDER_NAME = "templates/xlsx"
|
||||
|
||||
/**
|
||||
* docxTemplate Uses docx-template to convert input data and template to output buffer.
|
||||
* You have to handle exception throw by function
|
||||
* template keep in folder templates
|
||||
* @param {String} base base path of caller relate to template-docx foler (no trail slash)
|
||||
* @param {templateData} tdata Template Information in JSON format
|
||||
* @param {String} outputMediaType output extension
|
||||
* @param {Number} tab tab page of spread sheet , default = 1
|
||||
* @return {Promise<Uint8Array>} output buffer after apply template.
|
||||
*/
|
||||
export async function xlsxTemplateX(base: string=".", tdata: templateData, outputMediaType: string="xlsx",tab:number=1): Promise<Uint8Array> {
|
||||
try {
|
||||
const template = new ExcelTemplate();
|
||||
let templateBuff = await fs.promises.readFile(`${base}/${TEMPLATE_FOLDER_NAME}/${tdata.template}.xlsx`)
|
||||
await template.load(templateBuff);
|
||||
await template.process(tab,tdata.data)
|
||||
const buffer = await template.build({ type: 'uint8array' })
|
||||
if (outputMediaType === "xlsx")
|
||||
return buffer as Uint8Array
|
||||
const libreOfficeFileConverter = new LibreOfficeFileConverter({
|
||||
childProcessOptions: {
|
||||
timeout: 60 * 1000,
|
||||
},
|
||||
});
|
||||
const lbuffer = await libreOfficeFileConverter.convertBuffer(Buffer.from(buffer as Uint8Array), outputMediaType);
|
||||
return lbuffer
|
||||
|
||||
} catch (e) {
|
||||
throw (e)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/** javascript-obfuscator:disable
|
||||
* @swagger
|
||||
* /api/v1/report-template/xlsx:
|
||||
* get:
|
||||
* summary: แสดงรายการ xlsx template
|
||||
* tags: [report-template]
|
||||
* responses:
|
||||
* 200:
|
||||
* description: array of template
|
||||
* content:
|
||||
* applicatin/json:
|
||||
* schema:
|
||||
* type: array
|
||||
* items:
|
||||
* type: string
|
||||
* example: ["hello"]
|
||||
* 500:
|
||||
* description: Server error
|
||||
*/
|
||||
xlsxTemplateRoute.get("/", async function (req, res) {
|
||||
try {
|
||||
const fileList = await fs.promises.readdir(`./${TEMPLATE_FOLDER_NAME}`)
|
||||
const templateList = fileList.map((f) => f.split('.xlsx')[0])
|
||||
res.send(templateList)
|
||||
} catch (ex) {
|
||||
res.statusCode = 500;
|
||||
res.statusMessage = 'Internal Server Error during get xlsx template list';
|
||||
res.end(res.statusMessage);
|
||||
console.error('Error during get template list: ', ex);
|
||||
}
|
||||
})
|
||||
|
||||
/** javascript-obfuscator:disable
|
||||
* @swagger
|
||||
* /api/v1/report-template/xlsx:
|
||||
* post:
|
||||
* summary: สร้าองเอกสารจาก xlsx template แล้วส่งกลับมาเป็น xlsx pdf odt
|
||||
* tags: [report-template]
|
||||
* requestBody:
|
||||
* required: true
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* $ref: '#/components/schemas/templateData'
|
||||
* example:
|
||||
* template: hello
|
||||
* reportName: xlsx-report
|
||||
* data: {"docNo": "๑๒๓๔๕","me": "กระผม","prefix": "นาย","name": "สรวิชญ์","surname": "พลสิทธิ์","position": "Chief Technology Officer","org": {"type": "บริษัท","name": "เฟรปเป้ที","url": "https://frappet.com"},"employees": [{"id":1,"name": "ภาวิชญ์","surname": "พลสิทธิ์","score":80},{"id":2,"name": "วิชญาภา","surname": "พลสิทธิ์","score":50},{"id":3,"name": "ฐิตาภา","surname": "พลสิทธิ์","score":90},{"id":4,"name": "สรวิชญ์ พลสิทธิ์","surname": "พลสิทธิ์","score":99}]}
|
||||
* responses:
|
||||
* 201:
|
||||
* description: เอกสารถูกสร้างขึ้น created.
|
||||
* content:
|
||||
* application/vnd.openxmlformats-officedocument.wordprocessingml.document:
|
||||
* schema:
|
||||
* type: string
|
||||
* format: binary
|
||||
* application/pdf:
|
||||
* schema:
|
||||
* type: string
|
||||
* format: binary
|
||||
* application/vnd.oasis.opendocument.text:
|
||||
* schema:
|
||||
* type: string
|
||||
* format: binary
|
||||
* 500:
|
||||
* description: Server error
|
||||
*
|
||||
*/
|
||||
xlsxTemplateRoute.post("/", async function (req, res) {
|
||||
try {
|
||||
if (!req.headers['content-type'] || !req.headers['accept'])
|
||||
throw new Error("Require header content-type, accept")
|
||||
let inputType = mimeToExtension(req.headers['content-type']);
|
||||
let outputMediaType = mimeToExtension(req.headers['accept']);
|
||||
console.log('content-type: ', inputType);
|
||||
console.log('accept: ', outputMediaType);
|
||||
let buffer = await xlsxTemplateX(".",req.body,outputMediaType)
|
||||
res.statusCode = 201;
|
||||
res.setHeader('Content-Type', req.headers['accept']);
|
||||
res.setHeader('Content-Disposition', `attachment;filename=${req.body.reportName}.${outputMediaType}`);
|
||||
res.setHeader('Content-Length', buffer.length);
|
||||
res.end(buffer);
|
||||
} catch (ex) {
|
||||
res.statusCode = 500;
|
||||
res.statusMessage = 'Internal Server Error';
|
||||
res.end(res.statusMessage);
|
||||
console.error('Error during apply template: ', ex);
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue