دليل شامل: كيفية إنشاء تقارير PDF احترافية في تطبيقات React

دقائق القراءة: 7

هل تبحث عن طريقة فعالة لإنشاء تقارير بصيغة PDF مباشرة من تطبيقات React الخاصة بك؟ غالبًا ما يواجه مطورو الويب تحديًا في إيجاد حل سهل ومباشر لتوليد مستندات PDF من البيانات الديناميكية. في هذا الدليل الشامل، سنستعرض أسهل وأكثر الطرق فعالية لتحقيق ذلك، مع التركيز على توفير محتوى قيم ومفيد.

تخيل أنك تعمل على تطبيق CRM (إدارة علاقات العملاء) كامل الميزات، وتحتاج إلى تمكين وكلاء الدعم من إنشاء ملخصات للتذاكر المغلقة كملفات PDF. هذا هو بالضبط السيناريو الذي سنبنيه خطوة بخطوة، معتمدين على مكتبات قوية وموثوقة.

الخطوة الأولى: إعداد وتثبيت الحزم الضرورية

قبل الغوص في كتابة التعليمات البرمجية، نحتاج إلى تثبيت المكتبات الأساسية التي ستمكننا من توليد ملفات PDF وتنسيق الجداول داخلها. سنستخدم مكتبتي jspdf و jspdf-autotable.

  • jspdf: هي مكتبة قوية لتوليد ملفات PDF من جانب العميل باستخدام JavaScript.
  • jspdf-autotable: هي إضافة لمكتبة jspdf تسهل بشكل كبير إنشاء الجداول وتنسيقها داخل مستندات PDF.

لتثبيت هذه الحزم، افتح طرفية المشروع ونفذ الأمر التالي:

npm i jspdf jspdf-autotable

بالإضافة إلى ذلك، سنحتاج إلى مكتبة date-fns لتنسيق التواريخ التي قد نتلقاها من استدعاءات API، مما يضمن عرضها بشكل مقروء ومنظم في التقرير.

بناء وظيفة توليد تقارير PDF ديناميكية

الآن، لنقم بتعريف وظيفة مركزية يمكن استدعاؤها من أي مكان في تطبيقك لتوليد تقرير PDF. سنقوم بإنشاء ملف جديد باسم reportGenerator.js داخل مجلد services (أو أي مجلد تفضله لتنظيم الخدمات).

فهم آلية عمل وظيفة generatePDF

هذه الوظيفة ستستقبل قائمة بالتذاكر (tickets) كمعامل، وتقوم بمعالجتها لإنشاء مستند PDF. لقد أضفنا تعليقات توضيحية مكثفة داخل الكود لمساعدتك على فهم كل سطر برمجي.

// services/reportGenerator.js
import jsPDF from "jspdf";
import "jspdf-autotable";
// Date Fns is used to format the dates we receive
// from our API call
import { format } from "date-fns";

// define a generatePDF function that accepts a tickets argument
const generatePDF = tickets => {
  // initialize jsPDF
  const doc = new jsPDF();

  // define the columns we want and their titles
  const tableColumn = [
    "Id",
    "Title",
    "Issue",
    "Status",
    "Closed on"
  ];
  // define an empty array of rows
  const tableRows = [];

  // for each ticket pass all its data into an array
  tickets.forEach(ticket => {
    const ticketData = [
      ticket.id,
      ticket.title,
      ticket.request,
      ticket.status,
      // called date-fns to format the date on the ticket
      format(new Date(ticket.updated_at), "yyyy-MM-dd")
    ];
    // push each tickcet's info into a row
    tableRows.push(ticketData);
  });

  // startY is basically margin-top
  doc.autoTable(tableColumn, tableRows, {
    startY: 20
  });
  const date = Date().split(" ");
  // we use a date string to generate our filename.
  const dateStr = date[0] + date[1] + date[2] + date[3] + date[4];
  // ticket title. and margin-top + margin-left
  doc.text("Closed tickets within the last one month.", 14, 15);
  // we define the name of our PDF file.
  doc.save(`report_${dateStr}.pdf`);
};

export default generatePDF;

دعنا نوضح بعض النقاط الهامة في هذه الوظيفة:

  • يبدأ الكود باستيراد jsPDF و jspdf-autotable، بالإضافة إلى وظيفة format من date-fns.
  • نقوم بتهيئة كائن jsPDF جديد باسم doc.
  • يتم تعريف tableColumn لتحديد رؤوس الأعمدة في جدول PDF (مثل "Id"، "Title"، إلخ).
  • نستخدم حلقة forEach على مصفوفة التذاكر (tickets) لتحويل بيانات كل تذكرة إلى صفوف (tableRows) تتوافق مع الأعمدة المحددة.
  • يتم تنسيق تاريخ التحديث (updated_at) باستخدام format(new Date(ticket.updated_at), "yyyy-MM-dd") لضمان عرضه بشكل موحد.
  • تستخدم الدالة doc.autoTable() لإنشاء الجدول تلقائيًا. يشير startY: 20 إلى الهامش العلوي للجدول داخل المستند.
  • يتم إنشاء اسم ملف فريد للتقرير باستخدام التاريخ الحالي، ويتم حفظ الملف باستخدام doc.save().

إنشاء مكون React لجلب وتخزين بيانات التذاكر

الآن، لنقم ببناء مكون React بسيط يقوم بجلب التذاكر من واجهة برمجة تطبيقات (API) ويحفظها في حالة المكون (state). هذا المكون سيكون مسؤولاً عن استدعاء وظيفة توليد PDF.

مكون Tickets: جلب البيانات وإدارة الحالة

import React, { useEffect, useState } from "react";
import generatePDF from "../services/reportGenerator";

const Tickets = () => {
  const [tickets, setTickets] = useState([]);

  useEffect(() => {
    const getAllTickets = async () => {
      try {
        const response = await axios.get("http://localhost:3000/tickets");
        setTickets(response.data.tickets);
      } catch (err) {
        console.log("error");
      }
    };
    getAllTickets();
  }, []);

  const reportTickets = tickets.filter(
    ticket => ticket.status === "completed"
  );

  return (
    <div>
      <div className="container mb-4 mt-4 p-3">
        <div className="row">
          {user.user.role === "user" ? (
            <></>
          ) : (
            <button
              className="btn btn-primary"
              onClick={() => generatePDF(reportTickets)}
            >
              Generate monthly report
            </button>
          )}
        </div>
      </div>
      <TicketsComponent tickets={tickets} />
    </div>
  );
};

export default Tickets;

ملاحظات حول مكون <Tickets />:

  • عند تحميل المكون، يتم إجراء طلب HTTP إلى http://localhost:3000/tickets لجلب جميع التذاكر.
  • يتم حفظ التذاكر المستلمة في حالة المكون باستخدام setTickets.
  • يتم تمرير هذه التذاكر كخاصية (prop) إلى مكون فرعي آخر، وهو <TicketsComponent />، لعرضها في واجهة المستخدم.
  • تم تعريف متغير reportTickets الذي يقوم بتصفية التذاكر للحصول فقط على تلك التي حالتها "completed". هذا يضمن أن التقرير سيحتوي فقط على التذاكر المكتملة.
  • يحتوي المكون على زر Generate monthly report (توليد التقرير الشهري) الذي يستدعي وظيفة generatePDF() التي قمنا بتعريفها سابقًا عند النقر عليه.

تصميم مكون عرض التذاكر في جدول تفاعلي

بعد جلب البيانات، نحتاج إلى مكون لعرض هذه التذاكر بطريقة منظمة وجذابة. سنقوم بإنشاء مكون <TicketsComponent /> الذي يستقبل التذاكر كخاصية (prop) ويعرضها في جدول.

مكون TicketsComponent: عرض البيانات وتنسيقها

import React from "react";
import { Link } from "react-router-dom";

const TicketsComponent = ({ tickets }) => {
  // a function that assigns bootstrap styling classes based on
  // the status of the ticket
  const assignColorToTicketStatus = ticket => {
    if (ticket.status === "completed") {
      return "p-3 mb-2 bg-success text-white";
    } else if (ticket.status === "in_progress") {
      return "p-3 mb-2 bg-warning text-dark";
    } else if (ticket.status === "opened") {
      return "p-3 mb-2 bg-light text-dark";
    }
  };

  return (
    <div className="container">
      {tickets.length === 0 ? (
        "You currently have no tickets created"
      ) : (
        <div style="overflow-x: auto; max-width: 100%;">
          <table className="table">
            <thead>
              <tr>
                <th scope="col">#</th>
                <th scope="col">Title</th>
                <th scope="col">Issue</th>
                <th scope="col">Status</th>
                <th scope="col"></th>
              </tr>
            </thead>
            <tbody>
              {tickets.map(ticket => (
                <tr key={ticket.id}>
                  <td>{ticket.id}</td>
                  <td>{ticket.title}</td>
                  <td>{ticket.request}</td>
                  <td className={assignColorToTicketStatus(ticket)}>
                    {ticket.status}
                  </td>
                  <td>
                    <Link to={`/ticket/${ticket.id}`}> See comments </Link>
                  </td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      )}
    </div>
  );
};

export default TicketsComponent;

في هذا المكون:

  • تستقبل الدالة assignColorToTicketStatus التذكرة كمعامل وتقوم بإرجاع فئات Bootstrap للتصميم بناءً على حالة التذكرة (completed، in_progress، opened)، مما يوفر تمييزًا بصريًا واضحًا.
  • يتم استخدام التحقق الشرطي (tickets.length === 0) لعرض رسالة مناسبة إذا لم تكن هناك تذاكر.
  • يتم عرض التذاكر في جدول HTML باستخدام دالة map لتكرار مصفوفة التذاكر وإنشاء صف لكل تذكرة.
  • لضمان التجاوب مع شاشات الجوال، تم تغليف الجدول داخل <div style="overflow-x: auto; max-width: 100%;">، مما يسمح بالتمرير الأفقي إذا كان محتوى الجدول أكبر من عرض الشاشة.
  • يتم استخدام مكون <Link> من react-router-dom لتوفير روابط تفاعلية لعرض تفاصيل كل تذكرة.

مشاهدة النتائج: تقرير PDF جاهز للتنزيل

بعد دمج هذه المكونات، سيكون لديك تطبيق React قادر على جلب وعرض بيانات التذاكر، بالإضافة إلى زر لتوليد تقارير PDF. عند النقر على زر Generate monthly report، سيتم إنشاء ملف PDF وتنزيله تلقائيًا في متصفحك.

لقطة شاشة لتطبيق React يعرض قائمة تذاكر الدعم وزر لتوليد تقرير PDF شهري.

كما ترى في الصورة أعلاه، لدينا عدد من التذاكر بحالات مختلفة. عند النقر على زر Generate monthly report، ستحصل على ملف PDF باسم مشابه لـ report_ddmmyyyy.pdf (حيث ddmmyyyy يمثل التاريخ الحالي) يتم تنزيله مباشرة في متصفحك.

الخلاصة التقنية

لقد استعرضنا في هذا الدليل طريقة فعالة ومباشرة لإنشاء تقارير PDF ديناميكية في تطبيقات React. من خلال الاستفادة من قوة مكتبتي jsPDF و jspdf-autotable، أصبح بإمكان المطورين توليد مستندات احترافية من جانب العميل بكل سهولة. هذه الطريقة لا تقلل من الحمل على الخادم فحسب، بل توفر أيضًا مرونة كبيرة في تخصيص التقارير وتنسيقها. إن القدرة على تحويل البيانات المعروضة في واجهة المستخدم إلى تقارير قابلة للتنزيل بصيغة PDF هي ميزة بالغة الأهمية للعديد من التطبيقات التجارية والإدارية، وتساهم في تحسين تجربة المستخدم بشكل كبير.

اترك تعليقاً

لن يتم نشر عنوان بريدك الإلكتروني. الحقول الإلزامية مشار إليها بـ *