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();

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/78435.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【bug】Unity无法创建项目

bug UnityHub无法创建项目 UnityHub无法创建项目 出现的问题&#xff1a;在创建新项目时弹出来一个 无法创建项目 尝试的方法&#xff1a; 刷新许可证 ❌没用退出账号重新登陆 ❌没用重启电脑 ❌没用 最后发现是什么问题呢&#xff1f; 2021.3.3这个版本我之前在资源管理器中…

Arcgis连续数据的分类(求不同值域的面积)

问题描述&#xff1a;如果得到的一个连续的影响数值数据&#xff0c;但是我们想求取某一段值域的面积占比&#xff0c;需要进行以下操作&#xff1a; 1.按照数值重分类&#xff0c;将某段数值变成一个类别 2.栅格转矢量&#xff0c;再求取面积

Kafka 集群搭建过程

前言 跟着尚硅谷海哥文档搭建的Kafka集群环境&#xff0c;在此记录一下&#xff0c;侵删 注意&#xff1a;博主在服务器上搭建环境的时候使用的是一个服务器&#xff0c;所以这篇博客可能会出现一些xsync分发到其他服务器时候的错误&#xff0c;如果你在搭建的过程中出现了错…

【脚踢数据结构】图(纯享版)

(꒪ꇴ꒪ )&#xff0c;Hello我是祐言QAQ我的博客主页&#xff1a;C/C语言&#xff0c;Linux基础&#xff0c;ARM开发板&#xff0c;软件配置等领域博主&#x1f30d;快上&#x1f698;&#xff0c;一起学习&#xff0c;让我们成为一个强大的攻城狮&#xff01;送给自己和读者的…

能耗监测管理系统在产业园区中的应用分析

摘要&#xff1a;随着电信公司企业级智能化办公系统的不断迭代优化及财务辅助系统与各个业务系统之间的壁垒不断打破、融合&#xff0c;能耗监测管理系统在企业生产运行管理中&#xff0c;为实现企业能耗数据归集&#xff0c;“节能减排、降本增效”提供了系统支撑及可行性保障…

Html+JavaScript实现手写签名

前言 Hello各位&#xff0c;本葡萄又来啦&#xff0c;今天遇到的场景是这样的&#xff1a;在日常业务流程中&#xff0c;经常需要某一流程环节中相关责任人员进行审批签字&#xff0c;早期许多公司为了省事就直接会把这位负责人的签名以键盘打字&#xff08;楷体&#xff09;的…

数据结构—散列表的查找

7.4散列表的查找 7.4.1散列表的基本概念 基本思想&#xff1a;记录的存储位置域关键字之间存在对应关系 ​ 对应关系——hash函数 ​ Loc&#xff08;i&#xff09; H&#xff08;keyi&#xff09; 如何查找&#xff1a; 根据散列函数 H(key) k 查找key9&#xff0c;则访…

easyx图形库基础4:贪吃蛇

贪吃蛇 一实现贪吃蛇&#xff1a;1.绘制网格&#xff1a;1.绘制蛇&#xff1a;3.控制蛇的默认移动向右&#xff1a;4.控制蛇的移动方向&#xff1a;5.生成食物6.判断蛇吃到食物并且长大。7.判断游戏结束&#xff1a;8.重置函数&#xff1a; 二整体代码&#xff1a; 一实现贪吃蛇…

springboot里 运用 easyexcel 导出

引入pom <dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>2.2.6</version> </dependency>运用 import com.alibaba.excel.EasyExcel; import org.springframework.stereotype.Contr…

【算法篇C++实现】常见排序算法

文章目录 &#x1f680;一、选择排序&#x1f680;二、冒泡排序&#x1f680;三、插入排序&#x1f680;四、希尔排序&#x1f680;五、堆排序&#x1f680;六、归并排序&#x1f680;七、快速排序⛳总结&#xff1a; &#x1f680;一、选择排序 算法精炼每趟从待排序的记录中…

Ceph分布式存储系统优化分析

Ceph支持多种存储访问接口&#xff0c;现有的多种性能测试工具都可用于Ceph的性能测试&#xff0c;如测试块接口性能的fio&#xff0c;iometer等&#xff1b;测试CephFS接口的filebench&#xff0c;fio等;测试对象接口的cosbench等。Ceph有专用的基准测试集CBT&#xff0c;其包…

web实现酷炫的canvas粒子动画背景

文章目录 前言一、particle-bg1. git地址&#xff1a;2. 安装3. 使用4. 完整demo 二、tsParticles1. 源码地址&#xff1a;2. 安装3. 引入4. 使用5. 几个例子5.1 ts粒子五彩纸屑烟花5.2 多粒子产卵器-用tsParticles制作5.3 ts粒子鼠标吸引力5.4 粒子烟花 源码地址完结 前言 粒…

【RP2040】香瓜树莓派RP2040之自定义的短按、双击、长按按键

本文最后修改时间&#xff1a;2022年09月15日 11:02 一、本节简介 本节介绍如何编写一个可以自己选择引脚的短按、双击、长按三种方式的按键驱动。 二、实验平台 1、硬件平台 1&#xff09;树莓派pico开发板 ①树莓派pico开发板*2 ②micro usb数据线*2 2&#xff09;电脑…

【运维】linkis安装dss保姆级教程与踩坑实践

文章目录 一. 安装准备二. 创建用户三. 准备安装包四. 修改配置1. 修改config.sh2. 修改db.sh 五、安装和使用1. 执行安装脚本2. 启动服务3. 查看验证是否成功 六. 报错处理报错一&#xff1a;The user is not logged in报错二&#xff1a;dss接口报错报错三&#xff1a;执行没…

IDEA常用工具配置

IDEA常用工具&配置 如果发现插件市场用不了&#xff0c;可以设置Http Proxy&#xff0c;在该界面上点击”Check connection“并输入的地址&#xff1a;https://plugins.jetbrains.com/ 。 一、常用插件 1、MybatisX Mybaits Plus插件&#xff0c;支持java与xml互转 2、F…

TCP/IP协议组

TCP/IP通信协议是目前最完整、使用最广泛的通信协议。它的魅力在于可使不同硬件结构、不同操作系统的计算机相互通信。TCP/IP协议既可用于广域网&#xff0c;也可用于局域网&#xff0c;它是Internet/Intranet的基石。TCP/IP通信协议事实上是一组协议。 TCP/IP协议可分为5层也可…

日志系统——日志格式化模块设计

一&#xff0c;模块主要成员 该模块的主要作用是对日志消息进行格式化&#xff0c;将日志消息组织成制定格式的字符串。 该模块主要成员有两个&#xff1a;1.格式化字符串。 2.格式化子项数组 1.1 格式化字符串 格式化字符串的主要功能是保存日志输出的格式字符串。其格式化字…

机器学习赋能乳腺癌预测:如何使用贝叶斯分级进行精确诊断?

一、引言 乳腺癌是女性最常见的恶性肿瘤之一&#xff0c;也会发生在男性身上。每年全球有数百万人被诊断出乳腺癌&#xff0c;对患者的生活和健康造成了巨大的影响。早期的乳腺癌检测和准确的诊断对于提高治疗的成功率至关重要。然而&#xff0c;乳腺癌的早期诊断面临着许多挑战…

大语言模型与语义搜索;钉钉个人版启动内测,提供多项AI服务

&#x1f989; AI新闻 &#x1f680; 钉钉个人版启动内测&#xff0c;提供多项AI服务 摘要&#xff1a;钉钉个人版正式开始内测&#xff0c;面向小团队、个人用户、高校大学生等人群。该版本具有AI为核心的功能&#xff0c;包括文生文AI、文生图AI和角色化对话等。用户可通过…

整理mongodb文档:find方法查询数据

个人博客 整理mongodb文档:find方法查询数据 求关注&#xff0c;求批评&#xff0c;求指出&#xff0c;如果哪儿不清晰&#xff0c;请指出来&#xff0c;谢谢 文章概叙 如题&#xff0c;本文讲的是如何用find查询数据&#xff0c;如何在数组、字段、对象中查询&#xff0c;以…