Cài đặt tính năng in bảng thống kê ra pdf

This commit is contained in:
3dtours committed 2026-06-15 20:43:32 +07:00
1 parent f52580717f
commit 75cf96898c
4 files changed
+310 -5

No files matched your search

Binary file not shown.

After

Width:  |  Height:  |  Size: 225 KiB

+77 -4
View File
@@ -1,7 +1,9 @@
import React, { useState, useMemo } from 'react';
import { Wallet, Users, Info, PieChart, Tag, Calendar, User, FileText, TrendingUp, BarChart3 } from 'lucide-react';
import { Wallet, Users, Info, PieChart, Tag, Calendar, User, FileText, TrendingUp, BarChart3, Download } from 'lucide-react';
import { useTourStore } from '@/store/useTourStore';
import { format, parseISO } from 'date-fns';
import { jsPDF } from 'jspdf';
import autoTable from 'jspdf-autotable';
export const ExpenseManager = () => {
const { legs, currentTour } = useTourStore();
@@ -85,6 +87,69 @@ export const ExpenseManager = () => {
};
}, [legs, adults, children, discount]);
// Hàm xuất PDF
const handleExportPDF = () => {
const doc = new jsPDF();
// 1. Khai báo chuỗi Base64 của font (Đây là ví dụ, bạn thay bằng chuỗi thực tế từ Bước 1)
const robotoBase64 = "AAEAAAAOAIAAAwBgR0RFRgslCyYAAU70AAAAQEdQT1OW7t6tAAFPNAAAUZJHU1VCLJENOgABoMgAAAQsT1MvMrivKbYAAAFoAAAAYFZETVhu6nZPAAASiAAABeBjbWFwe1eWmQAAGGgAAAh+Z2x5ZnKsuk0AAClMAAD8BGhlYWT3/7sxAAAA7AAAADZoaGVhCywJXgAAASQAAAAkaG10eMBzVnEAAAHIAAAQwGxvY2Hm+KbaAAAg6AAACGJtYXhwBE8BKgAAAUgAAAAgbmFtZfDWLcMAASVQAAAEo3Bvc3RDYN+ZAAEp9AAAJP0AAQAAAAEAAOqeVyxfDzz1AAsIAAAAAADE8BEuAAAAANAzXr36jf3VCTAIcwAAAAkAAgAAAAAAAAABAAAHbP4MAAAJSfqN/dgJMAABAAAAAAAAAAAAAAAAAAAEMAABAAAEMACwABYAeAAFAAEAAAAAAAAAAAAAAAAAAwABAAMEigGQAAUAAAWaBTMAAAEfBZoFMwAAA9EAZgIAAAAAAAAAAAAAAAAA4AAC/1AAIFsAAAAgAAAAAHB5cnMAQAAA//0GAP4AAGYHmgIAIAABn08BAAAEOgWwAAAAIAACAfsAAAAAAAAB+wAAAfsAAAKPAIgE+wBGBH4AbgXcAGkE+QBlAWUAZwK8AIUCyAAmA3IAHASJAE4BkgAdAjUAJQIbAJADTAASBH4AcwR+AKoEfgBdBH4AXgR+ADUEfgCaBH0AgwR+AE0EfgBwBH4AZAHwAIYBsQApBBEASARkAJgELgCGA8cASwcvAGoFOAAcBPsAqQU1AHcFPwCpBIwAqQRsAKkFcwB6BbQAqQItALcEagA1BQQAqQROAKkG/ACpBbQAqQWAAHYFDACpBYAAbQTtAKgEvwBQBMYAMQUwAIwFFwAcBxkAPQUEADkEzgAPBMoAVgIfAJIDSAAoAh8ACQNYAEADnAAEAnkAOQRaAG0EfQCMBDAAXASDAF8EPQBdAscAPAR9AGAEaACMAfEAjQHp/78EDgCNAfEAnAcDAIsEagCMBJAAWwR9AIwEjABfArUAjAQgAF8CnQAJBGkAiAPgACEGAwArA/cAKQPJABYD9wBYArUAQAHzAK8CtQATBXEAgwHzAIsEYQBpBKYAWwW0AGkE2AAfAesAkwToAFoDWABmBkkAWwOTAJMDwQBmBG4AfwZKAFoDqgB4Av0AggRHAGEC7wBCAu8APgKCAHsEiACaA+kAQwIWAJMB+wB0ArkAegOjAHoDwABmBdwAVQY1AFAGOQBvA8kARAd6//IERABZBYEAdgS6AKYEwgCLBsEATgSwAH4EkQBHBIkAWwScAJUFmwAeAfoAmwRzAJoETwAjAioAIwWLAKIEiACRB6EAaQdEAGEB/ACgArn/5AV/AGUEkwBbBZAAjATzAIgCA/+0BDcAYgPEAKkDjQCMA2oAgQHxAI0CrQB5AioAMgPGAHsC/ABeAloAfgAA/TYAAP2GAAD8iwAA/V4AAPwnAe/9OAINALcECwBxAhcAkwRzALEFpAAfBXIAZwU+ADIEkQB4BbUAsgSRAEUFuwBNBYkAWgVSAHEEhQBkBL0AoAQCAC4EiABgBFAAYwQlAG0EiACRBI4AegKXAMMEbgAlA+wAZQTFACkEiACRBE0AZQSIAGAELABRBF0AjwWjAFcFmgBfBpcAegShAHkEQv/aBkgASgX/ACoFZAB7CJkAMQikALEGggA+BbQAsAULAKIGBAAyB0MAGwS/AFAFtACxBakALwUHAE0GLQBTBdkArwV6AJYHhwCwB8AAsAYSABEG6wCyBQUAowVkAJMHJwC3BRgAWQRsAGEEkgCdA1sAmgTUAC4GIAAVBBAAWASeAJwEUgCcBKAAKAXvAJ0EnQCcBJ4AnAPYACgFzQBkBL0AnARZAGcGeACcBp8AkQT3AB4GNgCdBFgAnQRNAGQGiACdBGQALwRo/+cETgBnBskAJwbkAJwEif/9BJ4AnAcIAJwGKwCBBFb/3AcsALgF+QCZBNIAKARGAA8HDADKBgwAvAbRAJMF4QCWCQUAtwfRAJsEJABQA9sATAVyAGcEjABbBQoAFgQDAC4FcgBnBIkAWwcBAJwGJAB+BwkAnAYsAIEFMgB1BEcAZAT9AHQAAPxnAAD8cQAA/WYAAP2kAAD6jQAA+qQEVv/cBRsAqASKAIwEZACiA5AAkQTbALEEBgCRBQkAowR+AJoGjABFBYQAPgfPAKgFtACRCDEAsAb0AJEF7gBxBNMAbQctADQFXAAfBXAAlgRrAIMFcACKBi8APwS+/90FCQCjBFoAmgWyALEEiACRBYcAXQSoAGgEqABpBLcAOgNJADsE9gBXBpQAWQbkAGQGVgA2BSsAMQRKAFMECAB5B8EARAZ1AD8H+wCpBqEAkAT2AHYEHQBlBa0AIwUgAEYFZACWBBQAAAgpAAAEFAAACCkAAAK5AAACCgAAAVwAAAR/AAACMAAAAaIAAADRAAAAAAAABUAAogY/AJADpgANAZkAYAGZADABlwAkAZoAUALUAGgC2wA8AsEAJARpAEYEjwBXArIAigPEAJQFWgCUB6oARAJmAGwCZgBZA6MAOwLvADYDYAB6BKYAWwaRAKcEfgBfBegAewPOAGgIOgCiBQEAZwUXAJgGJgBUBtcAZAbPAGMGagBZBI8AagWOAKkErwBFBJIAqATFAD8IOgBiAgz/sASCAGUEZACYBBEAPgQvAIUECAArAkwAtQKPAG4CAwBcBG4AHwAAAAAIMwBbCDUAXALvAFADC/+iA/P/XgPvAG4DpABbAf0AnwSFABMEUACKBHwAYASAAIoD5gCKA8sAigSsAGME4wCKAegAlwPPACsEVACKA7QAigYCAIoE4wCKBLsAYARcAIoEuwBZBEoAigQgAEMEJgAoBHwAdARnABQGFQAxBFQAJgQrAA0EIwBHBA8AYwQPAJgEDwBOBA8ATgQPADAEDwCABA4AcgQPAEIEDwBgBA8AVQOkAIMC7wB6Au8AQgLvAD4C7wA2Au8AWwLvAFYC7wA6Au8ATwLvAEkDlgCPArUAngNHAIEBkQBnAiUAGwH8/7YEDgBpBDoAHgN5AFcD9ABpBG8AWgTDAGQEiABgBUwAsQUkALIEEwCSBT0AsgQPAJIDnwCBA54AgQR+AE0FfgCDBYEAfgWuAH4FkwCyBeAAfgXjAH4D1QCgBIIAgwRYAA8EzwA+BGsAZQQuAEoEuQCCBQAAeAQgADsEfQCMBDIAXASTAFsEjABbBJ4AWgSNAIwEnABbBDAAXAQ9AF0EfQBgBH4AhQR+AFoFPwCpBYAAdwRaAG0DagCBAfsAAAI1ACUFXQAlBV0AJQSGAAAExgAxAp3/9AU4ABwFOAAcBTgAHAU4ABwFOAAcBTgAHAU4ABwFNQB3BIwAqQSMAKkEjACpBIwAqQIt/+ACLQCwAi3/6QIt/9YFtACpBYAAdgWAAHYFgAB2BYAAdgWAAHYFMACMBTAAjAUwAIwFMACMBM4ADwRaAG0EWgBtBFoAbQRaAG0EWgBtBFoAbQRaAG0EMABcBD0AXQQ9AF0EPQBdBD0AXQH6/8YB+gCWAfr/zwH6/7wEagCMBJAAWwSQAFsEkABbBJAAWwSQAFsEaQCIBGkAiARpAIgEaQCIA8kAFgPJABYFOAAcBFoAbQU4ABwEWgBtBTgAHARaAG0FNQB3BDAAXAU1AHcEMABcBTUAdwQwAFwFNQB3BDAAXAU/AKkFGQBfBIwAqQQ9AF0EjACpBD0AXQSMAKkEPQBdBIwAqQQ9AF0EjACpBD0AXQVzAHoEfQBgBXMAegR9AGAFcwB6BH0AYAVzAHoEfQBgBbQAqQRoAIwCLf+3Afr/nQIt/7YB+v+cAi3/7AH6/9ICLQAJAfH/+gItAKoGlwC3A9oAjQRqADUCA/+0BQQAqQQOAI0ETgChAfEAkwROAKkB8QBXBE4AqQKHAJwETgCpAs0AnAW0AKkEagCMBbQAqQRqAIwFtACpBGoAjARq/84FgAB2BJAAWwWAAHYEkABbBYAAdgSQAFsE7QCoArUAjATtAKgCtQBTBO0AqAK1AGMEvwBQBCAAXwS/AFAEIABfBL8AUAQgAF8EvwBQBCAAXwS/AFAEIABfBMYAMQKdAAkExgAxAp0ACQTGADECxQAJBTAAjARpAIgFMACMBGkAiAUwAIwEaQCIBTAAjARpAIgFMACMBGkAiAUwAIwEaQCIBxkAPQYDACsEzgAPA8kAFgTOAA8EygBWA/cAWATKAFYD9wBYBMoAVgP3AFgHev/yBsEATgWBAHYEiQBbBID/wQSA/8EEJgAoBIUAEwSFABMEhQATBIUAEwSFABMEhQATBIUAEwR8AGAD5gCKA+YAigPmAIoD5gCKAej/vgHoAI4B6P/HAej/tATjAIoEuwBgBLsAYAS7AGAEuwBgBLsAYAR8AHQEfAB0BHwAdAR8AHQEKwANBIUAEwSFABMEhQATBHwAYAR8AGAEfABgBHwAYASAAIoD5gCKA+YAigPmAIoD5gCKA+YAigSsAGMErABjBKwAYwSsAGME4wCKAej/lQHo/5QB6P/KAej/4wHoAIkDzwArBFQAigO0AIIDtACKA7QAigO0AIoE4wCKBOMAigTjAIoEuwBgBLsAYAS7AGAESgCKBEoAigRKAIoEIABDBCAAQwQgAEMEIABDBCYAKAQmACgEfAB0BHwAdAR8AHQEfAB0BHwAdAR8AHQGFQAxBCsADQQrAA0EIwBHBCMARwQjAEcIQABDBTgAHATw//AGGP/+ApEABAWUAD0FMv94BWYAMwKX/5sFOAAcBPsAqQSMAKkEygBWBbQAqQItALcFBACpBvwAqQW0AKkFgAB2BQwAqQTGADEEzgAPBQQAOQIt/9YEzgAPBIUAZARQAGMEiACRApcAwwRdAI8EcwCaBJAAWwSIAJoD4AAhA/cAKQKX/+YEXQCPBJAAWwRdAI8Gl Line truncated
// Khai báo chuỗi Base64 của Logo (Thay bằng chuỗi thực tế của bạn)
const logoBase64 = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAy...";
// 2. Thêm font vào Virtual File System của jsPDF
doc.addFileToVFS("Roboto-Regular.ttf", robotoBase64);
// 3. Đăng ký font với tên gọi 'Roboto'
doc.addFont("Roboto-Regular.ttf", "Roboto", "normal");
// 4. Thiết lập font mặc định cho tài liệu
doc.setFont("Roboto");
// 5. Thêm Logo vào PDF (x, y, width, height)
doc.addImage(logoBase64, 'PNG', 14, 10, 15, 15);
// Bây giờ bạn có thể viết tiếng Việt có dấu thoải mái
doc.setFontSize(18);
doc.setTextColor(37, 99, 235); // Blue-600
doc.text("BÁO CÁO CHI PHÍ TOUR", 35, 21); // Đẩy tiêu đề sang phải logo
doc.setFontSize(11);
doc.setTextColor(100);
doc.text(`Chuyến đi: ${currentTour?.title || 'Hành trình'}`, 14, 40);
doc.text(`Ngày xuất: ${format(new Date(), 'dd/MM/yyyy HH:mm')}`, 14, 47);
doc.setTextColor(0);
doc.setFontSize(12);
doc.text(`Tổng chi: ${stats.total.toLocaleString()} VNĐ`, 14, 57);
doc.text(`Định mức: Người lớn: ${stats.adultPrice.toLocaleString()}đ | Trẻ em: ${stats.childPrice.toLocaleString()}đ`, 14, 64);
// Cấu hình bảng dữ liệu
const tableColumn = ["STT", "Ngày giờ", "Chặng", "Dịch vụ", "Số tiền (VNĐ)", "Người chi"];
const tableRows = stats.list.map((exp: any, index: number) => [
index + 1,
exp.date ? format(new Date(exp.date), 'dd/MM HH:mm') : '--/--',
`Chặng ${exp.legSequence}`,
exp.description || 'Không có mô tả',
Number(exp.amount).toLocaleString(),
exp.paidBy?.name || 'Chưa rõ'
]);
autoTable(doc, {
head: [tableColumn],
body: tableRows,
startY: 75, // Đẩy bảng xuống để không đè lên thông tin phía trên
theme: 'grid',
headStyles: { fillColor: [37, 99, 235], textColor: [255, 255, 255], fontStyle: 'normal' }, // Roboto Bold nếu bạn thêm font bold
styles: { font: "Roboto", fontSize: 8, cellPadding: 3 }, // Quan trọng: Khai báo font ở đây cho autoTable
columnStyles: {
4: { halign: 'right' }
}
});
doc.save(`Chi-phi-tour-${currentTour?.title || 'export'}.pdf`);
};
const categoryLabels: Record<string, { label: string, color: string }> = {
ACCOMMODATION: { label: 'Chỗ ở', color: 'bg-blue-500' },
FOOD: { label: 'Ăn uống', color: 'bg-orange-500' },
@@ -212,9 +277,17 @@ export const ExpenseManager = () => {
{/* Bảng thống kê chi tiết chi phí */}
<div className="bg-white rounded-3xl border border-gray-100 shadow-sm overflow-hidden">
<div className="p-6 border-b border-gray-100 bg-gray-50/30 flex items-center gap-2">
<FileText className="w-5 h-5 text-blue-600" />
<h3 className="font-black text-gray-900 uppercase tracking-tight">Bảng kê chi tiết các khoản chi</h3>
<div className="p-6 border-b border-gray-100 bg-gray-50/30 flex items-center justify-between">
<div className="flex items-center gap-2">
<FileText className="w-5 h-5 text-blue-600" />
<h3 className="font-black text-gray-900 uppercase tracking-tight">Bảng kê chi tiết các khoản chi</h3>
</div>
<button
onClick={handleExportPDF}
className="flex items-center gap-2 px-4 py-2 bg-blue-600 hover:bg-blue-700 text-white rounded-xl text-[11px] font-black uppercase tracking-wider transition-all shadow-lg shadow-blue-200 active:scale-95"
>
<Download className="w-3.5 h-3.5" /> Xuất PDF
</button>
</div>
<div className="overflow-x-auto">
+229 -1
View File
@@ -11,6 +11,10 @@
"backend",
"frontend"
],
"dependencies": {
"jspdf": "^4.2.1",
"jspdf-autotable": "^5.0.8"
},
"devDependencies": {
"concurrently": "^8.2.2"
}
@@ -373,7 +377,6 @@
"version": "7.29.7",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.7.tgz",
"integrity": "sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=6.9.0"
@@ -1857,6 +1860,12 @@
"undici-types": ">=7.24.0 <7.24.7"
}
},
"node_modules/@types/pako": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/@types/pako/-/pako-2.0.4.tgz",
"integrity": "sha512-VWDCbrLeVXJM9fihYodcLiIv0ku+AlOa/TQ1SvYOaBuyrSKgEcro95LJyIsJ4vSo6BXIxOKxiJAat04CmST9Fw==",
"license": "MIT"
},
"node_modules/@types/pg": {
"version": "8.20.0",
"resolved": "https://registry.npmjs.org/@types/pg/-/pg-8.20.0.tgz",
@@ -1876,6 +1885,13 @@
"devOptional": true,
"license": "MIT"
},
"node_modules/@types/raf": {
"version": "3.4.3",
"resolved": "https://registry.npmjs.org/@types/raf/-/raf-3.4.3.tgz",
"integrity": "sha512-c4YAvMedbPZ5tEyxzQdMoOhhJ4RD3rngZIdwC2/qDN3d7JpEhB6fiBRKVY1lg5B7Wk+uPBjn5f39j1/2MY1oOw==",
"license": "MIT",
"optional": true
},
"node_modules/@types/react": {
"version": "18.3.31",
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.31.tgz",
@@ -1887,6 +1903,13 @@
"csstype": "^3.2.2"
}
},
"node_modules/@types/trusted-types": {
"version": "2.0.7",
"resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz",
"integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==",
"license": "MIT",
"optional": true
},
"node_modules/@vitejs/plugin-react": {
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-6.0.2.tgz",
@@ -2309,6 +2332,16 @@
"dev": true,
"license": "MIT"
},
"node_modules/base64-arraybuffer": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz",
"integrity": "sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==",
"license": "MIT",
"optional": true,
"engines": {
"node": ">= 0.6.0"
}
},
"node_modules/base64-js": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
@@ -2555,6 +2588,26 @@
],
"license": "CC-BY-4.0"
},
"node_modules/canvg": {
"version": "3.0.11",
"resolved": "https://registry.npmjs.org/canvg/-/canvg-3.0.11.tgz",
"integrity": "sha512-5ON+q7jCTgMp9cjpu4Jo6XbvfYwSB2Ow3kzHKfIyJfaCAOHLbdKPQqGKgfED/R5B+3TFFfe8pegYA+b423SRyA==",
"license": "MIT",
"optional": true,
"dependencies": {
"@babel/runtime": "^7.12.5",
"@types/raf": "^3.4.0",
"core-js": "^3.8.3",
"raf": "^3.4.1",
"regenerator-runtime": "^0.13.7",
"rgbcolor": "^1.0.1",
"stackblur-canvas": "^2.0.0",
"svg-pathdata": "^6.0.3"
},
"engines": {
"node": ">=10.0.0"
}
},
"node_modules/chalk": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
@@ -2829,6 +2882,18 @@
"node": ">=6.6.0"
}
},
"node_modules/core-js": {
"version": "3.49.0",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.49.0.tgz",
"integrity": "sha512-es1U2+YTtzpwkxVLwAFdSpaIMyQaq0PBgm3YD1W3Qpsn1NAmO3KSgZfu+oGSWVu6NvLHoHCV/aYcsE5wiB7ALg==",
"hasInstallScript": true,
"license": "MIT",
"optional": true,
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/core-js"
}
},
"node_modules/cors": {
"version": "2.8.6",
"resolved": "https://registry.npmjs.org/cors/-/cors-2.8.6.tgz",
@@ -2895,6 +2960,16 @@
"node": ">= 8"
}
},
"node_modules/css-line-break": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/css-line-break/-/css-line-break-2.1.0.tgz",
"integrity": "sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==",
"license": "MIT",
"optional": true,
"dependencies": {
"utrie": "^1.0.2"
}
},
"node_modules/csstype": {
"version": "3.2.3",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz",
@@ -2988,6 +3063,16 @@
"node": ">=0.3.1"
}
},
"node_modules/dompurify": {
"version": "3.4.10",
"resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.4.10.tgz",
"integrity": "sha512-0xzNv0e7oYC6yyuOGZIABPM4qtg3QxLFniDNPP4ZP90wR8Yq3zgwpRbrNiT4N3IKqDbbYFEJLV+JWEs19aZ//w==",
"license": "(MPL-2.0 OR Apache-2.0)",
"optional": true,
"optionalDependencies": {
"@types/trusted-types": "^2.0.7"
}
},
"node_modules/dotenv": {
"version": "17.4.2",
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.4.2.tgz",
@@ -3305,6 +3390,17 @@
"dev": true,
"license": "MIT"
},
"node_modules/fast-png": {
"version": "6.4.0",
"resolved": "https://registry.npmjs.org/fast-png/-/fast-png-6.4.0.tgz",
"integrity": "sha512-kAqZq1TlgBjZcLr5mcN6NP5Rv4V2f22z00c3g8vRrwkcqjerx7BEhPbOnWCPqaHUl2XWQBJQvOT/FQhdMT7X/Q==",
"license": "MIT",
"dependencies": {
"@types/pako": "^2.0.3",
"iobuffer": "^5.3.2",
"pako": "^2.1.0"
}
},
"node_modules/fast-safe-stringify": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz",
@@ -3346,6 +3442,12 @@
}
}
},
"node_modules/fflate": {
"version": "0.8.3",
"resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.3.tgz",
"integrity": "sha512-tbZNuJrLwGUp3zshBtdy4W+ORxZuIh8a5ilyIEQDC5rY1f3U20JMry0Ll3WBzU58EZKsEuJFXhb5gwv8CsPvgA==",
"license": "MIT"
},
"node_modules/file-type": {
"version": "21.3.4",
"resolved": "https://registry.npmjs.org/file-type/-/file-type-21.3.4.tgz",
@@ -3659,6 +3761,20 @@
"node": ">= 0.4"
}
},
"node_modules/html2canvas": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/html2canvas/-/html2canvas-1.4.1.tgz",
"integrity": "sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==",
"license": "MIT",
"optional": true,
"dependencies": {
"css-line-break": "^2.1.0",
"text-segmentation": "^1.0.3"
},
"engines": {
"node": ">=8.0.0"
}
},
"node_modules/http-errors": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz",
@@ -3738,6 +3854,12 @@
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
"license": "ISC"
},
"node_modules/iobuffer": {
"version": "5.4.0",
"resolved": "https://registry.npmjs.org/iobuffer/-/iobuffer-5.4.0.tgz",
"integrity": "sha512-DRebOWuqDvxunfkNJAlc3IzWIPD5xVxwUNbHr7xKB8E6aLJxIPfNX3CoMJghcFjpv6RWQsrcJbghtEwSPoJqMA==",
"license": "MIT"
},
"node_modules/ipaddr.js": {
"version": "1.9.1",
"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
@@ -3932,6 +4054,32 @@
"npm": ">=6"
}
},
"node_modules/jspdf": {
"version": "4.2.1",
"resolved": "https://registry.npmjs.org/jspdf/-/jspdf-4.2.1.tgz",
"integrity": "sha512-YyAXyvnmjTbR4bHQRLzex3CuINCDlQnBqoSYyjJwTP2x9jDLuKDzy7aKUl0hgx3uhcl7xzg32agn5vlie6HIlQ==",
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.28.6",
"fast-png": "^6.2.0",
"fflate": "^0.8.1"
},
"optionalDependencies": {
"canvg": "^3.0.11",
"core-js": "^3.6.0",
"dompurify": "^3.3.1",
"html2canvas": "^1.0.0-rc.5"
}
},
"node_modules/jspdf-autotable": {
"version": "5.0.8",
"resolved": "https://registry.npmjs.org/jspdf-autotable/-/jspdf-autotable-5.0.8.tgz",
"integrity": "sha512-Hy05N86yBO7CXBrnSLOge7i1ZYpKH2DjQ94iybaP7vBhSInjvRBgDc99ngKzSbSO8Jc98ZCally8I6n0tj2RJQ==",
"license": "MIT",
"peerDependencies": {
"jspdf": "^2 || ^3 || ^4"
}
},
"node_modules/jwa": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.1.tgz",
@@ -4743,6 +4891,12 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/pako": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/pako/-/pako-2.1.0.tgz",
"integrity": "sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug==",
"license": "(MIT AND Zlib)"
},
"node_modules/parent-module": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
@@ -4872,6 +5026,13 @@
"resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz",
"integrity": "sha512-KG8UEiEVkR3wGEb4m5yZkVCzigAD+cVEJck2CzYZO37ZGJfctvVptVO192MwrtPhzONn6go8ylnOdMhKqi4nfg=="
},
"node_modules/performance-now": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
"integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==",
"license": "MIT",
"optional": true
},
"node_modules/pg": {
"version": "8.21.0",
"resolved": "https://registry.npmjs.org/pg/-/pg-8.21.0.tgz",
@@ -5104,6 +5265,16 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/raf": {
"version": "3.4.1",
"resolved": "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz",
"integrity": "sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==",
"license": "MIT",
"optional": true,
"dependencies": {
"performance-now": "^2.1.0"
}
},
"node_modules/range-parser": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
@@ -5216,6 +5387,13 @@
"integrity": "sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==",
"license": "Apache-2.0"
},
"node_modules/regenerator-runtime": {
"version": "0.13.11",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz",
"integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==",
"license": "MIT",
"optional": true
},
"node_modules/require-directory": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
@@ -5267,6 +5445,16 @@
"dev": true,
"license": "ISC"
},
"node_modules/rgbcolor": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/rgbcolor/-/rgbcolor-1.0.1.tgz",
"integrity": "sha512-9aZLIrhRaD97sgVhtJOW6ckOEh6/GnvQtdVNfdZ6s67+3/XwLS9lBcQYzEEhYVeUowN7pRzMLsyGhK2i/xvWbw==",
"license": "MIT OR SEE LICENSE IN FEEL-FREE.md",
"optional": true,
"engines": {
"node": ">= 0.8.15"
}
},
"node_modules/rolldown": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.3.tgz",
@@ -5654,6 +5842,16 @@
"node": ">= 10.x"
}
},
"node_modules/stackblur-canvas": {
"version": "2.7.0",
"resolved": "https://registry.npmjs.org/stackblur-canvas/-/stackblur-canvas-2.7.0.tgz",
"integrity": "sha512-yf7OENo23AGJhBriGx0QivY5JP6Y1HbrrDI6WLt6C5auYZXlQrheoY8hD4ibekFKz1HOfE48Ww8kMWMnJD/zcQ==",
"license": "MIT",
"optional": true,
"engines": {
"node": ">=0.1.14"
}
},
"node_modules/statuses": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz",
@@ -5750,6 +5948,16 @@
"url": "https://github.com/chalk/supports-color?sponsor=1"
}
},
"node_modules/svg-pathdata": {
"version": "6.0.3",
"resolved": "https://registry.npmjs.org/svg-pathdata/-/svg-pathdata-6.0.3.tgz",
"integrity": "sha512-qsjeeq5YjBZ5eMdFuUa4ZosMLxgr5RZ+F+Y1OrDhuOCEInRMA3x74XdBtggJcj9kOeInz0WE+LgCPDkZFlBYJw==",
"license": "MIT",
"optional": true,
"engines": {
"node": ">=12.0.0"
}
},
"node_modules/symbol-observable": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-4.0.0.tgz",
@@ -5906,6 +6114,16 @@
"dev": true,
"license": "MIT"
},
"node_modules/text-segmentation": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/text-segmentation/-/text-segmentation-1.0.3.tgz",
"integrity": "sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw==",
"license": "MIT",
"optional": true,
"dependencies": {
"utrie": "^1.0.2"
}
},
"node_modules/tinyglobby": {
"version": "0.2.17",
"resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz",
@@ -6197,6 +6415,16 @@
"node": ">= 0.4.0"
}
},
"node_modules/utrie": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/utrie/-/utrie-1.0.2.tgz",
"integrity": "sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==",
"license": "MIT",
"optional": true,
"dependencies": {
"base64-arraybuffer": "^1.0.2"
}
},
"node_modules/v8-compile-cache-lib": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz",
+4
View File
@@ -18,5 +18,9 @@
},
"devDependencies": {
"concurrently": "^8.2.2"
},
"dependencies": {
"jspdf": "^4.2.1",
"jspdf-autotable": "^5.0.8"
}
}