NodeJs导出PDF
(优于别人,并不高贵,真正的高贵应该是优于过去的自己。——海明威)
场景
根据订单参数生成账单PDF
结果
示例代码
/* eslint-disable no-unused-vars */
/* eslint-disable no-undef */
/* eslint-disable complexity */
const PDFDocument = require('pdfkit');
const fs = require('fs');
const dayjs = require('dayjs');
const AgencyWithdrawOrderStatus = {Completed: 'Completed',Submitted: 'Submitted',Rejected: 'Rejected',
}
const agencyName = 'Jasin';
const agencyEmail = 'pdfkit@dev.com';
const order = {"id": "FI-AWO-20230718-8657637839","accountID": {"id": "ID-AGE-20230707-6351711990","type": "AGENCY"},"transactionNo": "FIAWO202307180650601146","referenceID": "","transferWay": "Bank card","walletID": "FI-WAL-20230707-5401898911","transferID": "FI-TRF-20230718-4134849682","transactionID": "FI-TRA-20230718-2048728248","somoServiceFee": 345,"somoServiceFeeRate": 0.05,"bankTransferFee": 3000,"bankTransferFeeRate": 3000,"paypalTransferFee": 345,"paypalTransferFeeRate": 0.05,"paypalRemittanceAmount": 6555,"bankRemittanceAmount": 6900,"totalAmount": 6900,"status": "Submitted","transactionList": [{"brandName": "asdasdads","transactionID": "FI-TRA-20230710-1494352833","brandID": "ID-BRA-20230627-2309656536","campaignID": "AC-CAM-20230710-3827733853","campaignTitle": "Jack","orderID": "AC-ORD-20230710-2795223591","type": "AGENCY_CAMPAIGN_ORDER_PAYMENT","amount": 6900,"somoServiceFee": 345,"paypalTransferFee": 345,"bankTransferFee": 0}, {"brandName": "asdasdads","transactionID": "FI-TRA-20230710-5284753385","brandID": "ID-BRA-20230627-2309656536","campaignID": "AC-CAM-20230710-4072616238","campaignTitle": "Kami","orderID": "AC-ORD-20230710-7402268061","type": "AGENCY_CAMPAIGN_ORDER_PAYMENT","amount": 0,"somoServiceFee": 0,"paypalTransferFee": 0,"bankTransferFee": 0}],"transactionCount": 2,"accountBalance": 888750099,"withdrawalMethod": {"bankEnabled": true,"bankAccountName": "12213","bankAccountNumber": "22","bankName": "333","bankAddress": "444","bankSwiftCode": "555"},"reason": "","createdAt": {"$date": "2023-07-18T09:53:45.568Z"},"updatedAt": {"$date": "2023-07-18T09:53:45.568Z"},"__v": 0
};
const method = async () => {const pdfBuffer = await new Promise((resolve) => {// 实例化PDF对象const doc = new PDFDocument({ size: 'A4' });const fontSize = 14;const remittanceText = 'Remittance amount:';const remittanceTitleColor = '#8792A2';const remittanceAmountColor = '#181C1F';const remittanceAmountSize = 40;const orderStatusText = order.status;const orderStatusColor = {Submitted: '#4E515C',Completed: '#009944',Rejected: '#FF0000',}[orderStatusText];const orderStatusBackColor = {Submitted: '#f2f4f9',Completed: '#d8f7e6',Rejected: '#f0dede',}[orderStatusText];const orderStatusOffset = {Submitted: -6,Completed: -8,Rejected: 0,}[orderStatusText];const getFloatNumber = (number) => {return parseFloat(number.toString()).toFixed(2);};const getConvertAmount = (number) => {return number / 100;};const rejectedOffset = order.status === 'Rejected' ? 45 : 0;const remittanceAmount = order.withdrawalMethod.paypalEnabled? order.paypalRemittanceAmount: order.bankRemittanceAmount;const transferFee = order.withdrawalMethod.paypalEnabled? order.paypalTransferFee: order.bankTransferFee;const remittanceAmountLength = getFloatNumber(getConvertAmount(remittanceAmount),).length;const remittanceAmoutOffset =remittanceAmountLength - 4 > 0 ? remittanceAmountLength - 4 : 0;const transferAccount =(order.withdrawalMethod.paypalEnabled? order.withdrawalMethod.paypalAccountID: order.withdrawalMethod.bankAccountName) ?? ' ';const transferDetailTitleColor = '#F2F3F7';const transferDetailTitleSize = 16;const transferDetailBackgroundColor = '#171A1F';const transferDetailTitleText = 'Transfer detail:';const orderStatusX = 100;const orderStatusY = 105;const startX = 73;const transferDetailRectY = 150;const transferDetailX = 80;const transferDetailY = 168;const transferDetailWidth = 500;const transferDetailHeight = 60;const sideWidth = 500;const sideHeight = 1;const valueColor = '#272A33';const linceColor = '#F5F7F7';doc.// 使用字体font(`${__dirname}/Montserrat-Bold.ttf`).// 字体大小fontSize(fontSize).// 字体颜色fillColor(remittanceTitleColor).// 这一行的文本text(remittanceText).fontSize(remittanceAmountSize).fillColor(remittanceAmountColor).text(`$ ${getFloatNumber(getConvertAmount(remittanceAmount))}`).// 渲染块,指定x,y坐标以及宽高rect(orderStatusX + 112 + remittanceAmoutOffset * 23,orderStatusY - 8,92,34,).// 块的颜色fill(orderStatusBackColor).// 块的字体大小fontSize(fontSize).// 字体的颜色fillColor(orderStatusColor).font(`${__dirname}/Montserrat-Regular.ttf`).// 指定x,y坐标text(orderStatusText,orderStatusX +16 +112 +orderStatusOffset +remittanceAmoutOffset * 23,orderStatusY,);if (orderStatusText === AgencyWithdrawOrderStatus.Rejected) {doc.rect(startX, transferDetailRectY, 469, 30).fill('#FFE58F').// 插入图片image('withdraw.pdf.rejected.png',startX + 10,transferDetailRectY + 5,{ width: 20, height: 20 },).fontSize(12).fillColor('#000000').text(` ${order.reason}`, startX + 35, transferDetailRectY + 6.5);}doc.rect(startX,transferDetailRectY + rejectedOffset,transferDetailWidth,transferDetailHeight,).fill(transferDetailTitleColor).fontSize(transferDetailTitleSize).fillColor(transferDetailBackgroundColor).font(`${__dirname}/Montserrat-Bold.ttf`).text(transferDetailTitleText,transferDetailX,transferDetailY + rejectedOffset,{continued: false,baseline: 'top',},).font(`${__dirname}/Montserrat-Regular.ttf`).fontSize(fontSize).fillColor(remittanceTitleColor).text('Agency:',startX,transferDetailRectY + transferDetailHeight + 20 + rejectedOffset,{ lineBreak: false },).fillColor(valueColor).text(agencyName, startX + 200, doc.y, { lineGap: 5 }).fontSize(fontSize).fillColor(remittanceTitleColor).text(`Email:`, startX, doc.y, { lineBreak: false, lineGap: 5 }).fillColor(valueColor).text(agencyEmail, startX + 200, doc.y, { lineGap: 5 }).fontSize(fontSize).fillColor(remittanceTitleColor).text('Transaction No. :', startX, doc.y, { lineBreak: false }).fillColor(valueColor).text(order.transactionNo, startX + 200, doc.y, { lineGap: 5 }).fontSize(fontSize).fillColor(remittanceTitleColor).text('Reference ID. :', startX, doc.y, { lineBreak: false }).fillColor(valueColor).text(order.referenceID || ' ', startX + 200, doc.y, { lineGap: 5 }).fontSize(fontSize).fillColor(remittanceTitleColor).text('Transfer way:', startX, doc.y, { lineBreak: false }).fillColor(valueColor).text(order.transferWay, startX + 200, doc.y, { lineGap: 5 }).fontSize(fontSize).fillColor(remittanceTitleColor).text('Transfer account:', startX, doc.y, { lineBreak: false }).fillColor(valueColor).text(transferAccount, startX + 200, doc.y, { lineGap: 5 }).fontSize(fontSize).fillColor(remittanceTitleColor).text('Transfer status:', startX, doc.y, { lineBreak: false }).fillColor(valueColor).text(orderStatusText, startX + 200, doc.y, { lineGap: 5 }).fontSize(fontSize).fillColor(remittanceTitleColor).text('Created time:', startX, doc.y, { lineBreak: false }).fillColor(valueColor).text(dayjs(order.createdAt.valueOf()).format('YYYY-MM-DD HH:mm:ss'),startX + 200,doc.y,{ lineGap: 5 },).fontSize(fontSize).fillColor(remittanceTitleColor).text('Update time:', startX, doc.y, { lineBreak: false }).fillColor(valueColor).text(dayjs(order.updatedAt.valueOf()).format('YYYY-MM-DD HH:mm:ss'),startX + 200,doc.y,{ lineGap: 5 },).rect(startX, doc.y + 10, sideWidth, sideHeight).fill(linceColor).fontSize(fontSize).fillColor(remittanceTitleColor).text('Order total amount:', startX, doc.y + 20, { lineBreak: false }).fillColor(valueColor).text(`$ ${getFloatNumber(getConvertAmount(order.totalAmount))}`,startX + 200,doc.y,{lineGap: 5,},).fontSize(fontSize).fillColor(remittanceTitleColor).text('SOMO service fee:', startX, doc.y, {lineBreak: false,}).fillColor(remittanceTitleColor).text(`$ ${getFloatNumber(getConvertAmount(order.somoServiceFee))}`,startX + 200,doc.y,{lineGap: 5,strike: true,},).fontSize(fontSize).fillColor(remittanceTitleColor).text('Transfer fee:', startX, doc.y, { lineBreak: false }).fillColor(valueColor).text(`$ ${getFloatNumber(getConvertAmount(transferFee))}`,startX + 200,doc.y,{lineGap: 5,},).fontSize(fontSize).fillColor(remittanceTitleColor).text('Remittance amount:', startX, doc.y, { lineBreak: false }).fillColor(valueColor).text(`$ ${getFloatNumber(getConvertAmount(remittanceAmount))}`,startX + 200,doc.y,{lineGap: 5,},).rect(startX, doc.y + 10, sideWidth, 60).fill('#F2F3F7').fontSize(transferDetailTitleSize).fillColor('#171A1F').font(`${__dirname}/Montserrat-Bold.ttf`).text('Associated with the order', transferDetailX, doc.y + 30, {lineBreak: false,baseline: 'top',}).text(' ', { lineGap: 10 }).font(`${__dirname}/Montserrat-Regular.ttf`);for (let i = 0; i < order.transactionList.length; i++) {const item = order.transactionList[i];const itemTransferFee = order.withdrawalMethod.paypalEnabled? item.paypalTransferFee: item.bankTransferFee;doc.text(' ', { lineGap: 10 });doc.fontSize(fontSize).fillColor(remittanceTitleColor).text('Brand:', startX, doc.y, { paragraphGap: -20 }).fillColor(valueColor).text(item.brandName, startX + 200, doc.y, { lineGap: 8 });doc.fontSize(fontSize).fillColor(remittanceTitleColor).text('Campaign:', startX, doc.y, { paragraphGap: -20 }).fillColor(valueColor).text(item.campaignTitle, startX + 200, doc.y, { lineGap: 8 });doc.fontSize(fontSize).fillColor(remittanceTitleColor).text('Order ID:', startX, doc.y, { paragraphGap: -20 }).fillColor(valueColor).text(item.orderID, startX + 200, doc.y, { lineGap: 8 });doc.fontSize(fontSize).fillColor(remittanceTitleColor).text('Oder price:', startX, doc.y, { paragraphGap: -20 }).fillColor(valueColor).text(`$ ${getFloatNumber(getConvertAmount(item.amount))}`,startX + 200,doc.y,{lineGap: 8,},);doc.fontSize(fontSize).fillColor(remittanceTitleColor).text('SOMO service fee:', startX, doc.y, {paragraphGap: -20,}).fillColor(remittanceTitleColor).text(`$ ${getFloatNumber(getConvertAmount(item.somoServiceFee))}`,startX + 200,doc.y,{lineGap: 8,strike: true,},);doc.fontSize(fontSize).fillColor(remittanceTitleColor).text('Transfer fee:', startX, doc.y, { paragraphGap: -20 }).fillColor(valueColor).text(`$ ${getFloatNumber(getConvertAmount(itemTransferFee))}`,startX + 200,doc.y,{lineGap: 8,},);doc.rect(startX, doc.y + 20, sideWidth, sideHeight).fill(linceColor);}doc.end();const buffers = [];// 使用pdfkit的监听方法收集buffer,便于后续文件处理doc.on('data', buffers.push.bind(buffers));doc.on('end', () => {const pdfData = Buffer.concat(buffers);return resolve(pdfData);});});fs.writeFileSync(`${__dirname}/file.pdf`, pdfBuffer);
};
method();
相关文章:

NodeJs导出PDF
(优于别人,并不高贵,真正的高贵应该是优于过去的自己。——海明威) 场景 根据订单参数生成账单PDF 结果 示例代码 /* eslint-disable no-unused-vars */ /* eslint-disable no-undef */ /* eslint-disable complexity */ const…...

内核编译机制
inux内核的编译主要过程:配置、编译、安装。 配置主要由Kconfig提供图形界面完成 编译主要基于Kbuild编译系统,执行make完成编译 安装主要也是基于Kbuild提供的脚本,然后执行make完成安装 Kconfig Kconfig用于内核的配置,mak…...

机器人TF坐标系变换与一些可视化工具的应用
TF坐标在ROS中是一个非常重要的概念,因为机器人在做日常操作任务的时候,对于其所在位置和朝向是需要时刻知道的,而机器人是由很多节点组成的协同任务,对于每个部件,我们需要知道它的位姿(位置和朝向),这使得…...

c++ 友元 运算符重载详解
友元 c是面向对象的,目的之一:封装 封装: 优点之一,就是安全。 缺点:在某些特殊的场合,不是很方便。 华为与IBM 40亿的咨询故事 IBM需要对华为各级部门做深度咨询分析, 为了提高咨询效率&a…...

DataWhale 机器学习夏令营第三期
DataWhale 机器学习夏令营第二期 学习记录一 (2023.08.18)1.赛题理解2.缺失值分析3. 简单特征提取4. 数据可视化离散变量离散变量分布分析 DataWhale 机器学习夏令营第三期 ——用户新增预测挑战赛 学习记录一 (2023.08.18) 已跑通baseline,换为lightgbm基线&#…...

回归预测 | MATLAB实现BES-LSSVM秃鹰搜索算法优化最小二乘支持向量机多输入单输出回归预测(多指标,多图)
回归预测 | MATLAB实现BES-LSSVM秃鹰搜索算法优化最小二乘支持向量机多输入单输出回归预测(多指标,多图) 目录 回归预测 | MATLAB实现BES-LSSVM秃鹰搜索算法优化最小二乘支持向量机多输入单输出回归预测(多指标,多图&a…...

python分析实战(4)--获取某音热榜
1. 分析需求 打开某音热搜,选择需要获取的热榜如图 查找包含热搜内容的接口返回如图 将url地址保存 2. 开发 定义请求头 headers {Cookie: 自己的cookie,Accept: application/json, text/plain, */*,Accept-Encoding: gzip, deflate,Host: www.douyin.com,…...
Java根据List集合中的一个字段对集合进行去重
利用HashSet 创建了一个HashSet用于存储唯一的字段值,并创建了一个新的列表uniqueList用于存储去重后的对象。遍历原始列表时,如果字段值未在HashSet中出现过,则将其添加到HashSet和uniqueList中。 List<Person> originalList new Ar…...
(AtCoder Beginner Contest 315)
A.直接模拟即可 import random import sys import os import math from collections import Counter, defaultdict, deque from functools import lru_cache, reduce from itertools import accumulate, combinations, permutations from heapq import nsmallest, nlargest, h…...

API 接口选择那个?RESTful、GraphQL、gRPC、WebSocket、Webhook
大家好,我是比特桃。目前我们的生活紧紧地被大量互联网服务所包围,互联网上每天都有数百亿次API调用。API 是两个设备相互通讯的一种方式,人们在手机上每次指尖的悦动,背后都是 API 接口的调用。 本文将列举常见的一些 API 接口&…...

「Python|音视频处理|环境准备」如何在Windows系统下安装并配置音视频处理工具FFmpeg
本文主要介绍如何在Windows系统下安装并配置音视频处理工具FFmpeg,方便使用python进行音视频相关的下载或编辑处理。 文章目录 一、下载软件二、解压并配置三、验证安装 一、下载软件 首先要去 ffmpeg官网 下载软件包 由于上面直接下载的按钮是.tar.xz格式的。为了…...

软考高级架构师下篇-12层次式架构设计理论与实践
目录 1. 考情分析2. 层次式体系结构概述3. 表现层框架设计4. 中间层框架设计5. 数据访问层设计6. 数据架构规划与设计7. 物联网层次架构设计8. 前文回顾1. 考情分析 根据考试大纲,层次式架构设计理论与实践知识点会涉及单选题型(约占2~5分)和案例题(25分),本小时内容偏重于方…...
234. 回文链表
234. 回文链表 给你一个单链表的头节点 head ,请你判断该链表是否为回文链表。如果是,返回 true ;否则,返回 false 。 /*** Definition for singly-linked list.* struct ListNode {* int val;* ListNode *next;* L…...

LInux之例行工作
目录 场景 单一执行例行任务 --- at(一次性) 安装 命令详解 语法格式 参数及作用 时间格式 案例 at命令执行过程分析 循环执行的例行性任务--crontab(周期性) crontd服务安装 linux 任务调度的工分类 crontab工作过程…...
C++,从“hello world“开始
一、"hello world" #inclue <iostream>using namespace std;int main() {cout << "hello world" << endl;return 0; } 1.1 #include:预处理标识 1.2 <iostream>:输入输出流类所在头文件 1.2.1 istream&a…...

/root/.ssh/config line 2: Bad protocol 2 host key algorithms ‘+ssh-rsa‘.
文章目录 1、问题2、查看openssh版本3、解决问题4、重新生成密钥5、查看是否可连接工蜂 1、问题 ssh访问工蜂报错: [rootlocalhost .ssh]# ssh -T gitgit.code.tencent.com /root/.ssh/config line 2: Bad protocol 2 host key algorithms ‘ssh-rsa’. 2、查看o…...

mac m1上系统内录内部声音的方法/无需安装Blackhole
总所周知,m1的mac不能录制桌面音频,obsstudio都不行。 最快的解决方法就是下载飞书: 登陆后新建直播/视频会议: 共享的时候选择下面的两个钩上去就好了...
数字人学习目录
数字人学习目录 百度PaddlePaddleHub图像风格迁移模型pp-tinypose模型 PaddleGANPaddleLitePaddleDetectionPP-TinyPose 人体骨骼关键点识别 PaddleSpeechVisualDLPaddleBobo TransformerWav2LibCLIPFFMpeg模型库数据集学习天地PythonJupyter Notebook Unity3DUE 百度Paddle P…...

PHP 房产网站系统Dreamweaver开发mysql数据库web结构php编程计算机网页项目
一、源码特点 PHP 房产网站系统是一套完善的WEB设计系统,对理解php编程开发语言有帮助,系统具有完整的源代码和数据库,系统主要采用B/S模式开发。 源码 https://download.csdn.net/download/qq_41221322/88233553 论文 https://download…...

0基础入门代码审计-2 Fortify初探
0x01 序言 目前又加入一位新童鞋了,最近将会再加入cs相关的专栏,都是以基础为主,毕竟太复杂的东西,能看懂的人太少。 0x02 准备工具 1、Fortify 2、需要审计的源码 0x03 Fortify的简单使用 1、 1、在开始菜单栏中找到Audit Wo…...

linux之kylin系统nginx的安装
一、nginx的作用 1.可做高性能的web服务器 直接处理静态资源(HTML/CSS/图片等),响应速度远超传统服务器类似apache支持高并发连接 2.反向代理服务器 隐藏后端服务器IP地址,提高安全性 3.负载均衡服务器 支持多种策略分发流量…...

大话软工笔记—需求分析概述
需求分析,就是要对需求调研收集到的资料信息逐个地进行拆分、研究,从大量的不确定“需求”中确定出哪些需求最终要转换为确定的“功能需求”。 需求分析的作用非常重要,后续设计的依据主要来自于需求分析的成果,包括: 项目的目的…...

云启出海,智联未来|阿里云网络「企业出海」系列客户沙龙上海站圆满落地
借阿里云中企出海大会的东风,以**「云启出海,智联未来|打造安全可靠的出海云网络引擎」为主题的阿里云企业出海客户沙龙云网络&安全专场于5.28日下午在上海顺利举办,现场吸引了来自携程、小红书、米哈游、哔哩哔哩、波克城市、…...

vscode(仍待补充)
写于2025 6.9 主包将加入vscode这个更权威的圈子 vscode的基本使用 侧边栏 vscode还能连接ssh? debug时使用的launch文件 1.task.json {"tasks": [{"type": "cppbuild","label": "C/C: gcc.exe 生成活动文件"…...

关于nvm与node.js
1 安装nvm 安装过程中手动修改 nvm的安装路径, 以及修改 通过nvm安装node后正在使用的node的存放目录【这句话可能难以理解,但接着往下看你就了然了】 2 修改nvm中settings.txt文件配置 nvm安装成功后,通常在该文件中会出现以下配置&…...

UE5 学习系列(三)创建和移动物体
这篇博客是该系列的第三篇,是在之前两篇博客的基础上展开,主要介绍如何在操作界面中创建和拖动物体,这篇博客跟随的视频链接如下: B 站视频:s03-创建和移动物体 如果你不打算开之前的博客并且对UE5 比较熟的话按照以…...

HTML 列表、表格、表单
1 列表标签 作用:布局内容排列整齐的区域 列表分类:无序列表、有序列表、定义列表。 例如: 1.1 无序列表 标签:ul 嵌套 li,ul是无序列表,li是列表条目。 注意事项: ul 标签里面只能包裹 li…...
渲染学进阶内容——模型
最近在写模组的时候发现渲染器里面离不开模型的定义,在渲染的第二篇文章中简单的讲解了一下关于模型部分的内容,其实不管是方块还是方块实体,都离不开模型的内容 🧱 一、CubeListBuilder 功能解析 CubeListBuilder 是 Minecraft Java 版模型系统的核心构建器,用于动态创…...

UR 协作机器人「三剑客」:精密轻量担当(UR7e)、全能协作主力(UR12e)、重型任务专家(UR15)
UR协作机器人正以其卓越性能在现代制造业自动化中扮演重要角色。UR7e、UR12e和UR15通过创新技术和精准设计满足了不同行业的多样化需求。其中,UR15以其速度、精度及人工智能准备能力成为自动化领域的重要突破。UR7e和UR12e则在负载规格和市场定位上不断优化…...
python报错No module named ‘tensorflow.keras‘
是由于不同版本的tensorflow下的keras所在的路径不同,结合所安装的tensorflow的目录结构修改from语句即可。 原语句: from tensorflow.keras.layers import Conv1D, MaxPooling1D, LSTM, Dense 修改后: from tensorflow.python.keras.lay…...