import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; import '../models/invoice_models.dart'; import '../services/invoice_repository.dart'; import 'invoice_detail_page.dart'; /// 帳票(見積・納品・請求・領収)の履歴一覧を表示・管理する画面 class InvoiceHistoryScreen extends StatefulWidget { const InvoiceHistoryScreen({Key? key}) : super(key: key); @override State createState() => _InvoiceHistoryScreenState(); } class _InvoiceHistoryScreenState extends State { final InvoiceRepository _repository = InvoiceRepository(); List _invoices = []; bool _isLoading = true; @override void initState() { super.initState(); _loadInvoices(); } /// DBから履歴を読み込む Future _loadInvoices() async { setState(() => _isLoading = true); final data = await _repository.getAllInvoices(); setState(() { _invoices = data; _isLoading = false; }); } /// 不要な(DBに紐付かない)PDFファイルを一括削除 Future _cleanupFiles() async { final count = await _repository.cleanupOrphanedPdfs(); if (mounted) { ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text('$count 個の不要なPDFファイルを削除しました')), ); } } /// 履歴から個別に削除 Future _deleteInvoice(Invoice invoice) async { final confirmed = await showDialog( context: context, builder: (context) => AlertDialog( title: const Text("削除の確認"), content: Text("${invoice.type.label}番号: ${invoice.invoiceNumber}\nこのデータを削除しますか?\n(実体PDFファイルも削除されます)"), actions: [ TextButton(onPressed: () => Navigator.pop(context, false), child: const Text("キャンセル")), TextButton( onPressed: () => Navigator.pop(context, true), child: const Text("削除する", style: TextStyle(color: Colors.red)), ), ], ), ); if (confirmed == true) { await _repository.deleteInvoice(invoice); _loadInvoices(); } } @override Widget build(BuildContext context) { final amountFormatter = NumberFormat("#,###"); final dateFormatter = DateFormat('yyyy/MM/dd HH:mm'); return Scaffold( appBar: AppBar( title: const Text("発行履歴管理"), backgroundColor: Colors.blueGrey, foregroundColor: Colors.white, actions: [ IconButton( icon: const Icon(Icons.cleaning_services), tooltip: "ゴミファイルを掃除", onPressed: _cleanupFiles, ), IconButton( icon: const Icon(Icons.refresh), onPressed: _loadInvoices, ), ], ), body: _isLoading ? const Center(child: CircularProgressIndicator()) : _invoices.isEmpty ? Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon(Icons.history, size: 64, color: Colors.grey.shade300), const SizedBox(height: 16), const Text("発行済みの帳票はありません", style: TextStyle(color: Colors.grey)), ], ), ) : ListView.builder( itemCount: _invoices.length, itemBuilder: (context, index) { final invoice = _invoices[index]; return Card( margin: const EdgeInsets.symmetric(horizontal: 12, vertical: 6), child: ListTile( leading: Stack( alignment: Alignment.bottomRight, children: [ const CircleAvatar( backgroundColor: Colors.indigo, child: Icon(Icons.description, color: Colors.white), ), if (invoice.isShared) Container( decoration: const BoxDecoration( color: Colors.white, shape: BoxShape.circle, ), child: const Icon( Icons.check_circle, color: Colors.green, size: 18, ), ), ], ), title: Row( children: [ Container( padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2), decoration: BoxDecoration( color: Colors.blueGrey.shade100, borderRadius: BorderRadius.circular(4), ), child: Text( invoice.type.label, style: const TextStyle(fontSize: 10, fontWeight: FontWeight.bold), ), ), const SizedBox(width: 8), Expanded( child: Text( invoice.customer.formalName, style: const TextStyle(fontWeight: FontWeight.bold), overflow: TextOverflow.ellipsis, ), ), ], ), subtitle: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text("No: ${invoice.invoiceNumber}"), Text(dateFormatter.format(invoice.date), style: const TextStyle(fontSize: 12)), ], ), trailing: Text( "¥${amountFormatter.format(invoice.totalAmount)}", style: const TextStyle( fontWeight: FontWeight.bold, color: Colors.indigo, fontSize: 16, ), ), onTap: () async { await Navigator.push( context, MaterialPageRoute( builder: (context) => InvoiceDetailPage(invoice: invoice), ), ); _loadInvoices(); }, onLongPress: () => _deleteInvoice(invoice), ), ); }, ), ); } }