دليل شامل: كيفية إنشاء تقارير PDF احترافية في تطبيقات React
هل تبحث عن طريقة فعالة لإنشاء تقارير بصيغة 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 وتنزيله تلقائيًا في متصفحك.

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