// Version: 3.0 - シンプル得意先マスタ画面(簡素版) // ※ MasterEditDialog を使用するため、独自の実装は不要です import 'package:flutter/material.dart'; import '../../models/customer.dart'; import '../../services/database_helper.dart'; import 'master_edit_dialog.dart'; class CustomerMasterScreen extends StatefulWidget { const CustomerMasterScreen({super.key}); @override State createState() => _CustomerMasterScreenState(); } class _CustomerMasterScreenState extends State { final DatabaseHelper _db = DatabaseHelper.instance; List _customers = []; bool _isLoading = true; @override void initState() { super.initState(); _loadCustomers(); } Future _loadCustomers() async { try { final customers = await _db.getCustomers(); if (mounted) setState(() { _customers = customers ?? const []; _isLoading = false; }); } catch (e) { if (!mounted) return; ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text('顧客データを読み込みませんでした:$e'), backgroundColor: Colors.red), ); } } Future _addCustomer() async { final customer = await showDialog( context: context, builder: (ctx) => MasterEditDialog( title: '新規得意先登録', onSave: (data) async { if (mounted) { setState(() => _customers.insert(0, data)); await _db.insertCustomer(data); ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('顧客を登録しました'), backgroundColor: Colors.green), ); _loadCustomers(); } return true; }, ), ); if (customer != null) _loadCustomers(); } Future _editCustomer(Customer customer) async { final updated = await showDialog( context: context, builder: (ctx) => MasterEditDialog( title: '得意先編集', initialData: customer, showStatusFields: true, onSave: (data) async { if (mounted) { await _db.updateCustomer(data); ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('顧客を更新しました'), backgroundColor: Colors.green), ); _loadCustomers(); } return true; }, ), ); if (updated != null) _loadCustomers(); } Future _deleteCustomer(int id) async { final confirmed = await showDialog( context: context, builder: (ctx) => AlertDialog( title: const Text('顧客削除'), content: Text('この顧客を削除しますか?履歴データも消去されます。'), actions: [ TextButton(onPressed: () => Navigator.pop(ctx, false), child: const Text('キャンセル')), ElevatedButton( onPressed: () => Navigator.pop(ctx, true), style: ElevatedButton.styleFrom(backgroundColor: Colors.red), child: const Text('削除'), ), ], ), ); if (confirmed == true) { try { await _db.deleteCustomer(id); ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('顧客を削除しました'), backgroundColor: Colors.green), ); _loadCustomers(); } catch (e) { ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text('削除に失敗:$e'), backgroundColor: Colors.red), ); } } } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('/M2. 得意先マスタ')), body: _isLoading ? const Center(child: CircularProgressIndicator()) : _customers.isEmpty ? Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon(Icons.inbox_outlined, size: 64, color: Colors.grey[300]), SizedBox(height: 16), Text('得意先データがありません', style: TextStyle(color: Colors.grey)), SizedBox(height: 16), FloatingActionButton.extended( icon: Icon(Icons.add, color: Theme.of(context).primaryColor), label: const Text('新規登録'), onPressed: _addCustomer, ), ], ), ) : ListView.builder( padding: const EdgeInsets.all(8), itemCount: _customers.length, itemBuilder: (context, index) { final customer = _customers[index]; return Card( margin: const EdgeInsets.only(bottom: 8), elevation: 4, child: ListTile( leading: CircleAvatar(backgroundColor: Colors.blue.shade100, child: const Icon(Icons.person, color: Colors.blue)), title: Text(customer.name ?? '未入力'), subtitle: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ if (customer.email.isNotEmpty) Text('Email: ${customer.email}', style: const TextStyle(fontSize: 12)), Text('登録日:${DateFormat('yyyy/MM/dd').format(customer.createdAt ?? DateTime.now())}'), ], ), trailing: Row( mainAxisSize: MainAxisSize.min, children: [ IconButton(icon: const Icon(Icons.edit), onPressed: () => _editCustomer(customer)), PopupMenuButton( onSelected: (value) => value == 'delete' ? _deleteCustomer(customer.id ?? 0) : null, itemBuilder: (ctx) => [ PopupMenuItem(child: const Text('詳細'), onPressed: () => _showDetail(context, customer)), PopupMenuItem(child: const Text('削除'), onPressed: () => _deleteCustomer(customer.id ?? 0)), ], ), ], ), ), ); }, ), floatingActionButton: FloatingActionButton.extended( icon: const Icon(Icons.add), label: const Text('新規登録'), onPressed: _addCustomer, ), ); } Future _showDetail(BuildContext context, Customer customer) async { showDialog( context: context, builder: (ctx) => AlertDialog( title: const Text('顧客詳細'), content: SingleChildScrollView( child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ _detailRow('得意先コード', customer.customerCode ?? '-'), _detailRow('名称', customer.name ?? '-'), _detailRow('Email', customer.email.isNotEmpty ? customer.email : '-'), _detailRow('登録日', DateFormat('yyyy/MM/dd').format(customer.createdAt)), ], ), ), actions: [TextButton(onPressed: () => Navigator.pop(ctx), child: const Text('閉じる'))], ), ); } Widget _detailRow(String label, String value) { return Padding( padding: const EdgeInsets.only(bottom: 12), child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ SizedBox(width: 80), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(label, style: TextStyle(fontWeight: FontWeight.bold)), if (value != '-') Text(value), ], ), ), ], ), ); } Future _onCopyFromOtherMaster() async { final selected = await showDialog( context: context, builder: (ctx) => AlertDialog( title: const Text('他のマスタからコピー'), content: Column( mainAxisSize: MainAxisSize.min, children: [ ListTile(leading: Icon(Icons.store, color: Colors.blue), title: const Text('仕入先マスタから'), onTap: () => Navigator.pop(ctx, 'supplier')), ListTile(leading: Icon(Icons.inventory_2, color: Colors.orange), title: const Text('商品マスタから'), onTap: () => Navigator.pop(ctx, 'product')), ], ), actions: [ TextButton(onPressed: () => Navigator.pop(ctx), child: const Text('キャンセル')), ], ), ); if (selected != null && mounted) { ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('コピー機能は後期開発:$selected'))); } } }