NodeJs导出PDF

(优于别人,并不高贵,真正的高贵应该是优于过去的自己。------海明威)

场景

根据订单参数生成账单PDF

结果

示例代码

javascript 复制代码
/* 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();
相关推荐
一个处女座的程序猿1 天前
LLMs之PDF:zeroX(一款PDF到Markdown 的视觉模型转换工具)的简介、安装和使用方法、案例应用之详细攻略
pdf·markdown·zerox
Dxy12393102161 天前
python下载pdf
数据库·python·pdf
周亚鑫1 天前
vue3 pdf base64转成文件流打开
前端·javascript·pdf
一名技术极客1 天前
Vue2 doc、excel、pdf、ppt、txt、图片以及视频等在线预览
pdf·powerpoint·excel·文件在线预览
S. Dylan2 天前
Edge浏览器打开PDF无法显示电子签章
edge·pdf
一马平川的大草原2 天前
如何基于pdf2image实现pdf批量转换为图片
计算机视觉·pdf·文件拆分
m0_594526302 天前
Python批量合并多个PDF
java·python·pdf
hairenjing11232 天前
将图片添加到 PDF 的 5 种方法
pdf
✿゚卡笨卡2 天前
pdf 添加页眉页脚,获取前五页
java·pdf
blegn2 天前
PDF编辑工具Adobe Acrobat DC 2023安装教程(附安装包)
pdf·办公软件·office