如何在Flutter中使用pdf包生成多成员多页PDF报表
多成员多页PDF报表生成代码改造方案
核心改造思路
将原单页报表逻辑改为遍历成员列表,为每个成员单独生成报表页面并合并到同一个PDF文档中,同时调整参数结构以支持批量传入成员信息及对应交易数据。
改造后完整代码
import 'package:bachat_gat/common/common_index.dart'; import 'package:bachat_gat/features/groups/models/models_index.dart'; import 'package:flutter/services.dart'; import 'package:pdf/pdf.dart'; import 'package:pdf/widgets.dart' as pw; import 'package:printing/printing.dart'; import 'getFontLoad.dart'; class PdfApi { // 改造方法:接收成员名列表和按成员分组的交易数据 static Future<Uint8List> generateMultiMemberTable( Map<String, List<MemberTransactionDetails>> memberDataMap, String groupName, List<String> memberNames, ) async { // 一次性加载所有字体,避免重复加载浪费资源 final rfont = await FontLoaders.loadFont('assets/fonts/NotoSansDevanagari-Regular.ttf'); final mfont = await FontLoaders.loadFont('assets/fonts/NotoSansDevanagari-Medium.ttf'); final bfont = await FontLoaders.loadFont('assets/fonts/NotoSansDevanagari-Bold.ttf'); final sbfont = await FontLoaders.loadFont('assets/fonts/NotoSansDevanagari-SemiBold.ttf'); final nfont = await FontLoaders.loadFont('assets/fonts/marathi.ttf'); var myTheme = pw.ThemeData.withFont( base: rfont, bold: bfont, fontFallback: [nfont, mfont, sbfont], ); final pdf = pw.Document(theme: myTheme); final headers = [ 'Month', 'Paid Shares', 'Loan Taken', 'Paid Interest', 'Paid Loan', 'Remaining Loan', 'Late Fee', 'Others', 'Total Paid' ]; // 遍历每个成员,生成对应报表页面 for (String memberName in memberNames) { final memberData = memberDataMap[memberName] ?? []; List<double> totalPaid = []; for (var m in memberData) { double total = m.paidOtherAmount! + m.paidInterest! + m.paidLoan! + m.paidLateFee! + m.paidShares!; totalPaid.add(total); } final data = memberData .asMap() .entries .map((entry) => [ entry.value.trxPeriod ?? '', entry.value.paidShares?.toString() ?? '', entry.value.loanTaken?.toString() ?? '', entry.value.paidInterest?.toString() ?? '', entry.value.paidLoan?.toString() ?? '', entry.value.remainingLoan?.toString() ?? '', entry.value.paidLateFee?.toString() ?? '', entry.value.paidOtherAmount?.toString() ?? '', totalPaid[entry.key].toString(), ]) .toList(); // 为当前成员添加独立页面 pdf.addPage(pw.Page(build: (context) { return pw.Column( children: [ pw.Text(groupName, style: pw.TextStyle( fontSize: 20, fontWeight: pw.FontWeight.bold, )), pw.SizedBox(height: 20), pw.Text("Member Name: $memberName", style: pw.TextStyle( fontSize: 15, fontWeight: pw.FontWeight.normal, fontStyle: pw.FontStyle.normal, )), pw.SizedBox(height: 15), pw.TableHelper.fromTextArray( headers: headers, data: data, ), ], ); })); } return pdf.save(); } static Future<void> previewPDF(Uint8List bytes) async { await Printing.layoutPdf(onLayout: (PdfPageFormat format) => bytes); } static Future<void> saveAsPDF(String fileName, Uint8List bytes) async { await AppUtils.saveAsBytes(fileName, "pdf", bytes); } }
关键修改说明
- 参数结构调整:将原单个成员的
memberData和memberName改为Map<String, List<MemberTransactionDetails>>(键为成员名,值为对应交易数据)和List<String>成员列表,实现批量处理。 - 字体加载优化:字体仅在方法开头加载一次,避免循环中重复加载导致性能损耗。
- 多页生成逻辑:通过
for循环遍历成员列表,为每个成员计算交易总额、生成表格数据,再调用pdf.addPage()添加独立页面。 - 空值兼容处理:获取成员交易数据时增加
?? []判断,避免成员无数据时出现异常。
内容的提问来源于stack exchange,提问作者BTCOD278 Pranav Mohite
相关产品推荐
相关产品推荐

