برنامه نویسی

نحوه خودکارسازی اسناد PDF با React و TypeScript

یکی از مشکلی که بسیاری از مشاغل در بعضی از مواقع با آن روبرو خواهند شد ، تولید PDF است – موارد ، گزارش ها ، رسیدها یا فرم ها ، برای ذکر برخی از آنها. از نظر تاریخی ، این دردناک بوده است: Word و Latex برای الگوهای زیادی فراهم نمی کنند ، و گزینه های دیگر راه حل ها یا راه حل های HTML/CSS شکننده هستند یا راه حل هایی مانند WKHTMLTOPDF یا WEASYPRINT که فقط از زیر مجموعه CSS پشتیبانی می کنند.

اما اگر بتوانیم PDF ها را مانند اجزای React درمان کنیم ، چه می شود؟ HTMLDOCS یک کتابخانه جدید است که DX بزرگ وب مدرن را به اسناد ساختمانی می رساند ، مشابه آنچه که ایمیل React برای ایمیل انجام داد.

آنچه می خواهیم بسازیم

در این راهنما ، ما یاد می گیریم:

  • یک پروژه React + TypeScript + tailwindcss را تنظیم کنید
  • یک الگوی سند فاکتور بسازید
  • برای پیش نمایش و ارائه آن به PDF از htmldocs استفاده کنید
  • در غرفه های پویا مانند جزئیات مشتری و موارد خط عبور کنید
  • به صورت اختیاری الگوی خود را به API منتشر کنید

ابزارهایی که ما استفاده خواهیم کرد

  • واکنش و نوع برای اجزای سازنده و نوع ایمنی
  • tailwindcss برای یک ظاهر طراحی شده
  • htmldocs برای ارائه سند

تنظیم پروژه

اگر تازه شروع می کنید ، ساده ترین راه برای داربست یک پروژه جدید است

npx htmldocs@latest init
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

با این کار یک پروژه آماده برای رفتن با برخی از tepmlates از پیش ساخته شده تنظیم می شود.

برای این آموزش ، فرض خواهیم کرد که قبلاً یک پروژه موجود داریم و می خواهیم اضافه کنیم htmldocs به آن ابتدا بسته ها را به صورت دستی نصب خواهیم کرد:

npm install htmldocs @htmldocs/react @htmldocs/render
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

سپس ، شما می خواهید ایجاد کنید documents پوشه برای الگوهای شما.

mkdir documents
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

import { Document } from "@htmldocs/react";
import "~/index.css"; // import global TailwindCSS file

function Invoice() {
    return (
      <Document size="A4" orientation="portrait">
        <h1 className="text-xl font-bold">Invoice starterh1>
      Document>
    )
};

export default Invoice;
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

در داخل پوشه جدید ، یک فایل جدید به نام ایجاد کنید Invoice.tsx:

همچنین باید این پوشه را به tsconfig خود اضافه کنید:

// tsconfig.json
{
  "include": [..., "documents"],
}
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

و همچنین tailwind.config.js شما:

/** @type {import('tailwindcss').Config} */
module.exports = {
  //... other config options
  content: [..., "./documents/**/*.{js,jsx,ts,tsx}"],
};
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

سرانجام ، شما می خواهید یک اسکریپت جدید به بسته خود اضافه کنید.

// package.json
{
  ...
  "scripts": {
    "docs:dev": "npx htmldocs@latest dev"
  },
}
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

حالا ، وقتی دویدید npm run docs:dev، شما باید یک سرور پیش نمایش زنده را با سند جدید خود مشاهده کنید.

سرور پیش نمایش زنده htmldocs

اضافه کردن داده های پویا

در htmldocs ، داده های پویا به عنوان غرفه به مؤلفه منتقل می شوند. بیایید الگوی استارت ما را برای به دست آوردن جزئیات مشتری و همچنین مجموعه ای از خدمات تغییر دهیم. ما همچنین طرح را تازه می کنیم و برخی از محاسبات قیمت را اضافه خواهیم کرد.

import { Document, Head, Page, Footer } from "@htmldocs/react";
import "../src/styles/tailwind.css"; // import global TailwindCSS file

interface Service {
  name: string;
  description?: string;
  quantity: number;
  rate: number;
}

interface InvoiceProps {
  customerName: string;
  customerEmail: string;
  services: Service[];
}

function Invoice({ customerName, customerEmail, services }: InvoiceProps) {
    const subtotal = services.reduce(
        (acc, service) => acc + service.quantity * service.rate,
        0
    );
    const taxRate = 0.1; // 10% tax
    const tax = subtotal * taxRate;
    const total = subtotal + tax;

    return (
        <Document size="A4" orientation="portrait">
            <Head>
                <title>Invoice for {customerName}title>
            Head>
            <Page className="p-8">
                <div className="flex justify-between items-start mb-8">
                    <div>
                        <h1 className="text-2xl font-bold my-0">INVOICEh1>
                        <p className="text-gray-600">{new Date().toLocaleDateString()}p>
                    div>
                    <div className="text-right">
                        <p className="font-medium">{customerName}p>
                        <p className="text-gray-600">{customerEmail}p>
                    div>
                div>

                <table className="w-full mb-8">
                    <thead>
                        <tr className="border-b">
                            <th className="text-left py-2">Serviceth>
                            <th className="text-right py-2">Qtyth>
                            <th className="text-right py-2">Rateth>
                            <th className="text-right py-2">Amountth>
                        tr>
                    thead>
                    <tbody>
                        {services.map((service, index) => (
                            <tr key={index} className="border-b">
                                <td className="py-2">
                                    <div>
                                        <p className="font-medium">{service.name}p>
                                        {service.description && (
                                            <p className="text-sm text-gray-600">{service.description}p>
                                        )}
                                    div>
                                td>
                                <td className="text-right py-2">{service.quantity}td>
                                <td className="text-right py-2">${service.rate.toFixed(2)}td>
                                <td className="text-right py-2">
                                    ${(service.quantity * service.rate).toFixed(2)}
                                td>
                            tr>
                        ))}
                    tbody>
                table>

                <div className="flex flex-col items-end gap-2">
                    <div className="flex justify-between w-48">
                        <span>Subtotal:span>
                        <span>${subtotal.toFixed(2)}span>
                    div>
                    <div className="flex justify-between w-48">
                        <span>Tax ({(taxRate * 100)}%):span>
                        <span>${tax.toFixed(2)}span>
                    div>
                    <div className="flex justify-between w-48 font-bold border-t pt-2">
                        <span>Total:span>
                        <span>${total.toFixed(2)}span>
                    div>
                div>

                <Footer 
                    position="bottom-center"
                    className="text-center text-gray-600"
                    marginBoxStyles={{
                        marginBottom: "0.5in",
                    }}
                >
                    {() => (
                        <p>Thank you for your business!p>
                    )}
                Footer>
            Page>
        Document>
    );
}

Invoice.PreviewProps = {
    customerName: "Acme Corp",
    customerEmail: "billing@acmecorp.com",
    services: [
        { name: "Web Design", description: "Homepage redesign", quantity: 1, rate: 1500 },
        { name: "Consulting", description: "Technical architecture review", quantity: 2, rate: 800 },
    ],
};

export default Invoice;

حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

Invoice.PreviewProps به تنظیم پیش فرض های پیش فرض روی سند برای ارائه کمک می کند. این یک ویژگی مورد نیاز برای اطمینان از اینکه سند شما قادر به تهیه صحیح است.

اکنون سند شما باید به این شکل باشد:

الگوی فاکتور

برای ایجاد دستی یک سندی بر اساس این الگوی ، می توانید روی “پر و تولید” کلیک کنید که برای پر کردن جزئیات فرم ایجاد می شود

فرم را پر و تولید کنید

انتشار به یک API

HTMLDOCS همچنین یک سرویس ابری را ارائه می دهد که می توانید اسناد را منتشر کنید تا آنها را در پشت یک API REST ساده قرار دهید.

قبل از انتشار ، باید یک شناسه سند را به پرونده اضافه کنید:

// rest of Invoice.tsx

Invoice.PreviewProps = {
    customerName: "Acme Corp",
    customerEmail: "billing@acmecorp.com",
    services: [
        { name: "Web Design", description: "Homepage redesign", quantity: 1, rate: 1500 },
        { name: "Consulting", description: "Technical architecture review", quantity: 2, rate: 800 },
    ],
};

// add this line
Invoice.documentId = "invoice"

export default Invoice;

حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

سپس ، شما می توانید اجرا کنید

npx htmldocs@latest login
npx htmldocs@latest publish documents/Invoice.tsx
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

سپس ، شما می توانید برای دیدن سند بارگذاری شده وارد داشبورد شوید

شرح تصویر

اکنون می توانید با برقراری یک تماس API ساده ، یک فایل PDF ایجاد کنید!

curl -X POST https://htmldocs.com/api/documents/invoice \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "props": {
      "services": [
        {
          "name": "Web Design",
          "rate": 1500,
          "quantity": 1,
          "description": "Homepage redesign"
        },
        {
          "name": "Consulting",
          "rate": 800,
          "quantity": 2,
          "description": "Technical architecture review"
        }
      ],
      "customerName": "Acme Corp",
      "customerEmail": "billing@acmecorp.com"
    },
    "format": "json"
  }'
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

و آنجا می رویم!

شرح تصویر

برای کسب اطلاعات بیشتر در مورد HTMLDOCS ، این موارد را بررسی کنید:

نوشته های مشابه

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

دکمه بازگشت به بالا