diff --git a/lib/screens/estimate_screen.dart b/lib/screens/estimate_screen.dart new file mode 100644 index 0000000..22c8bef --- /dev/null +++ b/lib/screens/estimate_screen.dart @@ -0,0 +1,100 @@ +// Version: 1.0.0 +import 'package:flutter/material.dart'; + +/// 見積入力画面(Material Design テンプレート) +class EstimateScreen extends StatelessWidget { + const EstimateScreen({super.key}); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text('見積入力'), + actions: [ + IconButton( + icon: const Icon(Icons.save), + onPressed: () => _showSaveDialog(context), + ), + ], + ), + body: ListView( + padding: const EdgeInsets.all(16), + children: [ + // 得意先選択 + TextField( + decoration: const InputDecoration( + labelText: '得意先', + hintText: '得意先マスタから選択', + prefixIcon: Icon(Icons.person_search), + ), + readOnly: true, + onTap: () => _showCustomerPicker(context), + ), + const SizedBox(height: 16), + + // 商品追加リスト(簡易テンプレート) + Card( + margin: EdgeInsets.zero, + child: ExpansionTile( + title: const Text('見積商品'), + children: [ + ListView.builder( + shrinkWrap: true, + padding: EdgeInsets.zero, + itemCount: 0, // デモ用 + itemBuilder: (context, index) => Card( + margin: const EdgeInsets.symmetric(vertical: 4), + child: ListTile( + leading: CircleAvatar( + backgroundColor: Colors.blue.shade100, + child: Icon(Icons.receipt, color: Colors.blue), + ), + title: Text('商品${index + 1}'), + subtitle: Text('単価:¥${(index + 1) * 1000}'), + ), + ), + ), + ], + ), + ), + ], + ), + ); + } + + void _showSaveDialog(BuildContext context) { + showDialog( + context: context, + builder: (ctx) => AlertDialog( + title: const Text('見積確定'), + content: SingleChildScrollView( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Text('見積データを保存しますか?'), + ], + ), + ), + actions: [ + TextButton( + onPressed: () => Navigator.pop(ctx), + child: const Text('キャンセル'), + ), + ElevatedButton( + onPressed: () { + Navigator.pop(ctx); + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar(content: Text('見積保存しました')), + ); + }, + child: const Text('確定'), + ), + ], + ), + ); + } + + void _showCustomerPicker(BuildContext context) { + // TODO: CustomerPickerModal を再利用して実装 + } +} \ No newline at end of file diff --git a/lib/screens/invoice_screen.dart b/lib/screens/invoice_screen.dart new file mode 100644 index 0000000..b35a57f --- /dev/null +++ b/lib/screens/invoice_screen.dart @@ -0,0 +1,127 @@ +// Version: 1.0.0 +import 'package:flutter/material.dart'; + +/// 請求書発行画面(Material Design テンプレート) +class InvoiceScreen extends StatelessWidget { + const InvoiceScreen({super.key}); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text('請求書発行'), + actions: [ + IconButton( + icon: const Icon(Icons.insert_drive_file), + onPressed: () => _showSaveDialog(context), + ), + ], + ), + body: ListView( + padding: const EdgeInsets.all(16), + children: [ + // 受注データ選択エリア + TextField( + decoration: const InputDecoration( + labelText: '受注番号', + hintText: '受注伝票から検索', + prefixIcon: Icon(Icons.arrow_upward), + ), + readOnly: true, + onTap: () => _showOrderSelection(context), + ), + + const SizedBox(height: 16), + + // 請求書情報表示エリア + Card( + margin: EdgeInsets.zero, + child: Padding( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Text('請求書総額', style: const TextStyle(fontWeight: FontWeight.bold)), + Text('¥0', style: const TextStyle(fontSize: 24, color: Colors.green)), + const SizedBox(height: 8), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text('請求元:'), + Text('株式会社サンプル'), + ], + ), + ], + ), + ), + ), + + const SizedBox(height: 16), + + // 商品リスト(簡易テンプレート) + Card( + margin: EdgeInsets.zero, + child: ExpansionTile( + title: const Text('請求書商品'), + children: [ + ListView.builder( + shrinkWrap: true, + padding: EdgeInsets.zero, + itemCount: 0, // デモ用 + itemBuilder: (context, index) => Card( + margin: const EdgeInsets.symmetric(vertical: 4), + child: ListTile( + leading: CircleAvatar( + backgroundColor: Colors.purple.shade100, + child: Icon(Icons.receipt_long, color: Colors.purple), + ), + title: Text('商品${index + 1}'), + subtitle: Text('数量:0 pcs / 金額:¥0'), + ), + ), + ), + ], + ), + ), + ], + ), + ); + } + + void _showSaveDialog(BuildContext context) { + showDialog( + context: context, + builder: (ctx) => AlertDialog( + title: const Text('請求書発行'), + content: SingleChildScrollView( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Text('請求書を発行しますか?'), + ], + ), + ), + actions: [ + TextButton( + onPressed: () => Navigator.pop(ctx), + child: const Text('キャンセル'), + ), + ElevatedButton( + onPressed: () { + Navigator.pop(ctx); + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar(content: Text('請求書発行しました')), + ); + }, + style: ElevatedButton.styleFrom(backgroundColor: Colors.blue), + child: const Text('発行'), + ), + ], + ), + ); + } + + void _showOrderSelection(BuildContext context) { + // TODO: 受注伝票一覧から選択ダイアログ + } +} \ No newline at end of file diff --git a/lib/screens/order_screen.dart b/lib/screens/order_screen.dart new file mode 100644 index 0000000..4e4ecb0 --- /dev/null +++ b/lib/screens/order_screen.dart @@ -0,0 +1,100 @@ +// Version: 1.0.0 +import 'package:flutter/material.dart'; + +/// 受注入力画面(Material Design テンプレート) +class OrderScreen extends StatelessWidget { + const OrderScreen({super.key}); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text('受注入力'), + actions: [ + IconButton( + icon: const Icon(Icons.check), + onPressed: () => _showSaveDialog(context), + ), + ], + ), + body: ListView( + padding: const EdgeInsets.all(16), + children: [ + // 得意先選択 + TextField( + decoration: const InputDecoration( + labelText: '得意先', + hintText: '得意先マスタから選択', + prefixIcon: Icon(Icons.person_search), + ), + readOnly: true, + onTap: () => _showCustomerPicker(context), + ), + const SizedBox(height: 16), + + // 商品追加リスト(簡易テンプレート) + Card( + margin: EdgeInsets.zero, + child: ExpansionTile( + title: const Text('受注商品'), + children: [ + ListView.builder( + shrinkWrap: true, + padding: EdgeInsets.zero, + itemCount: 0, // デモ用 + itemBuilder: (context, index) => Card( + margin: const EdgeInsets.symmetric(vertical: 4), + child: ListTile( + leading: CircleAvatar( + backgroundColor: Colors.teal.shade100, + child: Icon(Icons.shopping_cart, color: Colors.teal), + ), + title: Text('商品${index + 1}'), + subtitle: Text('数量:1 pcs / 単価:¥0'), + ), + ), + ), + ], + ), + ), + ], + ), + ); + } + + void _showSaveDialog(BuildContext context) { + showDialog( + context: context, + builder: (ctx) => AlertDialog( + title: const Text('受注確定'), + content: SingleChildScrollView( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Text('受注データを保存しますか?'), + ], + ), + ), + actions: [ + TextButton( + onPressed: () => Navigator.pop(ctx), + child: const Text('キャンセル'), + ), + ElevatedButton( + onPressed: () { + Navigator.pop(ctx); + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar(content: Text('受注保存しました')), + ); + }, + child: const Text('確定'), + ), + ], + ), + ); + } + + void _showCustomerPicker(BuildContext context) { + // TODO: CustomerPickerModal を再利用して実装 + } +} \ No newline at end of file diff --git a/lib/screens/sales_return_screen.dart b/lib/screens/sales_return_screen.dart new file mode 100644 index 0000000..c8b4ed2 --- /dev/null +++ b/lib/screens/sales_return_screen.dart @@ -0,0 +1,102 @@ +// Version: 1.0.0 +import 'package:flutter/material.dart'; + +/// 売上返品入力画面(Material Design テンプレート) +class SalesReturnScreen extends StatelessWidget { + const SalesReturnScreen({super.key}); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text('売上返品入力'), + actions: [ + IconButton( + icon: const Icon(Icons.undo), + onPressed: () => _showSaveDialog(context), + ), + ], + ), + body: ListView( + padding: const EdgeInsets.all(16), + children: [ + // 売上返品先選択 + TextField( + decoration: const InputDecoration( + labelText: '元伝票番号', + hintText: '売上伝票から検索', + prefixIcon: Icon(Icons.arrow_downward), + ), + readOnly: true, + onTap: () => _showSalesSelection(context), + ), + + const SizedBox(height: 16), + + // 返品商品リスト(簡易テンプレート) + Card( + margin: EdgeInsets.zero, + child: ExpansionTile( + title: const Text('返品商品'), + children: [ + ListView.builder( + shrinkWrap: true, + padding: EdgeInsets.zero, + itemCount: 0, // デモ用 + itemBuilder: (context, index) => Card( + margin: const EdgeInsets.symmetric(vertical: 4), + child: ListTile( + leading: CircleAvatar( + backgroundColor: Colors.red.shade100, + child: Icon(Icons.inventory_2_outlined, color: Colors.red), + ), + title: Text('返品商品${index + 1}'), + subtitle: Text('数量:-pcs / 単価:¥0'), + ), + ), + ), + ], + ), + ), + ], + ), + ); + } + + void _showSaveDialog(BuildContext context) { + showDialog( + context: context, + builder: (ctx) => AlertDialog( + title: const Text('売上返品確定'), + content: SingleChildScrollView( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Text('返品データを保存しますか?'), + ], + ), + ), + actions: [ + TextButton( + onPressed: () => Navigator.pop(ctx), + child: const Text('キャンセル'), + ), + ElevatedButton( + onPressed: () { + Navigator.pop(ctx); + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar(content: Text('売上返品保存しました')), + ); + }, + style: ElevatedButton.styleFrom(backgroundColor: Colors.red), + child: const Text('確定'), + ), + ], + ), + ); + } + + void _showSalesSelection(BuildContext context) { + // TODO: 売上伝票一覧から選択ダイアログ + } +} \ No newline at end of file diff --git a/lib/screens/sales_screen.dart b/lib/screens/sales_screen.dart new file mode 100644 index 0000000..a2b6230 --- /dev/null +++ b/lib/screens/sales_screen.dart @@ -0,0 +1,135 @@ +// Version: 1.0.0 +import 'package:flutter/material.dart'; + +/// 売上入力画面(レジモードの主戦場)(Material Design テンプレート) +class SalesScreen extends StatelessWidget { + const SalesScreen({super.key}); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text('売上入力'), + actions: [ + IconButton( + icon: const Icon(Icons.receipt_long), + onPressed: () => _showSaveDialog(context), + ), + ], + ), + body: ListView( + padding: const EdgeInsets.all(16), + children: [ + // レジモードのメイン表示エリア + Card( + margin: EdgeInsets.zero, + child: Padding( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + // 合計金額表示 + Text( + '合計:¥0', + style: const TextStyle( + fontSize: 32, + fontWeight: FontWeight.bold, + color: Colors.black87, + ), + ), + const SizedBox(height: 16), + + // 税率/税額表示 + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text('税別:¥0'), + Text('税込:¥0', style: const TextStyle(fontWeight: FontWeight.bold)), + ], + ), + ], + ), + ), + ), + + const SizedBox(height: 16), + + // 商品入力エリア + TextField( + decoration: const InputDecoration( + labelText: '商品検索', + hintText: 'JAN コードまたは商品名を入力', + prefixIcon: Icon(Icons.search), + ), + onChanged: (value) { /* TODO: 商品検索 */ }, + ), + + const SizedBox(height: 16), + + // 商品リスト + Card( + margin: EdgeInsets.zero, + child: ExpansionTile( + title: const Text('売上商品'), + children: [ + ListView.builder( + shrinkWrap: true, + padding: EdgeInsets.zero, + itemCount: 0, // デモ用 + itemBuilder: (context, index) => Card( + margin: const EdgeInsets.symmetric(vertical: 4), + child: ListTile( + leading: CircleAvatar( + backgroundColor: Colors.orange.shade100, + child: Icon(Icons.store, color: Colors.orange), + ), + title: Text('商品${index + 1}'), + subtitle: Text('数量:0 pcs / 単価:¥0'), + ), + ), + ), + ], + ), + ), + ], + ), + ); + } + + void _showSaveDialog(BuildContext context) { + showDialog( + context: context, + builder: (ctx) => AlertDialog( + title: const Text('売上確定'), + content: SingleChildScrollView( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Text('売上データを保存しますか?'), + ], + ), + ), + actions: [ + TextButton( + onPressed: () => Navigator.pop(ctx), + child: const Text('キャンセル'), + ), + ElevatedButton( + onPressed: () { + Navigator.pop(ctx); + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar(content: Text('売上保存しました')), + ); + }, + style: ElevatedButton.styleFrom(backgroundColor: Colors.green), + child: const Text('確定'), + ), + ], + ), + ); + } + + void _showCustomerPicker(BuildContext context) { + // TODO: CustomerPickerModal を再利用して実装 + } +} \ No newline at end of file