feat: update poultry science feature with new data models and repository methods, enhance inspection submission process, and improve UI for better user experience

This commit is contained in:
2025-12-13 12:22:13 +03:30
parent b8a914ec0e
commit 0d47710e81
27 changed files with 4856 additions and 376 deletions

View File

@@ -15,7 +15,7 @@ class ActiveHatchingPage extends GetView<ActiveHatchingLogic> {
return ChickenBasePage(
hasSearch: true,
hasFilter: false,
backId: poultryFirstKey,
backId: poultryScienceActionKey,
routes: controller.routesName,
onSearchChanged: (data) {
controller.searchedValue.value = data;

View File

@@ -28,7 +28,7 @@ class FarmPage extends GetView<FarmLogic> {
controller.getFarmList();
},
routes: controller.routes,
backId: poultryFirstKey,
backId: poultryScienceActionKey,
child: Column(children: [firstTagInformation(), farmListWidget()]),
);
}
@@ -76,7 +76,6 @@ class FarmPage extends GetView<FarmLogic> {
itemCount: data.value.data?.results?.length ?? 0,
separatorBuilder: (context, index) => SizedBox(height: 8.h),
onLoadMore: () async => controller.getFarmList(true),
);
}, controller.farmList),
);
@@ -85,7 +84,10 @@ class FarmPage extends GetView<FarmLogic> {
Container itemListExpandedWidget(PoultryFarm item) {
return Container(
padding: EdgeInsets.symmetric(horizontal: 8),
decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(8)),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8),
),
child: Column(
spacing: 8,
children: [
@@ -134,10 +136,19 @@ class FarmPage extends GetView<FarmLogic> {
),
),
buildRow(title: 'مالک/ تلفن', value: '${item.user?.fullname} (${item.user?.mobile})'),
buildRow(
title: 'مالک/ تلفن',
value: '${item.user?.fullname} (${item.user?.mobile})',
),
buildRow(title: 'شناسه یکتا', value: item.breedingUniqueId ?? 'N/A'),
buildRow(title: 'کد اپیدمیولوژیک', value: item.epidemiologicalCode ?? 'N/A'),
buildRow(title: 'کد بهداشتی', value: item.healthCertificateNumber ?? 'N/A'),
buildRow(
title: 'کد اپیدمیولوژیک',
value: item.epidemiologicalCode ?? 'N/A',
),
buildRow(
title: 'کد بهداشتی',
value: item.healthCertificateNumber ?? 'N/A',
),
buildRow(
title: 'دامپزشک فارم',
value: '${item.vetFarm?.fullName} (${item.vetFarm?.mobile ?? '-'})',

View File

@@ -23,7 +23,7 @@ class GenocidePage extends GetView<GenocideLogic> {
controller.searchedValue.value = data;
controller.getPoultryOrderList();
},
backId: poultryFirstKey,
backId: poultryScienceActionKey,
onFilterTap: () {
Get.bottomSheet(
isScrollControlled: true,

View File

@@ -23,7 +23,7 @@ class InspectionPoultrySciencePage extends GetView<InspectionPoultryScienceLogic
},
onRefresh: controller.onRefresh,
onSearchChanged: (data) => controller.setSearchValue(data),
backId: poultryFirstKey,
backId: poultryScienceActionKey,
routesWidget: ContainerBreadcrumb(rxRoutes: controller.routesName),
child: Column(
children: [

View File

@@ -1,13 +1,13 @@
import 'package:flutter/material.dart';
import 'package:rasadyar_chicken/features/poultry_science/data/model/request/submit_inspection/submit_inspection_response.dart';
import 'package:rasadyar_chicken/features/poultry_science/data/model/response/poultry_science_report/poultry_science_report.dart';
import 'package:rasadyar_chicken/features/poultry_science/presentation/pages/root/logic.dart';
import 'package:rasadyar_core/core.dart';
class NewInspectionPoultryScienceLogic extends GetxController {
BaseLogic baseLogic = Get.find<BaseLogic>();
Rx<Resource<PaginationModel<SubmitInspectionResponse>>> submitInspectionList =
Resource<PaginationModel<SubmitInspectionResponse>>.loading().obs;
Rx<Resource<PaginationModel<PoultryScienceReport>>> submitInspectionList =
Resource<PaginationModel<PoultryScienceReport>>.loading().obs;
PoultryScienceRootLogic rootLogic = Get.find<PoultryScienceRootLogic>();
@@ -57,7 +57,7 @@ class NewInspectionPoultryScienceLogic extends GetxController {
isLoadingMoreAllocationsMade.value = true;
} else {
submitInspectionList.value =
Resource<PaginationModel<SubmitInspectionResponse>>.loading();
Resource<PaginationModel<PoultryScienceReport>>.loading();
}
if (searchedValue.value != null &&
@@ -74,18 +74,18 @@ class NewInspectionPoultryScienceLogic extends GetxController {
role: 'PoultryScience',
pageSize: 50,
search: 'filter',
page: currentPage.value,
),
),
onSuccess: (res) {
if ((res?.count ?? 0) == 0) {
submitInspectionList.value =
Resource<PaginationModel<SubmitInspectionResponse>>.empty();
Resource<PaginationModel<PoultryScienceReport>>.empty();
} else {
submitInspectionList.value =
Resource<PaginationModel<SubmitInspectionResponse>>.success(
PaginationModel<SubmitInspectionResponse>(
Resource<PaginationModel<PoultryScienceReport>>.success(
PaginationModel<PoultryScienceReport>(
count: res?.count ?? 0,
next: res?.next,
previous: res?.previous,
@@ -140,15 +140,17 @@ class NewInspectionPoultryScienceLogic extends GetxController {
await getReport();
}
String getStatus(SubmitInspectionResponse item) {
if (item.inspectionStatus == null || item.inspectionStatus!.isEmpty) {
String getStatus(PoultryScienceReport item) {
final status = item.reportInformation?.inspectionStatus ?? item.state;
if (status == null || status.isEmpty) {
return 'در حال بررسی';
}
return item.inspectionStatus!;
return status;
}
Color getStatusColor(SubmitInspectionResponse item) {
if (item.inspectionStatus == null || item.inspectionStatus!.isEmpty) {
Color getStatusColor(PoultryScienceReport item) {
final status = item.reportInformation?.inspectionStatus ?? item.state;
if (status == null || status.isEmpty) {
return AppColor.yellowNormal;
}
// می‌توانید منطق رنگ را بر اساس inspectionStatus تنظیم کنید

View File

@@ -1,5 +1,5 @@
import 'package:flutter/material.dart';
import 'package:rasadyar_chicken/features/poultry_science/data/model/request/submit_inspection/submit_inspection_response.dart';
import 'package:rasadyar_chicken/features/poultry_science/data/model/response/poultry_science_report/poultry_science_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';
@@ -21,7 +21,7 @@ class NewInspectionPoultrySciencePage
},
onRefresh: controller.onRefresh,
onSearchChanged: (data) => controller.setSearchValue(data),
backId: poultryFirstKey,
backId: poultryScienceActionKey,
routesWidget: ContainerBreadcrumb(rxRoutes: controller.routesName),
child: Column(children: [reportWidget()]),
);
@@ -57,7 +57,7 @@ class NewInspectionPoultrySciencePage
);
}
Widget itemListExpandedWidgetReport(SubmitInspectionResponse item) {
Widget itemListExpandedWidgetReport(PoultryScienceReport item) {
return Container(
padding: EdgeInsets.symmetric(horizontal: 8),
decoration: BoxDecoration(
@@ -77,42 +77,66 @@ class NewInspectionPoultrySciencePage
color: controller.getStatusColor(item),
),
),
if (item.poultryHatchingId != null)
if (item.hatching?.poultry?.unitName != null)
buildRow(
title: 'مرغداری',
value: item.hatching?.poultry?.unitName ?? '-',
),
if (item.hatching?.id != null)
buildRow(
title: 'شناسه جوجه‌ریزی',
value: item.poultryHatchingId.toString(),
value: item.hatching!.id.toString(),
),
if (item.role != null)
buildRow(title: 'نقش', value: item.role ?? '-'),
if (item.technicalOfficer?.technicalHealthOfficer != null)
if (item
.reportInformation
?.technicalOfficer
?.technicalHealthOfficer !=
null)
buildRow(
title: 'کارشناس بهداشت',
value: item.technicalOfficer!.technicalHealthOfficer ?? '-',
value:
item
.reportInformation!
.technicalOfficer!
.technicalHealthOfficer ??
'-',
),
if (item.technicalOfficer?.technicalEngineeringOfficer != null)
if (item
.reportInformation
?.technicalOfficer
?.technicalEngineeringOfficer !=
null)
buildRow(
title: 'کارشناس فنی',
value: item.technicalOfficer!.technicalEngineeringOfficer ?? '-',
value:
item
.reportInformation!
.technicalOfficer!
.technicalEngineeringOfficer ??
'-',
),
if (item.casualties?.normalLosses != null ||
item.casualties?.abnormalLosses != null)
if (item.reportInformation?.casualties?.normalLosses != null ||
item.reportInformation?.casualties?.abnormalLosses != null)
buildUnitRow(
title: 'تلفات عادی',
value: (item.casualties?.normalLosses ?? 0).toString(),
value: (item.reportInformation?.casualties?.normalLosses ?? 0)
.toString(),
unit: '(قطعه)',
),
if (item.casualties?.abnormalLosses != null)
if (item.reportInformation?.casualties?.abnormalLosses != null)
buildUnitRow(
title: 'تلفات غیرعادی',
value: item.casualties!.abnormalLosses.toString(),
value: item.reportInformation!.casualties!.abnormalLosses
.toString(),
unit: '(قطعه)',
),
if (item.lat != null && item.log != null)
buildRow(title: 'موقعیت', value: '${item.lat}, ${item.log}'),
if (item.inspectionNotes != null && item.inspectionNotes!.isNotEmpty)
if (item.reportInformation?.inspectionNotes != null &&
item.reportInformation!.inspectionNotes!.isNotEmpty)
buildRow(
title: 'یادداشت بازرسی',
value: item.inspectionNotes ?? '-',
value: item.reportInformation!.inspectionNotes ?? '-',
),
RElevated(
@@ -124,14 +148,14 @@ class NewInspectionPoultrySciencePage
showDetailsBottomSheet(item);
},
textStyle: AppFonts.yekan16.copyWith(color: Colors.white),
backgroundColor: AppColor.blueNormal,
backgroundColor: AppColor.greenNormal,
),
],
),
);
}
Row itemListWidgetReport(SubmitInspectionResponse item) {
Row itemListWidgetReport(PoultryScienceReport item) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
@@ -144,16 +168,14 @@ class NewInspectionPoultrySciencePage
spacing: 5,
children: [
Text(
item.role ?? 'نقش نامشخص',
textAlign: TextAlign.start,
'شناسه جوجه‌ریزی: ${item.hatching?.id ?? '-'}',
textAlign: TextAlign.center,
style: AppFonts.yekan12.copyWith(color: AppColor.blueNormal),
),
Text(
controller.getStatus(item),
textAlign: TextAlign.start,
style: AppFonts.yekan14.copyWith(
color: controller.getStatusColor(item),
),
item.createDate?.toJalali.formatCompactDate() ?? '-',
style: AppFonts.yekan12.copyWith(color: AppColor.bgIcon),
),
],
),
@@ -166,39 +188,26 @@ class NewInspectionPoultrySciencePage
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text(
'شناسه جوجه‌ریزی: ${item.poultryHatchingId ?? 'N/A'}',
'مرغداری: ${item.hatching?.poultry?.unitName ?? '-'}',
textAlign: TextAlign.center,
style: AppFonts.yekan12.copyWith(color: AppColor.blueNormal),
),
if (item.technicalOfficer?.technicalHealthOfficer != null)
if (item.reportInformation?.inspectionStatus != null)
Text(
'کارشناس: ${item.technicalOfficer!.technicalHealthOfficer}',
'وضعیت بازرسی: ${item.reportInformation?.inspectionStatus ?? '-'}',
textAlign: TextAlign.center,
style: AppFonts.yekan12.copyWith(color: AppColor.bgDark),
)
else
Text(
item.inspectionStatus ?? 'وضعیت نامشخص',
textAlign: TextAlign.center,
style: AppFonts.yekan12.copyWith(color: AppColor.bgDark),
style: AppFonts.yekan12.copyWith(color: AppColor.bgIcon),
),
],
),
),
Expanded(
flex: 1,
child: Assets.vec.scanSvg.svg(
width: 32.w,
height: 32.h,
colorFilter: ColorFilter.mode(AppColor.blueNormal, BlendMode.srcIn),
),
),
],
);
}
void showDetailsBottomSheet(SubmitInspectionResponse item) {
void showDetailsBottomSheet(PoultryScienceReport item) {
Get.bottomSheet(
isScrollControlled: true,
BaseBottomSheet(
height: Get.height * 0.8,
rootChild: DetailsBottomSheetWidget(item: item),
@@ -252,7 +261,7 @@ class NewInspectionPoultrySciencePage
}
class DetailsBottomSheetWidget extends StatefulWidget {
final SubmitInspectionResponse item;
final PoultryScienceReport item;
const DetailsBottomSheetWidget({super.key, required this.item});
@@ -344,7 +353,7 @@ class _DetailsBottomSheetWidgetState extends State<DetailsBottomSheetWidget> {
}
Widget technicalOfficerTable() {
final officer = widget.item.technicalOfficer;
final officer = widget.item.reportInformation?.technicalOfficer;
if (officer == null) {
return Center(
child: Padding(
@@ -415,22 +424,25 @@ class _DetailsBottomSheetWidgetState extends State<DetailsBottomSheetWidget> {
children: [
rTableRow(
title: 'وضعیت بازرسی',
value: widget.item.inspectionStatus ?? '-',
value:
widget.item.reportInformation?.inspectionStatus ??
widget.item.state ??
'-',
),
rTableRow(
title: 'یادداشت بازرسی',
value: widget.item.inspectionNotes ?? '-',
value: widget.item.reportInformation?.inspectionNotes ?? '-',
),
rTableRow(title: 'نقش', value: widget.item.role ?? '-'),
rTableRow(title: 'نقش', value: widget.item.reporterRole ?? '-'),
if (widget.item.lat != null && widget.item.log != null)
rTableRow(
title: 'موقعیت',
value: '${widget.item.lat}, ${widget.item.log}',
),
if (widget.item.poultryHatchingId != null)
if (widget.item.hatching?.id != null)
rTableRow(
title: 'شناسه جوجه ریزی',
value: widget.item.poultryHatchingId.toString(),
value: widget.item.hatching!.id.toString(),
),
],
),
@@ -440,7 +452,7 @@ class _DetailsBottomSheetWidgetState extends State<DetailsBottomSheetWidget> {
}
Widget generalConditionHallTable() {
final hall = widget.item.generalConditionHall;
final hall = widget.item.reportInformation?.generalConditionHall;
if (hall == null) {
return Center(
child: Padding(
@@ -504,14 +516,17 @@ class _DetailsBottomSheetWidgetState extends State<DetailsBottomSheetWidget> {
scrollDirection: Axis.horizontal,
itemCount: hall.images!.length,
separatorBuilder: (context, index) => SizedBox(width: 10),
itemBuilder: (context, index) => Container(
width: 80.w,
height: 80.h,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
image: DecorationImage(
fit: BoxFit.cover,
image: NetworkImage(hall.images![index]),
itemBuilder: (context, index) => GestureDetector(
onTap: () => showImageDialog(hall.images!, index),
child: Container(
width: 80.w,
height: 80.h,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
image: DecorationImage(
fit: BoxFit.cover,
image: NetworkImage(hall.images![index]),
),
),
),
),
@@ -523,7 +538,7 @@ class _DetailsBottomSheetWidgetState extends State<DetailsBottomSheetWidget> {
}
Widget casualtiesTable() {
final casualties = widget.item.casualties;
final casualties = widget.item.reportInformation?.casualties;
if (casualties == null) {
return Center(
child: Padding(
@@ -602,14 +617,17 @@ class _DetailsBottomSheetWidgetState extends State<DetailsBottomSheetWidget> {
scrollDirection: Axis.horizontal,
itemCount: casualties.images!.length,
separatorBuilder: (context, index) => SizedBox(width: 10),
itemBuilder: (context, index) => Container(
width: 80.w,
height: 80.h,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
image: DecorationImage(
fit: BoxFit.cover,
image: NetworkImage(casualties.images![index]),
itemBuilder: (context, index) => GestureDetector(
onTap: () => showImageDialog(casualties.images!, index),
child: Container(
width: 80.w,
height: 80.h,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
image: DecorationImage(
fit: BoxFit.cover,
image: NetworkImage(casualties.images![index]),
),
),
),
),
@@ -621,7 +639,7 @@ class _DetailsBottomSheetWidgetState extends State<DetailsBottomSheetWidget> {
}
Widget inputStatusTable() {
final inputStatus = widget.item.inputStatus;
final inputStatus = widget.item.reportInformation?.inputStatus;
if (inputStatus == null) {
return Center(
child: Padding(
@@ -698,14 +716,17 @@ class _DetailsBottomSheetWidgetState extends State<DetailsBottomSheetWidget> {
scrollDirection: Axis.horizontal,
itemCount: inputStatus.images!.length,
separatorBuilder: (context, index) => SizedBox(width: 10),
itemBuilder: (context, index) => Container(
width: 80.w,
height: 80.h,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
image: DecorationImage(
fit: BoxFit.cover,
image: NetworkImage(inputStatus.images![index]),
itemBuilder: (context, index) => GestureDetector(
onTap: () => showImageDialog(inputStatus.images!, index),
child: Container(
width: 80.w,
height: 80.h,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
image: DecorationImage(
fit: BoxFit.cover,
image: NetworkImage(inputStatus.images![index]),
),
),
),
),
@@ -717,7 +738,7 @@ class _DetailsBottomSheetWidgetState extends State<DetailsBottomSheetWidget> {
}
Widget infrastructureEnergyTable() {
final infra = widget.item.infrastructureEnergy;
final infra = widget.item.reportInformation?.infrastructureEnergy;
if (infra == null) {
return Center(
child: Padding(
@@ -801,7 +822,7 @@ class _DetailsBottomSheetWidgetState extends State<DetailsBottomSheetWidget> {
}
Widget hrTable() {
final hr = widget.item.hr;
final hr = widget.item.reportInformation?.hr;
if (hr == null) {
return Center(
child: Padding(
@@ -865,7 +886,7 @@ class _DetailsBottomSheetWidgetState extends State<DetailsBottomSheetWidget> {
}
Widget facilitiesTable() {
final facilities = widget.item.facilities;
final facilities = widget.item.reportInformation?.facilities;
if (facilities == null) {
return Center(
child: Padding(
@@ -930,64 +951,49 @@ class _DetailsBottomSheetWidgetState extends State<DetailsBottomSheetWidget> {
Function(int) onTabSelected,
) {
return SizedBox(
height: 38.h,
height: 40.h,
width: Get.width,
child: Stack(
fit: StackFit.expand,
child: Column(
children: [
Positioned(
right: 0,
top: 0,
bottom: 0,
child: SingleChildScrollView(
scrollDirection: Axis.horizontal,
reverse: true,
child: Row(
children: [
...tabs.map(
(tab) => GestureDetector(
onTap: () => onTabSelected(tabs.indexOf(tab)),
behavior: HitTestBehavior.opaque,
child: Container(
padding: EdgeInsets.symmetric(
horizontal: 10,
vertical: 11,
),
decoration: BoxDecoration(
border: tab == tabs[selectedIndex]
? Border(
bottom: BorderSide(
color: AppColor.blueNormalOld,
width: 3,
),
)
: null,
),
child: Text(
tab,
style: AppFonts.yekan12Bold.copyWith(
color: tab == tabs[selectedIndex]
? AppColor.blueNormalOld
: AppColor.mediumGrey,
),
SingleChildScrollView(
scrollDirection: Axis.horizontal,
reverse: true,
child: Row(
children: [
...tabs.map(
(tab) => GestureDetector(
onTap: () => onTabSelected(tabs.indexOf(tab)),
behavior: HitTestBehavior.opaque,
child: Container(
padding: EdgeInsets.symmetric(
horizontal: 10,
vertical: 11,
),
decoration: BoxDecoration(
border: tab == tabs[selectedIndex]
? Border(
bottom: BorderSide(
color: AppColor.blueNormalOld,
width: 3,
),
)
: null,
),
child: Text(
tab,
style: AppFonts.yekan12Bold.copyWith(
color: tab == tabs[selectedIndex]
? AppColor.blueNormalOld
: AppColor.mediumGrey,
),
),
),
),
],
),
),
),
Positioned(
bottom: 0,
left: 0,
right: 0,
child: Divider(
color: AppColor.blackLightHover,
height: 1,
thickness: 1,
),
],
),
),
Divider(color: AppColor.blackLightHover, height: 1, thickness: 1),
],
),
);
@@ -1032,4 +1038,98 @@ class _DetailsBottomSheetWidgetState extends State<DetailsBottomSheetWidget> {
],
);
}
void showImageDialog(List<String> images, int initialIndex) {
final pageController = PageController(initialPage: initialIndex);
final currentIndex = initialIndex.obs;
Get.dialog(
Dialog(
backgroundColor: Colors.transparent,
insetPadding: EdgeInsets.zero,
child: Container(
width: Get.width,
height: Get.height,
color: Colors.black,
child: Stack(
children: [
PageView.builder(
controller: pageController,
itemCount: images.length,
onPageChanged: (index) {
currentIndex.value = index;
},
itemBuilder: (context, index) {
return InteractiveViewer(
minScale: 0.5,
maxScale: 4.0,
child: Center(
child: Image.network(
images[index],
fit: BoxFit.contain,
loadingBuilder: (context, child, loadingProgress) {
if (loadingProgress == null) return child;
return Center(
child: CircularProgressIndicator(
value: loadingProgress.expectedTotalBytes != null
? loadingProgress.cumulativeBytesLoaded /
loadingProgress.expectedTotalBytes!
: null,
color: Colors.white,
),
);
},
errorBuilder: (context, error, stackTrace) {
return Center(
child: Icon(
Icons.error,
color: Colors.white,
size: 50,
),
);
},
),
),
);
},
),
Positioned(
top: 40,
right: 16,
child: IconButton(
icon: Icon(Icons.close, color: Colors.white, size: 30),
onPressed: () => Get.back(),
),
),
if (images.length > 1)
Positioned(
bottom: 20,
left: 0,
right: 0,
child: Center(
child: Obx(
() => Container(
padding: EdgeInsets.symmetric(
horizontal: 12,
vertical: 6,
),
decoration: BoxDecoration(
color: Colors.black54,
borderRadius: BorderRadius.circular(20),
),
child: Text(
'${currentIndex.value + 1} / ${images.length}',
style: TextStyle(color: Colors.white, fontSize: 14),
),
),
),
),
),
],
),
),
),
barrierDismissible: true,
);
}
}

View File

@@ -10,7 +10,12 @@ class PoultryActionPage extends GetView<PoultryActionLogic> {
@override
Widget build(BuildContext context) {
return ChickenBasePage(isBase: true, hasNews: true, hasNotification: true, child: gridWidget());
return ChickenBasePage(
isBase: true,
hasNews: true,
hasNotification: true,
child: gridWidget(),
);
}
Widget gridWidget() {
@@ -31,7 +36,7 @@ class PoultryActionPage extends GetView<PoultryActionLogic> {
title: item.title,
vecIcon: item.icon,
onTap: () async {
Get.toNamed(item.route, id: poultryFirstKey);
Get.toNamed(item.route, id: poultryScienceActionKey);
},
);
},

View File

@@ -25,7 +25,7 @@ class PoultryScienceRootLogic extends GetxController {
final pages = [
Navigator(
key: Get.nestedKey(poultryFirstKey),
key: Get.nestedKey(poultryScienceActionKey),
onGenerateRoute: (settings) {
final page = ChickenPages.pages.firstWhere(
(e) => e.name == settings.name,

View File

@@ -30,11 +30,9 @@ class PoultryScienceRootPage extends GetView<PoultryScienceRootLogic> {
isSelected: controller.currentPage.value == 0,
onTap: () {
Get.nestedKey(
poultrySecondKey,
)?.currentState?.popUntil((route) => route.isFirst);
Get.nestedKey(
poultryFirstKey,
poultryScienceActionKey,
)?.currentState?.popUntil((route) => route.isFirst);
controller.changePage(0);
},
),
@@ -44,11 +42,9 @@ class PoultryScienceRootPage extends GetView<PoultryScienceRootLogic> {
isSelected: controller.currentPage.value == 1,
onTap: () {
Get.nestedKey(
poultryFirstKey,
)?.currentState?.popUntil((route) => route.isFirst);
Get.nestedKey(
poultryThirdKey,
poultryScienceActionKey,
)?.currentState?.popUntil((route) => route.isFirst);
controller.changePage(1);
},
),
@@ -58,11 +54,9 @@ class PoultryScienceRootPage extends GetView<PoultryScienceRootLogic> {
isSelected: controller.currentPage.value == 2,
onTap: () {
Get.nestedKey(
poultryFirstKey,
)?.currentState?.popUntil((route) => route.isFirst);
Get.nestedKey(
poultrySecondKey,
poultryScienceActionKey,
)?.currentState?.popUntil((route) => route.isFirst);
controller.changePage(2);
},
),

View File

@@ -28,7 +28,7 @@ class CreateInspectionBottomSheetLogic extends GetxController
RxBool nextStepButtonEnabled = false.obs;
RxInt casualtiesInformationHeight = 310.obs;
RxInt casualtiesInformationHeight = 315.obs;
SubmitInspectionResponse? submitInspectionResponse;
@@ -87,7 +87,7 @@ class CreateInspectionBottomSheetLogic extends GetxController
TextEditingController otherTypeOfDiseaseController = TextEditingController();
RxList<String> pultryImagesUrls = RxList<String>();
RxMap<XFile, bool> pultryImages = RxMap<XFile, bool>();
RxList<XFile> pultryImages = RxList<XFile>();
TextEditingController hatchingTemperatureController = TextEditingController();
TextEditingController waterHardnessController = TextEditingController();
@@ -189,13 +189,13 @@ class CreateInspectionBottomSheetLogic extends GetxController
TextEditingController();
RxList<String> hallImagesUrls = RxList<String>();
RxMap<XFile, bool> hallImages = RxMap<XFile, bool>();
RxList<XFile> hallImages = RxList<XFile>();
RxList<String> inputWarehouseImagesUrls = RxList<String>();
RxMap<XFile, bool> inputWarehouseImages = RxMap<XFile, bool>();
RxList<XFile> inputWarehouseImages = RxList<XFile>();
RxList<String> lossesImagesUrls = RxList<String>();
RxMap<XFile, bool> lossesImages = RxMap<XFile, bool>();
RxList<XFile> lossesImages = RxList<XFile>();
//location
Rxn<LatLng> currentLocation = Rxn<LatLng>();
@@ -525,6 +525,7 @@ class CreateInspectionBottomSheetLogic extends GetxController
void setInspectorConclusionIndex(int index, String item) {
inspectorConclusion.value = item;
submitInspectionResponse?.inspectionStatus = item;
inspectorConclusionIndex.value = index == inspectorConclusionIndex.value
? -1
: index;
@@ -563,17 +564,18 @@ class CreateInspectionBottomSheetLogic extends GetxController
}
}
Future<void> pickImageFromCamera(RxMap<XFile, bool> images) async {
Future<void> pickImageFromCamera(RxList<XFile> images) async {
try {
final XFile? image = await imagePicker.pickImage(
source: ImageSource.camera,
preferredCameraDevice: CameraDevice.rear,
imageQuality: 50,
maxWidth: 1080,
maxHeight: 720,
);
if (image != null) {
images[image] = false;
images.add(image);
//await uploadImage(image);
}
@@ -601,10 +603,10 @@ class CreateInspectionBottomSheetLogic extends GetxController
if (urls != null) {
pultryImagesUrls.addAll(urls);
}
pultryImages[imageFile] = true;
pultryImages.add(imageFile);
},
onError: (error, e) {
pultryImages[imageFile] = false;
pultryImages.remove(imageFile);
},
);
}
@@ -657,7 +659,7 @@ class CreateInspectionBottomSheetLogic extends GetxController
// آپلود عکس‌های سالن
if (hallImages.isNotEmpty) {
uploadStatusMessage.value = 'در حال آپلود عکس‌های سالن...';
final hallImageFiles = hallImages.keys.toList();
final hallImageFiles = hallImages.toList();
final hallUrls = await uploadImageBatch(hallImageFiles);
if (hallUrls != null && hallUrls.isNotEmpty) {
@@ -672,7 +674,7 @@ class CreateInspectionBottomSheetLogic extends GetxController
// آپلود عکس‌های انبار دان
if (inputWarehouseImages.isNotEmpty) {
uploadStatusMessage.value = 'در حال آپلود عکس‌های انبار دان...';
final inputImageFiles = inputWarehouseImages.keys.toList();
final inputImageFiles = inputWarehouseImages.toList();
final inputUrls = await uploadImageBatch(inputImageFiles);
if (inputUrls != null && inputUrls.isNotEmpty) {
@@ -687,7 +689,7 @@ class CreateInspectionBottomSheetLogic extends GetxController
// آپلود عکس‌های تلفات
if (lossesImages.isNotEmpty) {
uploadStatusMessage.value = 'در حال آپلود عکس‌های تلفات...';
final lossesImageFiles = lossesImages.keys.toList();
final lossesImageFiles = lossesImages.toList();
final lossesUrls = await uploadImageBatch(lossesImageFiles);
if (lossesUrls != null && lossesUrls.isNotEmpty) {
@@ -702,14 +704,12 @@ class CreateInspectionBottomSheetLogic extends GetxController
// آپلود عکس‌های مرغداری
if (pultryImages.isNotEmpty) {
uploadStatusMessage.value = 'در حال آپلود عکس‌های مرغداری...';
final poultryImageFiles = pultryImages.keys.toList();
final poultryImageFiles = pultryImages.toList();
final poultryUrls = await uploadImageBatch(poultryImageFiles);
if (poultryUrls != null && poultryUrls.isNotEmpty) {
// اگر فیلد جداگانه‌ای برای عکس‌های مرغداری نداریم، به generalConditionHall اضافه می‌کنیم
if (submitInspectionResponse?.generalConditionHall?.images == null) {
submitInspectionResponse?.generalConditionHall?.images = [];
}
submitInspectionResponse?.generalConditionHall?.images ??= [];
submitInspectionResponse?.generalConditionHall?.images?.addAll(
poultryUrls,
);
@@ -738,8 +738,8 @@ class CreateInspectionBottomSheetLogic extends GetxController
}
}
void removeImage(RxMap<XFile, bool> images, XFile image) {
images.remove(image);
void removeImage(RxList<XFile> images, String imagePath) {
images.removeWhere((element) => element.path == imagePath);
}
void setTypeOfDiseaseIndex(String item) {
@@ -853,10 +853,6 @@ class CreateInspectionBottomSheetLogic extends GetxController
hallImages.remove(key);
}
void removeInputWarehouseImage(XFile key) {
inputWarehouseImages.remove(key);
}
void removeLossesImage(XFile key) {
lossesImages.remove(key);
}
@@ -939,9 +935,10 @@ class CreateInspectionBottomSheetLogic extends GetxController
submitInspectionResponse?.hr?.numberNonIndigenous = int.parse(
nonNativeWorkersCountController.text.clearComma,
);
iLog(submitInspectionResponse?.toJson());
submitInspectionResponse?.inspectionNotes =
inspectorConclusionDescriptionController.text;
await safeCall(
call: () async {
await repository.submitInspection(
@@ -950,16 +947,17 @@ class CreateInspectionBottomSheetLogic extends GetxController
);
},
onSuccess: (result) {
Get.back();
Future.delayed(Duration(seconds: 2), () { Get.snackbar(
'موفق',
'بازرسی با موفقیت ثبت شد',
snackPosition: SnackPosition.TOP,
backgroundColor: Colors.green,
colorText: Colors.white,
);});
Future.delayed(Duration(seconds: 2), () {
Get.snackbar(
'موفق',
'بازرسی با موفقیت ثبت شد',
snackPosition: SnackPosition.TOP,
backgroundColor: Colors.green,
colorText: Colors.white,
);
});
},
onError: (error, stackTrace) {
Get.snackbar(

View File

@@ -13,8 +13,8 @@ Widget step1Page(CreateInspectionBottomSheetLogic controller) {
Container(
height: controller.tenantStatusController.text == 'دارد'
? 588.h
: 445.h,
? 600.h
: 460.h,
clipBehavior: Clip.none,
width: Get.width,
child: farmInfoWidget(

View File

@@ -14,7 +14,7 @@ Widget step2Page(CreateInspectionBottomSheetLogic controller) {
SizedBox(height: 35.h),
Container(
height: 600.h,
height: 630.h,
clipBehavior: Clip.none,
width: Get.width,
child: farmInfoWidget(
@@ -71,83 +71,63 @@ Column generalConditionOfTheHall(CreateInspectionBottomSheetLogic controller) {
scrollDirection: Axis.horizontal,
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
// Fix: Use spread .entries.map for map iteration, and correct image argument
spacing: 8,
children: [
...controller.pultryImages.entries
.map(
(entry) => Stack(
children: [
Container(
height: 80.h,
width: 80.w,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
border: Border.all(
width: 1,
color: AppColor.blackLightHover,
),
),
child: ClipRRect(
borderRadius: BorderRadius.circular(8),
child: Image.file(
File(entry.key.path),
fit: BoxFit.cover,
),
),
...controller.pultryImages.map(
(entry) => Stack(
children: [
Container(
height: 80.h,
width: 80.w,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
border: Border.all(
width: 1,
color: AppColor.blackLightHover,
),
// Delete button
Positioned(
top: -4,
right: -4,
child: GestureDetector(
onTap: () =>
controller.removeImage(controller.pultryImages, entry.key),
child: Container(
width: 24,
height: 24,
decoration: BoxDecoration(
color: Colors.red,
shape: BoxShape.circle,
),
child: Icon(
Icons.close,
color: Colors.white,
size: 16,
),
),
),
),
child: ClipRRect(
borderRadius: BorderRadius.circular(8),
child: Image.file(
File(entry.path),
fit: BoxFit.cover,
),
// Upload indicator
if (entry.value == false)
Positioned.fill(
child: Container(
decoration: BoxDecoration(
color: Colors.black.withOpacity(0.5),
borderRadius: BorderRadius.circular(8),
),
child: Center(
child: SizedBox(
width: 20,
height: 20,
child: CircularProgressIndicator(
strokeWidth: 2,
valueColor:
AlwaysStoppedAnimation<Color>(
Colors.white,
),
),
),
),
),
),
],
),
),
)
,
// Delete button
Positioned(
top: 4,
left: 4,
child: GestureDetector(
onTap: () => controller.removeImage(
controller.hallImages,
entry.path,
),
child: Container(
width: 24,
height: 24,
decoration: BoxDecoration(
color: Colors.red,
shape: BoxShape.circle,
),
child: Icon(
Icons.close,
color: Colors.white,
size: 16,
),
),
),
),
// Upload indicator
],
),
),
// Add image button
GestureDetector(
onTap: () => controller.pickImageFromCamera(controller.pultryImages),
onTap: () => controller.pickImageFromCamera(
controller.pultryImages,
),
child: Container(
height: 80.h,
width: 80.w,

View File

@@ -14,7 +14,7 @@ Widget step3Page(CreateInspectionBottomSheetLogic controller) {
SizedBox(height: 35.h),
Container(
height: 360.h,
height: 370.h,
clipBehavior: Clip.none,
width: Get.width,
child: farmInfoWidget(
@@ -27,7 +27,7 @@ Widget step3Page(CreateInspectionBottomSheetLogic controller) {
SizedBox(height: 30.h),
Container(
height: 610.h,
height: 625.h,
clipBehavior: Clip.none,
width: Get.width,
child: farmInfoWidget(
@@ -39,7 +39,7 @@ Widget step3Page(CreateInspectionBottomSheetLogic controller) {
SizedBox(height: 24.h),
Container(
height: 310.h,
height: 320.h,
clipBehavior: Clip.none,
width: Get.width,
child: farmInfoWidget(
@@ -51,7 +51,7 @@ Widget step3Page(CreateInspectionBottomSheetLogic controller) {
SizedBox(height: 24.h),
Container(
height: 325.h,
height: 335.h,
clipBehavior: Clip.none,
width: Get.width,
child: farmInfoWidget(
@@ -461,8 +461,8 @@ Column facilitiesAndSupport(CreateInspectionBottomSheetLogic controller) {
children: [
SizedBox(height: 1.h),
ResourceOverlayDropdown(
items: Resource.success([ 'دارد', 'ندارد']),
ResourceOverlayDropdown(
items: Resource.success(['دارد', 'ندارد']),
onChanged: (item) => controller.setHasFacilities(item),
itemBuilder: (item) => Text(item),
labelBuilder: (selected) => Text(selected ?? ' تسهیلات دریافتی فعال'),

View File

@@ -16,7 +16,7 @@ Widget step4Page(CreateInspectionBottomSheetLogic controller) {
SizedBox(height: 35.h),
Container(
height: 440.h,
height: 455.h,
clipBehavior: Clip.none,
width: Get.width,
child: farmInfoWidget(
@@ -62,7 +62,7 @@ Column documents(CreateInspectionBottomSheetLogic controller) {
mainAxisAlignment: MainAxisAlignment.start,
spacing: 8,
children: [
...controller.hallImages.entries.map(
...controller.hallImages.map(
(entry) => Stack(
children: [
Container(
@@ -78,7 +78,7 @@ Column documents(CreateInspectionBottomSheetLogic controller) {
child: ClipRRect(
borderRadius: BorderRadius.circular(8),
child: Image.file(
File(entry.key.path),
File(entry.path),
fit: BoxFit.cover,
),
),
@@ -90,7 +90,7 @@ Column documents(CreateInspectionBottomSheetLogic controller) {
child: GestureDetector(
onTap: () => controller.removeImage(
controller.hallImages,
entry.key,
entry.path,
),
child: Container(
width: 24,
@@ -172,7 +172,7 @@ Column documents(CreateInspectionBottomSheetLogic controller) {
mainAxisAlignment: MainAxisAlignment.start,
spacing: 8,
children: [
...controller.inputWarehouseImages.entries.map(
...controller.inputWarehouseImages.map(
(entry) => Stack(
children: [
Container(
@@ -188,18 +188,19 @@ Column documents(CreateInspectionBottomSheetLogic controller) {
child: ClipRRect(
borderRadius: BorderRadius.circular(8),
child: Image.file(
File(entry.key.path),
File(entry.path),
fit: BoxFit.cover,
),
),
),
// Delete button
Positioned(
top: 4,
top: 4,
left: 4,
child: GestureDetector(
onTap: () => controller.removeInputWarehouseImage(
entry.key,
onTap: () => controller.removeImage(
controller.inputWarehouseImages,
entry.path,
),
child: Container(
width: 24,
@@ -268,7 +269,7 @@ Column documents(CreateInspectionBottomSheetLogic controller) {
mainAxisAlignment: MainAxisAlignment.start,
spacing: 8,
children: [
...controller.lossesImages.entries.map(
...controller.lossesImages.map(
(entry) => Stack(
children: [
Container(
@@ -284,7 +285,7 @@ Column documents(CreateInspectionBottomSheetLogic controller) {
child: ClipRRect(
borderRadius: BorderRadius.circular(8),
child: Image.file(
File(entry.key.path),
File(entry.path),
fit: BoxFit.cover,
),
),
@@ -294,8 +295,9 @@ Column documents(CreateInspectionBottomSheetLogic controller) {
top: 4,
left: 4,
child: GestureDetector(
onTap: () => controller.removeInputWarehouseImage(
entry.key,
onTap: () => controller.removeImage(
controller.lossesImages,
entry.path,
),
child: Container(
width: 24,