Update: 2026-08-02 22:51:18

This commit is contained in:
Hamza-Ayed
2026-08-02 22:51:18 +03:00
parent c9af364cbc
commit 2c962bf80a
39 changed files with 627 additions and 191 deletions
+191 -20
View File
@@ -1,3 +1,4 @@
import 'package:siro_admin/constant/theme.dart';
import 'dart:math';
import 'package:fl_chart/fl_chart.dart';
@@ -502,6 +503,167 @@ class _AdminHomePageState extends State<AdminHomePage>
);
}
/// توزيع الرحلات على فترات اليوم (صباح / مساء / ليل).
/// الحدود مطابقة لما يحسبه backend/Admin/dashbord.php:
/// صباحاً 6–11، مساءً 12–17، ليلاً 18–5.
Widget _buildPeakHoursCard(
double morning, double evening, double night, ColorScheme cs) {
final total = morning + evening + night;
final maxVal = [morning, evening, night].reduce((a, b) => a > b ? a : b);
final maxY = maxVal > 0 ? (maxVal * 1.3).ceilToDouble() : 10.0;
final slots = [
(label: 'صباحاً', hint: '6–11', value: morning, color: cs.warning),
(label: 'مساءً', hint: '12–17', value: evening, color: cs.info),
(label: 'ليلاً', hint: '18–5', value: night, color: cs.secondary),
];
return AnimationConfiguration.staggeredList(
position: 1,
duration: const Duration(milliseconds: 450),
child: SlideAnimation(
verticalOffset: 40.0,
child: FadeInAnimation(
child: Container(
decoration: BoxDecoration(
color: cs.surfaceContainerHighest,
borderRadius: BorderRadius.circular(16),
border: Border.all(color: cs.outline),
),
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Icon(Icons.schedule_rounded, color: cs.primary, size: 18),
const SizedBox(width: 8),
Text('توزيع الرحلات حسب الوقت',
style: TextStyle(
color: cs.onSurface,
fontSize: 13,
fontWeight: FontWeight.w600)),
const Spacer(),
if (total > 0)
Text('${total.toInt()} رحلة',
style: TextStyle(
color: cs.onSurfaceVariant, fontSize: 11)),
],
),
const SizedBox(height: 16),
SizedBox(
height: 140,
child: Directionality(
textDirection: TextDirection.ltr,
child: BarChart(
BarChartData(
alignment: BarChartAlignment.spaceAround,
maxY: maxY,
barTouchData: BarTouchData(
touchTooltipData: BarTouchTooltipData(
getTooltipColor: (_) => cs.surfaceContainerHighest,
getTooltipItem: (group, groupIndex, rod, rodIndex) {
final pct = total > 0
? (rod.toY / total * 100).toStringAsFixed(1)
: '0.0';
return BarTooltipItem(
'${rod.toY.toInt()} ($pct%)',
TextStyle(
color: cs.onSurface,
fontSize: 11,
fontWeight: FontWeight.w600),
);
},
),
),
gridData: FlGridData(
show: true,
drawVerticalLine: false,
getDrawingHorizontalLine: (v) => FlLine(
color: cs.outline.withValues(alpha: 0.5),
strokeWidth: 1),
),
borderData: FlBorderData(show: false),
titlesData: FlTitlesData(
show: true,
topTitles: const AxisTitles(
sideTitles: SideTitles(showTitles: false)),
rightTitles: const AxisTitles(
sideTitles: SideTitles(showTitles: false)),
leftTitles: AxisTitles(
sideTitles: SideTitles(
showTitles: true,
reservedSize: 34,
getTitlesWidget: (v, _) => Text(
v >= 1000
? '${(v / 1000).toStringAsFixed(0)}k'
: v.toInt().toString(),
style: TextStyle(
color: cs.onSurfaceVariant, fontSize: 9),
),
),
),
bottomTitles: AxisTitles(
sideTitles: SideTitles(
showTitles: true,
reservedSize: 34,
getTitlesWidget: (value, meta) {
final i = value.toInt();
if (i < 0 || i >= slots.length) {
return const SizedBox();
}
return Padding(
padding: const EdgeInsets.only(top: 6),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text(slots[i].label,
style: TextStyle(
color: cs.onSurface,
fontSize: 10,
fontWeight: FontWeight.w600)),
Text(slots[i].hint,
style: TextStyle(
color: cs.onSurfaceVariant,
fontSize: 8)),
],
),
);
},
),
),
),
barGroups: [
for (var i = 0; i < slots.length; i++)
BarChartGroupData(
x: i,
barRods: [
BarChartRodData(
toY: slots[i].value,
color: slots[i].color,
width: 26,
borderRadius: BorderRadius.circular(6),
backDrawRodData: BackgroundBarChartRodData(
show: true,
toY: maxY,
color: cs.outline.withValues(alpha: 0.25),
),
),
],
),
],
),
),
),
),
],
),
),
),
),
);
}
Widget _buildChartsSection(
dynamic data, DashboardController controller, ColorScheme cs) {
final completed = (data['completed_rides'] ?? 0).toDouble();
@@ -520,6 +682,12 @@ class _AdminHomePageState extends State<AdminHomePage>
final driverCount = (data['countDriver'] ?? 0).toDouble();
final monthRides = (data['countRideThisMonth'] ?? 0).toDouble();
// توزيع الرحلات على أوقات اليوم — تعيده dashbord.php منذ البداية
// (morning/evening/night_ride_count) ولم يكن معروضاً في أي شاشة.
final morningRides = (data['morning_ride_count'] ?? 0).toDouble();
final eveningRides = (data['evening_ride_count'] ?? 0).toDouble();
final nightRides = (data['night_ride_count'] ?? 0).toDouble();
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: Column(
@@ -677,7 +845,7 @@ class _AdminHomePageState extends State<AdminHomePage>
barRods: [
BarChartRodData(
toY: speed,
color: const Color(0xFFF59E0B),
color: cs.warning,
width: 28,
borderRadius: const BorderRadius.vertical(top: Radius.circular(6)),
),
@@ -828,6 +996,8 @@ class _AdminHomePageState extends State<AdminHomePage>
),
),
const SizedBox(height: 12),
_buildPeakHoursCard(morningRides, eveningRides, nightRides, cs),
const SizedBox(height: 12),
AnimationConfiguration.staggeredList(
position: 2,
duration: const Duration(milliseconds: 450),
@@ -1139,15 +1309,16 @@ class _AdminHomePageState extends State<AdminHomePage>
}
List<ActionCategory> _getAllActionCategories() {
final cs = Theme.of(context).colorScheme;
return [
ActionCategory(
title: 'المستخدمين',
items: [
ActionItem('الركاب', Icons.people_outline_rounded, const Color(0xFF3B82F6),
ActionItem('الركاب', Icons.people_outline_rounded, cs.info,
() => Get.to(() => Passengrs())),
ActionItem('السائقون', Icons.drive_eta_rounded, const Color(0xFFF59E0B),
ActionItem('السائقون', Icons.drive_eta_rounded, cs.warning,
() => Get.to(() => CaptainsPage())),
ActionItem('المراقب', Icons.track_changes_rounded, const Color(0xFFEF4444),
ActionItem('المراقب', Icons.track_changes_rounded, cs.danger,
() => Get.to(() => SiroTrackerScreen())),
],
),
@@ -1163,11 +1334,11 @@ class _AdminHomePageState extends State<AdminHomePage>
items: [
ActionItem('أكواد الخصم', Icons.confirmation_number_rounded, const Color(0xFF6366F1),
() => Get.toNamed('/promo')),
ActionItem('تعديل الأسعار', Icons.settings_suggest_rounded, const Color(0xFFF59E0B),
ActionItem('تعديل الأسعار', Icons.settings_suggest_rounded, cs.warning,
() => Get.toNamed('/kazan')),
ActionItem('الشكاوى', Icons.report_problem_rounded, const Color(0xFFEF4444),
ActionItem('الشكاوى', Icons.report_problem_rounded, cs.danger,
() => Get.toNamed('/complaints')),
ActionItem('مراجعة الوثائق', Icons.assignment_ind_rounded, const Color(0xFF3B82F6),
ActionItem('مراجعة الوثائق', Icons.assignment_ind_rounded, cs.info,
() => Get.toNamed('/driver-docs')),
ActionItem('استخبارات السوشيال', Icons.insights_rounded, const Color(0xFFC792EA),
() => Get.toNamed('/social-intelligence')),
@@ -1188,7 +1359,7 @@ class _AdminHomePageState extends State<AdminHomePage>
await Get.put(StaticController()).getAll();
Get.to(() => const StaticDash());
}),
ActionItem('التحليلات المتقدمة', Icons.analytics_rounded, const Color(0xFF3B82F6),
ActionItem('التحليلات المتقدمة', Icons.analytics_rounded, cs.info,
() => Get.to(() => const AdvancedAnalyticsPage())),
ActionItem('لوحة البيانات التفاعلية', Icons.dashboard_customize_rounded,
const Color(0xFF00CEC9),
@@ -1198,7 +1369,7 @@ class _AdminHomePageState extends State<AdminHomePage>
ActionCategory(
title: 'الجودة والدعم',
items: [
ActionItem('القائمة السوداء', Icons.block_flipped, const Color(0xFFEF4444),
ActionItem('القائمة السوداء', Icons.block_flipped, cs.danger,
() => Get.to(() => const BlacklistPage())),
],
),
@@ -1210,10 +1381,10 @@ class _AdminHomePageState extends State<AdminHomePage>
const Color(0xFF6366F1), () => Get.to(() => const FinancialV2Page())),
ActionItem('المحفظة', Icons.account_balance_wallet_rounded, const Color(0xFF6366F1),
() => Get.to(() => Wallet())),
ActionItem('هدية 300', Icons.card_giftcard_rounded, const Color(0xFFF59E0B),
ActionItem('هدية 300', Icons.card_giftcard_rounded, cs.warning,
() => Get.to(() => DriverGiftCheckPage())),
ActionItem('الفواتير', Icons.receipt_long_rounded,
const Color(0xFF10B981), () => Get.to(() => InvoiceListPage())),
cs.success, () => Get.to(() => InvoiceListPage())),
ActionItem('الموظفون', Icons.badge_rounded, const Color(0xFF9CA3AF),
() => Get.to(() => EmployeePage())),
ActionItem('موافقة المشرفين', Icons.how_to_reg_rounded, const Color(0xFF6366F1),
@@ -1225,11 +1396,11 @@ class _AdminHomePageState extends State<AdminHomePage>
title: 'النظام والتواصل',
items: [
ActionItem('سجل العمليات', Icons.admin_panel_settings_rounded,
const Color(0xFFEF4444), () => Get.to(() => const AuditLogsPage())),
cs.danger, () => Get.to(() => const AuditLogsPage())),
ActionItem('واتساب جماعي', Icons.message_rounded,
const Color(0xFF25D366), () => _showWhatsAppDialog(context)),
ActionItem('أتمتة التسويق', Icons.campaign_rounded,
const Color(0xFF10B981), () => Get.toNamed('/marketing')),
cs.success, () => Get.toNamed('/marketing')),
ActionItem(
'إشعار سائقين',
Icons.notifications_active_rounded,
@@ -1242,7 +1413,7 @@ class _AdminHomePageState extends State<AdminHomePage>
const Color(0xFFF06292),
() => Get.put(NotificationController())
.sendNotificationPassengers()),
ActionItem('تسجيل سائق', Icons.person_add_rounded, const Color(0xFF3B82F6),
ActionItem('تسجيل سائق', Icons.person_add_rounded, cs.info,
() => Get.to(() => DriversPendingPage())),
ActionItem(
'تحديث التطبيق',
@@ -1251,7 +1422,7 @@ class _AdminHomePageState extends State<AdminHomePage>
() => Get.to(() => PackageUpdateScreen())),
ActionItem('مراقب السيرفر', Icons.dns_rounded, const Color(0xFF6366F1),
() => Get.to(() => ServerMonitorPage())),
ActionItem('سجل الأخطاء', Icons.error_outline_rounded, const Color(0xFFEF4444),
ActionItem('سجل الأخطاء', Icons.error_outline_rounded, cs.danger,
() => Get.to(() => ErrorListPage())),
ActionItem(
'أداة التشفير',
@@ -1275,7 +1446,7 @@ class _AdminHomePageState extends State<AdminHomePage>
ActionItem(
'إضافة خدمة عملاء',
Icons.support_agent_rounded,
const Color(0xFF3B82F6),
cs.info,
() => Get.to(() => const AddStaffPage(role: 'service')),
),
],
@@ -1297,25 +1468,25 @@ class _AdminHomePageState extends State<AdminHomePage>
'title': 'مكتملة',
'value': data['completed_rides'],
'icon': Icons.check_circle_rounded,
'color': const Color(0xFF10B981),
'color': cs.success,
},
{
'title': 'ملغاة',
'value': data['cancelled_rides'],
'icon': Icons.cancel_rounded,
'color': const Color(0xFFEF4444),
'color': cs.danger,
},
{
'title': 'مدفوعات',
'value': _formatCurrency(data['payments']),
'icon': Icons.attach_money_rounded,
'color': const Color(0xFFF59E0B),
'color': cs.warning,
},
{
'title': 'Comfort',
'value': data['comfort'],
'icon': Icons.chair_rounded,
'color': const Color(0xFF10B981),
'color': cs.success,
},
{
'title': 'Speed',