Files
Siro/siro_admin/lib/views/admin/fuel/fuel_drawdowns_page.dart
T

175 lines
6.1 KiB
Dart

// fuel_drawdowns_page.dart — حركة القسائم وملخّص الائتمان
//
// ‏الشاشة التي تُجيب: كم أقرضنا؟ كم استُرد؟ وكم بقي في الشارع؟
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import '../../../controller/fuel/fuel_admin_controller.dart';
import '../../../controller/fuel/fuel_admin_models.dart';
class FuelDrawdownsPageView extends StatefulWidget {
const FuelDrawdownsPageView({super.key});
@override
State<FuelDrawdownsPageView> createState() => _FuelDrawdownsPageViewState();
}
class _FuelDrawdownsPageViewState extends State<FuelDrawdownsPageView> {
String? _status;
@override
void initState() {
super.initState();
Get.find<FuelAdminController>().fetchDrawdowns();
}
@override
Widget build(BuildContext context) {
final cs = Theme.of(context).colorScheme;
return GetBuilder<FuelAdminController>(
builder: (c) => Scaffold(
backgroundColor: cs.surface,
appBar: AppBar(
backgroundColor: cs.surface,
foregroundColor: cs.onSurface,
title: const Text('حركة القسائم'),
),
body: Column(
children: [
if (c.drawdowns != null) _summary(c.drawdowns!, cs),
_filters(c, cs),
Expanded(
child: c.isLoadingDrawdowns
? Center(child: CircularProgressIndicator(color: cs.primary))
: (c.drawdowns?.vouchers.isEmpty ?? true)
? Center(
child: Text('لا توجد قسائم',
style: TextStyle(color: cs.onSurfaceVariant)))
: ListView.builder(
padding: const EdgeInsets.symmetric(horizontal: 12),
itemCount: c.drawdowns!.vouchers.length,
itemBuilder: (_, i) =>
_voucherCard(c.drawdowns!.vouchers[i], cs),
),
),
],
),
),
);
}
/// ‏الملخّص على كامل المنتج لا على القائمة المعروضة: رقم يتغيّر بتغيّر
/// ‏الفلتر يُقرأ كأنه حقيقة عن المنصة وهو ليس كذلك.
Widget _summary(FuelDrawdownsPage d, ColorScheme cs) => Container(
margin: const EdgeInsets.fromLTRB(12, 12, 12, 4),
padding: const EdgeInsets.all(14),
decoration: BoxDecoration(
color: cs.surfaceContainerHighest,
borderRadius: BorderRadius.circular(14),
),
child: Row(
children: [
_stat('أُقرض', d.lentTotal.toString(), cs.onSurface, cs),
_stat('استُرد', d.collectedTotal.toString(), cs.primary, cs),
_stat('قائم', d.outstandingTotal.toString(), cs.tertiary, cs),
_stat('سائق', d.driversCount.toString(), cs.onSurfaceVariant, cs),
],
),
);
Widget _stat(String label, String value, Color color, ColorScheme cs) =>
Expanded(
child: Column(
children: [
Text(value,
style: TextStyle(
color: color, fontSize: 16, fontWeight: FontWeight.w700)),
const SizedBox(height: 2),
Text(label,
style: TextStyle(color: cs.onSurfaceVariant, fontSize: 11)),
],
),
);
Widget _filters(FuelAdminController c, ColorScheme cs) {
const options = {
null: 'الكل',
'issued': 'سارية',
'redeemed': 'مصروفة',
'expired': 'منتهية',
'cancelled': 'ملغاة',
};
return SizedBox(
height: 46,
child: ListView(
scrollDirection: Axis.horizontal,
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6),
children: options.entries.map((e) {
final selected = _status == e.key;
return Padding(
padding: const EdgeInsets.only(left: 8),
child: ChoiceChip(
label: Text(e.value),
selected: selected,
onSelected: (_) {
setState(() => _status = e.key);
c.fetchDrawdowns(status: e.key);
},
),
);
}).toList(),
),
);
}
Widget _voucherCard(FuelVoucher v, ColorScheme cs) {
final (color, label) = switch (v.status) {
'redeemed' => (cs.primary, 'مصروفة'),
'issued' => (cs.tertiary, 'سارية'),
'cancelled' => (cs.error, 'ملغاة'),
_ => (cs.onSurfaceVariant, 'منتهية'),
};
// ‏المصروف لا المأذون: السائق قد يطلب عشرين ويتزوّد بخمسة عشر،
// ‏والدَّين على ما صُرف. عرض المأذون هنا يضخّم الأرقام في عين القارئ.
final amount = v.status == 'redeemed' ? v.amountRedeemed : v.amountAuthorized;
return Card(
color: cs.surfaceContainerHighest,
margin: const EdgeInsets.only(bottom: 8),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
child: ListTile(
title: Row(
children: [
Text('$amount ${v.currency}',
style: TextStyle(
color: cs.onSurface, fontWeight: FontWeight.bold)),
const SizedBox(width: 8),
Container(
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 2),
decoration: BoxDecoration(
color: color.withValues(alpha: 0.15),
borderRadius: BorderRadius.circular(6),
),
child: Text(label, style: TextStyle(color: color, fontSize: 11)),
),
],
),
subtitle: Padding(
padding: const EdgeInsets.only(top: 4),
child: Text(
[
'سائق ${v.driverId}',
if (v.station != null && v.station!.isNotEmpty) v.station!,
v.redeemedAt ?? v.createdAt ?? '',
].where((s) => s.isNotEmpty).join(' · '),
style: TextStyle(color: cs.onSurfaceVariant, fontSize: 11),
),
),
),
);
}
}