Files
rasadyar_application/packages/chicken/lib/features/poultry_science/inspection/view.dart

700 lines
25 KiB
Dart

import 'dart:io';
import 'package:flutter/material.dart';
import 'package:rasadyar_chicken/data/models/response/hatching/hatching_models.dart';
import 'package:rasadyar_chicken/data/models/response/hatching_report/hatching_report.dart';
import 'package:rasadyar_chicken/presentation/utils/nested_keys_utils.dart';
import 'package:rasadyar_chicken/presentation/widget/base_page/view.dart';
import 'package:rasadyar_core/core.dart';
import 'logic.dart';
class InspectionPoultrySciencePage extends GetView<InspectionPoultryScienceLogic> {
const InspectionPoultrySciencePage({super.key});
@override
Widget build(BuildContext context) {
return ChickenBasePage(
hasBack: true,
hasFilter: true,
hasSearch: true,
onFilterTap: () {
Get.bottomSheet(filterBottomSheet());
},
onRefresh: controller.onRefresh,
onSearchChanged: (data) => controller.setSearchValue(data),
backId: poultryFirstKey,
routesWidget: ContainerBreadcrumb(rxRoutes: controller.routesName),
child: Column(
children: [
SizedBox(height: 50, child: segmentWidget()),
ObxValue((data) {
return data.value == 0 ? hatchingWidget() : reportWidget();
}, controller.selectedSegmentIndex),
],
),
);
}
Widget hatchingWidget() {
return Expanded(
child: ObxValue((data) {
return RPaginatedListView(
listType: ListType.separated,
resource: data.value,
hasMore: data.value.data?.next != null,
padding: EdgeInsets.fromLTRB(8, 8, 8, 80),
itemBuilder: (context, index) {
var item = data.value.data!.results![index];
return ObxValue((val) {
return ExpandableListItem2(
selected: val.value.isEqual(index),
onTap: () => controller.toggleExpanded(index),
index: index,
child: itemListWidget(item),
secondChild: itemListExpandedWidget(item),
labelColor: AppColor.blueLight,
labelIcon: item.reportInfo?.image == false
? Assets.vec.timerSvg.path
: Assets.vec.checkSquareSvg.path,
labelIconColor: item.reportInfo?.image == false
? AppColor.yellowNormal2
: AppColor.mediumGreyDarkHover,
);
}, controller.expandedIndex);
},
itemCount: data.value.data?.results?.length ?? 0,
separatorBuilder: (context, index) => SizedBox(height: 8.h),
onLoadMore: () async => controller.getHatchingList(true),
);
}, controller.hatchingList),
);
}
Container itemListExpandedWidget(HatchingModel item) {
return Container(
padding: EdgeInsets.symmetric(horizontal: 8),
decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(8)),
child: Column(
spacing: 8,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Text(
item.poultry?.user?.fullname ?? 'N/A',
textAlign: TextAlign.center,
style: AppFonts.yekan16.copyWith(color: AppColor.greenDark),
),
Spacer(),
Visibility(
child: Text(
item.violation == true ? 'پیگیری' : 'عادی',
textAlign: TextAlign.center,
style: AppFonts.yekan10.copyWith(color: AppColor.redDark),
),
),
],
),
Container(
height: 32,
padding: EdgeInsets.symmetric(horizontal: 8),
decoration: ShapeDecoration(
color: AppColor.blueLight,
shape: RoundedRectangleBorder(
side: BorderSide(width: 1, color: AppColor.blueLightHover),
borderRadius: BorderRadius.circular(8),
),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'نژاد:${item.breed?.first.breed ?? 'N/A'}',
style: AppFonts.yekan14.copyWith(color: AppColor.textColor),
),
Text(
' سن ${item.age} (روزه)',
style: AppFonts.yekan14.copyWith(color: AppColor.blueNormal),
),
Text(
' دوره جوجه ریزی:${item.period}',
style: AppFonts.yekan14.copyWith(color: AppColor.textColor),
),
],
),
),
buildRow(title: 'شماره مجوز جوجه ریزی', value: item.licenceNumber ?? 'N/A'),
buildUnitRow(
title: 'حجم جوجه ریزی',
value: item.quantity.separatedByCommaFa,
unit: '(قطعه)',
),
buildUnitRow(
title: 'مانده در سالن',
value: item.leftOver.separatedByCommaFa,
unit: '(قطعه)',
),
buildUnitRow(title: 'تلفات', value: item.losses.separatedByCommaFa, unit: '(قطعه)'),
buildRow(
title: 'دامپزشک فارم',
value: '${item.vetFarm?.vetFarmFullName}(${item.vetFarm?.vetFarmMobile})',
),
buildRow(
title: 'شرح بازرسی',
value: item.reportInfo?.image == false ? 'ارسال تصویر جوجه ریزی فارم ' : 'تکمیل شده',
titleStyle: AppFonts.yekan14.copyWith(
color: (item.reportInfo?.image ?? false) ? AppColor.greenNormal : AppColor.redDark,
),
valueStyle: AppFonts.yekan14.copyWith(
color: (item.reportInfo?.image ?? false) ? AppColor.greenNormal : AppColor.redDark,
),
),
Visibility(
visible: (item.reportInfo?.image == false),
child: RElevated(
text: 'ثبت بازرسی',
isFullWidth: true,
width: 150.w,
height: 40.h,
onPressed: () {
cameraBottomSheet(item.id!);
},
textStyle: AppFonts.yekan20.copyWith(color: Colors.white),
backgroundColor: AppColor.greenNormal,
),
),
],
),
);
}
void cameraBottomSheet(int id) {
Get.bottomSheet(
isDismissible: false,
isScrollControlled: false,
BaseBottomSheet(
height: 350.h,
child: Column(
children: [
ObxValue((data) {
return GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 4,
mainAxisSpacing: 8,
crossAxisSpacing: 8,
childAspectRatio: 1,
),
shrinkWrap: true,
itemCount: controller.pickedImages.length + 1,
itemBuilder: (context, index) {
if (index + 1 < 7 && index == data.length) {
return GestureDetector(
onTap: () async {
await controller.pickImages();
},
child: Container(
width: 80.h,
height: 80.h,
decoration: BoxDecoration(
color: AppColor.lightGreyNormal,
borderRadius: BorderRadius.circular(8.r),
),
child: Center(
child: Icon(
Icons.add_a_photo,
color: AppColor.lightGreyDarker,
size: 32.h,
),
),
),
);
} else {
return Container(
width: 80.h,
height: 80.h,
decoration: BoxDecoration(
color: AppColor.lightGreyNormal,
borderRadius: BorderRadius.circular(8.r),
),
child: Stack(
children: [
Positioned.fill(
child: Image.file(File(data[index].path), fit: BoxFit.cover),
),
Positioned(
top: 4,
left: 4,
child: GestureDetector(
onTap: () {
controller.removeImage(index);
},
child: Container(
width: 24.w,
height: 24.h,
clipBehavior: Clip.antiAlias,
padding: EdgeInsets.all(4),
decoration: ShapeDecoration(
color: Colors.white.withValues(alpha: 0.80),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(4),
),
),
child: Assets.vec.trashSvg.svg(
width: 8.w,
height: 8.h,
colorFilter: ColorFilter.mode(
AppColor.redNormal,
BlendMode.srcIn,
),
),
),
),
),
],
),
);
}
},
);
}, controller.pickedImages),
SizedBox(height: 35.h),
Text(
'حداقل ۲ تصویر برای ثبت بازرسی لازم است',
style: AppFonts.yekan12.copyWith(color: AppColor.textColor),
),
SizedBox(height: 8.h),
Row(
spacing: 16,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Obx(() {
return RElevated(
height: 40.h,
text: 'ارسال',
backgroundColor: AppColor.greenNormal,
progress: controller.presentUpload.value,
isLoading: controller.isOnUpload.value,
enabled: controller.pickedImages.length >= 2,
onPressed: () async {
controller.submitInspectionReport(id: id);
},
);
}),
ObxValue((data) {
return RElevated(
height: 40.h,
text: 'انصراف',
backgroundColor: AppColor.redNormal,
enabled: !data.value,
onPressed: () {
if (!data.value) {
controller.clearImages();
Get.back();
}
},
);
}, controller.isOnUpload),
],
),
SizedBox(height: 8.h),
],
),
),
).whenComplete(() {
controller.pickedImages.clear();
});
}
Padding segmentWidget() {
return Padding(
padding: const EdgeInsets.fromLTRB(8, 0, 8, 8),
child: Row(
children: [
Expanded(
child: RSegment(
children: ['بازرسی', 'بایگانی'],
selectedIndex: 0,
borderColor: const Color(0xFFB4B4B4),
selectedBorderColor: AppColor.blueNormal,
selectedBackgroundColor: AppColor.blueLight,
onSegmentSelected: (index) => controller.selectedSegmentIndex.value = index,
backgroundColor: AppColor.whiteGreyNormal,
),
),
],
),
);
}
Widget reportWidget() {
return Expanded(
child: ObxValue((data) {
return RPaginatedListView(
listType: ListType.separated,
resource: data.value,
hasMore: data.value.data?.next != null,
padding: EdgeInsets.fromLTRB(8, 8, 8, 80),
itemBuilder: (context, index) {
var item = data.value.data!.results![index];
return ObxValue((val) {
return ExpandableListItem2(
selected: val.value.isEqual(index),
onTap: () => controller.toggleExpanded(index),
index: index,
child: itemListWidgetReport(item),
secondChild: itemListExpandedWidgetReport(item),
labelColor: item.state == 'rejected' ? AppColor.redLight : AppColor.greenLight,
labelIcon: Assets.vec.cubeSearchSvg.path,
);
}, controller.expandedIndex);
},
itemCount: data.value.data?.results?.length ?? 0,
separatorBuilder: (context, index) => SizedBox(height: 8.h),
onLoadMore: () async => controller.getHatchingReport(true),
);
}, controller.hatchingReportList),
);
}
Widget itemListExpandedWidgetReport(HatchingReport item) {
return Container(
padding: EdgeInsets.symmetric(horizontal: 8),
decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(8)),
child: Column(
spacing: 8,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Text(
item.hatching?.poultry?.user?.fullname ?? 'N/A',
textAlign: TextAlign.center,
style: AppFonts.yekan16.copyWith(color: AppColor.greenDark),
),
Spacer(),
Visibility(
child: Text(
item.hatching?.violation == true ? 'پیگیری' : 'عادی',
textAlign: TextAlign.center,
style: AppFonts.yekan10.copyWith(color: AppColor.redDark),
),
),
],
),
Container(
height: 32,
padding: EdgeInsets.symmetric(horizontal: 8),
decoration: ShapeDecoration(
color: AppColor.blueLight,
shape: RoundedRectangleBorder(
side: BorderSide(width: 1, color: AppColor.blueLightHover),
borderRadius: BorderRadius.circular(8),
),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
spacing: 3,
children: [
Text('نژاد:', style: AppFonts.yekan14.copyWith(color: AppColor.textColor)),
Text(
item.hatching?.chickenBreed ?? 'N/A',
style: AppFonts.yekan14.copyWith(color: AppColor.textColor),
),
],
),
Text(
' سن ${item.hatching?.chickenAge} (روزه)',
style: AppFonts.yekan14.copyWith(color: AppColor.blueNormal),
),
Text(
' دوره جوجه ریزی:${item.hatching?.period}',
style: AppFonts.yekan14.copyWith(color: AppColor.textColor),
),
],
),
),
buildRow(title: 'شماره مجوز جوجه ریزی', value: item.hatching?.licenceNumber ?? 'N/A'),
buildUnitRow(
title: 'حجم جوجه ریزی',
value: item.hatching?.quantity.separatedByCommaFa ?? 'N/A',
unit: '(قطعه)',
),
buildUnitRow(
title: 'مانده در سالن',
value: item.hatching?.leftOver.separatedByCommaFa ?? 'N/A',
unit: '(قطعه)',
),
buildUnitRow(
title: 'تلفات',
value: item.hatching?.losses.separatedByCommaFa ?? 'N/A',
unit: '(قطعه)',
),
buildRow(
title: 'دامپزشک فارم',
value:
'${item.hatching?.vetFarm?.vetFarmFullName}(${item.hatching?.vetFarm?.vetFarmMobile})',
),
buildRow(
title: 'شرح بازرسی',
value: controller.getStatus(item),
titleStyle: AppFonts.yekan14.copyWith(color: controller.getStatusColor(item)),
valueStyle: AppFonts.yekan14.copyWith(color: controller.getStatusColor(item)),
),
if (item.state == 'accepted') ...{
Visibility(
visible: item.realQuantityAi != null,
child: buildRow(
title: 'تعداد تاییده هوش مصنوعی',
value: item.realQuantityAi.separatedByComma,
),
),
Visibility(
visible: item.realQuantity != null,
child: buildRow(
title: 'تعداد تاییده',
value: item.realQuantity.separatedByComma,
),
),
},
if (item.state == 'rejected') ...{
Visibility(
visible: item.messageAi != null,
child: buildRow(title: 'پیام هوش مصنوعی', value: item.messageAi ?? '-'),
),
Visibility(
visible: item.message != null,
child: buildRow(title: 'پیام', value: item.message ?? '-'),
),
Visibility(
visible: item.messageRegistererFullname != null,
child: buildRow(
title: 'ثبت کننده گزارش',
value: item.messageRegistererFullname ?? '-',
),
),
Visibility(
visible: item.messageRegistererMobile != null,
child: buildRow(
title: 'موبایل کننده گزارش',
value: item.messageRegistererMobile ?? '-',
),
),
Visibility(
visible: item.messageRegistererRole != null,
child: buildRow(title: 'نقش کننده گزارش', value: item.messageRegistererRole ?? '-'),
),
},
SizedBox(
height: 140.h,
child: GridView.builder(
shrinkWrap: true,
itemCount: item.image?.length ?? 0,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
mainAxisSpacing: 10,
crossAxisSpacing: 10,
),
itemBuilder: (context, index) => Container(
height: 100.h,
clipBehavior: Clip.hardEdge,
child: Image.network(
item.image?[index] ?? '',
loadingBuilder: (context, child, loadingProgress) {
if (loadingProgress == null) return child;
return Padding(
padding: EdgeInsetsGeometry.all(80),
child: CircularProgressIndicator(
color: AppColor.blueDark,
value: loadingProgress.expectedTotalBytes != null
? loadingProgress.cumulativeBytesLoaded /
(loadingProgress.expectedTotalBytes ?? 1)
: null,
),
);
},
),
decoration: BoxDecoration(borderRadius: BorderRadius.circular(8.r)),
),
),
),
],
),
);
}
Widget itemListWidget(HatchingModel item) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
SizedBox(width: 20),
Expanded(
flex: 2,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
spacing: 5,
children: [
Text(
item.poultry?.user?.fullname ?? 'N/A',
textAlign: TextAlign.start,
style: AppFonts.yekan12.copyWith(color: AppColor.blueNormal),
),
Text(
item.poultry?.user?.mobile ?? 'N/A',
textAlign: TextAlign.center,
style: AppFonts.yekan14.copyWith(color: AppColor.bgDark),
),
],
),
),
Expanded(
flex: 3,
child: Column(
spacing: 5,
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text(
item.poultry?.unitName ?? 'N/Aaq',
textAlign: TextAlign.start,
style: AppFonts.yekan12.copyWith(color: AppColor.blueNormal),
),
Text(
item.poultry?.licenceNumber ?? 'N/A',
textAlign: TextAlign.left,
style: AppFonts.yekan12.copyWith(color: AppColor.bgDark),
),
],
),
),
Expanded(
flex: 1,
child: Assets.vec.scanSvg.svg(
width: 32.w,
height: 32.h,
colorFilter: ColorFilter.mode(AppColor.blueNormal, BlendMode.srcIn),
),
),
],
);
}
Row itemListWidgetReport(HatchingReport item) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
SizedBox(width: 20),
Expanded(
flex: 2,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
spacing: 5,
children: [
Text(
item.hatching?.poultry?.user?.fullname ?? 'N/A',
textAlign: TextAlign.start,
style: AppFonts.yekan12.copyWith(color: AppColor.blueNormal),
),
Text(
item.hatching?.poultry?.user?.mobile ?? 'N/A',
textAlign: TextAlign.center,
style: AppFonts.yekan14.copyWith(color: AppColor.bgDark),
),
],
),
),
Expanded(
flex: 3,
child: Column(
spacing: 5,
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text(
item.hatching?.poultry?.unitName ?? 'N/Aaq',
textAlign: TextAlign.start,
style: AppFonts.yekan12.copyWith(color: AppColor.blueNormal),
),
Text(
item.hatching?.licenceNumber ?? 'N/A',
textAlign: TextAlign.left,
style: AppFonts.yekan12.copyWith(color: AppColor.bgDark),
),
],
),
),
Expanded(
flex: 1,
child: Assets.vec.scanSvg.svg(
width: 32.w,
height: 32.h,
colorFilter: ColorFilter.mode(AppColor.blueNormal, BlendMode.srcIn),
),
),
],
);
}
Widget filterBottomSheet() {
return BaseBottomSheet(
height: 200,
child: Column(
spacing: 16,
children: [
Text('فیلترها', style: AppFonts.yekan16Bold.copyWith(color: AppColor.blueNormal)),
Row(
spacing: 8,
children: [
Expanded(
child: dateFilterWidget(
date: controller.fromDateFilter,
onChanged: (jalali) => controller.fromDateFilter.value = jalali,
),
),
Expanded(
child: dateFilterWidget(
isFrom: false,
date: controller.toDateFilter,
onChanged: (jalali) => controller.toDateFilter.value = jalali,
),
),
],
),
RElevated(
text: 'اعمال فیلتر',
isFullWidth: true,
backgroundColor: AppColor.greenNormal,
onPressed: () {
final isReporter = controller.selectedSegmentIndex.value == 0;
if (isReporter) {
controller.getHatchingReport();
} else {
controller.getHatchingList();
}
Get.back();
},
height: 40,
),
],
),
);
}
}