当前位置: 首页 > news >正文

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

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

内核编译机制

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

机器人TF坐标系变换与一些可视化工具的应用

TF坐标在ROS中是一个非常重要的概念&#xff0c;因为机器人在做日常操作任务的时候&#xff0c;对于其所在位置和朝向是需要时刻知道的&#xff0c;而机器人是由很多节点组成的协同任务&#xff0c;对于每个部件&#xff0c;我们需要知道它的位姿(位置和朝向)&#xff0c;这使得…...

c++ 友元 运算符重载详解

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

DataWhale 机器学习夏令营第三期

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

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

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

python分析实战(4)--获取某音热榜

1. 分析需求 打开某音热搜&#xff0c;选择需要获取的热榜如图 查找包含热搜内容的接口返回如图 将url地址保存 2. 开发 定义请求头 headers {Cookie: 自己的cookie,Accept: application/json, text/plain, */*,Accept-Encoding: gzip, deflate,Host: www.douyin.com,…...

Java根据List集合中的一个字段对集合进行去重

利用HashSet 创建了一个HashSet用于存储唯一的字段值&#xff0c;并创建了一个新的列表uniqueList用于存储去重后的对象。遍历原始列表时&#xff0c;如果字段值未在HashSet中出现过&#xff0c;则将其添加到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

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

「Python|音视频处理|环境准备」如何在Windows系统下安装并配置音视频处理工具FFmpeg

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

软考高级架构师下篇-12层次式架构设计理论与实践

目录 1. 考情分析2. 层次式体系结构概述3. 表现层框架设计4. 中间层框架设计5. 数据访问层设计6. 数据架构规划与设计7. 物联网层次架构设计8. 前文回顾1. 考情分析 根据考试大纲,层次式架构设计理论与实践知识点会涉及单选题型(约占2~5分)和案例题(25分),本小时内容偏重于方…...

234. 回文链表

234. 回文链表 给你一个单链表的头节点 head &#xff0c;请你判断该链表是否为回文链表。如果是&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。 /*** Definition for singly-linked list.* struct ListNode {* int val;* ListNode *next;* L…...

LInux之例行工作

目录 场景 单一执行例行任务 --- at&#xff08;一次性&#xff09; 安装 命令详解 语法格式 参数及作用 时间格式 案例 at命令执行过程分析 循环执行的例行性任务--crontab&#xff08;周期性&#xff09; crontd服务安装 linux 任务调度的工分类 crontab工作过程…...

C++,从“hello world“开始

一、"hello world" #inclue <iostream>using namespace std;int main() {cout << "hello world" << endl;return 0; } 1.1 #include&#xff1a;预处理标识 1.2 <iostream>&#xff1a;输入输出流类所在头文件 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访问工蜂报错&#xff1a; [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

总所周知&#xff0c;m1的mac不能录制桌面音频&#xff0c;obsstudio都不行。 最快的解决方法就是下载飞书&#xff1a; 登陆后新建直播/视频会议&#xff1a; 共享的时候选择下面的两个钩上去就好了...

数字人学习目录

数字人学习目录 百度PaddlePaddleHub图像风格迁移模型pp-tinypose模型 PaddleGANPaddleLitePaddleDetectionPP-TinyPose 人体骨骼关键点识别 PaddleSpeechVisualDLPaddleBobo TransformerWav2LibCLIPFFMpeg模型库数据集学习天地PythonJupyter Notebook Unity3DUE 百度Paddle P…...

PHP 房产网站系统Dreamweaver开发mysql数据库web结构php编程计算机网页项目

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

0基础入门代码审计-2 Fortify初探

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

springboot 百货中心供应链管理系统小程序

一、前言 随着我国经济迅速发展&#xff0c;人们对手机的需求越来越大&#xff0c;各种手机软件也都在被广泛应用&#xff0c;但是对于手机进行数据信息管理&#xff0c;对于手机的各种软件也是备受用户的喜爱&#xff0c;百货中心供应链管理系统被用户普遍使用&#xff0c;为方…...

RocketMQ延迟消息机制

两种延迟消息 RocketMQ中提供了两种延迟消息机制 指定固定的延迟级别 通过在Message中设定一个MessageDelayLevel参数&#xff0c;对应18个预设的延迟级别指定时间点的延迟级别 通过在Message中设定一个DeliverTimeMS指定一个Long类型表示的具体时间点。到了时间点后&#xf…...

椭圆曲线密码学(ECC)

一、ECC算法概述 椭圆曲线密码学&#xff08;Elliptic Curve Cryptography&#xff09;是基于椭圆曲线数学理论的公钥密码系统&#xff0c;由Neal Koblitz和Victor Miller在1985年独立提出。相比RSA&#xff0c;ECC在相同安全强度下密钥更短&#xff08;256位ECC ≈ 3072位RSA…...

visual studio 2022更改主题为深色

visual studio 2022更改主题为深色 点击visual studio 上方的 工具-> 选项 在选项窗口中&#xff0c;选择 环境 -> 常规 &#xff0c;将其中的颜色主题改成深色 点击确定&#xff0c;更改完成...

Neo4j 集群管理:原理、技术与最佳实践深度解析

Neo4j 的集群技术是其企业级高可用性、可扩展性和容错能力的核心。通过深入分析官方文档,本文将系统阐述其集群管理的核心原理、关键技术、实用技巧和行业最佳实践。 Neo4j 的 Causal Clustering 架构提供了一个强大而灵活的基石,用于构建高可用、可扩展且一致的图数据库服务…...

ServerTrust 并非唯一

NSURLAuthenticationMethodServerTrust 只是 authenticationMethod 的冰山一角 要理解 NSURLAuthenticationMethodServerTrust, 首先要明白它只是 authenticationMethod 的选项之一, 并非唯一 1 先厘清概念 点说明authenticationMethodURLAuthenticationChallenge.protectionS…...

蓝桥杯3498 01串的熵

问题描述 对于一个长度为 23333333的 01 串, 如果其信息熵为 11625907.5798&#xff0c; 且 0 出现次数比 1 少, 那么这个 01 串中 0 出现了多少次? #include<iostream> #include<cmath> using namespace std;int n 23333333;int main() {//枚举 0 出现的次数//因…...

接口自动化测试:HttpRunner基础

相关文档 HttpRunner V3.x中文文档 HttpRunner 用户指南 使用HttpRunner 3.x实现接口自动化测试 HttpRunner介绍 HttpRunner 是一个开源的 API 测试工具&#xff0c;支持 HTTP(S)/HTTP2/WebSocket/RPC 等网络协议&#xff0c;涵盖接口测试、性能测试、数字体验监测等测试类型…...

c# 局部函数 定义、功能与示例

C# 局部函数&#xff1a;定义、功能与示例 1. 定义与功能 局部函数&#xff08;Local Function&#xff09;是嵌套在另一个方法内部的私有方法&#xff0c;仅在包含它的方法内可见。 • 作用&#xff1a;封装仅用于当前方法的逻辑&#xff0c;避免污染类作用域&#xff0c;提升…...

Java求职者面试指南:Spring、Spring Boot、Spring MVC与MyBatis技术解析

Java求职者面试指南&#xff1a;Spring、Spring Boot、Spring MVC与MyBatis技术解析 一、第一轮基础概念问题 1. Spring框架的核心容器是什么&#xff1f;它的作用是什么&#xff1f; Spring框架的核心容器是IoC&#xff08;控制反转&#xff09;容器。它的主要作用是管理对…...