375 lines
16 KiB
Dart
375 lines
16 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:superport/models/company_model.dart';
|
|
import 'package:superport/screens/company/widgets/company_info_card.dart';
|
|
import 'package:pdf/widgets.dart' as pw; // PDF 생성용
|
|
import 'package:printing/printing.dart'; // PDF 프린트/미리보기용
|
|
import 'dart:typed_data'; // Uint8List
|
|
import 'package:pdf/pdf.dart'; // PdfColors, PageFormat 등 전체 임포트
|
|
import 'package:superport/screens/common/custom_widgets.dart'; // DataTableCard 사용을 위한 import
|
|
import 'package:flutter/services.dart'; // rootBundle 사용을 위한 import
|
|
|
|
/// 본사와 지점 리스트를 보여주는 다이얼로그 위젯
|
|
class CompanyBranchDialog extends StatelessWidget {
|
|
final Company mainCompany;
|
|
|
|
const CompanyBranchDialog({super.key, required this.mainCompany});
|
|
|
|
// 본사+지점 정보를 PDF로 생성하는 함수
|
|
Future<Uint8List> _buildPdf(final pw.Document pdf) async {
|
|
// 한글 폰트 로드 (lib/assets/fonts/NotoSansKR-VariableFont_wght.ttf)
|
|
final fontData = await rootBundle.load(
|
|
'lib/assets/fonts/NotoSansKR-VariableFont_wght.ttf',
|
|
);
|
|
final ttf = pw.Font.ttf(fontData);
|
|
final List<Branch> branchList = mainCompany.branches ?? [];
|
|
pdf.addPage(
|
|
pw.Page(
|
|
build: (pw.Context context) {
|
|
return pw.Column(
|
|
crossAxisAlignment: pw.CrossAxisAlignment.start,
|
|
children: [
|
|
pw.Text(
|
|
'본사 및 지점 목록',
|
|
style: pw.TextStyle(
|
|
font: ttf, // 한글 폰트 적용
|
|
fontSize: 20,
|
|
fontWeight: pw.FontWeight.bold,
|
|
),
|
|
),
|
|
pw.SizedBox(height: 16),
|
|
pw.Table(
|
|
border: pw.TableBorder.all(color: PdfColors.grey800),
|
|
defaultVerticalAlignment: pw.TableCellVerticalAlignment.middle,
|
|
children: [
|
|
pw.TableRow(
|
|
decoration: pw.BoxDecoration(color: PdfColors.grey300),
|
|
children: [
|
|
pw.Padding(
|
|
padding: const pw.EdgeInsets.all(4),
|
|
child: pw.Text('구분', style: pw.TextStyle(font: ttf)),
|
|
),
|
|
pw.Padding(
|
|
padding: const pw.EdgeInsets.all(4),
|
|
child: pw.Text('이름', style: pw.TextStyle(font: ttf)),
|
|
),
|
|
pw.Padding(
|
|
padding: const pw.EdgeInsets.all(4),
|
|
child: pw.Text('우편번호', style: pw.TextStyle(font: ttf)),
|
|
),
|
|
pw.Padding(
|
|
padding: const pw.EdgeInsets.all(4),
|
|
child: pw.Text('담당자', style: pw.TextStyle(font: ttf)),
|
|
),
|
|
pw.Padding(
|
|
padding: const pw.EdgeInsets.all(4),
|
|
child: pw.Text('직책', style: pw.TextStyle(font: ttf)),
|
|
),
|
|
pw.Padding(
|
|
padding: const pw.EdgeInsets.all(4),
|
|
child: pw.Text('전화번호', style: pw.TextStyle(font: ttf)),
|
|
),
|
|
pw.Padding(
|
|
padding: const pw.EdgeInsets.all(4),
|
|
child: pw.Text('이메일', style: pw.TextStyle(font: ttf)),
|
|
),
|
|
],
|
|
),
|
|
// 본사
|
|
pw.TableRow(
|
|
children: [
|
|
pw.Padding(
|
|
padding: const pw.EdgeInsets.all(4),
|
|
child: pw.Text('본사', style: pw.TextStyle(font: ttf)),
|
|
),
|
|
pw.Padding(
|
|
padding: const pw.EdgeInsets.all(4),
|
|
child: pw.Text(
|
|
mainCompany.name,
|
|
style: pw.TextStyle(font: ttf),
|
|
),
|
|
),
|
|
pw.Padding(
|
|
padding: const pw.EdgeInsets.all(4),
|
|
child: pw.Text(
|
|
mainCompany.address.zipCode,
|
|
style: pw.TextStyle(font: ttf),
|
|
),
|
|
),
|
|
pw.Padding(
|
|
padding: const pw.EdgeInsets.all(4),
|
|
child: pw.Text(
|
|
mainCompany.contactName ?? '',
|
|
style: pw.TextStyle(font: ttf),
|
|
),
|
|
),
|
|
pw.Padding(
|
|
padding: const pw.EdgeInsets.all(4),
|
|
child: pw.Text(
|
|
mainCompany.contactPosition ?? '',
|
|
style: pw.TextStyle(font: ttf),
|
|
),
|
|
),
|
|
pw.Padding(
|
|
padding: const pw.EdgeInsets.all(4),
|
|
child: pw.Text(
|
|
mainCompany.contactPhone ?? '',
|
|
style: pw.TextStyle(font: ttf),
|
|
),
|
|
),
|
|
pw.Padding(
|
|
padding: const pw.EdgeInsets.all(4),
|
|
child: pw.Text(
|
|
mainCompany.contactEmail ?? '',
|
|
style: pw.TextStyle(font: ttf),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
// 지점
|
|
...branchList.map(
|
|
(branch) => pw.TableRow(
|
|
children: [
|
|
pw.Padding(
|
|
padding: const pw.EdgeInsets.all(4),
|
|
child: pw.Text('지점', style: pw.TextStyle(font: ttf)),
|
|
),
|
|
pw.Padding(
|
|
padding: const pw.EdgeInsets.all(4),
|
|
child: pw.Text(
|
|
branch.name,
|
|
style: pw.TextStyle(font: ttf),
|
|
),
|
|
),
|
|
pw.Padding(
|
|
padding: const pw.EdgeInsets.all(4),
|
|
child: pw.Text(
|
|
branch.address.zipCode,
|
|
style: pw.TextStyle(font: ttf),
|
|
),
|
|
),
|
|
pw.Padding(
|
|
padding: const pw.EdgeInsets.all(4),
|
|
child: pw.Text(
|
|
branch.contactName ?? '',
|
|
style: pw.TextStyle(font: ttf),
|
|
),
|
|
),
|
|
pw.Padding(
|
|
padding: const pw.EdgeInsets.all(4),
|
|
child: pw.Text(
|
|
branch.contactPosition ?? '',
|
|
style: pw.TextStyle(font: ttf),
|
|
),
|
|
),
|
|
pw.Padding(
|
|
padding: const pw.EdgeInsets.all(4),
|
|
child: pw.Text(
|
|
branch.contactPhone ?? '',
|
|
style: pw.TextStyle(font: ttf),
|
|
),
|
|
),
|
|
pw.Padding(
|
|
padding: const pw.EdgeInsets.all(4),
|
|
child: pw.Text(
|
|
branch.contactEmail ?? '',
|
|
style: pw.TextStyle(font: ttf),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
],
|
|
),
|
|
],
|
|
);
|
|
},
|
|
),
|
|
);
|
|
return pdf.save();
|
|
}
|
|
|
|
// 프린트 버튼 클릭 시 PDF 미리보기 및 인쇄
|
|
void _printPopupData() async {
|
|
final pdf = pw.Document();
|
|
await Printing.layoutPdf(
|
|
onLayout: (format) async {
|
|
return _buildPdf(pdf);
|
|
},
|
|
);
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final List<Branch> branchList = mainCompany.branches ?? [];
|
|
// 본사와 지점 정보를 한 리스트로 합침
|
|
final List<Map<String, dynamic>> displayList = [
|
|
{
|
|
'type': '본사',
|
|
'name': mainCompany.name,
|
|
'companyTypes': mainCompany.companyTypes,
|
|
'address': mainCompany.address,
|
|
'contactName': mainCompany.contactName,
|
|
'contactPosition': mainCompany.contactPosition,
|
|
'contactPhone': mainCompany.contactPhone,
|
|
'contactEmail': mainCompany.contactEmail,
|
|
},
|
|
...branchList.map(
|
|
(branch) => {
|
|
'type': '지점',
|
|
'name': branch.name,
|
|
'companyTypes': mainCompany.companyTypes,
|
|
'address': branch.address,
|
|
'contactName': branch.contactName,
|
|
'contactPosition': branch.contactPosition,
|
|
'contactPhone': branch.contactPhone,
|
|
'contactEmail': branch.contactEmail,
|
|
},
|
|
),
|
|
];
|
|
final double maxDialogHeight = MediaQuery.of(context).size.height * 0.7;
|
|
final double maxDialogWidth = MediaQuery.of(context).size.width * 0.8;
|
|
return Dialog(
|
|
child: ConstrainedBox(
|
|
constraints: BoxConstraints(
|
|
maxHeight: maxDialogHeight,
|
|
maxWidth: maxDialogWidth,
|
|
),
|
|
child: Padding(
|
|
padding: const EdgeInsets.all(24.0),
|
|
child: Column(
|
|
mainAxisSize: MainAxisSize.min,
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Row(
|
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
children: [
|
|
const Text(
|
|
'본사 및 지점 목록',
|
|
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
|
|
),
|
|
Row(
|
|
children: [
|
|
IconButton(
|
|
icon: const Icon(Icons.print),
|
|
tooltip: '프린트',
|
|
onPressed: _printPopupData,
|
|
),
|
|
IconButton(
|
|
icon: const Icon(Icons.close),
|
|
onPressed: () => Navigator.of(context).pop(),
|
|
),
|
|
],
|
|
),
|
|
],
|
|
),
|
|
const SizedBox(height: 16),
|
|
Expanded(
|
|
child: DataTableCard(
|
|
width: maxDialogWidth - 48,
|
|
child: SingleChildScrollView(
|
|
scrollDirection: Axis.horizontal,
|
|
child: Container(
|
|
width: maxDialogWidth - 48,
|
|
constraints: BoxConstraints(minWidth: 900),
|
|
child: SingleChildScrollView(
|
|
scrollDirection: Axis.vertical,
|
|
child: DataTable(
|
|
columns: const [
|
|
DataColumn(label: Text('번호')),
|
|
DataColumn(label: Text('구분')),
|
|
DataColumn(label: Text('회사명')),
|
|
DataColumn(label: Text('유형')),
|
|
DataColumn(label: Text('주소')),
|
|
DataColumn(label: Text('담당자')),
|
|
DataColumn(label: Text('직책')),
|
|
DataColumn(label: Text('전화번호')),
|
|
DataColumn(label: Text('이메일')),
|
|
],
|
|
rows:
|
|
displayList.asMap().entries.map((entry) {
|
|
final int index = entry.key;
|
|
final data = entry.value;
|
|
return DataRow(
|
|
cells: [
|
|
DataCell(Text('${index + 1}')),
|
|
DataCell(Text(data['type'])),
|
|
DataCell(Text(data['name'])),
|
|
DataCell(
|
|
Row(
|
|
children:
|
|
(data['companyTypes']
|
|
as List<CompanyType>)
|
|
.map(
|
|
(type) => Container(
|
|
margin:
|
|
const EdgeInsets.only(
|
|
right: 4,
|
|
),
|
|
padding:
|
|
const EdgeInsets.symmetric(
|
|
horizontal: 8,
|
|
vertical: 2,
|
|
),
|
|
decoration: BoxDecoration(
|
|
color:
|
|
type ==
|
|
CompanyType
|
|
.customer
|
|
? Colors
|
|
.blue
|
|
.shade50
|
|
: Colors
|
|
.green
|
|
.shade50,
|
|
borderRadius:
|
|
BorderRadius.circular(
|
|
8,
|
|
),
|
|
),
|
|
child: Text(
|
|
companyTypeToString(type),
|
|
style: TextStyle(
|
|
color:
|
|
type ==
|
|
CompanyType
|
|
.customer
|
|
? Colors
|
|
.blue
|
|
.shade800
|
|
: Colors
|
|
.green
|
|
.shade800,
|
|
fontWeight:
|
|
FontWeight.bold,
|
|
fontSize: 14,
|
|
),
|
|
),
|
|
),
|
|
)
|
|
.toList(),
|
|
),
|
|
),
|
|
DataCell(Text(data['address'].toString())),
|
|
DataCell(Text(data['contactName'] ?? '')),
|
|
DataCell(
|
|
Text(data['contactPosition'] ?? ''),
|
|
),
|
|
DataCell(Text(data['contactPhone'] ?? '')),
|
|
DataCell(Text(data['contactEmail'] ?? '')),
|
|
],
|
|
);
|
|
}).toList(),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|