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
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -6,6 +6,7 @@ yarn-debug.log*
|
|||
yarn-error.log*
|
||||
lerna-debug.log*
|
||||
.pnpm-debug.log*
|
||||
dist2
|
||||
|
||||
# Diagnostic reports (https://nodejs.org/api/report.html)
|
||||
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
||||
|
|
|
|||
22
Dockerfile
Normal file
22
Dockerfile
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
# docker build -t docker.frappet.com/demo/report-server .
|
||||
# docker push docker.frappet.com/demo/report-server
|
||||
# docker run --name rserver -p 80:3000 docker.frappet.com/demo/report-server
|
||||
FROM node:20
|
||||
# ENV PANDOC_VERSION 3.1.7
|
||||
|
||||
ENV TZ=Asia/Bangkok
|
||||
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
|
||||
RUN mkdir -p /usr/share/fonts/truetype/th
|
||||
COPY ./ThaiFonts/*.ttf /usr/share/fonts/truetype/th/
|
||||
# RUN fc-cache -f -v
|
||||
RUN apt-get -qq update && apt-get -qq -y install wget fonts-noto fonts-noto-cjk libreoffice --no-install-recommends
|
||||
RUN fc-cache -f && rm -rf /var/cache/* && apt -y autoremove && rm -rf /var/lib/apt/lists/* && apt-get clean
|
||||
RUN mkdir /app
|
||||
WORKDIR /app
|
||||
COPY templates templates
|
||||
COPY package.json .
|
||||
ENV NODE_ENV production
|
||||
RUN npm install
|
||||
COPY dist2 .
|
||||
EXPOSE 80
|
||||
CMD ["node","app.js"]
|
||||
57
README.md
57
README.md
|
|
@ -1,2 +1,57 @@
|
|||
# report-server-ts
|
||||
Typescript and bun port of Report Server (Javascript node)
|
||||
เป็น Web API ออกแบบมาเพื่อสร้างเอกสาร สามารถใช้ frontend โดยตรง เพื่อจะได้ไม่ต้องเขียนโปรแกรมทำเอกสารเฉพาะแต่ละตัวออกมา ปรับปรุงของเดิมจาก
|
||||
เขียนใหม่เป็น TypeScript ตัด pandoc ออก เริ่มแรกลองใช้ bun แทน node รองรับ TypeScript โดยไม่ต้องตั้งค่า แต่มีปัญหากับ libreoffice-file-converter ต้องแก้ค่าใน package.json และ docker-template คาดว่าเป็นปัญหาจาก eval ทำให้ ส่วน EXEC กับ custom function ทำงานไม่ได้ เลยกลับมาใช้ node ตั้งค่าของ TypeScript [ตามเวปนี้](https://www.geeksforgeeks.org/how-to-use-express-in-typescript/) ให้ใช้ ES module ได้ด้วย
|
||||
|
||||
```bash
|
||||
npm i express
|
||||
npm i -D typescript @types/express @types/node ts-node
|
||||
npm i docx-templates xlsx-template-next swagger-ui-express swagger-jsdoc yaqrcode libreoffice-file-converter
|
||||
npm i -D @types/swagger-ui-express @types/swagger-jsdoc
|
||||
# obfuscate code tools
|
||||
npm i -D javascript-obfuscator
|
||||
# add type support for yaqrcode
|
||||
cd node_modules/yaqrcode
|
||||
wget https://raw.githubusercontent.com/zenozeng/node-yaqrcode/master/index.d.ts
|
||||
|
||||
```
|
||||
# การใช้งาน
|
||||
ดู scripts ใน package.json และ compose.yaml
|
||||
```bash
|
||||
npm run dev
|
||||
npm run build
|
||||
npm run serve
|
||||
npm run obfuscator
|
||||
npm run preview
|
||||
npm run build:docker
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
# ทดสอบ template
|
||||
ไปที่โฟลเดอร์ test-run จะมีโค้ดเพื่อทดสอบ template docx และ xlsx อย่างง่าย ใช้ค่า default ได้เลย สามารถทดสอบการแปลงไปไฟล์แบบต่างๆที่ Libreoffice รองรับได้ ควรทดสอบรูปแบบข้อมูล(json) ให้เข้ากับ template(docx,xlsx) ก่อนใช้งานเพราะ error log จะแสดงที่เซิร์เวอร์เท่านั้น
|
||||
``` bash
|
||||
$ npx ts-node docx-template.ts
|
||||
Output extension(docx,pdf,odt): pdf
|
||||
JSON data path(./docx.json):
|
||||
Base path of templates-docx(..):
|
||||
|
||||
$ npx ts-node xlsx-template.ts
|
||||
Output extension(xlsx,pdf): ods
|
||||
JSON data path(./xlsx.json):
|
||||
Base path of templates-docx(..):
|
||||
```
|
||||
|
||||
|
||||
|
||||
# Build docker
|
||||
```bash
|
||||
docker build -t docker.frappet.com/demo/report-server .
|
||||
docker push docker.frappet.com/demo/report-server
|
||||
docker run --name rserver -p 80:3000 docker.frappet.com/demo/report-server
|
||||
```
|
||||
|
||||
## report-templates/docx
|
||||
|
||||
ใช้ library [docx-templates](https://www.npmjs.com/package/docx-templates) รับข้อมูลใน json กับ MS Word (template) เพิ่อสร้างเอกสาร MS Word สำหรับการใช้งาน PDF จะใช้ LibreOffice ในการแปลงจาก docx เป็น pdf เพื่อจะได้ตัดคำภาษาไทยได้
|
||||
|
||||
## report-templates/xlsx
|
||||
comming soon
|
||||
|
|
|
|||
BIN
ThaiFonts/TH Baijam Bold Italic.ttf
Normal file
BIN
ThaiFonts/TH Baijam Bold Italic.ttf
Normal file
Binary file not shown.
BIN
ThaiFonts/TH Baijam Bold.ttf
Normal file
BIN
ThaiFonts/TH Baijam Bold.ttf
Normal file
Binary file not shown.
BIN
ThaiFonts/TH Baijam Italic.ttf
Normal file
BIN
ThaiFonts/TH Baijam Italic.ttf
Normal file
Binary file not shown.
BIN
ThaiFonts/TH Baijam.ttf
Normal file
BIN
ThaiFonts/TH Baijam.ttf
Normal file
Binary file not shown.
BIN
ThaiFonts/TH Chakra Petch Bold Italic.ttf
Normal file
BIN
ThaiFonts/TH Chakra Petch Bold Italic.ttf
Normal file
Binary file not shown.
BIN
ThaiFonts/TH Chakra Petch Bold.ttf
Normal file
BIN
ThaiFonts/TH Chakra Petch Bold.ttf
Normal file
Binary file not shown.
BIN
ThaiFonts/TH Chakra Petch Italic.ttf
Normal file
BIN
ThaiFonts/TH Chakra Petch Italic.ttf
Normal file
Binary file not shown.
BIN
ThaiFonts/TH Chakra Petch.ttf
Normal file
BIN
ThaiFonts/TH Chakra Petch.ttf
Normal file
Binary file not shown.
BIN
ThaiFonts/TH Charm of AU.ttf
Normal file
BIN
ThaiFonts/TH Charm of AU.ttf
Normal file
Binary file not shown.
BIN
ThaiFonts/TH Charmonman Bold.ttf
Normal file
BIN
ThaiFonts/TH Charmonman Bold.ttf
Normal file
Binary file not shown.
BIN
ThaiFonts/TH Charmonman.ttf
Normal file
BIN
ThaiFonts/TH Charmonman.ttf
Normal file
Binary file not shown.
BIN
ThaiFonts/TH Fahkwang Bold Italic.ttf
Normal file
BIN
ThaiFonts/TH Fahkwang Bold Italic.ttf
Normal file
Binary file not shown.
BIN
ThaiFonts/TH Fahkwang Bold.ttf
Normal file
BIN
ThaiFonts/TH Fahkwang Bold.ttf
Normal file
Binary file not shown.
BIN
ThaiFonts/TH Fahkwang Italic.ttf
Normal file
BIN
ThaiFonts/TH Fahkwang Italic.ttf
Normal file
Binary file not shown.
BIN
ThaiFonts/TH Fahkwang.ttf
Normal file
BIN
ThaiFonts/TH Fahkwang.ttf
Normal file
Binary file not shown.
BIN
ThaiFonts/TH K2D July8 Bold Italic.ttf
Normal file
BIN
ThaiFonts/TH K2D July8 Bold Italic.ttf
Normal file
Binary file not shown.
BIN
ThaiFonts/TH K2D July8 Bold.ttf
Normal file
BIN
ThaiFonts/TH K2D July8 Bold.ttf
Normal file
Binary file not shown.
BIN
ThaiFonts/TH K2D July8 Italic.ttf
Normal file
BIN
ThaiFonts/TH K2D July8 Italic.ttf
Normal file
Binary file not shown.
BIN
ThaiFonts/TH K2D July8.ttf
Normal file
BIN
ThaiFonts/TH K2D July8.ttf
Normal file
Binary file not shown.
BIN
ThaiFonts/TH KoHo Bold Italic.ttf
Normal file
BIN
ThaiFonts/TH KoHo Bold Italic.ttf
Normal file
Binary file not shown.
BIN
ThaiFonts/TH KoHo Bold.ttf
Normal file
BIN
ThaiFonts/TH KoHo Bold.ttf
Normal file
Binary file not shown.
BIN
ThaiFonts/TH KoHo Italic.ttf
Normal file
BIN
ThaiFonts/TH KoHo Italic.ttf
Normal file
Binary file not shown.
BIN
ThaiFonts/TH KoHo.ttf
Normal file
BIN
ThaiFonts/TH KoHo.ttf
Normal file
Binary file not shown.
BIN
ThaiFonts/TH Kodchasal Bold Italic.ttf
Normal file
BIN
ThaiFonts/TH Kodchasal Bold Italic.ttf
Normal file
Binary file not shown.
BIN
ThaiFonts/TH Kodchasal Bold.ttf
Normal file
BIN
ThaiFonts/TH Kodchasal Bold.ttf
Normal file
Binary file not shown.
BIN
ThaiFonts/TH Kodchasal Italic.ttf
Normal file
BIN
ThaiFonts/TH Kodchasal Italic.ttf
Normal file
Binary file not shown.
BIN
ThaiFonts/TH Kodchasal.ttf
Normal file
BIN
ThaiFonts/TH Kodchasal.ttf
Normal file
Binary file not shown.
BIN
ThaiFonts/TH Krub Bold Italic.ttf
Normal file
BIN
ThaiFonts/TH Krub Bold Italic.ttf
Normal file
Binary file not shown.
BIN
ThaiFonts/TH Krub Bold.ttf
Normal file
BIN
ThaiFonts/TH Krub Bold.ttf
Normal file
Binary file not shown.
BIN
ThaiFonts/TH Krub Italic.ttf
Normal file
BIN
ThaiFonts/TH Krub Italic.ttf
Normal file
Binary file not shown.
BIN
ThaiFonts/TH Krub.ttf
Normal file
BIN
ThaiFonts/TH Krub.ttf
Normal file
Binary file not shown.
BIN
ThaiFonts/TH Mali Grade6 Bold Italic.ttf
Normal file
BIN
ThaiFonts/TH Mali Grade6 Bold Italic.ttf
Normal file
Binary file not shown.
BIN
ThaiFonts/TH Mali Grade6 Bold.ttf
Normal file
BIN
ThaiFonts/TH Mali Grade6 Bold.ttf
Normal file
Binary file not shown.
BIN
ThaiFonts/TH Mali Grade6 Italic.ttf
Normal file
BIN
ThaiFonts/TH Mali Grade6 Italic.ttf
Normal file
Binary file not shown.
BIN
ThaiFonts/TH Mali Grade6.ttf
Normal file
BIN
ThaiFonts/TH Mali Grade6.ttf
Normal file
Binary file not shown.
BIN
ThaiFonts/TH Niramit AS Bold Italic.ttf
Normal file
BIN
ThaiFonts/TH Niramit AS Bold Italic.ttf
Normal file
Binary file not shown.
BIN
ThaiFonts/TH Niramit AS Bold.ttf
Normal file
BIN
ThaiFonts/TH Niramit AS Bold.ttf
Normal file
Binary file not shown.
BIN
ThaiFonts/TH Niramit AS Italic.ttf
Normal file
BIN
ThaiFonts/TH Niramit AS Italic.ttf
Normal file
Binary file not shown.
BIN
ThaiFonts/TH Niramit AS-IT๙ Bold Italic.ttf
Normal file
BIN
ThaiFonts/TH Niramit AS-IT๙ Bold Italic.ttf
Normal file
Binary file not shown.
BIN
ThaiFonts/TH Niramit AS.ttf
Normal file
BIN
ThaiFonts/TH Niramit AS.ttf
Normal file
Binary file not shown.
BIN
ThaiFonts/TH NiramitIT๙ Bold.ttf
Normal file
BIN
ThaiFonts/TH NiramitIT๙ Bold.ttf
Normal file
Binary file not shown.
BIN
ThaiFonts/TH NiramitIT๙ Italic.ttf
Normal file
BIN
ThaiFonts/TH NiramitIT๙ Italic.ttf
Normal file
Binary file not shown.
BIN
ThaiFonts/TH NiramitIT๙.ttf
Normal file
BIN
ThaiFonts/TH NiramitIT๙.ttf
Normal file
Binary file not shown.
BIN
ThaiFonts/TH Srisakdi Bold.ttf
Normal file
BIN
ThaiFonts/TH Srisakdi Bold.ttf
Normal file
Binary file not shown.
BIN
ThaiFonts/TH Srisakdi.ttf
Normal file
BIN
ThaiFonts/TH Srisakdi.ttf
Normal file
Binary file not shown.
BIN
ThaiFonts/THSarabun Bold Italic.ttf
Normal file
BIN
ThaiFonts/THSarabun Bold Italic.ttf
Normal file
Binary file not shown.
BIN
ThaiFonts/THSarabun Bold.ttf
Normal file
BIN
ThaiFonts/THSarabun Bold.ttf
Normal file
Binary file not shown.
BIN
ThaiFonts/THSarabun BoldItalic.ttf
Normal file
BIN
ThaiFonts/THSarabun BoldItalic.ttf
Normal file
Binary file not shown.
BIN
ThaiFonts/THSarabun Italic.ttf
Normal file
BIN
ThaiFonts/THSarabun Italic.ttf
Normal file
Binary file not shown.
BIN
ThaiFonts/THSarabun.ttf
Normal file
BIN
ThaiFonts/THSarabun.ttf
Normal file
Binary file not shown.
BIN
ThaiFonts/THSarabunIT๙ Bold.ttf
Normal file
BIN
ThaiFonts/THSarabunIT๙ Bold.ttf
Normal file
Binary file not shown.
BIN
ThaiFonts/THSarabunIT๙ BoldItalic.ttf
Normal file
BIN
ThaiFonts/THSarabunIT๙ BoldItalic.ttf
Normal file
Binary file not shown.
BIN
ThaiFonts/THSarabunIT๙ Italic.ttf
Normal file
BIN
ThaiFonts/THSarabunIT๙ Italic.ttf
Normal file
Binary file not shown.
BIN
ThaiFonts/THSarabunIT๙.ttf
Normal file
BIN
ThaiFonts/THSarabunIT๙.ttf
Normal file
Binary file not shown.
BIN
ThaiFonts/THSarabunNew Bold.ttf
Normal file
BIN
ThaiFonts/THSarabunNew Bold.ttf
Normal file
Binary file not shown.
BIN
ThaiFonts/THSarabunNew BoldItalic.ttf
Normal file
BIN
ThaiFonts/THSarabunNew BoldItalic.ttf
Normal file
Binary file not shown.
BIN
ThaiFonts/THSarabunNew Italic.ttf
Normal file
BIN
ThaiFonts/THSarabunNew Italic.ttf
Normal file
Binary file not shown.
BIN
ThaiFonts/THSarabunNew.ttf
Normal file
BIN
ThaiFonts/THSarabunNew.ttf
Normal file
Binary file not shown.
27
app.ts
Normal file
27
app.ts
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* Report Server
|
||||
* Web API สำหรับสร้างรายงาน กำหนด Path และเพิ่มฟีเจอร์ได้
|
||||
* จะใช้ Node.js เป็น reverse proxy ไปหา pandoc ที่ swan ขึ้นมา
|
||||
* demo frontent อยู่ในโฟลเดอร์ public
|
||||
*/
|
||||
import swaggerspecs from "./libs/swagger-specs.json"
|
||||
import swaggerUi from "swagger-ui-express"
|
||||
import express, { Express, Request, Response } from 'express'
|
||||
import { docxTemplateRoute } from './libs/docx-templates-lib'
|
||||
import { xlsxTemplateRoute } from './libs/xlsx-template-lib'
|
||||
import { convertTemplateRoute } from './libs/convert-libs'
|
||||
const app: Express = express()
|
||||
const port: number = Number(process.env.PORT) || 80;
|
||||
app.use(express.json()); //‘application/json’
|
||||
app.use(express.raw()); //‘application/octet-stream’
|
||||
app.use(express.urlencoded({ extended: true }));
|
||||
app.use("/swagger", swaggerUi.serve, swaggerUi.setup(swaggerspecs,{ explorer: true }));
|
||||
app.get('/', (req: Request, res: Response) => {
|
||||
res.json({
|
||||
message: 'Hello report-template API !!',
|
||||
})
|
||||
})
|
||||
app.use('/api/v1/report-template/docx', docxTemplateRoute);
|
||||
app.use('/api/v1/report-template/xlsx', xlsxTemplateRoute);
|
||||
app.use('/api/v1/report-template/convert', convertTemplateRoute);
|
||||
app.listen(port, () => console.log(`Application is running on port ${port}`))
|
||||
8
compose.yaml
Normal file
8
compose.yaml
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
version: "3.2"
|
||||
services:
|
||||
report-server:
|
||||
image: docker.frappet.com/demo/report-server:latest
|
||||
ports:
|
||||
- 3000:80
|
||||
volumes:
|
||||
- ./templates:/app/templates
|
||||
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);
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
|
||||
2500
package-lock.json
generated
Normal file
2500
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
36
package.json
Normal file
36
package.json
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
{
|
||||
"name": "report-server-ts",
|
||||
"version": "1.0.0",
|
||||
"description": "docx-template มีปัญหากับ bun คาดว่าเป็นปัญหาจาก eval",
|
||||
"scripts": {
|
||||
"dev": "PORT=3000 nodemon app.ts",
|
||||
"swaggergen":"ts-node libs/create-swagger-spec.ts ",
|
||||
"build": "ts-node libs/create-swagger-spec.ts && tsc && cp libs/swagger-specs.json dist/libs",
|
||||
"serve": "PORT=3000 node dist/app.js",
|
||||
"obfuscator": "tsc && javascript-obfuscator ./dist --output ./dist2 && cp libs/swagger-specs.json dist/libs",
|
||||
"preview": "PORT=3000 node dist2/app.js",
|
||||
"build:docker": "ts-node libs/create-swagger-spec.ts && tsc && javascript-obfuscator ./dist --output ./dist2&& cp libs/swagger-specs.json dist2/libs && docker build -t docker.frappet.com/demo/report-server ."
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"docx-templates": "^4.11.3",
|
||||
"express": "^4.18.2",
|
||||
"libreoffice-file-converter": "^1.2.1",
|
||||
"swagger-jsdoc": "^6.2.8",
|
||||
"swagger-ui-express": "^5.0.0",
|
||||
"xlsx-template-next": "^0.1.2",
|
||||
"yaqrcode": "^0.2.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/express": "^4.17.18",
|
||||
"@types/node": "^20.8.2",
|
||||
"@types/swagger-jsdoc": "^6.0.1",
|
||||
"@types/swagger-ui-express": "^4.1.4",
|
||||
"javascript-obfuscator": "^4.1.0",
|
||||
"nodemon": "^3.0.1",
|
||||
"ts-node": "^10.9.1",
|
||||
"typescript": "^5.2.2"
|
||||
}
|
||||
}
|
||||
BIN
templates/docx/blank.docx
Normal file
BIN
templates/docx/blank.docx
Normal file
Binary file not shown.
BIN
templates/docx/hello.docx
Normal file
BIN
templates/docx/hello.docx
Normal file
Binary file not shown.
BIN
templates/xlsx/hello.xlsx
Normal file
BIN
templates/xlsx/hello.xlsx
Normal file
Binary file not shown.
21
test-run/docx-template.ts
Normal file
21
test-run/docx-template.ts
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
|
||||
// npx ts-node docx-templates.ts
|
||||
import * as readline from 'node:readline/promises'; // This uses the promise-based APIs
|
||||
import { stdin as input, stdout as output } from 'node:process';
|
||||
import { docxTemplateX} from '../src/libs/docx-templates-lib';
|
||||
import {templateData} from '../src/libs/report-template'
|
||||
import fs from 'fs';
|
||||
(async ()=>{
|
||||
const rl = readline.createInterface({ input, output });
|
||||
const e = await rl.question('Output extension(docx,pdf,odt): ');
|
||||
const ext =e?e:"docx"
|
||||
const dpath = await rl.question('JSON data path(./docx.json): ');
|
||||
const datapath = dpath?dpath:"./docx.json"
|
||||
const data_raw = fs.readFileSync(datapath);
|
||||
const tdata:templateData = JSON.parse(data_raw.toString());
|
||||
const bpath = await rl.question('Base path of templates-docx(..): ');
|
||||
const basepath = bpath?bpath:".."
|
||||
let buffer = await docxTemplateX(basepath,tdata,ext)
|
||||
fs.writeFileSync(tdata.reportName+"."+ext, buffer);
|
||||
rl.close();
|
||||
})()
|
||||
28
test-run/docx.json
Normal file
28
test-run/docx.json
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
{
|
||||
|
||||
"template": "hello",
|
||||
"reportName": "report-docx",
|
||||
"data": {
|
||||
"docNo": "๑๒๓๔๕",
|
||||
"me": "กระผม",
|
||||
"prefix": "นาย",
|
||||
"name": "สรวิชญ์",
|
||||
"surname": "พลสิทธิ์",
|
||||
"position": "Chief Technology Officer",
|
||||
"org": {
|
||||
"type": "บริษัท",
|
||||
"name": "เฟรปเป้ที",
|
||||
"url": "https://frappet.com"
|
||||
},
|
||||
"employees": [
|
||||
{
|
||||
"name": "ภาวิชญ์",
|
||||
"surname": "พลสิทธิ์"
|
||||
},
|
||||
{
|
||||
"name": "วิชญาภา",
|
||||
"surname": "พลสิทธิ์"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
BIN
test-run/report-docx.pdf
Normal file
BIN
test-run/report-docx.pdf
Normal file
Binary file not shown.
BIN
test-run/report-xlsx.pdf
Normal file
BIN
test-run/report-xlsx.pdf
Normal file
Binary file not shown.
BIN
test-run/report.docx
Normal file
BIN
test-run/report.docx
Normal file
Binary file not shown.
BIN
test-run/report.odt
Normal file
BIN
test-run/report.odt
Normal file
Binary file not shown.
BIN
test-run/report.pdf
Normal file
BIN
test-run/report.pdf
Normal file
Binary file not shown.
21
test-run/xlsx-template.ts
Normal file
21
test-run/xlsx-template.ts
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
|
||||
// npx ts-node xlsx-template.ts
|
||||
import * as readline from 'node:readline/promises'; // This uses the promise-based APIs
|
||||
import { stdin as input, stdout as output } from 'node:process';
|
||||
import {xlsxTemplateX} from '../src/libs/xlsx-template-lib'
|
||||
import {templateData} from '../src/libs/report-template'
|
||||
import fs from 'fs';
|
||||
(async ()=>{
|
||||
const rl = readline.createInterface({ input, output });
|
||||
const e = await rl.question('Output extension(xlsx,pdf,ods): ');
|
||||
const ext =e?e:"xlsx"
|
||||
const dpath = await rl.question('JSON data path(./xlsx.json): ');
|
||||
const datapath = dpath?dpath:"./xlsx.json"
|
||||
const data_raw = fs.readFileSync(datapath);
|
||||
const tdata:templateData = JSON.parse(data_raw.toString());
|
||||
const bpath = await rl.question('Base path of templates-docx(..): ');
|
||||
const basepath = bpath?bpath:".."
|
||||
let buffer = await xlsxTemplateX(basepath,tdata,ext)
|
||||
fs.writeFileSync(tdata.reportName+"."+ext, buffer);
|
||||
rl.close();
|
||||
})()
|
||||
44
test-run/xlsx.json
Normal file
44
test-run/xlsx.json
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
{
|
||||
"template": "hello",
|
||||
"reportName": "report-xlsx",
|
||||
"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
|
||||
}
|
||||
|
||||
]
|
||||
}
|
||||
}
|
||||
14
tsconfig.json
Normal file
14
tsconfig.json
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"target": "es6",
|
||||
"module": "commonjs",
|
||||
"rootDir": "./",
|
||||
"outDir": "dist",
|
||||
"esModuleInterop": true,
|
||||
"resolveJsonModule": true,
|
||||
"strict": true,
|
||||
"skipLibCheck": true
|
||||
},
|
||||
"include": ["libs/**/*.ts","app.ts"],
|
||||
"exclude": ["node_modules","test-run"]
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue