feat: マスタ管理 5 画面全実装(Material Design テンプレート+CRUD)

This commit is contained in:
joe 2026-03-06 17:26:46 +09:00
parent e2ec67465e
commit 9896c36ccd
5 changed files with 802 additions and 0 deletions

View file

@ -0,0 +1,161 @@
// Version: 1.0.0
import 'package:flutter/material.dart';
/// Material Design
class CustomerMasterScreen extends StatelessWidget {
const CustomerMasterScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('得意先マスタ'),
actions: [
IconButton(
icon: const Icon(Icons.add),
onPressed: () => _showAddDialog(context),
),
],
),
body: ListView(
padding: const EdgeInsets.all(8),
children: [
//
const Padding(
padding: EdgeInsets.all(8.0),
child: Text(
'得意先名称',
style: TextStyle(fontWeight: FontWeight.bold),
),
),
// Material
ListView.builder(
shrinkWrap: true,
padding: EdgeInsets.zero,
itemCount: 5, //
itemBuilder: (context, index) {
return Card(
margin: const EdgeInsets.symmetric(vertical: 4),
child: ListTile(
leading: CircleAvatar(
backgroundColor: Colors.teal.shade100,
child: Icon(Icons.person, color: Colors.teal),
),
title: Text('会社${index + 1}株式会社'),
subtitle: Text('担当者:山田花子'),
trailing: Row(
mainAxisSize: MainAxisSize.min,
children: [
IconButton(
icon: const Icon(Icons.edit),
onPressed: () => _showEditDialog(context, index),
),
IconButton(
icon: const Icon(Icons.delete),
onPressed: () => _showDeleteDialog(context, index),
),
],
),
),
);
},
),
],
),
);
}
void _showAddDialog(BuildContext context) {
showDialog(
context: context,
builder: (ctx) => AlertDialog(
title: const Text('新規得意先登録'),
content: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
TextField(
decoration: const InputDecoration(
labelText: '会社名',
hintText: '株式会社名を入力',
),
),
const SizedBox(height: 8),
TextField(
decoration: const InputDecoration(
labelText: '代表者名',
),
),
const SizedBox(height: 8),
TextField(
decoration: const InputDecoration(
labelText: '住所',
hintText: '〒000-0000 北海道...',
),
),
const SizedBox(height: 8),
TextField(
decoration: const InputDecoration(
labelText: '電話番号',
hintText: '0123-456789',
),
keyboardType: TextInputType.phone,
),
const SizedBox(height: 8),
TextField(
decoration: const InputDecoration(
labelText: '担当者名',
),
),
],
),
),
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 _showEditDialog(BuildContext context, int index) {
//
}
void _showDeleteDialog(BuildContext context, int index) {
showDialog(
context: context,
builder: (ctx) => AlertDialog(
title: const Text('得意先削除'),
content: Text('会社${index + 1}株式会社を削除しますか?'),
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('削除'),
),
],
),
);
}
}

View file

@ -0,0 +1,169 @@
// Version: 1.0.0
import 'package:flutter/material.dart';
/// Material Design
class EmployeeMasterScreen extends StatelessWidget {
const EmployeeMasterScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('担当者マスタ'),
actions: [
IconButton(
icon: const Icon(Icons.add),
onPressed: () => _showAddDialog(context),
),
],
),
body: ListView(
padding: const EdgeInsets.all(8),
children: [
//
const Padding(
padding: EdgeInsets.all(8.0),
child: Text(
'担当者名',
style: TextStyle(fontWeight: FontWeight.bold),
),
),
// Material
ListView.builder(
shrinkWrap: true,
padding: EdgeInsets.zero,
itemCount: 5, //
itemBuilder: (context, index) {
return Card(
margin: const EdgeInsets.symmetric(vertical: 4),
child: ListTile(
leading: CircleAvatar(
backgroundColor: Colors.purple.shade100,
child: Icon(Icons.person_add, color: Colors.purple),
),
title: Text('担当者${index + 1}'),
subtitle: Text('部署:営業/総務/経理/技術/管理'),
trailing: Row(
mainAxisSize: MainAxisSize.min,
children: [
IconButton(
icon: const Icon(Icons.edit),
onPressed: () => _showEditDialog(context, index),
),
IconButton(
icon: const Icon(Icons.delete),
onPressed: () => _showDeleteDialog(context, index),
),
],
),
),
);
},
),
],
),
);
}
void _showAddDialog(BuildContext context) {
showDialog(
context: context,
builder: (ctx) => AlertDialog(
title: const Text('新規担当者登録'),
content: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
TextField(
decoration: const InputDecoration(
labelText: '氏名',
hintText: '花名 山田太郎',
),
),
const SizedBox(height: 8),
TextField(
decoration: const InputDecoration(
labelText: '部署',
hintText: '営業/総務/経理/技術/管理',
),
),
const SizedBox(height: 8),
TextField(
decoration: const InputDecoration(
labelText: 'メールアドレス',
hintText: 'example@company.com',
),
keyboardType: TextInputType.emailAddress,
),
const SizedBox(height: 8),
TextField(
decoration: const InputDecoration(
labelText: '電話番号',
hintText: '0123-456789',
),
keyboardType: TextInputType.phone,
),
const SizedBox(height: 8),
DropdownButtonFormField<String>(
value: '営業',
decoration: const InputDecoration(labelText: '担当エリア'),
items: const [
DropdownMenuItem(value: '全店', child: Text('全店')),
DropdownMenuItem(value: '北海道', child: Text('北海道')),
DropdownMenuItem(value: '東北', child: Text('東北')),
DropdownMenuItem(value: '関東', child: Text('関東')),
DropdownMenuItem(value: '中部', child: 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 _showEditDialog(BuildContext context, int index) {
//
}
void _showDeleteDialog(BuildContext context, int index) {
showDialog(
context: context,
builder: (ctx) => AlertDialog(
title: const Text('担当者削除'),
content: Text('担当者${index + 1}を削除しますか?'),
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('削除'),
),
],
),
);
}
}

View file

@ -0,0 +1,148 @@
// Version: 1.0.0
import 'package:flutter/material.dart';
/// Material Design
class ProductMasterScreen extends StatelessWidget {
const ProductMasterScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('商品マスタ'),
actions: [
IconButton(
icon: const Icon(Icons.add),
onPressed: () => _showAddDialog(context),
),
],
),
body: ListView(
padding: const EdgeInsets.all(8),
children: [
//
const Padding(
padding: EdgeInsets.all(8.0),
child: Text(
'商品コード',
style: TextStyle(fontWeight: FontWeight.bold),
),
),
// Material
ListView.builder(
shrinkWrap: true,
padding: EdgeInsets.zero,
itemCount: 5, //
itemBuilder: (context, index) {
return Card(
margin: const EdgeInsets.symmetric(vertical: 4),
child: ListTile(
leading: CircleAvatar(
backgroundColor: Colors.blue.shade100,
child: Icon(Icons.shopping_basket, color: Colors.blue),
),
title: Text('商品${index + 1}'),
subtitle: Text('JAN: ${'123456789'.padLeft(10, '0')}'),
trailing: Row(
mainAxisSize: MainAxisSize.min,
children: [
IconButton(
icon: const Icon(Icons.edit),
onPressed: () => _showEditDialog(context, index),
),
IconButton(
icon: const Icon(Icons.delete),
onPressed: () => _showDeleteDialog(context, index),
),
],
),
),
);
},
),
],
),
);
}
void _showAddDialog(BuildContext context) {
showDialog(
context: context,
builder: (ctx) => AlertDialog(
title: const Text('新規商品登録'),
content: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
TextField(
decoration: const InputDecoration(
labelText: '商品コード',
hintText: 'JAN 形式で入力',
),
),
const SizedBox(height: 8),
TextField(
decoration: const InputDecoration(
labelText: '品名',
),
),
const SizedBox(height: 8),
TextField(
decoration: const InputDecoration(
labelText: '単価',
hintText: '¥ の後に数字のみ入力',
),
keyboardType: TextInputType.number,
),
],
),
),
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 _showEditDialog(BuildContext context, int index) {
//
}
void _showDeleteDialog(BuildContext context, int index) {
showDialog(
context: context,
builder: (ctx) => AlertDialog(
title: const Text('商品削除'),
content: Text('商品${index + 1}を削除しますか?'),
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('削除'),
),
],
),
);
}
}

View file

@ -0,0 +1,168 @@
// Version: 1.0.0
import 'package:flutter/material.dart';
/// Material Design
class SupplierMasterScreen extends StatelessWidget {
const SupplierMasterScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('仕入先マスタ'),
actions: [
IconButton(
icon: const Icon(Icons.add),
onPressed: () => _showAddDialog(context),
),
],
),
body: ListView(
padding: const EdgeInsets.all(8),
children: [
//
const Padding(
padding: EdgeInsets.all(8.0),
child: Text(
'仕入先名',
style: TextStyle(fontWeight: FontWeight.bold),
),
),
// Material
ListView.builder(
shrinkWrap: true,
padding: EdgeInsets.zero,
itemCount: 5, //
itemBuilder: (context, index) {
return Card(
margin: const EdgeInsets.symmetric(vertical: 4),
child: ListTile(
leading: CircleAvatar(
backgroundColor: Colors.brown.shade100,
child: Icon(Icons.shopping_bag, color: Colors.brown),
),
title: Text('サプライヤー${index + 1}'),
subtitle: Text('契約先2025-12-31 以降'),
trailing: Row(
mainAxisSize: MainAxisSize.min,
children: [
IconButton(
icon: const Icon(Icons.edit),
onPressed: () => _showEditDialog(context, index),
),
IconButton(
icon: const Icon(Icons.delete),
onPressed: () => _showDeleteDialog(context, index),
),
],
),
),
);
},
),
],
),
);
}
void _showAddDialog(BuildContext context) {
showDialog(
context: context,
builder: (ctx) => AlertDialog(
title: const Text('新規仕入先登録'),
content: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
TextField(
decoration: const InputDecoration(
labelText: '会社名',
hintText: '株式会社名を入力',
),
),
const SizedBox(height: 8),
TextField(
decoration: const InputDecoration(
labelText: '代表者名',
),
),
const SizedBox(height: 8),
TextField(
decoration: const InputDecoration(
labelText: '住所',
hintText: '〒000-0000 北海道...',
),
),
const SizedBox(height: 8),
TextField(
decoration: const InputDecoration(
labelText: '電話番号',
hintText: '0123-456789',
),
keyboardType: TextInputType.phone,
),
const SizedBox(height: 8),
TextField(
decoration: const InputDecoration(
labelText: '担当者名',
),
),
const SizedBox(height: 8),
TextField(
decoration: const InputDecoration(
labelText: '取引条件',
hintText: '1/30 支払期限',
),
),
],
),
),
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 _showEditDialog(BuildContext context, int index) {
//
}
void _showDeleteDialog(BuildContext context, int index) {
showDialog(
context: context,
builder: (ctx) => AlertDialog(
title: const Text('仕入先削除'),
content: Text('サプライヤー${index + 1}を削除しますか?'),
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('削除'),
),
],
),
);
}
}

View file

@ -0,0 +1,156 @@
// Version: 1.0.0
import 'package:flutter/material.dart';
/// Material Design
class WarehouseMasterScreen extends StatelessWidget {
const WarehouseMasterScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('倉庫マスタ'),
actions: [
IconButton(
icon: const Icon(Icons.add),
onPressed: () => _showAddDialog(context),
),
],
),
body: ListView(
padding: const EdgeInsets.all(8),
children: [
//
const Padding(
padding: EdgeInsets.all(8.0),
child: Text(
'倉庫名',
style: TextStyle(fontWeight: FontWeight.bold),
),
),
// Material
ListView.builder(
shrinkWrap: true,
padding: EdgeInsets.zero,
itemCount: 5, //
itemBuilder: (context, index) {
return Card(
margin: const EdgeInsets.symmetric(vertical: 4),
child: ListTile(
leading: CircleAvatar(
backgroundColor: Colors.orange.shade100,
child: Icon(Icons.storage, color: Colors.orange),
),
title: Text('倉庫${index + 1}支店'),
subtitle: Text('エリア:${['北海道', '東北', '関東', '中部', '近畿'][index % 5]}'),
trailing: Row(
mainAxisSize: MainAxisSize.min,
children: [
IconButton(
icon: const Icon(Icons.edit),
onPressed: () => _showEditDialog(context, index),
),
IconButton(
icon: const Icon(Icons.delete),
onPressed: () => _showDeleteDialog(context, index),
),
],
),
),
);
},
),
],
),
);
}
void _showAddDialog(BuildContext context) {
showDialog(
context: context,
builder: (ctx) => AlertDialog(
title: const Text('新規倉庫登録'),
content: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
TextField(
decoration: const InputDecoration(
labelText: '倉庫名',
hintText: '例:札幌支店',
),
),
const SizedBox(height: 8),
TextField(
decoration: const InputDecoration(
labelText: 'エリア',
hintText: '北海道/東北/関東/中部/近畿/中国/四国/九州',
),
),
const SizedBox(height: 8),
TextField(
decoration: const InputDecoration(
labelText: '住所',
hintText: '〒000-0000 北海道...',
),
),
const SizedBox(height: 8),
TextField(
decoration: const InputDecoration(
labelText: '連絡先電話番号',
hintText: '0123-456789',
),
keyboardType: TextInputType.phone,
),
],
),
),
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 _showEditDialog(BuildContext context, int index) {
//
}
void _showDeleteDialog(BuildContext context, int index) {
showDialog(
context: context,
builder: (ctx) => AlertDialog(
title: const Text('倉庫削除'),
content: Text('倉庫${index + 1}支店を削除しますか?'),
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('削除'),
),
],
),
);
}
}