162 lines
No EOL
6.1 KiB
Dart
162 lines
No EOL
6.1 KiB
Dart
// Version: 1.9 - 倉庫マスタ画面(簡素版として維持)
|
||
// ※ DB モデルと同期していないため簡素版のまま
|
||
|
||
import 'package:flutter/material.dart';
|
||
|
||
/// 倉庫マスタ管理画面(CRUD 機能付き - 簡素版)
|
||
class WarehouseMasterScreen extends StatefulWidget {
|
||
const WarehouseMasterScreen({super.key});
|
||
|
||
@override
|
||
State<WarehouseMasterScreen> createState() => _WarehouseMasterScreenState();
|
||
}
|
||
|
||
class _WarehouseMasterScreenState extends State<WarehouseMasterScreen> {
|
||
List<Map<String, dynamic>> _warehouses = [];
|
||
bool _loading = true;
|
||
|
||
@override
|
||
void initState() {
|
||
super.initState();
|
||
_loadWarehouses();
|
||
}
|
||
|
||
Future<void> _loadWarehouses() async {
|
||
setState(() => _loading = true);
|
||
try {
|
||
final demoData = [
|
||
{'id': 1, 'name': '札幌倉庫', 'area': '北海道', 'address': '〒040-0001 札幌市中央区'},
|
||
{'id': 2, 'name': '仙台倉庫', 'area': '東北', 'address': '〒980-0001 仙台市青葉区'},
|
||
{'id': 3, 'name': '東京倉庫', 'area': '関東', 'address': '〒100-0001 東京都千代田区'},
|
||
{'id': 4, 'name': '名古屋倉庫', 'area': '中部', 'address': '〒460-0001 名古屋市中村区'},
|
||
{'id': 5, 'name': '大阪倉庫', 'area': '近畿', 'address': '〒530-0001 大阪市中央区'},
|
||
];
|
||
setState(() => _warehouses = demoData);
|
||
} catch (e) {
|
||
if (mounted) ScaffoldMessenger.of(context).showSnackBar(
|
||
SnackBar(content: Text('読み込みエラー:$e'), backgroundColor: Colors.red),
|
||
);
|
||
} finally {
|
||
setState(() => _loading = false);
|
||
}
|
||
}
|
||
|
||
Future<void> _addWarehouse() async {
|
||
final warehouse = <String, dynamic>{'id': DateTime.now().millisecondsSinceEpoch, 'name': '', 'area': '', 'address': ''};
|
||
|
||
final result = await showDialog<Map<String, dynamic>>(
|
||
context: context,
|
||
builder: (context) => _WarehouseDialogState(
|
||
Dialog(
|
||
child: SingleChildScrollView(
|
||
padding: EdgeInsets.zero,
|
||
child: ConstrainedBox(
|
||
constraints: const BoxConstraints(minHeight: 200),
|
||
child: WarehouseForm(warehouse: warehouse),
|
||
),
|
||
),
|
||
),
|
||
),
|
||
);
|
||
|
||
if (result != null && mounted) {
|
||
setState(() => _warehouses.add(result));
|
||
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text('倉庫登録完了'), backgroundColor: Colors.green));
|
||
}
|
||
}
|
||
|
||
Future<void> _editWarehouse(int id) async {
|
||
final warehouse = _warehouses.firstWhere((w) => w['id'] == id);
|
||
final edited = await showDialog<Map<String, dynamic>>(
|
||
context: context,
|
||
builder: (context) => _WarehouseDialogState(
|
||
Dialog(
|
||
child: SingleChildScrollView(
|
||
padding: EdgeInsets.zero,
|
||
child: ConstrainedBox(
|
||
constraints: const BoxConstraints(minHeight: 200),
|
||
child: WarehouseForm(warehouse: warehouse),
|
||
),
|
||
),
|
||
),
|
||
),
|
||
);
|
||
|
||
if (edited != null && mounted) {
|
||
final index = _warehouses.indexWhere((w) => w['id'] == id);
|
||
setState(() => _warehouses[index] = edited);
|
||
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text('倉庫更新完了'), backgroundColor: Colors.green));
|
||
}
|
||
}
|
||
|
||
Future<void> _deleteWarehouse(int id) async {
|
||
final confirmed = await showDialog<bool>(
|
||
context: context,
|
||
builder: (context) => AlertDialog(
|
||
title: const Text('倉庫削除'),
|
||
content: Text('この倉庫を削除しますか?'),
|
||
actions: [
|
||
TextButton(onPressed: () => Navigator.pop(context), child: const Text('キャンセル')),
|
||
ElevatedButton(
|
||
onPressed: () => Navigator.pop(context, true),
|
||
style: ElevatedButton.styleFrom(backgroundColor: Colors.red),
|
||
child: const Text('削除'),
|
||
),
|
||
],
|
||
),
|
||
);
|
||
|
||
if (confirmed == true) {
|
||
setState(() {
|
||
_warehouses.removeWhere((w) => w['id'] == id);
|
||
});
|
||
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text('倉庫削除完了'), backgroundColor: Colors.green));
|
||
}
|
||
}
|
||
|
||
@override
|
||
Widget build(BuildContext context) {
|
||
return Scaffold(
|
||
appBar: AppBar(
|
||
title: const Text('/M4. 倉庫マスタ'),
|
||
actions: [
|
||
IconButton(icon: const Icon(Icons.refresh), onPressed: _loadWarehouses),
|
||
IconButton(icon: const Icon(Icons.add), onPressed: _addWarehouse),
|
||
],
|
||
),
|
||
body: _loading ? const Center(child: CircularProgressIndicator()) :
|
||
_warehouses.isEmpty ? Center(child: Text('倉庫データがありません')) :
|
||
ListView.builder(
|
||
padding: const EdgeInsets.all(8),
|
||
itemCount: _warehouses.length,
|
||
itemBuilder: (context, index) {
|
||
final warehouse = _warehouses[index];
|
||
return Card(
|
||
margin: const EdgeInsets.only(bottom: 8),
|
||
child: ListTile(
|
||
leading: CircleAvatar(backgroundColor: Colors.orange.shade50, child: Icon(Icons.storage, color: Colors.orange)),
|
||
title: Text(warehouse['name'] ?? '倉庫(未入力)'),
|
||
subtitle: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
|
||
Text('エリア:${warehouse['area']}'),
|
||
if (warehouse['address'] != null) Text('住所:${warehouse['address']}'),
|
||
]),
|
||
trailing: Row(
|
||
mainAxisSize: MainAxisSize.min,
|
||
children: [
|
||
IconButton(icon: const Icon(Icons.edit), onPressed: () => _editWarehouse(warehouse['id'] as int)),
|
||
IconButton(icon: const Icon(Icons.delete), onPressed: () => _deleteWarehouse(warehouse['id'] as int)),
|
||
],
|
||
),
|
||
),
|
||
);
|
||
},
|
||
),
|
||
);
|
||
}
|
||
}
|
||
|
||
/// 倉庫フォーム部品(簡素版)
|
||
class WarehouseForm extends StatelessWidget {
|
||
final Map<String, dynamic> warehouse;
|
||
|
||
const |