Explorar o código

merge master-ukk to master

glglove hai 3 semanas
pai
achega
757ab89a95
Modificáronse 100 ficheiros con 9508 adicións e 1891 borrados
  1. 1 0
      .fvm/flutter_sdk
  2. 3 0
      .fvm/fvm_config.json
  3. 1 0
      .fvm/release
  4. 1 0
      .fvm/version
  5. 1 0
      .fvm/versions/3.24.5
  6. 3 0
      .fvmrc
  7. 1 2
      packages/cpt_auth/lib/modules/select_country/select_country_page.dart
  8. 1 0
      packages/cpt_sg/lib/modules/job/applied_staff/applied_staff_controller.dart
  9. 59 0
      packages/cpt_uk/lib/modules/attendance/e_attendance_list/item_e_attendance.dart
  10. 156 57
      packages/cpt_uk/lib/modules/job/job_applied/applied_staff_item.dart
  11. 79 11
      packages/cpt_uk/lib/modules/job/job_applied/job_applied_controller.dart
  12. 31 1
      packages/cpt_uk/lib/modules/job/job_applied/job_applied_page.dart
  13. 7 2
      packages/cpt_uk/lib/modules/job/job_applied/job_applied_state.dart
  14. 16 2
      packages/cpt_uk/lib/modules/job/job_applied/widget/applied_add_staff.dart
  15. 32 5
      packages/cpt_uk/lib/modules/job/job_applied/widget/applied_add_staff_controller.dart
  16. 183 0
      packages/cpt_uk/lib/modules/job/job_applied/widget/applied_set_tip.dart
  17. 74 0
      packages/cpt_uk/lib/modules/job/job_applied/widget/status_popup_menu.dart
  18. 5 0
      packages/cpt_uk/lib/modules/job/job_applied_edit/job_applied_edit_controller.dart
  19. 38 33
      packages/cpt_uk/lib/modules/job/job_applied_edit/job_applied_edit_page.dart
  20. 2 0
      packages/cpt_uk/lib/modules/job/job_applied_edit/job_applied_edit_state.dart
  21. 287 0
      packages/cpt_uk/lib/modules/job/job_applied_revise_list/job_applied_revise_list_controller.dart
  22. 144 0
      packages/cpt_uk/lib/modules/job/job_applied_revise_list/job_applied_revise_list_page.dart
  23. 13 0
      packages/cpt_uk/lib/modules/job/job_applied_revise_list/job_applied_revise_list_state.dart
  24. 322 0
      packages/cpt_uk/lib/modules/job/job_applied_revise_list/revise_list_item.dart
  25. 46 8
      packages/cpt_uk/lib/modules/job/job_applied_staff_detail/applied_staff_detail_controller.dart
  26. 83 33
      packages/cpt_uk/lib/modules/job/job_applied_staff_detail/applied_staff_detail_page.dart
  27. 5 4
      packages/cpt_uk/lib/modules/job/job_applied_staff_detail/applied_staff_detail_state.dart
  28. 180 0
      packages/cpt_uk/lib/modules/job/job_applied_staff_detail/certification_dialog_widget.dart
  29. 214 160
      packages/cpt_uk/lib/modules/job/job_applied_staff_detail/staff_detail_widget.dart
  30. 23 21
      packages/cpt_uk/lib/modules/job/job_applied_staff_detail/staff_labour_history_item.dart
  31. 1 1
      packages/cpt_uk/lib/modules/job/job_applied_staff_reviews/applied_staff_reviews_page.dart
  32. 5 5
      packages/cpt_uk/lib/modules/job/job_category/job_category_controller.dart
  33. 6 5
      packages/cpt_uk/lib/modules/job/job_category/job_category_state.dart
  34. 36 0
      packages/cpt_uk/lib/modules/job/job_list/job_list_controller.dart
  35. 2 1
      packages/cpt_uk/lib/modules/job/job_list/job_list_item.dart
  36. 393 39
      packages/cpt_uk/lib/modules/job/labour_request_add/labour_request_add_controller.dart
  37. 767 269
      packages/cpt_uk/lib/modules/job/labour_request_add/labour_request_add_page.dart
  38. 105 3
      packages/cpt_uk/lib/modules/job/labour_request_add/labour_request_add_state.dart
  39. 996 0
      packages/cpt_uk/lib/modules/job/labour_request_add/widget/lab_request_and_request_review_form.dart
  40. 120 0
      packages/cpt_uk/lib/modules/job/labour_request_add/widget/labour_request_interface.dart
  41. 22 22
      packages/cpt_uk/lib/modules/job/labour_request_list/labour_request_filter.dart
  42. 245 30
      packages/cpt_uk/lib/modules/job/labour_request_list/labour_request_item.dart
  43. 93 11
      packages/cpt_uk/lib/modules/job/labour_request_list/labour_request_list_controller.dart
  44. 9 0
      packages/cpt_uk/lib/modules/job/labour_request_list/labour_request_list_page.dart
  45. 2 2
      packages/cpt_uk/lib/modules/job/labour_request_list/labour_request_list_state.dart
  46. 227 0
      packages/cpt_uk/lib/modules/job/labour_request_list/widget/quick_copy_dialog_widget.dart
  47. 128 0
      packages/cpt_uk/lib/modules/job/labour_request_list/widget/quick_copy_dialog_widget_controller.dart
  48. 14 0
      packages/cpt_uk/lib/modules/job/labour_request_list/widget/quick_copy_dialog_widget_state.dart
  49. 243 0
      packages/cpt_uk/lib/modules/job/labour_request_preselected_list/labour_request-preselected_item.dart
  50. 264 0
      packages/cpt_uk/lib/modules/job/labour_request_preselected_list/labour_request_preselected_list_controller.dart
  51. 139 0
      packages/cpt_uk/lib/modules/job/labour_request_preselected_list/labour_request_preselected_list_page.dart
  52. 10 0
      packages/cpt_uk/lib/modules/job/labour_request_preselected_list/labour_request_preselected_list_state.dart
  53. 358 0
      packages/cpt_uk/lib/modules/job/labour_request_preselected_list/widget/preselected_add_staff.dart
  54. 136 0
      packages/cpt_uk/lib/modules/job/labour_request_preselected_list/widget/preselected_add_staff_controller.dart
  55. 108 0
      packages/cpt_uk/lib/modules/job/revise_add_edit/revise_add_edit_controller.dart
  56. 70 0
      packages/cpt_uk/lib/modules/job/revise_add_edit/revise_add_edit_item.dart
  57. 220 0
      packages/cpt_uk/lib/modules/job/revise_add_edit/revise_add_edit_page.dart
  58. 40 0
      packages/cpt_uk/lib/modules/job/revise_add_edit/revise_add_edit_state.dart
  59. 101 0
      packages/cpt_uk/lib/modules/job/revise_log/revise_log_controller.dart
  60. 156 0
      packages/cpt_uk/lib/modules/job/revise_log/revise_log_item.dart
  61. 102 0
      packages/cpt_uk/lib/modules/job/revise_log/revise_log_page.dart
  62. 11 0
      packages/cpt_uk/lib/modules/job/revise_log/revise_log_state.dart
  63. 308 28
      packages/cpt_uk/lib/modules/job/template_add/template_add_controller.dart
  64. 166 27
      packages/cpt_uk/lib/modules/job/template_add/template_add_page.dart
  65. 34 3
      packages/cpt_uk/lib/modules/job/template_add/template_add_state.dart
  66. 46 0
      packages/cpt_uk/lib/modules/job/template_list/item_template.dart
  67. 3 3
      packages/cpt_uk/lib/modules/job/template_list/template_list_controller.dart
  68. 1 1
      packages/cpt_uk/lib/modules/job/template_list/template_list_page.dart
  69. 39 36
      packages/cpt_uk/lib/modules/main/main_controller.dart
  70. 1 1
      packages/cpt_uk/lib/modules/main/main_state.dart
  71. 107 37
      packages/cpt_uk/lib/modules/report/casual_payout_report/casual_payout_report_controller.dart
  72. 107 142
      packages/cpt_uk/lib/modules/report/casual_payout_report/casual_payout_report_item.dart
  73. 102 77
      packages/cpt_uk/lib/modules/report/casual_payout_report/casual_payout_report_page.dart
  74. 3 5
      packages/cpt_uk/lib/modules/report/casual_payout_report/casual_payout_report_state.dart
  75. 45 88
      packages/cpt_uk/lib/modules/report/casual_report/casual_report_controller.dart
  76. 228 108
      packages/cpt_uk/lib/modules/report/casual_report/casual_report_item.dart
  77. 49 43
      packages/cpt_uk/lib/modules/report/casual_report/casual_report_page.dart
  78. 6 5
      packages/cpt_uk/lib/modules/report/casual_report/casual_report_state.dart
  79. 3 2
      packages/cpt_uk/lib/modules/report/finance_report/report_finance_item.dart
  80. 23 35
      packages/cpt_uk/lib/modules/report/outlet_staff_report/outlet_staff_report_controller.dart
  81. 2 2
      packages/cpt_uk/lib/modules/report/outlet_staff_report/outlet_staff_report_item.dart
  82. 7 3
      packages/cpt_uk/lib/modules/report/outlet_staff_report/outlet_staff_report_state.dart
  83. 9 8
      packages/cpt_uk/lib/modules/report/report_list/report_list_controller.dart
  84. 6 6
      packages/cpt_uk/lib/modules/report/report_list/report_list_state.dart
  85. 63 17
      packages/cpt_uk/lib/modules/review/attendance_review_list/attendance_review_controller.dart
  86. 69 63
      packages/cpt_uk/lib/modules/review/attendance_review_list/attendance_review_item.dart
  87. 4 1
      packages/cpt_uk/lib/modules/review/attendance_review_list/attendance_review_page.dart
  88. 219 0
      packages/cpt_uk/lib/modules/review/attendance_review_list/attendance_review_remark_dialog.dart
  89. 2 2
      packages/cpt_uk/lib/modules/review/attendance_review_list/attendance_review_state.dart
  90. 380 69
      packages/cpt_uk/lib/modules/review/labour_review_edit/labour_review_edit_controller.dart
  91. 4 257
      packages/cpt_uk/lib/modules/review/labour_review_edit/labour_review_edit_page.dart
  92. 103 2
      packages/cpt_uk/lib/modules/review/labour_review_edit/labour_review_edit_state.dart
  93. 109 66
      packages/cpt_uk/lib/modules/review/labour_review_list/labour_review_controller.dart
  94. 107 20
      packages/cpt_uk/lib/modules/review/labour_review_list/labour_review_item.dart
  95. 1 0
      packages/cpt_uk/lib/modules/review/labour_review_list/labour_review_page.dart
  96. 2 1
      packages/cpt_uk/lib/modules/review/labour_review_list/labour_review_state.dart
  97. 2 2
      packages/cpt_uk/lib/modules/review/labour_review_workflow/labour_request_workflow_state.dart
  98. 6 3
      packages/cpt_uk/lib/modules/review/labour_review_workflow/labour_review_workflow_controller.dart
  99. 2 1
      packages/cpt_uk/lib/modules/review/labour_review_workflow/labour_review_workflow_item.dart
  100. 0 0
      packages/cpt_uk/lib/router/uk_router.dart

+ 1 - 0
.fvm/flutter_sdk

@@ -0,0 +1 @@
+I:/programInstall/fvm/versions/3.24.5

+ 3 - 0
.fvm/fvm_config.json

@@ -0,0 +1,3 @@
+{
+  "flutterSdkVersion": "3.24.5"
+}

+ 1 - 0
.fvm/release

@@ -0,0 +1 @@
+3.24.5

+ 1 - 0
.fvm/version

@@ -0,0 +1 @@
+3.24.5

+ 1 - 0
.fvm/versions/3.24.5

@@ -0,0 +1 @@
+I:/programInstall/fvm/versions/3.24.5

+ 3 - 0
.fvmrc

@@ -0,0 +1,3 @@
+{
+  "flutter": "3.24.5"
+}

+ 1 - 2
packages/cpt_auth/lib/modules/select_country/select_country_page.dart

@@ -25,8 +25,7 @@ class SelectCountryPage extends BaseStatelessPage<SelectCountryController> {
   }
 
   @override
-  void initState() {
-  }
+  void initState() {}
 
   @override
   SelectCountryController createRawController() {

+ 1 - 0
packages/cpt_sg/lib/modules/job/applied_staff/applied_staff_controller.dart

@@ -68,6 +68,7 @@ class AppliedStaffController extends GetxController with DioCancelableMixin {
       cancelToken: cancelToken,
     );
 
+
     // 处理数据
     if (listResult.isSuccess) {
       handleList(listResult.data?.rows);

+ 59 - 0
packages/cpt_uk/lib/modules/attendance/e_attendance_list/item_e_attendance.dart

@@ -275,6 +275,65 @@ class EAttendanceItem extends StatelessWidget {
             ],
           ).marginOnly(top: 12),
 
+          // 总小时
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                '${"Total Hours".tr}:',
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+
+              //时间
+              MyTextView(
+                item.totalHours ?? "-",
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor:  Colors.white,
+                fontSize: 14,
+                marginRight: 5,
+              ),
+
+              // reviseHours
+              Visibility(
+                visible: item.reviseHours != null && item.reviseHours != "",
+                child: MyTextView(
+                  '+${item.reviseHours}',
+                  marginLeft: 5,
+                  isFontRegular: true,
+                  textColor:  Colors.blue,
+                  fontSize: 14,
+                ).expanded(),
+              ),
+            ],
+          ).marginOnly(top: 12),
+
+          // 小费
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                '${"Gratuity".tr}:',
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+
+              //时间
+              MyTextView(
+                item.gratuity ?? "0.00",
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor: /*item.securityOut?.changed == 1 ? ColorConstants.textRedFF6262 : */ Colors.white,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ).marginOnly(top: 12),
+
           // 申请时间
           Row(
             mainAxisSize: MainAxisSize.max,

+ 156 - 57
packages/cpt_uk/lib/modules/job/job_applied/applied_staff_item.dart

@@ -2,6 +2,7 @@ import 'package:cs_resources/constants/color_constants.dart';
 import 'package:cs_resources/generated/assets.dart';
 import 'package:domain/entity/response/job_list_applied_info_entity.dart';
 import 'package:domain/entity/response/job_list_applied_staff_list_entity.dart';
+import 'package:domain/entity/response/uk_job_applied_staff_list_entity.dart';
 import 'package:flutter/cupertino.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter/widgets.dart';
@@ -12,18 +13,23 @@ import 'package:widgets/my_button.dart';
 import 'package:widgets/my_load_image.dart';
 import 'package:widgets/my_text_view.dart';
 
+import 'widget/status_popup_menu.dart';
+
 /**
  * 已申请的员工列表Item
  */
 class AppliedStaffItem extends StatelessWidget {
   final int index;
   final JobListAppliedInfoEntity? jobInfo;
-  final JobListAppliedStaffListRows item;
+  final UkJobAppliedStaffListRows item;
   final VoidCallback? onStatusAction;
   final VoidCallback? onEditAction;
+  final VoidCallback? onReviseAction;
   final VoidCallback? onRemarkAction;
   final VoidCallback? onItemAction;
   final VoidCallback? onMemberAction;
+  final VoidCallback? onTipAction;
+  final Function(String? statusText, String? status, String? toChangeStatusText, String? toChangeStatus)? onChangeStatusAction;
 
   AppliedStaffItem({
     required this.index,
@@ -32,8 +38,11 @@ class AppliedStaffItem extends StatelessWidget {
     this.onStatusAction,
     this.onRemarkAction,
     this.onEditAction,
+    this.onReviseAction,
     this.onItemAction,
     this.onMemberAction,
+    this.onTipAction,
+    this.onChangeStatusAction,
   });
 
   @override
@@ -80,9 +89,9 @@ class AppliedStaffItem extends StatelessWidget {
 
               //是否选中
               Visibility(
-                visible: item.status == 3,
+                visible: item.status == 3,  // 1 Pending 2 Rejected 3 applied 4 Cancelled 5 No Show 6 Approve 7 Completed
                 child: MyAssetImage(
-                  item.isSelected ? Assets.baseServiceItemSelectedIcon : Assets.baseServiceItemUnselectedIcon,
+                  item.isSelected??item.isSelected!? Assets.baseServiceItemSelectedIcon : Assets.baseServiceItemUnselectedIcon,
                   width: 20.5,
                   height: 20.5,
                 ),
@@ -90,8 +99,10 @@ class AppliedStaffItem extends StatelessWidget {
             ],
           ),
 
-          // 工作开始时间
-          Row(
+          // 开始时间   结束时间
+          _buildRowItems(
+              context,
+              leftWidget: Row(
             mainAxisSize: MainAxisSize.max,
             crossAxisAlignment: CrossAxisAlignment.center,
             children: [
@@ -111,15 +122,12 @@ class AppliedStaffItem extends StatelessWidget {
                 fontSize: 14,
               ).expanded(),
             ],
-          ).marginOnly(top: 12),
-
-          // 门卫签到时间
-          Row(
+          ), rightWidget:Row(
             mainAxisSize: MainAxisSize.max,
             crossAxisAlignment: CrossAxisAlignment.center,
             children: [
               MyTextView(
-                "Security In:".tr,
+                "End Time:".tr,
                 isFontRegular: true,
                 textColor: ColorConstants.textGrayAECAE5,
                 fontSize: 14,
@@ -127,22 +135,22 @@ class AppliedStaffItem extends StatelessWidget {
 
               //时间
               MyTextView(
-                item.securityIn?.time ?? "-",
+                item.endTime ?? "-",
                 marginLeft: 5,
                 isFontRegular: true,
-                textColor: item.securityIn?.changed == 1 ? ColorConstants.textRedFF6262 : Colors.white,
+                textColor: Colors.white,
                 fontSize: 14,
               ).expanded(),
             ],
-          ).marginOnly(top: 12),
+          )).marginOnly(top: 12),
 
-          // 工作地签到时
-          Row(
+          // 门卫签到时间  门卫签出时
+          _buildRowItems(context, leftWidget: Row(
             mainAxisSize: MainAxisSize.max,
             crossAxisAlignment: CrossAxisAlignment.center,
             children: [
               MyTextView(
-                "Work In:".tr,
+                "Security In:".tr,
                 isFontRegular: true,
                 textColor: ColorConstants.textGrayAECAE5,
                 fontSize: 14,
@@ -150,22 +158,19 @@ class AppliedStaffItem extends StatelessWidget {
 
               //时间
               MyTextView(
-                item.workIn?.time ?? "-",
+                item.securityIn?.time ?? "-",
                 marginLeft: 5,
                 isFontRegular: true,
-                textColor: item.workIn?.changed == 1 ? ColorConstants.textRedFF6262 : Colors.white,
+                textColor: item.securityIn?.changed == 1 ? ColorConstants.textRedFF6262 : Colors.white,
                 fontSize: 14,
               ).expanded(),
             ],
-          ).marginOnly(top: 12),
-
-          //工作结束时间
-          Row(
+          ), rightWidget: Row(
             mainAxisSize: MainAxisSize.max,
             crossAxisAlignment: CrossAxisAlignment.center,
             children: [
               MyTextView(
-                "End Time:".tr,
+                "Security Out:".tr,
                 isFontRegular: true,
                 textColor: ColorConstants.textGrayAECAE5,
                 fontSize: 14,
@@ -173,22 +178,22 @@ class AppliedStaffItem extends StatelessWidget {
 
               //时间
               MyTextView(
-                item.endTime ?? "-",
+                item.securityOut?.time ?? "-",
                 marginLeft: 5,
                 isFontRegular: true,
-                textColor: Colors.white,
+                textColor: item.securityOut?.changed == 1 ? ColorConstants.textRedFF6262 : Colors.white,
                 fontSize: 14,
               ).expanded(),
             ],
-          ).marginOnly(top: 12),
+          )).marginOnly(top: 12),
 
-          // 工作地签出时间
-          Row(
+          // 工作地签到时间  工作地签出时间
+          _buildRowItems(context, leftWidget: Row(
             mainAxisSize: MainAxisSize.max,
             crossAxisAlignment: CrossAxisAlignment.center,
             children: [
               MyTextView(
-                "Work Out:".tr,
+                "Work In:".tr,
                 isFontRegular: true,
                 textColor: ColorConstants.textGrayAECAE5,
                 fontSize: 14,
@@ -196,22 +201,19 @@ class AppliedStaffItem extends StatelessWidget {
 
               //时间
               MyTextView(
-                item.workOut?.time ?? "-",
+                item.workIn?.time ?? "-",
                 marginLeft: 5,
                 isFontRegular: true,
-                textColor: item.workOut?.changed == 1 ? ColorConstants.textRedFF6262 : Colors.white,
+                textColor: item.workIn?.changed == 1 ? ColorConstants.textRedFF6262 : Colors.white,
                 fontSize: 14,
               ).expanded(),
             ],
-          ).marginOnly(top: 12),
-
-          // 门卫签出时间
-          Row(
+          ), rightWidget: Row(
             mainAxisSize: MainAxisSize.max,
             crossAxisAlignment: CrossAxisAlignment.center,
             children: [
               MyTextView(
-                "Security Out:".tr,
+                "Work Out:".tr,
                 isFontRegular: true,
                 textColor: ColorConstants.textGrayAECAE5,
                 fontSize: 14,
@@ -219,17 +221,20 @@ class AppliedStaffItem extends StatelessWidget {
 
               //时间
               MyTextView(
-                item.securityOut?.time ?? "-",
+                item.workOut?.time ?? "-",
                 marginLeft: 5,
                 isFontRegular: true,
-                textColor: item.securityOut?.changed == 1 ? ColorConstants.textRedFF6262 : Colors.white,
+                textColor: item.workOut?.changed == 1 ? ColorConstants.textRedFF6262 : Colors.white,
                 fontSize: 14,
               ).expanded(),
             ],
-          ).marginOnly(top: 12),
+          )).marginOnly(top: 12),
 
-          // + - Hours
-          Visibility(
+
+          // + - Hours  Total Hours
+          _buildRowItems(context,
+              showLeftWidget: jobInfo?.jobUnit == "hour",
+              leftWidget: Visibility(
             visible: jobInfo?.jobUnit == "hour",
             child: Row(
               mainAxisSize: MainAxisSize.max,
@@ -251,11 +256,10 @@ class AppliedStaffItem extends StatelessWidget {
                   fontSize: 14,
                 ).expanded(),
               ],
-            ).marginOnly(top: 12),
+            ),
           ),
-
-          // Total Hours
-          Visibility(
+              showRightWidget: jobInfo?.jobUnit == "hour",
+              rightWidget: Visibility(
             visible: jobInfo?.jobUnit == "hour",
             child: Row(
               mainAxisSize: MainAxisSize.max,
@@ -277,8 +281,77 @@ class AppliedStaffItem extends StatelessWidget {
                   fontSize: 14,
                 ).expanded(),
               ],
-            ).marginOnly(top: 12),
+            ),
           ),
+          ).marginOnly(top: 12),
+
+          // tip  status
+          _buildRowItems(context,
+            showLeftWidget: true,
+            leftWidget: Row(
+              mainAxisSize: MainAxisSize.max,
+              crossAxisAlignment: CrossAxisAlignment.center,
+              children: [
+                MyTextView(
+                  "Tip:".tr,
+                  isFontRegular: true,
+                  textColor: ColorConstants.textGrayAECAE5,
+                  fontSize: 14,
+                ),
+
+                //小费
+                MyTextView(
+                  item.gratuity ?? "0.00",
+                  marginLeft: 5,
+                  isFontRegular: true,
+                  textColor: ColorConstants.textBlue06D9FF,  //默认蓝色
+                  fontSize: 14,
+                  onClick: (){
+                    onTipAction?.call();
+                  },
+                ).expanded(),
+              ],
+            ),
+            showRightWidget: true,
+            rightWidget: Row(
+              mainAxisSize: MainAxisSize.max,
+              crossAxisAlignment: CrossAxisAlignment.center,
+              children: [
+                MyTextView(
+                  "Status:".tr,
+                  isFontRegular: true,
+                  textColor: ColorConstants.textGrayAECAE5,
+                  fontSize: 14,
+                ),
+
+                //发布状态
+                MyTextView(
+                  onClick: (){
+                    onChangeStatusAction?.call(item.statusShow, item.status.toString(), '2', '2');
+                  },
+                  item.statusShow ?? "-",
+                  marginLeft: 5,
+                  isFontRegular: true,
+                  textColor: "Completed" == item.statusShow
+                      ? ColorConstants.textGreen05DC82
+                      : "Cancelled" == item.statusShow || "Rejected" == item.statusShow
+                      ? ColorConstants.textRedFF6262
+                      : "Revised" == item.statusShow || "Pending" == item.statusShow || "Approve" == item.statusShow
+                      ? ColorConstants.textYellowFFBB1B
+                      : ColorConstants.textBlue06D9FF,  //默认蓝色
+                  fontSize: 14,
+                ).expanded(),
+
+                // StatusPopupMenu(
+                //   statusShow: item.statusShow,
+                //   status: item.status,
+                //   onChangeStatusAction: (String? statusText, String? status, String? toChangeStatusText, String? toChangeStatus){
+                //         onChangeStatusAction?.call(statusText, status.toString(), toChangeStatusText, toChangeStatus);
+                //   },
+                // )
+              ],
+            ),
+          ).marginOnly(top: 12),
 
           // Total Rooms
           Visibility(
@@ -329,30 +402,23 @@ class AppliedStaffItem extends StatelessWidget {
             ],
           ).marginOnly(top: 12),
 
-          // 状态
+          // Reason
           Row(
             mainAxisSize: MainAxisSize.max,
             crossAxisAlignment: CrossAxisAlignment.center,
             children: [
               MyTextView(
-                "Status:".tr,
+                "Reason:".tr,
                 isFontRegular: true,
                 textColor: ColorConstants.textGrayAECAE5,
                 fontSize: 14,
               ),
 
-              //发布状态
               MyTextView(
-                item.statusShow ?? "-",
+                item.rejectRemark??"-",
                 marginLeft: 5,
                 isFontRegular: true,
-                textColor: "Completed" == item.statusShow
-                    ? ColorConstants.textGreen05DC82
-                    : "Cancelled" == item.statusShow || "Rejected" == item.statusShow
-                        ? ColorConstants.textRedFF6262
-                        : "Revised" == item.statusShow || "Pending" == item.statusShow || "Approve" == item.statusShow
-                            ? ColorConstants.textYellowFFBB1B
-                            : ColorConstants.textBlue06D9FF,  //默认蓝色
+                textColor: Colors.white,
                 fontSize: 14,
               ).expanded(),
             ],
@@ -385,6 +451,24 @@ class AppliedStaffItem extends StatelessWidget {
                   ).marginOnly(left: 12),
                 ),
 
+                // revise 按钮
+                Visibility(
+                  visible: item.actionList?.contains("revise") ?? false,
+                  child: MyButton(
+                    onPressed: () {
+                      FocusScope.of(context).unfocus();
+                      onReviseAction?.call();
+                    },
+                    text: "Revise".tr,
+                    textColor: ColorConstants.white,
+                    backgroundColor: hexToColor("#FFFFBB1B"),
+                    radius: 17.25,
+                    minWidth: 60,
+                    minHeight: 35,
+                  ).marginOnly(left: 12),
+                ),
+
+
                 //状态工作流按钮
                 Visibility(
                   visible: item.actionList?.contains("status") ?? false,
@@ -427,4 +511,19 @@ class AppliedStaffItem extends StatelessWidget {
       }),
     );
   }
+
+
+  Widget _buildRowItems(BuildContext? context, {
+    bool showLeftWidget = true,
+    bool showRightWidget = true,
+    Widget? leftWidget,
+    Widget? rightWidget,
+  }){
+    return Row(
+      children: [
+        showLeftWidget && leftWidget!=null ? Expanded(flex:1, child: leftWidget ?? const SizedBox.shrink(),): const SizedBox.shrink(),
+        showRightWidget && rightWidget!=null ? Expanded(flex:1,child: rightWidget ?? const SizedBox.shrink()): const SizedBox.shrink(),
+      ],
+    );
+  }
 }

+ 79 - 11
packages/cpt_uk/lib/modules/job/job_applied/job_applied_controller.dart

@@ -1,5 +1,9 @@
+import 'dart:ui';
+
 import 'package:domain/entity/response/job_list_applied_staff_list_entity.dart';
+import 'package:domain/entity/response/uk_job_applied_staff_list_entity.dart';
 import 'package:domain/repository/job_repository.dart';
+import 'package:domain/repository/uk_job_repository.dart';
 import 'package:get/get.dart';
 import 'package:plugin_basic/constants/app_constant.dart';
 import 'package:plugin_platform/engine/dialog/dialog_engine.dart';
@@ -8,20 +12,24 @@ import 'package:plugin_platform/engine/toast/toast_engine.dart';
 import 'package:plugin_platform/http/dio/dio_cancelable_mixin.dart';
 import 'package:shared/utils/date_time_utils.dart';
 import 'package:shared/utils/event_bus.dart';
+import 'package:shared/utils/log_utils.dart';
 import 'package:shared/utils/util.dart';
 import 'package:widgets/dialog/app_default_dialog.dart';
 import 'package:widgets/load_state_layout.dart';
 import 'package:widgets/widget_export.dart';
 import '../job_applied_edit/job_applied_edit_page.dart';
+import '../job_applied_revise_list/job_applied_revise_list_page.dart';
 import '../job_applied_staff_detail/applied_staff_detail_page.dart';
 import '../job_applied_workflow/applied_workflow_page.dart';
 import 'job_applied_state.dart';
 import 'widget/applied_add_staff.dart';
 import 'widget/applied_butch_modify.dart';
+import 'widget/applied_set_tip.dart';
 import 'widget/applied_staff_reviews.dart';
 
 class JobAppliedController extends GetxController with DioCancelableMixin {
   final JobRepository _jobRepository = Get.find();
+  final UKJobRepository _ukjobRepository = Get.find();
   final JobAppliedState state = JobAppliedState();
 
   var _curPage = 1;
@@ -86,7 +94,7 @@ class JobAppliedController extends GetxController with DioCancelableMixin {
     }
 
     // 获取 Applied 列表
-    var listResult = await _jobRepository.fetchJobAppliedStaffs(
+    var listResult = await _ukjobRepository.fetchJobAppliedStaffs(
       state.jobId,
       state.keyword,
       curPage: _curPage,
@@ -106,7 +114,7 @@ class JobAppliedController extends GetxController with DioCancelableMixin {
   }
 
   // 处理数据与展示的逻辑
-  void handleList(List<JobListAppliedStaffListRows>? list) {
+  void handleList(List<UkJobAppliedStaffListRows>? list) {
     if (list != null && list.isNotEmpty) {
       //有数据,判断是刷新还是加载更多的数据
       if (_curPage == 1) {
@@ -189,6 +197,8 @@ class JobAppliedController extends GetxController with DioCancelableMixin {
       widget: AppliedAddStaff(
         jobId: state.jobId!,
         confirmAction: (selectedIds) {
+          state.addStaffCount = selectedIds?.split(",").length?? 0;
+          Log.d("新添加员工数量:${state.addStaffCount}");
           //调用接口添加员工
           _requestAddStaff2Applied(selectedIds);
         },
@@ -201,6 +211,7 @@ class JobAppliedController extends GetxController with DioCancelableMixin {
     var result = await _jobRepository.addStaff2Job(state.jobId, selectedIds, cancelToken: cancelToken);
 
     if (result.isSuccess) {
+
       var addStaffEntity = result.data;
       List<String> filteredMessages = [];
       if (addStaffEntity != null && addStaffEntity.resultList?.isNotEmpty == true) {
@@ -210,6 +221,7 @@ class JobAppliedController extends GetxController with DioCancelableMixin {
             .toList();
       }
 
+
       if (filteredMessages.isNotEmpty) {
         //有错误信息
         NotifyEngine.showFailure(filteredMessages.join(" , "));
@@ -218,6 +230,8 @@ class JobAppliedController extends GetxController with DioCancelableMixin {
         NotifyEngine.showSuccess("Successful".tr);
         //添加成功之后刷新页面
         refreshController.callRefresh();
+        // 同时还需要 通知 job-list 页面 修改 指定item的 staff
+        bus.emit(AppConstant.eventJobListChangeStaffNo, {'addStaffCount': state.addStaffCount,'jobId': state.jobId});
       }
     } else {
       ToastEngine.show(result.errorMsg ?? "Network Load Error".tr);
@@ -225,13 +239,25 @@ class JobAppliedController extends GetxController with DioCancelableMixin {
     }
   }
 
+  // 修改状态
+  void changeStatus(String? statusText, String? status, String? toChangeStatusText, String? toChangeStatus) async {
+    // 修改状态   只有applied 状态才能修改 成 Rejected 和 No Show
+    Log.d("修改前的 statusText: ${statusText}, 修改前的 status: ${status}, 要修改的 statusText: ${toChangeStatusText}, 要修改的 status: ${toChangeStatus}");
+  }
+
+  // 去Revise 页面
+  void gotoRevisePage(UkJobAppliedStaffListRows data) {
+    UKJobAppliedRevisePage.startInstance(data.appliedId.toString());
+  }
+
+
   /// 去编辑员工信息页面
-  void gotoAppliedEditPage(JobListAppliedStaffListRows data) {
+  void gotoAppliedEditPage(UkJobAppliedStaffListRows data) {
     UKJobAppliedEditPage.startInstance(data.appliedId.toString());
   }
 
   /// 展示评论的弹窗
-  void showRemarkDialog(JobListAppliedStaffListRows data) async {
+  void showRemarkDialog(UkJobAppliedStaffListRows data) async {
     //请求接口获取到已评论的数据
     var result = await _jobRepository.fetchAppliedStaffReviewView(data.appliedId.toString());
 
@@ -266,20 +292,62 @@ class JobAppliedController extends GetxController with DioCancelableMixin {
   }
 
   /// 去展示员工状态的审核流程页面
-  void gotoAppliedWorkflowPage(JobListAppliedStaffListRows data) {
+  void gotoAppliedWorkflowPage(UkJobAppliedStaffListRows data) {
     UKAppliedWorkflowPage.startInstance(data.appliedId.toString());
   }
 
   /// 去查看员工详情页面
-  void gotoStaffDetailPage(JobListAppliedStaffListRows data) {
+  void gotoStaffDetailPage(UkJobAppliedStaffListRows data) {
     UKAppliedStaffDetailPage.startInstance(data.memberId.toString());
   }
 
+  // 设置小费
+  void showTipDialog(UkJobAppliedStaffListRows data){
+    // 只有 statusShow 不为 Approve 或者不为Completed 的状态才能设置小费
+    DialogEngine.show(
+      tag: 'AppliedSetTip',
+      widget: SetTip(
+        settedTip: '',
+        isConfirmAutoClose: false,
+        confirmAction: (tipNum) {
+          Log.d("设置的小费为----  ${tipNum}");
+          if(Utils.isNotEmpty(tipNum)){
+            //调用接口设置小费
+            _requestSetTip(tipNum, data.appliedId.toString(), callback: (){
+              SmartDialog.dismiss(tag: 'AppliedSetTip');
+            });
+          }else {
+            ToastEngine.show("Please enter the tip amount".tr);
+          }
+        },
+      ),
+    );
+  }
+
+  Future<void> _requestSetTip(String tipNum, String appliedId, {VoidCallback? callback}) async {
+    final result = await _ukjobRepository.appliedStaffBatchSetTipSubmit(
+      appliedIds: appliedId,
+      gratuity: tipNum,
+    );
+    if(result.isSuccess){
+      // 更新当前员工的小费
+      // 找到 当前员工
+      var appliedStaff = state.datas.where((element) => element.appliedId?.toString() == appliedId)?.first;
+      appliedStaff?.gratuity = tipNum;
+      update();
+      NotifyEngine.showSuccess("Successful".tr);
+      callback?.call();
+    }else{
+      ToastEngine.show(result.errorMsg ?? "Network Load Error".tr);
+    }
+  }
+
   /// Item选中与未选中设置
-  void doSelectedOrNot(JobListAppliedStaffListRows data) {
+  void doSelectedOrNot(UkJobAppliedStaffListRows data) {
+    // 1 Pending 2 Rejected 3 applied 4 Cancelled 5 No Show 6 Approve 7 Completed
     //只有 Approve = 3 的状态才能选中
     if (data.status == 3) {
-      data.isSelected = !data.isSelected;
+      data.isSelected = !(data.isSelected??false);
       update();
     }
   }
@@ -363,7 +431,7 @@ class JobAppliedController extends GetxController with DioCancelableMixin {
 
   /// 根据ID获取Item对象,用于刷新
   void fetchItemByIdAndRefreshItem(String appliedIds) async {
-    var result = await _jobRepository.fetchItemByAppliedIds(
+    var result = await _ukjobRepository.fetchItemByAppliedIds(
       state.jobId,
       appliedIds,
       cancelToken: cancelToken,
@@ -373,10 +441,10 @@ class JobAppliedController extends GetxController with DioCancelableMixin {
     if (result.isSuccess) {
       var data = result.data;
       if (data != null && data.rows != null && data.rows!.isNotEmpty) {
-        List<JobListAppliedStaffListRows> newItem = data.rows!;
+        List<UkJobAppliedStaffListRows> newItem = data.rows!;
 
         // 创建一个 Map 来加速查找
-        Map<int, JobListAppliedStaffListRows> newItemMap = {for (var item in newItem) item.appliedId: item};
+        Map<int, UkJobAppliedStaffListRows> newItemMap = {for (var item in newItem) item.appliedId!: item};
 
         // 遍历 state.datas 进行替换
         for (int i = 0; i < state.datas.length; i++) {

+ 31 - 1
packages/cpt_uk/lib/modules/job/job_applied/job_applied_page.dart

@@ -2,6 +2,7 @@ import 'package:cs_resources/constants/color_constants.dart';
 import 'package:flutter/cupertino.dart';
 import 'package:flutter/material.dart';
 import 'package:get/get.dart';
+import 'package:shared/utils/log_utils.dart';
 import 'package:widgets/ext/ex_widget.dart';
 import 'package:widgets/load_state_layout.dart';
 import 'package:widgets/my_button.dart';
@@ -144,9 +145,15 @@ class _JobAppliedState extends BaseState<UKJobAppliedPage, JobAppliedController>
                             index: index,
                             jobInfo: state.jobInfo,
                             item: state.datas[index],
+                            onChangeStatusAction: (String? statusText, String? status, String? toChangeStatusText, String? toChangeStatus) {
+                              controller.changeStatus(statusText, status, toChangeStatusText, toChangeStatus );
+                            },
                             onEditAction: () {
                               controller.gotoAppliedEditPage(state.datas[index]);
                             },
+                            onReviseAction: (){
+                              controller.gotoRevisePage(state.datas[index]);
+                            },
                             onRemarkAction: () {
                               controller.showRemarkDialog(state.datas[index]);
                             },
@@ -159,6 +166,9 @@ class _JobAppliedState extends BaseState<UKJobAppliedPage, JobAppliedController>
                             onMemberAction: (){
                               controller.gotoStaffDetailPage(state.datas[index]);
                             },
+                            onTipAction: () {
+                              controller.showTipDialog(state.datas[index]);
+                            },
                           );
                         },
                         childCount: state.datas.length,
@@ -167,6 +177,26 @@ class _JobAppliedState extends BaseState<UKJobAppliedPage, JobAppliedController>
                   ),
                 ).expanded(),
 
+                // 小费 (批量设置小费 和 批量审核/拒绝 能设置的状态不一致 导致公用同一个选项选择有问题 故先不批量设置小费 单独进行设置小费)
+                // Row(
+                //   mainAxisSize: MainAxisSize.max,
+                //   children: [
+                //     MyTextView(
+                //       "Tip".tr,
+                //       fontSize: 17,
+                //       isFontMedium: true,
+                //       boxHeight: 48,
+                //       onClick: () {
+                //         controller.showTipDialog();
+                //       },
+                //       alignment: Alignment.center,
+                //       textAlign: TextAlign.center,
+                //       textColor: Colors.white,
+                //       backgroundColor: Color(0XFFCA28E4),
+                //     ).expanded(),
+                //
+                //   ],
+                // ),
                 Row(
                   mainAxisSize: MainAxisSize.max,
                   children: [
@@ -185,7 +215,7 @@ class _JobAppliedState extends BaseState<UKJobAppliedPage, JobAppliedController>
                       backgroundColor: Color(0XFF0AC074),
                     ).expanded(),
 
-                    //批量修改时间
+                    //批量reject
                     MyTextView(
                       "Batch Modify".tr,
                       fontSize: 17,

+ 7 - 2
packages/cpt_uk/lib/modules/job/job_applied/job_applied_state.dart

@@ -1,5 +1,7 @@
 import 'package:domain/entity/response/job_list_applied_info_entity.dart';
 import 'package:domain/entity/response/job_list_applied_staff_list_entity.dart';
+import 'package:domain/entity/response/uk_job_applied_staff_list_entity.dart';
+import 'package:domain/entity/response/uk_labour_request_review_list_entity.dart';
 import 'package:flutter/material.dart';
 
 class JobAppliedState {
@@ -8,7 +10,10 @@ class JobAppliedState {
   String keyword = "";
 
   String? jobId;
-  JobListAppliedInfoEntity? jobInfo; //指定工作的简短信息
+  JobListAppliedInfoEntity? jobInfo;
 
-  List<JobListAppliedStaffListRows> datas = []; //Applied的员工列表
+  int addStaffCount = 0;
+
+
+  List<UkJobAppliedStaffListRows> datas = []; //Applied的员工列表
 }

+ 16 - 2
packages/cpt_uk/lib/modules/job/job_applied/widget/applied_add_staff.dart

@@ -2,11 +2,13 @@ import 'dart:ui';
 
 import 'package:cs_resources/generated/assets.dart';
 import 'package:domain/entity/response/job_list_applied_staff_search_entity.dart';
+import 'package:domain/entity/response/uk_job_list_applied_staff_search_entity.dart';
 import 'package:flutter/cupertino.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter/widgets.dart';
 import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
 import 'package:get/get.dart';
+import 'package:shared/utils/log_utils.dart';
 import 'package:widgets/ext/ex_widget.dart';
 import 'package:cs_resources/constants/color_constants.dart';
 import 'package:widgets/load_state_layout.dart';
@@ -140,6 +142,9 @@ class _AppliedAddStaffState extends State<AppliedAddStaff> {
                             /// Item选中与未选中设置
                             controller.datas[index].isSelected = !controller.datas[index].isSelected;
                             controller.update();
+                          }, clickFavoriteCallback: () {
+                            // 调用 打标的 接口
+                            controller.handlerSetFavourite(controller.datas[index]);
                           });
                         },
                         childCount: controller.datas.length,
@@ -222,7 +227,7 @@ class _AppliedAddStaffState extends State<AppliedAddStaff> {
 
   }
 
-  Widget _buildStaffItem(JobListAppliedStaffSearchRows item, VoidCallback callback) {
+  Widget _buildStaffItem(UkJobListAppliedStaffSearchRows item, VoidCallback clickItemCallback, { VoidCallback? clickFavoriteCallback }) {
     return Stack(
       children: [
         Column(
@@ -330,6 +335,15 @@ class _AppliedAddStaffState extends State<AppliedAddStaff> {
           ],
         ).paddingOnly(left: 19, right: 20, top: 17),
 
+        //是否打标记的员工
+        MyAssetImage(
+          (item.isFavourite !=null && item.isFavourite == 1) ? Assets.baseServiceMarkActive : Assets.baseServiceMarkInactive,
+          width: 20,
+          height: 18.5,
+        ).alignRight().marginOnly(right: 55, top: 17.5).onTap((){
+          clickFavoriteCallback?.call();
+        }),
+
         //是否勾选
         MyAssetImage(
           item.isSelected ? Assets.baseServiceItemSelectedIcon : Assets.baseServiceItemUnselectedGrayIcon,
@@ -337,6 +351,6 @@ class _AppliedAddStaffState extends State<AppliedAddStaff> {
           height: 20.5,
         ).alignRight().marginOnly(right: 20, top: 17.5),
       ],
-    ).onTap(callback);
+    ).onTap(clickItemCallback);
   }
 }

+ 32 - 5
packages/cpt_uk/lib/modules/job/job_applied/widget/applied_add_staff_controller.dart

@@ -1,7 +1,10 @@
-import 'package:domain/entity/response/job_list_applied_staff_search_entity.dart';
-import 'package:domain/repository/job_repository.dart';
+import 'package:domain/entity/response/uk_job_list_applied_staff_search_entity.dart';
+import 'package:domain/repository/uk_job_repository.dart';
 import 'package:flutter/material.dart';
 import 'package:plugin_basic/basic_export.dart';
+import 'package:plugin_platform/engine/loading/loading_engine.dart';
+import 'package:plugin_platform/engine/notify/notify_engine.dart';
+import 'package:plugin_platform/engine/toast/toast_engine.dart';
 import 'package:plugin_platform/http/dio/dio_cancelable_mixin.dart';
 import 'package:shared/utils/log_utils.dart';
 import 'package:widgets/load_state_layout.dart';
@@ -11,7 +14,7 @@ import 'package:widgets/widget_export.dart';
  * 添加员工的弹窗的控制器
  */
 class AppliedAddStaffController extends GetxController with DioCancelableMixin {
-  final JobRepository _jobRepository = Get.find();
+  final UKJobRepository _jobRepository = Get.find();
 
   TextEditingController searchController = TextEditingController();
 
@@ -24,7 +27,7 @@ class AppliedAddStaffController extends GetxController with DioCancelableMixin {
 
   String keyword = "";
   String? jobId = null;
-  List<JobListAppliedStaffSearchRows> datas = [];
+  List<UkJobListAppliedStaffSearchRows> datas = [];
 
   //刷新页面状态
   void changeLoadingState(LoadState state) {
@@ -84,13 +87,16 @@ class AppliedAddStaffController extends GetxController with DioCancelableMixin {
   }
 
   // 处理数据与展示的逻辑
-  void handleList(List<JobListAppliedStaffSearchRows>? list) {
+  void handleList(List<UkJobListAppliedStaffSearchRows>? list) {
+    Log.d("563435  ${list}");
+
     if (list != null && list.isNotEmpty) {
       //有数据,判断是刷新还是加载更多的数据
       if (_curPage == 1) {
         //刷新的方式
         datas.clear();
         datas.addAll(list);
+        Log.d("fdjskfjdskfjsd  ${datas}");
         refreshController.finishRefresh();
 
         //更新展示的状态
@@ -120,6 +126,27 @@ class AppliedAddStaffController extends GetxController with DioCancelableMixin {
     refreshController.callRefresh();
   }
 
+  // 打标签
+  Future handlerSetFavourite(UkJobListAppliedStaffSearchRows  data) async{
+    Log.d("点击前 isFavourite: ${data.isFavourite}");
+    String memberId = data.id!.toString();
+    String isFavourite = data.isFavourite?.toString()??"0";
+    String toFavourite = isFavourite == "0" ? "1" : "0";
+    Log.d("isFavourite需要设置成 : ${toFavourite}");
+
+    LoadingEngine.show();
+    final result = await _jobRepository.staffSetFavourite(memberId, toFavourite);
+    if(result.isSuccess){
+      data.isFavourite = int.parse(toFavourite);
+      update();
+      LoadingEngine.dismiss();
+      NotifyEngine.showSuccess("Successful".tr);
+    }else {
+      LoadingEngine.dismiss();
+      ToastEngine.show(result.errorMsg ?? "Network Load Error".tr);
+    }
+  }
+
   @override
   void onReady() {
     super.onReady();

+ 183 - 0
packages/cpt_uk/lib/modules/job/job_applied/widget/applied_set_tip.dart

@@ -0,0 +1,183 @@
+import 'dart:typed_data';
+import 'dart:ui';
+
+import 'package:cs_resources/generated/assets.dart';
+import 'package:flutter/cupertino.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter/services.dart';
+import 'package:flutter/widgets.dart';
+import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
+import 'package:get/get.dart';
+import 'package:plugin_platform/engine/toast/toast_engine.dart';
+import 'package:shared/utils/date_time_utils.dart';
+import 'package:shared/utils/log_utils.dart';
+import 'package:widgets/ext/ex_widget.dart';
+import 'package:cs_resources/constants/color_constants.dart';
+import 'package:widgets/my_load_image.dart';
+import 'package:widgets/my_text_view.dart';
+import 'package:widgets/picker/date_picker_util.dart';
+import 'package:widgets/shatter/form_require_text.dart';
+import 'package:widgets/shatter/round_my_text_field.dart';
+import 'package:widgets/widget_export.dart';
+
+/*
+ * 设置小费的弹窗
+ */
+class SetTip extends StatefulWidget {
+  String? settedTip;
+  bool? isConfirmAutoClose = true;
+  TextInputType? textInputType = TextInputType.numberWithOptions(decimal: true);
+  void Function(String settedTip)? confirmAction;
+
+  SetTip({this.settedTip,this.isConfirmAutoClose, this.confirmAction});
+
+  @override
+  State<SetTip> createState() => _SetTipState();
+}
+
+class _SetTipState extends State<SetTip> {
+  String? settedTip;
+
+  //表单的校验与数据
+  Map<String, Map<String, dynamic>> formData = {
+    'setted_tip': {
+      'value': '',
+      'controller': TextEditingController(),
+      'focusNode': FocusNode(),
+      'hintText': 'Enter...'.tr,
+      'obsecure': false,
+    },
+  };
+
+  @override
+  void initState() {
+    super.initState();
+    settedTip = widget.settedTip;
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return Column(
+      crossAxisAlignment: CrossAxisAlignment.center,
+      mainAxisAlignment: MainAxisAlignment.center,
+      children: [
+        //Title (如果使用 Container 为最外层容器则默认为 match_parent 的效果,除非我们限制宽度和最大高度最小高度)
+        Container(
+          padding: const EdgeInsets.symmetric(horizontal: 16.5),
+          width: double.infinity,
+          decoration: const BoxDecoration(
+            color: Colors.white,
+            borderRadius: BorderRadius.all(Radius.circular(15)),
+          ),
+          child: Column(
+            crossAxisAlignment: CrossAxisAlignment.start,
+            children: [
+              Center(
+                child: MyTextView(
+                  "Tip".tr,
+                  fontSize: 19,
+                  isFontMedium: true,
+                  textColor: ColorConstants.black,
+                  marginTop: 20,
+                  marginBottom: 20,
+                ),
+              ),
+
+              FormRequireText(
+                fontSize: 14,
+                textColor: ColorConstants.black33,
+                fontWeight: FontWeight.w400,
+                text: "Tip".tr,
+              ),
+
+              //输入框(只允许输入带小数的数字)
+              CustomTextField(
+                formKey: "setted_tip",
+                marginLeft: 0,
+                marginRight: 0,
+                paddingTop: 0,
+                paddingBottom: 0,
+                height: 45,
+                fillBackgroundColor: Color(0xFFF0F0F0),
+                enabled: true,
+                inputFormatters: <TextInputFormatter>[ FilteringTextInputFormatter.allow(RegExp(r'^\d+\.?\d*'))],
+                textInputType: widget.textInputType??TextInputType.numberWithOptions(decimal: true),
+                formData: formData,
+                textInputAction: TextInputAction.done,
+                textColor:  ColorConstants.black,
+                onSubmit: (key, value) {
+                  FocusScope.of(context).unfocus();
+                  var tipNumController = formData['setted_tip']!['controller'];
+                  settedTip = tipNumController.text;
+                },
+                marginTop: 10,
+              ),
+
+              Container(
+                margin: const EdgeInsets.only(top: 25),
+                color: const Color(0XFFCECECE),
+                height: 0.5,
+              ),
+              Row(
+                children: [
+                  Expanded(
+                      flex: 1,
+                      child: InkWell(
+                        onTap: () {
+                          onCancel();
+                        },
+                        child: MyTextView(
+                          "Cancel".tr,
+                          fontSize: 17.5,
+                          isFontMedium: true,
+                          textAlign: TextAlign.center,
+                          textColor: Color(0XFF0085C4),
+                          cornerRadius: 3,
+                          borderWidth: 1,
+                        ),
+                      )),
+                  Container(
+                    color: Color(0xff09141F).withOpacity(0.13),
+                    width: 0.5,
+                  ),
+                  Expanded(
+                      flex: 1,
+                      child: InkWell(
+                        onTap: () async {
+                          var tipNumController = formData['setted_tip']!['controller'];
+                          String tipNum = tipNumController.text;
+                          settedTip = tipNum;
+                          if (settedTip == null) {
+                            ToastEngine.show("Enter Tip".tr);
+                            return;
+                          }
+
+                          widget.confirmAction?.call(settedTip!);
+                          if(widget.isConfirmAutoClose??true){
+                            onCancel();
+                          }
+                        },
+                        child: MyTextView(
+                          "Submit".tr,
+                          marginLeft: 10,
+                          fontSize: 17.5,
+                          isFontMedium: true,
+                          textAlign: TextAlign.center,
+                          textColor: const Color(0XFF0085C4),
+                          cornerRadius: 3,
+                        ),
+                      )),
+                ],
+              ).constrained(height: 46),
+            ],
+          ),
+        ),
+      ],
+    ).constrained(width: 285);
+  }
+
+  //取消弹框
+  void onCancel() async {
+    SmartDialog.dismiss();
+  }
+}

+ 74 - 0
packages/cpt_uk/lib/modules/job/job_applied/widget/status_popup_menu.dart

@@ -0,0 +1,74 @@
+import 'dart:ui';
+
+import 'package:cs_resources/constants/color_constants.dart';
+import 'package:flutter/material.dart';
+import 'package:shared/utils/log_utils.dart';
+import 'package:widgets/ext/ex_widget.dart';
+import 'package:widgets/my_text_view.dart';
+
+class StatusPopupMenu extends StatelessWidget {
+  final String? statusShow;
+  final int? status;
+  final Function(String? statusText, String? status, String? toChangeStatusText, String? toChangeStatus)? onChangeStatusAction;
+
+  const StatusPopupMenu({
+    Key? key,
+    required this.statusShow,
+    required this.status,
+    this.onChangeStatusAction,
+  }) : super(key: key);
+
+  @override
+  Widget build(BuildContext context) {
+    return PopupMenuButton<String>(
+        offset: Offset(50, 20),
+      onSelected: (String result) {
+        Log.d("选取的 result: ${result}");
+        // 根据选择的结果调用onChangeStatusAction
+        // 1 Pending 2 Rejected 3 applied 4 Cancelled 5 No Show 6 Approve 7 Completed
+        if (result == 'Rejected') {
+          onChangeStatusAction?.call(statusShow, status?.toString(), 'Rejected', '2');
+        } else if (result == 'No Show') {
+          onChangeStatusAction?.call(statusShow, status?.toString(), 'No Show', '5');
+        }
+      },
+      itemBuilder: (BuildContext context) => <PopupMenuEntry<String>>[
+        PopupMenuItem<String>(
+          height: 40,
+          value: 'Rejected',
+          child: MyTextView(
+            'Rejected',
+            textColor: ColorConstants.textRedFF6262,
+          ),
+        ),
+        PopupMenuItem<String>(
+          height: 40,
+          value: 'No Show',
+          child: MyTextView(
+            'No Show',
+            textColor: ColorConstants.textYellowFFBB1B,
+          ),
+        ),
+      ],
+      child: MyTextView(
+        statusShow ?? "-",
+        marginLeft: 5,
+        isFontRegular: true,
+        textColor: _getStatusColor(statusShow),
+        fontSize: 14,
+      ),
+    );
+  }
+
+  Color _getStatusColor(String? statusShow) {
+    if (statusShow == "Completed") {
+      return ColorConstants.textGreen05DC82;
+    } else if (statusShow == "Cancelled" || statusShow == "Rejected") {
+      return ColorConstants.textRedFF6262;
+    } else if (statusShow == "Revised" || statusShow == "Pending" || statusShow == "Approve") {
+      return ColorConstants.textYellowFFBB1B;
+    } else {
+      return ColorConstants.textBlue06D9FF;
+    }
+  }
+}

+ 5 - 0
packages/cpt_uk/lib/modules/job/job_applied_edit/job_applied_edit_controller.dart

@@ -141,6 +141,11 @@ class JobAppliedEditController extends GetxController with DioCancelableMixin {
     TextEditingController totalRoomController = state.formData['total_room']!['controller'];
     TextEditingController addHourController = state.formData['add_hours']!['controller'];
     TextEditingController reasonController = state.formData['reason']!['controller'];
+    // 当 选择的 reason 选项的value 为 3 时 需要必须填写原因
+    if (state.appliedEditView!.reasonType == 3 && reasonController.text.isEmpty) {
+      ToastEngine.show("Please fill in the reason".tr);
+      return;
+    }
     // 获取文本并尝试转换为整数
     String totalRoomText = totalRoomController.text;
     if (totalRoomText.isNotEmpty) {

+ 38 - 33
packages/cpt_uk/lib/modules/job/job_applied_edit/job_applied_edit_page.dart

@@ -4,6 +4,7 @@ import 'package:flutter/cupertino.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter/services.dart';
 import 'package:get/get.dart';
+import 'package:shared/utils/log_utils.dart';
 import 'package:widgets/ext/ex_widget.dart';
 import 'package:widgets/my_button.dart';
 import 'package:widgets/my_load_image.dart';
@@ -159,16 +160,12 @@ class _JobAppliedEditState extends BaseState<UKJobAppliedEditPage, JobAppliedEdi
                         controller.pickStartTime();
                       }),
 
-                      //门卫签到时间
-                      MyTextView(
-                        "Security In".tr,
-                        textColor: Colors.white,
-                        fontSize: 15,
-                        marginTop: 15,
-                        isFontRegular: true,
-                      ),
+                      //结束时间
+                      FormRequireText(
+                        text: "End Time".tr,
+                      ).marginOnly(top: 15),
 
-                      //门卫签到时间
+                      //结束时间
                       Container(
                         padding: EdgeInsets.only(left: 16, right: 10),
                         margin: EdgeInsets.only(top: 10),
@@ -183,32 +180,33 @@ class _JobAppliedEditState extends BaseState<UKJobAppliedEditPage, JobAppliedEdi
                           mainAxisAlignment: MainAxisAlignment.start,
                           children: [
                             MyTextView(
-                              state.appliedEditView?.securityIn ?? "-",
+                              state.appliedEditView?.endTime ?? "-",
                               fontSize: 14,
-                              hint: "Security In".tr,
+                              hint: "Job End Time".tr,
                               textHintColor: ColorConstants.textGrayAECAE5,
                               isFontMedium: true,
                               textColor: ColorConstants.white,
                             ).expanded(),
+
                             //下拉选图标
                             MyAssetImage(Assets.baseServiceTriangleDropDownIcon, width: 11.5, height: 6.28),
                           ],
                         ),
                       ).onTap(() {
                         FocusScope.of(context).unfocus();
-                        controller.pickSecurityInTime();
+                        controller.pickEndTime();
                       }),
 
-                      //工作地签到时间
+                      //门卫签到时间
                       MyTextView(
-                        "Work In".tr,
+                        "Security In".tr,
                         textColor: Colors.white,
                         fontSize: 15,
                         marginTop: 15,
                         isFontRegular: true,
                       ),
 
-                      //工作地签到时间
+                      //门卫签到时间
                       Container(
                         padding: EdgeInsets.only(left: 16, right: 10),
                         margin: EdgeInsets.only(top: 10),
@@ -223,9 +221,9 @@ class _JobAppliedEditState extends BaseState<UKJobAppliedEditPage, JobAppliedEdi
                           mainAxisAlignment: MainAxisAlignment.start,
                           children: [
                             MyTextView(
-                              state.appliedEditView?.workIn ?? "-",
+                              state.appliedEditView?.securityIn ?? "-",
                               fontSize: 14,
-                              hint: "Work In".tr,
+                              hint: "Security In".tr,
                               textHintColor: ColorConstants.textGrayAECAE5,
                               isFontMedium: true,
                               textColor: ColorConstants.white,
@@ -236,15 +234,19 @@ class _JobAppliedEditState extends BaseState<UKJobAppliedEditPage, JobAppliedEdi
                         ),
                       ).onTap(() {
                         FocusScope.of(context).unfocus();
-                        controller.pickWorkInTime();
+                        controller.pickSecurityInTime();
                       }),
 
-                      //结束时间
-                      FormRequireText(
-                        text: "End Time".tr,
-                      ).marginOnly(top: 15),
+                      //门卫签出时间
+                      MyTextView(
+                        "Security Out".tr,
+                        textColor: Colors.white,
+                        fontSize: 15,
+                        marginTop: 15,
+                        isFontRegular: true,
+                      ),
 
-                      //结束时间
+                      //门卫签出时间
                       Container(
                         padding: EdgeInsets.only(left: 16, right: 10),
                         margin: EdgeInsets.only(top: 10),
@@ -259,33 +261,32 @@ class _JobAppliedEditState extends BaseState<UKJobAppliedEditPage, JobAppliedEdi
                           mainAxisAlignment: MainAxisAlignment.start,
                           children: [
                             MyTextView(
-                              state.appliedEditView?.endTime ?? "-",
+                              state.appliedEditView?.securityOut ?? "-",
                               fontSize: 14,
-                              hint: "Job End Time".tr,
+                              hint: "Security Out".tr,
                               textHintColor: ColorConstants.textGrayAECAE5,
                               isFontMedium: true,
                               textColor: ColorConstants.white,
                             ).expanded(),
-
                             //下拉选图标
                             MyAssetImage(Assets.baseServiceTriangleDropDownIcon, width: 11.5, height: 6.28),
                           ],
                         ),
                       ).onTap(() {
                         FocusScope.of(context).unfocus();
-                        controller.pickEndTime();
+                        controller.pickSecurityOutTime();
                       }),
 
-                      //门卫签出时间
+                      //工作地签到时间
                       MyTextView(
-                        "Security Out".tr,
+                        "Work In".tr,
                         textColor: Colors.white,
                         fontSize: 15,
                         marginTop: 15,
                         isFontRegular: true,
                       ),
 
-                      //门卫签出时间
+                      //工作地签到时间
                       Container(
                         padding: EdgeInsets.only(left: 16, right: 10),
                         margin: EdgeInsets.only(top: 10),
@@ -300,9 +301,9 @@ class _JobAppliedEditState extends BaseState<UKJobAppliedEditPage, JobAppliedEdi
                           mainAxisAlignment: MainAxisAlignment.start,
                           children: [
                             MyTextView(
-                              state.appliedEditView?.securityOut ?? "-",
+                              state.appliedEditView?.workIn ?? "-",
                               fontSize: 14,
-                              hint: "Security Out".tr,
+                              hint: "Work In".tr,
                               textHintColor: ColorConstants.textGrayAECAE5,
                               isFontMedium: true,
                               textColor: ColorConstants.white,
@@ -313,9 +314,10 @@ class _JobAppliedEditState extends BaseState<UKJobAppliedEditPage, JobAppliedEdi
                         ),
                       ).onTap(() {
                         FocusScope.of(context).unfocus();
-                        controller.pickSecurityOutTime();
+                        controller.pickWorkInTime();
                       }),
 
+
                       //工作地签出时间
                       MyTextView(
                         "Work Out".tr,
@@ -440,6 +442,9 @@ class _JobAppliedEditState extends BaseState<UKJobAppliedEditPage, JobAppliedEdi
                               options: state.appliedEditView!.reasonList!.map((e) => e.txt).whereType<String>().toList(), //后台返回的数据展示,并且根据后台的数据匹配索引
                               selectedPosition: state.appliedEditView!.reasonList!.indexWhere((element) => element.value == state.appliedEditView!.reasonType),
                               onOptionSelected: (index, text) {
+                                // Log.d("00003  ${index} ${text}");
+                                state.selectedReasonItem = state.appliedEditView!.reasonList![index];
+                                // Log.d("${state.appliedEditView!.reasonList![index]}");
                                 //修改内存的值
                                 state.appliedEditView!.reasonType = state.appliedEditView!.reasonList![index].value;
                               },

+ 2 - 0
packages/cpt_uk/lib/modules/job/job_applied_edit/job_applied_edit_state.dart

@@ -3,6 +3,8 @@ import 'package:flutter/material.dart';
 import 'package:plugin_basic/basic_export.dart';
 
 class JobAppliedEditState {
+  // reason 当前选中的选项
+  JobListAppliedEditReasonList? selectedReasonItem;
   //表单的校验与数据
   Map<String, Map<String, dynamic>> formData = {
     'add_hours': {

+ 287 - 0
packages/cpt_uk/lib/modules/job/job_applied_revise_list/job_applied_revise_list_controller.dart

@@ -0,0 +1,287 @@
+import 'dart:ui';
+
+import 'package:domain/entity/response/uk_job_applied_revise_info_entity.dart';
+import 'package:domain/entity/response/uk_job_applied_staff_list_entity.dart';
+import 'package:domain/repository/job_repository.dart';
+import 'package:domain/repository/uk_job_repository.dart';
+import 'package:get/get.dart';
+import 'package:plugin_platform/engine/dialog/dialog_engine.dart';
+import 'package:plugin_platform/engine/notify/notify_engine.dart';
+import 'package:plugin_platform/engine/toast/toast_engine.dart';
+import 'package:plugin_platform/http/dio/dio_cancelable_mixin.dart';
+import 'package:shared/utils/event_bus.dart';
+import 'package:shared/utils/log_utils.dart';
+import 'package:shared/utils/util.dart';
+import 'package:widgets/dialog/app_default_dialog.dart';
+import 'package:widgets/load_state_layout.dart';
+import 'package:widgets/widget_export.dart';
+import '../job_applied_edit/job_applied_edit_page.dart';
+import '../job_applied_staff_detail/applied_staff_detail_page.dart';
+import '../job_applied_workflow/applied_workflow_page.dart';
+import '../revise_add_edit/revise_add_edit_page.dart';
+import '../revise_log/revise_log_page.dart';
+import 'job_applied_revise_list_state.dart';
+
+
+class JobAppliedReviseListController extends GetxController with DioCancelableMixin {
+  final JobRepository _jobRepository = Get.find();
+  final UKJobRepository _ukjobRepository = Get.find();
+  final JobAppliedReviseListState state = JobAppliedReviseListState();
+
+  var _curPage = 1;
+  var _needShowPlaceholder = true;
+
+  //页面PlaceHolder的展示
+  LoadState loadingState = LoadState.State_Success;
+  String? errorMessage;
+
+  //刷新页面状态
+  void changeLoadingState(LoadState state) {
+    loadingState = state;
+    update();
+  }
+
+  // Refresh 控制器
+  final EasyRefreshController refreshController = EasyRefreshController(
+    controlFinishRefresh: true,
+    controlFinishLoad: true,
+  );
+
+  // Refresh 刷新事件
+  Future onRefresh() async {
+    _curPage = 1;
+    fetchListData();
+  }
+
+  // Refresh 加载事件
+  Future loadMore() async {
+    _curPage++;
+    fetchListData();
+  }
+
+  // 重试请求
+  Future retryRequest() async {
+    _curPage = 1;
+    _needShowPlaceholder = true;
+    fetchListData();
+  }
+
+  /// 获取服务器数据,通知消息列表
+  Future fetchListData() async {
+    if (_needShowPlaceholder) {
+      changeLoadingState(LoadState.State_Loading);
+    }
+
+
+    // 获取  列表
+    var listResult = await _ukjobRepository.fetchJobAppliedReviseList(
+        appliedId: state.appliedId,
+        curPage: _curPage,
+        cancelToken: cancelToken,
+    );
+
+    // 处理数据
+    if (listResult.isSuccess) {
+      handleList(listResult.data?.rows);
+    } else {
+      errorMessage = listResult.errorMsg;
+      changeLoadingState(LoadState.State_Error);
+    }
+
+    // 最后赋值
+    _needShowPlaceholder = false;
+  }
+
+  // 处理数据与展示的逻辑
+  void handleList(List<UkJobAppliedReviseInfoRows>? list) {
+    if (list != null && list.isNotEmpty) {
+      //有数据,判断是刷新还是加载更多的数据
+      if (_curPage == 1) {
+        //刷新的方式
+        state.datas.clear();
+        state.datas.addAll(list);
+        refreshController.finishRefresh();
+
+        //更新展示的状态
+        changeLoadingState(LoadState.State_Success);
+      } else {
+        //加载更多
+        state.datas.addAll(list);
+        refreshController.finishLoad();
+        update();
+      }
+    } else {
+      if (_curPage == 1) {
+        //展示无数据的布局
+        state.datas.clear();
+        changeLoadingState(LoadState.State_Empty);
+        refreshController.finishRefresh();
+      } else {
+        //展示加载完成,没有更多数据了
+        refreshController.finishLoad(IndicatorResult.noMore);
+      }
+    }
+  }
+
+  @override
+  void onReady() {
+    super.onReady();
+    fetchListData();
+    registerEventBus();
+  }
+
+  @override
+  void onClose() {
+    unregisterEventBus();
+    state.datas.clear();
+    super.onClose();
+  }
+
+  // EventBus 的事件接收
+  Subscription? subscribe;
+
+  void registerEventBus() {
+    // subscribe = bus.on(AppConstant.eventAppliedListRefresh, (arg) {
+    //   var appliedId = arg as String;
+    //   if (Utils.isNotEmpty(appliedId)) {
+    //     fetchItemByIdAndRefreshItem(appliedId);
+    //   } else {
+    //     refreshController.callRefresh();
+    //   }
+    // });
+  }
+
+  void unregisterEventBus() {
+    // bus.off(AppConstant.eventAppliedListRefresh, subscribe);
+  }
+
+  /// 搜索员工
+  void doSearch(String keyword) {
+    state.keyword = keyword;
+    //赋值之后刷新
+    refreshController.callRefresh();
+  }
+
+  /// 清空筛选条件
+  void resetFiltering() {
+    state.keyword = "";
+    state.searchController.text = "";
+    //赋值之后刷新
+    refreshController.callRefresh();
+  }
+
+  /// 展示添加员工的弹窗
+  void showAddStaffDialog() {
+
+  }
+
+  //调用接口添加员工
+  void _requestAddStaff2Applied(String selectedIds) async {
+    var result = await _jobRepository.addStaff2Job(state.appliedId, selectedIds, cancelToken: cancelToken);
+
+    if (result.isSuccess) {
+      var addStaffEntity = result.data;
+      List<String> filteredMessages = [];
+      if (addStaffEntity != null && addStaffEntity.resultList?.isNotEmpty == true) {
+        filteredMessages = addStaffEntity.resultList!
+            .where((resultList) => resultList.result == false && Utils.isNotEmpty(resultList.msg))
+            .map((resultList) => '${resultList.name} : ${resultList.msg!}')
+            .toList();
+      }
+
+
+      if (filteredMessages.isNotEmpty) {
+        //有错误信息
+        NotifyEngine.showFailure(filteredMessages.join(" , "));
+      } else {
+        //无错误信息
+        NotifyEngine.showSuccess("Successful".tr);
+        //添加成功之后刷新页面
+        refreshController.callRefresh();
+      }
+    } else {
+      ToastEngine.show(result.errorMsg ?? "Network Load Error".tr);
+      return;
+    }
+  }
+
+
+  /// 去编辑员工信息页面   0 新增  1 编辑 2 详情
+  void gotoReviseDetailPage(int? index, String appliedId, int type) {
+    Log.d("appliedId   $appliedId --- type  $type");
+    if(index != null){
+      Log.d("编辑 时 id: ${state.datas[index].id!.toString()}");
+      UKReviseAddEditPage.startInstance(type, state.datas[index].id!.toString(), (value){});
+    }else {
+      UKReviseAddEditPage.startInstance(type, appliedId, (value){});
+    }
+  }
+  /// 去logs 页面
+  void gotoReviseLogsPage(int? index, String appliedId){
+    if(index != null){
+      UKReviseLogPage.startInstance(state.datas[index].id!.toString());
+    }
+  }
+
+  /// recall 操作
+  void doRecallAction(int index) {
+    DialogEngine.show(
+      tag: 'recallActionTag',
+        widget: AppDefaultDialog(
+          title: "Confirmation".tr,
+          message: "Are you sure you want to recall this revise?".tr,
+          confirmAction: () {
+            _requestRecall(index);
+          },
+        ));
+  }
+
+  void _requestRecall(int index) async {
+    var result = await _ukjobRepository.reviseRecall(reviseId: state.datas[index].id!.toString(), cancelToken: cancelToken);
+
+    if (result.isSuccess) {
+      NotifyEngine.showSuccess("Successful".tr);
+
+      fetchItemByIdAndRefreshItem(state.datas[index].id!.toString());
+    } else {
+      ToastEngine.show(result.errorMsg ?? "Network Load Error".tr);
+    }
+  }
+
+  /// 去展示员工状态的审核流程页面
+  void gotoAppliedWorkflowPage(UkJobAppliedStaffListRows data) {
+    UKAppliedWorkflowPage.startInstance(data.appliedId.toString());
+  }
+  
+
+  /// 根据ID获取Item对象,用于刷新
+  void fetchItemByIdAndRefreshItem(String appliedIds) async {
+    var result = await _ukjobRepository.fetchJobAppliedReviseListById(
+      appliedId: state.appliedId,
+      cancelToken: cancelToken,
+    );
+
+    //处理数据
+    if (result.isSuccess) {
+      var data = result.data;
+      if (data != null && data.rows != null && data.rows!.isNotEmpty) {
+        List<UkJobAppliedReviseInfoRows> newItem = data.rows!;
+
+        // 创建一个 Map 来加速查找
+        Map<int, UkJobAppliedReviseInfoRows> newItemMap = {for (var item in newItem) item.id!: item};
+
+        // 遍历 state.datas 进行替换
+        for (int i = 0; i < state.datas.length; i++) {
+          if (newItemMap.containsKey(state.datas[i].id)) {
+            state.datas[i] = newItemMap[state.datas[i].id]!;
+          }
+        }
+
+        //刷新
+        update();
+      }
+    } else {
+      ToastEngine.show(result.errorMsg ?? "Network Load Error".tr);
+    }
+  }
+}

+ 144 - 0
packages/cpt_uk/lib/modules/job/job_applied_revise_list/job_applied_revise_list_page.dart

@@ -0,0 +1,144 @@
+import 'package:cpt_uk/modules/job/job_applied_revise_list/revise_list_item.dart';
+import 'package:cs_resources/constants/color_constants.dart';
+import 'package:flutter/cupertino.dart';
+import 'package:flutter/material.dart';
+import 'package:get/get.dart';
+import 'package:widgets/ext/ex_widget.dart';
+import 'package:widgets/load_state_layout.dart';
+import 'package:widgets/my_button.dart';
+import 'package:widgets/my_text_view.dart';
+import 'package:widgets/search_app_bar.dart';
+import 'package:widgets/widget_export.dart';
+
+
+import 'package:plugin_basic/base/base_state.dart';
+import 'package:plugin_basic/base/base_stateful_page.dart';
+import 'package:plugin_basic/utils/ext_get_nav.dart';
+import 'package:router/path/router_path.dart';
+import 'package:shared/utils/screen_util.dart';
+import 'package:widgets/my_appbar.dart';
+
+import 'job_applied_revise_list_controller.dart';
+import 'job_applied_revise_list_state.dart';
+
+/*
+ * 已申请的页面,可以签到签出、加人、修改状态、评论等操作
+ */
+class UKJobAppliedRevisePage extends BaseStatefulPage<JobAppliedReviseListController> {
+  UKJobAppliedRevisePage({Key? key}) : super(key: key);
+
+  //启动当前页面
+  static void startInstance(String? appliedId) {
+    return Get.start(RouterPath.UKJobAppliedReviseList, arguments: {'appliedId': appliedId});
+  }
+
+  @override
+  JobAppliedReviseListController createRawController() {
+    return JobAppliedReviseListController();
+  }
+
+  @override
+  State<UKJobAppliedRevisePage> createState() => _JobAppliedState();
+}
+
+class _JobAppliedState extends BaseState<UKJobAppliedRevisePage, JobAppliedReviseListController> {
+  late JobAppliedReviseListState state;
+
+  @override
+  void initState() {
+    super.initState();
+    state = controller.state;
+    state.appliedId = Get.arguments['appliedId'];
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return autoCtlGetBuilder(builder: (controller) {
+      return  SafeArea(
+        bottom: MediaQuery.of(context).padding.bottom > 38,
+        top: false,
+        child: Container(
+          width: double.infinity,
+          height: double.infinity,
+          padding: EdgeInsets.only(top: ScreenUtil.getStatusBarH(context)),
+          decoration: const BoxDecoration(
+            gradient: LinearGradient(
+              colors: [
+                Color(0xFF091D44),
+                Color(0xFF245A8A),
+                Color(0xFF7F7CEC),
+              ],
+              begin: Alignment.topCenter,
+              end: Alignment.bottomCenter,
+            ),
+          ),
+          child: Column(
+            children: [
+              MyAppBar.titleBar(
+                context,
+                "Revise".tr,
+                // subTitle: "",
+                subTitleColor: ColorConstants.textGrayAECAE5,
+              ),
+              // 添加按钮
+              MyButton(
+                type: ClickType.throttle,
+                milliseconds: 500,
+                onPressed: () {
+                  FocusScope.of(context).unfocus();
+                  controller.gotoReviseDetailPage(null, state.appliedId.toString(), 0);
+                },
+                text: "Add Revise".tr,
+                textColor: ColorConstants.white,
+                fontSize: 16,
+                radius: 20,
+                backgroundColor: hexToColor("#855EF5"),
+                fontWeight: FontWeight.w500,
+              ).marginOnly(left: 15, right: 15, top: 5, bottom: 10),
+
+              //底部的列表
+              EasyRefresh(
+                controller: controller.refreshController,
+                onRefresh: controller.onRefresh,
+                onLoad: controller.loadMore,
+                child: LoadStateLayout(
+                  state: controller.loadingState,
+                  errorMessage: controller.errorMessage,
+                  errorRetry: () {
+                    controller.retryRequest();
+                  },
+                  successSliverWidget: [
+                    SliverList(
+                        delegate: SliverChildBuilderDelegate(
+                              (context, index) {
+                            return ReviseListItem(
+                              index: index,
+                              item: state.datas[index],
+                              onDetailAction: () {
+                                controller.gotoReviseDetailPage(index, state.appliedId.toString(), 2);
+                              },
+                              onEditAction: () {
+                                controller.gotoReviseDetailPage(index, state.appliedId.toString(), 1);
+                              },
+                              onLogsAction: () {
+                                controller.gotoReviseLogsPage(index, state.appliedId.toString());
+                              },
+                              onRecallAction: () {
+                                controller.doRecallAction(index);
+                              },
+                              onDeleteAction: () {
+                              },
+                            );
+                          },
+                          childCount: state.datas.length,
+                        ))
+                  ],
+                ),
+              ).expanded(),
+            ],
+          ),
+        ),
+      );
+    });
+  }
+}

+ 13 - 0
packages/cpt_uk/lib/modules/job/job_applied_revise_list/job_applied_revise_list_state.dart

@@ -0,0 +1,13 @@
+import 'package:domain/entity/response/uk_job_applied_revise_info_entity.dart';
+import 'package:flutter/material.dart';
+
+class JobAppliedReviseListState {
+  //筛选条件
+  final TextEditingController searchController = TextEditingController();
+  String keyword = "";
+
+  String? appliedId;
+
+
+  List<UkJobAppliedReviseInfoRows> datas = []; //Revised的列表
+}

+ 322 - 0
packages/cpt_uk/lib/modules/job/job_applied_revise_list/revise_list_item.dart

@@ -0,0 +1,322 @@
+import 'package:cs_resources/constants/color_constants.dart';
+import 'package:domain/entity/response/uk_job_applied_revise_info_entity.dart';
+import 'package:flutter/cupertino.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter/widgets.dart';
+import 'package:plugin_basic/basic_export.dart';
+import 'package:widgets/ext/ex_widget.dart';
+import 'package:widgets/my_button.dart';
+import 'package:widgets/my_text_view.dart';
+
+/*
+ * Revise的Item布局
+ */
+class ReviseListItem extends StatelessWidget {
+  final int index;
+  final UkJobAppliedReviseInfoRows item;
+  final VoidCallback? onDetailAction;
+  final VoidCallback? onLogsAction;
+  final VoidCallback? onDeleteAction;
+  final VoidCallback? onRecallAction;
+  final VoidCallback? onEditAction;
+
+  ReviseListItem({
+    required this.index,
+    required this.item,
+    this.onDetailAction,
+    this.onLogsAction,
+    this.onDeleteAction,
+    this.onRecallAction,
+    this.onEditAction,
+  });
+
+  @override
+  Widget build(BuildContext context) {
+    return Container(
+      padding: const EdgeInsets.symmetric(vertical: 23, horizontal: 21),
+      margin: const EdgeInsets.only(left: 15, right: 15, top: 5, bottom: 5),
+      decoration: BoxDecoration(
+        color: const Color(0xFF4DCFF6).withOpacity(0.2), // 设置背景颜色和不透明度
+        borderRadius: BorderRadius.circular(5), // 设置圆角
+      ),
+      child: Column(
+        mainAxisSize: MainAxisSize.max,
+        crossAxisAlignment: CrossAxisAlignment.start,
+        children: [
+          // 姓名
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "Name:".tr,
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+              MyTextView(
+                 item.staffName??"-",
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor: Colors.white,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ).marginOnly(top: 15),
+
+          // 身份证
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "Nric".tr + ":",
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+
+              MyTextView(
+                 item.staffNric??"-",
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor: Colors.white,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ).marginOnly(top: 15),
+
+          // 工作时间
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "Job Time".tr + ":",
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+              MyTextView(
+                 item.jobTime??"-",
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor: ColorConstants.white,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ).marginOnly(top: 15),
+
+          // // 加减小时
+          // Row(
+          //   mainAxisSize: MainAxisSize.max,
+          //   crossAxisAlignment: CrossAxisAlignment.center,
+          //   children: [
+          //     MyTextView(
+          //       "+/- Hours".tr + ":",
+          //       isFontRegular: true,
+          //       textColor: ColorConstants.textGrayAECAE5,
+          //       fontSize: 14,
+          //     ),
+          //     MyTextView(
+          //       '0',
+          //       marginLeft: 5,
+          //       isFontRegular: true,
+          //       textColor: Colors.white,
+          //       fontSize: 14,
+          //     ).expanded(),
+          //   ],
+          // ).marginOnly(top: 15),
+
+          // 总小时
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "Total Hours:".tr,
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+              MyTextView(
+                item.totalHours != null? item.totalHours!.toString():"-",
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor: Colors.white,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ).marginOnly(top: 15),
+
+          // 修改小时
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "Revise Hours".tr + ":",
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+              MyTextView(
+                item.reviseHours != null? item.reviseHours!.toString():"-",
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor: Colors.white,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ).marginOnly(top: 15),
+
+          // 状态
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "Status:".tr,
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+
+              //状态
+              MyTextView(
+                item.statusShow == null ? "" : item.statusShow!.tr,
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor: Colors.white,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ).marginOnly(top: 15),
+
+          // 修改小时
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "Create At".tr + ":",
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+              MyTextView(
+                item.createdAt??"-",
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor: Colors.white,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ).marginOnly(top: 15),
+
+          //按钮组
+          Visibility(
+            visible: item.actionList?.isNotEmpty ?? false,
+            child: Row(
+              mainAxisSize: MainAxisSize.max,
+              mainAxisAlignment: MainAxisAlignment.end,
+              crossAxisAlignment: CrossAxisAlignment.center,
+              children: [
+                //编辑按钮
+                Visibility(
+                  visible: item.actionList?.contains("edit") ?? false,
+                  child: MyButton(
+                    onPressed: () {
+                      FocusScope.of(context).unfocus();
+                      onEditAction?.call();
+                    },
+                    text: "Edit".tr,
+                    textColor: ColorConstants.white,
+                    backgroundColor: hexToColor(
+                      "#FFBB1B",
+                    ),
+                    radius: 17.25,
+                    minWidth: 60,
+                    minHeight: 35,
+                  ).marginOnly(left: 5,right: 5),
+                ),
+
+                //状态工作流按钮
+                Visibility(
+                  visible: item.actionList?.contains("recall") ?? false,
+                  child: MyButton(
+                    padding: const EdgeInsets.symmetric(horizontal: 10),
+                    onPressed: () {
+                      FocusScope.of(context).unfocus();
+                      onRecallAction?.call();
+                    },
+                    text: "Recall".tr,
+                    textColor: ColorConstants.white,
+                    backgroundColor: ColorConstants.textYellowF8AE00,
+                    radius: 17.25,
+                    minWidth: 60,
+                    minHeight: 35,
+                  ).marginOnly(left: 5,right: 5),
+                ),
+
+                //状态工作流按钮
+                Visibility(
+                  visible: item.actionList?.contains("delete") ?? false,
+                  child: MyButton(
+                    padding: const EdgeInsets.symmetric(horizontal: 10),
+                    onPressed: () {
+                      FocusScope.of(context).unfocus();
+                      onDeleteAction?.call();
+                    },
+                    text: "Delete".tr,
+                    textColor: ColorConstants.white,
+                    backgroundColor: ColorConstants.textRedFF6262,
+                    radius: 17.25,
+                    minWidth: 60,
+                    minHeight: 35,
+                  ).marginOnly(left: 5,right: 5),
+                ),
+
+                //详情按钮
+                Visibility(
+                  visible: item.actionList?.contains("detail") ?? false,
+                  child: MyButton(
+                    padding: const EdgeInsets.symmetric(horizontal: 10),
+                    onPressed: () {
+                      FocusScope.of(context).unfocus();
+                      onDetailAction?.call();
+                    },
+                    text: "Detail".tr,
+                    textColor: ColorConstants.white,
+                    backgroundColor: ColorConstants.textBlue56AAFF,
+                    radius: 17.25,
+                    minWidth: 60,
+                    minHeight: 35,
+                  ).marginOnly(left: 5,right: 5),
+                ),
+
+                //日志
+                Visibility(
+                  visible: item.actionList?.contains("logs") ?? false,
+                  child: MyButton(
+                    padding: const EdgeInsets.symmetric(horizontal: 10),
+                    onPressed: () {
+                      FocusScope.of(context).unfocus();
+                      onLogsAction?.call();
+                    },
+                    text: "Logs".tr,
+                    textColor: ColorConstants.white,
+                    backgroundColor: ColorConstants.textGreen0AC074,
+                    radius: 17.25,
+                    minWidth: 60,
+                    minHeight: 35,
+                  ).marginOnly(left: 5,right: 5),
+                ),
+              ],
+            ).marginOnly(top: 18, bottom: 2),
+          ),
+        ],
+      ),
+    );
+  }
+}

+ 46 - 8
packages/cpt_uk/lib/modules/job/job_applied_staff_detail/applied_staff_detail_controller.dart

@@ -1,18 +1,28 @@
 import 'package:domain/entity/response/staff_detail_entity.dart';
 import 'package:domain/entity/response/staff_labour_history_entity.dart';
+import 'package:domain/entity/response/uk_staff_detail_entity.dart';
+import 'package:domain/entity/response/uk_staff_labour_history_entity.dart';
 import 'package:domain/repository/job_repository.dart';
+import 'package:domain/repository/uk_job_repository.dart';
+import 'package:flutter/cupertino.dart';
 import 'package:get/get.dart';
+import 'package:plugin_basic/modules/preview_photo_page.dart';
+import 'package:plugin_platform/engine/dialog/dialog_engine.dart';
+import 'package:plugin_platform/engine/image/image_preview.dart';
 import 'package:plugin_platform/engine/loading/loading_engine.dart';
 import 'package:plugin_platform/http/dio/dio_cancelable_mixin.dart';
 import 'package:plugin_platform/http/http_result.dart';
+import 'package:shared/utils/log_utils.dart';
 import 'package:widgets/load_state_layout.dart';
 import 'package:widgets/widget_export.dart';
 
 import '../job_applied_staff_reviews/applied_staff_reviews_page.dart';
 import 'applied_staff_detail_state.dart';
+import 'certification_dialog_widget.dart';
 
 class AppliedStaffDetailController extends GetxController with DioCancelableMixin {
   final JobRepository _jobRepository = Get.find();
+  final UKJobRepository _ukJobRepository = Get.find();
   final AppliedStaffDetailState state = AppliedStaffDetailState();
 
   var _curPage = 1;
@@ -64,24 +74,24 @@ class AppliedStaffDetailController extends GetxController with DioCancelableMixi
 
     // 并发执行两个请求
     var futures = [
-      _jobRepository.fetchStaffLabourHistory(
+      _ukJobRepository.fetchStaffLabourHistory(
         state.memberId,
         state.keyword,
         curPage: _curPage,
         cancelToken: cancelToken,
       ),
       state.detail == null
-          ? _jobRepository.fetchStaffDetail(state.memberId, cancelToken: cancelToken)
+          ? _ukJobRepository.fetchStaffDetail(state.memberId, cancelToken: cancelToken)
           : Future(() => HttpResult(isSuccess: true).convert(data: state.detail!)),
     ];
 
     //拿到结果
     var results = await Future.wait(futures);
-    var listResult = results[0] as HttpResult<StaffLabourHistoryEntity>;
-    var detailResult = results[1] as HttpResult<StaffDetailEntity>;
+    var detailResult = results[1] as HttpResult<UkStaffDetailEntity>;
+    var listResult = results[0] as HttpResult<UkStaffLabourHistoryEntity>;
 
     //详情数据
-    if (state.detail == null && detailResult.isSuccess) {
+    if (detailResult.isSuccess) {
       state.detail = detailResult.data!;
     }
 
@@ -100,7 +110,7 @@ class AppliedStaffDetailController extends GetxController with DioCancelableMixi
   }
 
   // 处理数据与展示的逻辑
-  void handleList(List<StaffLabourHistoryRows>? list) {
+  void handleList(List<UkStaffLabourHistoryRows>? list) {
     if (list != null && list.isNotEmpty) {
       //有数据,判断是刷新还是加载更多的数据
       if (_curPage == 1) {
@@ -119,9 +129,23 @@ class AppliedStaffDetailController extends GetxController with DioCancelableMixi
       }
     } else {
       if (_curPage == 1) {
+        // if(_isSearch){
+        //   // // 只需要将  job History list 展示为 空
+        //   // state.datas = [];
+        //   // update();
+        // }else {
+        //   //展示无数据的布局
+        //   state.datas.clear();
+        //   changeLoadingState(LoadState.State_Empty);
+        //   refreshController.finishRefresh();
+        // }
         //展示无数据的布局
         state.datas.clear();
-        changeLoadingState(LoadState.State_Empty);
+        if(state.detail == null){
+          changeLoadingState(LoadState.State_Empty);
+        }else {
+          changeLoadingState(LoadState.State_Success);
+        }
         refreshController.finishRefresh();
       } else {
         //展示加载完成,没有更多数据了
@@ -133,6 +157,7 @@ class AppliedStaffDetailController extends GetxController with DioCancelableMixi
   // 执行搜索
   void doSearch(String keyword) {
     state.keyword = keyword;
+    _curPage = 1;
     //赋值之后刷新
     // refreshController.callRefresh();
     _isSearch = true;
@@ -150,9 +175,22 @@ class AppliedStaffDetailController extends GetxController with DioCancelableMixi
     super.onClose();
   }
 
+  // 显示 证书弹框
+  void showCertificateDialog(BuildContext? context, UkStaffDetailCertificates certificateItem) {
+    DialogEngine.show(
+      tag: 'CertificateDialogTag',
+      widget: certificationDialog(
+        certificateItem: certificateItem,
+          onPreviewImageAction: (String url, List<String> urls, int?  index){
+            ImagePreviewEngine.singleImagePreview(context!, url);
+            // PreviewPhotoPage.startInstance(urls!, index??0);
+        }
+      ),
+    );
+  }
   // 去员工的评论列表页面
   void gotoRemarkHistoryPage() {
-    UKAppliedStaffReviewsPage.startInstance(state.memberId,state.detail?.name,state.detail?.remRate,state.detail?.remNum.toString());
+    UKAppliedStaffReviewsPage.startInstance(state.memberId,state.detail?.name,state.detail?.remRate?.toDouble(),state.detail?.remNum.toString());
   }
 
 }

+ 83 - 33
packages/cpt_uk/lib/modules/job/job_applied_staff_detail/applied_staff_detail_page.dart

@@ -1,6 +1,9 @@
 import 'package:cs_resources/constants/color_constants.dart';
+import 'package:cs_resources/generated/assets.dart';
+import 'package:domain/entity/response/uk_staff_detail_entity.dart';
 import 'package:flutter/material.dart';
 import 'package:get/get.dart';
+import 'package:shared/utils/log_utils.dart';
 import 'package:widgets/ext/ex_widget.dart';
 import 'package:widgets/load_state_layout.dart';
 import 'package:widgets/my_load_image.dart';
@@ -68,43 +71,52 @@ class _AppliedStaffDetailState extends BaseState<UKAppliedStaffDetailPage, Appli
               ),
             ),
             child: Column(
+              mainAxisSize: MainAxisSize.max,
               children: [
                 MyAppBar.titleBar(context, "Staff Detail".tr),
 
-                EasyRefresh(
-                  controller: controller.refreshController,
-                  onRefresh: controller.onRefresh,
-                  onLoad: controller.loadMore,
-                  child: LoadStateLayout(
-                    state: controller.loadingState,
-                    errorMessage: controller.errorMessage,
-                    errorRetry: () {
-                      controller.retryRequest();
-                    },
-                    successSliverWidget: [
-                      //顶部用户信息
-                      SliverToBoxAdapter(
-                        child: StaffDetailWidget(detail: state.detail,onRemarkAction: (){
-                          controller.gotoRemarkHistoryPage();
-                        }),
-                      ),
+                Expanded(
+                  child: EasyRefresh(
+                    controller: controller.refreshController,
+                    onRefresh: controller.onRefresh,
+                    onLoad: controller.loadMore,
+                    child: LoadStateLayout(
+                      state: controller.loadingState,
+                      errorMessage: controller.errorMessage,
+                      errorRetry: () {
+                        controller.retryRequest();
+                      },
+                      successSliverWidget: [
+                        //顶部用户信息
+                        SliverToBoxAdapter(
+                          child: StaffDetailWidget(detail: state.detail,
+                            onRemarkAction: (){
+                              controller.gotoRemarkHistoryPage();
+                            },
+                            onScanCertificateAction: (BuildContext context, UkStaffDetailCertificates certificateItem){
+                              controller.showCertificateDialog(context, certificateItem);
+                            }
+                          ),
+                        ),
 
-                      //中间搜索布局
-                      SliverToBoxAdapter(
-                        child: _buildSearchWidget(),
-                      ),
-
-                      //底部工作历史列表
-                      SliverList(
-                          delegate: SliverChildBuilderDelegate(
-                        (context, index) {
-                          return StaffLabourHistoryItem(index: index, item: state.datas[index]);
-                        },
-                        childCount: state.datas.length,
-                      ))
-                    ],
-                  ),
-                ).marginOnly(top: 5,bottom: 5).expanded(),
+                        //中间搜索布局
+                        SliverToBoxAdapter(
+                          child: _buildSearchWidget(),
+                        ),
+                  
+                        //底部工作历史列表
+                        state.datas ==null ||  state.datas.isEmpty? _warpStateLayout(_emptyView(context)):
+                        SliverList(
+                            delegate: SliverChildBuilderDelegate(
+                          (context, index) {
+                            return StaffLabourHistoryItem(index: index, item: state.datas[index]);
+                          },
+                          childCount:  state.datas.length,
+                        ))
+                      ],
+                    ),
+                  ).marginOnly(top: 5,bottom: 5).expanded(),
+                ),
               ],
             ),
           ),
@@ -136,4 +148,42 @@ class _AppliedStaffDetailState extends BaseState<UKAppliedStaffDetailPage, Appli
       ],
     );
   }
+
+  Widget _warpStateLayout(Widget widget) {
+    // return SliverFillViewport(
+    //   delegate: SliverChildBuilderDelegate(
+    //         (context, index) {
+    //       return widget;
+    //     },
+    //     childCount: 1,
+    //   ),
+    // );
+    return SliverToBoxAdapter(
+      child: widget,
+    );
+  }
+
+  ///数据为空的视图
+  Widget _emptyView(BuildContext context,) {
+    return Container(
+      width: double.infinity,
+      height: 200,
+      alignment: Alignment.center,
+      padding: const EdgeInsets.only(bottom: 10),
+      child: Column(
+        mainAxisSize: MainAxisSize.min,
+        crossAxisAlignment: CrossAxisAlignment.center,
+        mainAxisAlignment: MainAxisAlignment.center,
+        children: <Widget>[
+          const MyAssetImage(Assets.baseServicePageNoData, width: 123.5, height: 115.5, fit: BoxFit.contain),
+          MyTextView(
+            'There is currently no content available'.tr,
+            marginTop: 18,
+            fontSize: 14,
+            textColor: ColorConstants.primaryAppColor?? Color(0XFFD6E9F1),
+          ),
+        ],
+      ),
+    );
+  }
 }

+ 5 - 4
packages/cpt_uk/lib/modules/job/job_applied_staff_detail/applied_staff_detail_state.dart

@@ -1,5 +1,6 @@
-import 'package:domain/entity/response/staff_detail_entity.dart';
-import 'package:domain/entity/response/staff_labour_history_entity.dart';
+
+import 'package:domain/entity/response/uk_staff_detail_entity.dart';
+import 'package:domain/entity/response/uk_staff_labour_history_entity.dart';
 import 'package:flutter/cupertino.dart';
 
 class AppliedStaffDetailState {
@@ -9,7 +10,7 @@ class AppliedStaffDetailState {
   String? memberId;
   String keyword = "";
 
-  StaffDetailEntity? detail;
-  List<StaffLabourHistoryRows> datas = [];
+  UkStaffDetailEntity? detail;
+  List<UkStaffLabourHistoryRows> datas = [];
 
 }

+ 180 - 0
packages/cpt_uk/lib/modules/job/job_applied_staff_detail/certification_dialog_widget.dart

@@ -0,0 +1,180 @@
+import 'dart:typed_data';
+import 'dart:ui';
+
+import 'package:cs_resources/generated/assets.dart';
+import 'package:domain/entity/response/uk_staff_detail_entity.dart';
+import 'package:flutter/cupertino.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter/services.dart';
+import 'package:flutter/widgets.dart';
+import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
+import 'package:get/get.dart';
+import 'package:plugin_platform/engine/image/image_preview.dart';
+import 'package:plugin_platform/engine/toast/toast_engine.dart';
+import 'package:shared/utils/date_time_utils.dart';
+import 'package:shared/utils/log_utils.dart';
+import 'package:widgets/ext/ex_widget.dart';
+import 'package:cs_resources/constants/color_constants.dart';
+import 'package:widgets/my_load_image.dart';
+import 'package:widgets/my_text_view.dart';
+import 'package:widgets/picker/date_picker_util.dart';
+import 'package:widgets/shatter/form_require_text.dart';
+import 'package:widgets/shatter/round_my_text_field.dart';
+import 'package:widgets/widget_export.dart';
+
+/*
+ * 证书查看弹窗
+ */
+class certificationDialog extends StatefulWidget {
+  UkStaffDetailCertificates certificateItem;
+  bool? isConfirmAutoClose = true;
+  final Function(String url, List<String> urls, int? index)? onPreviewImageAction;
+
+  certificationDialog({required this.certificateItem,required this.onPreviewImageAction, this.isConfirmAutoClose});
+
+  @override
+  State<certificationDialog> createState() => _certificationDialogState();
+}
+
+class _certificationDialogState extends State<certificationDialog> {
+
+
+  @override
+  void initState() {
+    super.initState();
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return Column(
+      crossAxisAlignment: CrossAxisAlignment.center,
+      mainAxisAlignment: MainAxisAlignment.center,
+      children: [
+        Stack(
+          children: [
+            //Title (如果使用 Container 为最外层容器则默认为 match_parent 的效果,除非我们限制宽度和最大高度最小高度)
+            Container(
+              padding: const EdgeInsets.symmetric(horizontal: 16.5),
+              width: double.infinity,
+              decoration: const BoxDecoration(
+                color: Colors.white,
+                borderRadius: BorderRadius.all(Radius.circular(15)),
+              ),
+              child: Column(
+                crossAxisAlignment: CrossAxisAlignment.start,
+                children: [
+                  Center(
+                    child: MyTextView(
+                      "Show Certificate".tr,
+                      fontSize: 19,
+                      isFontMedium: true,
+                      textColor: ColorConstants.black,
+                      marginTop: 20,
+                    ),
+                  ),
+                  Column(
+                    children: [
+                      SizedBox.fromSize(size: Size(0, 20)),
+                      Row(
+                        children: [
+                          MyTextView(
+                            "Type".tr,
+                            fontSize: 15,
+                            isFontMedium: true,
+                            textColor: const Color(0xFF666666),
+                          ),
+                          Expanded(
+                            child: MyTextView(
+                              widget.certificateItem.type.toString()??'-',
+                              fontSize: 15,
+                              isFontMedium: true,
+                              textColor: const Color(0xFF666666),
+                              marginLeft: 20,
+                            ),
+                          ),
+                        ],
+                      ),
+                      SizedBox.fromSize(size: Size(0, 10)),
+                      Row(
+                        children: [
+                          MyTextView(
+                            "Images".tr,
+                            fontSize: 15,
+                            isFontMedium: true,
+                            textColor: const Color(0xFF666666),
+                            marginRight: 20,
+                          ),
+
+                          Wrap(
+                            spacing: 2,
+                            runSpacing: 2,
+                            children: [
+                              if ((widget.certificateItem.url ?? []).isNotEmpty)
+                                ...widget.certificateItem.url!.asMap().entries.map((entry) {
+                                  int index = entry.key;
+                                  String itemUrl = entry.value;
+                                  return MyLoadImage(
+                                    itemUrl,
+                                    width: 80,
+                                    height: 80,
+                                  ).onTap(() {
+                                    widget.onPreviewImageAction?.call(itemUrl, widget.certificateItem.url!, index);});
+                                }).toList()
+                              else ...[
+                                  MyTextView(
+                                    '\\',
+                                    fontSize: 15,
+                                    isFontMedium: true,
+                                    textColor: const Color(0xFF666666),
+                                  )
+                                ]
+                            ],
+                          )
+                        ],
+                      ),
+                      SizedBox.fromSize(size: Size(0, 10)),
+                      Row(
+                        children: [
+                          MyTextView(
+                            "Status".tr,
+                            fontSize: 15,
+                            isFontMedium: true,
+                            textColor: const Color(0xFF666666),
+                          ),
+                          Expanded(
+                            child: MyTextView(
+                              widget.certificateItem.status.toString()??'-',
+                              fontSize: 15,
+                              isFontMedium: true,
+                              textColor: const Color(0xFF666666),
+                              marginLeft: 20,
+                            ),
+                          ),
+                        ],
+                      ),
+                      SizedBox.fromSize(size: Size(0, 30)),
+                    ],
+                  ),
+                ],
+              ),
+            ),
+
+            // 关闭按钮
+            Positioned(
+              right: 15,
+              top: 15,
+              child: const MyAssetImage(Assets.baseLibDialogCloseRed, width: 20.5, height: 20.5).onTap((){
+                SmartDialog.dismiss();
+              }),
+            ),
+          ]
+        )
+      ],
+    ).constrained(width: 285);
+  }
+
+  //取消弹框
+  void onCancel() async {
+    SmartDialog.dismiss();
+  }
+}

+ 214 - 160
packages/cpt_uk/lib/modules/job/job_applied_staff_detail/staff_detail_widget.dart

@@ -1,10 +1,12 @@
+
 import 'package:cs_resources/constants/color_constants.dart';
-import 'package:domain/entity/response/staff_detail_entity.dart';
+import 'package:domain/entity/response/uk_staff_detail_entity.dart';
 import 'package:flutter/cupertino.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter/widgets.dart';
 import 'package:plugin_basic/basic_export.dart';
 import 'package:plugin_platform/engine/image/image_preview.dart';
+import 'package:shared/utils/log_utils.dart';
 import 'package:shared/utils/util.dart';
 import 'package:widgets/ext/ex_widget.dart';
 import 'package:widgets/my_load_image.dart';
@@ -14,12 +16,14 @@ import 'package:widgets/my_text_view.dart';
  * 员工的信息
  */
 class StaffDetailWidget extends StatelessWidget {
-  final StaffDetailEntity? detail;
+  final UkStaffDetailEntity? detail;
   final void Function() onRemarkAction;
+  final void Function(BuildContext context, UkStaffDetailCertificates  certItem ) onScanCertificateAction;
 
   StaffDetailWidget({
     required this.detail,
     required this.onRemarkAction,
+    required this.onScanCertificateAction,
   });
 
   @override
@@ -43,7 +47,7 @@ class StaffDetailWidget extends StatelessWidget {
               height: 100,
             ),
           )).onTap(() {
-            if (Utils.isNotEmpty(detail?.avatar)) {
+            if (detail!=null && detail!.avatar != null && Utils.isNotEmpty(detail!.avatar)) {
               ImagePreviewEngine.singleImagePreview(context, detail!.avatar!, heroTag: '112cc8a34e13');
             }
           }).marginOnly(top: 25, bottom: 15),
@@ -68,46 +72,6 @@ class StaffDetailWidget extends StatelessWidget {
             ],
           ).marginOnly(left: 22, right: 22),
 
-          //性别
-          Row(
-            mainAxisSize: MainAxisSize.max,
-            children: [
-              MyTextView(
-                "${"Gender".tr}:",
-                textColor: ColorConstants.textGrayAECAE5,
-                fontSize: 14,
-                isFontRegular: true,
-              ),
-              MyTextView(
-                detail?.sex ?? "-",
-                marginLeft: 5,
-                textColor: ColorConstants.white,
-                fontSize: 14,
-                isFontMedium: true,
-              ).expanded(),
-            ],
-          ).marginOnly(left: 22, right: 22, top: 10),
-
-          //生日
-          Row(
-            mainAxisSize: MainAxisSize.max,
-            children: [
-              MyTextView(
-                "DOB:",
-                textColor: ColorConstants.textGrayAECAE5,
-                fontSize: 14,
-                isFontRegular: true,
-              ),
-              MyTextView(
-                detail?.dob ?? "-",
-                marginLeft: 5,
-                textColor: ColorConstants.white,
-                fontSize: 14,
-                isFontMedium: true,
-              ).expanded(),
-            ],
-          ).marginOnly(left: 22, right: 22, top: 10),
-
           //身份证
           Row(
             mainAxisSize: MainAxisSize.max,
@@ -128,58 +92,18 @@ class StaffDetailWidget extends StatelessWidget {
             ],
           ).marginOnly(left: 22, right: 22, top: 10),
 
-          //电话号码
-          Row(
-            mainAxisSize: MainAxisSize.max,
-            children: [
-              MyTextView(
-                "${"Mobile".tr}:",
-                textColor: ColorConstants.textGrayAECAE5,
-                fontSize: 14,
-                isFontRegular: true,
-              ),
-              MyTextView(
-                detail?.mobile ?? "-",
-                marginLeft: 5,
-                textColor: ColorConstants.white,
-                fontSize: 14,
-                isFontMedium: true,
-              ).expanded(),
-            ],
-          ).marginOnly(left: 22, right: 22, top: 10),
-
-          //邮箱
-          Row(
-            mainAxisSize: MainAxisSize.max,
-            children: [
-              MyTextView(
-                "${"Email".tr}:",
-                textColor: ColorConstants.textGrayAECAE5,
-                fontSize: 14,
-                isFontRegular: true,
-              ),
-              MyTextView(
-                detail?.email ?? "-",
-                marginLeft: 5,
-                textColor: ColorConstants.white,
-                fontSize: 14,
-                isFontMedium: true,
-              ).expanded(),
-            ],
-          ).marginOnly(left: 22, right: 22, top: 10),
-
-          //国籍
+          //生日
           Row(
             mainAxisSize: MainAxisSize.max,
             children: [
               MyTextView(
-                "Nationality:",
+                "DOB:",
                 textColor: ColorConstants.textGrayAECAE5,
                 fontSize: 14,
                 isFontRegular: true,
               ),
               MyTextView(
-                detail?.natl ?? "-",
+                detail?.dob ?? "-",
                 marginLeft: 5,
                 textColor: ColorConstants.white,
                 fontSize: 14,
@@ -188,85 +112,179 @@ class StaffDetailWidget extends StatelessWidget {
             ],
           ).marginOnly(left: 22, right: 22, top: 10),
 
-          //语言
-          Row(
-            mainAxisSize: MainAxisSize.max,
-            children: [
-              MyTextView(
-                "Language:",
-                textColor: ColorConstants.textGrayAECAE5,
-                fontSize: 14,
-                isFontRegular: true,
-              ),
-              MyTextView(
-                detail?.lang ?? "-",
-                marginLeft: 5,
-                textColor: ColorConstants.white,
-                fontSize: 14,
-                isFontMedium: true,
-              ).expanded(),
-            ],
-          ).marginOnly(left: 22, right: 22, top: 10),
+          // //性别
+          // Row(
+          //   mainAxisSize: MainAxisSize.max,
+          //   children: [
+          //     MyTextView(
+          //       "${"Gender".tr}:",
+          //       textColor: ColorConstants.textGrayAECAE5,
+          //       fontSize: 14,
+          //       isFontRegular: true,
+          //     ),
+          //     MyTextView(
+          //       detail?.sex ?? "-",
+          //       marginLeft: 5,
+          //       textColor: ColorConstants.white,
+          //       fontSize: 14,
+          //       isFontMedium: true,
+          //     ).expanded(),
+          //   ],
+          // ).marginOnly(left: 22, right: 22, top: 10),
+          //
+          // //电话号码
+          // Row(
+          //   mainAxisSize: MainAxisSize.max,
+          //   children: [
+          //     MyTextView(
+          //       "${"Mobile".tr}:",
+          //       textColor: ColorConstants.textGrayAECAE5,
+          //       fontSize: 14,
+          //       isFontRegular: true,
+          //     ),
+          //     MyTextView(
+          //       detail?.mobile ?? "-",
+          //       marginLeft: 5,
+          //       textColor: ColorConstants.white,
+          //       fontSize: 14,
+          //       isFontMedium: true,
+          //     ).expanded(),
+          //   ],
+          // ).marginOnly(left: 22, right: 22, top: 10),
+          //
+          // //邮箱
+          // Row(
+          //   mainAxisSize: MainAxisSize.max,
+          //   children: [
+          //     MyTextView(
+          //       "${"Email".tr}:",
+          //       textColor: ColorConstants.textGrayAECAE5,
+          //       fontSize: 14,
+          //       isFontRegular: true,
+          //     ),
+          //     MyTextView(
+          //       detail?.email ?? "-",
+          //       marginLeft: 5,
+          //       textColor: ColorConstants.white,
+          //       fontSize: 14,
+          //       isFontMedium: true,
+          //     ).expanded(),
+          //   ],
+          // ).marginOnly(left: 22, right: 22, top: 10),
+          //
+          // //国籍
+          // Row(
+          //   mainAxisSize: MainAxisSize.max,
+          //   children: [
+          //     MyTextView(
+          //       "Nationality:",
+          //       textColor: ColorConstants.textGrayAECAE5,
+          //       fontSize: 14,
+          //       isFontRegular: true,
+          //     ),
+          //     MyTextView(
+          //       detail?.natl ?? "-",
+          //       marginLeft: 5,
+          //       textColor: ColorConstants.white,
+          //       fontSize: 14,
+          //       isFontMedium: true,
+          //     ).expanded(),
+          //   ],
+          // ).marginOnly(left: 22, right: 22, top: 10),
+          //
+          // //语言
+          // Row(
+          //   mainAxisSize: MainAxisSize.max,
+          //   children: [
+          //     MyTextView(
+          //       "Language:",
+          //       textColor: ColorConstants.textGrayAECAE5,
+          //       fontSize: 14,
+          //       isFontRegular: true,
+          //     ),
+          //     MyTextView(
+          //       detail?.lang ?? "-",
+          //       marginLeft: 5,
+          //       textColor: ColorConstants.white,
+          //       fontSize: 14,
+          //       isFontMedium: true,
+          //     ).expanded(),
+          //   ],
+          // ).marginOnly(left: 22, right: 22, top: 10),
+          //
+          // //地址
+          // Row(
+          //   mainAxisSize: MainAxisSize.max,
+          //   children: [
+          //     MyTextView(
+          //       "Address:",
+          //       textColor: ColorConstants.textGrayAECAE5,
+          //       fontSize: 14,
+          //       isFontRegular: true,
+          //     ),
+          //     MyTextView(
+          //       detail?.address ?? "-",
+          //       marginLeft: 5,
+          //       textColor: ColorConstants.white,
+          //       fontSize: 14,
+          //       isFontMedium: true,
+          //     ).expanded(),
+          //   ],
+          // ).marginOnly(left: 22, right: 22, top: 10),
+          //
+          // //紧急联系人
+          // Row(
+          //   mainAxisSize: MainAxisSize.max,
+          //   children: [
+          //     MyTextView(
+          //       "Emergency Name:",
+          //       textColor: ColorConstants.textGrayAECAE5,
+          //       fontSize: 14,
+          //       isFontRegular: true,
+          //     ),
+          //     MyTextView(
+          //       detail?.emerName ?? "-",
+          //       marginLeft: 5,
+          //       textColor: ColorConstants.white,
+          //       fontSize: 14,
+          //       isFontMedium: true,
+          //     ).expanded(),
+          //   ],
+          // ).marginOnly(left: 22, right: 22, top: 10),
+          //
+          // //紧急联系人电话
+          // Row(
+          //   mainAxisSize: MainAxisSize.max,
+          //   children: [
+          //     MyTextView(
+          //       "Emergency Phone:",
+          //       textColor: ColorConstants.textGrayAECAE5,
+          //       fontSize: 14,
+          //       isFontRegular: true,
+          //     ),
+          //     MyTextView(
+          //       "----",
+          //       marginLeft: 5,
+          //       textColor: ColorConstants.white,
+          //       fontSize: 14,
+          //       isFontMedium: true,
+          //     ).expanded(),
+          //   ],
+          // ).marginOnly(left: 22, right: 22, top: 10),
 
-          //地址
-          Row(
-            mainAxisSize: MainAxisSize.max,
-            children: [
-              MyTextView(
-                "Address:",
-                textColor: ColorConstants.textGrayAECAE5,
-                fontSize: 14,
-                isFontRegular: true,
-              ),
-              MyTextView(
-                detail?.address ?? "-",
-                marginLeft: 5,
-                textColor: ColorConstants.white,
-                fontSize: 14,
-                isFontMedium: true,
-              ).expanded(),
-            ],
-          ).marginOnly(left: 22, right: 22, top: 10),
+          // 	Insurance Certificate
 
-          //紧急联系人
-          Row(
-            mainAxisSize: MainAxisSize.max,
-            children: [
-              MyTextView(
-                "Emergency Name:",
-                textColor: ColorConstants.textGrayAECAE5,
-                fontSize: 14,
-                isFontRegular: true,
-              ),
-              MyTextView(
-                detail?.emerName ?? "-",
-                marginLeft: 5,
-                textColor: ColorConstants.white,
-                fontSize: 14,
-                isFontMedium: true,
-              ).expanded(),
-            ],
-          ).marginOnly(left: 22, right: 22, top: 10),
 
-          //紧急联系人电话
-          Row(
-            mainAxisSize: MainAxisSize.max,
+          // 循环显示证书 detail.certificates
+          Column(
             children: [
-              MyTextView(
-                "Emergency Phone:",
-                textColor: ColorConstants.textGrayAECAE5,
-                fontSize: 14,
-                isFontRegular: true,
-              ),
-              MyTextView(
-                detail?.emerPhone ?? "-",
-                marginLeft: 5,
-                textColor: ColorConstants.white,
-                fontSize: 14,
-                isFontMedium: true,
-              ).expanded(),
+              ...(detail?.certificates?.asMap().entries.map((entry) {
+                int index = entry.key;
+                UkStaffDetailCertificates certificate = entry.value;
+                return _buildCertificateWidget(context, certificate, index);
+              }).toList() ?? []),
             ],
-          ).marginOnly(left: 22, right: 22, top: 10),
+          ),
 
           //评分
           Row(
@@ -293,4 +311,40 @@ class StaffDetailWidget extends StatelessWidget {
       ),
     );
   }
+
+  Widget _buildCertificateWidget(BuildContext context,UkStaffDetailCertificates certificateItem, int index ){
+    return Row(
+      children: [
+          MyTextView(
+            '${certificateItem.type!}:',
+            textColor: ColorConstants.textGrayAECAE5,
+            fontSize: 14,
+            isFontRegular: true,
+          ),
+          MyTextView(
+            certificateItem.status?? "",
+            textColor: _getStatusColor(certificateItem.statusColor?? ''),
+            fontSize: 14,
+            isFontRegular: true,
+            marginLeft: 5,
+          ).onTap((){
+            onScanCertificateAction?.call(context, certificateItem);
+          }),
+      ]
+    ).marginOnly(left: 22, right: 22,top: 10);
+  }
+
+  Color _getStatusColor(String statusColor) {
+    switch (statusColor) {
+      case 'springgreen':
+        return Color(0xFF0AC074);
+      case 'red':
+        return Color(0xFFFF6262);
+      case 'dodgerblue':
+        return Colors.blue;
+      default:
+        return Color(0xFFEA9F0D);
+    }
+  }
+
 }

+ 23 - 21
packages/cpt_uk/lib/modules/job/job_applied_staff_detail/staff_labour_history_item.dart

@@ -1,6 +1,7 @@
 import 'package:cs_resources/constants/color_constants.dart';
 import 'package:cs_resources/generated/assets.dart';
-import 'package:domain/entity/response/staff_labour_history_entity.dart';
+import 'package:cs_resources/local/theme/theme_config.dart';
+import 'package:domain/entity/response/uk_staff_labour_history_entity.dart';
 import 'package:flutter/cupertino.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter/widgets.dart';
@@ -16,7 +17,7 @@ import 'package:widgets/my_text_view.dart';
  */
 class StaffLabourHistoryItem extends StatelessWidget {
   final int index;
-  final StaffLabourHistoryRows item;
+  final UkStaffLabourHistoryRows item;
 
   StaffLabourHistoryItem({
     required this.index,
@@ -50,7 +51,7 @@ class StaffLabourHistoryItem extends StatelessWidget {
 
               //日期
               MyTextView(
-                item.jobDate ?? "-",
+                item?.jobDate ?? "-",
                 isFontRegular: true,
                 textColor: ColorConstants.white,
                 fontSize: 14,
@@ -75,7 +76,7 @@ class StaffLabourHistoryItem extends StatelessWidget {
 
               //姓名
               MyTextView(
-                item.staffName ?? "-",
+                item?.staffName ?? "-",
                 isFontRegular: true,
                 textColor: ColorConstants.white,
                 fontSize: 14,
@@ -100,7 +101,7 @@ class StaffLabourHistoryItem extends StatelessWidget {
 
               //标题
               MyTextView(
-                item.jobTitle ?? "-",
+                item?.jobTitle ?? "-",
                 isFontRegular: true,
                 textColor: ColorConstants.white,
                 fontSize: 14,
@@ -125,7 +126,7 @@ class StaffLabourHistoryItem extends StatelessWidget {
 
               //部门
               MyTextView(
-                item.outletName ?? "-",
+                item?.outletName ?? "-",
                 isFontRegular: true,
                 textColor: ColorConstants.white,
                 fontSize: 14,
@@ -150,7 +151,7 @@ class StaffLabourHistoryItem extends StatelessWidget {
 
               //时间
               MyTextView(
-                item.startTime ?? "-",
+                item?.startTime ?? "-",
                 marginLeft: 5,
                 isFontRegular: true,
                 textColor: Colors.white,
@@ -173,10 +174,10 @@ class StaffLabourHistoryItem extends StatelessWidget {
 
               //时间
               MyTextView(
-                item.securityIn?.time ?? "-",
+                item?.securityIn?.time ?? "-",
                 marginLeft: 5,
                 isFontRegular: true,
-                textColor: item.securityIn?.changed == 1 ? ColorConstants.textRedFF6262 : Colors.white,
+                textColor: item?.securityIn?.changed == 1 ? ColorConstants.textRedFF6262 : Colors.white,
                 fontSize: 14,
               ).expanded(),
             ],
@@ -196,10 +197,10 @@ class StaffLabourHistoryItem extends StatelessWidget {
 
               //时间
               MyTextView(
-                item.workIn?.time ?? "-",
+                item?.workIn?.time ?? "-",
                 marginLeft: 5,
                 isFontRegular: true,
-                textColor: item.workIn?.changed == 1 ? ColorConstants.textRedFF6262 : Colors.white,
+                textColor: item?.workIn?.changed == 1 ? ColorConstants.textRedFF6262 : Colors.white,
                 fontSize: 14,
               ).expanded(),
             ],
@@ -219,7 +220,7 @@ class StaffLabourHistoryItem extends StatelessWidget {
 
               //时间
               MyTextView(
-                item.endTime ?? "-",
+                item?.endTime ?? "-",
                 marginLeft: 5,
                 isFontRegular: true,
                 textColor: Colors.white,
@@ -242,10 +243,10 @@ class StaffLabourHistoryItem extends StatelessWidget {
 
               //时间
               MyTextView(
-                item.workOut?.time ?? "-",
+                item?.workOut?.time ?? "-",
                 marginLeft: 5,
                 isFontRegular: true,
-                textColor: item.workOut?.changed == 1 ? ColorConstants.textRedFF6262 : Colors.white,
+                textColor: item?.workOut?.changed == 1 ? ColorConstants.textRedFF6262 : Colors.white,
                 fontSize: 14,
               ).expanded(),
             ],
@@ -265,10 +266,10 @@ class StaffLabourHistoryItem extends StatelessWidget {
 
               //时间
               MyTextView(
-                item.securityOut?.time ?? "-",
+                item?.securityOut?.time ?? "-",
                 marginLeft: 5,
                 isFontRegular: true,
-                textColor: item.securityOut?.changed == 1 ? ColorConstants.textRedFF6262 : Colors.white,
+                textColor: item?.securityOut?.changed == 1 ? ColorConstants.textRedFF6262 : Colors.white,
                 fontSize: 14,
               ).expanded(),
             ],
@@ -288,7 +289,7 @@ class StaffLabourHistoryItem extends StatelessWidget {
 
               //发布状态
               MyTextView(
-                item.appliedAt ?? "-",
+                item?.appliedAt ?? "-",
                 marginLeft: 5,
                 isFontRegular: true,
                 textColor: Colors.white,
@@ -311,14 +312,14 @@ class StaffLabourHistoryItem extends StatelessWidget {
 
               //发布状态
               MyTextView(
-                item.statusShow ?? "-",
+                item?.statusShow ?? "-",
                 marginLeft: 5,
                 isFontRegular: true,
-                textColor: "Completed" == item.statusShow
+                textColor: "Completed" == item?.statusShow
                     ? ColorConstants.textGreen05DC82
-                    : "Cancelled" == item.statusShow || "Rejected" == item.statusShow
+                    : "Cancelled" == item?.statusShow || "Rejected" == item?.statusShow
                         ? ColorConstants.textRedFF6262
-                        : "Revised" == item.statusShow || "Pending" == item.statusShow || "Approve" == item.statusShow
+                        : "Revised" == item?.statusShow || "Pending" == item?.statusShow || "Approve" == item?.statusShow
                             ? ColorConstants.textYellowFFBB1B
                             : ColorConstants.textBlue06D9FF,  //默认蓝色
                 fontSize: 14,
@@ -330,4 +331,5 @@ class StaffLabourHistoryItem extends StatelessWidget {
       ),
     );
   }
+
 }

+ 1 - 1
packages/cpt_uk/lib/modules/job/job_applied_staff_reviews/applied_staff_reviews_page.dart

@@ -81,7 +81,7 @@ class _AppliedStaffReviewsState extends BaseState<UKAppliedStaffReviewsPage, App
             crossAxisAlignment: CrossAxisAlignment.start,
             mainAxisSize: MainAxisSize.max,
             children: [
-              MyAppBar.titleBar(context, "Staff Detail".tr),
+              MyAppBar.titleBar(context, "Remark Detail".tr),
               EasyRefresh(
                 controller: controller.refreshController,
                 onRefresh: controller.onRefresh,

+ 5 - 5
packages/cpt_uk/lib/modules/job/job_category/job_category_controller.dart

@@ -29,19 +29,19 @@ class JobCategoryController extends GetxController with DioCancelableMixin {
   /// 跳转到指定的模块中去
   void gotoModulePage(HomeModule module) {
     switch (module.key) {
-      case 'job_template':
+      case 'template':
         UKTemplateListPage.startInstance();
         break;
-      case 'labour_request':
+      case 'labReq':
         UKLabourRequestListPage.startInstance();
         break;
-      case 'lab_review':
+      case 'reqReview':
         UKLabourReviewPage.startInstance();
         break;
-      case 'job_list':
+      case 'jobList':
         UKJobListPage.startInstance();
         break;
-      case 'attendance_review':
+      case 'attReview':
         UKAttendanceReviewPage.startInstance();
         break;
     }

+ 6 - 5
packages/cpt_uk/lib/modules/job/job_category/job_category_state.dart

@@ -5,10 +5,11 @@ import 'package:plugin_basic/basic_export.dart';
 class JobCategoryState {
   //全部的模块
   final List<HomeModule> datas = [
-    HomeModule(key: 'job_template', moduleName: 'Job Template'.tr, moduleIconPath: Assets.cptJobCategoryTemplate, iconWidth: 40, iconHeight: 40),
-    HomeModule(key: 'labour_request', moduleName: 'Labour Request'.tr, moduleIconPath: Assets.cptJobCategoryLabour, iconWidth: 40, iconHeight: 40),
-    HomeModule(key: 'lab_review', moduleName: 'Labour Request Review'.tr, moduleIconPath: Assets.cptJobCategoryLabourReview, iconWidth: 40, iconHeight: 40),
-    HomeModule(key: 'job_list', moduleName: 'Job List'.tr, moduleIconPath: Assets.cptJobCategoryList, iconWidth: 40, iconHeight: 40),
-    HomeModule(key: 'attendance_review', moduleName: 'Attendance Review'.tr, moduleIconPath: Assets.cptJobCategoryAttendanceReview, iconWidth: 40, iconHeight: 40),
+    HomeModule(key: 'template', moduleName: 'Job Template'.tr, moduleIconPath: Assets.cptJobCategoryTemplate, iconWidth: 40, iconHeight: 40),
+    HomeModule(key: 'labReq', moduleName: 'Labour Request'.tr, moduleIconPath: Assets.cptJobCategoryLabour, iconWidth: 40, iconHeight: 40),
+    HomeModule(key: 'reqReview', moduleName: 'Labour Request Review'.tr, moduleIconPath: Assets.cptJobCategoryLabourReview, iconWidth: 40, iconHeight: 40),
+    HomeModule(key: 'jobList', moduleName: 'Job List'.tr, moduleIconPath: Assets.cptJobCategoryList, iconWidth: 40, iconHeight: 40),
+    HomeModule(key: 'attReview', moduleName: 'Attendance Review'.tr, moduleIconPath: Assets.cptJobCategoryAttendanceReview, iconWidth: 40, iconHeight: 40),
   ];
 }
+

+ 36 - 0
packages/cpt_uk/lib/modules/job/job_list/job_list_controller.dart

@@ -2,10 +2,13 @@ import 'package:domain/entity/response/job_list_entity.dart';
 import 'package:domain/entity/response/job_list_index_entity.dart';
 import 'package:domain/repository/job_repository.dart';
 import 'package:get/get.dart';
+import 'package:plugin_basic/constants/app_constant.dart';
 import 'package:plugin_platform/engine/dialog/dialog_engine.dart';
 import 'package:plugin_platform/http/dio/dio_cancelable_mixin.dart';
 import 'package:plugin_platform/http/http_result.dart';
 import 'package:shared/utils/date_time_utils.dart';
+import 'package:shared/utils/event_bus.dart';
+import 'package:shared/utils/log_utils.dart';
 import 'package:widgets/load_state_layout.dart';
 import 'package:widgets/widget_export.dart';
 
@@ -25,6 +28,37 @@ class JobListController extends GetxController with DioCancelableMixin {
   LoadState loadingState = LoadState.State_Success;
   String? errorMessage;
 
+
+  Subscription? subscribe;
+
+  void registerEventBus() {
+    subscribe = bus.on(AppConstant.eventJobListChangeStaffNo, (arg) {
+      String? argJobId = arg?['jobId']??'';
+      int argStaffCount = arg?['addStaffCount']??0;
+      Log.d("接收消息argJobId  ${argJobId}");
+      Log.d("接收消息argStaffCount  ${argStaffCount}");
+      List<JobListRows>? result = state.datas.where((item) => item.jobId.toString() == argJobId)?.toList();
+
+      if(result != null && result.isNotEmpty){
+        String staffShow = result.first?.staffShow?? '';
+        if(staffShow.isNotEmpty){
+          List<String> staffShowList = staffShow.replaceAll(' ', '').split('/');
+          if(staffShowList.length == 2){
+            int staffCount = int.parse(staffShowList[0]);
+            int staffTotal = int.parse(staffShowList[1]);
+            result.first?.staffShow = "${staffCount + argStaffCount} / $staffTotal";
+            update();
+          }
+        }
+      }
+    });
+  }
+
+  void unregisterEventBus() {
+    bus.off(AppConstant.eventJobListChangeStaffNo, subscribe);
+  }
+
+
   //刷新页面状态
   void changeLoadingState(LoadState state) {
     loadingState = state;
@@ -184,10 +218,12 @@ class JobListController extends GetxController with DioCancelableMixin {
   void onReady() {
     super.onReady();
     fetchNotifyList();
+    registerEventBus();
   }
 
   @override
   void onClose() {
+    unregisterEventBus();
     state.datas.clear();
     super.onClose();
   }

+ 2 - 1
packages/cpt_uk/lib/modules/job/job_list/job_list_item.dart

@@ -51,6 +51,7 @@ class JobListItem extends StatelessWidget {
             decorationStyle: TextDecorationStyle.solid, // 可选,设置下划线的样式
           ),
 
+
           // 部门
           Row(
             mainAxisSize: MainAxisSize.max,
@@ -80,7 +81,7 @@ class JobListItem extends StatelessWidget {
             crossAxisAlignment: CrossAxisAlignment.center,
             children: [
               MyTextView(
-                "Datetime:".tr,
+                "DateTime:".tr,
                 isFontRegular: true,
                 textColor: ColorConstants.textGrayAECAE5,
                 fontSize: 14,

+ 393 - 39
packages/cpt_uk/lib/modules/job/labour_request_add/labour_request_add_controller.dart

@@ -1,31 +1,54 @@
-import 'package:domain/entity/response/labour_request_edit_index_entity.dart';
+import 'dart:io';
+
+import 'package:cpt_uk/modules/job/labour_request_add/widget/labour_request_interface.dart';
+import 'package:domain/entity/response/uk_labour_request_detail_entity.dart';
 import 'package:domain/repository/labour_repository.dart';
+import 'package:domain/repository/uk_job_repository.dart';
+import 'package:domain/repository/uk_labour_repository.dart';
 import 'package:flutter/cupertino.dart';
 import 'package:get/get.dart';
 import 'package:plugin_basic/constants/app_constant.dart';
+import 'package:plugin_platform/engine/dialog/dialog_engine.dart';
 import 'package:plugin_platform/engine/notify/notify_engine.dart';
 import 'package:plugin_platform/engine/toast/toast_engine.dart';
 import 'package:plugin_platform/http/http_result.dart';
+import 'package:plugin_platform/http/dio/dio_cancelable_mixin.dart';
 import 'package:shared/utils/date_time_utils.dart';
 import 'package:shared/utils/event_bus.dart';
+import 'package:shared/utils/log_utils.dart';
 import 'package:shared/utils/util.dart';
 import 'package:widgets/picker/date_picker_util.dart';
 import 'package:widgets/picker/option_pick_util.dart';
+import 'package:file_picker/file_picker.dart';
 
+import '../../../widget/date_range_picker_dialog.dart';
+import '../labour_request_preselected_list/widget/preselected_add_staff.dart';
 import 'labour_request_add_state.dart';
 
-class LabourRequestAddController extends GetxController {
+class LabourRequestAddController extends GetxController with DioCancelableMixin implements CommonLabourRequestController {
   final LabourRepository _labourRepository = Get.find();
+  final UKJobRepository _ukJobRepository = Get.find();
+  final UkLabourRepository _ukLabourRepository = Get.find();
   final LabourRequestAddState state = LabourRequestAddState();
 
+  late PlatformFile? _selectedPlatFormFile;
+
+
+  @override
+  CommonLabourRequestState get commonState => state;
+
   /// 获取首页的数据
   void fetchRequestDetail() async {
     //获取到数据
-    Future<HttpResult<LabourRequestEditIndexEntity>> taskFuture;
-    if (state.pageType != 0 && Utils.isNotEmpty(state.appliedId) && state.appliedId != "0") {
-      taskFuture = _labourRepository.fetchLabourRequestEditDetail(state.appliedId);
+    Future<HttpResult<UkLabourRequestDetailEntity>> taskFuture;
+    // Log.d("请求的state.appliedId  ${state.appliedId}");
+    if (Utils.isNotEmpty(state.appliedId) && state.appliedId != "0") {
+      // 编辑
+      // Log.d("请求的state.appliedId3333  ${state.appliedId}");
+      taskFuture = _ukLabourRepository.fetchLabourRequestDetail(state.appliedId);
     } else {
-      taskFuture = _labourRepository.fetchLabourRequestAddOption();
+      // 新增时获取详情
+      taskFuture = _ukLabourRepository.fetchLabourRequestAddOption();
     }
 
     var result = await taskFuture;
@@ -33,17 +56,58 @@ class LabourRequestAddController extends GetxController {
     //处理数据
     if (result.isSuccess) {
       state.labReqOption = result.data;
+
+      Log.d("详情页面 获取到的数据  ${state.labReqOption.toString()}");
+
+      state.selectedTemplateId = state.labReqOption?.templateId.toString();
+
+      state.selectedDate = state.labReqOption?.jobStart == null ? null : DateTimeUtils.getDateTime(state.labReqOption!.jobStart!);
       state.selectedStartTime = state.labReqOption?.jobStart == null ? null : DateTimeUtils.getDateTime(state.labReqOption!.jobStart!);
       state.selectedEndTime = state.labReqOption?.jobEnd == null ? null : DateTimeUtils.getDateTime(state.labReqOption!.jobEnd!);
-      state.noStaff = state.labReqOption?.needNum.toString() == "0" ? "" : state.labReqOption?.needNum.toString();
+
+      Log.d("获取到的 atturl  ${state.labReqOption?.attUrl}");
+
+      state.attFilePath = state.labReqOption?.attUrl?? '';
+      state.selectedTypeId = state.labReqOption?.employmentType.toString() ?? '';
+
+      state.jobSelectJobStart = state.labReqOption?.jobStart?? '';
+      state.jobSelectJobEnd = state.labReqOption?.jobEnd?? '';
+
+      if(state.pageType == 0){
+        // 新增
+        state.noStaff = '';
+        state.amount =  '';
+      }else {
+        // 编辑/详情
+        state.noStaff = state.labReqOption?.needNum?.toString() == "0" ? "" : state.labReqOption?.needNum.toString();
+        state.amount = state.labReqOption?.amount?.toString() == "0" ? "" : state.labReqOption?.amount.toString();
+
+      }
+
       var needNumController = state.formData['no_of_staff']!['controller'];
-      needNumController.text = state.noStaff;
+      needNumController.text = state.noStaff??state.noStaff =='null'??"0";
       var amountController = state.formData['amount']!['controller'];
-      amountController.text = state.labReqOption?.amount ?? "";
-      state.selectedTemplateId = state.labReqOption?.templateId;
-      state.selectedDepartmentId = state.labReqOption?.departmentId;
+      amountController.text = state.amount??state.amount!='null'??"0";
+
+      var remarkController = state.formData['remark']!['controller'];
+      var eventController = state.formData['event']!['controller'];
+      var eventTypeController = state.formData['event_type']!['controller'];
+      var eventPaxController = state.formData['event_pax']!['controller'];
+      var revenueController = state.formData['revenue']!['controller'];
+      var positionController = state.formData['position']!['controller'];
+      var totalCostController = state.formData['total_cost']!['controller'];
+      remarkController.text = state.labReqOption?.description ?? '';
+      eventController.text = state.labReqOption?.eventName ?? "";
+      eventTypeController.text = state.labReqOption?.eventType ?? "";
+      eventPaxController.text = state.labReqOption?.passengers?.toString() ?? "0";
+      revenueController.text = state.labReqOption?.estRevenue ?? "";
+      positionController.text = state.labReqOption?.position ?? "";
+      totalCostController.text = state.labReqOption?.estCost ?? "";
+
+
+      state.selectedDepartmentId = state.labReqOption?.departmentId.toString();
       //时薪还是房间计费
-      state.chargeOptionId = state.labReqOption?.chargeList.firstWhere((element) => element.checked == "checked").value;
+      state.chargeOptionId = state.labReqOption?.chargeList!.firstWhere((element) => element.checked == "checked").value;
 
       update();
     } else {
@@ -59,11 +123,32 @@ class LabourRequestAddController extends GetxController {
 
   /// 提交
   void doSubmit() async {
+    Log.d("labour_review controller 提交");
+
     var needNumController = state.formData['no_of_staff']!['controller'];
     var amountController = state.formData['amount']!['controller'];
-    String needNum = needNumController.text.toString();
+    String needNum = needNumController.text.toString()??"0";
     String amount = amountController.text.toString();
+    // String? jobApplyPreId = state.preSelectedIds;
+
+    var remarkController = state.formData['remark']!['controller'];
+    var eventController = state.formData['event']!['controller'];
+    var eventTypeController = state.formData['event_type']!['controller'];
+    var eventPaxController = state.formData['event_pax']!['controller'];
+    var revenueController = state.formData['revenue']!['controller'];
+    var positionController = state.formData['position']!['controller'];
+    var totalCostController = state.formData['total_cost']!['controller'];
 
+    String event = eventController.text.toString();
+    String eventType = eventTypeController.text.toString();
+    String eventPax = eventPaxController.text.toString()?? "0";
+    String revenue = revenueController.text.toString();
+    String position = positionController.text.toString();
+    String totalCost = totalCostController.text.toString();
+    String remark = remarkController.text.toString();
+
+    // Log.d("89328392  ${state.selectedTypeId}");
+    // Log.d("89328392  ${state.selectedTypeId.runtimeType}");
     if (Utils.isEmpty(state.selectedTemplateId)) {
       ToastEngine.show("Choose Job Title".tr);
       return;
@@ -82,32 +167,121 @@ class LabourRequestAddController extends GetxController {
     } else if (state.labReqOption?.serviceType == 1 && Utils.isEmpty(amount)) {
       ToastEngine.show("Enter Amount".tr);
       return;
+    }else if(Utils.isEmpty(state.selectedTypeId)){
+      ToastEngine.show("Choose Employment Type".tr);
+      return;
     }
 
     Future<HttpResult> taskFuture;
     if (state.pageType != 0 && Utils.isNotEmpty(state.appliedId) && state.appliedId != "0") {
-      taskFuture = _labourRepository.editLabourRequestSubmit(
-        state.appliedId,
-        state.selectedTemplateId,
-        DateTimeUtils.formatDate(state.selectedStartTime),
-        DateTimeUtils.formatDate(state.selectedEndTime),
-        state.selectedDepartmentId,
-        needNum,
-        state.chargeOptionId,
-        state.labReqOption?.serviceType == 1 ? amount : null,
+      Map<String, dynamic> params = {
+        "requestId": state.appliedId,
+        "templateId": state.selectedTemplateId,
+        "jobStart": "${DateTimeUtils.formatDate(state.selectedDate, format: 'yyyy-MM-dd')} ${DateTimeUtils.formatDate(state.selectedStartTime, format: 'HH:mm')}:00",
+        "jobEnd": "${DateTimeUtils.formatDate(state.selectedDate, format: 'yyyy-MM-dd')} ${DateTimeUtils.formatDate(state.selectedEndTime, format: 'HH:mm')}:00",
+        "departmentId": state.selectedDepartmentId,
+        "needNum": needNum,
+        "salaryBy": 'hour',
+        "amount": state.labReqOption?.serviceType == 1 ? amount : null,
+        "certificate": state.selectedCertificateList?.join(",")?? "",
+        "challenge25": state.selectedChallenge25Id?? "",
+        "vehicle": state.selectedVehicleList?.join(",")??"",
+        "description": remark,
+        "employmentType": state.selectedTypeId,
+        "eventName": event,
+        "eventType": eventType,
+        "passengers": eventPax,
+        "estRevenue": revenue,
+        "position": position,
+        "estCost": totalCost,
+        "attUrl": state.attFilePath,
+        'cancelToken': cancelToken
+      };
+      // Log.d("编辑时 state.selectedCertificateList  ${state.selectedCertificateList}");
+      // Log.d("编辑时 state.selectedCertificateList  ${state.selectedCertificateList.join(",")}");
+      // Log.d("编辑时 state.selectedVehicleList  ${state.selectedVehicleList.join(",")}");
+      //
+      // Log.d("编辑时准备提交的 params  ${params}");
+      // 编辑
+      taskFuture = _ukLabourRepository.editLabourRequestSubmit(
+        requestId: params['requestId'],
+        templateId: params['templateId'],
+        jobStart: params['jobStart'],
+        jobEnd: params['jobEnd'],
+        departmentId: params['departmentId'],
+        needNum: params['needNum'],
+        salaryBy: params['salaryBy'],
+        amount: params['amount'],
+        certificate: params['certificate'],
+        challenge25: params['challenge25'],
+        vehicle: params['vehicle'],
+        description: params['description'],
+        employmentType: params['employmentType'],
+        eventName: params['eventName'],
+        eventType: params['eventType'],
+        passengers: params['passengers'],
+        estRevenue: params['estRevenue'],
+        position: params['position'],
+        estCost: params['estCost'],
+        attUrl: params['attUrl'],
+        cancelToken: params['cancelToken'],
       );
     } else {
-      taskFuture = _labourRepository.addLabourRequestSubmit(
-        state.selectedTemplateId,
-        DateTimeUtils.formatDate(state.selectedStartTime),
-        DateTimeUtils.formatDate(state.selectedEndTime),
-        state.selectedDepartmentId,
-        needNum,
-        state.chargeOptionId,
-        state.labReqOption?.serviceType == 1 ? amount : null,
+      Map<String, dynamic> params = {
+        "templateId": state.selectedTemplateId,
+        "jobDate": DateTimeUtils.formatDate(state.selectedDate, format: 'yyyy-MM-dd'),
+        "jobStart": "${DateTimeUtils.formatDate(state.selectedStartTime, format: 'HH:mm')}",
+        "jobEnd": "${DateTimeUtils.formatDate(state.selectedEndTime, format: 'HH:mm')}",
+        "departmentId": state.selectedDepartmentId,
+        "needNum": needNum,
+        "salaryBy": 'hour',
+        "repeatDateStr": state.repeatDateStr,
+        "amount": state.labReqOption?.serviceType == 1 ? amount : null,
+        "certificate": state.selectedCertificateList?.join(",")?? "",
+        "challenge25": state.selectedChallenge25Id?? "",
+        "vehicle": state.selectedVehicleList?.join(",")??"",
+        "jobApplyPreId": state.preSelectedIds,
+        "description": remark,
+        "employmentType": state.selectedTypeId,
+        "eventName": event,
+        "eventType": eventType,
+        "passengers": eventPax,
+        "estRevenue": revenue,
+        "position": position,
+        "estCost": totalCost,
+        "attUrl": state.attFilePath,
+        'cancelToken': cancelToken,
+      };
+      // Log.d("新增时准备提交的 params  ${params}");
+      // 新增
+      taskFuture = _ukLabourRepository.addLabourRequestSubmit(
+        templateId: params['templateId'],
+        jobDate: params['jobDate'],
+        jobStart: params['jobStart'],
+        jobEnd: params['jobEnd'],
+        departmentId: params['departmentId'],
+        needNum: params['needNum'],
+        salaryBy: params['salaryBy'],
+        repeatDateStr: params['repeatDateStr'],
+        amount: params['amount'],
+        certificate: params['certificate'],
+        challenge25: params['challenge25'],
+        vehicle: params['vehicle'],
+        jobApplyPreId: params['jobApplyPreId'],
+        description: params['description'],
+        employmentType: params['employmentType'],
+        eventName: params['eventName'],
+        eventType: params['eventType'],
+        passengers: params['passengers'],
+        estRevenue: params['estRevenue'],
+        position: params['position'],
+        estCost: params['estCost'],
+        attUrl: params['attUrl'],
+        cancelToken: params['cancelToken'],
       );
     }
 
+
     var result = await taskFuture;
 
     //处理数据
@@ -139,7 +313,7 @@ class LabourRequestAddController extends GetxController {
     if (state.selectedTemplateId == null) {
       selectedTemplateIndex = 0;
     } else {
-      selectedTemplateIndex = state.labReqOption!.templateList.indexWhere((department) => department.value.toString() == state.selectedTemplateId);
+      selectedTemplateIndex = state.labReqOption!.templateList!.indexWhere((department) => department.value.toString() == state.selectedTemplateId);
     }
 
     if (selectedTemplateIndex < 0) {
@@ -147,12 +321,85 @@ class LabourRequestAddController extends GetxController {
     }
 
     OptionPickerUtil.showCupertinoOptionPicker(
-      items: state.labReqOption!.templateList.map((e) => e.txt!).toList(growable: false),
+      items: state.labReqOption!.templateList!.map((e) => e.txt!).toList(growable: false),
       initialSelectIndex: selectedTemplateIndex,
-      onPickerChanged: (_, index) {
-        state.selectedTemplateId = state.labReqOption!.templateList[index].value!.toString();
+      onPickerChanged: (_, index) async{
+        state.selectedTemplateId = state.labReqOption!.templateList![index].value!.toString();
+        Log.d("选择标题后,此时选择的selectedTemplateId:${state.selectedTemplateId} ");
+        // 选择了标题后 需要 将此时选择的 标题 回显 给position
+        var positionController = state.formData['position']!['controller'];
+        state.position = state.templateList!
+            .firstWhere((element) => element.value.toString() == state.selectedTemplateId,
+            orElse: () => UkLabourRequestDetailTemplateList())
+            .txt ??
+            "";
+        positionController.text = state.position;
+
+        // 并且需要根据 state.selectedTemplateId调用 接口 回显 证书 、vehicle
+        await _getShowTemplateData(state.selectedTemplateId!);
+
+      },
+    );
+  }
+
+  Future<HttpResult?> _getShowTemplateData(String templateId) async{
+    final result = await _ukLabourRepository.fetchLabourRequestShowTemplateData(templateId);
+    if (result.isSuccess) {
+      state.showTemplateData = result.data;
+      if (state.showTemplateData != null) {
+        // 回显 证书、vehicle
+        if((state.showTemplateData?.certificate??'').isNotEmpty){
+          state.selectedCertificateList = state.showTemplateData?.certificate?.split(',')?? [];
+          // 循环 state.labReqOption?.certificateList 满足条件修改  checked
+          state.labReqOption?.certificateList?.forEach((e)=> {
+            if(state.selectedCertificateList.contains(e.value.toString())){
+              e.checked = 'checked'
+            }else {
+              e.checked = ''
+            }
+          });
+
+          Log.d("切换模板后, 需要回显的证书列表: ${state.selectedCertificateList}");
+          Log.d("切换模板后, 证书的回显 selectedCertificateList: ${state.labReqOption?.certificateList}");
+
+          state.selectedVehicleList = state.showTemplateData?.vehicle?.split(',')?? [];
+          // 循环 state.labReqOption?.vehicleList 满足条件修改  checked
+          state.labReqOption?.vehicleList?.forEach((e)=> {
+            if(state.selectedVehicleList.contains(e.value.toString())){
+              e.checked = 'checked'
+            }else {
+              e.checked = ''
+            }
+          });
+
+
+          Log.d("切换模板后, 需要回显的vehicle列表: ${state.selectedVehicleList}");
+          Log.d("切换模板后, 证书的回显 vehicleList: ${state.labReqOption?.vehicleList}");
+
+        }
+        // 更新
+        update();
+      }
+    }else {
+      ToastEngine.show(result.errorMsg ?? "Network Load Error".tr);
+    }
+  }
+
+
+  //选择日期
+  void pickJobDate() {
+    if (state.labReqOption == null || state.pageType == 2) {
+      return;
+    }
+
+    DatePickerUtil.showCupertinoDatePicker(
+      selectedDateTime: state.selectedDate,
+      mode: CupertinoDatePickerMode.date,
+      onDateTimeChanged: (date) {
+        state.selectedDate = date;
         update();
       },
+      title: "Job Date".tr,
     );
   }
 
@@ -164,7 +411,7 @@ class LabourRequestAddController extends GetxController {
 
     DatePickerUtil.showCupertinoDatePicker(
       selectedDateTime: state.selectedStartTime,
-      mode: CupertinoDatePickerMode.dateAndTime,
+      mode: CupertinoDatePickerMode.time,
       onDateTimeChanged: (date) {
         state.selectedStartTime = date;
         update();
@@ -181,7 +428,7 @@ class LabourRequestAddController extends GetxController {
 
     DatePickerUtil.showCupertinoDatePicker(
       selectedDateTime: state.selectedEndTime ?? state.selectedStartTime,
-      mode: CupertinoDatePickerMode.dateAndTime,
+      mode: CupertinoDatePickerMode.time,
       onDateTimeChanged: (date) {
         state.selectedEndTime = date;
         update();
@@ -190,6 +437,40 @@ class LabourRequestAddController extends GetxController {
     );
   }
 
+  // 筛选 employ ment type
+  void pickEmploymentType() {
+    if (state.labReqOption == null || state.pageType == 2) {
+      return;
+    }
+
+    int selectedEmploymentTypeIndex;
+    if (state.selectedTypeId == null) {
+      selectedEmploymentTypeIndex = 0;
+    } else {
+      if (state.labReqOption?.employmentList != null && state.labReqOption!.employmentList!.isNotEmpty) {
+        selectedEmploymentTypeIndex = state.labReqOption!.employmentList!.indexWhere(
+                (employment) => employment.value.toString() == state.selectedTypeId
+        );
+      } else {
+        // 处理 departmentList 为空或 null 的情况
+        selectedEmploymentTypeIndex = 0;
+      }
+    }
+
+    if (selectedEmploymentTypeIndex < 0) {
+      selectedEmploymentTypeIndex = 0;
+    }
+
+    OptionPickerUtil.showCupertinoOptionPicker(
+      items: state.labReqOption!.employmentList!.map((e) => e.txt!).toList(growable: false),
+      initialSelectIndex: selectedEmploymentTypeIndex,
+      onPickerChanged: (_, index) {
+        state.selectedTypeId = state.labReqOption!.employmentList![index].value!.toString();
+        update();
+      },
+    );
+  }
+
   // 筛选部门
   void pickDepartment() {
     if (state.labReqOption == null || state.pageType == 2) {
@@ -200,7 +481,14 @@ class LabourRequestAddController extends GetxController {
     if (state.selectedDepartmentId == null) {
       selectedDepartmentIndex = 0;
     } else {
-      selectedDepartmentIndex = state.labReqOption!.departmentList.indexWhere((department) => department.value.toString() == state.selectedDepartmentId);
+      if (state.labReqOption?.departmentList != null && state.labReqOption!.departmentList!.isNotEmpty) {
+        selectedDepartmentIndex = state.labReqOption!.departmentList!.indexWhere(
+                (department) => department.value.toString() == state.selectedDepartmentId
+        );
+      } else {
+        // 处理 departmentList 为空或 null 的情况
+        selectedDepartmentIndex = 0;
+      }
     }
 
     if (selectedDepartmentIndex < 0) {
@@ -208,12 +496,78 @@ class LabourRequestAddController extends GetxController {
     }
 
     OptionPickerUtil.showCupertinoOptionPicker(
-      items: state.labReqOption!.departmentList.map((e) => e.txt!).toList(growable: false),
+      items: state.labReqOption!.departmentList!.map((e) => e.txt!).toList(growable: false),
       initialSelectIndex: selectedDepartmentIndex,
       onPickerChanged: (_, index) {
-        state.selectedDepartmentId = state.labReqOption!.departmentList[index].value!.toString();
+        state.selectedDepartmentId = state.labReqOption!.departmentList![index].value!.toString();
+        update();
+      },
+    );
+  }
+
+  //选择时间段
+  void pickDateRange() {
+    DialogEngine.show(
+        widget: DateRangePickerDialog(
+      dateRange: state.repeatDateStr,
+      confirmAction: (dateStr) {
+        Log.d("选择的时间段:$dateStr");
+        state.repeatDateStr = dateStr;
         update();
       },
+    ));
+  }
+
+  // 选择预选人
+  void handlerSelectPreSelect(){
+    DialogEngine.show(
+      widget: PreselectedAddStaff(
+        jobId: '0',
+        selectedStaffIds: state.preSelectedIds,
+        confirmAction: (selectedIds, [selectedList]) {
+          state.preSelectedIds = selectedIds;
+          state.preSelectedList = selectedList;
+          state.preSelectedNames = selectedList?.map((item) => item.name).join(',');
+          update();
+        },
+      ),
+    );
+  }
+
+  // 选择单个文件
+  void pickAttFile() async {
+
+    FilePickerResult? result = await FilePicker.platform.pickFiles(
+      allowMultiple: false,
+      type: FileType.custom,
+      allowedExtensions: ['jpg', 'png', 'jpeg', 'pdf', 'docx'],
     );
+
+    if (result != null) {
+      PlatformFile selectedPlatformFile = result.files.first;
+      Log.d("选取的文件的path:${selectedPlatformFile.path} name:${selectedPlatformFile.name}");
+      _selectedPlatFormFile = selectedPlatformFile;
+      state.attFilePath = selectedPlatformFile.path;
+
+      update();
+
+      // final fileResult = await _thRepository.uploadFile(file.path);
+      // if (fileResult.isSuccess) {
+      //   state.attFilePath = fileResult.data?.path;
+      //   update();
+      // } else {
+      //   ToastEngine.show(fileResult.errorMsg ?? "Network Load Error".tr);
+      // }
+    }
+  }
+
+  @override
+  void pickJobEnd() {
+    // TODO: implement pickJobEnd
+  }
+
+  @override
+  void pickJobStart() {
+    // TODO: implement pickJobStart
   }
 }

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 767 - 269
packages/cpt_uk/lib/modules/job/labour_request_add/labour_request_add_page.dart


+ 105 - 3
packages/cpt_uk/lib/modules/job/labour_request_add/labour_request_add_state.dart

@@ -1,21 +1,64 @@
-import 'package:domain/entity/response/labour_request_edit_index_entity.dart';
+import 'dart:io';
+
+import 'package:cpt_uk/modules/job/labour_request_add/widget/labour_request_interface.dart';
+import 'package:domain/entity/response/uk_lab_req_show_template_entity.dart';
+import 'package:domain/entity/response/uk_labour_request_detail_entity.dart';
+import 'package:domain/entity/response/uk_labour_request_preselect_addstatff_list_entity.dart';
 import 'package:flutter/material.dart';
 import 'package:plugin_basic/basic_export.dart';
+import 'package:shared/utils/date_time_utils.dart';
+
+class LabourRequestAddState implements CommonLabourRequestState {
 
-class LabourRequestAddState {
+  @override
+  String useInSence = 'labour_request';  // labour_request 、 labour_request_review
 
   int pageType = 0;  //页面的状态 0 是新增  1是编辑  2是详情
   String? appliedId;  //编辑和详情需要用到ID
 
   //页面对应的详情数据
-  LabourRequestEditIndexEntity? labReqOption;
+  UkLabourRequestDetailEntity? labReqOption;
+
+  @override
+  DateTime? get jobEnd => labReqOption?.jobEnd != null? DateTimeUtils.getDateTime(labReqOption!.jobEnd!): null;
+
+  @override
+  DateTime? get jobStart => labReqOption?.jobStart !=null? DateTimeUtils.getDateTime(labReqOption!.jobStart!): null;
+  @override
+  String? jobSelectJobStart;
+  @override
+  String? jobSelectJobEnd;
 
   //页面对应的选择的条件
+  DateTime? selectedDate;
   DateTime? selectedStartTime;
   DateTime? selectedEndTime;
+  String? repeatDateStr;  //2025-06-28,2025-06-29,2025-06-30
   String? selectedTemplateId;
   String? selectedDepartmentId;
   String? noStaff;  //成员数量
+  String? amount;
+
+  String? preSelectedNames; // 预选人姓名
+  String? preSelectedIds; // 预选人ids
+  List<UkLabourRequestPreselectAddstatffListRows>? preSelectedList = []; // 预选人列表
+
+  UkLabReqShowTemplateEntity? showTemplateData; // 切换模板时 获取的回显的部分数据(证书、chanllenge25、vehicle)
+
+  List<String> selectedCertificateList = [];   //选中的 证书 certificate
+  List<String> selectedVehicleList = [];   //选中的 车辆 vehicle
+  String? selectedChallenge25Id;   // 选择的 challenge25 id
+
+  String? selectedTypeId;
+  String? selectedType;
+  String? event;
+  String? eventType;
+  String? eventPax;
+  String? estimatedRevenue;
+  String? position;
+  String? estimatedTotalCost;
+  String? remark; //备注
+  String? attFilePath; // 附件地址
 
   String? chargeOptionId;
 
@@ -35,6 +78,65 @@ class LabourRequestAddState {
       'hintText': 'Enter Amount'.tr,
       'obsecure': false,
     },
+    'remark': {
+      'value': '',
+      'controller': TextEditingController(),
+      'focusNode': FocusNode(),
+      'hintText': 'Enter...'.tr,
+      'obsecure': false,
+    },
+    'event': {
+      'value': '',
+      'controller': TextEditingController(),
+      'focusNode': FocusNode(),
+      'hintText': 'Enter...'.tr,
+      'obsecure': false,
+    },
+    'event_type': {
+      'value': '',
+      'controller': TextEditingController(),
+      'focusNode': FocusNode(),
+      'hintText': 'Enter...'.tr,
+      'obsecure': false,
+    },
+    'event_pax': {
+      'value': '',
+      'controller': TextEditingController(),
+      'focusNode': FocusNode(),
+      'hintText': 'Enter...'.tr,
+      'obsecure': false,
+    },
+    'revenue': {
+      'value': '',
+      'controller': TextEditingController(),
+      'focusNode': FocusNode(),
+      'hintText': 'Enter...'.tr,
+      'obsecure': false,
+    },
+    'position': {
+      'value': '',
+      'controller': TextEditingController(),
+      'focusNode': FocusNode(),
+      'hintText': 'Enter...'.tr,
+      'obsecure': false,
+    },
+    'total_cost': {
+      'value': '',
+      'controller': TextEditingController(),
+      'focusNode': FocusNode(),
+      'hintText': 'Enter...'.tr,
+      'obsecure': false,
+    },
   };
 
+  int get serviceType => labReqOption?.serviceType ?? 0;
+  List<UkLabourRequestDetailLocationList>? get locationList => labReqOption?.locationList;
+  List<UkLabourRequestDetailTemplateList>? get templateList => labReqOption?.templateList;
+  List<UkLabourRequestDetailDepartmentList>? get departmentList => labReqOption?.departmentList;
+  List<UkLabourRequestDetailChargeList>? get chargeList => labReqOption?.chargeList;
+  List<UkLabourRequestDetailEmploymentList>? get employmentList => labReqOption?.employmentList;
+  List<UkLabourRequestDetailCertificateList>? get certificateList => labReqOption?.certificateList;
+  List<UkLabourRequestDetailVehicleList>? get vehicleList => labReqOption?.vehicleList;
+  List<UkLabourRequestDetailChallenge25List>? get challenge25List => labReqOption?.challenge25List;
+
 }

+ 996 - 0
packages/cpt_uk/lib/modules/job/labour_request_add/widget/lab_request_and_request_review_form.dart

@@ -0,0 +1,996 @@
+import 'package:cs_resources/constants/color_constants.dart';
+import 'package:cs_resources/generated/assets.dart';
+import 'package:domain/entity/response/uk_labour_request_detail_entity.dart';
+import 'package:flutter/cupertino.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter/services.dart';
+import 'package:plugin_basic/basic_export.dart';
+import 'package:shared/utils/date_time_utils.dart';
+import 'package:shared/utils/log_utils.dart';
+import 'package:shared/utils/util.dart';
+import 'package:widgets/ext/ex_widget.dart';
+import 'package:widgets/my_button.dart';
+import 'package:widgets/my_load_image.dart';
+import 'package:widgets/my_text_view.dart';
+import 'package:widgets/shatter/custom_check_box.dart';
+import 'package:widgets/shatter/custom_radio_check.dart';
+import 'package:widgets/shatter/form_require_text.dart';
+import 'package:widgets/shatter/round_my_text_field.dart';
+import 'package:widgets/widget_export.dart';
+
+import 'labour_request_interface.dart';
+
+class CommonLabourRequestFormFields extends StatelessWidget {
+  final CommonLabourRequestController controller;
+
+  const CommonLabourRequestFormFields({Key? key, required this.controller}) : super(key: key);
+
+  @override
+  Widget build(BuildContext context) {
+    final state = controller.commonState;
+    Log.d("--当前的useInSence---  ${state.useInSence}");
+    Log.d("--当前的pageType(0新增 1编辑 2详情)---  ${state.pageType}");
+
+    bool? isLabourRequestModule = state.useInSence == 'labour_request' ? true : false;
+    bool? isLabourRequestReviewModule = state.useInSence == 'labour_request_review' ? true : false;
+    bool? isAddAction = state.pageType == 0 ? true : false;
+    bool? isEditAction = state.pageType == 1 ? true : false;
+    bool? isDetailAction = state.pageType == 2 ? true : false;
+
+    return Column(
+      crossAxisAlignment: CrossAxisAlignment.start,
+        children: [
+        //工作标题,选择模板
+        FormRequireText(
+          text: "Job Title".tr,
+        ).marginOnly(top: 15),
+
+        //工作标题
+        Container(
+          padding: const EdgeInsets.only(left: 16, right: 10),
+          margin: const EdgeInsets.only(top: 10),
+          height: 45,
+          decoration: BoxDecoration(
+            color: const Color(0xFF4DCFF6).withOpacity(state.pageType == 2 ? 0.5 : 0.2),
+            borderRadius: const BorderRadius.all(Radius.circular(5)),
+          ),
+          child: Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            mainAxisAlignment: MainAxisAlignment.start,
+            children: [
+              MyTextView(
+                state.selectedTemplateId == null || state.selectedTemplateId == "0"
+                    ? ""
+                    : state.templateList!
+                            .firstWhere((element) => element.value.toString() == state.selectedTemplateId,
+                                orElse: () => UkLabourRequestDetailTemplateList())
+                            .txt ??
+                        "",
+                fontSize: 14,
+                hint: "Choose Job Title".tr,
+                textHintColor: ColorConstants.textGrayAECAE5,
+                isFontMedium: true,
+                textColor: ColorConstants.white,
+              ).expanded(),
+
+              //下拉选图标
+              Visibility(
+                visible: state.pageType != 2,
+                child: const MyAssetImage(Assets.baseServiceTriangleDropDownIcon, width: 11.5, height: 6.28),
+              ),
+            ],
+          ),
+        ).onTap(() {
+          FocusScope.of(context).unfocus();
+          controller.pickJobTitle();
+        }),
+
+        if(isAddAction)
+          // 新增时 工作时间筛选
+          _getAddChooseDateAndTimeWidget(context, controller, true)
+        else
+          // 编辑 和 详情时 工作时间筛选
+          _getEditOrDetailDateAndTimeWidget(context, controller, isEditAction, isDetailAction),
+
+        //工作选择部门
+        FormRequireText(
+          text: "Outlet".tr,
+        ).marginOnly(top: 15),
+
+        //选择部门
+        Container(
+          padding: const EdgeInsets.only(left: 16, right: 10),
+          margin: const EdgeInsets.only(top: 10),
+          height: 45,
+          decoration: BoxDecoration(
+            color: const Color(0xFF4DCFF6).withOpacity(state.pageType == 2 ? 0.5 : 0.2),
+            borderRadius: const BorderRadius.all(Radius.circular(5)),
+          ),
+          child: Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            mainAxisAlignment: MainAxisAlignment.start,
+            children: [
+              MyTextView(
+                state.selectedDepartmentId == null || state.selectedDepartmentId == "0"
+                    ? ""
+                    : state.departmentList!
+                            .firstWhere((element) => element.value.toString() == state.selectedDepartmentId,
+                                orElse: () => UkLabourRequestDetailDepartmentList())
+                            .txt ??
+                        "",
+                fontSize: 14,
+                hint: "Choose Outlet".tr,
+                textHintColor: ColorConstants.textGrayAECAE5,
+                isFontMedium: true,
+                textColor: ColorConstants.white,
+              ).expanded(),
+              //下拉选图标
+              Visibility(
+                visible: state.pageType != 2,
+                child: const MyAssetImage(Assets.baseServiceTriangleDropDownIcon, width: 11.5, height: 6.28),
+              ),
+            ],
+          ),
+        ).onTap(() {
+          FocusScope.of(context).unfocus();
+          controller.pickDepartment();
+        }),
+
+        //需要的人数
+        FormRequireText(
+          text: "No. of Staff".tr,
+        ).marginOnly(top: 15),
+
+        //输入框(只允许输入数字)
+        CustomTextField(
+          formKey: "no_of_staff",
+          marginLeft: 0,
+          marginRight: 0,
+          paddingTop: 0,
+          paddingBottom: 0,
+          height: 45,
+          fillBackgroundColor: const Color(0xFF4DCFF6).withOpacity(state.pageType == 2 ? 0.5 : 0.2),
+          enabled: state.pageType != 2,
+          inputFormatters: <TextInputFormatter>[FilteringTextInputFormatter.digitsOnly],
+          textInputType: TextInputType.number,
+          formData: state.formData,
+          textInputAction: TextInputAction.done,
+          onSubmit: (key, value) {
+            FocusScope.of(context).unfocus();
+          },
+          marginTop: 10,
+        ),
+
+        //选择是否需要输入金额
+        Visibility(
+          visible: state.labReqOption?.serviceType == 1,
+          child: FormRequireText(
+            text: "Amount".tr,
+          ).marginOnly(top: 15),
+        ),
+
+        Visibility(
+          visible: state.labReqOption?.serviceType == 1,
+          child: CustomTextField(
+            formKey: "amount",
+            marginLeft: 0,
+            marginRight: 0,
+            paddingTop: 0,
+            paddingBottom: 0,
+            height: 45,
+            fillBackgroundColor: const Color(0xFF4DCFF6).withOpacity(state.pageType == 2 ? 0.5 : 0.2),
+            enabled: state.pageType != 2,
+            textInputType: TextInputType.number,
+            formData: state.formData,
+            textInputAction: TextInputAction.done,
+            onSubmit: (key, value) {
+              FocusScope.of(context).unfocus();
+            },
+            marginTop: 10,
+          ),
+        ),
+
+
+        // 选择预选人
+        Visibility(
+          visible: isAddAction,
+          child: FormRequireText(
+            text: "Pre Selected".tr,
+            isRequired: false,
+          ).marginOnly(top: 15),
+        ),
+
+        //重复的预选人
+        Visibility(
+          visible: isAddAction,
+          child: Container(
+            padding: const EdgeInsets.only(left: 16, right: 10, top: 5, bottom: 5),
+            margin: const EdgeInsets.only(top: 10),
+            decoration: BoxDecoration(
+              color: const Color(0xFF4DCFF6).withOpacity(state.pageType == 2 ? 0.5 : 0.2),
+              borderRadius: const BorderRadius.all(Radius.circular(5)),
+            ),
+            child: Row(
+              mainAxisSize: MainAxisSize.max,
+              crossAxisAlignment: CrossAxisAlignment.center,
+              mainAxisAlignment: MainAxisAlignment.start,
+              children: [
+                //横向的流式布局
+                Expanded(
+                  child: Wrap(
+                    spacing: 8.0, // 子组件之间的水平间距
+                    runSpacing: 5.0, // 子组件之间的垂直间距
+                    children: state.preSelectedNames == null
+                        ? [
+                      MyTextView(
+                        "",
+                        textColor: Colors.white,
+                        isFontRegular: true,
+                        fontSize: 14,
+                        hint: "Choose Pre Selected".tr,
+                        textHintColor: ColorConstants.textGrayAECAE5,
+                        paddingTop: 5,
+                        paddingBottom: 5,
+                        paddingLeft: 7.5,
+                        paddingRight: 7.5,
+                      )
+                    ]
+                        : List.generate(state.preSelectedNames!.split(",").length, (index) {
+                      return MyTextView(
+                        state.preSelectedNames!.split(",")[index],
+                        textColor: Colors.white,
+                        isFontRegular: true,
+                        fontSize: 14,
+                        hint: "Choose Pre Selected".tr,
+                        backgroundColor: ColorConstants.string2Color('#0AC074'),
+                        paddingTop: 5,
+                        paddingBottom: 5,
+                        paddingLeft: 7.5,
+                        paddingRight: 7.5,
+                        cornerRadius: 5.0,
+                      );
+                    }),
+                  ),
+                ),
+
+                const SizedBox(width: 10),
+
+                //下拉选图标
+                Visibility(
+                  visible: !isDetailAction,
+                  child: const MyAssetImage(Assets.baseServiceTriangleDropDownIcon, width: 11.5, height: 6.28),
+                ),
+              ],
+            ),
+          ).constrained(minHeight: 60).onTap(() {
+            FocusScope.of(context).unfocus();
+            controller.handlerSelectPreSelect();
+          }),
+        ),
+
+        // certificate 证书
+        Visibility(
+          visible: state.certificateList?.isNotEmpty == true,
+          child: MyTextView(
+            "Certificate".tr,
+            textColor: Colors.white,
+            fontSize: 14,
+            isFontRegular: true,
+            marginLeft: 0,
+            marginTop: 15,
+          ),
+        ),
+
+        // 证书的多选
+        Visibility(
+          visible: state.certificateList?.isNotEmpty == true,
+          child: CustomCheckBox(
+            options: state.certificateList?.map<String>((e) => e.txt!).toList() ?? [],
+            onOptionsSelected: (selected) {
+              Log.d("操作了证书后的 selected   ${selected}");
+              Log.d("操作证书时的 state.certificateList   ${state.certificateList}");
+              // 转换选中的索引为对应的 value
+              state.selectedCertificateList = selected
+                  .map((index) {
+                return state.certificateList?[index].value?.toString(); // 获取对应的 value
+              })
+                  .whereType<String>()
+                  .toList();
+              Log.d("操作了证书后的 selectedList   ${state.selectedCertificateList}");
+            },
+            selectedOptions: state.certificateList?.where((e) => e.checked == "checked").map((e) => e.txt!).toList() ?? [],
+          ).marginOnly(left: 0, right: 15, top: 10),
+        ),
+
+        // challenge25
+        MyTextView(
+          "Challenge25".tr,
+          textColor: Colors.white,
+          fontSize: 14,
+          isFontRegular: true,
+          marginTop: 15,
+        ),
+
+        // challenge25 radiobox
+        Visibility(
+          visible: state.challenge25List?.isNotEmpty == true,
+          child: CustomRadioCheck(
+            options: state.challenge25List?.map((e) => e.txt!).toList() ?? [],
+              onOptionSelected: (index, text) {
+                state.selectedChallenge25Id = state.challenge25List![index].value?.toString()??'';
+              },
+              selectedPosition: state.challenge25List?.indexWhere((e) => e.checked == "checked") ?? -1,
+          ).marginOnly(left: 0, right: 15, top: 10),
+    ),
+
+        // Vehicle  交通工具
+        MyTextView(
+          "Vehicle".tr,
+          textColor: Colors.white,
+          fontSize: 14,
+          isFontRegular: true,
+          marginTop: 15,
+        ),
+
+        //交通工具的多选
+        Visibility(
+          visible: state.vehicleList?.isNotEmpty == true,
+          child: CustomCheckBox(
+            options: state.vehicleList?.map((e) => e.txt!).toList() ?? [],
+            onOptionsSelected: (selected) {
+              // 转换选中的索引为对应的 value
+              state.selectedVehicleList = selected
+                  .map((index) {
+                return state.vehicleList?[index].value?.toString(); // 获取对应的 value
+              })
+                  .whereType<String>()
+                  .toList();
+            },
+            selectedOptions: state.vehicleList?.where((e) => e.checked == "checked").map((e) => e.txt!).toList() ?? [],
+          ).marginOnly(left: 0, right: 15, top: 10),
+        ),
+
+
+        // Type 选项  employment list
+        FormRequireText(
+          text: "Choose Type".tr,
+          isRequired: true,
+        ).marginOnly(top: 15),
+        Container(
+          padding: const EdgeInsets.only(left: 16, right: 10),
+          margin: const EdgeInsets.only(top: 10),
+          height: 45,
+          decoration: BoxDecoration(
+            color: const Color(0xFF4DCFF6).withOpacity(isDetailAction ? 0.5 : 0.2),
+            borderRadius: const BorderRadius.all(Radius.circular(5)),
+          ),
+          child: Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            mainAxisAlignment: MainAxisAlignment.start,
+            children: [
+              MyTextView(
+                state.selectedTypeId == null || state.selectedTypeId == "0"
+                    ? ""
+                    : state.employmentList!
+                    .firstWhere((element) => element.value.toString() == state.selectedTypeId,
+                    orElse: () => UkLabourRequestDetailEmploymentList())
+                    .txt ??
+                    "",
+                fontSize: 14,
+                hint: "Choose Type".tr,
+                textHintColor: ColorConstants.textGrayAECAE5,
+                isFontMedium: true,
+                textColor: ColorConstants.white,
+              ).expanded(),
+              //下拉选图标
+              Visibility(
+                visible: !isDetailAction,
+                child: const MyAssetImage(Assets.baseServiceTriangleDropDownIcon, width: 11.5, height: 6.28),
+              ),
+            ],
+          ),
+        ).onTap(() {
+          FocusScope.of(context).unfocus();
+          controller.pickEmploymentType();
+        }),
+
+        //Event
+        MyTextView(
+          "I.Event".tr,
+          fontSize: 15,
+          isFontRegular: true,
+          textColor: Colors.white,
+          marginTop: 15,
+        ),
+
+        CustomTextField(
+          formKey: "event",
+          marginLeft: 0,
+          marginRight: 0,
+          paddingTop: 0,
+          paddingBottom: 0,
+          marginTop: 10,
+          height: 45,
+          fillBackgroundColor: const Color(0xFF4DCFF6).withOpacity(isDetailAction? 0.5 : 0.2),
+          enabled: !isDetailAction,
+          textInputType: TextInputType.text,
+          formData: state.formData,
+          textInputAction: TextInputAction.next,
+          onSubmit: (key, value) {
+            state.formData[key]!['focusNode'].unfocus();
+            FocusScope.of(context).requestFocus(state.formData['event_type']!['focusNode']);
+          },
+        ),
+
+        //Event Type
+        MyTextView(
+          "II.Event Type".tr,
+          fontSize: 15,
+          isFontRegular: true,
+          textColor: Colors.white,
+          marginTop: 15,
+        ),
+
+        CustomTextField(
+          formKey: "event_type",
+          marginLeft: 0,
+          marginRight: 0,
+          paddingTop: 0,
+          paddingBottom: 0,
+          marginTop: 10,
+          height: 45,
+          fillBackgroundColor: const Color(0xFF4DCFF6).withOpacity(isDetailAction? 0.5 : 0.2),
+          enabled: !isDetailAction,
+          textInputType: TextInputType.text,
+          formData: state.formData,
+          textInputAction: TextInputAction.next,
+          onSubmit: (key, value) {
+            state.formData[key]!['focusNode'].unfocus();
+            FocusScope.of(context).requestFocus(state.formData['event_pax']!['focusNode']);
+          },
+        ),
+
+        //Event Pax
+        MyTextView(
+          "III.Event Pax".tr,
+          fontSize: 15,
+          isFontRegular: true,
+          textColor: Colors.white,
+          marginTop: 15,
+        ),
+
+        CustomTextField(
+          formKey: "event_pax",
+          marginLeft: 0,
+          marginRight: 0,
+          paddingTop: 0,
+          paddingBottom: 0,
+          marginTop: 10,
+          height: 45,
+          fillBackgroundColor: const Color(0xFF4DCFF6).withOpacity(isDetailAction? 0.5 : 0.2),
+          enabled: !isDetailAction,
+          textInputType: TextInputType.number,
+          formData: state.formData,
+          textInputAction: TextInputAction.next,
+          onSubmit: (key, value) {
+            state.formData[key]!['focusNode'].unfocus();
+            FocusScope.of(context).requestFocus(state.formData['revenue']!['focusNode']);
+          },
+        ),
+
+        //Revenue
+        MyTextView(
+          "IV.Estimated Revenue".tr,
+          fontSize: 15,
+          isFontRegular: true,
+          textColor: Colors.white,
+          marginTop: 15,
+        ),
+
+        CustomTextField(
+          formKey: "revenue",
+          marginLeft: 0,
+          marginRight: 0,
+          paddingTop: 0,
+          paddingBottom: 0,
+          marginTop: 10,
+          height: 45,
+          fillBackgroundColor: const Color(0xFF4DCFF6).withOpacity(isDetailAction ? 0.5 : 0.2),
+          enabled: !isDetailAction,
+          textInputType: TextInputType.number,
+          formData: state.formData,
+          textInputAction: TextInputAction.next,
+          onSubmit: (key, value) {
+            state.formData[key]!['focusNode'].unfocus();
+            FocusScope.of(context).requestFocus(state.formData['position']!['focusNode']);
+          },
+        ),
+
+        //Position
+        MyTextView(
+          "V.Position".tr,
+          fontSize: 15,
+          isFontRegular: true,
+          textColor: Colors.white,
+          marginTop: 15,
+        ),
+
+        CustomTextField(
+          formKey: "position",
+          marginLeft: 0,
+          marginRight: 0,
+          paddingTop: 0,
+          paddingBottom: 0,
+          marginTop: 10,
+          height: 45,
+          fillBackgroundColor: const Color(0xFF4DCFF6).withOpacity(isDetailAction ? 0.5 : 0.2),
+          enabled: !isDetailAction,
+          textInputType: TextInputType.text,
+          formData: state.formData,
+          textInputAction: TextInputAction.next,
+          onSubmit: (key, value) {
+            state.formData[key]!['focusNode'].unfocus();
+            FocusScope.of(context).requestFocus(state.formData['total_cost']!['focusNode']);
+          },
+        ),
+
+        //total_cost
+        MyTextView(
+          "VI.Estimated Total Cost".tr,
+          fontSize: 15,
+          isFontRegular: true,
+          textColor: Colors.white,
+          marginTop: 15,
+        ),
+
+        CustomTextField(
+          formKey: "total_cost",
+          marginLeft: 0,
+          marginRight: 0,
+          paddingTop: 0,
+          paddingBottom: 0,
+          marginTop: 10,
+          height: 45,
+          fillBackgroundColor: const Color(0xFF4DCFF6).withOpacity(isDetailAction? 0.5 : 0.2),
+          enabled: !isDetailAction,
+          textInputType: TextInputType.number,
+          formData: state.formData,
+          textInputAction: TextInputAction.done,
+          onSubmit: (key, value) {
+            FocusScope.of(context).unfocus();
+          },
+        ),
+
+        //输入Remark
+        MyTextView(
+          "Remark".tr,
+          fontSize: 15,
+          isFontRegular: true,
+          textColor: Colors.white,
+          marginTop: 15,
+        ),
+
+        IgnoreKeyboardDismiss(
+          child: Container(
+            height: 160,
+            margin: const EdgeInsets.only(top: 10),
+            padding: const EdgeInsets.symmetric(vertical: 15, horizontal: 15),
+            decoration: BoxDecoration(
+              color: const Color(0xFF4DCFF6).withOpacity(isDetailAction == 2 ? 0.5 : 0.2),
+              borderRadius: const BorderRadius.all(Radius.circular(5)),
+            ),
+            child: TextField(
+              cursorColor: ColorConstants.white,
+              cursorWidth: 1.5,
+              autofocus: false,
+              enabled: isAddAction || isEditAction,
+              focusNode: state.formData["remark"]!['focusNode'],
+              controller: state.formData["remark"]!['controller'],
+              // 装饰
+              decoration: InputDecoration(
+                isDense: true,
+                isCollapsed: true,
+                border: InputBorder.none,
+                hintText: state.formData["remark"]!['hintText'],
+                hintStyle: const TextStyle(
+                  color: ColorConstants.textGrayAECAE5,
+                  fontSize: 15.0,
+                  fontWeight: FontWeight.w400,
+                ),
+              ),
+              style: const TextStyle(
+                color: ColorConstants.white,
+                fontSize: 15.0,
+                fontWeight: FontWeight.w400,
+              ),
+              // 键盘动作右下角图标
+              textInputAction: TextInputAction.done,
+              onSubmitted: (value) {
+                FocusScope.of(context).unfocus();
+              },
+            ),
+          ),
+        ),
+
+        // 附件
+        _buildAttachFileWidget(context, controller, isAddAction, isEditAction, isDetailAction),
+
+        const SizedBox(height: 30),
+
+        //提交按钮
+        Visibility(
+          visible: !isDetailAction,
+          child: MyButton(
+            type: ClickType.throttle,
+            milliseconds: 500,
+            onPressed: () {
+              FocusScope.of(context).unfocus();
+              controller.doSubmit();
+            },
+            text: "Submit".tr,
+            textColor: ColorConstants.white,
+            fontSize: 16,
+            radius: 22.5,
+            backgroundColor: hexToColor("#FFBB1B"),
+            fontWeight: FontWeight.w500,
+          ).marginSymmetric(horizontal: 0, vertical: 30),
+        ),
+      ],
+    );
+  }
+
+  // 新增 时 的 选择日期 选择开始时间 选择结束时间
+  Widget _getAddChooseDateAndTimeWidget(BuildContext context, CommonLabourRequestController controller, bool isAdd){
+    final state = controller.commonState;
+    return Column(
+      crossAxisAlignment: CrossAxisAlignment.start,
+      children: [
+        //开始时间
+        FormRequireText(
+          text: "Job Date".tr,
+        ).marginOnly(top: 15),
+        //选择开始日期
+        Container(
+          padding: const EdgeInsets.only(left: 16, right: 10),
+          margin: const EdgeInsets.only(top: 10),
+          height: 45,
+          decoration: BoxDecoration(
+            color: const Color(0xFF4DCFF6).withOpacity(state.pageType == 2 ? 0.5 : 0.2),
+            borderRadius: const BorderRadius.all(Radius.circular(5)),
+          ),
+          child: Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            mainAxisAlignment: MainAxisAlignment.start,
+            children: [
+              MyTextView(
+                state.selectedDate == null ? "" : DateTimeUtils.formatDate(state.selectedDate, format: 'yyyy-MM-dd'),
+                fontSize: 14,
+                hint: "Job Date".tr,
+                textHintColor: ColorConstants.textGrayAECAE5,
+                isFontMedium: true,
+                textColor: ColorConstants.white,
+              ).expanded(),
+              //下拉选图标
+              Visibility(
+                visible: state.pageType != 2,
+                child: const MyAssetImage(Assets.baseServiceTriangleDropDownIcon, width: 11.5, height: 6.28),
+              ),
+            ],
+          ),
+        ).onTap(() {
+          FocusScope.of(context).unfocus();
+          controller.pickJobDate();
+        }),
+        // 开始时间 - 结束时间
+        Row(
+          children: [
+            Container(
+              padding: const EdgeInsets.only(left: 16, right: 10),
+              margin: const EdgeInsets.only(top: 10),
+              height: 45,
+              decoration: BoxDecoration(
+                color: const Color(0xFF4DCFF6).withOpacity(state.pageType == 2 ? 0.5 : 0.2),
+                borderRadius: const BorderRadius.all(Radius.circular(5)),
+              ),
+              child: Row(
+                mainAxisSize: MainAxisSize.max,
+                crossAxisAlignment: CrossAxisAlignment.center,
+                mainAxisAlignment: MainAxisAlignment.start,
+                children: [
+                  MyTextView(
+                    state.selectedStartTime == null ? "" : DateTimeUtils.formatDate(state.selectedStartTime, format: 'HH:mm'),
+                    fontSize: 14,
+                    hint: "Job Start Time".tr,
+                    textHintColor: ColorConstants.textGrayAECAE5,
+                    isFontMedium: true,
+                    textColor: ColorConstants.white,
+                  ).expanded(),
+                  //下拉选图标
+                  Visibility(
+                    visible: state.pageType != 2,
+                    child: const MyAssetImage(Assets.baseServiceTriangleDropDownIcon, width: 11.5, height: 6.28),
+                  ),
+                ],
+              ),
+            ).onTap(() {
+              FocusScope.of(context).unfocus();
+              controller.pickStartTime();
+            }).expanded(),
+
+            //分割线
+            MyTextView(
+              "-",
+              textColor: Colors.white,
+              marginLeft: 10,
+              marginRight: 10,
+              fontSize: 14,
+              isFontRegular: true,
+            ),
+
+            //结束时间
+            Container(
+              padding: const EdgeInsets.only(left: 16, right: 10),
+              margin: const EdgeInsets.only(top: 10),
+              height: 45,
+              decoration: BoxDecoration(
+                color: const Color(0xFF4DCFF6).withOpacity(state.pageType == 2 ? 0.5 : 0.2),
+                borderRadius: const BorderRadius.all(Radius.circular(5)),
+              ),
+              child: Row(
+                mainAxisSize: MainAxisSize.max,
+                crossAxisAlignment: CrossAxisAlignment.center,
+                mainAxisAlignment: MainAxisAlignment.start,
+                children: [
+                  MyTextView(
+                    state.selectedEndTime == null ? "" : DateTimeUtils.formatDate(state.selectedEndTime, format: 'HH:mm'),
+                    fontSize: 14,
+                    hint: "Job End Time".tr,
+                    textHintColor: ColorConstants.textGrayAECAE5,
+                    isFontMedium: true,
+                    textColor: ColorConstants.white,
+                  ).expanded(),
+                  //下拉选图标
+                  Visibility(
+                    visible: state.pageType != 2,
+                    child: const MyAssetImage(Assets.baseServiceTriangleDropDownIcon, width: 11.5, height: 6.28),
+                  ),
+                ],
+              ),
+            ).onTap(() {
+              FocusScope.of(context).unfocus();
+              controller.pickEndTime();
+            }).expanded(),
+          ],
+        ),
+
+
+        //重复的日期
+        MyTextView(
+          "Repeat Date".tr,
+          fontSize: 15,
+          textColor: Colors.white,
+          isFontRegular: true,
+          marginTop: 15,
+        ),
+
+        //重复的日期区间
+        Container(
+          padding: const EdgeInsets.only(left: 16, right: 10, top: 5, bottom: 5),
+          margin: const EdgeInsets.only(top: 10),
+          decoration: BoxDecoration(
+            color: const Color(0xFF4DCFF6).withOpacity(state.pageType == 2 ? 0.5 : 0.2),
+            borderRadius: const BorderRadius.all(Radius.circular(5)),
+          ),
+          child: Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            mainAxisAlignment: MainAxisAlignment.start,
+            children: [
+              //横向的流式布局
+              Expanded(
+                child: Wrap(
+                  spacing: 8.0, // 子组件之间的水平间距
+                  runSpacing: 5.0, // 子组件之间的垂直间距
+                  children: state.repeatDateStr == null
+                      ? [
+                    MyTextView(
+                      "",
+                      textColor: Colors.white,
+                      isFontRegular: true,
+                      fontSize: 14,
+                      hint: "Choose Repeat Date".tr,
+                      textHintColor: ColorConstants.textGrayAECAE5,
+                      paddingTop: 5,
+                      paddingBottom: 5,
+                      paddingLeft: 7.5,
+                      paddingRight: 7.5,
+                    )
+                  ]
+                      : List.generate(state.repeatDateStr!.split(",").length, (index) {
+                    return MyTextView(
+                      state.repeatDateStr!.split(",")[index],
+                      textColor: Colors.white,
+                      isFontRegular: true,
+                      fontSize: 14,
+                      hint: "Choose Repeat Date".tr,
+                      backgroundColor: ColorConstants.string2Color('#0AC074'),
+                      paddingTop: 5,
+                      paddingBottom: 5,
+                      paddingLeft: 7.5,
+                      paddingRight: 7.5,
+                      cornerRadius: 5.0,
+                    );
+                  }),
+                ),
+              ),
+
+              const SizedBox(width: 10),
+
+              //下拉选图标
+              Visibility(
+                visible: state.pageType != 2,
+                child: const MyAssetImage(Assets.baseServiceTriangleDropDownIcon, width: 11.5, height: 6.28),
+              ),
+            ],
+          ),
+        ).constrained(minHeight: 60).onTap(() {
+          FocusScope.of(context).unfocus();
+          controller.pickDateRange();
+        }),
+      ],
+    );
+  }
+
+  // 编辑/详情 的 时间区域
+  Widget _getEditOrDetailDateAndTimeWidget(BuildContext context, CommonLabourRequestController controller, bool isEdit, bool isDetail){
+    final state = controller.commonState;
+    // Log.d("-------${state.jobStart}---${state.jobEnd}");
+    // String jobSelectJobStart = state.jobStart !=null? DateTimeUtils.formatDate(state.jobStart!, format: 'yyyy-MM-dd HH:mm'):"";
+    // String jobSelectJobEnd = state.jobEnd !=null? DateTimeUtils.formatDate(state.jobEnd!, format: 'yyyy-MM-dd HH:mm'):"";
+
+    return Column(
+      crossAxisAlignment: CrossAxisAlignment.start,
+      children: [
+        FormRequireText(
+          text: "Start Time".tr,
+        ).marginOnly(top: 15),
+        //开始时间
+        Container(
+          padding: const EdgeInsets.only(left: 16, right: 10),
+          margin: const EdgeInsets.only(top: 10),
+          height: 45,
+          decoration: BoxDecoration(
+            color: const Color(0xFF4DCFF6).withOpacity(isDetail ? 0.5 : 0.2),
+            borderRadius: const BorderRadius.all(Radius.circular(5)),
+          ),
+          child: Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            mainAxisAlignment: MainAxisAlignment.start,
+            children: [
+              MyTextView(
+                state.jobSelectJobStart?? "",
+                fontSize: 14,
+                hint: "Start Time".tr,
+                textHintColor: ColorConstants.textGrayAECAE5,
+                isFontMedium: true,
+                textColor: ColorConstants.white,
+              ).expanded(),
+              //下拉选图标
+              Visibility(
+                visible: state.pageType != 2,
+                child: const MyAssetImage(Assets.baseServiceTriangleDropDownIcon, width: 11.5, height: 6.28),
+              ),
+            ],
+          ),
+        ).onTap(() {
+          FocusScope.of(context).unfocus();
+          controller.pickJobStart();
+        }),
+
+
+        FormRequireText(
+          text: "End Time".tr,
+        ).marginOnly(top: 15),
+        //结束时间
+        Container(
+          padding: const EdgeInsets.only(left: 16, right: 10),
+          margin: const EdgeInsets.only(top: 10),
+          height: 45,
+          decoration: BoxDecoration(
+            color: const Color(0xFF4DCFF6).withOpacity(isDetail ? 0.5 : 0.2),
+            borderRadius: const BorderRadius.all(Radius.circular(5)),
+          ),
+          child: Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            mainAxisAlignment: MainAxisAlignment.start,
+            children: [
+              MyTextView(
+                state.jobSelectJobEnd?? "",
+                fontSize: 14,
+                hint: "End Time".tr,
+                textHintColor: ColorConstants.textGrayAECAE5,
+                isFontMedium: true,
+                textColor: ColorConstants.white,
+              ).expanded(),
+              //下拉选图标
+              Visibility(
+                visible: state.pageType != 2,
+                child: const MyAssetImage(Assets.baseServiceTriangleDropDownIcon, width: 11.5, height: 6.28),
+              ),
+            ],
+          ),
+        ).onTap(() {
+          FocusScope.of(context).unfocus();
+          controller.pickJobEnd();
+        }),
+      ]
+     );
+  }
+
+  // 附件
+  Widget _buildAttachFileWidget(BuildContext context, CommonLabourRequestController controller,bool isAdd, bool isEdit, bool isDetail){
+    final state = controller.commonState;
+    return Column(
+      crossAxisAlignment: CrossAxisAlignment.start,
+      children: [
+        //附件文件
+        MyTextView(
+          "Attachment".tr,
+          fontSize: 15,
+          isFontRegular: true,
+          textColor: Colors.white,
+          marginTop: 15,
+        ),
+
+        // 显示和选择附件
+        Container(
+          padding: const EdgeInsets.only(left: 16),
+          margin: const EdgeInsets.only(top: 10),
+          height: 45,
+          decoration: BoxDecoration(
+            color: const Color(0xFF4DCFF6).withOpacity(isDetail == 2 ? 0.5 : 0.2),
+            borderRadius: const BorderRadius.all(Radius.circular(5)),
+          ),
+          child: Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            mainAxisAlignment: MainAxisAlignment.start,
+            children: [
+              MyTextView(
+                Utils.isNotEmpty(state.attFilePath) ? Uri.parse(state.attFilePath!).pathSegments.last : "",
+                fontSize: 14,
+                hint: "Choose Attachment".tr,
+                textHintColor: ColorConstants.textGrayAECAE5,
+                isFontMedium: true,
+                textColor: ColorConstants.white,
+              ).expanded(),
+
+              // 上传附件的图标
+              Visibility(
+                visible: !isDetail,
+                child: MyTextView(
+                  'Upload'.tr,
+                  boxHeight: 45,
+                  textAlign: TextAlign.center,
+                  boxWidth: 90,
+                  cornerRadius: 5,
+                  onClick: controller.pickAttFile,
+                  textColor: Colors.white,
+                  fontSize: 15,
+                  fontWeight: FontWeight.w400,
+                  backgroundColor: ColorConstants.textGreen0AC074,
+                ),
+              ),
+            ],
+          ),
+        ),
+      ],
+    );
+  }
+}

+ 120 - 0
packages/cpt_uk/lib/modules/job/labour_request_add/widget/labour_request_interface.dart

@@ -0,0 +1,120 @@
+import 'package:domain/entity/response/uk_labour_request_detail_entity.dart';
+import 'package:flutter/material.dart';
+import 'package:plugin_basic/basic_export.dart';
+
+abstract class CommonLabourRequestState {
+  String? get useInSence; // labour_request  labour_request_review
+  int get pageType;  //页面的状态 0 是新增  1是编辑  2是详情
+  int get serviceType;
+  String? get selectedTemplateId;
+  dynamic get labReqOption;
+  String? get selectedDepartmentId;
+  DateTime? get selectedDate;
+  DateTime? get selectedStartTime;
+  DateTime? get selectedEndTime;
+  DateTime? get jobStart;
+  DateTime? get jobEnd;
+  String?  jobSelectJobStart;
+  String?  jobSelectJobEnd;
+  String? get repeatDateStr;
+  String? get selectedTypeId;
+  String? get preSelectedNames;
+  String? get attFilePath;
+
+  List<String> selectedCertificateList = [];   //选中的 证书 certificate id
+  List<String> selectedVehicleList = [];   //选中的 车辆 vehicle id
+  String? selectedChallenge25Id;   // 选择的 challenge25 id
+
+  List<UkLabourRequestDetailLocationList>? get locationList;
+  List<UkLabourRequestDetailTemplateList>? get templateList;
+  List<UkLabourRequestDetailDepartmentList>? get departmentList;
+  List<UkLabourRequestDetailChargeList>? get chargeList;
+  List<UkLabourRequestDetailEmploymentList>? get employmentList;
+  List<UkLabourRequestDetailCertificateList>? get certificateList => labReqOption?.certificateList;
+  List<UkLabourRequestDetailVehicleList>? get vehicleList => labReqOption?.vehicleList;
+  List<UkLabourRequestDetailChallenge25List>? get challenge25List => labReqOption?.challenge25List;
+
+
+  Map<String, Map<String, dynamic>> formData = {
+    'no_of_staff': {
+      'value': '',
+      'controller': TextEditingController(),
+      'focusNode': FocusNode(),
+      'hintText': 'Enter No. of Staff'.tr,
+      'obsecure': false,
+    },
+    'amount': {
+      'value': '',
+      'controller': TextEditingController(),
+      'focusNode': FocusNode(),
+      'hintText': 'Enter Amount'.tr,
+      'obsecure': false,
+    },
+    'remark': {
+      'value': '',
+      'controller': TextEditingController(),
+      'focusNode': FocusNode(),
+      'hintText': 'Enter...'.tr,
+      'obsecure': false,
+    },
+    'event': {
+      'value': '',
+      'controller': TextEditingController(),
+      'focusNode': FocusNode(),
+      'hintText': 'Enter...'.tr,
+      'obsecure': false,
+    },
+    'event_type': {
+      'value': '',
+      'controller': TextEditingController(),
+      'focusNode': FocusNode(),
+      'hintText': 'Enter...'.tr,
+      'obsecure': false,
+    },
+    'event_pax': {
+      'value': '',
+      'controller': TextEditingController(),
+      'focusNode': FocusNode(),
+      'hintText': 'Enter...'.tr,
+      'obsecure': false,
+    },
+    'revenue': {
+      'value': '',
+      'controller': TextEditingController(),
+      'focusNode': FocusNode(),
+      'hintText': 'Enter...'.tr,
+      'obsecure': false,
+    },
+    'position': {
+      'value': '',
+      'controller': TextEditingController(),
+      'focusNode': FocusNode(),
+      'hintText': 'Enter...'.tr,
+      'obsecure': false,
+    },
+    'total_cost': {
+      'value': '',
+      'controller': TextEditingController(),
+      'focusNode': FocusNode(),
+      'hintText': 'Enter...'.tr,
+      'obsecure': false,
+    },
+  };
+}
+
+abstract class CommonLabourRequestController {
+  CommonLabourRequestState get commonState;
+
+  void pickJobTitle();
+  void pickJobDate();
+  void pickStartTime();
+  void pickEndTime();
+  void pickJobStart();  // 编辑状态时 修改的开始日期  YYYY-MM-DD HH:mm
+  void pickJobEnd();  // 编辑状态时 修改的结束日期  YYYY-MM-DD HH:mm
+  void pickDepartment();
+  void pickDateRange();
+  void pickAttFile();
+  void pickEmploymentType();
+  void handlerSelectPreSelect();
+  void doSubmit();
+}

+ 22 - 22
packages/cpt_uk/lib/modules/job/labour_request_list/labour_request_filter.dart

@@ -67,9 +67,9 @@ class _LabourRequestFilterState extends State<LabourRequestFilter> {
           height: kToolbarHeight + ScreenUtil.getStatusBarH(context) + 1,
         ),
         Container(
-          padding: EdgeInsets.only(left: 15, right: 15, top: 17.5, bottom: 20),
+          padding: const EdgeInsets.only(left: 15, right: 15, top: 17.5, bottom: 20),
           width: double.infinity,
-          decoration: BoxDecoration(
+          decoration: const BoxDecoration(
             color: Colors.white,
           ),
           child: Column(
@@ -85,12 +85,12 @@ class _LabourRequestFilterState extends State<LabourRequestFilter> {
 
               //选择部门
               Container(
-                padding: EdgeInsets.only(left: 16, right: 10),
-                margin: EdgeInsets.only(top: 10),
+                padding: const EdgeInsets.only(left: 16, right: 10),
+                margin: const EdgeInsets.only(top: 10),
                 height: 45,
-                decoration: BoxDecoration(
+                decoration: const BoxDecoration(
                   color: ColorConstants.grayECECEC,
-                  borderRadius: const BorderRadius.all(Radius.circular(5)),
+                  borderRadius: BorderRadius.all(Radius.circular(5)),
                 ),
                 child: Row(
                   mainAxisSize: MainAxisSize.max,
@@ -107,7 +107,7 @@ class _LabourRequestFilterState extends State<LabourRequestFilter> {
                       isFontMedium: true,
                       textColor: ColorConstants.black33,
                     ).expanded(),
-                    MyAssetImage(Assets.baseServiceTriangleDropDownIcon, width: 11.5, height: 6.28),
+                    const MyAssetImage(Assets.baseServiceTriangleDropDownIcon, width: 11.5, height: 6.28),
                   ],
                 ),
               ).onTap(() {
@@ -125,12 +125,12 @@ class _LabourRequestFilterState extends State<LabourRequestFilter> {
 
               //选择状态
               Container(
-                padding: EdgeInsets.only(left: 16, right: 10),
-                margin: EdgeInsets.only(top: 10),
+                padding: const EdgeInsets.only(left: 16, right: 10),
+                margin: const EdgeInsets.only(top: 10),
                 height: 45,
-                decoration: BoxDecoration(
+                decoration: const BoxDecoration(
                   color: ColorConstants.grayECECEC,
-                  borderRadius: const BorderRadius.all(Radius.circular(5)),
+                  borderRadius: BorderRadius.all(Radius.circular(5)),
                 ),
                 child: Row(
                   mainAxisSize: MainAxisSize.max,
@@ -147,7 +147,7 @@ class _LabourRequestFilterState extends State<LabourRequestFilter> {
                       isFontMedium: true,
                       textColor: ColorConstants.black33,
                     ).expanded(),
-                    MyAssetImage(Assets.baseServiceTriangleDropDownIcon, width: 11.5, height: 6.28),
+                    const MyAssetImage(Assets.baseServiceTriangleDropDownIcon, width: 11.5, height: 6.28),
                   ],
                 ),
               ).onTap(() {
@@ -165,12 +165,12 @@ class _LabourRequestFilterState extends State<LabourRequestFilter> {
 
               //选择时间
               Container(
-                padding: EdgeInsets.only(left: 16, right: 10),
-                margin: EdgeInsets.only(top: 10),
+                padding: const EdgeInsets.only(left: 16, right: 10),
+                margin: const EdgeInsets.only(top: 10),
                 height: 45,
-                decoration: BoxDecoration(
+                decoration: const BoxDecoration(
                   color: ColorConstants.grayECECEC,
-                  borderRadius: const BorderRadius.all(Radius.circular(5)),
+                  borderRadius: BorderRadius.all(Radius.circular(5)),
                 ),
                 child: Row(
                   mainAxisSize: MainAxisSize.max,
@@ -185,7 +185,7 @@ class _LabourRequestFilterState extends State<LabourRequestFilter> {
                       isFontMedium: true,
                       textColor: ColorConstants.black33,
                     ).expanded(),
-                    MyAssetImage(Assets.baseServiceTriangleDropDownIcon, width: 11.5, height: 6.28),
+                    const MyAssetImage(Assets.baseServiceTriangleDropDownIcon, width: 11.5, height: 6.28),
                   ],
                 ),
               ).onTap(() {
@@ -203,12 +203,12 @@ class _LabourRequestFilterState extends State<LabourRequestFilter> {
 
               //选择结束日期
               Container(
-                padding: EdgeInsets.only(left: 16, right: 10),
-                margin: EdgeInsets.only(top: 10),
+                padding: const EdgeInsets.only(left: 16, right: 10),
+                margin: const EdgeInsets.only(top: 10),
                 height: 45,
-                decoration: BoxDecoration(
+                decoration: const BoxDecoration(
                   color: ColorConstants.grayECECEC,
-                  borderRadius: const BorderRadius.all(Radius.circular(5)),
+                  borderRadius: BorderRadius.all(Radius.circular(5)),
                 ),
                 child: Row(
                   mainAxisSize: MainAxisSize.max,
@@ -223,7 +223,7 @@ class _LabourRequestFilterState extends State<LabourRequestFilter> {
                       isFontMedium: true,
                       textColor: ColorConstants.black33,
                     ).expanded(),
-                    MyAssetImage(Assets.baseServiceTriangleDropDownIcon, width: 11.5, height: 6.28),
+                    const MyAssetImage(Assets.baseServiceTriangleDropDownIcon, width: 11.5, height: 6.28),
                   ],
                 ),
               ).onTap(() {

+ 245 - 30
packages/cpt_uk/lib/modules/job/labour_request_list/labour_request_item.dart

@@ -1,9 +1,10 @@
 import 'package:cs_resources/constants/color_constants.dart';
-import 'package:domain/entity/response/labour_request_list_entity.dart';
+import 'package:domain/entity/response/uk_labour_request_table_entity.dart';
 import 'package:flutter/cupertino.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter/widgets.dart';
 import 'package:plugin_basic/basic_export.dart';
+import 'package:shared/utils/log_utils.dart';
 import 'package:widgets/ext/ex_widget.dart';
 import 'package:widgets/my_button.dart';
 import 'package:widgets/my_text_view.dart';
@@ -13,11 +14,14 @@ import 'package:widgets/my_text_view.dart';
  */
 class LabourRequestItem extends StatelessWidget {
   final int index;
-  final LabourRequestListRows item;
+  final UkLabourRequestTableRows item;
   final VoidCallback? onStatusAction;
   final VoidCallback? onRecallAction;
   final VoidCallback? onDetailAction;
   final VoidCallback? onEditAction;
+  final VoidCallback? onCopyAction;
+  final VoidCallback? onQuickCopyAction;
+  final VoidCallback? onPreSelectedClickAction;
 
   LabourRequestItem({
     required this.index,
@@ -26,15 +30,18 @@ class LabourRequestItem extends StatelessWidget {
     this.onRecallAction,
     this.onDetailAction,
     this.onEditAction,
+    this.onCopyAction,
+    this.onQuickCopyAction,
+    this.onPreSelectedClickAction,
   });
 
   @override
   Widget build(BuildContext context) {
     return Container(
-      padding: EdgeInsets.symmetric(vertical: 23, horizontal: 21),
-      margin: EdgeInsets.only(left: 15, right: 15, top: 5, bottom: 5),
+      padding: const EdgeInsets.symmetric(vertical: 23, horizontal: 21),
+      margin: const EdgeInsets.only(left: 15, right: 15, top: 5, bottom: 5),
       decoration: BoxDecoration(
-        color: Color(0xFF4DCFF6).withOpacity(0.2), // 设置背景颜色和不透明度
+        color: const Color(0xFF4DCFF6).withOpacity(0.2), // 设置背景颜色和不透明度
         borderRadius: BorderRadius.circular(5), // 设置圆角
       ),
       child: Column(
@@ -55,6 +62,28 @@ class LabourRequestItem extends StatelessWidget {
             decorationStyle: TextDecorationStyle.solid, // 可选,设置下划线的样式
           ),
 
+          // Event
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "Event:".tr,
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+
+              MyTextView(
+                item.eventName?? "-",
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor: Colors.white,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ).marginOnly(top: 15),
+
           // 部门
           Row(
             mainAxisSize: MainAxisSize.max,
@@ -78,13 +107,13 @@ class LabourRequestItem extends StatelessWidget {
             ],
           ).marginOnly(top: 15),
 
-          // 工作日期时间
+          // 工作日期
           Row(
             mainAxisSize: MainAxisSize.max,
             crossAxisAlignment: CrossAxisAlignment.center,
             children: [
               MyTextView(
-                "Datetime:".tr,
+                "${"Job Date".tr}:",
                 isFontRegular: true,
                 textColor: ColorConstants.textGrayAECAE5,
                 fontSize: 14,
@@ -92,7 +121,7 @@ class LabourRequestItem extends StatelessWidget {
 
               //日期时间
               MyTextView(
-                item.jobTime ?? "-",
+                item.jobDate ?? "-",
                 marginLeft: 5,
                 isFontRegular: true,
                 textColor: Colors.white,
@@ -101,21 +130,21 @@ class LabourRequestItem extends StatelessWidget {
             ],
           ).marginOnly(top: 15),
 
-          // 人数
+          // 工作时间
           Row(
             mainAxisSize: MainAxisSize.max,
             crossAxisAlignment: CrossAxisAlignment.center,
             children: [
               MyTextView(
-                "No. of Staff:".tr,
+                "${"Job Time".tr}:",
                 isFontRegular: true,
                 textColor: ColorConstants.textGrayAECAE5,
                 fontSize: 14,
               ),
 
-              //人数
+              //日期时间
               MyTextView(
-                item.needNum.toString(),
+                item.jobTime ?? "-",
                 marginLeft: 5,
                 isFontRegular: true,
                 textColor: Colors.white,
@@ -124,53 +153,201 @@ class LabourRequestItem extends StatelessWidget {
             ],
           ).marginOnly(top: 15),
 
-          // 状态
+          // 人数 、 薪水
           Row(
             mainAxisSize: MainAxisSize.max,
             crossAxisAlignment: CrossAxisAlignment.center,
             children: [
+              Expanded(
+                flex: 1,
+                child:
+                  Row(
+                    children: [
+                      MyTextView(
+                        "No. of Staff:".tr,
+                        isFontRegular: true,
+                        textColor: ColorConstants.textGrayAECAE5,
+                        fontSize: 14,
+                      ),
+                      //人数
+                      MyTextView(
+                        item.needNum?.toString()??'-',
+                        marginLeft: 5,
+                        isFontRegular: true,
+                        textColor: Colors.white,
+                        fontSize: 14,
+                      ),
+                  ],
+                )
+              ),
+
+              // 薪水
+              Expanded(
+                child: Row(
+                  mainAxisAlignment: MainAxisAlignment.start,
+                  crossAxisAlignment: CrossAxisAlignment.center,
+                  children: [
+                    MyTextView(
+                      "${"Salary".tr}:",
+                      isFontRegular: true,
+                      textColor: ColorConstants.textGrayAECAE5,
+                      fontSize: 14,
+                    ),
+
+                    //薪水
+                    MyTextView(
+                      item.salary ?? "-",
+                      marginLeft: 5,
+                      isFontRegular: true,
+                      textColor: Colors.white,
+                      fontSize: 14,
+                    ),
+                  ]
+                ),
+              )
+            ],
+          ).marginOnly(top: 15),
+
+          // pre select 、 job hours
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+
+              Expanded(
+                flex: 1,
+                child: (
+                  Row(
+                    children: [
+                      MyTextView(
+                        "Pre Selected:".tr,
+                        isFontRegular: true,
+                        textColor: ColorConstants.textGrayAECAE5,
+                        fontSize: 14,
+                      ),
+                      // preNum
+                      Padding(
+                        padding: const EdgeInsets.all(8.0),
+                        child: MyTextView(
+                          item.preNum?.toString()??'-',
+                          marginLeft: 5,
+                          isFontRegular: true,
+                          textColor: Colors.yellow,
+                          fontSize: 14,
+                          textDecoration: TextDecoration.underline,
+                          decorationColor: ColorConstants.textYellowFFBB1B,
+                          // 可选,设置下划线的颜色
+                          decorationThickness: 2.0,
+                          // 可选,设置下划线的粗细
+                          decorationStyle: TextDecorationStyle.solid, // 可选,设置下划线的样式
+                        ),
+                      ).onTap((){
+                        Log.d("去预选人列表页面");
+                        // 去 预选人列表页面
+                        onPreSelectedClickAction?.call();
+                      })
+                    ],
+                  )
+                )
+              ),
+
+              // job hours
+              Expanded(
+                flex: 1,
+                child: Row(
+                    mainAxisAlignment: MainAxisAlignment.start,
+                    crossAxisAlignment: CrossAxisAlignment.center,
+                    children: [
+                      MyTextView(
+                        "${"Job Hours".tr}:",
+                        isFontRegular: true,
+                        textColor: ColorConstants.textGrayAECAE5,
+                        fontSize: 14,
+                      ),
+
+                      //薪水
+                      MyTextView(
+                        item.jobHours ?? "-",
+                        marginLeft: 5,
+                        isFontRegular: true,
+                        textColor: Colors.white,
+                        fontSize: 14,
+                      ),
+                    ]
+                ),
+              )
+            ],
+          ).marginOnly(top: 15),
+
+          // Est Amount 、 Publish Status
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+
               MyTextView(
-                "Status:".tr,
+                "Est Amount:".tr,
                 isFontRegular: true,
                 textColor: ColorConstants.textGrayAECAE5,
                 fontSize: 14,
               ),
-
-              //状态
+              // preNum
               MyTextView(
-                item.coStatusShow == null ? "" : item.coStatusShow!.tr,
+                item.estAmount?.toString()??"-",
                 marginLeft: 5,
                 isFontRegular: true,
-                textColor: "Approved" == item.coStatusShow
-                    ? ColorConstants.textGreen05DC82
-                    : "Rejected" == item.coStatusShow
-                        ? ColorConstants.textRedFF6262
-                        : "Recall" == item.coStatusShow
-                            ? ColorConstants.textYellowFFBB1B
-                            : ColorConstants.textBlue06D9FF,
+                textColor: ColorConstants.textBlue06D9FF,
                 fontSize: 14,
-              ).expanded(),
+              ).marginOnly(right: 20),
             ],
           ).marginOnly(top: 15),
 
-          // 发布状态
+          // publish status
+          Row(
+              mainAxisAlignment: MainAxisAlignment.start,
+              crossAxisAlignment: CrossAxisAlignment.center,
+              children: [
+                MyTextView(
+                  "${"Publish Status".tr}:",
+                  isFontRegular: true,
+                  textColor: ColorConstants.textGrayAECAE5,
+                  fontSize: 14,
+                ),
+
+                MyTextView(
+                  item.publishStatus==true? "Published".tr:"Unpublished".tr,
+                  marginLeft: 5,
+                  isFontRegular: true,
+                  textColor: Colors.white,
+                  fontSize: 14,
+                ),
+              ]
+          ).marginOnly(top: 15),
+
+          // 状态
           Row(
             mainAxisSize: MainAxisSize.max,
             crossAxisAlignment: CrossAxisAlignment.center,
             children: [
               MyTextView(
-                "Publish Status:".tr,
+                "Status:".tr,
                 isFontRegular: true,
                 textColor: ColorConstants.textGrayAECAE5,
                 fontSize: 14,
               ),
 
-              //发布状态
+              //状态
               MyTextView(
-                item.publishStatus ? "Published".tr : "Unpublished".tr,
+                item.coStatusShow == null ? "" : item.coStatusShow!.tr,
                 marginLeft: 5,
                 isFontRegular: true,
-                textColor: Colors.white,
+                textColor: "Approved" == item.coStatusShow
+                    ? ColorConstants.textGreen05DC82
+                    : "Rejected" == item.coStatusShow
+                        ? ColorConstants.textRedFF6262
+                        : "Recall" == item.coStatusShow
+                            ? ColorConstants.textYellowFFBB1B
+                            : ColorConstants.textBlue06D9FF,
                 fontSize: 14,
               ).expanded(),
             ],
@@ -207,6 +384,44 @@ class LabourRequestItem extends StatelessWidget {
               mainAxisAlignment: MainAxisAlignment.end,
               crossAxisAlignment: CrossAxisAlignment.center,
               children: [
+                //Copy按钮
+                // Visibility(
+                //   visible: item.actionList?.contains("copy") ?? false,
+                //   child: MyButton(
+                //     onPressed: () {
+                //       FocusScope.of(context).unfocus();
+                //       onCopyAction?.call();
+                //     },
+                //     text: "Copy".tr,
+                //     textColor: ColorConstants.white,
+                //     backgroundColor: hexToColor(
+                //       "#C009FC",
+                //     ),
+                //     radius: 17.25,
+                //     minWidth: 60,
+                //     minHeight: 35,
+                //   ).marginOnly(left: 12),
+                // ),
+
+                // repeat 快速复制
+                Visibility(
+                  visible: item.actionList?.contains("copy") ?? false,
+                  child: MyButton(
+                    onPressed: () {
+                      FocusScope.of(context).unfocus();
+                      onQuickCopyAction?.call();
+                    },
+                    text: "Quick Copy".tr,
+                    textColor: ColorConstants.white,
+                    backgroundColor: hexToColor(
+                      "#C009FC",
+                    ),
+                    radius: 17.25,
+                    minWidth: 60,
+                    minHeight: 35,
+                  ).marginOnly(left: 12),
+                ),
+
                 //详情按钮
                 Visibility(
                   visible: item.actionList?.contains("detail") ?? false,

+ 93 - 11
packages/cpt_uk/lib/modules/job/labour_request_list/labour_request_list_controller.dart

@@ -1,7 +1,11 @@
+import 'package:cpt_uk/modules/job/labour_request_list/widget/quick_copy_dialog_widget.dart';
+import 'package:cpt_uk/modules/job/labour_request_list/widget/quick_copy_dialog_widget_controller.dart';
 import 'package:cpt_uk/modules/job/labour_request_workflow/labour_request_workflow_page.dart';
 import 'package:domain/entity/response/labour_request_index_entity.dart';
-import 'package:domain/entity/response/labour_request_list_entity.dart';
+import 'package:domain/entity/response/uk_labour_request_table_entity.dart';
 import 'package:domain/repository/labour_repository.dart';
+import 'package:domain/repository/uk_labour_repository.dart';
+import 'package:flutter/cupertino.dart';
 import 'package:get/get.dart';
 import 'package:plugin_basic/constants/app_constant.dart';
 import 'package:plugin_platform/engine/dialog/dialog_engine.dart';
@@ -11,16 +15,20 @@ import 'package:plugin_platform/http/dio/dio_cancelable_mixin.dart';
 import 'package:plugin_platform/http/http_result.dart';
 import 'package:shared/utils/date_time_utils.dart';
 import 'package:shared/utils/event_bus.dart';
+import 'package:shared/utils/log_utils.dart';
 import 'package:shared/utils/util.dart';
 import 'package:widgets/dialog/app_default_dialog.dart';
 import 'package:widgets/load_state_layout.dart';
 import 'package:widgets/widget_export.dart';
+import 'package:widgets/dialog/app_custom_dialog.dart';
 
 import '../labour_request_add/labour_request_add_page.dart';
+import '../labour_request_preselected_list/labour_request_preselected_list_page.dart';
 import 'labour_request_filter.dart';
 import 'labour_request_list_state.dart';
 
 class LabourRequestListController extends GetxController with DioCancelableMixin {
+  final UkLabourRepository _UKlabourRepository = Get.find();
   final LabourRepository _labourRepository = Get.find();
   final LabourRequestListState state = LabourRequestListState();
 
@@ -70,7 +78,7 @@ class LabourRequestListController extends GetxController with DioCancelableMixin
 
     // 并发执行两个请求
     var futures = [
-      _labourRepository.fetchLabourRequestList(
+      _UKlabourRepository.fetchLabourRequestList(
         state.keyword,
         DateTimeUtils.formatDate(state.selectedStartDate, format: "yyyy-MM-dd"),
         DateTimeUtils.formatDate(state.selectedEndDate, format: "yyyy-MM-dd"),
@@ -88,7 +96,7 @@ class LabourRequestListController extends GetxController with DioCancelableMixin
 
     //拿到结果
     var results = await Future.wait(futures);
-    var listResult = results[0] as HttpResult<LabourRequestListEntity>;
+    var listResult = results[0] as HttpResult<UkLabourRequestTableEntity>;
     var optionResult = results[1] as HttpResult<LabourRequestIndexEntity>;
 
     //选项数据
@@ -109,7 +117,7 @@ class LabourRequestListController extends GetxController with DioCancelableMixin
   }
 
   // 处理数据与展示的逻辑
-  void handleList(List<LabourRequestListRows>? list) {
+  void handleList(List<UkLabourRequestTableRows>? list) {
     if (list != null && list.isNotEmpty) {
       //有数据,判断是刷新还是加载更多的数据
       if (_curPage == 1) {
@@ -122,6 +130,7 @@ class LabourRequestListController extends GetxController with DioCancelableMixin
         changeLoadingState(LoadState.State_Success);
       } else {
         //加载更多
+
         state.datas.addAll(list);
         refreshController.finishLoad();
         update();
@@ -204,7 +213,7 @@ class LabourRequestListController extends GetxController with DioCancelableMixin
 
   /// 根据ID获取Item对象,用于刷新
   void fetchItemByIdAndRefreshItem(String requestId) async {
-    var result = await _labourRepository.fetchItemByRequestId(
+    var result = await _UKlabourRepository.fetchItemByRequestId(
       requestId,
       cancelToken: cancelToken,
     );
@@ -214,7 +223,6 @@ class LabourRequestListController extends GetxController with DioCancelableMixin
       var data = result.data;
       if (data != null && data.rows != null && data.rows!.isNotEmpty) {
         final requestItem = data.rows![0];
-
         //找到当前数据中的此 requestId,并替换对象,再刷新
         var index = state.datas.indexWhere((element) => element.requestId == requestItem.requestId);
         if (index >= 0) {
@@ -266,21 +274,96 @@ class LabourRequestListController extends GetxController with DioCancelableMixin
   }
 
   //去详情页面
-  void gotoDetailPage(LabourRequestListRows data) {
+  void gotoDetailPage(UkLabourRequestTableRows data) {
     UKLabourRequestAddPage.startInstance(2, data.requestId.toString());
   }
 
   //去编辑页面
-  void gotoEditPage(LabourRequestListRows data) {
+  void gotoEditPage(UkLabourRequestTableRows data) {
     UKLabourRequestAddPage.startInstance(1, data.requestId.toString());
   }
 
+  // 快速复制
+  void quickCopy(UkLabourRequestTableRows data, BuildContext context) {
+    final String dialogTime = 'Repeat ${data.jobTitle} ${data.jobDate} ${data.jobTime}';
+    DialogEngine.show(
+      tag: 'QuickCopyDialog',
+      widget: AppCustomDialog(
+        title: dialogTime,
+        titleSize: 15,
+        dialogWidth: 300,
+        message: "",
+        messageBuilder: (context){
+          return QuickCopyDialogWidget(
+            confirmAction: (startDate, endDate, copyDate){},
+            cancelAction: (startDate, endDate, copyDate){},
+          );
+        },
+        confirmAutoDismiss: false,
+        confirmAction: () {
+          final QuickCopyDialogWidgetController quickCopyDialogWidgetController = Get.find();
+          // 快速复制
+          String job_date = quickCopyDialogWidgetController.state.selectedDate == null ? "" : DateTimeUtils.formatDate(quickCopyDialogWidgetController.state.selectedDate, format: 'yyyy-MM-dd');
+          String start_time = quickCopyDialogWidgetController.state.selectedStartTime == null ? "" : DateTimeUtils.formatDate(quickCopyDialogWidgetController.state.selectedStartTime, format: 'HH:mm');
+          String end_time = quickCopyDialogWidgetController.state.selectedEndTime == null ? "" : DateTimeUtils.formatDate(quickCopyDialogWidgetController.state.selectedEndTime, format: 'HH:mm');
+          if(Utils.isEmpty(job_date)){
+            ToastEngine.show("Job Date Is Empty");
+            return;
+          }
+          if(Utils.isEmpty(start_time)){
+            ToastEngine.show("Start Time Is Empty");
+            return;
+          }
+          if(Utils.isEmpty(end_time)){
+            ToastEngine.show("End Time Is Empty");
+            return;
+          }
+          doQuickCopy(data.requestId.toString(), job_date, start_time, end_time,(){
+            // 刷新列表
+            refreshController.callRefresh();
+            SmartDialog.dismiss(tag: "QuickCopyDialog");
+          });
+        },
+      ));
+  }
+
+  void doQuickCopy(String requestId, String job_date, String start_time, String end_time, Function sCallbak) async {
+    Log.d("快速拷贝的 requestId, job_date, start_time, end_time---- ${requestId}, ${job_date}, ${start_time}, ${end_time}");
+    var result = await _UKlabourRepository.quickCopyLabourRequestSubmit(
+      requestId,
+      job_date,
+      start_time,
+      end_time,
+      cancelToken: cancelToken,
+    );
+
+    //处理数据
+    if (result.isSuccess) {
+      NotifyEngine.showSuccess("Successful".tr);
+      sCallbak?.call();
+    } else {
+      ToastEngine.show(result.errorMsg ?? "Network Load Error".tr);
+    }
+  }
+
+  // 去预选人列表页面
+  void gotoPreSelectedPage(UkLabourRequestTableRows data, BuildContext? context, bool publishStatus){
+    Log.d("当前得id是---- ${data.requestId}");
+    UKLabourRequestPreselectedListPage.startInstance(data.requestId.toString(), publishStatus);
+  }
+
+  //去新增页面Copy
+  void gotoCopyPage(UkLabourRequestTableRows data) {
+    UKLabourRequestAddPage.startInstance(0, data.requestId.toString());
+  }
+
   //去状态工作流的页面
-  void gotoWorkflowPage(LabourRequestListRows data) {
+  void gotoWorkflowPage(UkLabourRequestTableRows data) {
     UKLabourRequestWorkflowPage.startInstance(data.requestId.toString());
   }
 
-  void doRecall(LabourRequestListRows data) {
+
+  void doRecall(UkLabourRequestTableRows data) {
     DialogEngine.show(
         widget: AppDefaultDialog(
       title: "Message".tr,
@@ -291,5 +374,4 @@ class LabourRequestListController extends GetxController with DioCancelableMixin
     ));
   }
 
-
 }

+ 9 - 0
packages/cpt_uk/lib/modules/job/labour_request_list/labour_request_list_page.dart

@@ -150,6 +150,15 @@ class _LabourRequestListState extends BaseState<UKLabourRequestListPage, LabourR
                           onStatusAction: () {
                             controller.gotoWorkflowPage(state.datas[index]);
                           },
+                          onCopyAction: (){
+                            controller.gotoCopyPage(state.datas[index]);
+                          },
+                          onQuickCopyAction: (){
+                            controller.quickCopy(state.datas[index], context);
+                          },
+                          onPreSelectedClickAction:(){
+                            controller.gotoPreSelectedPage(state.datas[index], context,  state.datas[index].publishStatus!);
+                          }
                         );
                       },
                       childCount: state.datas.length,

+ 2 - 2
packages/cpt_uk/lib/modules/job/labour_request_list/labour_request_list_state.dart

@@ -1,5 +1,5 @@
 import 'package:domain/entity/response/labour_request_index_entity.dart';
-import 'package:domain/entity/response/labour_request_list_entity.dart';
+import 'package:domain/entity/response/uk_labour_request_table_entity.dart';
 import 'package:flutter/material.dart';
 
 class LabourRequestListState {
@@ -12,6 +12,6 @@ class LabourRequestListState {
   String? selectedDepartmentId;
 
   //页面的列表数据
-  List<LabourRequestListRows> datas = [];
+  List<UkLabourRequestTableRows> datas = [];
   LabourRequestIndexEntity? indexOptions;
 }

+ 227 - 0
packages/cpt_uk/lib/modules/job/labour_request_list/widget/quick_copy_dialog_widget.dart

@@ -0,0 +1,227 @@
+import 'dart:ui';
+
+import 'package:cpt_uk/modules/job/labour_request_list/widget/quick_copy_dialog_widget_controller.dart';
+import 'package:cs_resources/generated/assets.dart';
+import 'package:domain/entity/response/job_list_applied_staff_search_entity.dart';
+import 'package:flutter/cupertino.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter/widgets.dart';
+import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
+import 'package:get/get.dart';
+import 'package:shared/utils/date_time_utils.dart';
+import 'package:widgets/ext/ex_widget.dart';
+import 'package:cs_resources/constants/color_constants.dart';
+import 'package:widgets/load_state_layout.dart';
+import 'package:widgets/my_load_image.dart';
+import 'package:widgets/my_text_view.dart';
+import 'package:widgets/search_app_bar.dart';
+import 'package:widgets/shatter/form_require_text.dart';
+import 'package:widgets/widget_export.dart';
+
+
+/*
+ *  快速复制 labourequest 弹窗
+ */
+class QuickCopyDialogWidget extends StatefulWidget {
+  void Function(DateTime? pickedDate)? pickDateAction;
+  void Function(DateTime? pickedStartTime)? pickStartTimeAction;
+  void Function(DateTime? pickedEndTime)? pickEndTimeAction;
+  void Function(DateTime? pickedDate, DateTime? pickedStartTime, DateTime? pickedEndTime) confirmAction;
+  void Function(DateTime? pickedDate, DateTime? pickedStartTime, DateTime? pickedEndTime) cancelAction;
+
+
+  QuickCopyDialogWidget({
+      super.key,
+      this.pickDateAction,
+       this.pickStartTimeAction,
+       this.pickEndTimeAction,
+       required this.confirmAction,
+        required this.cancelAction,
+  });
+
+  @override
+  State<QuickCopyDialogWidget> createState() => _QuickCopyDialogWidget();
+}
+
+class _QuickCopyDialogWidget extends State<QuickCopyDialogWidget> {
+  @override
+  void initState() {
+    super.initState();
+    Get.put(QuickCopyDialogWidgetController());
+  }
+
+  @override
+  void dispose() {
+    super.dispose();
+    Get.delete<QuickCopyDialogWidgetController>();
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return GetBuilder<QuickCopyDialogWidgetController>(
+      assignId: true,
+      builder: (controller) {
+        return Padding(
+          padding: const EdgeInsets.only(left: 20, right: 20),
+          child: Column(
+            children: [
+              //开始时间
+              Row(
+                children: [
+                  Expanded(
+                    child: FormRequireText(
+                      text: "Job Date".tr,
+                        textColor: Colors.black,
+                    ),
+                  ),
+                ],
+              ),
+
+              //选择时间
+              Container(
+                padding: const EdgeInsets.only(left: 16, right: 10),
+                margin: const EdgeInsets.only(top: 10),
+                height: 45,
+                decoration: BoxDecoration(
+                  color: const Color(0xFF4DCFF6).withOpacity(0.2),
+                  borderRadius: const BorderRadius.all(Radius.circular(5)),
+                ),
+                child: Row(
+                  mainAxisSize: MainAxisSize.max,
+                  crossAxisAlignment: CrossAxisAlignment.center,
+                  mainAxisAlignment: MainAxisAlignment.start,
+                  children: [
+                    Expanded(
+                      child: MyTextView(
+                        controller.state.selectedDate == null ? "" : DateTimeUtils.formatDate(controller.state.selectedDate, format: 'yyyy-MM-dd'),
+                        fontSize: 14,
+                        hint: "Job Date".tr,
+                        textHintColor: ColorConstants.textGrayAECAE5,
+                        isFontMedium: true,
+                        textColor: ColorConstants.black33,
+                      ),
+                    ),
+                    //下拉选图标
+                    const Visibility(
+                      visible: true,
+                      child: MyAssetImage(Assets.baseServiceTriangleDropDownIcon, width: 11.5, height: 6.28),
+                    ),
+                  ],
+                ),
+              ).onTap(() {
+                FocusScope.of(context).unfocus();
+                controller.pickJobDate();
+              }),
+
+              const SizedBox(height: 10),
+
+              Row(
+                children: [
+                  Expanded(
+                    child: FormRequireText(
+                      text: "Job Time".tr,
+                      textColor: Colors.black,
+                    ),
+                  ),
+                ],
+              ),
+
+              Row(
+                children: [
+                  Expanded(
+                    child: Container(
+                      padding: const EdgeInsets.only(left: 16, right: 10),
+                      margin: const EdgeInsets.only(top: 10),
+                      height: 45,
+                      decoration: BoxDecoration(
+                        color: const Color(0xFF4DCFF6).withOpacity(0.2),
+                        borderRadius: const BorderRadius.all(Radius.circular(5)),
+                      ),
+                      child: Row(
+                        mainAxisSize: MainAxisSize.max,
+                        crossAxisAlignment: CrossAxisAlignment.center,
+                        mainAxisAlignment: MainAxisAlignment.start,
+                        children: [
+                          Expanded(
+                            child: MyTextView(
+                              controller.state.selectedStartTime == null ? "" : DateTimeUtils.formatDate(controller.state.selectedStartTime, format: 'HH:mm'),
+                              fontSize: 14,
+                              hint: "Start Time".tr,
+                              textHintColor: ColorConstants.textGrayAECAE5,
+                              isFontMedium: true,
+                              textColor: ColorConstants.black33,
+                            ),
+                          ),
+                          //下拉选图标
+                          const Visibility(
+                            visible: true,
+                            child: MyAssetImage(Assets.baseServiceTriangleDropDownIcon, width: 11.5, height: 6.28),
+                          ),
+                        ],
+                      ),
+                    ).onTap(() {
+                      FocusScope.of(context).unfocus();
+                      controller.pickStartTime();
+                    }),
+                  ),
+
+                  //分割线
+                  MyTextView(
+                    "-",
+                    textColor: Colors.white,
+                    marginLeft: 10,
+                    marginRight: 10,
+                    fontSize: 14,
+                    isFontRegular: true,
+                  ),
+
+                  //结束时间
+                  Expanded(
+                    child: Container(
+                      padding: const EdgeInsets.only(left: 16, right: 10),
+                      margin: const EdgeInsets.only(top: 10),
+                      height: 45,
+                      decoration: BoxDecoration(
+                        color: const Color(0xFF4DCFF6).withOpacity(0.2),
+                        borderRadius: const BorderRadius.all(Radius.circular(5)),
+                      ),
+                      child: Row(
+                        mainAxisSize: MainAxisSize.max,
+                        crossAxisAlignment: CrossAxisAlignment.center,
+                        mainAxisAlignment: MainAxisAlignment.start,
+                        children: [
+                          MyTextView(
+                            controller.state.selectedEndTime == null ? "" : DateTimeUtils.formatDate(controller.state.selectedEndTime, format: 'HH:mm'),
+                            fontSize: 14,
+                            hint: "End Time".tr,
+                            textHintColor: ColorConstants.textGrayAECAE5,
+                            isFontMedium: true,
+                            textColor: ColorConstants.black33,
+                          ).expanded(),
+                          //下拉选图标
+                          const Visibility(
+                            visible: true,
+                            child: MyAssetImage(Assets.baseServiceTriangleDropDownIcon, width: 11.5, height: 6.28),
+                          ),
+                        ],
+                      ),
+                    ).onTap(() {
+                      FocusScope.of(context).unfocus();
+                      controller.pickEndTime();
+                    }),
+                  ),
+                ],
+              ),
+              //选择时间
+            ],
+          ),
+        );
+      },
+    );
+  }
+
+  //取消弹框
+  void onCancel() async {
+    SmartDialog.dismiss();
+  }
+}

+ 128 - 0
packages/cpt_uk/lib/modules/job/labour_request_list/widget/quick_copy_dialog_widget_controller.dart

@@ -0,0 +1,128 @@
+import 'package:cpt_uk/modules/job/labour_request_list/widget/quick_copy_dialog_widget_state.dart';
+import 'package:domain/entity/response/labour_request_edit_index_entity.dart';
+import 'package:domain/repository/labour_repository.dart';
+import 'package:domain/repository/uk_job_repository.dart';
+import 'package:flutter/cupertino.dart';
+import 'package:get/get.dart';
+import 'package:plugin_basic/constants/app_constant.dart';
+import 'package:plugin_platform/engine/dialog/dialog_engine.dart';
+import 'package:plugin_platform/engine/notify/notify_engine.dart';
+import 'package:plugin_platform/engine/toast/toast_engine.dart';
+import 'package:plugin_platform/http/http_result.dart';
+import 'package:shared/utils/date_time_utils.dart';
+import 'package:shared/utils/event_bus.dart';
+import 'package:shared/utils/log_utils.dart';
+import 'package:shared/utils/util.dart';
+import 'package:widgets/picker/date_picker_util.dart';
+import 'package:widgets/picker/option_pick_util.dart';
+
+import '../../../../widget/date_range_picker_dialog.dart';
+
+class QuickCopyDialogWidgetController extends GetxController {
+  final LabourRepository _labourRepository = Get.find();
+  final UKJobRepository _ukJobRepository = Get.find();
+  final QuickCopyDialogWidgetState state = QuickCopyDialogWidgetState();
+
+
+  @override
+  void onReady() {
+    super.onReady();
+    // fetchRequestDetail();
+  }
+
+  /// 提交
+  void doSubmit() async {
+
+
+   if (state.selectedStartTime == null) {
+      ToastEngine.show("Choose Start Date".tr);
+      return;
+    } else if (state.selectedEndTime == null) {
+      ToastEngine.show("Choose End Date".tr);
+      return;
+    }
+
+    Future<HttpResult> taskFuture;
+    // if (state.pageType != 0 && Utils.isNotEmpty(state.appliedId) && state.appliedId != "0") {
+    //   taskFuture = _labourRepository.editLabourRequestSubmit(
+    //     state.appliedId,
+    //     state.selectedTemplateId,
+    //     "${DateTimeUtils.formatDate(state.selectedDate, format: 'yyyy-MM-dd')} ${DateTimeUtils.formatDate(state.selectedStartTime, format: 'HH:mm')}:00",
+    //     "${DateTimeUtils.formatDate(state.selectedDate, format: 'yyyy-MM-dd')} ${DateTimeUtils.formatDate(state.selectedEndTime, format: 'HH:mm')}:00",
+    //     state.selectedDepartmentId,
+    //     needNum,
+    //     'hour',
+    //     state.labReqOption?.serviceType == 1 ? amount : null,
+    //   );
+    // } else {
+    //   taskFuture = _ukJobRepository.addLabourRequestSubmit(
+    //     templateId: state.selectedTemplateId,
+    //     jobDate: DateTimeUtils.formatDate(state.selectedDate, format: 'yyyy-MM-dd'),
+    //     startTime: DateTimeUtils.formatDate(state.selectedStartTime, format: 'HH:mm'),
+    //     endTime: DateTimeUtils.formatDate(state.selectedEndTime, format: 'HH:mm'),
+    //     departmentId: state.selectedDepartmentId,
+    //     needNum: needNum,
+    //     salaryBy: 'hour',
+    //     repeatDate: state.repeatDateStr,
+    //     amount: state.labReqOption?.serviceType == 1 ? amount : null,
+    //   );
+    // }
+
+    // var result = await taskFuture;
+
+  }
+
+  //选择日期
+  void pickJobDate() {
+    DatePickerUtil.showCupertinoDatePicker(
+      selectedDateTime: state.selectedDate,
+      mode: CupertinoDatePickerMode.date,
+      onDateTimeChanged: (date) {
+        state.selectedDate = date;
+        update();
+      },
+      title: "Job Date".tr,
+    );
+  }
+
+  //选择开始时间
+  void pickStartTime() {
+
+    DatePickerUtil.showCupertinoDatePicker(
+      selectedDateTime: state.selectedStartTime,
+      mode: CupertinoDatePickerMode.time,
+      onDateTimeChanged: (date) {
+        state.selectedStartTime = date;
+        update();
+      },
+      title: "Start Time".tr,
+    );
+  }
+
+  // 选择结束时间
+  void pickEndTime() {
+
+    DatePickerUtil.showCupertinoDatePicker(
+      selectedDateTime: state.selectedEndTime ?? state.selectedStartTime,
+      mode: CupertinoDatePickerMode.time,
+      onDateTimeChanged: (date) {
+        state.selectedEndTime = date;
+        update();
+      },
+      title: "End Time".tr,
+    );
+  }
+
+  //选择时间段
+  void pickDateRange() {
+    DialogEngine.show(
+        widget: DateRangePickerDialog(
+          dateRange: state.repeatDateStr,
+          confirmAction: (dateStr) {
+            Log.d("选择的时间段:$dateStr");
+            state.repeatDateStr = dateStr;
+            update();
+          },
+        ));
+  }
+}

+ 14 - 0
packages/cpt_uk/lib/modules/job/labour_request_list/widget/quick_copy_dialog_widget_state.dart

@@ -0,0 +1,14 @@
+
+import 'package:domain/entity/response/uk_labour_request_table_entity.dart';
+
+
+class QuickCopyDialogWidgetState {
+  late final UkLabourRequestTableRows itemObj;
+
+  //页面对应的选择的条件
+  DateTime? selectedDate;
+  DateTime? selectedStartTime;
+  DateTime? selectedEndTime;
+  String? repeatDateStr;  //2025-06-28,2025-06-29,2025-06-30
+
+}

+ 243 - 0
packages/cpt_uk/lib/modules/job/labour_request_preselected_list/labour_request-preselected_item.dart

@@ -0,0 +1,243 @@
+import 'package:cs_resources/constants/color_constants.dart';
+import 'package:domain/entity/response/uk_labour_request_preselected_list_entity.dart';
+import 'package:domain/entity/response/uk_labour_request_table_entity.dart';
+import 'package:flutter/cupertino.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter/widgets.dart';
+import 'package:plugin_basic/basic_export.dart';
+import 'package:widgets/ext/ex_widget.dart';
+import 'package:widgets/my_button.dart';
+import 'package:widgets/my_load_image.dart';
+import 'package:widgets/my_text_view.dart';
+
+/*
+ * preselected 主页面列表Item
+ */
+class LabourRequestPreselectedItem extends StatelessWidget {
+  final int index;
+  final UkLabourRequestPreselectedListRows item;
+  bool publishStatus = true;  // true 不显示 delete 按钮
+  final VoidCallback? onDeleteAction;
+
+  LabourRequestPreselectedItem({
+    required this.index,
+    required this.item,
+    this.publishStatus = true,
+    this.onDeleteAction,
+  });
+
+  @override
+  Widget build(BuildContext context) {
+    return Container(
+      padding: const EdgeInsets.symmetric(vertical: 23, horizontal: 21),
+      margin: const EdgeInsets.only(left: 15, right: 15, top: 5, bottom: 5),
+      decoration: BoxDecoration(
+        color: const Color(0xFF4DCFF6).withOpacity(0.2), // 设置背景颜色和不透明度
+        borderRadius: BorderRadius.circular(5), // 设置圆角
+      ),
+      child: Column(
+        mainAxisSize: MainAxisSize.max,
+        crossAxisAlignment: CrossAxisAlignment.start,
+        children: [
+          //工作标题
+          MyTextView(
+            item.name ?? "-",
+            isFontMedium: true,
+            textColor: ColorConstants.textYellowFFBB1B,
+            fontSize: 14,
+            // textDecoration: TextDecoration.underline,
+            // decorationColor: ColorConstants.textYellowFFBB1B,
+            // // 可选,设置下划线的颜色
+            // decorationThickness: 2.0,
+            // // 可选,设置下划线的粗细
+            // decorationStyle: TextDecorationStyle.solid, // 可选,设置下划线的样式
+          ),
+
+          // Name
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "Name:".tr,
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+
+              MyTextView(
+                item.name ?? "-",
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor: Colors.white,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ).marginOnly(top: 15),
+
+          // gender 、  idcard
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              Expanded(
+                  flex: 1,
+                  child:
+                  Row(
+                    children: [
+                      MyTextView(
+                        "Gender:".tr,
+                        isFontRegular: true,
+                        textColor: ColorConstants.textGrayAECAE5,
+                        fontSize: 14,
+                      ),
+                      //人数
+                      MyTextView(
+                        item.sex?? "-",
+                        marginLeft: 5,
+                        isFontRegular: true,
+                        textColor: Colors.white,
+                        fontSize: 14,
+                      ),
+                    ],
+                  )
+              ),
+
+              // id card
+              Expanded(
+                child: Row(
+                    mainAxisAlignment: MainAxisAlignment.start,
+                    crossAxisAlignment: CrossAxisAlignment.center,
+                    children: [
+                      MyTextView(
+                        "ID Card No.:".tr,
+                        isFontRegular: true,
+                        textColor: ColorConstants.textGrayAECAE5,
+                        fontSize: 14,
+                      ),
+
+                      //薪水
+                      MyTextView(
+                        item.nric?? "-",
+                        marginLeft: 5,
+                        isFontRegular: true,
+                        textColor: Colors.white,
+                        fontSize: 14,
+                      ),
+                    ]
+                ),
+              )
+            ],
+          ).marginOnly(top: 15),
+
+          // avatar Status
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+
+              Expanded(
+                  flex: 1,
+                  child: (
+                      Row(
+                        children: [
+                          MyTextView(
+                            "Avatar:".tr,
+                            isFontRegular: true,
+                            textColor: ColorConstants.textGrayAECAE5,
+                            fontSize: 14,
+                          ),
+                          // 头像
+                          MyLoadImage(
+                            item.avatar??'-',
+                            width: 40,
+                            height: 40,
+                          ),
+                        ],
+                      )
+                  )
+              ),
+
+              // Status
+              Expanded(
+                flex: 1,
+                child: Row(
+                    mainAxisAlignment: MainAxisAlignment.start,
+                    crossAxisAlignment: CrossAxisAlignment.center,
+                    children: [
+                      MyTextView(
+                        "Status:".tr,
+                        isFontRegular: true,
+                        textColor: ColorConstants.textGrayAECAE5,
+                        fontSize: 14,
+                      ),
+
+                      MyTextView(
+                        item.statusShow ?? "-",
+                        marginLeft: 5,
+                        isFontRegular: true,
+                        textColor: "Approved" == item.statusShow
+                            ? ColorConstants.textGreen05DC82
+                            : "Rejected" == item.statusShow
+                            ? ColorConstants.textRedFF6262
+                            : "Recall" == item.statusShow
+                            ? ColorConstants.textYellowFFBB1B
+                            : ColorConstants.textBlue06D9FF,
+                        fontSize: 14,
+                      ),
+                    ]
+                ),
+              )
+            ],
+          ).marginOnly(top: 15),
+
+          // message
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "Message:".tr,
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+
+              MyTextView(
+                item.message ?? "-",
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor: Colors.white,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ).marginOnly(top: 15),
+
+          //按钮
+          Visibility(
+            visible: !publishStatus,
+            child: Row(
+              mainAxisSize: MainAxisSize.max,
+              mainAxisAlignment: MainAxisAlignment.end,
+              crossAxisAlignment: CrossAxisAlignment.center,
+              children: [
+                //删除按钮
+                MyButton(
+                  onPressed: () {
+                    onDeleteAction?.call();
+                  },
+                  text: "Delete".tr,
+                  textColor: ColorConstants.white,
+                  backgroundColor: Colors.redAccent,
+                  radius: 17.25,
+                  minWidth: 60,
+                  minHeight: 35,
+                ).marginOnly(left: 12),
+              ],
+            ).marginOnly(top: 18, bottom: 2),
+          ),
+        ],
+      ),
+    );
+  }
+}

+ 264 - 0
packages/cpt_uk/lib/modules/job/labour_request_preselected_list/labour_request_preselected_list_controller.dart

@@ -0,0 +1,264 @@
+import 'package:cpt_uk/modules/job/labour_request_list/widget/quick_copy_dialog_widget.dart';
+import 'package:cpt_uk/modules/job/labour_request_list/widget/quick_copy_dialog_widget_controller.dart';
+import 'package:cpt_uk/modules/job/labour_request_preselected_list/widget/preselected_add_staff.dart';
+import 'package:cpt_uk/modules/job/labour_request_workflow/labour_request_workflow_page.dart';
+import 'package:domain/entity/response/labour_request_index_entity.dart';
+import 'package:domain/entity/response/uk_labour_request_preselected_list_entity.dart';
+import 'package:domain/entity/response/uk_labour_request_table_entity.dart';
+import 'package:domain/repository/uk_labour_repository.dart';
+import 'package:flutter/cupertino.dart';
+import 'package:get/get.dart';
+import 'package:plugin_basic/constants/app_constant.dart';
+import 'package:plugin_platform/engine/dialog/dialog_engine.dart';
+import 'package:plugin_platform/engine/notify/notify_engine.dart';
+import 'package:plugin_platform/engine/toast/toast_engine.dart';
+import 'package:plugin_platform/http/dio/dio_cancelable_mixin.dart';
+import 'package:plugin_platform/http/http_result.dart';
+import 'package:shared/utils/date_time_utils.dart';
+import 'package:shared/utils/event_bus.dart';
+import 'package:shared/utils/log_utils.dart';
+import 'package:shared/utils/util.dart';
+import 'package:widgets/dialog/app_default_dialog.dart';
+import 'package:widgets/load_state_layout.dart';
+import 'package:widgets/widget_export.dart';
+import 'package:widgets/dialog/app_custom_dialog.dart';
+
+import '../labour_request_add/labour_request_add_page.dart';
+import 'labour_request_preselected_list_state.dart';
+
+
+class UKLabourRequestPreselectedListController extends GetxController with DioCancelableMixin {
+  final UkLabourRepository _ukLabourRepository = Get.find();
+  final LabourRequestPreselectedListState state = LabourRequestPreselectedListState();
+
+  var _curPage = 1;
+  var _needShowPlaceholder = true;
+
+  //页面PlaceHolder的展示
+  LoadState loadingState = LoadState.State_Success;
+  String? errorMessage;
+
+  //刷新页面状态
+  void changeLoadingState(LoadState state) {
+    loadingState = state;
+    update();
+  }
+
+  // Refresh 控制器
+  final EasyRefreshController refreshController = EasyRefreshController(
+    controlFinishRefresh: true,
+    controlFinishLoad: true,
+  );
+
+  // Refresh 刷新事件
+  Future onRefresh() async {
+    _curPage = 1;
+    fetchLabourRequestList();
+  }
+
+  // Refresh 加载事件
+  Future loadMore() async {
+    _curPage++;
+    fetchLabourRequestList();
+  }
+
+  // 重试请求
+  Future retryRequest() async {
+    _curPage = 1;
+    _needShowPlaceholder = true;
+    fetchLabourRequestList();
+  }
+
+  /// 获取列表数据
+  Future fetchLabourRequestList() async {
+    if (_needShowPlaceholder) {
+      changeLoadingState(LoadState.State_Loading);
+    }
+
+    // 并发执行两个请求
+    var futures = [
+      _ukLabourRepository.fetchLabourRequestPreselectedList(
+        state.labourRequestId,
+        curPage: _curPage,
+        cancelToken: cancelToken,
+      ),
+    ];
+
+    //拿到结果
+    var results = await Future.wait(futures);
+    var listResult = results[0] as HttpResult<UkLabourRequestPreselectedListEntity>;
+
+
+    // 处理数据
+    if (listResult.isSuccess) {
+      handleList(listResult.data?.rows);
+    } else {
+      errorMessage = listResult.errorMsg;
+      changeLoadingState(LoadState.State_Error);
+    }
+
+    // 最后赋值
+    _needShowPlaceholder = false;
+  }
+
+  // 处理数据与展示的逻辑
+  void handleList(List<UkLabourRequestPreselectedListRows>? list) {
+    if (list != null && list.isNotEmpty) {
+      //有数据,判断是刷新还是加载更多的数据
+      if (_curPage == 1) {
+        //刷新的方式
+        state.datas.clear();
+        state.datas.addAll(list);
+        refreshController.finishRefresh();
+
+        //更新展示的状态
+        changeLoadingState(LoadState.State_Success);
+      } else {
+        //加载更多
+        state.datas.addAll(list);
+        refreshController.finishLoad();
+        update();
+      }
+    } else {
+      if (_curPage == 1) {
+        //展示无数据的布局
+        state.datas.clear();
+        changeLoadingState(LoadState.State_Empty);
+        refreshController.finishRefresh();
+      } else {
+        //展示加载完成,没有更多数据了
+        refreshController.finishLoad(IndicatorResult.noMore);
+      }
+    }
+  }
+
+  // 执行搜索
+  void doSearch(String keyword) {
+    //赋值之后刷新
+    refreshController.callRefresh();
+  }
+
+  // 清空搜索条件
+  void resetFiltering() {
+    //赋值之后刷新
+    refreshController.callRefresh();
+  }
+
+  //展示筛选的弹窗
+  void showFilterDialog() {
+
+  }
+
+  @override
+  void onReady() {
+    super.onReady();
+    fetchLabourRequestList();
+
+    registerEventBus();
+  }
+
+  @override
+  void onClose() {
+    unregisterEventBus();
+    state.datas.clear();
+    super.onClose();
+  }
+
+  // EventBus 的事件接收
+  Subscription? subscribe;
+
+  void registerEventBus() {
+    // subscribe = bus.on(AppConstant.eventLabourRequestRefresh, (arg) {
+    //   var requestId = arg as String;
+    //   if (Utils.isNotEmpty(requestId)) {
+    //
+    //   } else {
+    //     refreshController.callRefresh();
+    //   }
+    // });
+  }
+
+  void unregisterEventBus() {
+    // bus.off(AppConstant.eventLabourRequestRefresh, subscribe);
+  }
+
+  // 添加员工
+  showAddStaffDialog(){
+    DialogEngine.show(
+      widget: PreselectedAddStaff(
+        jobId: state.labourRequestId!,
+        confirmAction: (selectedIds, [selectedList]) {
+          //调用接口添加员工
+          _doPreselectedAddStaffSubmit(selectedIds);
+        },
+      ),
+    );
+  }
+
+  //调用接口添加员工
+  void _doPreselectedAddStaffSubmit(String selectedIds) async {
+    var result = await _ukLabourRepository.labourRequestPreselectedAddStaffSubmit(
+        state.labourRequestId,
+        selectedIds,
+        cancelToken: cancelToken
+    );
+
+    if (result.isSuccess) {
+      var addStaffEntity = result.data;
+      List<String> filteredMessages = [];
+      if (addStaffEntity != null && addStaffEntity.resultList?.isNotEmpty == true) {
+        filteredMessages = addStaffEntity.resultList!
+            .where((resultList) => resultList.result == false && Utils.isNotEmpty(resultList.msg))
+            .map((resultList) => '${resultList.name} : ${resultList.msg!}')
+            .toList();
+      }
+
+      if (filteredMessages.isNotEmpty) {
+        //有错误信息
+        NotifyEngine.showFailure(filteredMessages.join(" , "));
+      } else {
+        //无错误信息
+        NotifyEngine.showSuccess("Successful".tr);
+        //添加成功之后刷新页面
+        refreshController.callRefresh();
+      }
+    } else {
+      ToastEngine.show(result.errorMsg ?? "Network Load Error".tr);
+      return;
+    }
+  }
+
+  void deletePreselectedStaff(UkLabourRequestPreselectedListRows data, BuildContext? context) {
+    DialogEngine.show(
+      widget: AppDefaultDialog(
+        title: "Message".tr,
+        message: "Are you sure you want to delete this staff?".tr,
+        confirmAction: () {
+          doDeleteStaff(data, context);
+        },
+      ));
+  }
+
+  void doDeleteStaff(UkLabourRequestPreselectedListRows data, BuildContext? context) async {
+      final result = await _ukLabourRepository.labourRequestPreselectedDelete(
+        data.id.toString(),
+        cancelToken: cancelToken,
+      );
+
+      if (result.isSuccess) {
+        NotifyEngine.showSuccess("Successful".tr);
+
+        if (state.datas.length <= 1) {
+          refreshController.callRefresh();
+        } else {
+          // 找到对应id 删除
+          state.datas.removeWhere((item)=> item.id == data.id);
+          update();
+        }
+      } else {
+        ToastEngine.show(result.errorMsg ?? "Network Load Error".tr);
+      }
+
+  }
+
+}

+ 139 - 0
packages/cpt_uk/lib/modules/job/labour_request_preselected_list/labour_request_preselected_list_page.dart

@@ -0,0 +1,139 @@
+import 'package:cs_resources/constants/color_constants.dart';
+import 'package:flutter/material.dart';
+import 'package:get/get.dart';
+import 'package:plugin_basic/base/base_state.dart';
+import 'package:plugin_basic/base/base_stateful_page.dart';
+import 'package:plugin_basic/utils/ext_get_nav.dart';
+import 'package:router/path/router_path.dart';
+import 'package:shared/utils/log_utils.dart';
+import 'package:shared/utils/screen_util.dart';
+import 'package:widgets/ext/ex_widget.dart';
+import 'package:widgets/load_state_layout.dart';
+import 'package:widgets/my_appbar.dart';
+import 'package:widgets/my_button.dart';
+import 'package:widgets/my_load_image.dart';
+import 'package:widgets/widget_export.dart';
+
+import 'labour_request-preselected_item.dart';
+import 'labour_request_preselected_list_controller.dart';
+import 'labour_request_preselected_list_state.dart';
+
+
+/*
+ * preselected 的主页列表
+ */
+class UKLabourRequestPreselectedListPage extends BaseStatefulPage<UKLabourRequestPreselectedListController> {
+  UKLabourRequestPreselectedListPage({Key? key}) : super(key: key);
+
+  //启动当前页面
+  static void startInstance(String? labourRequestId, bool publishStatus) {
+    return Get.start(RouterPath.UKLabourPreselectedList,  arguments: {'labourRequestId': labourRequestId,'publishStatus':publishStatus});
+  }
+
+  @override
+  UKLabourRequestPreselectedListController createRawController() {
+    return UKLabourRequestPreselectedListController();
+  }
+
+  @override
+  State<UKLabourRequestPreselectedListPage> createState() => _LabourRequestPreselectedListState();
+}
+
+class _LabourRequestPreselectedListState extends BaseState<UKLabourRequestPreselectedListPage, UKLabourRequestPreselectedListController> {
+  late LabourRequestPreselectedListState state;
+
+  @override
+  void initState() {
+    super.initState();
+    state = controller.state;
+    state.labourRequestId = Get.arguments['labourRequestId'];
+    state.publishStatus = Get.arguments['publishStatus'];
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    // Log.d("${state.publishStatus}");
+    return autoCtlGetBuilder(builder: (controller) {
+      return SafeArea(
+        bottom: MediaQuery.of(context).padding.bottom > 38,
+        top: false,
+        child: Container(
+          width: double.infinity,
+          height: double.infinity,
+          padding: EdgeInsets.only(top: ScreenUtil.getStatusBarH(context)),
+          decoration: const BoxDecoration(
+            gradient: LinearGradient(
+              colors: [
+                Color(0xFF091D44),
+                Color(0xFF245A8A),
+                Color(0xFF7F7CEC),
+              ],
+              begin: Alignment.topCenter,
+              end: Alignment.bottomCenter,
+            ),
+          ),
+          child: Column(
+            mainAxisSize: MainAxisSize.max,
+            children: [
+              MyAppBar.titleBar(
+                context,
+                'Pre Selected'.tr,
+                actions: [],
+              ),
+              // 添加按钮
+              Visibility(
+                visible: !state.publishStatus,
+                child: MyButton(
+                  type: ClickType.throttle,
+                  milliseconds: 500,
+                  onPressed: () {
+                    FocusScope.of(context).unfocus();
+                    controller.showAddStaffDialog();
+                  },
+                  text: "Add Staff".tr,
+                  textColor: ColorConstants.white,
+                  fontSize: 16,
+                  radius: 20,
+                  backgroundColor: hexToColor("#FFBB1B"),
+                  fontWeight: FontWeight.w500,
+                ).marginSymmetric(horizontal: 15, vertical: 15),
+              ),
+
+              //底部的列表
+              Expanded(
+                child: EasyRefresh(
+                  controller: controller.refreshController,
+                  onRefresh: controller.onRefresh,
+                  onLoad: controller.loadMore,
+                  child: LoadStateLayout(
+                    state: controller.loadingState,
+                    errorMessage: controller.errorMessage,
+                    errorRetry: () {
+                      controller.retryRequest();
+                    },
+                    successSliverWidget: [
+                      SliverList(
+                          delegate: SliverChildBuilderDelegate(
+                                (context, index) {
+                              return LabourRequestPreselectedItem(
+                                  index: index,
+                                  item: state.datas[index],
+                                  publishStatus: state.publishStatus,
+                                  onDeleteAction:(){
+                                    controller.deletePreselectedStaff(state.datas[index], context);
+                                  }
+                              );
+                            },
+                            childCount: state.datas.length,
+                          ))
+                    ],
+                  ),
+                ),
+              ),
+            ],
+          ),
+        ),
+      );
+    });
+  }
+}

+ 10 - 0
packages/cpt_uk/lib/modules/job/labour_request_preselected_list/labour_request_preselected_list_state.dart

@@ -0,0 +1,10 @@
+
+import 'package:domain/entity/response/uk_labour_request_preselected_list_entity.dart';
+
+class  LabourRequestPreselectedListState {
+  String labourRequestId = "";
+  bool publishStatus = false;
+
+  //页面的列表数据
+  List<UkLabourRequestPreselectedListRows> datas = [];
+}

+ 358 - 0
packages/cpt_uk/lib/modules/job/labour_request_preselected_list/widget/preselected_add_staff.dart

@@ -0,0 +1,358 @@
+import 'dart:ui';
+
+import 'package:cs_resources/generated/assets.dart';
+import 'package:domain/entity/response/job_list_applied_staff_search_entity.dart';
+import 'package:domain/entity/response/uk_labour_request_preselect_addstatff_list_entity.dart';
+import 'package:flutter/cupertino.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter/widgets.dart';
+import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
+import 'package:get/get.dart';
+import 'package:widgets/ext/ex_widget.dart';
+import 'package:cs_resources/constants/color_constants.dart';
+import 'package:widgets/load_state_layout.dart';
+import 'package:widgets/my_load_image.dart';
+import 'package:widgets/my_text_view.dart';
+import 'package:widgets/search_app_bar.dart';
+import 'package:widgets/widget_export.dart';
+
+import 'preselected_add_staff_controller.dart';
+
+/*
+ * 添加员工的弹窗
+ */
+class PreselectedAddStaff extends StatefulWidget {
+  String jobId;
+  String? selectedStaffIds;
+  void Function(String selectIds, [List<UkLabourRequestPreselectAddstatffListRows>?])? confirmAction;
+
+  PreselectedAddStaff({required this.jobId, this.selectedStaffIds, this.confirmAction});
+
+  @override
+  State<PreselectedAddStaff> createState() => _PreselectedAddStaffState();
+}
+
+class _PreselectedAddStaffState extends State<PreselectedAddStaff> {
+  @override
+  void initState() {
+    super.initState();
+    Get.put(PreselectedAddStaffController());
+  }
+
+  @override
+  void dispose() {
+    super.dispose();
+    Get.delete<PreselectedAddStaffController>();
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return GetBuilder<PreselectedAddStaffController>(
+      assignId: true,
+      builder: (controller) {
+        return Container(
+          width: 300,
+          height: 555,
+          decoration: const BoxDecoration(
+            color: Color(0XFFF7F7F7),
+            borderRadius: BorderRadius.all(Radius.circular(15)),
+          ),
+          child: Column(
+            crossAxisAlignment: CrossAxisAlignment.start,
+            children: [
+              Center(
+                child: MyTextView(
+                  "Choose Staff".tr,
+                  fontSize: 19,
+                  isFontMedium: true,
+                  textColor: ColorConstants.black,
+                  marginTop: 22,
+                  marginBottom: 15,
+                  marginLeft: 22,
+                  marginRight: 22,
+                ),
+              ),
+
+              SearchAppBar(
+                value: controller.keyword,
+                searchBarHeight: 38,
+                searchBarBgColor: Colors.white,
+                searchBarBorderRadius: 15,
+                searchBarBorder: Border.all(
+                  color: Color(0XFFC3C3C3), // 设置边框颜色为灰色
+                  width: 0.5, // 设置边框宽度
+                ),
+                textHintColor: Color(0XFFAFB3B7),
+                textColor: ColorConstants.black33,
+                onSearch: (keyword) {
+                  controller.doSearch(keyword);
+                },
+                hintText: "Staff Name/ID/Phone".tr,
+                controller: controller.searchController,
+              ).marginOnly(left: 16.5, right: 1.5, bottom: 15.5),
+
+              Container(
+                color: Colors.white,
+                child: EasyRefresh(
+                  header: ClassicHeader(
+                    dragText: 'Pull to refresh'.tr,
+                    armedText: 'Release ready'.tr,
+                    readyText: 'Refreshing...'.tr,
+                    processingText: 'Refreshing...'.tr,
+                    processedText: 'Succeeded'.tr,
+                    noMoreText: 'No more'.tr,
+                    failedText: 'Failed'.tr,
+                    messageText: 'Last updated at %T'.tr,
+                    textStyle: const TextStyle(color: ColorConstants.black66, fontSize: 14),
+                    messageStyle: const TextStyle(color: ColorConstants.black66, fontSize: 12),
+                    iconTheme: const IconThemeData(color: ColorConstants.black66),
+                    backgroundColor: Colors.transparent,
+                  ),
+                  footer: ClassicFooter(
+                    dragText: 'Pull to load'.tr,
+                    armedText: 'Release ready'.tr,
+                    readyText: 'Loading...'.tr,
+                    processingText: 'Loading...'.tr,
+                    processedText: 'Succeeded'.tr,
+                    noMoreText: 'No more'.tr,
+                    failedText: 'Failed'.tr,
+                    showMessage: false,
+                    triggerOffset: 50,
+                    iconDimension: 22,
+                    textStyle: const TextStyle(color: ColorConstants.black66, fontSize: 14),
+                    messageStyle: const TextStyle(color: ColorConstants.black66, fontSize: 12),
+                    iconTheme: const IconThemeData(color: ColorConstants.black66),
+                    backgroundColor: Colors.transparent,
+                  ),
+                  controller: controller.refreshController,
+                  onRefresh: controller.onRefresh,
+                  onLoad: controller.loadMore,
+                  child: LoadStateLayout(
+                    themeColor: ColorConstants.black66,
+                    state: controller.loadingState,
+                    errorMessage: controller.errorMessage,
+                    errorRetry: () {
+                      controller.retryRequest();
+                    },
+                    successSliverWidget: [
+                      SliverList(
+                          delegate: SliverChildBuilderDelegate(
+                                (context, index) {
+                              return _buildStaffItem(controller.datas[index], () {
+                                /// Item选中与未选中设置
+                                controller.datas[index].isSelected = !controller.datas[index].isSelected;
+                                controller.update();
+                              });
+                            },
+                            childCount: controller.datas.length,
+                          ))
+                    ],
+                  ),
+                ),
+              ).expanded(),
+
+              //按钮组
+              Row(
+                children: [
+                  //取消按钮
+                  Expanded(
+                      flex: 1,
+                      child: InkWell(
+                        onTap: () {
+                          onCancel();
+                        },
+                        child: MyTextView(
+                          "Cancel".tr,
+                          fontSize: 17.5,
+                          isFontMedium: true,
+                          textAlign: TextAlign.center,
+                          textColor: Color(0XFF0085C4),
+                          cornerRadius: 3,
+                          borderWidth: 1,
+                        ),
+                      )),
+
+                  //垂直分割线
+                  Container(
+                    color: Color(0xff09141F).withOpacity(0.13),
+                    width: 0.5,
+                  ),
+
+                  //同意按钮
+                  Expanded(
+                      flex: 1,
+                      child: InkWell(
+                        onTap: () {
+                          doCallbackAction(controller);
+                        },
+                        child: MyTextView(
+                          "Submit".tr,
+                          marginLeft: 10,
+                          fontSize: 17.5,
+                          isFontMedium: true,
+                          textAlign: TextAlign.center,
+                          textColor: Color(0XFF0085C4),
+                          cornerRadius: 3,
+                        ),
+                      )),
+                ],
+              ).constrained(height: 46),
+            ],
+          ),
+        );
+      },
+    );
+  }
+
+  //取消弹框
+  void onCancel() async {
+    SmartDialog.dismiss();
+  }
+
+  //执行回调
+  void doCallbackAction(PreselectedAddStaffController controller) {
+    onCancel();
+
+    //找到当前选中的
+    var selectedList = controller.datas.where((element) => element.isSelected).toList(growable: false);
+    if (selectedList.isNotEmpty) {
+      var ids = selectedList.map((e) => e.id.toString()).toList(growable: false);
+      String separatedIds = ids.join(',');
+
+      widget.confirmAction?.call(separatedIds, selectedList);
+    }
+
+  }
+
+  Widget _buildStaffItem(UkLabourRequestPreselectAddstatffListRows item, VoidCallback callback) {
+    return Stack(
+      children: [
+        Column(
+          children: [
+            //姓名
+            Row(
+              children: [
+                MyTextView(
+                  "Name:".tr,
+                  textColor: ColorConstants.black66,
+                  fontSize: 13,
+                  marginRight: 3,
+                  isFontRegular: true,
+                ),
+                MyTextView(
+                  item.name ?? "-",
+                  textColor: ColorConstants.black66,
+                  fontSize: 13,
+                  isFontRegular: true,
+                ),
+              ],
+            ),
+
+            //头像
+            Row(
+              children: [
+                MyTextView(
+                  "Avatar:".tr,
+                  textColor: ColorConstants.black66,
+                  fontSize: 13,
+                  marginRight: 3,
+                  isFontRegular: true,
+                ),
+                MyLoadImage(
+                  item.profilePicture ?? "",
+                  width: 25,
+                  height: 25,
+                ),
+              ],
+            ).marginOnly(top: 5),
+
+            //性别
+            Row(
+              children: [
+                MyTextView(
+                  "Gender:".tr,
+                  marginRight: 3,
+                  textColor: ColorConstants.black66,
+                  fontSize: 13,
+                  isFontRegular: true,
+                ),
+                MyTextView(
+                  item.gender ?? "-",
+                  textColor: ColorConstants.black66,
+                  fontSize: 13,
+                  isFontRegular: true,
+                ),
+              ],
+            ).marginOnly(top: 5),
+
+            //身份证
+            Row(
+              children: [
+                MyTextView(
+                  "ID Card No.:".tr,
+                  marginRight: 3,
+                  textColor: ColorConstants.black66,
+                  fontSize: 13,
+                  isFontRegular: true,
+                ),
+                MyTextView(
+                  item.nric ?? "-",
+                  textColor: ColorConstants.black66,
+                  fontSize: 13,
+                  isFontRegular: true,
+                ),
+              ],
+            ).marginOnly(top: 5),
+
+            //status
+            Row(
+                mainAxisAlignment: MainAxisAlignment.start,
+                crossAxisAlignment: CrossAxisAlignment.center,
+                children: [
+                  MyTextView(
+                    "Status:".tr,
+                    isFontRegular: true,
+                    textColor: ColorConstants.black66,
+                    fontSize: 14,
+                  ),
+
+                  MyTextView(
+                    _getStatusText(item.status),
+                    marginLeft: 5,
+                    isFontRegular: true,
+                    textColor: ColorConstants.black66,
+                    fontSize: 14,
+                  ),
+                ]
+            ).marginOnly(top: 5),
+
+            Container(
+              margin: EdgeInsets.only(top: 19),
+              width: double.infinity,
+              height: 1,
+              color: Color(0XFFF7F7F7),
+            )
+          ],
+        ).paddingOnly(left: 19, right: 20, top: 17),
+
+        //是否勾选
+        MyAssetImage(
+          item.isSelected ? Assets.baseServiceItemSelectedIcon : Assets.baseServiceItemUnselectedGrayIcon,
+          width: 20.5,
+          height: 20.5,
+        ).alignRight().marginOnly(right: 20, top: 17.5),
+      ],
+    ).onTap((){
+      callback?.call();
+    });
+  }
+
+  String _getStatusText(int? status){
+    switch(status){
+      case 1:
+        return "Active".tr;
+      default:
+        return "-";
+    }
+  }
+}

+ 136 - 0
packages/cpt_uk/lib/modules/job/labour_request_preselected_list/widget/preselected_add_staff_controller.dart

@@ -0,0 +1,136 @@
+import 'package:domain/entity/response/job_list_applied_staff_search_entity.dart';
+import 'package:domain/entity/response/uk_labour_request_preselect_addstatff_list_entity.dart';
+import 'package:domain/repository/job_repository.dart';
+import 'package:domain/repository/uk_labour_repository.dart';
+import 'package:flutter/material.dart';
+import 'package:plugin_basic/basic_export.dart';
+import 'package:plugin_platform/http/dio/dio_cancelable_mixin.dart';
+import 'package:shared/utils/log_utils.dart';
+import 'package:widgets/load_state_layout.dart';
+import 'package:widgets/widget_export.dart';
+
+/*
+ * 添加员工的弹窗的控制器
+ */
+class PreselectedAddStaffController extends GetxController with DioCancelableMixin {
+  final UkLabourRepository _labourRepository = Get.find();
+
+  TextEditingController searchController = TextEditingController();
+
+  var _curPage = 1;
+  var _needShowPlaceholder = true;
+
+  //页面PlaceHolder的展示
+  LoadState loadingState = LoadState.State_Success;
+  String? errorMessage;
+
+  String keyword = "";
+  String? jobId = null;
+  List<UkLabourRequestPreselectAddstatffListRows> datas = [];
+
+  //刷新页面状态
+  void changeLoadingState(LoadState state) {
+    loadingState = state;
+    update();
+  }
+
+  // Refresh 控制器
+  final EasyRefreshController refreshController = EasyRefreshController(
+    controlFinishRefresh: true,
+    controlFinishLoad: true,
+  );
+
+  // Refresh 刷新事件
+  Future onRefresh() async {
+    _curPage = 1;
+    fetchAllStaffList();
+  }
+
+  // Refresh 加载事件
+  Future loadMore() async {
+    _curPage++;
+    fetchAllStaffList();
+  }
+
+  // 重试请求
+  Future retryRequest() async {
+    _curPage = 1;
+    _needShowPlaceholder = true;
+    fetchAllStaffList();
+  }
+
+  /// 获取列表数据
+  Future fetchAllStaffList() async {
+    if (_needShowPlaceholder) {
+      changeLoadingState(LoadState.State_Loading);
+    }
+
+    // 获取 Staff 列表
+    var listResult = await _labourRepository.fetchtPreselectedAddStaffList(
+      keyword,
+      jobId,
+      curPage: _curPage,
+      cancelToken: cancelToken,
+    );
+
+    // 处理数据
+    if (listResult.isSuccess) {
+      handleList(listResult.data?.rows);
+    } else {
+      errorMessage = listResult.errorMsg;
+      changeLoadingState(LoadState.State_Error);
+    }
+
+    // 最后赋值
+    _needShowPlaceholder = false;
+  }
+
+  // 处理数据与展示的逻辑
+  void handleList(List<UkLabourRequestPreselectAddstatffListRows>? list) {
+    if (list != null && list.isNotEmpty) {
+      //有数据,判断是刷新还是加载更多的数据
+      if (_curPage == 1) {
+        //刷新的方式
+        datas.clear();
+        datas.addAll(list);
+        refreshController.finishRefresh();
+
+        //更新展示的状态
+        changeLoadingState(LoadState.State_Success);
+      } else {
+        //加载更多
+        datas.addAll(list);
+        refreshController.finishLoad();
+        update();
+      }
+    } else {
+      if (_curPage == 1) {
+        //展示无数据的布局
+        datas.clear();
+        changeLoadingState(LoadState.State_Empty);
+        refreshController.finishRefresh();
+      } else {
+        //展示加载完成,没有更多数据了
+        refreshController.finishLoad(IndicatorResult.noMore);
+      }
+    }
+  }
+
+  //搜索
+  void doSearch(String keyword) {
+    this.keyword = keyword;
+    refreshController.callRefresh();
+  }
+
+  @override
+  void onReady() {
+    super.onReady();
+    fetchAllStaffList();
+  }
+
+  @override
+  void onClose() {
+    datas.clear();
+    super.onClose();
+  }
+}

+ 108 - 0
packages/cpt_uk/lib/modules/job/revise_add_edit/revise_add_edit_controller.dart

@@ -0,0 +1,108 @@
+import 'package:domain/entity/response/add_edit_revise_view_s_g_entity.dart';
+import 'package:domain/entity/response/uk_job_applied_revise_edit_detail_entity.dart';
+import 'package:domain/repository/job_sg_repository.dart';
+import 'package:domain/repository/uk_job_repository.dart';
+import 'package:flutter/material.dart';
+import 'package:get/get.dart';
+import 'package:plugin_platform/engine/notify/notify_engine.dart';
+import 'package:plugin_platform/engine/toast/toast_engine.dart';
+import 'package:plugin_platform/http/dio/dio_cancelable_mixin.dart';
+import 'package:plugin_platform/http/http_result.dart';
+import 'package:shared/utils/util.dart';
+
+import 'revise_add_edit_state.dart';
+
+class ReviseAddEditController extends GetxController with DioCancelableMixin {
+  final JobSGRepository _jobRepository = Get.find();
+  final UKJobRepository _ukJobRepository = Get.find();
+  final ReviseAddEditState state = ReviseAddEditState();
+
+  /// 获取首页的数据
+  void fetchRequestDetail() async {
+    //获取到数据
+    Future<HttpResult> taskFuture;
+    if (state.pageType != 0 && Utils.isNotEmpty(state.id) && state.id != "0") {
+      // 编辑/详情
+      taskFuture = _ukJobRepository.fetchEditReviseDetailInfo(reviseId: state.id, cancelToken: cancelToken);
+    } else {
+      // 新增
+      taskFuture = _ukJobRepository.fetchAddReviseDetailInfo(appliedId: state.id, cancelToken: cancelToken);
+    }
+
+    var result = await taskFuture;
+
+    //处理数据
+    if (result.isSuccess) {
+      state.addEditEntity = result.data;
+
+      TextEditingController reviseHourController = state.formData['revise_hour']!['controller'];
+      TextEditingController reasonController = state.formData['reason']!['controller'];
+
+      reviseHourController.text = state.addEditEntity?.revise?.reviseHours ?? "";
+      reasonController.text = state.addEditEntity?.revise?.rejectRemark ?? "";
+
+      update();
+    } else {
+      ToastEngine.show(result.errorMsg ?? "Network Load Error".tr);
+    }
+  }
+
+  @override
+  void onReady() {
+    super.onReady();
+    fetchRequestDetail();
+  }
+
+  /// 提交
+  void doSubmit() async {
+    TextEditingController reviseHourController = state.formData['revise_hour']!['controller'];
+    TextEditingController reasonController = state.formData['reason']!['controller'];
+    String reviseHour = reviseHourController.text.toString();
+    String reason = reasonController.text.toString();
+
+    if (Utils.isEmpty(reviseHour)) {
+      ToastEngine.show("Enter Revise Hour".tr);
+      return;
+    } else if (Utils.isEmpty(reason)) {
+      ToastEngine.show("Enter Reason".tr);
+      return;
+    }
+
+    Future<HttpResult> taskFuture;
+    if (state.pageType != 0 && Utils.isNotEmpty(state.id) && state.id != "0") {
+      taskFuture = _ukJobRepository.reviseEditSubmit(
+        reviseId: state.id,
+        reviseHours: reviseHour,
+        reason: reason,
+        cancelToken: cancelToken,
+      );
+    } else {
+      taskFuture = _ukJobRepository.reviseAddSubmit(
+        appliedId: state.id,
+        reviseHours: reviseHour,
+        reason: reason,
+        cancelToken: cancelToken,
+      );
+    }
+
+    var result = await taskFuture;
+
+    //处理数据
+    if (result.isSuccess) {
+      NotifyEngine.showSuccess("Successful".tr);
+
+      //根据类型刷新
+      if (state.pageType != 0 && Utils.isNotEmpty(state.id) && state.id != "0") {
+        //编辑就发送指定的 reviseId 刷新
+        state.cb?.call(state.id ?? "");
+      } else {
+        //新增的就发送空
+        state.cb?.call("");
+      }
+
+      Get.back();
+    } else {
+      ToastEngine.show(result.errorMsg ?? "Network Load Error".tr);
+    }
+  }
+}

+ 70 - 0
packages/cpt_uk/lib/modules/job/revise_add_edit/revise_add_edit_item.dart

@@ -0,0 +1,70 @@
+import 'package:cs_resources/constants/color_constants.dart';
+import 'package:cs_resources/generated/assets.dart';
+import 'package:domain/entity/response/job_applied_list_s_g_entity.dart';
+import 'package:flutter/cupertino.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter/widgets.dart';
+import 'package:plugin_basic/basic_export.dart';
+import 'package:widgets/ext/ex_widget.dart';
+import 'package:widgets/my_button.dart';
+import 'package:widgets/my_load_image.dart';
+import 'package:widgets/my_text_view.dart';
+import 'package:widgets/shatter/border_select_widget.dart';
+
+/**
+ * 每一个选项
+ */
+class ReviseAddEditItem extends StatelessWidget {
+  final String title;
+  final String content;
+
+  ReviseAddEditItem({
+    required this.title,
+    required this.content,
+  });
+
+  @override
+  Widget build(BuildContext context) {
+    return Column(
+      mainAxisSize: MainAxisSize.min,
+      crossAxisAlignment: CrossAxisAlignment.start,
+      children: [
+
+        //工作标题,选择模板
+        MyTextView(
+          title,
+          textColor:ColorConstants.white,
+          isFontRegular: true,
+          marginTop: 14,
+          fontSize: 15,
+        ),
+
+        //工作标题
+        Container(
+          padding: EdgeInsets.only(left: 16, right: 10),
+          margin: EdgeInsets.only(top: 10),
+          height: 45,
+          decoration: BoxDecoration(
+            color: Color(0xFF4DCFF6).withOpacity(0.5),
+            borderRadius: const BorderRadius.all(Radius.circular(5)),
+          ),
+          child: Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            mainAxisAlignment: MainAxisAlignment.start,
+            children: [
+              MyTextView(
+                content,
+                fontSize: 15,
+                isFontRegular: true,
+                textColor: ColorConstants.white,
+              ).expanded(),
+
+            ],
+          ),
+        ),
+
+      ],
+    );
+  }
+}

+ 220 - 0
packages/cpt_uk/lib/modules/job/revise_add_edit/revise_add_edit_page.dart

@@ -0,0 +1,220 @@
+import 'package:cs_resources/constants/color_constants.dart';
+import 'package:flutter/cupertino.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter/services.dart';
+import 'package:flutter/widgets.dart';
+import 'package:get/get.dart';
+import 'package:plugin_basic/base/base_state.dart';
+import 'package:plugin_basic/base/base_stateful_page.dart';
+import 'package:plugin_basic/utils/ext_get_nav.dart';
+import 'package:router/path/router_path.dart';
+import 'package:shared/utils/screen_util.dart';
+import 'package:shared/utils/util.dart';
+import 'package:widgets/ext/ex_widget.dart';
+import 'package:widgets/my_appbar.dart';
+import 'package:widgets/my_button.dart';
+
+import 'package:widgets/no_shadow_scroll_behavior.dart';
+import 'package:widgets/shatter/form_require_text.dart';
+import 'package:widgets/shatter/round_my_text_field.dart';
+import 'package:widgets/widget_export.dart';
+
+import 'revise_add_edit_controller.dart';
+import 'revise_add_edit_item.dart';
+import 'revise_add_edit_state.dart';
+
+/**
+ * Revise数据的添加,编辑,详情的页面
+ */
+class UKReviseAddEditPage extends BaseStatefulPage<ReviseAddEditController> {
+  UKReviseAddEditPage({Key? key}) : super(key: key);
+
+  //启动当前页面,pageType 0 是新增  1是编辑  2是详情
+  static void startInstance(int pageType, String? id, void Function(dynamic value)? cb) {
+    return Get.start(RouterPath.UKJobAppliedReviseAddEdit, arguments: {'pageType': pageType, 'id': id,'cb': cb});
+  }
+
+  @override
+  ReviseAddEditController createRawController() {
+    return ReviseAddEditController();
+  }
+
+  @override
+  State<UKReviseAddEditPage> createState() => _LabourRequestAddState();
+}
+
+class _LabourRequestAddState extends BaseState<UKReviseAddEditPage, ReviseAddEditController> {
+  late ReviseAddEditState state;
+
+  @override
+  void initState() {
+    super.initState();
+    state = controller.state;
+    state.pageType = Get.arguments['pageType'];
+    state.id = Get.arguments['id'];
+    state.cb = Get.arguments['cb'] as void Function(dynamic)?;
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return autoCtlGetBuilder(builder: (controller) {
+      return Scaffold(
+        extendBodyBehindAppBar: true,
+        appBar: MyAppBar.appBar(
+            context,
+            state.pageType == 0
+                ? "Add Revise".tr
+                : state.pageType == 1
+                    ? "Edit Revise".tr
+                    : "Detail".tr),
+        body: SafeArea(
+        bottom: MediaQuery.of(context).padding.bottom > 38,
+          top: false,
+          child: Container(
+            width: double.infinity,
+            height: double.infinity,
+            padding: EdgeInsets.only(top: kToolbarHeight + ScreenUtil.getStatusBarH(context) + 1),
+            decoration: const BoxDecoration(
+              gradient: LinearGradient(
+                colors: [
+                  Color(0xFF091D44),
+                  Color(0xFF245A8A),
+                  Color(0xFF7F7CEC),
+                ],
+                begin: Alignment.topCenter,
+                end: Alignment.bottomCenter,
+              ),
+            ),
+            child: Scrollbar(
+              child: ScrollConfiguration(
+                behavior: NoShadowScrollBehavior(),
+                child: SingleChildScrollView(
+                  scrollDirection: Axis.vertical,
+                  physics: const BouncingScrollPhysics(),
+                  child: Column(
+                    crossAxisAlignment: CrossAxisAlignment.start,
+                    children: [
+                      ReviseAddEditItem(title: "Staff Name".tr, content: state.addEditEntity?.applied?.memberName ?? ""),
+
+                      ReviseAddEditItem(title: "Job Start Time".tr, content: state.addEditEntity?.startTime ?? ""),
+
+                      ReviseAddEditItem(title: "Job End Time".tr, content: state.addEditEntity?.endTime ?? ""),
+
+                      ReviseAddEditItem(title: "Security Clock In".tr, content: state.addEditEntity?.securityIn ?? ""),
+
+                      ReviseAddEditItem(title: "Security Clock Out".tr, content: state.addEditEntity?.securityOut ?? ""),
+
+                      ReviseAddEditItem(title: "Work Clock In".tr, content: state.addEditEntity?.workIn ?? ""),
+
+                      ReviseAddEditItem(title: "Work Clock Out".tr, content: state.addEditEntity?.workOut ?? ""),
+
+                      ReviseAddEditItem(title: "+/- Hours".tr, content: state.addEditEntity?.adjustHours.toString() ?? ""),
+
+
+                      //修改的小时
+                      FormRequireText(
+                        fontSize: 15,
+                        text: "Revise Hours".tr,
+                      ).marginOnly(top: 15),
+
+                      //输入框
+                      CustomTextField(
+                        formKey: "revise_hour",
+                        marginLeft: 0,
+                        marginRight: 0,
+                        paddingTop: 0,
+                        paddingBottom: 0,
+                        height: 45,
+                        fillBackgroundColor: Color(0xFF4DCFF6).withOpacity(state.pageType == 2 ? 0.5 : 0.2),
+                        enabled: state.pageType != 2,
+                        textInputType: TextInputType.number,
+                        formData: state.formData,
+                        textInputAction: TextInputAction.next,
+                        onSubmit: (key, value) {
+                          state.formData[key]!['focusNode'].unfocus();
+                          FocusScope.of(context).requestFocus(state.formData['reason']!['focusNode']);
+                        },
+                        marginTop: 10,
+                      ),
+
+                      //修改的原因
+                      FormRequireText(
+                        fontSize: 15,
+                        text: "Reason".tr,
+                      ).marginOnly(top: 15),
+
+                      //输入框
+                      IgnoreKeyboardDismiss(
+                        child: Container(
+                          height: 160,
+                          padding: EdgeInsets.symmetric(vertical: 15, horizontal: 15),
+                          decoration: BoxDecoration(
+                            color: Color(0xFF4DCFF6).withOpacity(state.pageType == 2 ? 0.5 : 0.2),
+                            borderRadius: const BorderRadius.all(Radius.circular(5)),
+                          ),
+                          child: TextField(
+                            enabled: state.pageType != 2,
+                            cursorColor: ColorConstants.white,
+                            cursorWidth: 1.5,
+                            autofocus: false,
+                            controller: state.formData["reason"]!['controller'],
+                            focusNode: state.formData["reason"]!['focusNode'],
+                            obscureText: state.formData["reason"]!['obsecure'],
+                            // 装饰
+                            decoration: InputDecoration(
+                              isDense: true,
+                              isCollapsed: true,
+                              border: InputBorder.none,
+                              hintText: state.formData["reason"]!['hintText'],
+                              hintStyle: TextStyle(
+                                color: ColorConstants.textGrayAECAE5,
+                                fontSize: 15.0,
+                                fontWeight: FontWeight.w400,
+                              ),
+                            ),
+                            style: TextStyle(
+                              color: ColorConstants.white,
+                              fontSize: 15.0,
+                              fontWeight: FontWeight.w400,
+                            ),
+                            // 键盘动作右下角图标
+                            textInputAction: TextInputAction.done,
+                            onSubmitted: (value) {
+                              FocusScope.of(context).unfocus();
+                              controller.doSubmit();
+                            },
+                          ),
+                        ),
+                      ).marginOnly(top: 10),
+
+                      //提交按钮
+                      Visibility(
+                        visible: state.pageType != 2,
+                        child: MyButton(
+                          type: ClickType.throttle,
+                          milliseconds: 500,
+                          onPressed: () {
+                            FocusScope.of(context).unfocus();
+                            controller.doSubmit();
+                          },
+                          text: "Submit".tr,
+                          textColor: ColorConstants.white,
+                          fontSize: 16,
+                          radius: 22.5,
+                          backgroundColor: hexToColor("#FFBB1B"),
+                          fontWeight: FontWeight.w500,
+                        ).marginOnly(top: 20),
+                      ),
+
+                      SizedBox(height: 20),
+                    ],
+                  ).paddingOnly(left: 15, right: 15),
+                ),
+              ),
+            ),
+          ),
+        ),
+      );
+    });
+  }
+}

+ 40 - 0
packages/cpt_uk/lib/modules/job/revise_add_edit/revise_add_edit_state.dart

@@ -0,0 +1,40 @@
+import 'package:domain/entity/response/add_edit_revise_view_s_g_entity.dart';
+import 'package:domain/entity/response/uk_job_applied_revise_add_detail_entity.dart';
+import 'package:domain/entity/response/uk_job_applied_revise_edit_detail_entity.dart';
+import 'package:flutter/material.dart';
+import 'package:plugin_basic/basic_export.dart';
+
+class ReviseAddEditState {
+
+  int pageType = 0;  //页面的状态 0 是新增  1是编辑  2是详情
+
+  get isAdd => pageType == 0;
+  get isEdit => pageType == 1;
+  get isDetail => pageType == 2;
+
+  String? id;  //编辑和详情需要用到ID,新增是 appliedId  编辑和详情是 reviseId
+  void Function(dynamic value)? cb;
+
+  //页面对应的详情数据
+  UkJobAppliedReviseEditDetailEntity? addEditEntity;
+
+
+  //表单的校验与数据
+  Map<String, Map<String, dynamic>> formData = {
+    'revise_hour': {
+      'value': '',
+      'controller': TextEditingController(),
+      'focusNode': FocusNode(),
+      'hintText': 'Enter...'.tr,
+      'obsecure': false,
+    },
+    'reason': {
+      'value': '',
+      'controller': TextEditingController(),
+      'focusNode': FocusNode(),
+      'hintText': 'Enter...'.tr,
+      'obsecure': false,
+    },
+  };
+
+}

+ 101 - 0
packages/cpt_uk/lib/modules/job/revise_log/revise_log_controller.dart

@@ -0,0 +1,101 @@
+import 'package:domain/entity/response/revise_log_s_g_entity.dart';
+import 'package:domain/entity/response/uk_job_applied_revise_log_entity.dart';
+import 'package:domain/repository/job_sg_repository.dart';
+import 'package:domain/repository/uk_job_repository.dart';
+import 'package:get/get.dart';
+import 'package:plugin_platform/http/dio/dio_cancelable_mixin.dart';
+import 'package:widgets/load_state_layout.dart';
+import 'package:widgets/widget_export.dart';
+
+import 'revise_log_state.dart';
+
+/**
+ * 修改的记录
+ */
+class  ReviseLogController extends GetxController with DioCancelableMixin{
+  final JobSGRepository _jobRepository = Get.find();
+  final UKJobRepository _ukJobRepository = Get.find();
+  final ReviseLogState state = ReviseLogState();
+
+  var _needShowPlaceholder = true;
+
+  //页面PlaceHolder的展示
+  LoadState loadingState = LoadState.State_Success;
+  String? errorMessage;
+
+  //刷新页面状态
+  void changeLoadingState(LoadState state) {
+    loadingState = state;
+    update();
+  }
+
+  // Refresh 控制器
+  final EasyRefreshController refreshController = EasyRefreshController(
+    controlFinishRefresh: true,
+    controlFinishLoad: false,
+  );
+
+  // Refresh 刷新事件
+  Future onRefresh() async {
+    fetchWorkFlowList();
+  }
+
+  // 重试请求
+  Future retryRequest() async {
+    _needShowPlaceholder = true;
+    fetchWorkFlowList();
+  }
+
+  /// 获取服务器数据,成员考勤列表
+  Future fetchWorkFlowList() async {
+    if (_needShowPlaceholder) {
+      changeLoadingState(LoadState.State_Loading);
+    }
+
+    //获取到数据
+    var result = await _ukJobRepository.featchReviseLogs(
+      reviseId: state.reviseId,
+      cancelToken: cancelToken,
+    );
+
+    //处理数据
+    if (result.isSuccess) {
+      handleList(result.data?.records);
+      refreshController.finishRefresh(IndicatorResult.success);
+    } else {
+      errorMessage = result.errorMsg;
+      changeLoadingState(LoadState.State_Error);
+      refreshController.finishRefresh(IndicatorResult.fail);
+    }
+
+    //最后赋值
+    _needShowPlaceholder = false;
+  }
+
+  // 处理数据与展示的逻辑
+  void handleList(List<UkJobAppliedReviseLogRecords>? list) {
+    if (list != null && list.isNotEmpty) {
+      //有数据,判断是刷新还是加载更多的数据
+      state.datas.clear();
+      state.datas.addAll(list);
+      //更新状态
+      changeLoadingState(LoadState.State_Success);
+    } else {
+      //展示无数据的布局
+      state.datas.clear();
+      changeLoadingState(LoadState.State_Empty);
+    }
+  }
+
+  @override
+  void onReady() async {
+    super.onReady();
+    fetchWorkFlowList();
+  }
+
+  @override
+  void onClose() {
+    super.onClose();
+    state.datas.clear();
+  }
+}

+ 156 - 0
packages/cpt_uk/lib/modules/job/revise_log/revise_log_item.dart

@@ -0,0 +1,156 @@
+import 'package:cs_resources/constants/color_constants.dart';
+import 'package:domain/entity/response/revise_log_s_g_entity.dart';
+import 'package:domain/entity/response/uk_job_applied_revise_log_entity.dart';
+import 'package:flutter/cupertino.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter/widgets.dart';
+import 'package:plugin_basic/basic_export.dart';
+import 'package:widgets/ext/ex_widget.dart';
+import 'package:widgets/my_text_view.dart';
+
+/**
+ * 修改记录Item
+ */
+class ReviseLogItem extends StatelessWidget {
+  final int index;
+  final UkJobAppliedReviseLogRecords item;
+
+  ReviseLogItem({
+    required this.index,
+    required this.item,
+  });
+
+  @override
+  Widget build(BuildContext context) {
+    return Container(
+      padding: EdgeInsets.symmetric(vertical: 23, horizontal: 21),
+      margin: EdgeInsets.only(left: 15, right: 15, top: 5, bottom: 5),
+      decoration: BoxDecoration(
+        color: Color(0xFF4DCFF6).withOpacity(0.2), // 设置背景颜色和不透明度
+        borderRadius: BorderRadius.circular(5), // 设置圆角
+      ),
+      child: Column(
+        mainAxisSize: MainAxisSize.max,
+        crossAxisAlignment: CrossAxisAlignment.start,
+        children: [
+          //时间
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "Date Time".tr + ":",
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+              MyTextView(
+                item.createdAt ?? "-",
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor: Colors.white,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ),
+
+          // 操作者
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "Operator:".tr,
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+              MyTextView(
+                item.operationName ?? "-",
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor: Colors.white,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ).marginOnly(top: 15),
+
+          // 操作类型
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "Action".tr + ":",
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+
+              //状态
+              MyTextView(
+                item.actText ?? "-",
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor: item.actText == "Audit" ? ColorConstants.textYellowF8AE00 : ColorConstants.textGreen0AC074,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ).marginOnly(top: 15),
+
+          // 操作内容
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.start,
+            children: [
+              MyTextView(
+                "Content".tr + ":",
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+
+              //时间
+              MyTextView(
+                _obtainContent(),
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor: Colors.white,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ).marginOnly(top: 15),
+        ],
+      ),
+    );
+  }
+
+  String _obtainContent() {
+    String displayText = "";
+
+    // 检查 reviseHours
+    if (item.content?.reviseHours != null) {
+      displayText += "Revise Hours => ${item.content!.reviseHours!.value!}\n";
+    }
+
+    // 检查 reviseMsg
+    if (item.content?.reason != null) {
+      displayText += "Reason => ${item.content!.reason!.value!}\n";
+    }
+
+    // 检查 status
+    if (item.content?.status != null) {
+      displayText += "Status => ${item.content!.status!.value!}\n";
+    }
+
+    // 如果没有任何信息,则显示 "-"
+    if (displayText.isEmpty) {
+      displayText = "-";
+    } else {
+      // 去掉末尾的换行符
+      displayText = displayText.trim();
+    }
+
+    return displayText;
+  }
+}

+ 102 - 0
packages/cpt_uk/lib/modules/job/revise_log/revise_log_page.dart

@@ -0,0 +1,102 @@
+
+import 'package:flutter/material.dart';
+import 'package:get/get.dart';
+import 'package:plugin_basic/base/base_state.dart';
+import 'package:plugin_basic/base/base_stateful_page.dart';
+import 'package:plugin_basic/utils/ext_get_nav.dart';
+import 'package:router/path/router_path.dart';
+import 'package:shared/utils/screen_util.dart';
+import 'package:widgets/ext/ex_widget.dart';
+import 'package:widgets/load_state_layout.dart';
+import 'package:widgets/my_appbar.dart';
+import 'package:widgets/widget_export.dart';
+
+import 'revise_log_controller.dart';
+import 'revise_log_state.dart';
+import 'revise_log_item.dart';
+
+/**
+ * 修改的记录
+ */
+class UKReviseLogPage extends BaseStatefulPage<ReviseLogController> {
+  UKReviseLogPage({Key? key}) : super(key: key);
+
+  //启动当前页面
+  static void startInstance(String? reviseId) {
+    return Get.start(RouterPath.UKJobAppliedReviseLog,arguments: {'reviseId': reviseId});
+  }
+
+  @override
+  ReviseLogController createRawController() {
+    return ReviseLogController();
+  }
+
+  @override
+  State<UKReviseLogPage> createState() => _AppliedWorkflowState();
+
+}
+
+class _AppliedWorkflowState extends BaseState<UKReviseLogPage, ReviseLogController> {
+
+  late ReviseLogState state;
+
+  @override
+  void initState() {
+    super.initState();
+    state = controller.state;
+    state.reviseId = Get.arguments['reviseId'];
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return autoCtlGetBuilder(builder: (controller) {
+      return  SafeArea(
+        bottom: MediaQuery.of(context).padding.bottom > 38,
+          top: false,
+          child: Container(
+            width: double.infinity,
+            height: double.infinity,
+            padding: EdgeInsets.only(top:ScreenUtil.getStatusBarH(context)),
+            decoration: const BoxDecoration(
+              gradient: LinearGradient(
+                colors: [
+                  Color(0xFF091D44),
+                  Color(0xFF245A8A),
+                  Color(0xFF7F7CEC),
+                ],
+                begin: Alignment.topCenter,
+                end: Alignment.bottomCenter,
+              ),
+            ),
+            child: Column(
+              children: [
+                MyAppBar.titleBar(context, "Logs".tr),
+
+                EasyRefresh(
+                  controller: controller.refreshController,
+                  onRefresh: controller.onRefresh,
+                  child: LoadStateLayout(
+                    state: controller.loadingState,
+                    errorMessage: controller.errorMessage,
+                    errorRetry: () {
+                      controller.retryRequest();
+                    },
+                    successSliverWidget: [
+                      SliverList(
+                          delegate: SliverChildBuilderDelegate((context, index) {
+                              return ReviseLogItem(index: index,item: state.datas[index]);
+                            },
+                            childCount: state.datas.length,
+                          ))
+                    ],
+                  ),
+                ).marginOnly(top: 5,bottom: 5).expanded(),
+              ],
+            ).marginOnly(top: 10),
+          ),
+        );
+    });
+  }
+}
+
+

+ 11 - 0
packages/cpt_uk/lib/modules/job/revise_log/revise_log_state.dart

@@ -0,0 +1,11 @@
+
+import 'package:domain/entity/response/uk_job_applied_revise_log_entity.dart';
+
+class ReviseLogState {
+
+  String? reviseId;
+
+  //页面的列表数据
+  List<UkJobAppliedReviseLogRecords> datas = [];
+
+}

+ 308 - 28
packages/cpt_uk/lib/modules/job/template_add/template_add_controller.dart

@@ -1,13 +1,17 @@
-import 'package:domain/entity/response/job_template_edit_index_entity.dart';
-import 'package:domain/entity/response/u_k_template_detail_entity.dart';
+import 'package:domain/entity/response/uk_job_template_detail_by_select_title_entity.dart';
+import 'package:domain/entity/response/uk_template_detail_entity.dart';
+import 'package:domain/entity/response/uk_template_detail_index_entity.dart';
+import 'package:domain/entity/response/uk_template_title_option_entity.dart';
 import 'package:domain/repository/uk_job_repository.dart';
 import 'package:get/get.dart';
+import 'package:plugin_platform/engine/loading/loading_engine.dart';
 import 'package:plugin_platform/engine/notify/notify_engine.dart';
 import 'package:plugin_platform/engine/toast/toast_engine.dart';
 import 'package:plugin_platform/http/dio/dio_cancelable_mixin.dart';
 import 'package:plugin_platform/http/http_result.dart';
 import 'package:shared/utils/log_utils.dart';
 import 'package:shared/utils/util.dart';
+import 'package:widgets/picker/option_pick_util.dart';
 
 import 'template_add_state.dart';
 
@@ -15,36 +19,194 @@ class TemplateAddController extends GetxController with DioCancelableMixin {
   final UKJobRepository _labourRepository = Get.find();
   final LabourTemplateAddState state = LabourTemplateAddState();
 
+  @override
+  void onReady() {
+    super.onReady();
+    _fetchAddEditIndexDetail();
+  }
+
   // 获取添加或者编辑的详情
   void _fetchAddEditIndexDetail() async {
+
+    bool isEdit = state.pageType == 1;
+    bool isNeedFetchDetail = isEdit || Utils.isNotEmpty(state.selectedJobTitleStr);
+    String? templateId;
+    if (isEdit) {
+      templateId = state.selectedJobTitleId?? state.templateId;
+    }else {
+      templateId = state.selectedJobTitleId?.toString();
+    }
     //获取到数据
-    Future<HttpResult<UKTemplateDetailEntity>> taskFuture;
-    if (Utils.isNotEmpty(state.templateId) && state.templateId != "0") {
+    HttpResult<UkTemplateDetailEntity> taskDetailResult;
+    HttpResult<UkTemplateDetailIndexEntity> taskDetailOptionsResult;
+
+    if(state.indexOptionEntity == null){
+      // 获取选项
+      taskDetailOptionsResult = await _labourRepository.fetchJobTemplateIndex(cancelToken: cancelToken);
+      handlerAddDetailOptionsData(taskDetailOptionsResult);
+    }
+
+    if (isNeedFetchDetail) {
       //编辑
-      taskFuture = _labourRepository.fetchJobTemplateDetail(templateId: state.templateId, cancelToken: cancelToken);
+      taskDetailResult = await _labourRepository.fetchJobTemplateDetail(templateId: templateId, cancelToken: cancelToken);
+      // 处理数据
+      handlerEditDetailData(taskDetailResult);
+    }
+  }
+
+  // 新增时 选择了 jobtitle 后 获取该title对应的模板详情
+  void _fetchSelectJobTitleGetTemplateDetail() async {
+    String? templateId = "";
+    if(state.pageType == 0){
+      // 新增
+      templateId = state.selectedJobTitleId?.toString();
+    }else if(state.pageType == 1){
+      // 编辑
+      templateId = state.selectedJobTitleId?.toString();
+    }
+    Log.d("获取jobtitle选项时的  templateId  ${templateId}");
+    //获取到数据
+    HttpResult<UkJobTemplateDetailBySelectTitleEntity> taskDetailResult;
+
+    taskDetailResult = await _labourRepository.fetchSelectJobTitleGetTemplateDetail(templateId: templateId, cancelToken: cancelToken);
+      // 处理数据
+    handlerBySelectJobTitleDetailData(taskDetailResult);
+  }
+
+  // 处理 选择 jobtitle 后 该 jobtitle 对应的模板数据的回显
+  void handlerBySelectJobTitleDetailData(HttpResult<UkJobTemplateDetailBySelectTitleEntity> result) async {
+    //处理数据
+    if (result.isSuccess) {
+      UkJobTemplateDetailBySelectTitleEntity? resultData = result.data;
+      // var templateNameController = state.formData['template_name']!['controller'];
+      var descController = state.formData['desc']!['controller'];
+      var noteController = state.formData['note']!['controller'];
+      var contactNameController = state.formData['contact_name']!['controller'];
+      var contactNoController = state.formData['contact_no']!['controller'];
+
+
+      descController.text = resultData?.requirements ?? "";
+      noteController.text = resultData?.note ?? "";
+      contactNameController.text = resultData?.contact ?? "";
+      contactNoController.text = resultData?.contactNo ?? "";
+
+
+      // 证书回显
+      List<int> jobCertificateList = (resultData?.jobCertificate ?? '')
+          .split(',')
+          .where((s) => s.isNotEmpty)
+          .map((s) => int.tryParse(s) ?? 0)
+          .toList();
+
+
+      if (jobCertificateList.isNotEmpty) {
+        state.indexOptionEntity?.certificateList?.forEach((cerItem) {
+          if (jobCertificateList.contains(cerItem.value)) {
+            cerItem.checked = "checked";
+          }
+        });
+      }
+
+      // 交通工具回显
+      List<String> jobVechicleList = (resultData?.jobVehicle ?? '')
+          .split(',')
+          .where((s) => s.isNotEmpty)
+          .map((s) => s?.toString() ?? '')
+          .toList();
+      if (jobVechicleList.isNotEmpty) {
+        state.indexOptionEntity?.vehicleList?.forEach((vechicleItem) {
+          if (jobVechicleList.contains(vechicleItem.value)) {
+            vechicleItem.checked = "checked";
+          }
+        });
+      }
+
+      //回显
+      _handlerCertificateEcho();
+      _handlerVehicleEcho();
+
+      //刷新
+      update();
     } else {
-      //新增
-      taskFuture = _labourRepository.fetchJobTemplateIndex(cancelToken: cancelToken);
+      ToastEngine.show(result.errorMsg ?? "Network Load Error".tr);
     }
+  }
 
-    var result = await taskFuture;
 
+  // 处理编辑的详情数据
+  void handlerEditDetailData(HttpResult<UkTemplateDetailEntity> result) async {
     //处理数据
     if (result.isSuccess) {
       state.indexEntity = result.data;
+      state.selectedJobTemplateStr = state.indexEntity?.templateTitle ?? "";
+      // state.selectedJobTemplateStr 有值后 需要调取 工作标题的下拉选项
+      if(state.selectedJobTemplateStr != null && state.selectedJobTemplateStr != ""){
+        // 相当与选取了 模板
+        _fetchJobTitleOptionsList();
+      }
 
-      var templateNameController = state.formData['template_name']!['controller'];
       var descController = state.formData['desc']!['controller'];
       var noteController = state.formData['note']!['controller'];
-      templateNameController.text = state.indexEntity?.row?.jobTitle ?? "";
+      var contactNameController = state.formData['contact_name']!['controller'];
+      var contactNoController = state.formData['contact_no']!['controller'];
+
+
       descController.text = state.indexEntity?.row?.description ?? "";
       noteController.text = state.indexEntity?.row?.note ?? "";
+      contactNameController.text = state.indexEntity?.row?.contactName ?? "";
+      contactNoController.text = state.indexEntity?.row?.contactNo ?? "";
+
+      Log.d("获取详情后的 state.selectedJobTemplateStr---- ${state.selectedJobTemplateStr}");
+
+      Log.d("获取详情后的 state.indexEntity?.row---- ${state.indexEntity?.row}");
+      Log.d("645646  ${state.selectedJobTitleStr}");
+      Log.d("89389   ${state.selectedJobTitleId}");
+      // 将 state.indexEntity?.certificateList  与 state.indexOptionEntity 进行对比 将 checked 复制给
+      state.indexEntity?.certificateList?.forEach((e) {
+        var option = state.indexOptionEntity?.certificateList?.firstWhere((option) => option.value == e.value, orElse: () => UkTemplateDetailIndexCertificateList());
+        if (option != null) {
+          option.checked = e.checked;
+        }
+      });
+
+      // 将 state.indexEntity?.vehicleList  与 state.indexOptionEntity 进行对比 将 checked 复制给
+      state.indexEntity?.vehicleList?.forEach((e) {
+        var option = state.indexOptionEntity?.vehicleList?.firstWhere((option) => option.value == e.value, orElse: () => UkTemplateDetailIndexVehicleList());
+        if (option != null) {
+          option.checked = e.checked;
+        }
+      });
+
+      // 回显
+      _handlerCertificateEcho();
+      _handlerVehicleEcho();
+
+      //刷新
+      update();
+    } else {
+      ToastEngine.show(result.errorMsg ?? "Network Load Error".tr);
+    }
+  }
+
+
+  // 处理新增时详情页的选项数据
+  void handlerAddDetailOptionsData(HttpResult<UkTemplateDetailIndexEntity> result) async {
+    //处理数据
+    if (result.isSuccess) {
+      state.indexOptionEntity = result.data;
+      state.selectedJobTemplateStr = state.indexEntity?.templateTitle ?? "";
+      var descController = state.formData['desc']!['controller'];
+      var noteController = state.formData['note']!['controller'];
+      var contactNameController = state.formData['contact_name']!['controller'];
+      var contactNoController = state.formData['contact_no']!['controller'];
+      descController.text =  "";
+      noteController.text =  "";
+      contactNameController.text =  "";
+      contactNoController.text =  "";
 
-      //默认CheckBox
-      state.selectedCertificateList = state.indexEntity?.certificateList?.where((e) => e.checked == "checked").map((e) => e.value!).toList() ?? [];
-      Log.d("当前选中的证书:${state.selectedCertificateList}");
-      state.selectedVehicleList = state.indexEntity?.vehicleList?.where((e) => e.checked == "checked").map((e) => e.value!).toList() ?? [];
-      Log.d("当前选中的交通工具:${state.selectedVehicleList}");
+      //回显
+      _handlerCertificateEcho();
+      _handlerVehicleEcho();
 
       //刷新
       update();
@@ -53,40 +215,163 @@ class TemplateAddController extends GetxController with DioCancelableMixin {
     }
   }
 
+  // 回显 certificate
+  void _handlerCertificateEcho(){
+    //默认CheckBox
+    state.selectedCertificateList = state.indexOptionEntity?.certificateList
+        ?.where((e) => e.checked == "checked")
+        .map((e) => e.value!.toString())
+        .toList() ?? [];
+    Log.d("当前的证书: ${state.indexOptionEntity?.certificateList}");
+    Log.d("当前选中的证书:${state.selectedCertificateList}");
+  }
+
+  // 回显 vehicle
+  void _handlerVehicleEcho(){
+    state.selectedVehicleList = state.indexOptionEntity?.vehicleList
+        ?.where((e) => e.checked == "checked")
+        .map((e) => e.value!.toString())
+        .toList() ?? [];
+    Log.d("当前的交通工具: ${state.indexOptionEntity?.vehicleList}");
+    Log.d("当前选中的交通工具:${state.selectedVehicleList}");
+
+  }
+
+
+  // 新增时 选择 template
+  void showChooseTemplatePicker(){
+    int selectedTemplateIndex;
+    if (state.selectedJobTemplateStr == null) {
+      selectedTemplateIndex = 0;
+    } else {
+      selectedTemplateIndex = state.indexOptionEntity?.templateList?.indexWhere((template) => template.toString() == state.selectedJobTemplateStr)?? 0;
+    }
+
+    if (selectedTemplateIndex < 0) {
+      selectedTemplateIndex = 0;
+    }
+
+    OptionPickerUtil.showCupertinoOptionPicker(
+      items: state.indexOptionEntity?.templateList?.map((e) => e!).toList(growable: false)?? [],
+      initialSelectIndex: selectedTemplateIndex,
+      onPickerChanged: (_, index) {
+        String lastSelectedTemplateStr = state.selectedJobTemplateStr?? "";
+        String curSelectedTemplateStr = state.indexOptionEntity?.templateList?[index] ?? "";
+        if(lastSelectedTemplateStr != curSelectedTemplateStr){
+          state.selectedJobTemplateStr = curSelectedTemplateStr;
+          state.selectedJobTitleStr = "";
+          update();
+          // 需要调接口来获取工作标题的数据源
+          _fetchJobTitleOptionsList();
+        }
+      },
+    );
+  }
+
+  // 获取 工作标题的数据源
+  void _fetchJobTitleOptionsList() async {
+    LoadingEngine.show();
+    try {
+      // 获取到数据
+      HttpResult<UkTemplateTitleOptionEntity> taskResult;
+
+      taskResult = await _labourRepository.fetchJobTitleOptiosByTemplate(
+        state.selectedJobTemplateStr!,
+        cancelToken: cancelToken,
+      );
+
+      if (taskResult.isSuccess) {
+        state.jobTitleOptionEntityList = taskResult.list;
+      } else {
+        ToastEngine.show(taskResult.errorMsg ?? "Network Load Error".tr);
+      }
+    } catch (e) {
+      // Log.e(e);
+    } finally {
+      LoadingEngine.dismiss();
+    }
+  }
+
+
+  // 显示工作标题picker
+  void showChooseJobTitlePicker(){
+    int selectedjobTitleIndex;
+    if (state.selectedJobTitleStr == null) {
+      selectedjobTitleIndex = 0;
+    } else {
+      selectedjobTitleIndex = state.jobTitleOptionEntityList?.indexWhere((title) => title.jobTitle.toString() == state.selectedJobTitleStr)?? 0;
+    }
+
+    if (selectedjobTitleIndex < 0) {
+      selectedjobTitleIndex = 0;
+    }
+
+    OptionPickerUtil.showCupertinoOptionPicker(
+      items: state.jobTitleOptionEntityList?.map((e) => e.jobTitle.toString()!).toList(growable: false)?? [],
+      initialSelectIndex: selectedjobTitleIndex,
+      onPickerChanged: (_, index) {
+        state.selectedJobTitleStr = state.jobTitleOptionEntityList?[index]?.jobTitle?.toString()?? "";
+        update();
+        // 选择了 工作标题后 需要重新调用 详情接口
+        _fetchSelectJobTitleGetTemplateDetail();
+      },
+    );
+  }
+
   /// 提交
   void doSubmit() async {
-    var templateNameController = state.formData['template_name']!['controller'];
+
     var descController = state.formData['desc']!['controller'];
     var noteController = state.formData['note']!['controller'];
+    var contactNameController = state.formData['contact_name']!['controller'];
+    var contactNoController = state.formData['contact_no']!['controller'];
+
 
-    String templateTitle = templateNameController.text.toString();
+
+    String jobTemplate = state.selectedJobTemplateStr?? "";
+    String jobTitle = state.selectedJobTitleStr??"";
     String desc = descController.text.toString();
     String note = noteController.text.toString();
+    String contactName = contactNameController.text.toString();
+    String contactNo = contactNoController.text.toString();
 
-    //只校验模版的名称
-    if (Utils.isEmpty(templateTitle)) {
-      ToastEngine.show("Enter Job Template Title".tr);
+    if (Utils.isEmpty(jobTemplate)) {
+      ToastEngine.show("Enter Job Template".tr);
+      return;
+    }
+    if (Utils.isEmpty(jobTitle)) {
+      ToastEngine.show("Enter Job Title".tr);
       return;
     }
 
+
     Future<HttpResult> taskFuture;
     if (Utils.isNotEmpty(state.templateId) && state.templateId != "0") {
+      Log.d("state.selectedJobTitleId   ${state.selectedJobTitleId}");
+      // 编辑
       taskFuture = _labourRepository.editJobTemplateSubmit(
-        templateId: state.templateId,
-        jobTitle: templateTitle,
+        templateId: state.templateId?.toString()??'',
+        jobTemplateId: state.selectedJobTitleId?.toString()??'',
+        jobTitle: jobTitle,
         certificate: state.selectedCertificateList,
         vehicle: state.selectedVehicleList,
         desc: desc,
         note: note,
+        contactName: contactName,
+        contactNo: contactNo,
         cancelToken: cancelToken,
       );
     } else {
+      // 新增
       taskFuture = _labourRepository.addJobTemplateSubmit(
-        jobTitle: templateTitle,
+        jobTemplateId: state.selectedJobTitleId?.toString()??'',
+        jobTitle: state.selectedJobTitleStr?? '',
         certificate: state.selectedCertificateList,
         vehicle: state.selectedVehicleList,
         desc: desc,
         note: note,
+        contactName: contactName,
+        contactNo: contactNo,
         cancelToken: cancelToken,
       );
     }
@@ -106,9 +391,4 @@ class TemplateAddController extends GetxController with DioCancelableMixin {
     }
   }
 
-  @override
-  void onReady() {
-    super.onReady();
-    _fetchAddEditIndexDetail();
-  }
 }

+ 166 - 27
packages/cpt_uk/lib/modules/job/template_add/template_add_page.dart

@@ -1,17 +1,19 @@
 import 'package:cs_resources/constants/color_constants.dart';
+import 'package:cs_resources/generated/assets.dart';
 import 'package:flutter/material.dart';
 import 'package:get/get.dart';
 import 'package:plugin_basic/base/base_state.dart';
 import 'package:plugin_basic/base/base_stateful_page.dart';
+import 'package:shared/utils/log_utils.dart';
 import 'package:shared/utils/screen_util.dart';
 import 'package:shared/utils/util.dart';
 import 'package:widgets/ext/ex_widget.dart';
 import 'package:widgets/my_appbar.dart';
 import 'package:widgets/my_button.dart';
+import 'package:widgets/my_load_image.dart';
 import 'package:widgets/my_text_view.dart';
 import 'package:widgets/no_shadow_scroll_behavior.dart';
 import 'package:widgets/shatter/custom_check_box.dart';
-import 'package:widgets/shatter/custom_radio_check.dart';
 import 'package:widgets/shatter/form_require_text.dart';
 import 'package:widgets/shatter/round_my_text_field.dart';
 import 'package:widgets/widget_export.dart';
@@ -32,9 +34,10 @@ class UKTemplateAddPage extends BaseStatefulPage<TemplateAddController> {
   //启动当前页面
   static void startInstance(
     String templateId,
+    String jobTitle,
     void Function(dynamic value)? cb,
   ) {
-    return Get.start(RouterPath.UKTemplateAdd, arguments: {'templateId': templateId, 'cb': cb});
+    return Get.start(RouterPath.UKTemplateAdd, arguments: {'jobTitle':jobTitle,'templateId': templateId, 'cb': cb});
   }
 
   @override
@@ -53,20 +56,27 @@ class _LabourTemplateAddState extends BaseState<UKTemplateAddPage, TemplateAddCo
   void initState() {
     super.initState();
     state = controller.state;
+    state.jobTitle = Get.arguments['jobTitle'];
     state.templateId = Get.arguments['templateId'];
+    state.selectedJobTitleStr = state.jobTitle;
+    state.pageType = Utils.isEmpty(state.templateId)? 0:1;
+
+    Log.d("初始时 传入的 jobTitle: ${state.jobTitle} , templateId: ${state.templateId}");
     state.cb = Get.arguments['cb'] as void Function(dynamic)?;
   }
 
   @override
   Widget build(BuildContext context) {
+    bool isEdit = Utils.isNotEmpty(state.templateId);
+    bool isAdd = Utils.isEmpty(state.templateId);
     return autoCtlGetBuilder(
         id: "all",
         builder: (controller) {
           return Scaffold(
             extendBodyBehindAppBar: true,
-            appBar: MyAppBar.appBar(context, Utils.isEmpty(state.templateId) ? "Create Template".tr : "Edit Template".tr),
+            appBar: MyAppBar.appBar(context, isAdd ? "Create Template".tr : "Edit Template".tr),
             body: SafeArea(
-        bottom: MediaQuery.of(context).padding.bottom > 38,
+              bottom: MediaQuery.of(context).padding.bottom > 38,
               top: false,
               child: Container(
                 width: double.infinity,
@@ -92,24 +102,37 @@ class _LabourTemplateAddState extends BaseState<UKTemplateAddPage, TemplateAddCo
                       child: Column(
                         crossAxisAlignment: CrossAxisAlignment.start,
                         children: [
-                          //模板名称
-                          FormRequireText(text: "Template Title".tr).marginOnly(left: 15, top: 19),
 
-                          CustomTextField(
-                            formKey: "template_name",
-                            formData: state.formData,
-                            height: 46,
-                            fontSize: 14,
-                            onSubmit: (key, value) {
-                              state.formData[key]!['focusNode'].unfocus();
-                              FocusScope.of(context).requestFocus(state.formData['desc']!['focusNode']);
-                            },
-                            marginTop: 10,
-                          ),
+                          _buildTemplateSelectWidget(),
+                          _buildTemplateJobTitleWidget(),
+
+                          // if(isEdit)
+                          //   //模板名称
+                          //   ...[
+                          //     FormRequireText(text: "Template Title".tr).marginOnly(left: 15, top: 19),
+                          //     CustomTextField(
+                          //       formKey: "template_name",
+                          //       formData: state.formData,
+                          //       height: 46,
+                          //       fontSize: 14,
+                          //       enabled: isAdd ? true:false,
+                          //       onSubmit: (key, value) {
+                          //         state.formData[key]!['focusNode'].unfocus();
+                          //         FocusScope.of(context).requestFocus(state.formData['desc']!['focusNode']);
+                          //       },
+                          //       marginTop: 10,
+                          //     )
+                          //   ],
+                          // if(isAdd)
+                          //   ...[
+                          //     _buildTemplateSelectWidget(),
+                          //     _buildTemplateJobTitleWidget(),
+                          //   ],
+
 
                           //证书
                           Visibility(
-                            visible: state.indexEntity?.certificateList?.isNotEmpty == true,
+                            visible: state.indexOptionEntity?.certificateList?.isNotEmpty == true,
                             child: MyTextView(
                               "Certificate".tr,
                               textColor: Colors.white,
@@ -122,19 +145,19 @@ class _LabourTemplateAddState extends BaseState<UKTemplateAddPage, TemplateAddCo
 
                           // 证书的多选
                           Visibility(
-                            visible: state.indexEntity?.certificateList?.isNotEmpty == true,
+                            visible: state.indexOptionEntity?.certificateList?.isNotEmpty == true,
                             child: CustomCheckBox(
-                              options: state.indexEntity?.certificateList?.map((e) => e.txt!).toList() ?? [],
+                              options: state.indexOptionEntity?.certificateList?.map((e) => e.txt!).toList() ?? [],
                               onOptionsSelected: (selected) {
                                 // 转换选中的索引为对应的 value
                                 state.selectedCertificateList = selected
                                     .map((index) {
-                                      return state.indexEntity?.certificateList?[index].value; // 获取对应的 value
+                                      return state.indexOptionEntity?.certificateList?[index].value; // 获取对应的 value
                                     })
                                     .whereType<String>()
                                     .toList();
                               },
-                              selectedOptions: state.indexEntity?.certificateList?.where((e) => e.checked == "checked").map((e) => e.txt!).toList() ?? [],
+                              selectedOptions: state.indexOptionEntity?.certificateList?.where((e) => e.checked == "checked").map((e) => e.txt!).toList() ?? [],
                             ).marginOnly(left: 15, right: 15, top: 10),
                           ),
 
@@ -150,19 +173,19 @@ class _LabourTemplateAddState extends BaseState<UKTemplateAddPage, TemplateAddCo
 
                           //交通工具的多选
                           Visibility(
-                            visible: state.indexEntity?.vehicleList?.isNotEmpty == true,
+                            visible: state.indexOptionEntity?.vehicleList?.isNotEmpty == true,
                             child: CustomCheckBox(
-                              options: state.indexEntity?.vehicleList?.map((e) => e.txt!).toList() ?? [],
+                              options: state.indexOptionEntity?.vehicleList?.map((e) => e.txt!).toList() ?? [],
                               onOptionsSelected: (selected) {
                                 // 转换选中的索引为对应的 value
                                 state.selectedVehicleList = selected
                                     .map((index) {
-                                  return state.indexEntity?.vehicleList?[index].value; // 获取对应的 value
+                                  return state.indexOptionEntity?.vehicleList?[index].value; // 获取对应的 value
                                 })
                                     .whereType<String>()
                                     .toList();
                               },
-                              selectedOptions: state.indexEntity?.vehicleList?.where((e) => e.checked == "checked").map((e) => e.txt!).toList() ?? [],
+                              selectedOptions: state.indexOptionEntity?.vehicleList?.where((e) => e.checked == "checked").map((e) => e.txt!).toList() ?? [],
                             ).marginOnly(left: 15, right: 15, top: 10),
                           ),
 
@@ -184,9 +207,39 @@ class _LabourTemplateAddState extends BaseState<UKTemplateAddPage, TemplateAddCo
                           //     );
                           //   },
                           //   id: "language",
+                          //   id: "language",
                           //   init: controller,
                           // ).marginOnly(left: 15, right: 15, top: 10),
 
+                          // 联系人 Contact Name
+                          FormRequireText(text: "Contact Name".tr, isRequired: false).marginOnly(left: 15, top: 19),
+                          CustomTextField(
+                            formKey: "contact_name",
+                            formData: state.formData,
+                            height: 46,
+                            fontSize: 14,
+                            onSubmit: (key, value) {
+                              state.formData[key]!['focusNode'].unfocus();
+                              FocusScope.of(context).requestFocus(state.formData['contact_no']!['focusNode']);
+                            },
+                            marginTop: 10,
+                          ),
+
+
+                          // 联系人电话 Contact No
+                          FormRequireText(text: "Contact No".tr, isRequired: false,).marginOnly(left: 15, top: 19),
+                          CustomTextField(
+                            formKey: "contact_no",
+                            formData: state.formData,
+                            height: 46,
+                            fontSize: 14,
+                            onSubmit: (key, value) {
+                              state.formData[key]!['focusNode'].unfocus();
+                              FocusScope.of(context).requestFocus(state.formData['note']!['focusNode']);
+                            },
+                            marginTop: 10,
+                          ),
+
                           //备注
                           MyTextView(
                             "Note".tr,
@@ -239,7 +292,7 @@ class _LabourTemplateAddState extends BaseState<UKTemplateAddPage, TemplateAddCo
                             ),
                           ),
 
-                          //模板详情
+                          // 描述详情
                           MyTextView(
                             "Description".tr,
                             textColor: Colors.white,
@@ -317,4 +370,90 @@ class _LabourTemplateAddState extends BaseState<UKTemplateAddPage, TemplateAddCo
           );
         });
   }
+
+
+  Widget _buildTemplateSelectWidget() {
+    return Container(
+      margin: const EdgeInsets.only(left: 15, right: 15,),
+      child: Column(
+        mainAxisAlignment: MainAxisAlignment.start,
+        crossAxisAlignment: CrossAxisAlignment.start,
+        children: [
+          // template 模板
+          FormRequireText(text: "Template".tr).marginOnly(top: 15),
+          //选择template
+          Container(
+            padding: const EdgeInsets.only(left: 16, right: 10),
+            margin: const EdgeInsets.only(top: 10),
+            height: 45,
+            decoration: BoxDecoration(
+              color:  const Color(0xFF4DCFF6).withOpacity(0.2),
+              borderRadius: BorderRadius.all(Radius.circular(5)),
+            ),
+            child: Row(
+              mainAxisSize: MainAxisSize.max,
+              crossAxisAlignment: CrossAxisAlignment.center,
+              mainAxisAlignment: MainAxisAlignment.start,
+              children: [
+                MyTextView(
+                  state.selectedJobTemplateStr ==null || Utils.isEmpty(state.selectedJobTemplateStr)? '': state.selectedJobTemplateStr! ,
+                  hint: "Choose Template".tr,
+                  textHintColor: ColorConstants.textGrayAECAE5,
+                  fontSize: 14,
+                  isFontMedium: true,
+                  textColor: ColorConstants.white,
+                ).expanded(),
+                const MyAssetImage(Assets.baseServiceTriangleDropDownIcon, width: 11.5, height: 6.28),
+              ],
+            ),
+          ).onTap(() {
+            controller.showChooseTemplatePicker();
+          })
+        ],
+      ),
+    );
+  }
+
+
+  Widget _buildTemplateJobTitleWidget() {
+    return Container(
+      margin: const EdgeInsets.only(left: 15, right: 15,),
+      child: Column(
+        mainAxisAlignment: MainAxisAlignment.start,
+        crossAxisAlignment: CrossAxisAlignment.start,
+        children: [
+          // 工作标题
+          FormRequireText(text: "Job Title".tr).marginOnly(top: 15),
+          //选择template
+          Container(
+            padding: const EdgeInsets.only(left: 16, right: 10),
+            margin: const EdgeInsets.only(top: 10),
+            height: 45,
+            decoration: BoxDecoration(
+              color:  const Color(0xFF4DCFF6).withOpacity(0.2),
+              borderRadius: BorderRadius.all(Radius.circular(5)),
+            ),
+            child: Row(
+              mainAxisSize: MainAxisSize.max,
+              crossAxisAlignment: CrossAxisAlignment.center,
+              mainAxisAlignment: MainAxisAlignment.start,
+              children: [
+                MyTextView(
+                  state.selectedJobTitleStr ==null || Utils.isEmpty(state.selectedJobTitleStr)? '': state.selectedJobTitleStr! ,
+                  hint: "Choose Job Title".tr,
+                  textHintColor: ColorConstants.textGrayAECAE5,
+                  fontSize: 14,
+                  isFontMedium: true,
+                  textColor: ColorConstants.white,
+                ).expanded(),
+                const MyAssetImage(Assets.baseServiceTriangleDropDownIcon, width: 11.5, height: 6.28),
+              ],
+            ),
+          ).onTap(() {
+            controller.showChooseJobTitlePicker();
+          })
+        ],
+      ),
+    );
+  }
 }

+ 34 - 3
packages/cpt_uk/lib/modules/job/template_add/template_add_state.dart

@@ -1,5 +1,7 @@
-import 'package:domain/entity/response/job_template_edit_index_entity.dart';
-import 'package:domain/entity/response/u_k_template_detail_entity.dart';
+
+import 'package:domain/entity/response/uk_template_detail_entity.dart';
+import 'package:domain/entity/response/uk_template_detail_index_entity.dart';
+import 'package:domain/entity/response/uk_template_title_option_entity.dart';
 import 'package:flutter/material.dart';
 import 'package:plugin_basic/basic_export.dart';
 
@@ -13,6 +15,20 @@ class LabourTemplateAddState {
       'hintText': 'Enter...'.tr,
       'obsecure': false,
     },
+    'contact_name': {
+      'value': '',
+      'controller': TextEditingController(),
+      'focusNode': FocusNode(),
+      'hintText': 'Enter...'.tr,
+      'obsecure': false,
+    },
+    'contact_no': {
+      'value': '',
+      'controller': TextEditingController(),
+      'focusNode': FocusNode(),
+      'hintText': 'Enter...'.tr,
+      'obsecure': false,
+    },
     'desc': {
       'value': '',
       'controller': TextEditingController(),
@@ -32,10 +48,25 @@ class LabourTemplateAddState {
 
   final foodHygieneCertOption = ["Yes".tr, "No".tr];
 
+
+  String jobTitle = "";
   String templateId = "";
+  int pageType = 0; // 0:新增 1:编辑
   void Function(dynamic value)? cb;
 
-  UKTemplateDetailEntity? indexEntity;  //新增或者编辑的详情
+  String? selectedJobTemplateStr;  // 新增时选择的模版
+
+  String? get selectedJobTitleId {
+    // 遍历 jobTitleOptionEntityList 中获取 对应的 selectedJobTitleStr 的 id
+    return jobTitleOptionEntityList?.where((e) => e.jobTitle == selectedJobTitleStr)?.first?.id?.toString()?? null;
+  }
+
+  List<UkTemplateTitleOptionEntity>? jobTitleOptionEntityList; // 新增时工作标题的数据源
+  String? selectedJobTitleStr;  // 新增时选择的工作标题
+
+  UkTemplateDetailEntity? indexEntity;  //新增或者编辑的详情
+
+  UkTemplateDetailIndexEntity? indexOptionEntity; // 详情页的 数据源
 
   List<String> selectedCertificateList = [];   //选中的 age 的 id
   List<String> selectedVehicleList = [];   //选中的 language 的 id

+ 46 - 0
packages/cpt_uk/lib/modules/job/template_list/item_template.dart

@@ -104,6 +104,52 @@ class TemplateItem extends StatelessWidget {
             ],
           ).marginOnly(top: 14),
 
+          // 联系人
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "${"Contact Name".tr}:",
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+
+              //文本
+              MyTextView(
+                item.contactName ?? "-",
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor: Colors.white,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ).marginOnly(top: 14),
+
+          // 联系电话
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "${"Contact No".tr}:",
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+
+              //文本
+              MyTextView(
+                item.contactNo ?? "-",
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor: Colors.white,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ).marginOnly(top: 14),
+
           // 创建者
           Row(
             mainAxisSize: MainAxisSize.max,

+ 3 - 3
packages/cpt_uk/lib/modules/job/template_list/template_list_controller.dart

@@ -136,7 +136,7 @@ class TemplateListController extends GetxController with DioCancelableMixin {
 
   //去添加模板的页面
   void gotoTemplateAddPage() {
-    UKTemplateAddPage.startInstance("", (result) {
+    UKTemplateAddPage.startInstance("","", (result) {
       if (result is String) {
         refreshController.callRefresh();
       }
@@ -144,8 +144,8 @@ class TemplateListController extends GetxController with DioCancelableMixin {
   }
 
   //去编辑的页面
-  void gotoEditPage(String templateId) {
-    UKTemplateAddPage.startInstance(templateId, (result) {
+  void gotoEditPage(String templateId, String jobTitle) {
+    UKTemplateAddPage.startInstance(templateId, jobTitle, (result) {
       if (result is String) {
         //编辑完成之后刷机吧
         refreshController.callRefresh();

+ 1 - 1
packages/cpt_uk/lib/modules/job/template_list/template_list_page.dart

@@ -131,7 +131,7 @@ class _LabourTemplateListState extends BaseState<UKTemplateListPage, TemplateLis
                               index: index,
                               item: state.datas[index],
                               onEditAction: () {
-                                controller.gotoEditPage(state.datas[index].id.toString());
+                                controller.gotoEditPage(state.datas[index].id.toString(), state.datas[index].jobTitle?? "");
                               },
                               onDeleteAction: () {
                                 controller.deleteJobTitle(index);

+ 39 - 36
packages/cpt_uk/lib/modules/main/main_controller.dart

@@ -4,10 +4,13 @@ import 'package:cpt_uk/modules/attendance/security_registration/security_registr
 import 'package:cpt_uk/modules/job/job_category/job_category_page.dart';
 import 'package:cpt_uk/modules/report/report_list/report_list_page.dart';
 import 'package:domain/entity/home_module.dart';
+import 'package:domain/entity/response/hotel_info_entity.dart';
 import 'package:domain/repository/auth_repository.dart';
 import 'package:get/get.dart';
+import 'package:plugin_basic/constants/app_constant.dart';
 import 'package:plugin_basic/service/app_config_service.dart';
 import 'package:plugin_basic/service/user_service.dart';
+import 'package:plugin_platform/engine/sp/sp_util.dart';
 import 'package:plugin_platform/engine/toast/toast_engine.dart';
 import 'package:widgets/load_state_layout.dart';
 import 'package:widgets/widget_export.dart';
@@ -63,11 +66,11 @@ class MainController extends GetxController {
 
       if (hotelInfo != null) {
         UserService.to.hotelInfo.value = hotelInfo;
-
-        //展示UK全部的模块
-        state.datas.clear();
-        state.datas.addAll(state.modules);
-        changeLoadingState(LoadState.State_Success);
+        _handleList(hotelInfo.menus);
+        // //展示UK全部的模块
+        // state.datas.clear();
+        // state.datas.addAll(state.modules);
+        // changeLoadingState(LoadState.State_Success);
       } else {
         ToastEngine.show(result.errorMsg ?? "Network Load Error".tr);
       }
@@ -82,36 +85,36 @@ class MainController extends GetxController {
   }
 
   // 处理数据与展示的逻辑
-  // void _handleList(List<HotelInfoMenus>? list) {
-  //   if (list != null && list.isNotEmpty) {
-  //     //有数据,判断是刷新还是加载更多的数据
-  //     state.datas.clear();
-  //
-  //     int? isAdmin = SPUtil.getInt(AppConstant.storageIsAdmin);
-  //     if (isAdmin == 1) {
-  //       //如果是管理员登录,根据Key筛选需要展示的模块
-  //       for (var hotelInfo in list) {
-  //         if (hotelInfo.key != null) {
-  //           state.datas.addAll(_filterModulesByKey(hotelInfo.key!));
-  //         }
-  //       }
-  //     } else {
-  //       //如果只是签到签出模式,手动的添加模块
-  //       state.datas.addAll(_filterModulesByKey("sign"));
-  //     }
-  //
-  //     //更新状态
-  //     changeLoadingState(LoadState.State_Success);
-  //   } else {
-  //     //展示无数据的布局
-  //     state.datas.clear();
-  //     changeLoadingState(LoadState.State_Empty);
-  //   }
-  // }
-
-  // List<HomeModule> _filterModulesByKey(String key) {
-  //   return state.modules.where((module) => module.key == key).toList();
-  // }
+  void _handleList(List<HotelInfoMenus>? list) {
+    if (list != null && list.isNotEmpty) {
+      //有数据,判断是刷新还是加载更多的数据
+      state.datas.clear();
+
+      int? isAdmin = SPUtil.getInt(AppConstant.storageIsAdmin);
+      if (isAdmin == 1) {
+        //如果是管理员登录,根据Key筛选需要展示的模块
+        for (var hotelInfo in list) {
+          if (hotelInfo.key != null) {
+            state.datas.addAll(_filterModulesByKey(hotelInfo.key!));
+          }
+        }
+      } else {
+        //如果只是签到签出模式,手动的添加模块
+        state.datas.addAll(_filterModulesByKey("sign"));
+      }
+
+      //更新状态
+      changeLoadingState(LoadState.State_Success);
+    } else {
+      //展示无数据的布局
+      state.datas.clear();
+      changeLoadingState(LoadState.State_Empty);
+    }
+  }
+
+  List<HomeModule> _filterModulesByKey(String key) {
+    return state.modules.where((module) => module.key == key).toList();
+  }
 
   @override
   void onReady() async {
@@ -122,7 +125,7 @@ class MainController extends GetxController {
   /// 跳转到指定的模块中去
   void gotoModulePage(HomeModule module) {
     switch (module.key) {
-      case 'job':
+      case 'jobs':
         JobCategoryPage.startInstance();
         break;
       case 'device':

+ 1 - 1
packages/cpt_uk/lib/modules/main/main_state.dart

@@ -8,7 +8,7 @@ class MainState {
 
   //全部的模块
   final List<HomeModule> modules = [
-    HomeModule(key: 'job', moduleName: 'Jobs'.tr, moduleIconPath: Assets.mainHomeJobList, iconWidth: 45, iconHeight: 45),
+    HomeModule(key: 'jobs', moduleName: 'Jobs'.tr, moduleIconPath: Assets.mainHomeJobList, iconWidth: 45, iconHeight: 45),
     HomeModule(key: 'device', moduleName: 'Devices'.tr, moduleIconPath: Assets.mainHomeDevices, iconWidth: 45.5, iconHeight: 45.5),
     HomeModule(key: 'registration', moduleName: 'Security Registration'.tr, moduleIconPath: Assets.mainHomeSecurity, iconWidth: 58.5, iconHeight: 44.5),
     HomeModule(key: 'attendance', moduleName: 'E-Attendance'.tr, moduleIconPath: Assets.mainHomeAttendance, iconWidth: 44.5, iconHeight: 44.5),

+ 107 - 37
packages/cpt_uk/lib/modules/report/casual_payout_report/casual_payout_report_controller.dart

@@ -1,19 +1,40 @@
-import 'package:domain/entity/response/staff_request_report_entity.dart';
-import 'package:domain/repository/other_repository.dart';
+import 'package:domain/entity/response/labour_request_index_entity.dart';
+import 'package:domain/entity/response/labour_review_list_entity.dart';
+import 'package:domain/entity/response/uk_report_casual_entity.dart';
+import 'package:domain/repository/labour_repository.dart';
+import 'package:domain/repository/uk_report_repository.dart';
+import 'package:flutter/cupertino.dart';
 import 'package:get/get.dart';
+import 'package:plugin_platform/engine/dialog/dialog_engine.dart';
+import 'package:plugin_platform/engine/loading/loading_engine.dart';
+import 'package:plugin_platform/engine/notify/notify_engine.dart';
+import 'package:plugin_platform/engine/toast/toast_engine.dart';
 import 'package:plugin_platform/http/dio/dio_cancelable_mixin.dart';
+import 'package:plugin_platform/http/http_result.dart';
 import 'package:shared/utils/date_time_utils.dart';
+import 'package:shared/utils/log_utils.dart';
+import 'package:shared/utils/util.dart';
+import 'package:widgets/dialog/app_default_dialog.dart';
 import 'package:widgets/load_state_layout.dart';
 import 'package:widgets/picker/date_picker_util.dart';
-
+import 'package:widgets/widget_export.dart';
 import 'casual_payout_report_state.dart';
 
 class CasualPayoutReportController extends GetxController with DioCancelableMixin {
-  final OtherRepository _otherRepository = Get.find();
+  final UKReportRepository _ukReportRepository = Get.find();
   final CasualPayoutReportState state = CasualPayoutReportState();
 
+  var _curPage = 1;
+  var _needShowPlaceholder = true;
+
+  @override
+  void onInit() {
+    super.onInit();
+    state.startDateTime = DateTimeUtils.getFirstDayOfMonth();
+  }
+
   //页面PlaceHolder的展示
-  LoadState loadingState = LoadState.State_Loading;
+  LoadState loadingState = LoadState.State_Success;
   String? errorMessage;
 
   //刷新页面状态
@@ -22,32 +43,85 @@ class CasualPayoutReportController extends GetxController with DioCancelableMixi
     update();
   }
 
-  //重试
-  void retryRequest() {
+  // Refresh 控制器
+  final EasyRefreshController refreshController = EasyRefreshController(
+    controlFinishRefresh: true,
+    controlFinishLoad: false, // 禁用 上拉
+  );
+
+  // Refresh 刷新事件
+  Future onRefresh() async {
+    _curPage = 1;
+    fetchReportData();
+  }
+
+  // Refresh 加载事件
+  Future loadMore() async {
+    _curPage++;
+    fetchReportData();
+  }
+
+  // 重试请求
+  Future retryRequest() async {
+    _curPage = 1;
+    _needShowPlaceholder = true;
     fetchReportData();
   }
 
-  // 获取当前列表数据
-  void fetchReportData() async {
-    changeLoadingState(LoadState.State_Loading);
+  /// 获取服务器数据,通知消息列表
+  Future fetchReportData() async {
+    if (_needShowPlaceholder) {
+      changeLoadingState(LoadState.State_Loading);
+    }
 
-    var result = await _otherRepository.fetchReportLabour(
-      DateTimeUtils.formatDate(state.startDateTime, format: "yyyy-MM-dd"),
-      DateTimeUtils.formatDate(state.endDateTime, format: "yyyy-MM-dd"),
+    //请求列表数据
+    var listResult = await _ukReportRepository.fetchReportCasualData(
+      month: DateTimeUtils.formatDate(state.startDateTime, format: "yyyy-MM"),
       cancelToken: cancelToken,
     );
 
-    if (result.isSuccess) {
-      state.entity = result.data;
-      state.datas = result.data?.rows ?? [];
-      if (state.datas.isNotEmpty) {
+    LoadingEngine.dismiss();
+
+    // 处理数据
+    if (listResult.isSuccess) {
+      handleList(listResult.data?.rows);
+    } else {
+      errorMessage = listResult.errorMsg;
+      changeLoadingState(LoadState.State_Error);
+    }
+
+    // 最后赋值
+    _needShowPlaceholder = false;
+  }
+
+  // 处理数据与展示的逻辑
+  void handleList(List<UkReportCasualRows>? list) {
+    if (list != null && list.isNotEmpty) {
+      //有数据,判断是刷新还是加载更多的数据
+      if (_curPage == 1) {
+        //刷新的方式
+        state.datas.clear();
+        state.datas.addAll(list);
+        refreshController.finishRefresh();
+
+        //更新展示的状态
         changeLoadingState(LoadState.State_Success);
       } else {
-        changeLoadingState(LoadState.State_Empty);
+        //加载更多
+        state.datas.addAll(list);
+        refreshController.finishLoad();
+        update();
       }
     } else {
-      errorMessage = result.errorMsg ?? "Network Load Error".tr;
-      changeLoadingState(LoadState.State_Error);
+      if (_curPage == 1) {
+        //展示无数据的布局
+        state.datas.clear();
+        changeLoadingState(LoadState.State_Empty);
+        refreshController.finishRefresh();
+      } else {
+        //展示加载完成,没有更多数据了
+        refreshController.finishLoad(IndicatorResult.noMore);
+      }
     }
   }
 
@@ -57,29 +131,25 @@ class CasualPayoutReportController extends GetxController with DioCancelableMixi
     fetchReportData();
   }
 
-  /// 筛选开始日期
-  void pickerStartDate() {
-    DatePickerUtil.showCupertinoDatePicker(
-      selectedDateTime: state.startDateTime,
-      onDateTimeChanged: (date) {
-        state.startDateTime = date;
-        update();
-        fetchReportData();
-      },
-      title: "Start Date".tr,
-    );
+  @override
+  void onClose() {
+    state.datas.clear();
+    super.onClose();
   }
 
-  /// 筛选结束日期
-  void pickerEndDate() {
+  //   年月的日期筛选
+  void showDatePicker() {
     DatePickerUtil.showCupertinoDatePicker(
-      selectedDateTime: state.endDateTime ?? state.startDateTime,
+      selectedDateTime: state.startDateTime ?? DateTime.now(),
+      mode: CupertinoDatePickerMode.monthYear,
       onDateTimeChanged: (date) {
-        state.endDateTime = date;
-        update();
+        state.startDateTime = date;
+        LoadingEngine.show();
         fetchReportData();
+        update();
       },
-      title: "End Date".tr,
+      title: "Select Date".tr,
     );
   }
+
 }

+ 107 - 142
packages/cpt_uk/lib/modules/report/casual_payout_report/casual_payout_report_item.dart

@@ -1,142 +1,107 @@
-import 'package:cs_resources/constants/color_constants.dart';
-import 'package:domain/entity/response/labour_report_entity.dart';
-import 'package:flutter/cupertino.dart';
-import 'package:flutter/material.dart';
-import 'package:flutter/widgets.dart';
-import 'package:plugin_basic/basic_export.dart';
-import 'package:widgets/ext/ex_widget.dart';
-
-import 'package:widgets/my_text_view.dart';
-
-class ReportLabourItem extends StatelessWidget {
-  LabourReportEntity? entity; //主体数据
-  int type; //0 Completed  1 Incomplete  2 Completed + Incomplete
-
-  ReportLabourItem({
-    required this.entity,
-    required this.type,
-  });
-
-  @override
-  Widget build(BuildContext context) {
-    return Container(
-      width: double.infinity,
-      padding: const EdgeInsets.only(top: 16, bottom: 20),
-      margin: const EdgeInsets.symmetric(vertical: 5, horizontal: 15),
-      decoration: BoxDecoration(
-        color: const Color(0xFF4DCFF6).withOpacity(0.2), // 设置背景颜色和不透明度
-        borderRadius: BorderRadius.circular(5), // 设置圆角
-      ),
-      child: Column(
-        crossAxisAlignment: CrossAxisAlignment.start,
-        children: [
-          MyTextView(
-            type == 0
-                ? "Completed".tr
-                : type == 1
-                    ? "Incomplete".tr
-                    : "Completed + Incomplete".tr,
-            fontSize: 14,
-            isFontBold: true,
-            marginBottom: 15,
-            marginLeft: 20,
-            marginRight: 20,
-            textColor: type == 0
-                ? ColorConstants.textGreen0AC074
-                : type == 1
-                    ? ColorConstants.textBlue06D9FF
-                    : ColorConstants.textRedFF6262,
-          ),
-          const Divider(height: 0.5, color: ColorConstants.dividerBar),
-
-          Row(
-            crossAxisAlignment: CrossAxisAlignment.start,
-            children: [
-              MyTextView(
-                "Outlet".tr,
-                fontSize: 14,
-                textColor: Colors.white,
-                isFontRegular: true,
-              ).expanded(),
-              Column(
-                crossAxisAlignment: CrossAxisAlignment.start,
-                children: [
-                  MyTextView("Hours".tr, textColor: Colors.white, fontSize: 14, isFontRegular: true),
-                  MyTextView(
-                    "(${entity?.total?.hrs})",
-                    textColor: type == 0
-                        ? ColorConstants.textGreen0AC074
-                        : type == 1
-                            ? ColorConstants.textBlue06D9FF
-                            : ColorConstants.textRedFF6262,
-                    fontSize: 14,
-                    isFontRegular: true,
-                  ),
-                ],
-              ).expanded(),
-              Column(
-                crossAxisAlignment: CrossAxisAlignment.start,
-                children: [
-                  MyTextView("TotalAmt".tr, textColor: Colors.white, fontSize: 14, isFontRegular: true),
-                  MyTextView(
-                    "(${entity?.total?.agAmt})",
-                    textColor: type == 0
-                        ? ColorConstants.textGreen0AC074
-                        : type == 1
-                            ? ColorConstants.textBlue06D9FF
-                            : ColorConstants.textRedFF6262,
-                    fontSize: 14,
-                    isFontRegular: true,
-                  ),
-                ],
-              ).expanded(),
-            ],
-          ).marginOnly(left: 20, right: 20, top: 18, bottom: 2),
-
-          //底部的实际数据
-          ...(entity?.rows.map((item) {
-                return _childItem(
-                  item.outletName,
-                  type == 0
-                      ? item.hrs
-                      : type == 1
-                          ? item.inHrs
-                          : item.totHrs,
-                  type == 0
-                      ? item.agAmt
-                      : type == 1
-                          ? item.inAgAmt
-                          : item.totAgAmt,
-                );
-              }).toList() ??
-              []),
-        ],
-      ),
-    );
-  }
-
-  Widget _childItem(String? outletName, String? hours, String? agAmt) {
-    return Row(
-      children: [
-        MyTextView(
-          outletName ?? "",
-          fontSize: 14,
-          textColor: Colors.white,
-          isFontRegular: true,
-        ).expanded(),
-        MyTextView(
-          "$hours H",
-          fontSize: 14,
-          textColor: Colors.white,
-          isFontRegular: true,
-        ).expanded(),
-        MyTextView(
-          "\$ $agAmt",
-          fontSize: 14,
-          textColor: Colors.white,
-          isFontRegular: true,
-        ).expanded(),
-      ],
-    ).marginOnly(top: 16, left: 20, right: 20);
-  }
-}
+import 'package:cs_resources/constants/color_constants.dart';
+import 'package:domain/entity/response/uk_report_casual_entity.dart';
+import 'package:flutter/cupertino.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter/widgets.dart';
+import 'package:plugin_basic/basic_export.dart';
+import 'package:widgets/ext/ex_widget.dart';
+import 'package:widgets/my_text_view.dart';
+
+/*
+ * 用工的列表
+ */
+class CasualPayoutReportItem extends StatelessWidget {
+  final int index;
+  final UkReportCasualRows item;
+
+  CasualPayoutReportItem({
+    required this.index,
+    required this.item,
+  });
+
+  @override
+  Widget build(BuildContext context) {
+    return Container(
+      padding: const EdgeInsets.symmetric(vertical: 23, horizontal: 21),
+      margin: const EdgeInsets.only(left: 15, right: 15, top: 5, bottom: 5),
+      decoration: BoxDecoration(
+        color: const Color(0xFF4DCFF6).withOpacity(0.2), // 设置背景颜色和不透明度
+        borderRadius: BorderRadius.circular(5), // 设置圆角
+      ),
+      child: Column(
+        mainAxisSize: MainAxisSize.max,
+        crossAxisAlignment: CrossAxisAlignment.start,
+        children: [
+          // 部门
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "Outlet:".tr,
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+
+              //部门
+              MyTextView(
+                item.outletName??"-",
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor: Colors.white,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ),
+
+          // 小时
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                '${"Hours".tr}:',
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+
+              //文本
+              MyTextView(
+                item.totHrs?.toString()??'-',
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor: Colors.white,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ).marginOnly(top: 15),
+
+          // 总金额
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                '${"TotalAmt".tr}:',
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+
+              //文本
+              MyTextView(
+                item.totAmt?.toString()??"-",
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor: Colors.white,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ).marginOnly(top: 15),
+        ],
+      ),
+    );
+  }
+}

+ 102 - 77
packages/cpt_uk/lib/modules/report/casual_payout_report/casual_payout_report_page.dart

@@ -1,23 +1,28 @@
 import 'package:cs_resources/constants/color_constants.dart';
+import 'package:flutter/cupertino.dart';
 import 'package:flutter/material.dart';
 import 'package:get/get.dart';
 import 'package:shared/utils/date_time_utils.dart';
-import 'package:shared/utils/screen_util.dart';
 import 'package:widgets/ext/ex_widget.dart';
 import 'package:widgets/load_state_layout.dart';
-import 'package:widgets/my_appbar.dart';
 import 'package:widgets/my_text_view.dart';
+import 'package:widgets/widget_export.dart';
 
+import 'casual_payout_report_item.dart';
 import 'casual_payout_report_controller.dart';
 
-import 'package:plugin_basic/base/base_stateless_page.dart';
+import 'package:plugin_basic/base/base_state.dart';
+import 'package:plugin_basic/base/base_stateful_page.dart';
 import 'package:plugin_basic/utils/ext_get_nav.dart';
 import 'package:router/path/router_path.dart';
-
-import 'casual_payout_report_item.dart';
+import 'package:shared/utils/screen_util.dart';
+import 'package:widgets/my_appbar.dart';
 import 'casual_payout_report_state.dart';
 
-class UKCasualPayoutReportPage extends BaseStatelessPage<CasualPayoutReportController> {
+/*
+ * 最后一个Casual payout 的月度报表
+ */
+class UKCasualPayoutReportPage extends BaseStatefulPage<CasualPayoutReportController> {
   UKCasualPayoutReportPage({Key? key}) : super(key: key);
 
   //启动当前页面
@@ -25,98 +30,118 @@ class UKCasualPayoutReportPage extends BaseStatelessPage<CasualPayoutReportContr
     return Get.start(RouterPath.UKReportCasualPayout);
   }
 
+  @override
+  CasualPayoutReportController createRawController() {
+    return CasualPayoutReportController();
+  }
+
+  @override
+  State<UKCasualPayoutReportPage> createState() => _LabourReviewState();
+}
+
+class _LabourReviewState extends BaseState<UKCasualPayoutReportPage, CasualPayoutReportController> {
   late CasualPayoutReportState state;
 
   @override
   void initState() {
+    super.initState();
     state = controller.state;
   }
 
   @override
-  CasualPayoutReportController createRawController() {
-    return CasualPayoutReportController();
-  }
-
-  @override
-  Widget buildWidget(BuildContext context) {
+  Widget build(BuildContext context) {
     return autoCtlGetBuilder(builder: (controller) {
-      return Scaffold(
-        extendBodyBehindAppBar: true,
-        appBar: MyAppBar.appBar(context, "YY Casual Labour Report".tr),
-        body: SafeArea(
+      return SafeArea(
         bottom: MediaQuery.of(context).padding.bottom > 38,
-          top: false,
-          child: Container(
-            width: double.infinity,
-            height: double.infinity,
-            padding: EdgeInsets.only(top: kToolbarHeight + ScreenUtil.getStatusBarH(context) + 1),
-            decoration: const BoxDecoration(
-              gradient: LinearGradient(
-                colors: [
-                  Color(0xFF091D44),
-                  Color(0xFF245A8A),
-                  Color(0xFF7F7CEC),
-                ],
-                begin: Alignment.topCenter,
-                end: Alignment.bottomCenter,
-              ),
+        top: false,
+        child: Container(
+          width: double.infinity,
+          height: double.infinity,
+          padding: EdgeInsets.only(top: ScreenUtil.getStatusBarH(context)),
+          decoration: const BoxDecoration(
+            gradient: LinearGradient(
+              colors: [
+                Color(0xFF091D44),
+                Color(0xFF245A8A),
+                Color(0xFF7F7CEC),
+              ],
+              begin: Alignment.topCenter,
+              end: Alignment.bottomCenter,
             ),
-            child: Column(
-              children: [
-                // 时间筛选
-                Container(
-                    width: double.infinity,
-                    height: 36,
-                    margin: const EdgeInsets.symmetric(vertical: 10, horizontal: 15),
-                    decoration: BoxDecoration(
-                      color: const Color(0xFF4DCFF6).withOpacity(0.2), // 设置背景颜色和不透明度
-                      borderRadius: BorderRadius.circular(20.0), // 设置圆角
-                    ),
-                    child: Row(
-                      children: [
-                        MyTextView(
-                          DateTimeUtils.formatDate(state.startDateTime, format: "yyyy-MM-dd"),
-                          hint: "Start Date".tr,
-                          textHintColor: ColorConstants.textGrayAECAE5,
-                          fontSize: 15,
-                          textAlign: TextAlign.center,
-                          isFontRegular: true,
-                          onClick: controller.pickerStartDate,
-                          textColor: ColorConstants.textGrayAECAE5,
-                        ).expanded(),
-                        Container(color: ColorConstants.dividerBar, height: 21.5, width: 0.5),
-                        MyTextView(
-                          DateTimeUtils.formatDate(state.endDateTime, format: "yyyy-MM-dd"),
-                          hint: "End Date".tr,
-                          textHintColor: ColorConstants.textGrayAECAE5,
-                          fontSize: 15,
-                          textAlign: TextAlign.center,
-                          isFontRegular: true,
-                          onClick: controller.pickerEndDate,
-                          textColor: ColorConstants.textGrayAECAE5,
-                        ).expanded(),
-                      ],
-                    )),
+          ),
+          child: Column(
+            children: [
+              MyAppBar.titleBar(context, "Casual Payout".tr),
 
-                //动态列表
-                LoadStateLayout(
+              //选择时间
+              Container(
+                  width: double.infinity,
+                  height: 36,
+                  margin: const EdgeInsets.symmetric(vertical: 10, horizontal: 15),
+                  decoration: BoxDecoration(
+                    color: const Color(0xFF4DCFF6).withOpacity(0.2), // 设置背景颜色和不透明度
+                    borderRadius: BorderRadius.circular(20.0), // 设置圆角
+                  ),
+                  child: Row(
+                    mainAxisAlignment: MainAxisAlignment.center,
+                    children: [
+                      MyTextView(
+                        DateTimeUtils.formatDate(state.startDateTime, format: "yyyy-MM"),
+                        hint: "Month".tr,
+                        textHintColor: ColorConstants.textGrayAECAE5,
+                        fontSize: 15,
+                        textAlign: TextAlign.center,
+                        isFontRegular: true,
+                        textColor: ColorConstants.textGrayAECAE5,
+                      ).expanded(),
+                    ],
+                  ).onTap(()=>{
+                    controller.showDatePicker()
+                  })),
+
+              Padding(
+                padding: const EdgeInsets.only(left: 15,right: 15),
+                child: Row(
+                    mainAxisSize: MainAxisSize.max,
+                    crossAxisAlignment: CrossAxisAlignment.center,
+                    children: [
+                      MyTextView(
+                        "YY Casual Report By Payout Date (Based the Client Rate)",
+                        isFontMedium: true,
+                        textColor: ColorConstants.textGrayAECAE5,
+                        fontSize: 16,
+                        marginBottom: 10,
+                      ).expanded(),
+                    ]
+                ),
+              ),
+
+              //底部的列表
+              EasyRefresh(
+                controller: controller.refreshController,
+                onRefresh: controller.onRefresh,
+                onLoad: controller.loadMore,
+                child: LoadStateLayout(
                   state: controller.loadingState,
                   errorMessage: controller.errorMessage,
                   errorRetry: () {
                     controller.retryRequest();
                   },
                   successSliverWidget: [
-
-                    SliverList(delegate: SliverChildBuilderDelegate((context, index) {
-                        return ReportLabourItem(entity: state.entity, type: index);
+                    SliverList(
+                        delegate: SliverChildBuilderDelegate(
+                      (context, index) {
+                        return CasualPayoutReportItem(
+                          index: index,
+                          item: state.datas[index],
+                        );
                       },
-                      childCount: state.datas.isNotEmpty ? 3 : 0,
+                      childCount: state.datas.length,
                     ))
-
                   ],
-                ).expanded(),
-              ],
-            ),
+                ),
+              ).expanded(),
+            ],
           ),
         ),
       );

+ 3 - 5
packages/cpt_uk/lib/modules/report/casual_payout_report/casual_payout_report_state.dart

@@ -1,10 +1,8 @@
-import 'package:domain/entity/response/labour_report_entity.dart';
+import 'package:domain/entity/response/uk_report_casual_entity.dart';
 
 class CasualPayoutReportState {
-
   DateTime? startDateTime;
-  DateTime? endDateTime;
 
-  LabourReportEntity? entity;   //主体数据
-  List<LabourReportRows> datas = [];  //列表数据
+  //页面的列表数据
+  List<UkReportCasualRows> datas = [];
 }

+ 45 - 88
packages/cpt_uk/lib/modules/report/casual_report/casual_report_controller.dart

@@ -1,6 +1,8 @@
 import 'package:domain/entity/response/labour_request_index_entity.dart';
 import 'package:domain/entity/response/labour_review_list_entity.dart';
+import 'package:domain/entity/response/uk_report_casual_entity.dart';
 import 'package:domain/repository/labour_repository.dart';
+import 'package:domain/repository/uk_report_repository.dart';
 import 'package:flutter/cupertino.dart';
 import 'package:get/get.dart';
 import 'package:plugin_platform/engine/dialog/dialog_engine.dart';
@@ -18,129 +20,84 @@ import 'package:widgets/widget_export.dart';
 import 'casual_report_state.dart';
 
 class CasualReportController extends GetxController with DioCancelableMixin {
-  final LabourRepository _labourRepository = Get.find();
+  final UKReportRepository _ukReportRepository = Get.find();
   final CasualReportState state = CasualReportState();
 
-  var _curPage = 1;
-  var _needShowPlaceholder = true;
-
   //页面PlaceHolder的展示
-  LoadState loadingState = LoadState.State_Success;
+  LoadState loadingState = LoadState.State_Loading;
   String? errorMessage;
 
+  @override
+  void onInit() {
+    super.onInit();
+    state.startDateTime = DateTimeUtils.getFirstDayOfMonth();
+    state.endDateTime = DateTimeUtils.getLastDayOfMonth();
+  }
+
   //刷新页面状态
   void changeLoadingState(LoadState state) {
     loadingState = state;
     update();
   }
 
-  // Refresh 控制器
-  final EasyRefreshController refreshController = EasyRefreshController(
-    controlFinishRefresh: true,
-    controlFinishLoad: true,
-  );
-
-  // Refresh 刷新事件
-  Future onRefresh() async {
-    _curPage = 1;
-    fetchList();
-  }
-
-  // Refresh 加载事件
-  Future loadMore() async {
-    _curPage++;
-    fetchList();
+  //重试
+  void retryRequest() {
+    fetchReportData();
   }
 
-  // 重试请求
-  Future retryRequest() async {
-    _curPage = 1;
-    _needShowPlaceholder = true;
-    fetchList();
-  }
+  // 获取当前列表数据
+  void fetchReportData() async {
+    changeLoadingState(LoadState.State_Loading);
 
-  /// 获取服务器数据,通知消息列表
-  Future fetchList() async {
-    if (_needShowPlaceholder) {
-      changeLoadingState(LoadState.State_Loading);
-    }
-
-    //请求列表数据
-    var listResult = await _labourRepository.fetchLabourReviewList(
-      "",
-      DateTimeUtils.formatDate(state.selectedDate, format: "yyyy-MM-dd"),
-      DateTimeUtils.formatDate(state.selectedDate, format: "yyyy-MM-dd"),
-      "",
-      curPage: _curPage,
+    var result = await _ukReportRepository.fetchReportCasualPayData(
+      startDate: DateTimeUtils.formatDate(state.startDateTime, format: "yyyy-MM-dd"),
+      endDate: DateTimeUtils.formatDate(state.endDateTime, format: "yyyy-MM-dd"),
       cancelToken: cancelToken,
     );
-    
-    // 处理数据
-    if (listResult.isSuccess) {
-      handleList(listResult.data?.rows);
-    } else {
-      errorMessage = listResult.errorMsg;
-      changeLoadingState(LoadState.State_Error);
-    }
-
-    // 最后赋值
-    _needShowPlaceholder = false;
-  }
 
-  // 处理数据与展示的逻辑
-  void handleList(List<LabourReviewListRows>? list) {
-    if (list != null && list.isNotEmpty) {
-      //有数据,判断是刷新还是加载更多的数据
-      if (_curPage == 1) {
-        //刷新的方式
-        state.datas.clear();
-        state.datas.addAll(list);
-        refreshController.finishRefresh();
-
-        //更新展示的状态
+    if (result.isSuccess) {
+      state.entity = result.data;
+      state.datas = result.data?.rows ?? [];
+      if (state.datas.isNotEmpty) {
         changeLoadingState(LoadState.State_Success);
       } else {
-        //加载更多
-        state.datas.addAll(list);
-        refreshController.finishLoad();
-        update();
-      }
-    } else {
-      if (_curPage == 1) {
-        //展示无数据的布局
-        state.datas.clear();
         changeLoadingState(LoadState.State_Empty);
-        refreshController.finishRefresh();
-      } else {
-        //展示加载完成,没有更多数据了
-        refreshController.finishLoad(IndicatorResult.noMore);
       }
+    } else {
+      errorMessage = result.errorMsg ?? "Network Load Error".tr;
+      changeLoadingState(LoadState.State_Error);
     }
   }
 
   @override
   void onReady() {
     super.onReady();
-    fetchList();
+    fetchReportData();
   }
 
-  @override
-  void onClose() {
-    state.datas.clear();
-    super.onClose();
+  /// 筛选开始日期
+  void pickerStartDate() {
+    DatePickerUtil.showCupertinoDatePicker(
+      selectedDateTime: state.startDateTime,
+      onDateTimeChanged: (date) {
+        state.startDateTime = date;
+        update();
+        fetchReportData();
+      },
+      title: "Start Date".tr,
+    );
   }
 
-  /// 年月的日期筛选
-  void showDatePicker() {
-
+  /// 筛选结束日期
+  void pickerEndDate() {
     DatePickerUtil.showCupertinoDatePicker(
-      selectedDateTime: state.selectedDate ?? DateTime.now(),
-      mode: CupertinoDatePickerMode.monthYear,
+      selectedDateTime: state.endDateTime ?? state.startDateTime,
       onDateTimeChanged: (date) {
-        state.selectedDate = date;
+        state.endDateTime = date;
         update();
+        fetchReportData();
       },
-      title: "Select Date".tr,
+      title: "End Date".tr,
     );
   }
 

+ 228 - 108
packages/cpt_uk/lib/modules/report/casual_report/casual_report_item.dart

@@ -1,108 +1,228 @@
-import 'package:cs_resources/constants/color_constants.dart';
-import 'package:cs_resources/generated/assets.dart';
-import 'package:domain/entity/response/labour_review_list_entity.dart';
-import 'package:flutter/cupertino.dart';
-import 'package:flutter/material.dart';
-import 'package:flutter/widgets.dart';
-import 'package:plugin_basic/basic_export.dart';
-import 'package:widgets/ext/ex_widget.dart';
-import 'package:widgets/my_text_view.dart';
-
-/*
- * 用工的列表
- */
-class CasualReportItem extends StatelessWidget {
-  final int index;
-  final LabourReviewListRows item;
-
-  CasualReportItem({
-    required this.index,
-    required this.item,
-  });
-
-  @override
-  Widget build(BuildContext context) {
-    return Container(
-      padding: const EdgeInsets.symmetric(vertical: 23, horizontal: 21),
-      margin: const EdgeInsets.only(left: 15, right: 15, top: 5, bottom: 5),
-      decoration: BoxDecoration(
-        color: const Color(0xFF4DCFF6).withOpacity(0.2), // 设置背景颜色和不透明度
-        borderRadius: BorderRadius.circular(5), // 设置圆角
-      ),
-      child: Column(
-        mainAxisSize: MainAxisSize.max,
-        crossAxisAlignment: CrossAxisAlignment.start,
-        children: [
-          // 部门
-          Row(
-            mainAxisSize: MainAxisSize.max,
-            crossAxisAlignment: CrossAxisAlignment.center,
-            children: [
-              MyTextView(
-                "Outlet:".tr,
-                isFontRegular: true,
-                textColor: ColorConstants.textGrayAECAE5,
-                fontSize: 14,
-              ),
-
-              //部门
-              MyTextView(
-                item.departmentName ?? "-",
-                marginLeft: 5,
-                isFontRegular: true,
-                textColor: Colors.white,
-                fontSize: 14,
-              ).expanded(),
-            ],
-          ),
-
-          // 小时
-          Row(
-            mainAxisSize: MainAxisSize.max,
-            crossAxisAlignment: CrossAxisAlignment.center,
-            children: [
-              MyTextView(
-                "Hours(2):",
-                isFontRegular: true,
-                textColor: ColorConstants.textGrayAECAE5,
-                fontSize: 14,
-              ),
-
-              //文本
-              MyTextView(
-                "2h",
-                marginLeft: 5,
-                isFontRegular: true,
-                textColor: Colors.white,
-                fontSize: 14,
-              ).expanded(),
-            ],
-          ).marginOnly(top: 15),
-
-          // 总金额
-          Row(
-            mainAxisSize: MainAxisSize.max,
-            crossAxisAlignment: CrossAxisAlignment.center,
-            children: [
-              MyTextView(
-                "TotalAmt(0):",
-                isFontRegular: true,
-                textColor: ColorConstants.textGrayAECAE5,
-                fontSize: 14,
-              ),
-
-              //文本
-              MyTextView(
-                "£ 0",
-                marginLeft: 5,
-                isFontRegular: true,
-                textColor: Colors.white,
-                fontSize: 14,
-              ).expanded(),
-            ],
-          ).marginOnly(top: 15),
-        ],
-      ),
-    );
-  }
-}
+import 'package:cs_resources/constants/color_constants.dart';
+import 'package:domain/entity/response/uk_report_casual_entity.dart';
+import 'package:domain/entity/response/uk_report_casual_pay_entity.dart';
+import 'package:flutter/cupertino.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter/widgets.dart';
+import 'package:plugin_basic/basic_export.dart';
+import 'package:widgets/ext/ex_widget.dart';
+import 'package:widgets/my_text_view.dart';
+
+/*
+ * 用工的列表
+ */
+class CasualReportItem extends StatelessWidget {
+  UkReportCasualPayEntity? entity; //主体数据
+  int type; //0 Completed  1 Incomplete  2 Completed + Incomplete
+
+  CasualReportItem({
+    required this.entity,
+    required this.type,
+  });
+
+  @override
+  Widget build(BuildContext context) {
+    bool isComplated = type == 0;
+    bool isIncomplete = type == 1;
+    bool isCompletedAndIncomplete = type == 2;
+    return Container(
+      width: double.infinity,
+      padding: const EdgeInsets.only(top: 16, bottom: 20),
+      margin: const EdgeInsets.symmetric(vertical: 5, horizontal: 15),
+      decoration: BoxDecoration(
+        color: const Color(0xFF4DCFF6).withOpacity(0.2), // 设置背景颜色和不透明度
+        borderRadius: BorderRadius.circular(5), // 设置圆角
+      ),
+      child: Column(
+        crossAxisAlignment: CrossAxisAlignment.start,
+        children: [
+          MyTextView(
+            isComplated
+                ? "Completed".tr
+                : isIncomplete
+                ? "Incomplete".tr
+                : "Completed + Incomplete".tr,
+            fontSize: 14,
+            isFontBold: true,
+            marginBottom: 15,
+            marginLeft: 20,
+            marginRight: 20,
+            textColor: isComplated
+                ? ColorConstants.textGreen0AC074
+                : isIncomplete
+                ? ColorConstants.textBlue06D9FF
+                : ColorConstants.textRedFF6262,
+          ),
+          const Divider(height: 0.5, color: ColorConstants.dividerBar),
+
+          Row(
+            crossAxisAlignment: CrossAxisAlignment.start,
+            children: [
+
+
+
+              MyTextView(
+                "Outlet".tr,
+                fontSize: 14,
+                textColor: Colors.white,
+                isFontRegular: true,
+              ).expanded(),
+              Column(
+                crossAxisAlignment: CrossAxisAlignment.start,
+                children: [
+                  MyTextView("Hours".tr, textColor: Colors.white, fontSize: 14, isFontRegular: true),
+                  MyTextView(
+                    _getTitleHeaderData(entity!, isComplated, isIncomplete, isCompletedAndIncomplete, 'hours')??'--',
+                    textColor: isComplated
+                        ? ColorConstants.textGreen0AC074
+                        : isIncomplete
+                        ? ColorConstants.textBlue06D9FF
+                        : ColorConstants.textRedFF6262,
+                    fontSize: 14,
+                    isFontRegular: true,
+                  ),
+                ],
+              ).expanded(),
+              Column(
+                crossAxisAlignment: CrossAxisAlignment.start,
+                children: [
+                  MyTextView("Count".tr, textColor: Colors.white, fontSize: 14, isFontRegular: true),
+                  MyTextView(
+                    _getTitleHeaderData(entity!, isComplated, isIncomplete, isCompletedAndIncomplete, 'count')??'--',
+                    textColor: isComplated
+                        ? ColorConstants.textGreen0AC074
+                        : isIncomplete
+                        ? ColorConstants.textBlue06D9FF
+                        : ColorConstants.textRedFF6262,
+                    fontSize: 14,
+                    isFontRegular: true,
+                  ),
+                ],
+              ).expanded(),
+              Column(
+                crossAxisAlignment: CrossAxisAlignment.start,
+                children: [
+                  MyTextView("TotalAmt".tr, textColor: Colors.white, fontSize: 14, isFontRegular: true),
+                  MyTextView(
+                    _getTitleHeaderData(entity!, isComplated, isIncomplete, isCompletedAndIncomplete, 'totalAmount')??'--',
+                    textColor: isComplated
+                        ? ColorConstants.textGreen0AC074
+                        : isIncomplete
+                        ? ColorConstants.textBlue06D9FF
+                        : ColorConstants.textRedFF6262,
+                    fontSize: 14,
+                    isFontRegular: true,
+                  ),
+                ],
+              ).expanded(),
+            ],
+
+          ).marginOnly(left: 20, right: 20, top: 18, bottom: 2),
+
+          //底部的实际数据
+          ...(entity?.rows?.map((item) {
+            return _buildCardContentItemMainContent(
+              item.outletName,
+              _getHours(item, isComplated, isIncomplete, isCompletedAndIncomplete),
+              _getCount(item, isComplated, isIncomplete, isCompletedAndIncomplete),
+              _getAgAmt(item, isComplated, isIncomplete, isCompletedAndIncomplete),
+            );
+          }).toList() ??
+              []),
+        ],
+      ),
+    );
+  }
+
+  String? _getHours(UkReportCasualPayRows item, bool isComplated, bool isIncomplete, bool isCompletedAndIncomplete) {
+    if(isComplated){
+      return item?.hrs?.toString()??'-';
+    }else if(isIncomplete){
+      return item?.inHrs?.toString()??'-';
+    }else {
+      return item?.totHrs?.toString()??'-';
+    }
+
+  }
+
+  String? _getCount(UkReportCasualPayRows item, bool isComplated, bool isIncomplete, bool isCompletedAndIncomplete) {
+    if(isComplated){
+      return item?.num?.toString()??'-';
+    }else if(isIncomplete){
+      return item?.inNum?.toString()??'-';
+    }else {
+      return item?.totNum?.toString()??'-';
+    }
+
+  }
+
+  String? _getAgAmt(UkReportCasualPayRows item, bool isComplated, bool isIncomplete, bool isCompletedAndIncomplete) {
+    if(isComplated){
+      return item?.amt?.toString()??'-';
+    }else if(isIncomplete){
+      return item?.inAmt?.toString()??'-';
+    }else {
+      return item?.totAmt?.toString()??'-';
+    }
+  }
+
+  Widget _buildCardContentItemMainContent(String? outletName, String? hours, String? num,  String? agAmt) {
+    return Row(
+      children: [
+        MyTextView(
+          outletName ?? "",
+          fontSize: 14,
+          textColor: Colors.white,
+          isFontRegular: true,
+        ).expanded(),
+        MyTextView(
+          "$hours H",
+          fontSize: 14,
+          textColor: Colors.white,
+          isFontRegular: true,
+        ).expanded(),
+        MyTextView(
+          "$num",
+          fontSize: 14,
+          textColor: Colors.white,
+          isFontRegular: true,
+        ).expanded(),
+        MyTextView(
+          "\£ $agAmt",
+          fontSize: 14,
+          textColor: Colors.white,
+          isFontRegular: true,
+        ).expanded(),
+      ],
+    ).marginOnly(top: 16, left: 20, right: 20);
+  }
+
+  String? _getTitleHeaderData(UkReportCasualPayEntity entity, bool isComplated, bool isIncomplete, bool isCompletedAndIncomplete, String type) {
+    switch(type){
+      case 'hours':
+        if(isComplated){
+          return entity?.total?.hrs?.toString()??'-';
+        }else if(isIncomplete){
+          return entity?.total?.inHrs?.toString()??'-';
+        }else {
+          return entity?.total?.totHrs?.toString()??'-';
+        }
+      case 'count':
+        if(isComplated){
+          return entity?.total?.num?.toString()??'-';
+        }else if(isIncomplete){
+          return entity?.total?.inNum?.toString()??'-';
+        }else {
+          return entity?.total?.totNum?.toString()??'-';
+        }
+      case 'totalAmount':
+        if(isComplated){
+          return entity?.total?.amt?.toString()??'-';
+        }else if(isIncomplete){
+          return entity?.total?.inAmt?.toString()??'-';
+        }else {
+          return entity?.total?.totAmt?.toString()??'-';
+        }
+    }
+  }
+}

+ 49 - 43
packages/cpt_uk/lib/modules/report/casual_report/casual_report_page.dart

@@ -1,3 +1,4 @@
+import 'package:cs_resources/constants/color_constants.dart';
 import 'package:flutter/cupertino.dart';
 import 'package:flutter/material.dart';
 import 'package:get/get.dart';
@@ -19,7 +20,7 @@ import 'package:widgets/my_appbar.dart';
 import 'casual_report_state.dart';
 
 /*
- * 最后一个Casual的月度报表
+ * Casual 报表
  */
 class UKCasualReportPage extends BaseStatefulPage<CasualReportController> {
   UKCasualReportPage({Key? key}) : super(key: key);
@@ -74,52 +75,57 @@ class _LabourReviewState extends BaseState<UKCasualReportPage, CasualReportContr
 
               //选择时间
               Container(
-                width: double.infinity,
-                height: 42,
-                padding: const EdgeInsets.symmetric(horizontal: 14),
-                margin: const EdgeInsets.only(left: 15, right: 15, top: 10, bottom: 5),
-                decoration: BoxDecoration(
-                  color: const Color(0xFF4DCFF6).withOpacity(0.2), // 设置背景颜色和不透明度
-                  borderRadius: BorderRadius.circular(20), // 设置圆角
-                ),
-                child:Align(
-                  alignment: Alignment.centerLeft, // 左侧对齐
-                  child: MyTextView(
-                    DateTimeUtils.formatDate(state.selectedDate??DateTime.now(),format: "yyyy-MM"),
-                    textColor: Colors.white,
-                    fontSize: 15,
-                    isFontRegular: true,
+                  width: double.infinity,
+                  height: 36,
+                  margin: const EdgeInsets.symmetric(vertical: 10, horizontal: 15),
+                  decoration: BoxDecoration(
+                    color: const Color(0xFF4DCFF6).withOpacity(0.2), // 设置背景颜色和不透明度
+                    borderRadius: BorderRadius.circular(20.0), // 设置圆角
                   ),
-                ),
-              ).onTap((){
-                controller.showDatePicker();
-              }),
+                  child: Row(
+                    children: [
+                      MyTextView(
+                        DateTimeUtils.formatDate(state.startDateTime, format: "yyyy-MM-dd"),
+                        hint: "Start Date".tr,
+                        textHintColor: ColorConstants.textGrayAECAE5,
+                        fontSize: 15,
+                        textAlign: TextAlign.center,
+                        isFontRegular: true,
+                        onClick: controller.pickerStartDate,
+                        textColor: ColorConstants.textGrayAECAE5,
+                      ).expanded(),
+                      Container(color: ColorConstants.dividerBar, height: 21.5, width: 0.5),
+                      MyTextView(
+                        DateTimeUtils.formatDate(state.endDateTime, format: "yyyy-MM-dd"),
+                        hint: "End Date".tr,
+                        textHintColor: ColorConstants.textGrayAECAE5,
+                        fontSize: 15,
+                        textAlign: TextAlign.center,
+                        isFontRegular: true,
+                        onClick: controller.pickerEndDate,
+                        textColor: ColorConstants.textGrayAECAE5,
+                      ).expanded(),
+                    ],
+                  )),
 
-              //底部的列表
-              EasyRefresh(
-                controller: controller.refreshController,
-                onRefresh: controller.onRefresh,
-                onLoad: controller.loadMore,
-                child: LoadStateLayout(
-                  state: controller.loadingState,
-                  errorMessage: controller.errorMessage,
-                  errorRetry: () {
-                    controller.retryRequest();
+              //动态列表
+              LoadStateLayout(
+                state: controller.loadingState,
+                errorMessage: controller.errorMessage,
+                errorRetry: () {
+                  controller.retryRequest();
+                },
+                successSliverWidget: [
+
+                  SliverList(delegate: SliverChildBuilderDelegate((context, index) {
+                    return CasualReportItem(entity: state.entity, type: index);
                   },
-                  successSliverWidget: [
-                    SliverList(
-                        delegate: SliverChildBuilderDelegate(
-                      (context, index) {
-                        return CasualReportItem(
-                          index: index,
-                          item: state.datas[index],
-                        );
-                      },
-                      childCount: state.datas.length,
-                    ))
-                  ],
-                ),
+                    childCount: state.datas.isNotEmpty ? 3 : 0,
+                  ))
+
+                ],
               ).expanded(),
+
             ],
           ),
         ),

+ 6 - 5
packages/cpt_uk/lib/modules/report/casual_report/casual_report_state.dart

@@ -1,9 +1,10 @@
-import 'package:domain/entity/response/labour_request_index_entity.dart';
-import 'package:domain/entity/response/labour_review_list_entity.dart';
+import 'package:domain/entity/response/uk_report_casual_entity.dart';
+import 'package:domain/entity/response/uk_report_casual_pay_entity.dart';
 
 class CasualReportState {
-  DateTime? selectedDate;
+  DateTime? startDateTime;
+  DateTime? endDateTime;
 
-  //页面的列表数据
-  List<LabourReviewListRows> datas = [];
+  UkReportCasualPayEntity? entity;   //主体数据
+  List<UkReportCasualPayRows> datas = [];  //列表数据
 }

+ 3 - 2
packages/cpt_uk/lib/modules/report/finance_report/report_finance_item.dart

@@ -50,6 +50,7 @@ class ReportFinanceItem extends StatelessWidget {
           ).marginOnly(left: 15, top: 16, bottom: 14),
 
           Row(
+            crossAxisAlignment: CrossAxisAlignment.center,
             children: [
               Column(
                 children: [
@@ -62,8 +63,8 @@ class ReportFinanceItem extends StatelessWidget {
                   MyTextView(
                     item.request.toString(),
                     textColor: ColorConstants.textYellowF8AE00,
-                    fontSize: 11,
-                    isFontRegular: true,
+                    fontSize: 13,
+                    isFontBold: true,
                   ),
                 ],
               ),

+ 23 - 35
packages/cpt_uk/lib/modules/report/outlet_staff_report/outlet_staff_report_controller.dart

@@ -1,5 +1,7 @@
 import 'package:domain/entity/response/staff_request_report_entity.dart';
+import 'package:domain/entity/response/uk_report_outlet_entity.dart';
 import 'package:domain/repository/other_repository.dart';
+import 'package:domain/repository/uk_report_repository.dart';
 import 'package:get/get.dart';
 import 'package:plugin_basic/service/app_config_service.dart';
 import 'package:plugin_platform/http/dio/dio_cancelable_mixin.dart';
@@ -11,9 +13,15 @@ import 'package:widgets/picker/date_picker_util.dart';
 import 'outlet_staff_report_state.dart';
 
 class OutletStaffReportController extends GetxController with DioCancelableMixin {
-  final OtherRepository _otherRepository = Get.find();
+  final UKReportRepository _ukReportRepository = Get.find();
   final OutletStaffReportState state = OutletStaffReportState();
 
+  @override
+  void onInit() {
+    super.onInit();
+    state.formatStartDateTime();
+  }
+
   //页面PlaceHolder的展示
   LoadState loadingState = LoadState.State_Loading;
   String? errorMessage;
@@ -33,41 +41,21 @@ class OutletStaffReportController extends GetxController with DioCancelableMixin
   void fetchReportData() async {
     changeLoadingState(LoadState.State_Loading);
 
-    //根据不同的国家,调用不同的接口
-    if (ConfigService.to.selectCountry.value == 1) {
-      //如果是新加坡版本的
-      var result = await _otherRepository.fetchReportStaffRequest(
-        DateTimeUtils.formatDate(state.startDateTime, format: "yyyy-MM-dd"),
-        DateTimeUtils.formatDate(state.endDateTime, format: "yyyy-MM-dd"),
-        cancelToken: cancelToken,
-      );
-      if (result.isSuccess) {
-        state.datas = result.list
-                ?.whereType<StaffRequestReportEntity>() // 直接过滤出非 null 的 StaffRequestReportEntity
-                .toList() ??
-            [];
-        changeLoadingState(LoadState.State_Success);
-      } else {
-        errorMessage = result.errorMsg ?? "Network Load Error".tr;
-        changeLoadingState(LoadState.State_Error);
-      }
+    //如果是越南的版本
+    var result = await _ukReportRepository.fetchReportOutletData(
+      startDate: DateTimeUtils.formatDate(state.startDateTime, format: "yyyy-MM-dd"),
+      endDate: DateTimeUtils.formatDate(state.endDateTime, format: "yyyy-MM-dd"),
+      cancelToken: cancelToken,
+    );
+    if (result.isSuccess) {
+      state.datas = result.data?.requestList
+          ?.whereType<UkReportOutletRequestList>() // 直接过滤出非 null 的 StaffRequestReportEntity
+          .toList() ??
+          [];
+      changeLoadingState(LoadState.State_Success);
     } else {
-      //如果是越南的版本
-      var result = await _otherRepository.fetchStaffReportVN(
-        DateTimeUtils.formatDate(state.startDateTime, format: "yyyy-MM-dd"),
-        DateTimeUtils.formatDate(state.endDateTime, format: "yyyy-MM-dd"),
-        cancelToken: cancelToken,
-      );
-      if (result.isSuccess) {
-        state.datas = result.data?.requestList
-                .whereType<StaffRequestReportEntity>() // 直接过滤出非 null 的 StaffRequestReportEntity
-                .toList() ??
-            [];
-        changeLoadingState(LoadState.State_Success);
-      } else {
-        errorMessage = result.errorMsg ?? "Network Load Error".tr;
-        changeLoadingState(LoadState.State_Error);
-      }
+      errorMessage = result.errorMsg ?? "Network Load Error".tr;
+      changeLoadingState(LoadState.State_Error);
     }
   }
 

+ 2 - 2
packages/cpt_uk/lib/modules/report/outlet_staff_report/outlet_staff_report_item.dart

@@ -1,5 +1,5 @@
 import 'package:cs_resources/constants/color_constants.dart';
-import 'package:domain/entity/response/staff_request_report_entity.dart';
+import 'package:domain/entity/response/uk_report_outlet_entity.dart';
 import 'package:flutter/cupertino.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter/widgets.dart';
@@ -10,7 +10,7 @@ import 'package:widgets/my_text_view.dart';
 import 'package:widgets/shatter/custom_progress_bar.dart';
 
 class OutletStaffReportItem extends StatelessWidget {
-  final StaffRequestReportEntity item;
+  final UkReportOutletRequestList item;
 
   OutletStaffReportItem({
     required this.item,

+ 7 - 3
packages/cpt_uk/lib/modules/report/outlet_staff_report/outlet_staff_report_state.dart

@@ -1,9 +1,13 @@
-import 'package:domain/entity/response/staff_request_report_entity.dart';
+import 'package:domain/entity/response/uk_report_outlet_entity.dart';
 
 class OutletStaffReportState {
 
   DateTime? startDateTime;
-  DateTime? endDateTime;
+  // startDateTime 为 当月的 1号
+  formatStartDateTime() {
+    startDateTime = DateTime(endDateTime!.year, endDateTime!.month, 1);
+  }
+  DateTime? endDateTime = DateTime.now().add(Duration(days: 0));
 
-  List<StaffRequestReportEntity> datas = [];  //列表数据
+  List<UkReportOutletRequestList> datas = [];  //列表数据
 }

+ 9 - 8
packages/cpt_uk/lib/modules/report/report_list/report_list_controller.dart

@@ -60,28 +60,29 @@ class ReportListController extends GetxController {
 
   /// 跳转到指定的模块中去
   void gotoReportPage(HomeModule module) {
+    Log.d("点击的 module  ${module.key}");
     switch (module.key) {
-      case 'labour':
+      case 'labRep':
         UKLabourReportPage.startInstance();
         break;
-      case 'outlet':
+      case 'monReq':
         UKOutletStaffReportPage.startInstance();
         break;
-      case 'finale':
+      case 'finRep':
         UKReportFinancePage.startInstance();
         break;
-      case 'hours':
+      case 'workHours':
         UKWorkingHoursReportPage.startInstance();
         break;
       case 'attendance':
         UKAttendanceReportPage.startInstance();
         break;
-      case 'payout':
-        UKCasualPayoutReportPage.startInstance();
-        break;
-      case 'casual':
+      case 'casRep':
         UKCasualReportPage.startInstance();
         break;
+      case 'casLab':
+        UKCasualPayoutReportPage.startInstance();
+        break;
     }
   }
 }

+ 6 - 6
packages/cpt_uk/lib/modules/report/report_list/report_list_state.dart

@@ -8,13 +8,13 @@ class ReportListState {
 
   //全部的模块
   final List<HomeModule> modules = [
-    HomeModule(key: 'labour', moduleName: 'Labour Request'.tr, moduleIconPath: Assets.cptReportUkReportLabour, iconWidth: 40, iconHeight: 40),
-    HomeModule(key: 'outlet', moduleName: 'Outlet Request'.tr, moduleIconPath: Assets.cptReportUkReportOutlet, iconWidth: 40, iconHeight: 40),
-    HomeModule(key: 'finale', moduleName: 'Finance Report'.tr, moduleIconPath: Assets.cptReportUkReportFinale, iconWidth: 40, iconHeight: 40),
-    HomeModule(key: 'hours', moduleName: 'Working Hours'.tr, moduleIconPath: Assets.cptReportUkReportWorkHours, iconWidth: 40, iconHeight: 40),
+    HomeModule(key: 'labRep', moduleName: 'Labour Request'.tr, moduleIconPath: Assets.cptReportUkReportLabour, iconWidth: 40, iconHeight: 40),
+    HomeModule(key: 'monReq', moduleName: 'Outlet Request'.tr, moduleIconPath: Assets.cptReportUkReportOutlet, iconWidth: 40, iconHeight: 40),
+    HomeModule(key: 'finRep', moduleName: 'Finance Report'.tr, moduleIconPath: Assets.cptReportUkReportFinale, iconWidth: 40, iconHeight: 40),
+    HomeModule(key: 'workHours', moduleName: 'Working Hours'.tr, moduleIconPath: Assets.cptReportUkReportWorkHours, iconWidth: 40, iconHeight: 40),
     HomeModule(key: 'attendance', moduleName: 'E-Attendance'.tr, moduleIconPath: Assets.cptReportUkReportAttendance, iconWidth: 40, iconHeight: 40),
-    HomeModule(key: 'payout', moduleName: 'Casual Payout'.tr, moduleIconPath: Assets.cptReportUkReportCasualPayout, iconWidth: 40, iconHeight: 40),
-    HomeModule(key: 'casual', moduleName: 'Casual Report'.tr, moduleIconPath: Assets.cptReportUkReportCasual, iconWidth: 40, iconHeight: 40),
+    HomeModule(key: 'casRep', moduleName: 'Casual Report'.tr, moduleIconPath: Assets.cptReportUkReportCasual, iconWidth: 40, iconHeight: 40),
+    HomeModule(key: 'casLab', moduleName: 'Casual Payout'.tr, moduleIconPath: Assets.cptReportUkReportCasualPayout, iconWidth: 40, iconHeight: 40),
   ];
 
 }

+ 63 - 17
packages/cpt_uk/lib/modules/review/attendance_review_list/attendance_review_controller.dart

@@ -1,21 +1,29 @@
 import 'package:domain/entity/response/attendance_review_entity.dart';
+import 'package:domain/entity/response/uk_attendance_review_entity.dart';
+import 'package:domain/entity/response/uk_attendance_review_remark_entity.dart';
 import 'package:domain/repository/job_repository.dart';
+import 'package:domain/repository/uk_job_repository.dart';
 import 'package:get/get.dart';
 import 'package:plugin_platform/engine/dialog/dialog_engine.dart';
+import 'package:plugin_platform/engine/loading/loading_engine.dart';
 import 'package:plugin_platform/engine/notify/notify_engine.dart';
 import 'package:plugin_platform/engine/toast/toast_engine.dart';
 import 'package:plugin_platform/http/dio/dio_cancelable_mixin.dart';
+import 'package:plugin_platform/http/http_result.dart';
 
 import 'package:shared/utils/log_utils.dart';
 import 'package:widgets/dialog/app_default_dialog.dart';
 import 'package:widgets/load_state_layout.dart';
 import 'package:widgets/widget_export.dart';
 
+import '../../job/job_applied_workflow/applied_workflow_page.dart';
 import 'attendance_review_reject_dialog.dart';
+import 'attendance_review_remark_dialog.dart';
 import 'attendance_review_state.dart';
 
 class AttendanceReviewController extends GetxController with DioCancelableMixin {
   final JobRepository _jobRepository = Get.find();
+  final UKJobRepository _ukJobRepository = Get.find();
   final AttendanceReviewState state = AttendanceReviewState();
 
   var _curPage = 1;
@@ -62,8 +70,7 @@ class AttendanceReviewController extends GetxController with DioCancelableMixin
       changeLoadingState(LoadState.State_Loading);
     }
 
-    // 并发执行两个请求
-    final listResult = await _jobRepository.fetchAttendanceReviewList(
+    final listResult = await _ukJobRepository.fetchAttendanceReviewList(
       state.keyword,
       curPage: _curPage,
       cancelToken: cancelToken,
@@ -82,7 +89,7 @@ class AttendanceReviewController extends GetxController with DioCancelableMixin
   }
 
   // 处理数据与展示的逻辑
-  void handleList(List<AttendanceReviewRows>? list) {
+  void handleList(List<UkAttendanceReviewRows>? list) {
     if (list != null && list.isNotEmpty) {
       //有数据,判断是刷新还是加载更多的数据
       if (_curPage == 1) {
@@ -141,17 +148,19 @@ class AttendanceReviewController extends GetxController with DioCancelableMixin
   }
 
   /// Item选中与未选中设置
-  void doSelectedOrNot(AttendanceReviewRows data) {
+  void doSelectedOrNot(UkAttendanceReviewRows data) {
     data.isSelected = !data.isSelected;
     Log.d("isSelected:${data.isSelected}");
     update();
   }
 
   /// 执行批量同意
-  void _requestBatchApprove(String recordIds) async {
+  void _requestBatchApprove(String recordIds, String? auditMark) async {
     //执行请求
-    var result = await _jobRepository.approveAttendanceReviews(
+    var result = await _ukJobRepository.attendanceReviewsBatchSubmit(
       recordIds,
+      'approve', //审核类型Type【approve|reject】
+      auditMark,
       cancelToken: cancelToken,
     );
 
@@ -159,7 +168,7 @@ class AttendanceReviewController extends GetxController with DioCancelableMixin
       NotifyEngine.showSuccess("Successful".tr);
 
       //调用接口刷新指定的Staff的信息
-      _removeItemsByList(recordIds);
+      _removeItemsByIds(recordIds);
     } else {
       ToastEngine.show(result.errorMsg ?? "Network Load Error".tr);
       return;
@@ -167,11 +176,12 @@ class AttendanceReviewController extends GetxController with DioCancelableMixin
   }
 
   /// 执行批量拒绝
-  void _requestBatchReject(String recordIds, String? reason) async {
+  void _requestBatchReject(String recordIds, String? auditMark) async {
     //执行请求
-    var result = await _jobRepository.rejectLabourReviews(
+    var result = await _ukJobRepository.attendanceReviewsBatchSubmit(
       recordIds,
-      reason,
+      'reject', //审核类型Type【approve|reject】
+      auditMark,
       cancelToken: cancelToken,
     );
 
@@ -179,7 +189,7 @@ class AttendanceReviewController extends GetxController with DioCancelableMixin
       NotifyEngine.showSuccess("Successful".tr);
 
       //调用接口刷新指定的Staff的信息
-      _removeItemsByList(recordIds);
+      _removeItemsByIds(recordIds);
     } else {
       ToastEngine.show(result.errorMsg ?? "Network Load Error".tr);
       return;
@@ -200,7 +210,7 @@ class AttendanceReviewController extends GetxController with DioCancelableMixin
           title: "Message".tr,
           message: "Are you sure you want to setting approved?".tr,
           confirmAction: () {
-            _requestBatchApprove(recordIds);
+            _requestBatchApprove(recordIds, '');
           },
         ),
       );
@@ -232,18 +242,54 @@ class AttendanceReviewController extends GetxController with DioCancelableMixin
   }
 
   /// 删除对应的recordId的Item数据
-  void _removeItemsByList(String recordIds) {
+  void _removeItemsByIds(String recordIds) {
+    // Log.d("需要移除的recordIds  ${recordIds}");
     // 将逗号分隔的字符串转换为数组
     List<String> recordIdList = recordIds.split(',');
-
     // 移除列表中符合条件的项
-    state.datas.removeWhere((e) => recordIdList.contains(e.recordId));
+    state.datas.removeWhere((e) {
+      final recordIdStr = e.recordId?.toString();
+      final shouldRemove = recordIdStr != null && recordIdList.contains(recordIdStr);
+      if (shouldRemove) {
+        Log.d("移除项目 recordId: ${recordIdStr}");
+      }
+      return shouldRemove;
+    });
 
+    Log.d("移除后的 state.datas   ${state.datas}");
     update();
+
   }
 
   /// 去用工审核流程页面
-  void gotoStatusViewPage(AttendanceReviewRows data) {
-    ToastEngine.show("去工作流页面");
+  void gotoStatusViewPage(UkAttendanceReviewRows data) {
+    UKAppliedWorkflowPage.startInstance(data.appliedId?.toString());
+  }
+
+  /// 获取remark info
+  Future<UkAttendanceReviewRemarkEntity> getRemarkInfo(String appliedId) async {
+    final result = await _ukJobRepository.fetchAttendanceReviewRemarkInfo(appliedId);
+    if(result.isSuccess){
+      return result.data!;
+    }else {
+      return HttpResult(isSuccess: false) as UkAttendanceReviewRemarkEntity;
+    }
+  }
+
+  /// 显示 remarks 弹框
+  void showRemarkDialog(UkAttendanceReviewRows data) async{
+    // 先获取 remark info
+    LoadingEngine.show();
+    final result = await getRemarkInfo(data.appliedId.toString());
+    Log.d("result   ---- ${result}");
+    LoadingEngine.dismiss();
+    DialogEngine.show(
+      widget: AttendaceReviewRemarkDialog(
+        remarkInfo: result,
+        confirmAction: (reason) {
+
+        },
+      ),
+    );
   }
 }

+ 69 - 63
packages/cpt_uk/lib/modules/review/attendance_review_list/attendance_review_item.dart

@@ -1,12 +1,14 @@
 import 'package:cs_resources/constants/color_constants.dart';
 import 'package:cs_resources/generated/assets.dart';
 import 'package:domain/entity/response/attendance_review_entity.dart';
+import 'package:domain/entity/response/uk_attendance_review_entity.dart';
 import 'package:flutter/cupertino.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter/widgets.dart';
 import 'package:plugin_basic/basic_export.dart';
 import 'package:shared/utils/util.dart';
 import 'package:widgets/ext/ex_widget.dart';
+import 'package:widgets/my_button.dart';
 import 'package:widgets/my_load_image.dart';
 import 'package:widgets/my_text_view.dart';
 
@@ -15,14 +17,18 @@ import 'package:widgets/my_text_view.dart';
  */
 class AttendanceReviewItem extends StatelessWidget {
   final int index;
-  final AttendanceReviewRows item;
+  final UkAttendanceReviewRows item;
+  final VoidCallback? onEditAction;
   final VoidCallback? onStatusAction;
+  final VoidCallback? onRemarkAction;
   final VoidCallback? onItemAction;
 
   AttendanceReviewItem({
     required this.index,
     required this.item,
+    this.onEditAction,
     this.onStatusAction,
+    this.onRemarkAction,
     this.onItemAction,
   });
 
@@ -258,68 +264,68 @@ class AttendanceReviewItem extends StatelessWidget {
           ).marginOnly(top: 12),
 
           // //按钮组
-          // Visibility(
-          //   visible: item.actionList?.isNotEmpty ?? false,
-          //   child: Row(
-          //     mainAxisSize: MainAxisSize.max,
-          //     mainAxisAlignment: MainAxisAlignment.end,
-          //     crossAxisAlignment: CrossAxisAlignment.center,
-          //     children: [
-          //       //编辑按钮
-          //       Visibility(
-          //         visible: item.actionList?.contains("edit") ?? false,
-          //         child: MyButton(
-          //           onPressed: () {
-          //             FocusScope.of(context).unfocus();
-          //             onEditAction?.call();
-          //           },
-          //           text: "Edit".tr,
-          //           textColor: ColorConstants.white,
-          //           backgroundColor: hexToColor(
-          //             "#FFBB1B",
-          //           ),
-          //           radius: 17.25,
-          //           minWidth: 60,
-          //           minHeight: 35,
-          //         ).marginOnly(left: 12),
-          //       ),
-          //
-          //       //状态工作流按钮
-          //       Visibility(
-          //         visible: item.actionList?.contains("status") ?? false,
-          //         child: MyButton(
-          //           onPressed: () {
-          //             FocusScope.of(context).unfocus();
-          //             onStatusAction?.call();
-          //           },
-          //           text: "Status".tr,
-          //           textColor: ColorConstants.white,
-          //           backgroundColor: hexToColor("#0AC074"),
-          //           radius: 17.25,
-          //           minWidth: 60,
-          //           minHeight: 35,
-          //         ).marginOnly(left: 12),
-          //       ),
-          //
-          //       //Remark按钮
-          //       Visibility(
-          //         visible: item.actionList?.contains("remarks") ?? false,
-          //         child: MyButton(
-          //           onPressed: () {
-          //             FocusScope.of(context).unfocus();
-          //             onRemarkAction?.call();
-          //           },
-          //           text: "Remarks".tr,
-          //           textColor: ColorConstants.white,
-          //           backgroundColor: hexToColor("#56AAFF"),
-          //           radius: 17.25,
-          //           minWidth: 60,
-          //           minHeight: 35,
-          //         ).marginOnly(left: 12),
-          //       ),
-          //     ],
-          //   ).marginOnly(top: 15),
-          // ),
+          Visibility(
+            visible: item.actionList?.isNotEmpty ?? false,
+            child: Row(
+              mainAxisSize: MainAxisSize.max,
+              mainAxisAlignment: MainAxisAlignment.end,
+              crossAxisAlignment: CrossAxisAlignment.center,
+              children: [
+                //编辑按钮
+                // Visibility(
+                //   visible: item.actionList?.contains("edit") ?? false,
+                //   child: MyButton(
+                //     onPressed: () {
+                //       FocusScope.of(context).unfocus();
+                //       onEditAction?.call();
+                //     },
+                //     text: "Edit".tr,
+                //     textColor: ColorConstants.white,
+                //     backgroundColor: hexToColor(
+                //       "#FFBB1B",
+                //     ),
+                //     radius: 17.25,
+                //     minWidth: 60,
+                //     minHeight: 35,
+                //   ).marginOnly(left: 12),
+                // ),
+
+                //状态工作流按钮
+                Visibility(
+                  visible: item.actionList?.contains("status") ?? false,
+                  child: MyButton(
+                    onPressed: () {
+                      FocusScope.of(context).unfocus();
+                      onStatusAction?.call();
+                    },
+                    text: "Status".tr,
+                    textColor: ColorConstants.white,
+                    backgroundColor: hexToColor("#0AC074"),
+                    radius: 17.25,
+                    minWidth: 60,
+                    minHeight: 35,
+                  ).marginOnly(left: 12),
+                ),
+
+                //Remark按钮
+                Visibility(
+                  visible: item.actionList?.contains("remark") ?? false,
+                  child: MyButton(
+                    onPressed: () {
+                      FocusScope.of(context).unfocus();
+                      onRemarkAction?.call();
+                    },
+                    text: "Remarks".tr,
+                    textColor: ColorConstants.white,
+                    backgroundColor: hexToColor("#56AAFF"),
+                    radius: 17.25,
+                    minWidth: 60,
+                    minHeight: 35,
+                  ).marginOnly(left: 12),
+                ),
+              ],
+            ).marginOnly(top: 15),
+          ),
         ],
       ),
     ).onTap(() {

+ 4 - 1
packages/cpt_uk/lib/modules/review/attendance_review_list/attendance_review_page.dart

@@ -117,11 +117,14 @@ class _LabourReviewState extends BaseState<UKAttendanceReviewPage, AttendanceRev
                           index: index,
                           item: state.datas[index],
                           onStatusAction: () {
-
+                            controller.gotoStatusViewPage(state.datas[index]);
                           },
                           onItemAction: () {
                             controller.doSelectedOrNot(state.datas[index]);
                           },
+                          onRemarkAction: () {
+                            controller.showRemarkDialog(state.datas[index]);
+                          },
                         );
                       },
                       childCount: state.datas.length,

+ 219 - 0
packages/cpt_uk/lib/modules/review/attendance_review_list/attendance_review_remark_dialog.dart

@@ -0,0 +1,219 @@
+import 'dart:ui';
+
+import 'package:cs_resources/generated/assets.dart';
+import 'package:domain/entity/response/uk_attendance_review_entity.dart';
+import 'package:domain/entity/response/uk_attendance_review_remark_entity.dart';
+import 'package:flutter/cupertino.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter/widgets.dart';
+import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
+import 'package:get/get.dart';
+import 'package:plugin_platform/engine/toast/toast_engine.dart';
+import 'package:shared/utils/util.dart';
+import 'package:widgets/ext/ex_widget.dart';
+import 'package:cs_resources/constants/color_constants.dart';
+import 'package:widgets/my_load_image.dart';
+import 'package:widgets/my_text_view.dart';
+import 'package:widgets/widget_export.dart';
+
+/*
+ * remark的弹窗
+ */
+class AttendaceReviewRemarkDialog extends StatefulWidget {
+
+  UkAttendanceReviewRemarkEntity? remarkInfo;
+  void Function(String reason)? confirmAction;
+
+  AttendaceReviewRemarkDialog({this.confirmAction, this.remarkInfo});
+
+  @override
+  State<AttendaceReviewRemarkDialog> createState() => _AttendaceReviewRemarkDialogState();
+}
+
+class _AttendaceReviewRemarkDialogState extends State<AttendaceReviewRemarkDialog> {
+
+  late TextEditingController _controller;
+  late FocusNode _focusNode;
+
+  @override
+  void initState() {
+    super.initState();
+    _controller = TextEditingController();
+    _focusNode = FocusNode();
+
+    _controller.text = widget.remarkInfo?.remark??'-';
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return Column(
+      crossAxisAlignment: CrossAxisAlignment.center,
+      mainAxisAlignment: MainAxisAlignment.center,
+      children: [
+        //Title (如果使用 Container 为最外层容器则默认为 match_parent 的效果,除非我们限制宽度和最大高度最小高度)
+        Stack(
+          children: [
+            Container(
+              width: double.infinity,
+              decoration: const BoxDecoration(
+                color: Colors.white,
+                borderRadius: BorderRadius.all(Radius.circular(15)),
+              ),
+              child: Column(
+                crossAxisAlignment: CrossAxisAlignment.start,
+                children: [
+                  Center(
+                    child: MyTextView(
+                      "Remarks".tr,
+                      fontSize: 19,
+                      isFontMedium: true,
+                      textColor: ColorConstants.black,
+                      marginTop: 23,
+                      marginLeft: 22,
+                      marginRight: 22,
+                    ),
+                  ),
+
+                  MyTextView(
+                    widget.remarkInfo?.memberName ?? "",
+                    fontSize: 16,
+                    textColor: ColorConstants.black,
+                    marginTop: 10,
+                    marginLeft: 22,
+                    marginRight: 22,
+                  ),
+
+                  IgnoreKeyboardDismiss(
+                    child: Container(
+                      height: 130,
+                      margin: const EdgeInsets.symmetric(vertical: 19, horizontal: 22),
+                      padding: const EdgeInsets.symmetric(vertical: 15, horizontal: 15),
+                      decoration: BoxDecoration(
+                        color: const Color(0xFFF0F0F0),
+                        border: Border.all(
+                          color: const Color(0xFFD8D8D8),
+                          width: 0.5,
+                        ),
+                      ),
+                      child: TextField(
+                        cursorColor: ColorConstants.black66,
+                        cursorWidth: 1.5,
+                        autofocus: false,
+                        enabled: false,  // 禁止输入
+                        focusNode: _focusNode,
+                        controller: _controller,
+                        // 装饰
+                        decoration: const InputDecoration(
+                          isDense: true,
+                          isCollapsed: true,
+                          border: InputBorder.none,
+                          // hintText: "Enter...".tr,
+                          hintText: "",
+                          hintStyle: TextStyle(
+                            color: ColorConstants.black66,
+                            fontSize: 15.0,
+                            fontWeight: FontWeight.w400,
+                          ),
+
+                        ),
+                        style: const TextStyle(
+                          color: ColorConstants.black,
+                          fontSize: 15.0,
+                          fontWeight: FontWeight.w400,
+                        ),
+                        // 键盘动作右下角图标
+                        textInputAction: TextInputAction.done,
+                        onSubmitted: (value) {
+                          // doCallbackAction();
+                        },
+                      ),
+                    ),
+                  ),
+
+                  // 分割线
+                  Container(
+                    color: const Color(0XFFCECECE),
+                    height: 0.5,
+                  ),
+
+                  //按钮组
+                  Visibility(
+                    visible: false,
+                    child: Row(
+                      children: [
+                        Expanded(
+                            flex: 1,
+                            child: InkWell(
+                              onTap: () {
+                                onCancel();
+                              },
+                              child: MyTextView(
+                                "Cancel".tr,
+                                fontSize: 17.5,
+                                isFontMedium: true,
+                                textAlign: TextAlign.center,
+                                textColor: const Color(0XFF0085C4),
+                                cornerRadius: 3,
+                                borderWidth: 1,
+                              ),
+                            )),
+                        Container(
+                          color: const Color(0xff09141F).withOpacity(0.13),
+                          width: 0.5,
+                        ),
+                        Expanded(
+                            flex: 1,
+                            child: InkWell(
+                              onTap: () {
+                                doCallbackAction();
+                              },
+                              child: MyTextView(
+                                "Submit".tr,
+                                marginLeft: 10,
+                                fontSize: 17.5,
+                                isFontMedium: true,
+                                textAlign: TextAlign.center,
+                                textColor: const Color(0XFF0085C4),
+                                cornerRadius: 3,
+                              ),
+                            )),
+                      ],
+                    ).constrained(height: 46),
+                  ),
+                ],
+              ),
+            ),
+            Positioned(
+              top: 15,
+              right: 15,
+              child: const MyAssetImage(Assets.baseLibDialogCloseRed, width: 20.5, height: 20.5).onTap((){
+                SmartDialog.dismiss();
+              }),
+            )
+          ]
+        ),
+      ],
+    ).constrained(width: 285);
+  }
+
+  //取消弹框
+  void onCancel() async {
+    SmartDialog.dismiss();
+  }
+
+  //执行回调
+  void doCallbackAction() {
+    _focusNode.unfocus();
+
+    final content = _controller.text.toString();
+
+    if (Utils.isEmpty(content)) {
+      ToastEngine.show("Please Enter Reason".tr);
+      return;
+    }
+
+    onCancel();
+
+    widget.confirmAction?.call(content);
+  }
+}

+ 2 - 2
packages/cpt_uk/lib/modules/review/attendance_review_list/attendance_review_state.dart

@@ -1,4 +1,4 @@
-import 'package:domain/entity/response/attendance_review_entity.dart';
+import 'package:domain/entity/response/uk_attendance_review_entity.dart';
 import 'package:flutter/material.dart';
 
 class AttendanceReviewState {
@@ -7,6 +7,6 @@ class AttendanceReviewState {
   String keyword = "";
 
   //页面的列表数据
-  List<AttendanceReviewRows> datas = [];
+  List<UkAttendanceReviewRows> datas = [];
 
 }

+ 380 - 69
packages/cpt_uk/lib/modules/review/labour_review_edit/labour_review_edit_controller.dart

@@ -1,46 +1,100 @@
+import 'package:cpt_uk/modules/job/labour_request_add/widget/labour_request_interface.dart';
+import 'package:cpt_uk/modules/job/labour_request_preselected_list/widget/preselected_add_staff.dart';
+import 'package:cpt_uk/widget/date_range_picker_dialog.dart';
 import 'package:domain/entity/response/labour_request_edit_index_entity.dart';
+import 'package:domain/entity/response/uk_labour_request_detail_entity.dart';
 import 'package:domain/repository/labour_repository.dart';
+import 'package:domain/repository/uk_job_repository.dart';
+import 'package:domain/repository/uk_labour_repository.dart';
 import 'package:flutter/cupertino.dart';
 import 'package:get/get.dart';
 import 'package:plugin_basic/constants/app_constant.dart';
+import 'package:plugin_platform/engine/dialog/dialog_engine.dart';
 import 'package:plugin_platform/engine/notify/notify_engine.dart';
 import 'package:plugin_platform/engine/toast/toast_engine.dart';
 import 'package:plugin_platform/http/dio/dio_cancelable_mixin.dart';
 import 'package:plugin_platform/http/http_result.dart';
 import 'package:shared/utils/date_time_utils.dart';
 import 'package:shared/utils/event_bus.dart';
+import 'package:shared/utils/log_utils.dart';
 import 'package:shared/utils/util.dart';
 import 'package:widgets/picker/date_picker_util.dart';
 import 'package:widgets/picker/option_pick_util.dart';
+import 'package:file_picker/file_picker.dart';
 
 import 'labour_review_edit_state.dart';
 
-class LabourReviewEditController extends GetxController with DioCancelableMixin {
+class LabourReviewEditController extends GetxController with DioCancelableMixin implements CommonLabourRequestController {
   final LabourRepository _labourRepository = Get.find();
+  final UKJobRepository _ukJobRepository = Get.find();
+  final UkLabourRepository _ukLabourRepository = Get.find();
+
   final LabourReviewEditState state = LabourReviewEditState();
 
+  @override
+  CommonLabourRequestState get commonState => state;
+
   /// 获取首页的数据
   void fetchRequestDetail() async {
     //获取到数据
-
-    final taskFuture = _labourRepository.fetchLabourReviewDetail(state.requestId, cancelToken: cancelToken);
+    Future<HttpResult<UkLabourRequestDetailEntity>> taskFuture;
+    // Log.d("请求的state.appliedId  ${state.appliedId}");
+    if (Utils.isNotEmpty(state.requestId) && state.requestId != "0") {
+      // Log.d("请求的state.appliedId3333  ${state.appliedId}");
+      taskFuture = _ukLabourRepository.fetchLabourRequestDetail(state.requestId);
+    } else {
+      taskFuture = _ukLabourRepository.fetchLabourRequestAddOption();
+    }
 
     var result = await taskFuture;
 
     //处理数据
     if (result.isSuccess) {
       state.labReqOption = result.data;
+      // state.selectedDate = state.labReqOption?.jobStart == null ? null : DateTimeUtils.getDateTime(state.labReqOption!.jobStart!);
       state.selectedStartTime = state.labReqOption?.jobStart == null ? null : DateTimeUtils.getDateTime(state.labReqOption!.jobStart!);
       state.selectedEndTime = state.labReqOption?.jobEnd == null ? null : DateTimeUtils.getDateTime(state.labReqOption!.jobEnd!);
-      state.noStaff = state.labReqOption?.needNum.toString() == "0" ? "" : state.labReqOption?.needNum.toString();
+      state.selectedTypeId = state.labReqOption?.employmentType.toString() ?? '';
+
+      state.attFilePath = state.labReqOption?.attUrl?? '';
+      state.jobSelectJobStart = state.labReqOption?.jobStart?? '';
+      state.jobSelectJobEnd = state.labReqOption?.jobEnd?? '';
+
+
+      if(state.pageType == 0){
+        // 新增
+        state.noStaff = '';
+        state.amount =  '';
+      }else {
+        state.noStaff = state.labReqOption?.needNum?.toString() == "0" ? "" : state.labReqOption?.needNum.toString();
+        state.amount = state.labReqOption?.amount?.toString() == "0" ? "" : state.labReqOption?.amount.toString();
+      }
+
       var needNumController = state.formData['no_of_staff']!['controller'];
-      needNumController.text = state.noStaff;
+      needNumController.text = state.noStaff??state.noStaff!='null'??"0";
       var amountController = state.formData['amount']!['controller'];
-      amountController.text = state.labReqOption?.amount ?? "";
-      state.selectedTemplateId = state.labReqOption?.templateId;
-      state.selectedDepartmentId = state.labReqOption?.departmentId;
+      amountController.text = state.amount??state.amount!='null'??"0";
+
+      var remarkController = state.formData['remark']!['controller'];
+      var eventController = state.formData['event']!['controller'];
+      var eventTypeController = state.formData['event_type']!['controller'];
+      var eventPaxController = state.formData['event_pax']!['controller'];
+      var revenueController = state.formData['revenue']!['controller'];
+      var positionController = state.formData['position']!['controller'];
+      var totalCostController = state.formData['total_cost']!['controller'];
+      remarkController.text = state.labReqOption?.description ?? '';
+      eventController.text = state.labReqOption?.eventName ?? "";
+      eventTypeController.text = state.labReqOption?.eventType ?? "";
+      eventPaxController.text = state.labReqOption?.passengers.toString() ?? "0";
+      revenueController.text = state.labReqOption?.estRevenue ?? "";
+      positionController.text = state.labReqOption?.position ?? "";
+      totalCostController.text = state.labReqOption?.estCost ?? "";
+
 
-      state.chargeOptionId = state.labReqOption?.chargeList.firstWhere((element) => element.checked == "checked").value;
+      state.selectedTemplateId = state.labReqOption?.templateId.toString();
+      state.selectedDepartmentId = state.labReqOption?.departmentId.toString();
+      //时薪还是房间计费
+      state.chargeOptionId = state.labReqOption?.chargeList!.firstWhere((element) => element.checked == "checked").value;
 
       update();
     } else {
@@ -54,59 +108,8 @@ class LabourReviewEditController extends GetxController with DioCancelableMixin
     fetchRequestDetail();
   }
 
-  /// 提交
-  void doSubmit() async {
-    var needNumController = state.formData['no_of_staff']!['controller'];
-    var amountController = state.formData['amount']!['controller'];
-    String needNum = needNumController.text.toString();
-    String amount = amountController.text.toString();
-
-    if (Utils.isEmpty(state.selectedTemplateId)) {
-      ToastEngine.show("Choose Job Title".tr);
-      return;
-    } else if (state.selectedStartTime == null) {
-      ToastEngine.show("Choose Start Date".tr);
-      return;
-    } else if (state.selectedEndTime == null) {
-      ToastEngine.show("Choose End Date".tr);
-      return;
-    } else if (Utils.isEmpty(state.selectedDepartmentId)) {
-      ToastEngine.show("Choose Outlet".tr);
-      return;
-    } else if (Utils.isEmpty(needNum)) {
-      ToastEngine.show("Enter No. of Staff".tr);
-      return;
-    } else if (state.labReqOption?.serviceType == 1 && Utils.isEmpty(amount)) {
-      ToastEngine.show("Enter Amount".tr);
-      return;
-    }
-
-
-    var result = await _labourRepository.editLabourReviewSubmit(
-      state.requestId,
-      state.selectedTemplateId,
-      DateTimeUtils.formatDate(state.selectedStartTime),
-      DateTimeUtils.formatDate(state.selectedEndTime),
-      state.selectedDepartmentId,
-      needNum,
-      state.chargeOptionId,
-      state.labReqOption?.serviceType == 1 ? amount : null,
-    );
-
-    //处理数据
-    if (result.isSuccess) {
-      NotifyEngine.showSuccess("Successful".tr);
-
-      //根据类型刷新
-      state.cb?.call(state.requestId ?? "");
-
-      Get.back();
-    } else {
-      ToastEngine.show(result.errorMsg ?? "Network Load Error".tr);
-    }
-  }
-
   // 筛选工作模板
+  @override
   void pickJobTitle() {
     if (state.labReqOption == null || state.pageType == 2) {
       return;
@@ -116,7 +119,7 @@ class LabourReviewEditController extends GetxController with DioCancelableMixin
     if (state.selectedTemplateId == null) {
       selectedTemplateIndex = 0;
     } else {
-      selectedTemplateIndex = state.labReqOption!.templateList.indexWhere((department) => department.value.toString() == state.selectedTemplateId);
+      selectedTemplateIndex = state.labReqOption!.templateList!.indexWhere((department) => department.value.toString() == state.selectedTemplateId);
     }
 
     if (selectedTemplateIndex < 0) {
@@ -124,16 +127,68 @@ class LabourReviewEditController extends GetxController with DioCancelableMixin
     }
 
     OptionPickerUtil.showCupertinoOptionPicker(
-      items: state.labReqOption!.templateList.map((e) => e.txt!).toList(growable: false),
+      items: state.labReqOption!.templateList!.map((e) => e.txt!).toList(growable: false),
       initialSelectIndex: selectedTemplateIndex,
-      onPickerChanged: (_, index) {
-        state.selectedTemplateId = state.labReqOption!.templateList[index].value!.toString();
-        update();
+      onPickerChanged: (_, index) async{
+        state.selectedTemplateId = state.labReqOption!.templateList![index].value!.toString();
+        // 选择了标题后 需要 将此时选择的 标题 回显 给position
+        var positionController = state.formData['position']!['controller'];
+        state.position = state.templateList!
+            .firstWhere((element) => element.value.toString() == state.selectedTemplateId,
+            orElse: () => UkLabourRequestDetailTemplateList())
+            .txt ??
+            "";
+        positionController.text = state.position;
+
+        // 并且需要根据 state.selectedTemplateId调用 接口 回显 证书 、vehicle
+        await _getShowTemplateData(state.selectedTemplateId!);
       },
     );
   }
 
+  Future<HttpResult?> _getShowTemplateData(String templateId) async{
+    final result = await _ukLabourRepository.fetchLabourRequestShowTemplateData(templateId);
+    if (result.isSuccess) {
+      state.showTemplateData = result.data;
+      if (state.showTemplateData != null) {
+        // 回显 证书、vehicle
+        if((state.showTemplateData?.certificate??'').isNotEmpty){
+          List<String> selectedCertificateList = state.showTemplateData?.certificate?.split(',')?? [];
+          // 循环 state.labReqOption?.certificateList 满足条件修改  checked
+          state.labReqOption?.certificateList?.forEach((e)=> {
+            if(selectedCertificateList.contains(e.value.toString())){
+              e.checked = 'checked'
+            }else {
+              e.checked = ''
+            }
+          });
+          Log.d("切换模板后, 需要回显的证书列表: ${selectedCertificateList}");
+          Log.d("切换模板后, 证书的回显 selectedCertificateList: ${state.labReqOption?.certificateList}");
+
+          List<String> selectedVehicleList = state.showTemplateData?.vehicle?.split(',')?? [];
+          // 循环 state.labReqOption?.vehicleList 满足条件修改  checked
+          state.labReqOption?.vehicleList?.forEach((e)=> {
+            if(selectedVehicleList.contains(e.value.toString())){
+              e.checked = 'checked'
+            }else {
+              e.checked = ''
+            }
+          });
+
+          Log.d("切换模板后, 需要回显的vehicle列表: ${selectedVehicleList}");
+          Log.d("切换模板后, 证书的回显 vehicleList: ${state.labReqOption?.vehicleList}");
+
+        }
+        // 更新
+        update();
+      }
+    }else {
+      ToastEngine.show(result.errorMsg ?? "Network Load Error".tr);
+    }
+  }
+
   //选择开始时间
+  @override
   void pickStartTime() {
     if (state.labReqOption == null || state.pageType == 2) {
       return;
@@ -151,6 +206,7 @@ class LabourReviewEditController extends GetxController with DioCancelableMixin
   }
 
   // 选择结束时间
+  @override
   void pickEndTime() {
     if (state.labReqOption == null || state.pageType == 2) {
       return;
@@ -167,8 +223,46 @@ class LabourReviewEditController extends GetxController with DioCancelableMixin
     );
   }
 
+  // 筛选 employ ment type
+  @override
+  void pickEmploymentType() {
+    if (state.labReqOption == null || state.pageType == 2) {
+      return;
+    }
+
+    int selectedEmploymentTypeIndex;
+    if (state.selectedTypeId == null) {
+      selectedEmploymentTypeIndex = 0;
+    } else {
+      if (state.labReqOption?.employmentList != null && state.labReqOption!.employmentList!.isNotEmpty) {
+        selectedEmploymentTypeIndex = state.labReqOption!.employmentList!.indexWhere(
+                (employment) => employment.value.toString() == state.selectedTypeId
+        );
+      } else {
+        // 处理 departmentList 为空或 null 的情况
+        selectedEmploymentTypeIndex = 0;
+      }
+    }
+
+    if (selectedEmploymentTypeIndex < 0) {
+      selectedEmploymentTypeIndex = 0;
+    }
+
+    OptionPickerUtil.showCupertinoOptionPicker(
+      items: state.labReqOption!.employmentList!.map((e) => e.txt!).toList(growable: false),
+      initialSelectIndex: selectedEmploymentTypeIndex,
+      onPickerChanged: (_, index) {
+        state.selectedTypeId = state.labReqOption!.employmentList![index].value!.toString();
+        update();
+      },
+    );
+  }
+
+
   // 筛选部门
+  @override
   void pickDepartment() {
+    Log.d("点击了 筛选部门  ${state.labReqOption}");
     if (state.labReqOption == null || state.pageType == 2) {
       return;
     }
@@ -177,7 +271,7 @@ class LabourReviewEditController extends GetxController with DioCancelableMixin
     if (state.selectedDepartmentId == null) {
       selectedDepartmentIndex = 0;
     } else {
-      selectedDepartmentIndex = state.labReqOption!.departmentList.indexWhere((department) => department.value.toString() == state.selectedDepartmentId);
+      selectedDepartmentIndex = state.labReqOption!.departmentList!.indexWhere((department) => department.value.toString() == state.selectedDepartmentId);
     }
 
     if (selectedDepartmentIndex < 0) {
@@ -185,12 +279,229 @@ class LabourReviewEditController extends GetxController with DioCancelableMixin
     }
 
     OptionPickerUtil.showCupertinoOptionPicker(
-      items: state.labReqOption!.departmentList.map((e) => e.txt!).toList(growable: false),
+      items: state.labReqOption!.departmentList!.map((e) => e.txt!).toList(growable: false),
       initialSelectIndex: selectedDepartmentIndex,
       onPickerChanged: (_, index) {
-        state.selectedDepartmentId = state.labReqOption!.departmentList[index].value!.toString();
+        state.selectedDepartmentId = state.labReqOption!.departmentList![index].value!.toString();
+        update();
+      },
+    );
+  }
+
+  // 选择单个文件
+  @override
+  void pickAttFile() async {
+    FilePickerResult? result = await FilePicker.platform.pickFiles(
+      allowMultiple: false,
+      type: FileType.custom,
+      allowedExtensions: ['jpg', 'png', 'jpeg', 'pdf', 'docx'],
+    );
+
+    if (result != null) {
+      PlatformFile selectedPlatformFile = result.files.first;
+      Log.d("path:${selectedPlatformFile.path} name:${selectedPlatformFile.name}");
+
+      state.attFilePath = selectedPlatformFile.path;
+      update();
+
+      // final fileResult = await _thRepository.uploadFile(selectedPlatformFile.path);
+      // if (fileResult.isSuccess) {
+      //   state.attFilePath = fileResult.data?.path;
+      //   update();
+      // } else {
+      //   ToastEngine.show(fileResult.errorMsg ?? "Network Load Error".tr);
+      // }
+    }
+  }
+
+  @override
+  void handlerSelectPreSelect() {
+    // DialogEngine.show(
+    //   widget: PreselectedAddStaff(
+    //     jobId: '0',
+    //     selectedStaffIds: "",
+    //     confirmAction: (selectedIds, [selectedList]) {
+    //
+    //     },
+    //   ),
+    // );
+  }
+
+
+  //选择时间段
+  @override
+  void pickDateRange() {
+    // DialogEngine.show(
+    //   widget: DateRangePickerDialog(
+    //     dateRange: state.repeatDateStr,
+    //     confirmAction: (dateStr) {
+    //       Log.d("选择的时间段:$dateStr");
+    //       update();
+    //     },
+    //   ));
+  }
+  @override
+  void pickJobDate() {
+    // TODO: implement pickJobDate
+  }
+
+  // 编辑状态时 修改 开始日期时间  YYYY-MM-DD HH:mm
+  @override
+  void pickJobStart() {
+    // TODO: implement pickJobStart
+    DatePickerUtil.showCupertinoDatePicker(
+      title: "Job Start".tr,
+      selectedDateTime: state.jobStart,
+      mode: CupertinoDatePickerMode.dateAndTime,
+      onDateTimeChanged: (date) {
+        Log.d("选取的开始日期时间:${date.toString()}");
+        Log.d("----------${DateTimeUtils.formatDate(date, format: 'yyyy-MM-dd HH:mm')}");
+        state.jobSelectJobStart = DateTimeUtils.formatDate(date, format: 'yyyy-MM-dd HH:mm');
+        update();
+      },
+    );
+
+  }
+
+  // 编辑状态时 修改 结束日期时间  YYYY-MM-DD HH:mm
+  @override
+  void pickJobEnd() {
+    // TODO: implement pickJobEnd
+    DatePickerUtil.showCupertinoDatePicker(
+      title: "Job End".tr,
+      selectedDateTime: state.jobStart,
+      mode: CupertinoDatePickerMode.dateAndTime,
+      onDateTimeChanged: (date) {
+        Log.d("选取的结束日期时间:${date.toString()}");
+        state.jobSelectJobEnd = DateTimeUtils.formatDate(date, format: 'yyyy-MM-dd HH:mm');
         update();
       },
     );
   }
+
+
+  /// 提交
+  @override
+  void doSubmit() async {
+    Log.d("labour_review_edit controller 提交");
+
+    var needNumController = state.formData['no_of_staff']!['controller'];
+    var amountController = state.formData['amount']!['controller'];
+    String needNum = needNumController.text.toString();
+    String amount = amountController.text.toString();
+    // String? jobApplyPreId = state.preSelectedIds;
+
+    var remarkController = state.formData['remark']!['controller'];
+    var eventController = state.formData['event']!['controller'];
+    var eventTypeController = state.formData['event_type']!['controller'];
+    var eventPaxController = state.formData['event_pax']!['controller'];
+    var revenueController = state.formData['revenue']!['controller'];
+    var positionController = state.formData['position']!['controller'];
+    var totalCostController = state.formData['total_cost']!['controller'];
+
+    String event = eventController.text.toString();
+    String eventType = eventTypeController.text.toString();
+    String eventPax = eventPaxController.text.toString()??"0";
+    String revenue = revenueController.text.toString();
+    String position = positionController.text.toString();
+    String totalCost = totalCostController.text.toString();
+    String remark = remarkController.text.toString();
+
+
+    if (Utils.isEmpty(state.selectedTemplateId)) {
+      ToastEngine.show("Choose Job Title".tr);
+      return;
+    } else if (state.selectedStartTime == null) {
+      ToastEngine.show("Choose Start Date".tr);
+      return;
+    } else if (state.selectedEndTime == null) {
+      ToastEngine.show("Choose End Date".tr);
+      return;
+    } else if (Utils.isEmpty(state.selectedDepartmentId)) {
+      ToastEngine.show("Choose Outlet".tr);
+      return;
+    } else if (Utils.isEmpty(needNum)) {
+      ToastEngine.show("Enter No. of Staff".tr);
+      return;
+    } else if (state.labReqOption?.serviceType == 1 && Utils.isEmpty(amount)) {
+      ToastEngine.show("Enter Amount".tr);
+      return;
+    }else if(Utils.isEmpty(state.selectedTypeId)){
+      ToastEngine.show("Choose Employment Type".tr);
+      return;
+    }
+
+    Future<HttpResult> taskFuture;
+    // 编辑
+
+    Map<String, dynamic> params = {
+      "requestId": state.requestId,
+      "templateId": state.selectedTemplateId,
+      "jobStart": "${DateTimeUtils.formatDate(state.selectedDate, format: 'yyyy-MM-dd')} ${DateTimeUtils.formatDate(state.selectedStartTime, format: 'HH:mm')}:00",
+      "jobEnd": "${DateTimeUtils.formatDate(state.selectedDate, format: 'yyyy-MM-dd')} ${DateTimeUtils.formatDate(state.selectedEndTime, format: 'HH:mm')}:00",
+      "departmentId": state.selectedDepartmentId,
+      "needNum": needNum,
+      "salaryBy": 'hour',
+      "amount": state.labReqOption?.serviceType == 1 ? amount : null,
+      "certificate": state.selectedCertificateList?.join(",")?? "",
+      "challenge25": state.selectedChallenge25Id?? "",
+      "vehicle": state.selectedVehicleList?.join(",")??"",
+      "description": remark,
+      "employmentType": state.selectedTypeId,
+      "eventName": event,
+      "eventType": eventType,
+      "passengers": eventPax,
+      "estRevenue": revenue,
+      "position": position,
+      "estCost": totalCost,
+      "attUrl": state.attFilePath,
+      'cancelToken': cancelToken
+    };
+
+    // 调用的其实就是 lab-req 编辑的接口
+    taskFuture = _ukLabourRepository.editLabourRequestReviewSubmit(
+      requestId: params['requestId'],
+      templateId: params['templateId'],
+      jobStart: params['jobStart'],
+      jobEnd: params['jobEnd'],
+      departmentId: params['departmentId'],
+      needNum: params['needNum'],
+      salaryBy: params['salaryBy'],
+      amount: params['amount'],
+      certificate: params['certificate'],
+      challenge25: params['challenge25'],
+      vehicle: params['vehicle'],
+      description: params['description'],
+      employmentType: params['employmentType'],
+      eventName: params['eventName'],
+      eventType: params['eventType'],
+      passengers: params['passengers'],
+      estRevenue: params['estRevenue'],
+      position: params['position'],
+      estCost: params['estCost'],
+      attUrl: params['attUrl'],
+      cancelToken: params['cancelToken'],
+    );
+
+    var result = await taskFuture;
+
+    //处理数据
+    if (result.isSuccess) {
+      NotifyEngine.showSuccess("Successful".tr);
+
+      //根据类型刷新
+      if (state.pageType != 0 && Utils.isNotEmpty(state.requestId) && state.requestId != "0") {
+        //编辑就发送指定的 requestId
+        bus.emit(AppConstant.eventLabourRequestRefresh, state.requestId);
+      } else {
+        //新增的就发送空
+        bus.emit(AppConstant.eventLabourRequestRefresh, "");
+      }
+
+      Get.back();
+    } else {
+      ToastEngine.show(result.errorMsg ?? "Network Load Error".tr);
+    }
+  }
+
 }

+ 4 - 257
packages/cpt_uk/lib/modules/review/labour_review_edit/labour_review_edit_page.dart

@@ -1,3 +1,4 @@
+import 'package:cpt_uk/modules/job/labour_request_add/widget/lab_request_and_request_review_form.dart';
 import 'package:cs_resources/constants/color_constants.dart';
 import 'package:cs_resources/generated/assets.dart';
 import 'package:domain/entity/response/labour_request_edit_index_entity.dart';
@@ -12,6 +13,7 @@ import 'package:plugin_basic/utils/ext_get_nav.dart';
 import 'package:router/path/router_path.dart';
 import 'package:shared/utils/date_time_utils.dart';
 import 'package:shared/utils/screen_util.dart';
+import 'package:shared/utils/util.dart';
 import 'package:widgets/ext/ex_widget.dart';
 import 'package:widgets/my_appbar.dart';
 import 'package:widgets/my_button.dart';
@@ -21,6 +23,7 @@ import 'package:widgets/no_shadow_scroll_behavior.dart';
 import 'package:widgets/shatter/custom_radio_check.dart';
 import 'package:widgets/shatter/form_require_text.dart';
 import 'package:widgets/shatter/round_my_text_field.dart';
+import 'package:widgets/widget_export.dart';
 
 import 'labour_review_edit_controller.dart';
 import 'labour_review_edit_state.dart';
@@ -87,263 +90,7 @@ class _LabourReviewEditState extends BaseState<UKLabourReviewEditPage, LabourRev
                   child: Column(
                     crossAxisAlignment: CrossAxisAlignment.start,
                     children: [
-                      //工作标题,选择模板
-                      FormRequireText(
-                        text: "Job Title".tr,
-                      ).marginOnly(top: 15),
-
-                      //工作标题
-                      Container(
-                        padding: const EdgeInsets.only(left: 16, right: 10),
-                        margin: const EdgeInsets.only(top: 10),
-                        height: 45,
-                        decoration: BoxDecoration(
-                          color: const Color(0xFF4DCFF6).withOpacity(state.pageType == 2 ? 0.5 : 0.2),
-                          borderRadius: const BorderRadius.all(Radius.circular(5)),
-                        ),
-                        child: Row(
-                          mainAxisSize: MainAxisSize.max,
-                          crossAxisAlignment: CrossAxisAlignment.center,
-                          mainAxisAlignment: MainAxisAlignment.start,
-                          children: [
-                            MyTextView(
-                              state.selectedTemplateId == null || state.selectedTemplateId == "0"
-                                  ? ""
-                                  : state.labReqOption!.templateList
-                                          .firstWhere((element) => element.value.toString() == state.selectedTemplateId,
-                                              orElse: () => LabourRequestEditIndexTemplateList())
-                                          .txt ??
-                                      "",
-                              fontSize: 14,
-                              hint: "Choose Job Title".tr,
-                              textHintColor: ColorConstants.textGrayAECAE5,
-                              isFontMedium: true,
-                              textColor: ColorConstants.white,
-                            ).expanded(),
-
-                            //下拉选图标
-                            Visibility(
-                              visible: state.pageType != 2,
-                              child: const MyAssetImage(Assets.baseServiceTriangleDropDownIcon, width: 11.5, height: 6.28),
-                            ),
-                          ],
-                        ),
-                      ).onTap(() {
-                        FocusScope.of(context).unfocus();
-                        controller.pickJobTitle();
-                      }),
-
-                      //开始时间
-                      FormRequireText(
-                        text: "Start Time".tr,
-                      ).marginOnly(top: 15),
-
-                      //选择时间
-                      Container(
-                        padding: const EdgeInsets.only(left: 16, right: 10),
-                        margin: const EdgeInsets.only(top: 10),
-                        height: 45,
-                        decoration: BoxDecoration(
-                          color: const Color(0xFF4DCFF6).withOpacity(state.pageType == 2 ? 0.5 : 0.2),
-                          borderRadius: const BorderRadius.all(Radius.circular(5)),
-                        ),
-                        child: Row(
-                          mainAxisSize: MainAxisSize.max,
-                          crossAxisAlignment: CrossAxisAlignment.center,
-                          mainAxisAlignment: MainAxisAlignment.start,
-                          children: [
-                            MyTextView(
-                              state.selectedStartTime == null ? "" : DateTimeUtils.formatDate(state.selectedStartTime),
-                              fontSize: 14,
-                              hint: "Job Start Time".tr,
-                              textHintColor: ColorConstants.textGrayAECAE5,
-                              isFontMedium: true,
-                              textColor: ColorConstants.white,
-                            ).expanded(),
-                            //下拉选图标
-                            Visibility(
-                              visible: state.pageType != 2,
-                              child: const MyAssetImage(Assets.baseServiceTriangleDropDownIcon, width: 11.5, height: 6.28),
-                            ),
-                          ],
-                        ),
-                      ).onTap(() {
-                        FocusScope.of(context).unfocus();
-                        controller.pickStartTime();
-                      }),
-
-                      //结束时间
-                      FormRequireText(
-                        text: "End Time".tr,
-                      ).marginOnly(top: 15),
-
-                      //选择时间
-                      Container(
-                        padding: const EdgeInsets.only(left: 16, right: 10),
-                        margin: const EdgeInsets.only(top: 10),
-                        height: 45,
-                        decoration: BoxDecoration(
-                          color: const Color(0xFF4DCFF6).withOpacity(state.pageType == 2 ? 0.5 : 0.2),
-                          borderRadius: const BorderRadius.all(Radius.circular(5)),
-                        ),
-                        child: Row(
-                          mainAxisSize: MainAxisSize.max,
-                          crossAxisAlignment: CrossAxisAlignment.center,
-                          mainAxisAlignment: MainAxisAlignment.start,
-                          children: [
-                            MyTextView(
-                              state.selectedEndTime == null ? "" : DateTimeUtils.formatDate(state.selectedEndTime),
-                              fontSize: 14,
-                              hint: "Job End Time".tr,
-                              textHintColor: ColorConstants.textGrayAECAE5,
-                              isFontMedium: true,
-                              textColor: ColorConstants.white,
-                            ).expanded(),
-                            //下拉选图标
-                            Visibility(
-                              visible: state.pageType != 2,
-                              child: const MyAssetImage(Assets.baseServiceTriangleDropDownIcon, width: 11.5, height: 6.28),
-                            ),
-                          ],
-                        ),
-                      ).onTap(() {
-                        FocusScope.of(context).unfocus();
-                        controller.pickEndTime();
-                      }),
-
-                      //工作选择部门
-                      FormRequireText(
-                        text: "Outlet".tr,
-                      ).marginOnly(top: 15),
-
-                      //选择部门
-                      Container(
-                        padding: const EdgeInsets.only(left: 16, right: 10),
-                        margin: const EdgeInsets.only(top: 10),
-                        height: 45,
-                        decoration: BoxDecoration(
-                          color: const Color(0xFF4DCFF6).withOpacity(state.pageType == 2 ? 0.5 : 0.2),
-                          borderRadius: const BorderRadius.all(Radius.circular(5)),
-                        ),
-                        child: Row(
-                          mainAxisSize: MainAxisSize.max,
-                          crossAxisAlignment: CrossAxisAlignment.center,
-                          mainAxisAlignment: MainAxisAlignment.start,
-                          children: [
-                            MyTextView(
-                              state.selectedDepartmentId == null || state.selectedDepartmentId == "0"
-                                  ? ""
-                                  : state.labReqOption!.departmentList
-                                          .firstWhere((element) => element.value.toString() == state.selectedDepartmentId,
-                                              orElse: () => LabourRequestEditIndexDepartmentList())
-                                          .txt ??
-                                      "",
-                              fontSize: 14,
-                              hint: "Choose Outlet".tr,
-                              textHintColor: ColorConstants.textGrayAECAE5,
-                              isFontMedium: true,
-                              textColor: ColorConstants.white,
-                            ).expanded(),
-                            //下拉选图标
-                            Visibility(
-                              visible: state.pageType != 2,
-                              child: const MyAssetImage(Assets.baseServiceTriangleDropDownIcon, width: 11.5, height: 6.28),
-                            ),
-                          ],
-                        ),
-                      ).onTap(() {
-                        FocusScope.of(context).unfocus();
-                        controller.pickDepartment();
-                      }),
-
-                      //需要的人数
-                      FormRequireText(
-                        text: "No. of Staff".tr,
-                      ).marginOnly(top: 15),
-
-                      //输入框(只允许输入数字)
-                      CustomTextField(
-                        formKey: "no_of_staff",
-                        marginLeft: 0,
-                        marginRight: 0,
-                        paddingTop: 0,
-                        paddingBottom: 0,
-                        height: 45,
-                        fillBackgroundColor: const Color(0xFF4DCFF6).withOpacity(state.pageType == 2 ? 0.5 : 0.2),
-                        enabled: state.pageType != 2,
-                        inputFormatters: <TextInputFormatter>[FilteringTextInputFormatter.digitsOnly],
-                        textInputType: TextInputType.number,
-                        formData: state.formData,
-                        textInputAction: TextInputAction.done,
-                        onSubmit: (key, value) {
-                          FocusScope.of(context).unfocus();
-                        },
-                        marginTop: 10,
-                      ),
-
-                      FormRequireText(
-                        text: "Salary By".tr,
-                      ).marginOnly(top: 15),
-
-                      //选择计费类型
-                      state.labReqOption != null
-                          ? CustomRadioCheck(
-                              options: state.labReqOption!.chargeList.map((e) => e.txt).whereType<String>().toList(), //后台返回的数据展示,并且根据后台的数据匹配索引
-                              selectedPosition: state.labReqOption!.chargeList.indexWhere((element) => element.checked == "checked"),
-                              onOptionSelected: (index, text) {
-                                //修改内存的值
-                                state.chargeOptionId = state.labReqOption!.chargeList[index].value;
-                              },
-                            ).marginOnly(top: 15)
-                          : const CircularProgressIndicator(),
-
-                      //选择是否需要输入金额
-                      Visibility(
-                        visible: state.labReqOption?.serviceType == 1,
-                        child: FormRequireText(
-                          text: "Amount".tr,
-                        ).marginOnly(top: 15),
-                      ),
-
-                      Visibility(
-                        visible: state.labReqOption?.serviceType == 1,
-                        child: CustomTextField(
-                          formKey: "amount",
-                          marginLeft: 0,
-                          marginRight: 0,
-                          paddingTop: 0,
-                          paddingBottom: 0,
-                          height: 45,
-                          fillBackgroundColor: const Color(0xFF4DCFF6).withOpacity(state.pageType == 2 ? 0.5 : 0.2),
-                          enabled: state.pageType != 2,
-                          textInputType: TextInputType.number,
-                          formData: state.formData,
-                          textInputAction: TextInputAction.done,
-                          onSubmit: (key, value) {
-                            FocusScope.of(context).unfocus();
-                          },
-                          marginTop: 10,
-                        ),
-                      ),
-
-                      //提交按钮
-                      Visibility(
-                        visible: state.pageType != 2,
-                        child: MyButton(
-                          type: ClickType.throttle,
-                          milliseconds: 500,
-                          onPressed: () {
-                            FocusScope.of(context).unfocus();
-                            controller.doSubmit();
-                          },
-                          text: "Submit".tr,
-                          textColor: ColorConstants.white,
-                          fontSize: 16,
-                          radius: 22.5,
-                          backgroundColor: hexToColor("#FFBB1B"),
-                          fontWeight: FontWeight.w500,
-                        ).marginSymmetric(horizontal: 0, vertical: 30),
-                      ),
+                      CommonLabourRequestFormFields(controller: controller)
                     ],
                   ).paddingOnly(left: 15, right: 15),
                 ),

+ 103 - 2
packages/cpt_uk/lib/modules/review/labour_review_edit/labour_review_edit_state.dart

@@ -1,15 +1,34 @@
+import 'dart:io';
+
+import 'package:cpt_uk/modules/job/labour_request_add/widget/labour_request_interface.dart';
 import 'package:domain/entity/response/labour_request_edit_index_entity.dart';
+import 'package:domain/entity/response/uk_lab_req_show_template_entity.dart';
+import 'package:domain/entity/response/uk_labour_request_detail_entity.dart';
 import 'package:flutter/material.dart';
 import 'package:plugin_basic/basic_export.dart';
+import 'package:shared/utils/date_time_utils.dart';
+
+class LabourReviewEditState implements CommonLabourRequestState {
+  @override
+  String useInSence = 'labour_request_review';  // labour_request 、 labour_request_review
+
+  @override
+  DateTime? get jobEnd => labReqOption?.jobEnd != null? DateTimeUtils.getDateTime(labReqOption!.jobEnd!): null;
 
-class LabourReviewEditState {
+  @override
+  DateTime? get jobStart => labReqOption?.jobStart !=null? DateTimeUtils.getDateTime(labReqOption!.jobStart!): null;
+
+  @override
+  String? jobSelectJobStart;
+  @override
+  String? jobSelectJobEnd;
 
   int pageType = 2;  //页面的状态 1是编辑  2是详情
   String? requestId;  //编辑和详情需要用到ID
   void Function(dynamic value)? cb;
 
   //页面对应的详情数据
-  LabourRequestEditIndexEntity? labReqOption;
+  UkLabourRequestDetailEntity? labReqOption;
 
   //页面对应的选择的条件
   DateTime? selectedStartTime;
@@ -17,9 +36,42 @@ class LabourReviewEditState {
   String? selectedTemplateId;
   String? selectedDepartmentId;
   String? noStaff;  //成员数量
+  String? amount;
+
+  List<String> selectedCertificateList = [];   //选中的 证书 certificate
+  List<String> selectedVehicleList = [];   //选中的 车辆 vehicle
+  String? selectedChallenge25Id;   // 选择的 challenge25 id
+
+  UkLabReqShowTemplateEntity? showTemplateData; // 切换模板时 获取的回显的部分数据(证书、chanllenge25、vehicle)
+
+
+  String? selectedTypeId;
+  String? selectedType;
+  String? event;
+  String? eventType;
+  String? eventPax;
+  String? estimatedRevenue;
+  String? position;
+  String? estimatedTotalCost;
+  String? remark; //备注
+  String? attFilePath; // 附件地址
 
   String? chargeOptionId;
 
+  int get serviceType => labReqOption?.serviceType ?? 0;
+  List<UkLabourRequestDetailLocationList>? get locationList => labReqOption?.locationList;
+  List<UkLabourRequestDetailTemplateList>? get templateList => labReqOption?.templateList;
+  List<UkLabourRequestDetailDepartmentList>? get departmentList => labReqOption?.departmentList;
+  List<UkLabourRequestDetailChargeList>? get chargeList => labReqOption?.chargeList;
+  List<UkLabourRequestDetailEmploymentList>? get employmentList => labReqOption?.employmentList;
+  List<UkLabourRequestDetailCertificateList>? get certificateList => labReqOption?.certificateList;
+  List<UkLabourRequestDetailVehicleList>? get vehicleList => labReqOption?.vehicleList;
+  List<UkLabourRequestDetailChallenge25List>? get challenge25List => labReqOption?.challenge25List;
+
+  DateTime? get selectedDate => selectedStartTime;
+  String? get repeatDateStr => '';
+  String? get preSelectedNames => '';
+
   //表单的校验与数据
   Map<String, Map<String, dynamic>> formData = {
     'no_of_staff': {
@@ -36,6 +88,55 @@ class LabourReviewEditState {
       'hintText': 'Enter Amount'.tr,
       'obsecure': false,
     },
+    'remark': {
+      'value': '',
+      'controller': TextEditingController(),
+      'focusNode': FocusNode(),
+      'hintText': 'Enter...'.tr,
+      'obsecure': false,
+    },
+    'event': {
+      'value': '',
+      'controller': TextEditingController(),
+      'focusNode': FocusNode(),
+      'hintText': 'Enter...'.tr,
+      'obsecure': false,
+    },
+    'event_type': {
+      'value': '',
+      'controller': TextEditingController(),
+      'focusNode': FocusNode(),
+      'hintText': 'Enter...'.tr,
+      'obsecure': false,
+    },
+    'event_pax': {
+      'value': '',
+      'controller': TextEditingController(),
+      'focusNode': FocusNode(),
+      'hintText': 'Enter...'.tr,
+      'obsecure': false,
+    },
+    'revenue': {
+      'value': '',
+      'controller': TextEditingController(),
+      'focusNode': FocusNode(),
+      'hintText': 'Enter...'.tr,
+      'obsecure': false,
+    },
+    'position': {
+      'value': '',
+      'controller': TextEditingController(),
+      'focusNode': FocusNode(),
+      'hintText': 'Enter...'.tr,
+      'obsecure': false,
+    },
+    'total_cost': {
+      'value': '',
+      'controller': TextEditingController(),
+      'focusNode': FocusNode(),
+      'hintText': 'Enter...'.tr,
+      'obsecure': false,
+    },
   };
 
 }

+ 109 - 66
packages/cpt_uk/lib/modules/review/labour_review_list/labour_review_controller.dart

@@ -1,13 +1,17 @@
 import 'package:domain/entity/response/labour_request_index_entity.dart';
 import 'package:domain/entity/response/labour_review_list_entity.dart';
+import 'package:domain/entity/response/uk_labour_request_review_list_entity.dart';
 import 'package:domain/repository/labour_repository.dart';
+import 'package:domain/repository/uk_labour_repository.dart';
 import 'package:get/get.dart';
+import 'package:plugin_basic/constants/app_constant.dart';
 import 'package:plugin_platform/engine/dialog/dialog_engine.dart';
 import 'package:plugin_platform/engine/notify/notify_engine.dart';
 import 'package:plugin_platform/engine/toast/toast_engine.dart';
 import 'package:plugin_platform/http/dio/dio_cancelable_mixin.dart';
 import 'package:plugin_platform/http/http_result.dart';
 import 'package:shared/utils/date_time_utils.dart';
+import 'package:shared/utils/event_bus.dart';
 import 'package:shared/utils/log_utils.dart';
 import 'package:shared/utils/util.dart';
 import 'package:widgets/dialog/app_default_dialog.dart';
@@ -21,6 +25,7 @@ import 'labour_review_state.dart';
 
 class LabourReviewController extends GetxController with DioCancelableMixin {
   final LabourRepository _labourRepository = Get.find();
+  final UkLabourRepository _UkLabourRepository = Get.find();
   final LabourReviewState state = LabourReviewState();
 
   var _curPage = 1;
@@ -45,40 +50,40 @@ class LabourReviewController extends GetxController with DioCancelableMixin {
   // Refresh 刷新事件
   Future onRefresh() async {
     _curPage = 1;
-    fetchAppliedStaffList();
+    fetchLabourRequestReViewList();
   }
 
   // Refresh 加载事件
   Future loadMore() async {
     _curPage++;
-    fetchAppliedStaffList();
+    fetchLabourRequestReViewList();
   }
 
   // 重试请求
   Future retryRequest() async {
     _curPage = 1;
     _needShowPlaceholder = true;
-    fetchAppliedStaffList();
+    fetchLabourRequestReViewList();
   }
 
   /// 获取服务器数据,通知消息列表
-  Future fetchAppliedStaffList() async {
+  Future fetchLabourRequestReViewList() async {
     if (_needShowPlaceholder) {
       changeLoadingState(LoadState.State_Loading);
     }
 
     // 并发执行两个请求
     var futures = [
-      _labourRepository.fetchLabourReviewList(
-        state.keyword,
-        DateTimeUtils.formatDate(state.selectedStartDate, format: "yyyy-MM-dd"),
-        DateTimeUtils.formatDate(state.selectedEndDate, format: "yyyy-MM-dd"),
-        state.selectedDepartmentId,
-        curPage: _curPage,
-        cancelToken: cancelToken,
+      _UkLabourRepository.fetchLabourRequestReViewList(
+          keyword: state.keyword,
+          startDate: DateTimeUtils.formatDate(state.selectedStartDate, format: "yyyy-MM-dd"),
+          endDate:DateTimeUtils.formatDate(state.selectedEndDate, format: "yyyy-MM-dd"),
+          departmentId: state.selectedDepartmentId,
+          curPage: _curPage,
+          cancelToken: cancelToken,
       ),
       state.indexOptions == null
-          ? _labourRepository.fetchLabourReviewIndex(
+          ? _labourRepository.fetchLabourRequestIndex(
               cancelToken: cancelToken,
             )
           : Future(() => HttpResult(isSuccess: true).convert(data: state.indexOptions!)),
@@ -86,8 +91,12 @@ class LabourReviewController extends GetxController with DioCancelableMixin {
 
     //拿到结果
     var results = await Future.wait(futures);
-    var listResult = results[0] as HttpResult<LabourReviewListEntity>;
-    var optionResult = results[1] as HttpResult<LabourRequestIndexEntity>;
+    var listResult = results[0] as HttpResult<UkLabourRequestReviewListEntity?>;
+    var optionResult = results[1] as HttpResult<LabourRequestIndexEntity?>;
+
+    // Log.d("state.indexOptions  ${state.indexOptions}");
+
+    // Log.d("optionResult  ${optionResult}");
 
     //选项数据
     if (state.indexOptions == null && optionResult.isSuccess) {
@@ -96,7 +105,9 @@ class LabourReviewController extends GetxController with DioCancelableMixin {
 
     // 处理数据
     if (listResult.isSuccess) {
-      handleList(listResult.data?.rows);
+      List<UkLabourRequestReviewListRows> validList = listResult.data?.rows?.whereType<UkLabourRequestReviewListRows>().toList()?? [];
+
+      handleList(validList);
     } else {
       errorMessage = listResult.errorMsg;
       changeLoadingState(LoadState.State_Error);
@@ -107,7 +118,7 @@ class LabourReviewController extends GetxController with DioCancelableMixin {
   }
 
   // 处理数据与展示的逻辑
-  void handleList(List<LabourReviewListRows>? list) {
+  void handleList(List<UkLabourRequestReviewListRows>? list) {
     if (list != null && list.isNotEmpty) {
       //有数据,判断是刷新还是加载更多的数据
       if (_curPage == 1) {
@@ -140,15 +151,36 @@ class LabourReviewController extends GetxController with DioCancelableMixin {
   @override
   void onReady() {
     super.onReady();
-    fetchAppliedStaffList();
+    fetchLabourRequestReViewList();
+    registerEventBus();
   }
 
   @override
   void onClose() {
+    unregisterEventBus();
     state.datas.clear();
     super.onClose();
   }
 
+  // EventBus 的事件接收
+  Subscription? subscribe;
+
+  void registerEventBus() {
+    subscribe = bus.on(AppConstant.eventLabourRequestRefresh, (arg) {
+      var requestId = arg as String;
+      if (Utils.isNotEmpty(requestId)) {
+        // fetchItemByIdAndRefreshItem(requestId);
+        refreshController.callRefresh();
+      } else {
+        refreshController.callRefresh();
+      }
+    });
+  }
+
+  void unregisterEventBus() {
+    bus.off(AppConstant.eventLabourRequestRefresh, subscribe);
+  }
+
   /// 搜索
   void doSearch(String keyword) {
     state.keyword = keyword;
@@ -168,7 +200,7 @@ class LabourReviewController extends GetxController with DioCancelableMixin {
   }
 
   /// Item选中与未选中设置
-  void doSelectedOrNot(LabourReviewListRows data) {
+  void doSelectedOrNot(UkLabourRequestReviewListRows data) {
     data.isSelected = !data.isSelected;
     Log.d("isSelected:${data.isSelected}");
     update();
@@ -177,16 +209,17 @@ class LabourReviewController extends GetxController with DioCancelableMixin {
   /// 执行批量同意
   void _requestBatchApprove(String recordIds) async {
     //执行请求
-    var result = await _labourRepository.approveLabourReviews(
-      recordIds,
+    var result = await _UkLabourRepository.labourRequestReviewBatchSubmit(
+      recordIds: recordIds,
+      type: 'approve', // 审核类型Type【approve|reject】
       cancelToken: cancelToken,
     );
 
     if (result.isSuccess) {
       NotifyEngine.showSuccess("Successful".tr);
 
-      //调用接口刷新指定的Staff的信息
-      _removeItemsByList(recordIds);
+      //成功后 移除 指定的 recordIds的项
+      _removeItemsByIds(recordIds);
     } else {
       ToastEngine.show(result.errorMsg ?? "Network Load Error".tr);
       return;
@@ -196,17 +229,17 @@ class LabourReviewController extends GetxController with DioCancelableMixin {
   /// 执行批量拒绝
   void _requestBatchReject(String recordIds, String? reason) async {
     //执行请求
-    var result = await _labourRepository.rejectLabourReviews(
-      recordIds,
-      reason,
+    var result = await _UkLabourRepository.labourRequestReviewBatchSubmit(
+      recordIds: recordIds,
+      type: 'reject', // 审核类型Type【approve|reject】
       cancelToken: cancelToken,
     );
 
     if (result.isSuccess) {
       NotifyEngine.showSuccess("Successful".tr);
 
-      //调用接口刷新指定的Staff的信息
-      _removeItemsByList(recordIds);
+      // 成功后 移除 指定的 recordIds的项
+      _removeItemsByIds(recordIds);
     } else {
       ToastEngine.show(result.errorMsg ?? "Network Load Error".tr);
       return;
@@ -259,13 +292,21 @@ class LabourReviewController extends GetxController with DioCancelableMixin {
   }
 
   /// 删除对应的recordId的Item数据
-  void _removeItemsByList(String recordIds) {
+  void _removeItemsByIds(String recordIds) {
+    // Log.d("需要移除的recordIds  ${recordIds}");
     // 将逗号分隔的字符串转换为数组
     List<String> recordIdList = recordIds.split(',');
-
     // 移除列表中符合条件的项
-    state.datas.removeWhere((e) => recordIdList.contains(e.recordId));
+    state.datas.removeWhere((e) {
+      final recordIdStr = e.recordId?.toString();
+      final shouldRemove = recordIdStr != null && recordIdList.contains(recordIdStr);
+      if (shouldRemove) {
+        Log.d("移除项目 recordId: ${recordIdStr}");
+      }
+      return shouldRemove;
+    });
 
+    Log.d("移除后的 state.datas   ${state.datas}");
     update();
   }
 
@@ -294,52 +335,54 @@ class LabourReviewController extends GetxController with DioCancelableMixin {
   }
 
   /// 去详情页面
-  void gotoDetailPage(LabourReviewListRows data) {
-    UKLabourReviewEditPage.startInstance(2, data.requestId, null);
+  void gotoDetailPage(UkLabourRequestReviewListRows data) {
+    UKLabourReviewEditPage.startInstance(2, data.requestId!.toString(), null);
   }
 
   /// 去编辑页面
-  void gotoEditPage(LabourReviewListRows data) {
-    UKLabourReviewEditPage.startInstance(1, data.requestId, (result) {
+  void gotoEditPage(UkLabourRequestReviewListRows data) {
+    UKLabourReviewEditPage.startInstance(1, data.requestId!.toString(), (result) {
+      ToastEngine.show("回调  ${result}");
       if (Utils.isNotEmpty(result)) {
-        fetchItemByIdAndRefreshItem(data.recordId);
+        // fetchItemByIdAndRefreshItem(data.requestId!.toString());
+        refreshController.callRefresh();
       }
     });
   }
 
   /// 去用工审核流程页面
-  void gotoStatusViewPage(LabourReviewListRows data) {
-    UKLabourReviewWorkflowPage.startInstance(data.requestId);
+  void gotoStatusViewPage(UkLabourRequestReviewListRows data) {
+    UKLabourReviewWorkflowPage.startInstance(data.requestId!.toString());
   }
 
   /// 根据ID获取Item对象,用于刷新
-  void fetchItemByIdAndRefreshItem(String? recordId) async {
-    var result = await _labourRepository.fetchItemByRecordId(
-      recordId,
-      cancelToken: cancelToken,
-    );
-
-    //处理数据
-    if (result.isSuccess) {
-      var data = result.data;
-      if (data != null && data.rows.isNotEmpty) {
-        List<LabourReviewListRows> newItem = data.rows;
-
-        // 创建一个 Map 来加速查找
-        Map<String, LabourReviewListRows> newItemMap = {for (var item in newItem) item.recordId ?? "": item};
-
-        // 遍历 state.datas 进行替换
-        for (int i = 0; i < state.datas.length; i++) {
-          if (newItemMap.containsKey(state.datas[i].recordId)) {
-            state.datas[i] = newItemMap[state.datas[i].recordId]!;
-          }
-        }
-
-        //刷新
-        update();
-      }
-    } else {
-      ToastEngine.show(result.errorMsg ?? "Network Load Error".tr);
-    }
-  }
+  // void fetchItemByIdAndRefreshItem(String? requestId) async {
+  //   var result = await _labourRepository.fetchItemByRecordId(
+  //     requestId,
+  //     cancelToken: cancelToken,
+  //   );
+  //
+  //   //处理数据
+  //   if (result.isSuccess) {
+  //     var data = result.data;
+  //     if (data != null && data.rows.isNotEmpty) {
+  //       List<LabourReviewListRows> newItem = data.rows;
+  //
+  //       // 创建一个 Map 来加速查找
+  //       Map<String, LabourReviewListRows> newItemMap = {for (var item in newItem) item.recordId ?? "": item};
+  //
+  //       // 遍历 state.datas 进行替换
+  //       for (int i = 0; i < state.datas.length; i++) {
+  //         if (newItemMap.containsKey(state.datas[i].recordId)) {
+  //           state.datas[i] = newItemMap[state.datas[i].recordId]!;
+  //         }
+  //       }
+  //
+  //       //刷新
+  //       update();
+  //     }
+  //   } else {
+  //     ToastEngine.show(result.errorMsg ?? "Network Load Error".tr);
+  //   }
+  // }
 }

+ 107 - 20
packages/cpt_uk/lib/modules/review/labour_review_list/labour_review_item.dart

@@ -3,6 +3,7 @@ import 'package:cs_resources/generated/assets.dart';
 import 'package:domain/entity/response/job_list_applied_info_entity.dart';
 import 'package:domain/entity/response/job_list_applied_staff_list_entity.dart';
 import 'package:domain/entity/response/labour_review_list_entity.dart';
+import 'package:domain/entity/response/uk_labour_request_review_list_entity.dart';
 import 'package:flutter/cupertino.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter/widgets.dart';
@@ -18,7 +19,7 @@ import 'package:widgets/my_text_view.dart';
  */
 class LabourReviewItem extends StatelessWidget {
   final int index;
-  final LabourReviewListRows item;
+  final UkLabourRequestReviewListRows item;
   final VoidCallback? onStatusAction;
   final VoidCallback? onEditAction;
   final VoidCallback? onDetailAction;
@@ -76,13 +77,13 @@ class LabourReviewItem extends StatelessWidget {
             ],
           ),
 
-          // 部门
+          // Event Name
           Row(
             mainAxisSize: MainAxisSize.max,
             crossAxisAlignment: CrossAxisAlignment.center,
             children: [
               MyTextView(
-                "Outlet:".tr,
+                "${'Event Name'.tr}:",
                 isFontRegular: true,
                 textColor: ColorConstants.textGrayAECAE5,
                 fontSize: 14,
@@ -90,7 +91,7 @@ class LabourReviewItem extends StatelessWidget {
 
               //部门
               MyTextView(
-                item.departmentName ?? "-",
+                item.eventName ?? "-",
                 marginLeft: 5,
                 isFontRegular: true,
                 textColor: Colors.white,
@@ -99,21 +100,21 @@ class LabourReviewItem extends StatelessWidget {
             ],
           ).marginOnly(top: 15),
 
-          // 工作日期时间
+          // 部门
           Row(
             mainAxisSize: MainAxisSize.max,
             crossAxisAlignment: CrossAxisAlignment.center,
             children: [
               MyTextView(
-                "Datetime:".tr,
+                "Outlet:".tr,
                 isFontRegular: true,
                 textColor: ColorConstants.textGrayAECAE5,
                 fontSize: 14,
               ),
 
-              //日期时间
+              //部门
               MyTextView(
-                item.jobTime ?? "-",
+                item.departmentName ?? "-",
                 marginLeft: 5,
                 isFontRegular: true,
                 textColor: Colors.white,
@@ -122,21 +123,21 @@ class LabourReviewItem extends StatelessWidget {
             ],
           ).marginOnly(top: 15),
 
-          // 人数
+          // 工作日期时间
           Row(
             mainAxisSize: MainAxisSize.max,
             crossAxisAlignment: CrossAxisAlignment.center,
             children: [
               MyTextView(
-                "No. of Staff:".tr,
+                "DateTime:".tr,
                 isFontRegular: true,
                 textColor: ColorConstants.textGrayAECAE5,
                 fontSize: 14,
               ),
 
-              //人数
+              //日期时间
               MyTextView(
-                item.needNum.toString(),
+                "${item.jobDate} ${item.jobTime}"?? "-",
                 marginLeft: 5,
                 isFontRegular: true,
                 textColor: Colors.white,
@@ -145,13 +146,100 @@ class LabourReviewItem extends StatelessWidget {
             ],
           ).marginOnly(top: 15),
 
-          // 薪水
+          // 人数  薪水
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              Expanded(
+                flex: 1,
+                child: Row(
+                  children: [
+                    MyTextView(
+                      "No. of Staff:".tr,
+                      isFontRegular: true,
+                      textColor: ColorConstants.textGrayAECAE5,
+                      fontSize: 14,
+                    ),
+
+                    //人数
+                    MyTextView(
+                      item.needNum.toString(),
+                      marginLeft: 5,
+                      isFontRegular: true,
+                      textColor: Colors.white,
+                      fontSize: 14,
+                    ),
+                  ],
+                ),
+              ),
+              // 薪水
+              Expanded(
+                flex: 1,
+                child: Row(
+                  mainAxisSize: MainAxisSize.max,
+                  crossAxisAlignment: CrossAxisAlignment.center,
+                  children: [
+                    MyTextView(
+                      "${"Salary".tr}:",
+                      isFontRegular: true,
+                      textColor: ColorConstants.textGrayAECAE5,
+                      fontSize: 14,
+                    ),
+
+                    //发布状态
+                    MyTextView(
+                      item.salary ?? "-",
+                      marginLeft: 5,
+                      isFontRegular: true,
+                      textColor: Colors.redAccent,
+                      fontSize: 14,
+                    ).expanded(),
+                  ],
+                ),
+              ),
+            ],
+          ).marginOnly(top: 15),
+
+
+
+          // Est Amount job Hours
           Row(
             mainAxisSize: MainAxisSize.max,
             crossAxisAlignment: CrossAxisAlignment.center,
             children: [
+              // Est Amount
+              Expanded(
+                flex: 1,
+                child: Row(
+                  mainAxisSize: MainAxisSize.max,
+                  crossAxisAlignment: CrossAxisAlignment.center,
+                  children: [
+                    MyTextView(
+                      "${"Est Amount(£)".tr}:",
+                      isFontRegular: true,
+                      textColor: ColorConstants.textGrayAECAE5,
+                      fontSize: 14,
+                    ),
+
+                    MyTextView(
+                      item.estAmount ?? "-",
+                      marginLeft: 5,
+                      isFontRegular: true,
+                      textColor: Colors.teal,
+                      fontSize: 14,
+                    ).expanded(),
+                  ],
+                ),
+              )
+            ],
+          ).marginOnly(top: 15),
+
+          // Job Hours
+          Row(
+            children: [
               MyTextView(
-                "${"Salary".tr}:",
+                "${"Job Hours".tr}:",
                 isFontRegular: true,
                 textColor: ColorConstants.textGrayAECAE5,
                 fontSize: 14,
@@ -159,7 +247,7 @@ class LabourReviewItem extends StatelessWidget {
 
               //发布状态
               MyTextView(
-                item.salaryShow ?? "-",
+                item.jobHours ?? "-",
                 marginLeft: 5,
                 isFontRegular: true,
                 textColor: Colors.white,
@@ -209,7 +297,6 @@ class LabourReviewItem extends StatelessWidget {
                 fontSize: 14,
               ),
 
-              //发布状态
               MyTextView(
                 item.createdAt ?? "-",
                 marginLeft: 5,
@@ -222,7 +309,7 @@ class LabourReviewItem extends StatelessWidget {
 
           //按钮组
           Visibility(
-            visible: item.btnList?.isNotEmpty ?? false,
+            visible: true,
             child: Row(
               mainAxisSize: MainAxisSize.max,
               mainAxisAlignment: MainAxisAlignment.end,
@@ -230,7 +317,7 @@ class LabourReviewItem extends StatelessWidget {
               children: [
                 //详情按钮
                 Visibility(
-                  visible: item.btnList?.contains("detail") ?? false,
+                  visible: false,
                   child: MyButton(
                     onPressed: () {
                       FocusScope.of(context).unfocus();
@@ -249,7 +336,7 @@ class LabourReviewItem extends StatelessWidget {
 
                 //Edit按钮
                 Visibility(
-                  visible: item.btnList.contains("edit") ?? false,
+                  visible: true,
                   child: MyButton(
                     onPressed: () {
                       FocusScope.of(context).unfocus();
@@ -266,7 +353,7 @@ class LabourReviewItem extends StatelessWidget {
 
                 //状态工作流按钮
                 Visibility(
-                  visible: item.btnList.contains("status") ?? false,
+                  visible: true,
                   child: MyButton(
                     onPressed: () {
                       FocusScope.of(context).unfocus();

+ 1 - 0
packages/cpt_uk/lib/modules/review/labour_review_list/labour_review_page.dart

@@ -3,6 +3,7 @@ import 'package:cs_resources/generated/assets.dart';
 import 'package:flutter/cupertino.dart';
 import 'package:flutter/material.dart';
 import 'package:get/get.dart';
+import 'package:shared/utils/log_utils.dart';
 import 'package:widgets/ext/ex_widget.dart';
 import 'package:widgets/load_state_layout.dart';
 import 'package:widgets/my_button.dart';

+ 2 - 1
packages/cpt_uk/lib/modules/review/labour_review_list/labour_review_state.dart

@@ -1,5 +1,6 @@
 import 'package:domain/entity/response/labour_request_index_entity.dart';
 import 'package:domain/entity/response/labour_review_list_entity.dart';
+import 'package:domain/entity/response/uk_labour_request_review_list_entity.dart';
 import 'package:flutter/material.dart';
 
 class LabourReviewState {
@@ -11,6 +12,6 @@ class LabourReviewState {
   String? selectedDepartmentId;
 
   //页面的列表数据
-  List<LabourReviewListRows> datas = [];
+  List<UkLabourRequestReviewListRows> datas = [];
   LabourRequestIndexEntity? indexOptions;
 }

+ 2 - 2
packages/cpt_uk/lib/modules/review/labour_review_workflow/labour_request_workflow_state.dart

@@ -1,10 +1,10 @@
-import 'package:domain/entity/response/labour_review_status_entity.dart';
+import 'package:domain/entity/response/uk_labour_review_status_entity.dart';
 
 class LabourReviewWorkflowState {
 
   String? requestId;
 
   //页面的列表数据
-  List<LabourReviewStatusRecords> datas = [];
+  List<UkLabourReviewStatusRecords> datas = [];
 
 }

+ 6 - 3
packages/cpt_uk/lib/modules/review/labour_review_workflow/labour_review_workflow_controller.dart

@@ -1,5 +1,7 @@
 import 'package:domain/entity/response/labour_review_status_entity.dart';
+import 'package:domain/entity/response/uk_labour_review_status_entity.dart';
 import 'package:domain/repository/labour_repository.dart';
+import 'package:domain/repository/uk_labour_repository.dart';
 import 'package:get/get.dart';
 import 'package:plugin_platform/http/dio/dio_cancelable_mixin.dart';
 import 'package:widgets/load_state_layout.dart';
@@ -9,7 +11,8 @@ import 'labour_request_workflow_state.dart';
 
 
 class LabourReviewWorkflowController extends GetxController with DioCancelableMixin{
-  final LabourRepository _labourRepository = Get.find();
+  // final LabourRepository _labourRepository = Get.find();
+  final UkLabourRepository _ukLabourRepository = Get.find();
   final LabourReviewWorkflowState state = LabourReviewWorkflowState();
 
   var _needShowPlaceholder = true;
@@ -48,7 +51,7 @@ class LabourReviewWorkflowController extends GetxController with DioCancelableMi
     }
 
     //获取到数据
-    var result = await _labourRepository.fetchLabourReviewStatusView(
+    var result = await _ukLabourRepository.fetchLabourReviewStatusView(
       state.requestId,
       cancelToken: cancelToken,
     );
@@ -68,7 +71,7 @@ class LabourReviewWorkflowController extends GetxController with DioCancelableMi
   }
 
   // 处理数据与展示的逻辑
-  void handleList(List<LabourReviewStatusRecords>? list) {
+  void handleList(List<UkLabourReviewStatusRecords>? list) {
     if (list != null && list.isNotEmpty) {
       //有数据,判断是刷新还是加载更多的数据
       state.datas.clear();

+ 2 - 1
packages/cpt_uk/lib/modules/review/labour_review_workflow/labour_review_workflow_item.dart

@@ -1,5 +1,6 @@
 import 'package:cs_resources/constants/color_constants.dart';
 import 'package:domain/entity/response/labour_review_status_entity.dart';
+import 'package:domain/entity/response/uk_labour_review_status_entity.dart';
 import 'package:flutter/cupertino.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter/widgets.dart';
@@ -12,7 +13,7 @@ import 'package:widgets/my_text_view.dart';
  */
 class LabourReviewWorkFlowItem extends StatelessWidget {
   final int index;
-  final LabourReviewStatusRecords item;
+  final UkLabourReviewStatusRecords item;
 
   LabourReviewWorkFlowItem({
     required this.index,

+ 0 - 0
packages/cpt_uk/lib/router/uk_router.dart


Algúns arquivos non se mostraron porque demasiados arquivos cambiaron neste cambio