194 lines
5.9 KiB
Dart
194 lines
5.9 KiB
Dart
import 'dart:convert';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:get/get.dart';
|
|
import 'package:sefer_driver/constant/box_name.dart';
|
|
import 'package:sefer_driver/constant/links.dart';
|
|
import 'package:sefer_driver/controller/functions/crud.dart';
|
|
import 'package:sefer_driver/models/model/driver/rides_summary_model.dart';
|
|
import '../../../main.dart';
|
|
|
|
class StatisticsController extends GetxController {
|
|
bool isLoading = false;
|
|
|
|
// ═══ Weekly Data ═══
|
|
List<DayStat> weeklyStats = [];
|
|
double weeklyEarnings = 0;
|
|
int weeklyTrips = 0;
|
|
double weeklyHours = 0;
|
|
|
|
// ═══ Monthly Data ═══
|
|
List<MonthlyPriceDriverModel> monthlyEarnings = [];
|
|
List<MonthlyRideModel> monthlyRides = [];
|
|
List<MonthlyDataModel> monthlyDuration = [];
|
|
double monthlyTotalEarnings = 0;
|
|
int monthlyTotalTrips = 0;
|
|
double monthlyTotalHours = 0;
|
|
String bestDay = '--';
|
|
double bestDayEarnings = 0;
|
|
|
|
// ═══ Tab State ═══
|
|
int selectedTab = 0; // 0=weekly, 1=monthly
|
|
|
|
@override
|
|
void onInit() {
|
|
super.onInit();
|
|
fetchWeeklyData();
|
|
fetchMonthlyData();
|
|
}
|
|
|
|
void changeTab(int tab) {
|
|
selectedTab = tab;
|
|
update();
|
|
}
|
|
|
|
// ═══════ جلب البيانات الأسبوعية ═══════
|
|
Future<void> fetchWeeklyData() async {
|
|
isLoading = true;
|
|
update();
|
|
|
|
try {
|
|
var res = await CRUD().get(
|
|
link: AppLink.getWeeklyAggregate,
|
|
payload: {
|
|
'driver_id': box.read(BoxName.driverID).toString(),
|
|
},
|
|
);
|
|
|
|
if (res != null && res != 'failure') {
|
|
var data = jsonDecode(res);
|
|
if (data['message'] is List) {
|
|
weeklyStats = (data['message'] as List)
|
|
.map((e) => DayStat.fromJson(e))
|
|
.toList();
|
|
weeklyEarnings = weeklyStats.fold(0, (s, d) => s + d.earnings);
|
|
weeklyTrips = weeklyStats.fold(0, (s, d) => s + d.trips);
|
|
weeklyHours = weeklyStats.fold(0, (s, d) => s + d.hours);
|
|
}
|
|
}
|
|
} catch (e) {
|
|
debugPrint('❌ [Stats] Weekly fetch error: $e');
|
|
// Fallback: generate from local data
|
|
_generateLocalWeeklyData();
|
|
}
|
|
|
|
isLoading = false;
|
|
update();
|
|
}
|
|
|
|
// ═══════ جلب البيانات الشهرية ═══════
|
|
Future<void> fetchMonthlyData() async {
|
|
try {
|
|
// 1. أرباح شهرية
|
|
var earningsRes = await CRUD().getWallet(
|
|
link: AppLink.getAllPaymentFromRide,
|
|
payload: {'driverID': box.read(BoxName.driverID).toString()},
|
|
);
|
|
if (earningsRes != null && earningsRes != 'failure') {
|
|
var data = jsonDecode(earningsRes);
|
|
if (data['message'] is List) {
|
|
monthlyEarnings = (data['message'] as List)
|
|
.map((e) => MonthlyPriceDriverModel.fromJson(e))
|
|
.toList();
|
|
monthlyTotalEarnings = monthlyEarnings.fold(0, (s, d) => s + d.pricePerDay);
|
|
|
|
// أفضل يوم
|
|
if (monthlyEarnings.isNotEmpty) {
|
|
var best = monthlyEarnings.reduce((a, b) =>
|
|
a.pricePerDay > b.pricePerDay ? a : b);
|
|
bestDay = best.day.toString();
|
|
bestDayEarnings = best.pricePerDay;
|
|
}
|
|
}
|
|
}
|
|
|
|
// 2. رحلات شهرية
|
|
var ridesRes = await CRUD().get(
|
|
link: AppLink.getRidesDriverByDay,
|
|
payload: {'driver_id': box.read(BoxName.driverID).toString()},
|
|
);
|
|
if (ridesRes != null && ridesRes != 'failure') {
|
|
var data = jsonDecode(ridesRes);
|
|
if (data['message'] is List) {
|
|
monthlyRides = (data['message'] as List)
|
|
.map((e) => MonthlyRideModel.fromJson(e))
|
|
.toList();
|
|
monthlyTotalTrips = monthlyRides.fold(0, (s, d) => s + d.countRide);
|
|
}
|
|
}
|
|
|
|
// 3. ساعات شهرية
|
|
var durationRes = await CRUD().get(
|
|
link: AppLink.getTotalDriverDuration,
|
|
payload: {'driver_id': box.read(BoxName.driverID).toString()},
|
|
);
|
|
if (durationRes != null && durationRes != 'failure') {
|
|
var data = jsonDecode(durationRes);
|
|
if (data['message'] is List) {
|
|
monthlyDuration = (data['message'] as List)
|
|
.map((e) => MonthlyDataModel.fromJson(e))
|
|
.toList();
|
|
monthlyTotalHours = monthlyDuration.fold(0, (s, d) => s + d.totalDuration.toDouble());
|
|
}
|
|
}
|
|
} catch (e) {
|
|
debugPrint('❌ [Stats] Monthly fetch error: $e');
|
|
}
|
|
|
|
update();
|
|
}
|
|
|
|
void _generateLocalWeeklyData() {
|
|
// Fallback بيانات محلية عند عدم توفر الـ API
|
|
final now = DateTime.now();
|
|
weeklyStats = List.generate(7, (i) {
|
|
final day = now.subtract(Duration(days: 6 - i));
|
|
return DayStat(
|
|
date: day,
|
|
dayName: _getDayName(day.weekday),
|
|
earnings: 0,
|
|
trips: 0,
|
|
hours: 0,
|
|
);
|
|
});
|
|
}
|
|
|
|
String _getDayName(int weekday) {
|
|
const days = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'];
|
|
return days[weekday - 1];
|
|
}
|
|
|
|
Future<void> refresh() async {
|
|
await fetchWeeklyData();
|
|
await fetchMonthlyData();
|
|
}
|
|
}
|
|
|
|
// ═══════ نموذج إحصائية اليوم ═══════
|
|
class DayStat {
|
|
final DateTime date;
|
|
final String dayName;
|
|
final double earnings;
|
|
final int trips;
|
|
final double hours;
|
|
|
|
DayStat({
|
|
required this.date,
|
|
required this.dayName,
|
|
required this.earnings,
|
|
required this.trips,
|
|
required this.hours,
|
|
});
|
|
|
|
factory DayStat.fromJson(Map<String, dynamic> json) {
|
|
final date = DateTime.tryParse(json['day']?.toString() ?? '') ?? DateTime.now();
|
|
const dayNames = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'];
|
|
return DayStat(
|
|
date: date,
|
|
dayName: dayNames[date.weekday - 1],
|
|
earnings: double.tryParse(json['earnings']?.toString() ?? '0') ?? 0,
|
|
trips: int.tryParse(json['trips']?.toString() ?? '0') ?? 0,
|
|
hours: double.tryParse(json['hours']?.toString() ?? '0') ?? 0,
|
|
);
|
|
}
|
|
}
|