hesabixArc/hesabixUI/hesabix_ui/lib/pages/business/warehouses_page.dart

219 lines
7.5 KiB
Dart
Raw Normal View History

2025-10-27 22:17:45 +03:30
import 'package:flutter/material.dart';
import '../../services/warehouse_service.dart';
import '../../models/warehouse_model.dart';
2025-11-02 13:11:38 +03:30
import '../../widgets/data_table/data_table_widget.dart';
import '../../widgets/data_table/data_table_config.dart';
2025-10-27 22:17:45 +03:30
class WarehousesPage extends StatefulWidget {
final int businessId;
const WarehousesPage({super.key, required this.businessId});
@override
State<WarehousesPage> createState() => _WarehousesPageState();
}
class _WarehousesPageState extends State<WarehousesPage> {
final WarehouseService _service = WarehouseService();
2025-11-02 13:11:38 +03:30
final GlobalKey _tableKey = GlobalKey();
2025-10-27 22:17:45 +03:30
2025-11-02 13:11:38 +03:30
void _refreshTable() {
2025-10-27 22:17:45 +03:30
try {
2025-11-02 13:11:38 +03:30
final current = _tableKey.currentState as dynamic;
current?.refresh();
} catch (_) {}
2025-10-27 22:17:45 +03:30
}
@override
Widget build(BuildContext context) {
return Scaffold(
2025-11-02 13:11:38 +03:30
body: DataTableWidget<Warehouse>(
key: _tableKey,
fromJson: (m) => Warehouse.fromJson(m),
config: DataTableConfig<Warehouse>(
endpoint: '/api/v1/warehouses/business/${widget.businessId}/query',
title: 'فهرست انبارها',
showBackButton: true,
onBack: () => Navigator.of(context).maybePop(),
showTableIcon: false,
showSearch: true,
showPagination: true,
showRowNumbers: true,
enableSorting: true,
searchFields: const ['code', 'name', 'description'],
customHeaderActions: [
Tooltip(
message: 'افزودن انبار',
child: IconButton(
onPressed: _showCreateDialog,
icon: const Icon(Icons.add),
),
),
],
columns: [
ActionColumn('actions', 'عملیات', actions: [
DataTableAction(
icon: Icons.edit_outlined,
label: 'ویرایش',
onTap: (item) {
if (item is Warehouse) _showEditDialog(item);
},
),
DataTableAction(
icon: Icons.delete_outline,
label: 'حذف',
onTap: (item) {
if (item is Warehouse) _delete(item);
},
isDestructive: true,
),
]),
TextColumn('code', 'کد',
formatter: (item) => (item as Warehouse).code,
width: ColumnWidth.small),
TextColumn('name', 'نام',
formatter: (item) => (item as Warehouse).name,
width: ColumnWidth.medium),
TextColumn('description', 'توضیحات',
formatter: (item) => (item as Warehouse).description ?? '',
width: ColumnWidth.large,
searchable: true),
TextColumn('is_default', 'پیش‌فرض',
formatter: (item) => (item as Warehouse).isDefault ? 'بله' : 'خیر',
sortable: false,
searchable: false,
width: ColumnWidth.small),
DateColumn('created_at', 'ایجاد',
formatter: (item) => (item as Warehouse).createdAt?.toIso8601String() ?? '',
showTime: false,
width: ColumnWidth.small),
],
),
2025-10-27 22:17:45 +03:30
),
);
}
Future<void> _showCreateDialog() async {
final codeCtrl = TextEditingController();
final nameCtrl = TextEditingController();
bool isDefault = false;
final ok = await showDialog<bool>(
context: context,
builder: (_) => AlertDialog(
title: const Text('افزودن انبار'),
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
TextField(controller: codeCtrl, decoration: const InputDecoration(labelText: 'کد')),
TextField(controller: nameCtrl, decoration: const InputDecoration(labelText: 'نام')),
StatefulBuilder(builder: (ctx, setSt) {
return CheckboxListTile(
value: isDefault,
onChanged: (v) => setSt(() => isDefault = v ?? false),
title: const Text('پیش‌فرض'),
controlAffinity: ListTileControlAffinity.leading,
);
}),
],
),
actions: [
TextButton(onPressed: () => Navigator.of(context).pop(false), child: const Text('انصراف')),
FilledButton(onPressed: () => Navigator.of(context).pop(true), child: const Text('ذخیره')),
],
),
);
if (ok != true) return;
try {
2025-11-02 13:11:38 +03:30
await _service.createWarehouse(
2025-10-27 22:17:45 +03:30
businessId: widget.businessId,
payload: {
'code': codeCtrl.text.trim(),
'name': nameCtrl.text.trim(),
'is_default': isDefault,
},
);
if (!mounted) return;
2025-11-02 13:11:38 +03:30
_refreshTable();
2025-10-27 22:17:45 +03:30
} catch (e) {
if (!mounted) return;
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('خطا: $e')));
}
}
Future<void> _showEditDialog(Warehouse w) async {
final codeCtrl = TextEditingController(text: w.code);
final nameCtrl = TextEditingController(text: w.name);
bool isDefault = w.isDefault;
final ok = await showDialog<bool>(
context: context,
builder: (_) => AlertDialog(
title: const Text('ویرایش انبار'),
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
TextField(controller: codeCtrl, decoration: const InputDecoration(labelText: 'کد')),
TextField(controller: nameCtrl, decoration: const InputDecoration(labelText: 'نام')),
StatefulBuilder(builder: (ctx, setSt) {
return CheckboxListTile(
value: isDefault,
onChanged: (v) => setSt(() => isDefault = v ?? false),
title: const Text('پیش‌فرض'),
controlAffinity: ListTileControlAffinity.leading,
);
}),
],
),
actions: [
TextButton(onPressed: () => Navigator.of(context).pop(false), child: const Text('انصراف')),
FilledButton(onPressed: () => Navigator.of(context).pop(true), child: const Text('ذخیره')),
],
),
);
if (ok != true) return;
try {
2025-11-02 13:11:38 +03:30
await _service.updateWarehouse(
2025-10-27 22:17:45 +03:30
businessId: widget.businessId,
warehouseId: w.id!,
payload: {
'code': codeCtrl.text.trim(),
'name': nameCtrl.text.trim(),
'is_default': isDefault,
},
);
if (!mounted) return;
2025-11-02 13:11:38 +03:30
_refreshTable();
2025-10-27 22:17:45 +03:30
} catch (e) {
if (!mounted) return;
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('خطا: $e')));
}
}
Future<void> _delete(Warehouse w) async {
final ok = await showDialog<bool>(
context: context,
builder: (_) => AlertDialog(
title: const Text('حذف انبار'),
content: Text('آیا از حذف «${w.name}» مطمئن هستید؟'),
actions: [
TextButton(onPressed: () => Navigator.of(context).pop(false), child: const Text('انصراف')),
FilledButton(onPressed: () => Navigator.of(context).pop(true), child: const Text('حذف')),
],
),
);
if (ok != true) return;
try {
final deleted = await _service.deleteWarehouse(businessId: widget.businessId, warehouseId: w.id!);
if (!mounted) return;
if (deleted) {
2025-11-02 13:11:38 +03:30
_refreshTable();
2025-10-27 22:17:45 +03:30
}
} catch (e) {
if (!mounted) return;
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('خطا: $e')));
}
}
}