Explorar o código

越南的用工审核

liukai hai 6 meses
pai
achega
75f19c1f49
Modificáronse 29 ficheiros con 3105 adicións e 50 borrados
  1. 1 1
      packages/cpt_auth/lib/modules/main/main_controller.dart
  2. 15 15
      packages/cpt_job/lib/widget/applied_butch_modify.dart
  3. 10 10
      packages/cpt_job/lib/widget/applied_staff_reviews.dart
  4. 1 2
      packages/cpt_labour/lib/modules/labour_request_list/labour_request_filter.dart
  5. 1 1
      packages/cpt_labour/lib/modules/labour_request_list/labour_request_item.dart
  6. 196 0
      packages/cpt_labour/lib/modules/labour_review_edit/labour_review_edit_controller.dart
  7. 357 0
      packages/cpt_labour/lib/modules/labour_review_edit/labour_review_edit_page.dart
  8. 41 0
      packages/cpt_labour/lib/modules/labour_review_edit/labour_review_edit_state.dart
  9. 346 0
      packages/cpt_labour/lib/modules/labour_review_list/labour_review_controller.dart
  10. 318 0
      packages/cpt_labour/lib/modules/labour_review_list/labour_review_filter.dart
  11. 292 0
      packages/cpt_labour/lib/modules/labour_review_list/labour_review_item.dart
  12. 189 0
      packages/cpt_labour/lib/modules/labour_review_list/labour_review_page.dart
  13. 190 0
      packages/cpt_labour/lib/modules/labour_review_list/labour_review_reject_dialog.dart
  14. 16 0
      packages/cpt_labour/lib/modules/labour_review_list/labour_review_state.dart
  15. 102 0
      packages/cpt_labour/lib/modules/labour_review_workflow/labour_request_workflow_page.dart
  16. 10 0
      packages/cpt_labour/lib/modules/labour_review_workflow/labour_request_workflow_state.dart
  17. 96 0
      packages/cpt_labour/lib/modules/labour_review_workflow/labour_review_workflow_controller.dart
  18. 228 0
      packages/cpt_labour/lib/modules/labour_review_workflow/labour_review_workflow_item.dart
  19. 6 1
      packages/cpt_labour/lib/router/labour_service_impl.dart
  20. 22 0
      packages/cpt_labour/lib/router/page_router.dart
  21. 23 0
      packages/cs_domain/lib/constants/api_constants.dart
  22. 58 0
      packages/cs_domain/lib/entity/response/labour_review_list_entity.dart
  23. 55 0
      packages/cs_domain/lib/entity/response/labour_review_status_entity.dart
  24. 18 0
      packages/cs_domain/lib/generated/json/base/json_convert_content.dart
  25. 122 0
      packages/cs_domain/lib/generated/json/labour_review_list_entity.g.dart
  26. 114 0
      packages/cs_domain/lib/generated/json/labour_review_status_entity.g.dart
  27. 273 20
      packages/cs_domain/lib/repository/labour_repository.dart
  28. 2 0
      packages/cs_router/lib/componentRouter/labour_service.dart
  29. 3 0
      packages/cs_router/lib/path/router_path.dart

+ 1 - 1
packages/cpt_auth/lib/modules/main/main_controller.dart

@@ -145,7 +145,7 @@ class MainController extends GetxController {
         ComponentRouterServices.reportService.startDeviceListPage();
         break;
       case 'reqReview':
-        ToastEngine.show("进入 Labour Request Review 模块");
+        ComponentRouterServices.labourService.startLabourReviewPage();
         break;
       case 'attReview':
         ToastEngine.show("进入 Attendance Review 模块");

+ 15 - 15
packages/cpt_job/lib/widget/applied_butch_modify.dart

@@ -17,7 +17,7 @@ import 'package:widgets/picker/date_picker_util.dart';
 import 'package:widgets/shatter/form_require_text.dart';
 import 'package:widgets/widget_export.dart';
 
-/**
+/*
  * 批量操作修改时间的弹窗
  */
 class AppliedButchModify extends StatefulWidget {
@@ -50,11 +50,11 @@ class _AppliedButchModifyState extends State<AppliedButchModify> {
       children: [
         //Title (如果使用 Container 为最外层容器则默认为 match_parent 的效果,除非我们限制宽度和最大高度最小高度)
         Container(
-          padding: EdgeInsets.symmetric(horizontal: 16.5),
+          padding: const EdgeInsets.symmetric(horizontal: 16.5),
           width: double.infinity,
-          decoration: BoxDecoration(
+          decoration: const BoxDecoration(
             color: Colors.white,
-            borderRadius: const BorderRadius.all(Radius.circular(15)),
+            borderRadius: BorderRadius.all(Radius.circular(15)),
           ),
           child: Column(
             crossAxisAlignment: CrossAxisAlignment.start,
@@ -79,12 +79,12 @@ class _AppliedButchModifyState extends State<AppliedButchModify> {
 
               //选择时间
               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,
@@ -116,12 +116,12 @@ class _AppliedButchModifyState extends State<AppliedButchModify> {
 
               //选择结束日期
               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,
@@ -144,8 +144,8 @@ class _AppliedButchModifyState extends State<AppliedButchModify> {
               }),
 
               Container(
-                margin: EdgeInsets.only(top: 25),
-                color: Color(0XFFCECECE),
+                margin: const EdgeInsets.only(top: 25),
+                color: const Color(0XFFCECECE),
                 height: 0.5,
               ),
               Row(
@@ -193,7 +193,7 @@ class _AppliedButchModifyState extends State<AppliedButchModify> {
                           fontSize: 17.5,
                           isFontMedium: true,
                           textAlign: TextAlign.center,
-                          textColor: Color(0XFF0085C4),
+                          textColor: const Color(0XFF0085C4),
                           cornerRadius: 3,
                         ),
                       )),

+ 10 - 10
packages/cpt_job/lib/widget/applied_staff_reviews.dart

@@ -15,7 +15,7 @@ import 'package:widgets/my_text_view.dart';
 import 'package:widgets/shatter/rating_widget.dart';
 import 'package:widgets/widget_export.dart';
 
-/**
+/*
  * 员工的评价弹窗
  */
 class AppliedStaffReviews extends StatefulWidget {
@@ -61,9 +61,9 @@ class _AppliedStaffReviewsState extends State<AppliedStaffReviews> {
         //Title (如果使用 Container 为最外层容器则默认为 match_parent 的效果,除非我们限制宽度和最大高度最小高度)
         Container(
           width: double.infinity,
-          decoration: BoxDecoration(
+          decoration: const BoxDecoration(
             color: Colors.white,
-            borderRadius: const BorderRadius.all(Radius.circular(15)),
+            borderRadius: BorderRadius.all(Radius.circular(15)),
           ),
           child: Column(
             crossAxisAlignment: CrossAxisAlignment.start,
@@ -189,12 +189,12 @@ class _AppliedStaffReviewsState extends State<AppliedStaffReviews> {
               IgnoreKeyboardDismiss(
                 child: Container(
                   height: 130,
-                  margin: EdgeInsets.symmetric(vertical: 19, horizontal: 22),
-                  padding: EdgeInsets.symmetric(vertical: 15, horizontal: 15),
+                  margin: const EdgeInsets.symmetric(vertical: 19, horizontal: 22),
+                  padding: const EdgeInsets.symmetric(vertical: 15, horizontal: 15),
                   decoration: BoxDecoration(
-                    color: Color(0xFFF0F0F0),
+                    color: const Color(0xFFF0F0F0),
                     border: Border.all(
-                      color: Color(0xFFD8D8D8),
+                      color: const Color(0xFFD8D8D8),
                       width: 0.5,
                     ),
                   ),
@@ -211,13 +211,13 @@ class _AppliedStaffReviewsState extends State<AppliedStaffReviews> {
                       isCollapsed: true,
                       border: InputBorder.none,
                       hintText: "Enter...".tr,
-                      hintStyle: TextStyle(
+                      hintStyle: const TextStyle(
                         color: ColorConstants.black66,
                         fontSize: 15.0,
                         fontWeight: FontWeight.w400,
                       ),
                     ),
-                    style: TextStyle(
+                    style: const TextStyle(
                       color: ColorConstants.black,
                       fontSize: 15.0,
                       fontWeight: FontWeight.w400,
@@ -233,7 +233,7 @@ class _AppliedStaffReviewsState extends State<AppliedStaffReviews> {
 
               // 分割线
               Container(
-                color: Color(0XFFCECECE),
+                color: const Color(0XFFCECECE),
                 height: 0.5,
               ),
 

+ 1 - 2
packages/cpt_labour/lib/modules/labour_request_list/labour_request_filter.dart

@@ -7,7 +7,6 @@ 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/date_time_utils.dart';
 import 'package:shared/utils/screen_util.dart';
 import 'package:widgets/ext/ex_widget.dart';
@@ -19,7 +18,7 @@ import 'package:widgets/picker/date_picker_util.dart';
 import 'package:widgets/picker/option_pick_util.dart';
 import 'package:widgets/widget_export.dart';
 
-/**
+/*
  * 用工请求列表的筛选
  */
 class LabourRequestFilter extends StatefulWidget {

+ 1 - 1
packages/cpt_labour/lib/modules/labour_request_list/labour_request_item.dart

@@ -8,7 +8,7 @@ import 'package:widgets/ext/ex_widget.dart';
 import 'package:widgets/my_button.dart';
 import 'package:widgets/my_text_view.dart';
 
-/**
+/*
  * 用工请求的主页面列表Item
  */
 class LabourRequestItem extends StatelessWidget {

+ 196 - 0
packages/cpt_labour/lib/modules/labour_review_edit/labour_review_edit_controller.dart

@@ -0,0 +1,196 @@
+import 'package:domain/entity/response/labour_request_edit_index_entity.dart';
+import 'package:domain/repository/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/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/util.dart';
+import 'package:widgets/picker/date_picker_util.dart';
+import 'package:widgets/picker/option_pick_util.dart';
+
+import 'labour_review_edit_state.dart';
+
+class LabourReviewEditController extends GetxController with DioCancelableMixin {
+  final LabourRepository _labourRepository = Get.find();
+  final LabourReviewEditState state = LabourReviewEditState();
+
+  /// 获取首页的数据
+  void fetchRequestDetail() async {
+    //获取到数据
+
+    final taskFuture = _labourRepository.fetchLabourReviewDetail(state.requestId, cancelToken: cancelToken);
+
+    var result = await taskFuture;
+
+    //处理数据
+    if (result.isSuccess) {
+      state.labReqOption = result.data;
+      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();
+      var needNumController = state.formData['no_of_staff']!['controller'];
+      needNumController.text = state.noStaff;
+      var amountController = state.formData['amount']!['controller'];
+      amountController.text = state.labReqOption?.amount ?? "";
+      state.selectedTemplateId = state.labReqOption?.templateId;
+      state.selectedDepartmentId = state.labReqOption?.departmentId;
+
+      state.chargeOptionId = state.labReqOption?.chargeList.firstWhere((element) => element.checked == "checked").value;
+
+      update();
+    } else {
+      ToastEngine.show(result.errorMsg ?? "Network Load Error".tr);
+    }
+  }
+
+  @override
+  void onReady() {
+    super.onReady();
+    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);
+    }
+  }
+
+  // 筛选工作模板
+  void pickJobTitle() {
+    if (state.labReqOption == null || state.pageType == 2) {
+      return;
+    }
+
+    int selectedTemplateIndex;
+    if (state.selectedTemplateId == null) {
+      selectedTemplateIndex = 0;
+    } else {
+      selectedTemplateIndex = state.labReqOption!.templateList.indexWhere((department) => department.value.toString() == state.selectedTemplateId);
+    }
+
+    if (selectedTemplateIndex < 0) {
+      selectedTemplateIndex = 0;
+    }
+
+    OptionPickerUtil.showCupertinoOptionPicker(
+      items: state.labReqOption!.templateList.map((e) => e.txt!).toList(growable: false),
+      initialSelectIndex: selectedTemplateIndex,
+      onPickerChanged: (_, index) {
+        state.selectedTemplateId = state.labReqOption!.templateList[index].value!.toString();
+        update();
+      },
+    );
+  }
+
+  //选择开始时间
+  void pickStartTime() {
+    if (state.labReqOption == null || state.pageType == 2) {
+      return;
+    }
+
+    DatePickerUtil.showCupertinoDatePicker(
+      selectedDateTime: state.selectedStartTime,
+      mode: CupertinoDatePickerMode.dateAndTime,
+      onDateTimeChanged: (date) {
+        state.selectedStartTime = date;
+        update();
+      },
+      title: "Start Time".tr,
+    );
+  }
+
+  // 选择结束时间
+  void pickEndTime() {
+    if (state.labReqOption == null || state.pageType == 2) {
+      return;
+    }
+
+    DatePickerUtil.showCupertinoDatePicker(
+      selectedDateTime: state.selectedEndTime ?? state.selectedStartTime,
+      mode: CupertinoDatePickerMode.dateAndTime,
+      onDateTimeChanged: (date) {
+        state.selectedEndTime = date;
+        update();
+      },
+      title: "End Time".tr,
+    );
+  }
+
+  // 筛选部门
+  void pickDepartment() {
+    if (state.labReqOption == null || state.pageType == 2) {
+      return;
+    }
+
+    int selectedDepartmentIndex;
+    if (state.selectedDepartmentId == null) {
+      selectedDepartmentIndex = 0;
+    } else {
+      selectedDepartmentIndex = state.labReqOption!.departmentList.indexWhere((department) => department.value.toString() == state.selectedDepartmentId);
+    }
+
+    if (selectedDepartmentIndex < 0) {
+      selectedDepartmentIndex = 0;
+    }
+
+    OptionPickerUtil.showCupertinoOptionPicker(
+      items: state.labReqOption!.departmentList.map((e) => e.txt!).toList(growable: false),
+      initialSelectIndex: selectedDepartmentIndex,
+      onPickerChanged: (_, index) {
+        state.selectedDepartmentId = state.labReqOption!.departmentList[index].value!.toString();
+        update();
+      },
+    );
+  }
+}

+ 357 - 0
packages/cpt_labour/lib/modules/labour_review_edit/labour_review_edit_page.dart

@@ -0,0 +1,357 @@
+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';
+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/date_time_utils.dart';
+import 'package:shared/utils/screen_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_radio_check.dart';
+import 'package:widgets/shatter/form_require_text.dart';
+import 'package:widgets/shatter/round_my_text_field.dart';
+
+import 'labour_review_edit_controller.dart';
+import 'labour_review_edit_state.dart';
+
+class LabourReviewEditPage extends BaseStatefulPage<LabourReviewEditController> {
+  LabourReviewEditPage({Key? key}) : super(key: key);
+
+  //启动当前页面,pageType  1是编辑  2是详情
+  static void startInstance(int pageType, String? requestId,void Function(dynamic value)? cb) {
+    return Get.start(RouterPath.labourReviewEdit, arguments: {'pageType': pageType, 'requestId': requestId,'cb': cb});
+  }
+
+  @override
+  LabourReviewEditController createRawController() {
+    return LabourReviewEditController();
+  }
+
+  @override
+  State<LabourReviewEditPage> createState() => _LabourReviewEditState();
+}
+
+class _LabourReviewEditState extends BaseState<LabourReviewEditPage, LabourReviewEditController> {
+  late LabourReviewEditState state;
+
+  @override
+  void initState() {
+    super.initState();
+    state = controller.state;
+    state.pageType = Get.arguments['pageType'];
+    state.requestId = Get.arguments['requestId'];
+    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 == 1 ? "Edit Labour Requisition".tr : "Labour Requisition".tr),
+        body: SafeArea(
+          bottom: true,
+          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: [
+                      //工作标题,选择模板
+                      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),
+                      ),
+                    ],
+                  ).paddingOnly(left: 15, right: 15),
+                ),
+              ),
+            ),
+          ),
+        ),
+      );
+    });
+  }
+}

+ 41 - 0
packages/cpt_labour/lib/modules/labour_review_edit/labour_review_edit_state.dart

@@ -0,0 +1,41 @@
+import 'package:domain/entity/response/labour_request_edit_index_entity.dart';
+import 'package:flutter/material.dart';
+import 'package:plugin_basic/basic_export.dart';
+
+class LabourReviewEditState {
+
+  int pageType = 2;  //页面的状态 1是编辑  2是详情
+  String? requestId;  //编辑和详情需要用到ID
+  void Function(dynamic value)? cb;
+
+  //页面对应的详情数据
+  LabourRequestEditIndexEntity? labReqOption;
+
+  //页面对应的选择的条件
+  DateTime? selectedStartTime;
+  DateTime? selectedEndTime;
+  String? selectedTemplateId;
+  String? selectedDepartmentId;
+  String? noStaff;  //成员数量
+
+  String? chargeOptionId;
+
+  //表单的校验与数据
+  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,
+    },
+  };
+
+}

+ 346 - 0
packages/cpt_labour/lib/modules/labour_review_list/labour_review_controller.dart

@@ -0,0 +1,346 @@
+import 'package:domain/entity/response/labour_request_index_entity.dart';
+import 'package:domain/entity/response/labour_review_list_entity.dart';
+import 'package:domain/repository/labour_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: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/widget_export.dart';
+
+import '../labour_review_edit/labour_review_edit_page.dart';
+import '../labour_review_workflow/labour_request_workflow_page.dart';
+import 'labour_review_filter.dart';
+import 'labour_review_reject_dialog.dart';
+import 'labour_review_state.dart';
+
+class LabourReviewController extends GetxController with DioCancelableMixin {
+  final LabourRepository _labourRepository = Get.find();
+  final LabourReviewState state = LabourReviewState();
+
+  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;
+    fetchAppliedStaffList();
+  }
+
+  // Refresh 加载事件
+  Future loadMore() async {
+    _curPage++;
+    fetchAppliedStaffList();
+  }
+
+  // 重试请求
+  Future retryRequest() async {
+    _curPage = 1;
+    _needShowPlaceholder = true;
+    fetchAppliedStaffList();
+  }
+
+  /// 获取服务器数据,通知消息列表
+  Future fetchAppliedStaffList() 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,
+      ),
+      state.indexOptions == null
+          ? _labourRepository.fetchLabourReviewIndex(
+              cancelToken: cancelToken,
+            )
+          : Future(() => HttpResult(isSuccess: true).convert(data: state.indexOptions!)),
+    ];
+
+    //拿到结果
+    var results = await Future.wait(futures);
+    var listResult = results[0] as HttpResult<LabourReviewListEntity>;
+    var optionResult = results[1] as HttpResult<LabourRequestIndexEntity>;
+
+    //选项数据
+    if (state.indexOptions == null && optionResult.isSuccess) {
+      state.indexOptions = optionResult.data!;
+    }
+
+    // 处理数据
+    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();
+
+        //更新展示的状态
+        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();
+    fetchAppliedStaffList();
+  }
+
+  @override
+  void onClose() {
+    state.datas.clear();
+    super.onClose();
+  }
+
+  /// 搜索
+  void doSearch(String keyword) {
+    state.keyword = keyword;
+    //赋值之后刷新
+    refreshController.callRefresh();
+  }
+
+  /// 清空筛选条件
+  void resetFiltering() {
+    state.keyword = "";
+    state.searchController.text = "";
+    state.selectedStartDate = null;
+    state.selectedEndDate = null;
+    state.selectedDepartmentId = null;
+    //赋值之后刷新
+    refreshController.callRefresh();
+  }
+
+  /// Item选中与未选中设置
+  void doSelectedOrNot(LabourReviewListRows data) {
+    data.isSelected = !data.isSelected;
+    Log.d("isSelected:${data.isSelected}");
+    update();
+  }
+
+  /// 执行批量同意
+  void _requestBatchApprove(String recordIds) async {
+    //执行请求
+    var result = await _labourRepository.approveLabourReviews(
+      recordIds,
+      cancelToken: cancelToken,
+    );
+
+    if (result.isSuccess) {
+      NotifyEngine.showSuccess("Successful".tr);
+
+      //调用接口刷新指定的Staff的信息
+      _removeItemsByList(recordIds);
+    } else {
+      ToastEngine.show(result.errorMsg ?? "Network Load Error".tr);
+      return;
+    }
+  }
+
+  /// 执行批量拒绝
+  void _requestBatchReject(String recordIds, String? reason) async {
+    //执行请求
+    var result = await _labourRepository.rejectLabourReviews(
+      recordIds,
+      reason,
+      cancelToken: cancelToken,
+    );
+
+    if (result.isSuccess) {
+      NotifyEngine.showSuccess("Successful".tr);
+
+      //调用接口刷新指定的Staff的信息
+      _removeItemsByList(recordIds);
+    } else {
+      ToastEngine.show(result.errorMsg ?? "Network Load Error".tr);
+      return;
+    }
+  }
+
+  /// 批准的操作
+  void operationApprove() async {
+    //找出已经选中的员工(只有状态为3 Approve的状态才能修改)
+    var selectedList = state.datas.where((element) => element.isSelected).toList(growable: false);
+    if (selectedList.isNotEmpty) {
+      var ids = selectedList.map((e) => e.recordId.toString()).toList(growable: false);
+      var recordIds = ids.join(',');
+
+      // Are you sure 的弹窗
+      DialogEngine.show(
+        widget: AppDefaultDialog(
+          title: "Message".tr,
+          message: "Are you sure you want to setting approved?".tr,
+          confirmAction: () {
+            _requestBatchApprove(recordIds);
+          },
+        ),
+      );
+    } else {
+      ToastEngine.show("Please select the record".tr);
+    }
+  }
+
+  /// 拒绝的操作
+  void operationReject() async {
+    //找出已经选中的员工(只有状态为3 Approve的状态才能修改)
+    var selectedList = state.datas.where((element) => element.isSelected).toList(growable: false);
+    if (selectedList.isNotEmpty) {
+      var ids = selectedList.map((e) => e.recordId.toString()).toList(growable: false);
+      var recordIds = ids.join(',');
+
+      // Are you sure 的弹窗
+      DialogEngine.show(
+        widget: LabourReviewRejectDialog(
+          confirmAction: (reason) {
+            //请求接口,提交评论
+            _requestBatchReject(recordIds, reason);
+          },
+        ),
+      );
+    } else {
+      ToastEngine.show("Please select the record".tr);
+    }
+  }
+
+  /// 删除对应的recordId的Item数据
+  void _removeItemsByList(String recordIds) {
+    // 将逗号分隔的字符串转换为数组
+    List<String> recordIdList = recordIds.split(',');
+
+    // 移除列表中符合条件的项
+    state.datas.removeWhere((e) => recordIdList.contains(e.recordId));
+
+    update();
+  }
+
+  /// 展示顶部的筛选
+  void showFilterDialog() {
+    if (state.indexOptions != null) {
+      DialogEngine.show(
+        widget: LabourReviewFilter(
+          optionResult: state.indexOptions!,
+          selectedStartDate: state.selectedStartDate,
+          selectedEndDate: state.selectedEndDate,
+          selectedDepartmentId: state.selectedDepartmentId,
+          onFilterAction: (startDate, endDate, departmentId) {
+            state.selectedStartDate = startDate;
+            state.selectedEndDate = endDate;
+            state.selectedDepartmentId = departmentId;
+
+            //赋值之后刷新
+            refreshController.callRefresh();
+          },
+        ),
+        position: DialogPosition.top,
+        animType: DialogAnimation.fade,
+      );
+    }
+  }
+
+  /// 去详情页面
+  void gotoDetailPage(LabourReviewListRows data) {
+    LabourReviewEditPage.startInstance(2, data.requestId, null);
+  }
+
+  /// 去编辑页面
+  void gotoEditPage(LabourReviewListRows data) {
+    LabourReviewEditPage.startInstance(1, data.requestId, (result) {
+      if (Utils.isNotEmpty(result)) {
+        fetchItemByIdAndRefreshItem(data.recordId);
+      }
+    });
+  }
+
+  /// 去用工审核流程页面
+  void gotoStatusViewPage(LabourReviewListRows data) {
+    LabourReviewWorkflowPage.startInstance(data.requestId);
+  }
+
+  /// 根据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);
+    }
+  }
+}

+ 318 - 0
packages/cpt_labour/lib/modules/labour_review_list/labour_review_filter.dart

@@ -0,0 +1,318 @@
+import 'dart:typed_data';
+import 'dart:ui';
+import 'package:cs_resources/generated/assets.dart';
+import 'package:domain/entity/response/labour_request_index_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/date_time_utils.dart';
+import 'package:shared/utils/screen_util.dart';
+import 'package:widgets/ext/ex_widget.dart';
+import 'package:cs_resources/constants/color_constants.dart';
+import 'package:widgets/my_button.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/picker/option_pick_util.dart';
+import 'package:widgets/widget_export.dart';
+
+/*
+ * 用工请求列表的筛选
+ */
+class LabourReviewFilter extends StatefulWidget {
+  void Function(DateTime? selectedStartDate, DateTime? selectedEndDate, String? selectedDepartmentId)? onFilterAction;
+  LabourRequestIndexEntity optionResult;
+  DateTime? selectedStartDate;
+  DateTime? selectedEndDate;
+  String? selectedDepartmentId;
+
+  LabourReviewFilter({
+    required this.optionResult,
+    required this.selectedStartDate,
+    required this.selectedEndDate,
+    required this.selectedDepartmentId,
+    this.onFilterAction,
+  });
+
+  @override
+  State<LabourReviewFilter> createState() => _LabourReviewFilterState();
+}
+
+class _LabourReviewFilterState extends State<LabourReviewFilter> {
+  DateTime? selectedStartDate;
+  DateTime? selectedEndDate;
+  String? selectedStatusId;
+  String? selectedDepartmentId;
+
+  @override
+  void initState() {
+    super.initState();
+    this.selectedStartDate = widget.selectedStartDate;
+    this.selectedEndDate = widget.selectedEndDate;
+    this.selectedDepartmentId = widget.selectedDepartmentId;
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return Column(
+      crossAxisAlignment: CrossAxisAlignment.start,
+      mainAxisAlignment: MainAxisAlignment.start,
+      children: [
+        SizedBox(
+          height: kToolbarHeight + ScreenUtil.getStatusBarH(context) + 1,
+        ),
+        Container(
+          padding: const EdgeInsets.only(left: 15, right: 15, top: 17.5, bottom: 20),
+          width: double.infinity,
+          decoration: const BoxDecoration(
+            color: Colors.white,
+          ),
+          child: Column(
+            crossAxisAlignment: CrossAxisAlignment.start,
+            children: [
+              //部门
+              MyTextView(
+                "Outlet".tr,
+                fontSize: 14,
+                isFontMedium: true,
+                textColor: ColorConstants.black33,
+              ),
+
+              //选择部门
+              Container(
+                padding: const EdgeInsets.only(left: 16, right: 10),
+                margin: const EdgeInsets.only(top: 10),
+                height: 45,
+                decoration: const BoxDecoration(
+                  color: ColorConstants.grayECECEC,
+                  borderRadius: BorderRadius.all(Radius.circular(5)),
+                ),
+                child: Row(
+                  mainAxisSize: MainAxisSize.max,
+                  crossAxisAlignment: CrossAxisAlignment.center,
+                  mainAxisAlignment: MainAxisAlignment.start,
+                  children: [
+                    MyTextView(
+                      selectedDepartmentId == null || selectedDepartmentId == "0"
+                          ? ""
+                          : widget.optionResult.departmentList!.firstWhere((element) => element.value.toString() == selectedDepartmentId).txt!,
+                      hint: "Choose Outlet".tr,
+                      textHintColor: ColorConstants.textBlackHint,
+                      fontSize: 14,
+                      isFontMedium: true,
+                      textColor: ColorConstants.black33,
+                    ).expanded(),
+                    MyAssetImage(Assets.baseServiceTriangleDropDownIcon, width: 11.5, height: 6.28),
+                  ],
+                ),
+              ).onTap(() {
+                pickerOutlet();
+              }),
+
+              //开始时间
+              MyTextView(
+                "Start Date".tr,
+                fontSize: 14,
+                isFontMedium: true,
+                marginTop: 11,
+                textColor: ColorConstants.black33,
+              ),
+
+              //选择时间
+              Container(
+                padding: const EdgeInsets.only(left: 16, right: 10),
+                margin: const EdgeInsets.only(top: 10),
+                height: 45,
+                decoration: const BoxDecoration(
+                  color: ColorConstants.grayECECEC,
+                  borderRadius: BorderRadius.all(Radius.circular(5)),
+                ),
+                child: Row(
+                  mainAxisSize: MainAxisSize.max,
+                  crossAxisAlignment: CrossAxisAlignment.center,
+                  mainAxisAlignment: MainAxisAlignment.start,
+                  children: [
+                    MyTextView(
+                      selectedStartDate == null ? "" : DateTimeUtils.formatDate(selectedStartDate, format: "yyyy-MM-dd"),
+                      fontSize: 14,
+                      hint: "Choose Start Date".tr,
+                      textHintColor: ColorConstants.textBlackHint,
+                      isFontMedium: true,
+                      textColor: ColorConstants.black33,
+                    ).expanded(),
+                    const MyAssetImage(Assets.baseServiceTriangleDropDownIcon, width: 11.5, height: 6.28),
+                  ],
+                ),
+              ).onTap(() {
+                pickerStartDate();
+              }),
+
+              //结束日期
+              MyTextView(
+                "End Date".tr,
+                fontSize: 14,
+                marginTop: 11,
+                isFontMedium: true,
+                textColor: ColorConstants.black33,
+              ),
+
+              //选择结束日期
+              Container(
+                padding: const EdgeInsets.only(left: 16, right: 10),
+                margin: const EdgeInsets.only(top: 10),
+                height: 45,
+                decoration: const BoxDecoration(
+                  color: ColorConstants.grayECECEC,
+                  borderRadius: BorderRadius.all(Radius.circular(5)),
+                ),
+                child: Row(
+                  mainAxisSize: MainAxisSize.max,
+                  crossAxisAlignment: CrossAxisAlignment.center,
+                  mainAxisAlignment: MainAxisAlignment.start,
+                  children: [
+                    MyTextView(
+                      selectedEndDate == null ? "" : DateTimeUtils.formatDate(selectedEndDate, format: "yyyy-MM-dd"),
+                      fontSize: 14,
+                      hint: "Choose End Date".tr,
+                      textHintColor: ColorConstants.textBlackHint,
+                      isFontMedium: true,
+                      textColor: ColorConstants.black33,
+                    ).expanded(),
+                    const MyAssetImage(Assets.baseServiceTriangleDropDownIcon, width: 11.5, height: 6.28),
+                  ],
+                ),
+              ).onTap(() {
+                pickerEndDate();
+              }),
+
+              //按钮组
+              Row(
+                children: [
+                  MyButton(
+                    onPressed: () {
+                      //只是Reset当前的弹窗筛选选项
+                      widget.selectedStartDate = null;
+                      widget.selectedEndDate = null;
+                      widget.selectedDepartmentId = null;
+
+                      setState(() {
+                        selectedStartDate = null;
+                        selectedEndDate = null;
+                        selectedStatusId = null;
+                        selectedDepartmentId = null;
+                      });
+                    },
+                    text: "Reset".tr,
+                    textColor: ColorConstants.white,
+                    backgroundColor: hexToColor("#FFBB1B"),
+                    radius: 17.25,
+                    minWidth: 60,
+                    minHeight: 36,
+                  ).expanded(),
+                  SizedBox(width: 15),
+                  MyButton(
+                    onPressed: () {
+                      onCancel();
+                      widget.onFilterAction?.call(selectedStartDate, selectedEndDate, selectedDepartmentId);
+                    },
+                    text: "Filter".tr,
+                    textColor: ColorConstants.white,
+                    backgroundColor: hexToColor("#0AC074"),
+                    radius: 17.25,
+                    minWidth: 60,
+                    minHeight: 36,
+                  ).expanded(),
+                ],
+              ).marginOnly(top: 20),
+            ],
+          ),
+        ),
+        Center(child: const MyAssetImage(Assets.baseServiceDialogDeleteIcon, width: 26.5, height: 26.5).marginOnly(top: 35)).onTap(() {
+          onCancel();
+        }),
+      ],
+    );
+  }
+
+  //取消弹框
+  void onCancel() async {
+    SmartDialog.dismiss();
+  }
+
+  /// 筛选开始日期
+  void pickerStartDate() {
+    DatePickerUtil.showCupertinoDatePicker(
+      selectedDateTime: selectedStartDate,
+      onDateTimeChanged: (date) {
+        setState(() {
+          selectedStartDate = date;
+        });
+      },
+      title: "Start Date".tr,
+    );
+  }
+
+  /// 筛选结束日期
+  void pickerEndDate() {
+    DatePickerUtil.showCupertinoDatePicker(
+      selectedDateTime: selectedEndDate ?? selectedStartDate,
+      onDateTimeChanged: (date) {
+        setState(() {
+          selectedEndDate = date;
+        });
+      },
+      title: "End Date".tr,
+    );
+  }
+
+  /// 筛选部门
+  void pickerOutlet() {
+    int selectedDepartmentIndex;
+    if (selectedDepartmentId == null) {
+      selectedDepartmentIndex = 0;
+    } else {
+      selectedDepartmentIndex = widget.optionResult.departmentList!.indexWhere((department) => department.value.toString() == selectedDepartmentId);
+    }
+
+    if (selectedDepartmentIndex < 0) {
+      selectedDepartmentIndex = 0;
+    }
+
+    OptionPickerUtil.showCupertinoOptionPicker(
+      items: widget.optionResult.departmentList!.map((e) => e.txt!).toList(growable: false),
+      initialSelectIndex: selectedDepartmentIndex,
+      onPickerChanged: (_, index) {
+        setState(() {
+          selectedDepartmentId = widget.optionResult.departmentList![index].value!.toString();
+        });
+      },
+    );
+  }
+
+  /// 筛选状态
+  void pickerStatus() {
+    int selectedStatusIndex;
+    if (selectedStatusId == null) {
+      selectedStatusIndex = 0;
+    } else {
+      selectedStatusIndex = widget.optionResult.statusList!.indexWhere((department) => department.value.toString() == selectedStatusId);
+    }
+
+    if (selectedStatusIndex < 0) {
+      selectedStatusIndex = 0;
+    }
+
+    OptionPickerUtil.showCupertinoOptionPicker(
+      items: widget.optionResult.statusList!.map((e) => e.txt!).toList(growable: false),
+      initialSelectIndex: selectedStatusIndex,
+      onPickerChanged: (_, index) {
+        setState(() {
+          selectedStatusId = widget.optionResult.statusList![index].value!.toString();
+        });
+      },
+    );
+  }
+}

+ 292 - 0
packages/cpt_labour/lib/modules/labour_review_list/labour_review_item.dart

@@ -0,0 +1,292 @@
+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/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: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';
+
+/*
+ * 用工审核的列表Item
+ */
+class LabourReviewItem extends StatelessWidget {
+  final int index;
+  final LabourReviewListRows item;
+  final VoidCallback? onStatusAction;
+  final VoidCallback? onEditAction;
+  final VoidCallback? onDetailAction;
+  final VoidCallback? onItemAction;
+
+  LabourReviewItem({
+    required this.index,
+    required this.item,
+    this.onStatusAction,
+    this.onEditAction,
+    this.onDetailAction,
+    this.onItemAction,
+  });
+
+  @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(
+                item.jobTitle ?? "-",
+                isFontMedium: true,
+                textColor: ColorConstants.textYellowFFBB1B,
+                fontSize: 14,
+                marginLeft: 5,
+                marginRight: 5,
+                textDecoration: TextDecoration.underline,
+                decorationColor: ColorConstants.textYellowFFBB1B,
+                // 可选,设置下划线的颜色
+                decorationThickness: 2.0,
+                // 可选,设置下划线的粗细
+                decorationStyle: TextDecorationStyle.solid,
+              ).expanded(),
+
+              //是否选中
+              MyAssetImage(
+                item.isSelected ? Assets.baseServiceItemSelectedIcon : Assets.baseServiceItemUnselectedIcon,
+                width: 20.5,
+                height: 20.5,
+              ),
+            ],
+          ),
+
+          // 部门
+          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(),
+            ],
+          ).marginOnly(top: 15),
+
+          // 工作日期时间
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "Datetime:".tr,
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+
+              //日期时间
+              MyTextView(
+                item.jobTime ?? "-",
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor: Colors.white,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ).marginOnly(top: 15),
+
+          // 人数
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            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(),
+            ],
+          ).marginOnly(top: 15),
+
+          // 薪水
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "${"Salary".tr}:",
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+
+              //发布状态
+              MyTextView(
+                item.salaryShow ?? "-",
+                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: "Approved" == item.statusShow
+                    ? ColorConstants.textGreen05DC82
+                    : "Rejected" == item.statusShow
+                        ? ColorConstants.textRedFF6262
+                        : "Recall" == item.statusShow
+                            ? ColorConstants.textYellowFFBB1B
+                            : ColorConstants.textBlue06D9FF,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ).marginOnly(top: 15),
+
+          // 创建时间
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "Created 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.btnList?.isNotEmpty ?? false,
+            child: Row(
+              mainAxisSize: MainAxisSize.max,
+              mainAxisAlignment: MainAxisAlignment.end,
+              crossAxisAlignment: CrossAxisAlignment.center,
+              children: [
+                //详情按钮
+                Visibility(
+                  visible: item.btnList?.contains("detail") ?? false,
+                  child: MyButton(
+                    onPressed: () {
+                      FocusScope.of(context).unfocus();
+                      onDetailAction?.call();
+                    },
+                    text: "Detail".tr,
+                    textColor: ColorConstants.white,
+                    backgroundColor: hexToColor(
+                      "#56AAFF",
+                    ),
+                    radius: 17.25,
+                    minWidth: 60,
+                    minHeight: 35,
+                  ).marginOnly(left: 12),
+                ),
+
+                //Edit按钮
+                Visibility(
+                  visible: item.btnList.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.btnList.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),
+                ),
+              ],
+            ).marginOnly(top: 18, bottom: 2),
+          ),
+        ],
+      ),
+    ).onTap(() {
+      onItemAction?.call();
+    });
+  }
+}

+ 189 - 0
packages/cpt_labour/lib/modules/labour_review_list/labour_review_page.dart

@@ -0,0 +1,189 @@
+import 'package:cs_resources/constants/color_constants.dart';
+import 'package:cs_resources/generated/assets.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_load_image.dart';
+import 'package:widgets/my_text_view.dart';
+import 'package:widgets/widget_export.dart';
+
+import 'labour_review_item.dart';
+import 'labour_review_controller.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 'labour_review_state.dart';
+
+/*
+ * 用工请求审核的列表
+ */
+class LabourReviewPage extends BaseStatefulPage<LabourReviewController> {
+  LabourReviewPage({Key? key}) : super(key: key);
+
+  //启动当前页面
+  static void startInstance() {
+    return Get.start(RouterPath.labourReviewList);
+  }
+
+  @override
+  LabourReviewController createRawController() {
+    return LabourReviewController();
+  }
+
+  @override
+  State<LabourReviewPage> createState() => _LabourReviewState();
+}
+
+class _LabourReviewState extends BaseState<LabourReviewPage, LabourReviewController> {
+  late LabourReviewState state;
+
+  @override
+  void initState() {
+    super.initState();
+    state = controller.state;
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return autoCtlGetBuilder(builder: (controller) {
+      return SafeArea(
+        bottom: true,
+        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.searchTitleBar(
+                context,
+                value: state.keyword,
+                hintText: 'Title'.tr,
+                controller: state.searchController,
+                onSearch: (keyword) {
+                  controller.doSearch(keyword);
+                },
+                actions: [
+                  //重置按钮
+                  MyButton(
+                    onPressed: () {
+                      FocusScope.of(context).unfocus();
+                      controller.resetFiltering();
+                    },
+                    text: "Reset".tr,
+                    textColor: ColorConstants.white,
+                    backgroundColor: hexToColor("#2BA9F9", opacity: 0.5),
+                    radius: 17.25,
+                    minWidth: 60,
+                    minHeight: 35,
+                  ).marginOnly(right: 15),
+
+                  //筛选图标
+                  const MyAssetImage(
+                    Assets.baseServiceTitleBarFilterIcon,
+                    width: 24,
+                    height: 16.5,
+                  ).onTap(() {
+                    FocusScope.of(context).unfocus();
+                    controller.showFilterDialog();
+                  }).marginOnly(right: 15),
+                ],
+              ),
+
+              //底部的列表
+              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 LabourReviewItem(
+                          index: index,
+                          item: state.datas[index],
+                          onDetailAction: () {
+                            controller.gotoDetailPage(state.datas[index]);
+                          },
+                          onEditAction: () {
+                            controller.gotoEditPage(state.datas[index]);
+                          },
+                          onStatusAction: () {
+                            controller.gotoStatusViewPage(state.datas[index]);
+                          },
+                          onItemAction: () {
+                            controller.doSelectedOrNot(state.datas[index]);
+                          },
+                        );
+                      },
+                      childCount: state.datas.length,
+                    ))
+                  ],
+                ),
+              ).expanded(),
+
+              Row(
+                mainAxisSize: MainAxisSize.max,
+                children: [
+                  //批量Approve
+                  MyTextView(
+                    "Batch Confirm".tr,
+                    fontSize: 17,
+                    isFontMedium: true,
+                    boxHeight: 48,
+                    onClick: () {
+                      controller.operationApprove();
+                    },
+                    alignment: Alignment.center,
+                    textAlign: TextAlign.center,
+                    textColor: Colors.white,
+                    backgroundColor: ColorConstants.textGreen0AC074,
+                  ).expanded(),
+
+                  //批量修改时间
+                  MyTextView(
+                    "Batch Reject".tr,
+                    fontSize: 17,
+                    isFontMedium: true,
+                    boxHeight: 48,
+                    onClick: () {
+                      controller.operationReject();
+                    },
+                    alignment: Alignment.center,
+                    textAlign: TextAlign.center,
+                    textColor: Colors.white,
+                    backgroundColor: ColorConstants.textRedFF6262,
+                  ).expanded(),
+                ],
+              ),
+            ],
+          ),
+        ),
+      );
+    });
+  }
+}

+ 190 - 0
packages/cpt_labour/lib/modules/labour_review_list/labour_review_reject_dialog.dart

@@ -0,0 +1,190 @@
+import 'dart:ui';
+
+import 'package:cs_resources/generated/assets.dart';
+import 'package:domain/entity/response/job_list_remark_view_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_text_view.dart';
+import 'package:widgets/shatter/rating_widget.dart';
+import 'package:widgets/widget_export.dart';
+
+/*
+ * 拒绝的弹窗
+ */
+class LabourReviewRejectDialog extends StatefulWidget {
+
+  void Function(String reason)? confirmAction;
+
+  LabourReviewRejectDialog({this.confirmAction});
+
+  @override
+  State<LabourReviewRejectDialog> createState() => _LabourReviewRejectDialogState();
+}
+
+class _LabourReviewRejectDialogState extends State<LabourReviewRejectDialog> {
+
+  late TextEditingController _controller;
+  late FocusNode _focusNode;
+
+  @override
+  void initState() {
+    super.initState();
+    _controller = TextEditingController();
+    _focusNode = FocusNode();
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return Column(
+      crossAxisAlignment: CrossAxisAlignment.center,
+      mainAxisAlignment: MainAxisAlignment.center,
+      children: [
+        //Title (如果使用 Container 为最外层容器则默认为 match_parent 的效果,除非我们限制宽度和最大高度最小高度)
+        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(
+                  "Reason for refusal".tr,
+                  fontSize: 19,
+                  isFontMedium: true,
+                  textColor: ColorConstants.black,
+                  marginTop: 23,
+                  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: true,
+                    focusNode: _focusNode,
+                    controller: _controller,
+                    // 装饰
+                    decoration: InputDecoration(
+                      isDense: true,
+                      isCollapsed: true,
+                      border: InputBorder.none,
+                      hintText: "Enter...".tr,
+                      hintStyle: const 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,
+              ),
+
+              //按钮组
+              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),
+            ],
+          ),
+        ),
+      ],
+    ).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);
+  }
+}

+ 16 - 0
packages/cpt_labour/lib/modules/labour_review_list/labour_review_state.dart

@@ -0,0 +1,16 @@
+import 'package:domain/entity/response/labour_request_index_entity.dart';
+import 'package:domain/entity/response/labour_review_list_entity.dart';
+import 'package:flutter/material.dart';
+
+class LabourReviewState {
+  //筛选条件
+  final TextEditingController searchController = TextEditingController();
+  String keyword = "";
+  DateTime? selectedStartDate;
+  DateTime? selectedEndDate;
+  String? selectedDepartmentId;
+
+  //页面的列表数据
+  List<LabourReviewListRows> datas = [];
+  LabourRequestIndexEntity? indexOptions;
+}

+ 102 - 0
packages/cpt_labour/lib/modules/labour_review_workflow/labour_request_workflow_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 'labour_review_workflow_controller.dart';
+import 'labour_request_workflow_state.dart';
+import 'labour_review_workflow_item.dart';
+
+/*
+ * 用工请求审核-状态工作流列表
+ */
+class LabourReviewWorkflowPage extends BaseStatefulPage<LabourReviewWorkflowController> {
+  LabourReviewWorkflowPage({Key? key}) : super(key: key);
+
+  //启动当前页面
+  static void startInstance(String? requestId) {
+    return Get.start(RouterPath.labourReviewWorkflow,arguments: {'requestId': requestId});
+  }
+
+  @override
+  LabourReviewWorkflowController createRawController() {
+    return LabourReviewWorkflowController();
+  }
+
+  @override
+  State<LabourReviewWorkflowPage> createState() => _LabourReviewWorkflowState();
+
+}
+
+class _LabourReviewWorkflowState extends BaseState<LabourReviewWorkflowPage, LabourReviewWorkflowController> {
+
+  late LabourReviewWorkflowState state;
+
+  @override
+  void initState() {
+    super.initState();
+    state = controller.state;
+    state.requestId = Get.arguments['requestId'];
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return autoCtlGetBuilder(builder: (controller) {
+      return  SafeArea(
+          bottom: true,
+          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, "Workflow".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 LabourReviewWorkFlowItem(index: index,item: state.datas[index]);
+                            },
+                            childCount: state.datas.length,
+                          ))
+                    ],
+                  ),
+                ).expanded(),
+              ],
+            ).marginOnly(top: 10),
+          ),
+        );
+    });
+  }
+}
+
+

+ 10 - 0
packages/cpt_labour/lib/modules/labour_review_workflow/labour_request_workflow_state.dart

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

+ 96 - 0
packages/cpt_labour/lib/modules/labour_review_workflow/labour_review_workflow_controller.dart

@@ -0,0 +1,96 @@
+import 'package:domain/entity/response/labour_review_status_entity.dart';
+import 'package:domain/repository/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';
+import 'package:widgets/widget_export.dart';
+
+import 'labour_request_workflow_state.dart';
+
+
+class LabourReviewWorkflowController extends GetxController with DioCancelableMixin{
+  final LabourRepository _labourRepository = Get.find();
+  final LabourReviewWorkflowState state = LabourReviewWorkflowState();
+
+  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 _labourRepository.fetchLabourReviewStatusView(
+      state.requestId,
+      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<LabourReviewStatusRecords>? 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();
+  }
+}

+ 228 - 0
packages/cpt_labour/lib/modules/labour_review_workflow/labour_review_workflow_item.dart

@@ -0,0 +1,228 @@
+import 'package:cs_resources/constants/color_constants.dart';
+import 'package:domain/entity/response/labour_review_status_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 LabourReviewWorkFlowItem extends StatelessWidget {
+  final int index;
+  final LabourReviewStatusRecords item;
+
+  LabourReviewWorkFlowItem({
+    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: [
+          //Node
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "Node:".tr,
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+
+              MyTextView(
+                item.nodeName ?? "-",
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor: Colors.white,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ),
+
+          // assigneeType
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "Type:".tr,
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+
+              //日期时间
+              MyTextView(
+                item.assigneeTypeShow ?? "-",
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor: Colors.white,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ).marginOnly(top: 15),
+
+          // Designation
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "Designation:".tr,
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+
+              //人数
+              MyTextView(
+                item.designationShow ?? "-",
+                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: "Approved" == item.statusShow
+                    ? ColorConstants.textGreen05DC82
+                    : "Rejected" == item.statusShow
+                    ? ColorConstants.textRedFF6262
+                    : "Recall" == item.statusShow
+                    ? ColorConstants.textYellowFFBB1B
+                    : ColorConstants.textBlue06D9FF,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ).marginOnly(top: 15),
+
+          // Operator
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "Operator:".tr,
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+
+              //发布状态
+              MyTextView(
+                item.auditName ?? "-",
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor: Colors.white,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ).marginOnly(top: 15),
+
+          // 操作时间
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "Audit Time:".tr,
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+
+              //时间
+              MyTextView(
+                item.auditTime ?? "-",
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor: Colors.white,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ).marginOnly(top: 15),
+
+          // 创建时间
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "Created 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),
+
+          // Remark
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "Remark:".tr,
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+
+              //时间
+              MyTextView(
+                item.auditMark ?? "-",
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor: Colors.white,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ).marginOnly(top: 15),
+
+        ],
+      ),
+    );
+  }
+}

+ 6 - 1
packages/cpt_labour/lib/router/labour_service_impl.dart

@@ -1,3 +1,4 @@
+import 'package:cpt_labour/modules/labour_review_list/labour_review_page.dart';
 import 'package:plugin_basic/basic_export.dart';
 import 'package:router/componentRouter/labour_service.dart';
 import 'package:shared/utils/log_utils.dart';
@@ -18,6 +19,11 @@ class LabourServiceImpl extends GetxService implements LabourService {
   }
 
   @override
+  void startLabourReviewPage() {
+    LabourReviewPage.startInstance();
+  }
+
+  @override
   void onInit() {
     super.onInit();
     //初始化资源
@@ -31,5 +37,4 @@ class LabourServiceImpl extends GetxService implements LabourService {
     Log.d("LabourServiceImpl 销毁资源");
   }
 
-
 }

+ 22 - 0
packages/cpt_labour/lib/router/page_router.dart

@@ -4,6 +4,9 @@ import 'package:router/path/router_path.dart';
 import '../modules/labour_request_add/labour_request_add_page.dart';
 import '../modules/labour_request_list/labour_request_list_page.dart';
 import '../modules/labour_request_workflow/labour_request_workflow_page.dart';
+import '../modules/labour_review_edit/labour_review_edit_page.dart';
+import '../modules/labour_review_list/labour_review_page.dart';
+import '../modules/labour_review_workflow/labour_request_workflow_page.dart';
 import '../modules/labour_template_add/labour_template_add_page.dart';
 import '../modules/labour_template_list/labour_template_list_page.dart';
 
@@ -40,5 +43,24 @@ class LabourPageRouter {
       name: RouterPath.labourTemplateAdd,
       page: () => LabourTemplateAddPage(),
     ),
+
+    //用工请求审核列表
+    GetPage(
+      name: RouterPath.labourReviewList,
+      page: () => LabourReviewPage(),
+    ),
+
+    //用工请求审核编辑
+    GetPage(
+      name: RouterPath.labourReviewEdit,
+      page: () => LabourReviewEditPage(),
+    ),
+
+    //用工请求审核工作流
+    GetPage(
+      name: RouterPath.labourReviewWorkflow,
+      page: () => LabourReviewWorkflowPage(),
+    ),
+
   ];
 }

+ 23 - 0
packages/cs_domain/lib/constants/api_constants.dart

@@ -270,4 +270,27 @@ class ApiConstants {
   //员工申请报表
   static const apiReportStaffRequest = "/index.php/api/v1/hotel/report/staff";
 
+// =========================== 越南的审核 ↓=========================================
+
+  // 用工审核选项
+  static const apiLabourReviewIndex = "/index.php/api/v1/hotel/lab-review/index";
+
+  // 用工审核列表
+  static const apiLabourReviewTable = "/index.php/api/v1/hotel/lab-review/table";
+
+  // 用工审核的编辑详情
+  static const apiLabourReviewDetail = "/index.php/api/v1/hotel/lab-review/edit-view";
+
+  // 用工审核的编辑提交
+  static const apiLabourReviewEdit = "/index.php/api/v1/hotel/lab-review/edit-submit";
+
+  // 用工审核的审核流程列表
+  static const apiLabourReviewStatusView = "/index.php/api/v1/hotel/lab-review/status-view";
+
+  // 用工审核的批量同意
+  static const apiLabourReviewApprove = "/index.php/api/v1/hotel/lab-review/approve";
+
+  // 用工审核的批量拒绝
+  static const apiLabourReviewReject = "/index.php/api/v1/hotel/lab-review/reject";
+
 }

+ 58 - 0
packages/cs_domain/lib/entity/response/labour_review_list_entity.dart

@@ -0,0 +1,58 @@
+import 'package:domain/generated/json/base/json_field.dart';
+import 'package:domain/generated/json/labour_review_list_entity.g.dart';
+import 'dart:convert';
+export 'package:domain/generated/json/labour_review_list_entity.g.dart';
+
+@JsonSerializable()
+class LabourReviewListEntity {
+	int total = 0;
+	List<LabourReviewListRows> rows = [];
+
+	LabourReviewListEntity();
+
+	factory LabourReviewListEntity.fromJson(Map<String, dynamic> json) => $LabourReviewListEntityFromJson(json);
+
+	Map<String, dynamic> toJson() => $LabourReviewListEntityToJson(this);
+
+	@override
+	String toString() {
+		return jsonEncode(this);
+	}
+}
+
+@JsonSerializable()
+class LabourReviewListRows {
+	@JSONField(name: "record_id")
+	String? recordId;
+	@JSONField(name: "request_id")
+	String? requestId;
+	@JSONField(name: "job_title")
+	String? jobTitle;
+	@JSONField(name: "job_time")
+	String? jobTime;
+	@JSONField(name: "department_name")
+	String? departmentName;
+	@JSONField(name: "salary_show")
+	String? salaryShow;
+	@JSONField(name: "need_num")
+	String? needNum;
+	@JSONField(name: "status_show")
+	String? statusShow;
+	@JSONField(name: "created_at")
+	String? createdAt;
+	@JSONField(name: "btn_list")
+	List<String> btnList = [];
+
+	bool isSelected = false;  //自定义字段,是否选中
+
+	LabourReviewListRows();
+
+	factory LabourReviewListRows.fromJson(Map<String, dynamic> json) => $LabourReviewListRowsFromJson(json);
+
+	Map<String, dynamic> toJson() => $LabourReviewListRowsToJson(this);
+
+	@override
+	String toString() {
+		return jsonEncode(this);
+	}
+}

+ 55 - 0
packages/cs_domain/lib/entity/response/labour_review_status_entity.dart

@@ -0,0 +1,55 @@
+import 'package:domain/generated/json/base/json_field.dart';
+import 'package:domain/generated/json/labour_review_status_entity.g.dart';
+import 'dart:convert';
+export 'package:domain/generated/json/labour_review_status_entity.g.dart';
+
+@JsonSerializable()
+class LabourReviewStatusEntity {
+	@JSONField(name: "co_department_id")
+	int coDepartmentId = 0;
+	List<LabourReviewStatusRecords> records = [];
+
+	LabourReviewStatusEntity();
+
+	factory LabourReviewStatusEntity.fromJson(Map<String, dynamic> json) => $LabourReviewStatusEntityFromJson(json);
+
+	Map<String, dynamic> toJson() => $LabourReviewStatusEntityToJson(this);
+
+	@override
+	String toString() {
+		return jsonEncode(this);
+	}
+}
+
+@JsonSerializable()
+class LabourReviewStatusRecords {
+	@JSONField(name: "serial_number")
+	String? serialNumber;
+	@JSONField(name: "node_name")
+	String? nodeName;
+	@JSONField(name: "status_show")
+	String? statusShow;
+	@JSONField(name: "audit_name")
+	String? auditName;
+	@JSONField(name: "audit_time")
+	String? auditTime;
+	@JSONField(name: "audit_mark")
+	dynamic auditMark;
+	@JSONField(name: "created_at")
+	String? createdAt;
+	@JSONField(name: "assignee_type_show")
+	String? assigneeTypeShow;
+	@JSONField(name: "designation_show")
+	String? designationShow;
+
+	LabourReviewStatusRecords();
+
+	factory LabourReviewStatusRecords.fromJson(Map<String, dynamic> json) => $LabourReviewStatusRecordsFromJson(json);
+
+	Map<String, dynamic> toJson() => $LabourReviewStatusRecordsToJson(this);
+
+	@override
+	String toString() {
+		return jsonEncode(this);
+	}
+}

+ 18 - 0
packages/cs_domain/lib/generated/json/base/json_convert_content.dart

@@ -41,6 +41,8 @@ import 'package:domain/entity/response/labour_request_list_entity.dart';
 import 'package:domain/entity/response/labour_request_s_g_add_index_entity.dart';
 import 'package:domain/entity/response/labour_request_s_g_entity.dart';
 import 'package:domain/entity/response/labour_request_work_flow_entity.dart';
+import 'package:domain/entity/response/labour_review_list_entity.dart';
+import 'package:domain/entity/response/labour_review_status_entity.dart';
 import 'package:domain/entity/response/revise_index_s_g_entity.dart';
 import 'package:domain/entity/response/revise_list_s_g_entity.dart';
 import 'package:domain/entity/response/revise_log_s_g_entity.dart';
@@ -431,6 +433,18 @@ class JsonConvert {
     if (<LabourRequestWorkFlowRecords>[] is M) {
       return data.map<LabourRequestWorkFlowRecords>((Map<String, dynamic> e) => LabourRequestWorkFlowRecords.fromJson(e)).toList() as M;
     }
+    if (<LabourReviewListEntity>[] is M) {
+      return data.map<LabourReviewListEntity>((Map<String, dynamic> e) => LabourReviewListEntity.fromJson(e)).toList() as M;
+    }
+    if (<LabourReviewListRows>[] is M) {
+      return data.map<LabourReviewListRows>((Map<String, dynamic> e) => LabourReviewListRows.fromJson(e)).toList() as M;
+    }
+    if (<LabourReviewStatusEntity>[] is M) {
+      return data.map<LabourReviewStatusEntity>((Map<String, dynamic> e) => LabourReviewStatusEntity.fromJson(e)).toList() as M;
+    }
+    if (<LabourReviewStatusRecords>[] is M) {
+      return data.map<LabourReviewStatusRecords>((Map<String, dynamic> e) => LabourReviewStatusRecords.fromJson(e)).toList() as M;
+    }
     if (<ReviseIndexSGEntity>[] is M) {
       return data.map<ReviseIndexSGEntity>((Map<String, dynamic> e) => ReviseIndexSGEntity.fromJson(e)).toList() as M;
     }
@@ -614,6 +628,10 @@ class JsonConvertClassCollection {
     (LabourRequestSGCountList).toString(): LabourRequestSGCountList.fromJson,
     (LabourRequestWorkFlowEntity).toString(): LabourRequestWorkFlowEntity.fromJson,
     (LabourRequestWorkFlowRecords).toString(): LabourRequestWorkFlowRecords.fromJson,
+    (LabourReviewListEntity).toString(): LabourReviewListEntity.fromJson,
+    (LabourReviewListRows).toString(): LabourReviewListRows.fromJson,
+    (LabourReviewStatusEntity).toString(): LabourReviewStatusEntity.fromJson,
+    (LabourReviewStatusRecords).toString(): LabourReviewStatusRecords.fromJson,
     (ReviseIndexSGEntity).toString(): ReviseIndexSGEntity.fromJson,
     (ReviseIndexSGStatusList).toString(): ReviseIndexSGStatusList.fromJson,
     (ReviseListSGEntity).toString(): ReviseListSGEntity.fromJson,

+ 122 - 0
packages/cs_domain/lib/generated/json/labour_review_list_entity.g.dart

@@ -0,0 +1,122 @@
+import 'package:domain/generated/json/base/json_convert_content.dart';
+import 'package:domain/entity/response/labour_review_list_entity.dart';
+
+LabourReviewListEntity $LabourReviewListEntityFromJson(Map<String, dynamic> json) {
+  final LabourReviewListEntity labourReviewListEntity = LabourReviewListEntity();
+  final int? total = jsonConvert.convert<int>(json['total']);
+  if (total != null) {
+    labourReviewListEntity.total = total;
+  }
+  final List<LabourReviewListRows>? rows = (json['rows'] as List<dynamic>?)?.map(
+          (e) => jsonConvert.convert<LabourReviewListRows>(e) as LabourReviewListRows).toList();
+  if (rows != null) {
+    labourReviewListEntity.rows = rows;
+  }
+  return labourReviewListEntity;
+}
+
+Map<String, dynamic> $LabourReviewListEntityToJson(LabourReviewListEntity entity) {
+  final Map<String, dynamic> data = <String, dynamic>{};
+  data['total'] = entity.total;
+  data['rows'] = entity.rows.map((v) => v.toJson()).toList();
+  return data;
+}
+
+extension LabourReviewListEntityExtension on LabourReviewListEntity {
+  LabourReviewListEntity copyWith({
+    int? total,
+    List<LabourReviewListRows>? rows,
+  }) {
+    return LabourReviewListEntity()
+      ..total = total ?? this.total
+      ..rows = rows ?? this.rows;
+  }
+}
+
+LabourReviewListRows $LabourReviewListRowsFromJson(Map<String, dynamic> json) {
+  final LabourReviewListRows labourReviewListRows = LabourReviewListRows();
+  final String? recordId = jsonConvert.convert<String>(json['record_id']);
+  if (recordId != null) {
+    labourReviewListRows.recordId = recordId;
+  }
+  final String? requestId = jsonConvert.convert<String>(json['request_id']);
+  if (requestId != null) {
+    labourReviewListRows.requestId = requestId;
+  }
+  final String? jobTitle = jsonConvert.convert<String>(json['job_title']);
+  if (jobTitle != null) {
+    labourReviewListRows.jobTitle = jobTitle;
+  }
+  final String? jobTime = jsonConvert.convert<String>(json['job_time']);
+  if (jobTime != null) {
+    labourReviewListRows.jobTime = jobTime;
+  }
+  final String? departmentName = jsonConvert.convert<String>(json['department_name']);
+  if (departmentName != null) {
+    labourReviewListRows.departmentName = departmentName;
+  }
+  final String? salaryShow = jsonConvert.convert<String>(json['salary_show']);
+  if (salaryShow != null) {
+    labourReviewListRows.salaryShow = salaryShow;
+  }
+  final String? needNum = jsonConvert.convert<String>(json['need_num']);
+  if (needNum != null) {
+    labourReviewListRows.needNum = needNum;
+  }
+  final String? statusShow = jsonConvert.convert<String>(json['status_show']);
+  if (statusShow != null) {
+    labourReviewListRows.statusShow = statusShow;
+  }
+  final String? createdAt = jsonConvert.convert<String>(json['created_at']);
+  if (createdAt != null) {
+    labourReviewListRows.createdAt = createdAt;
+  }
+  final List<String>? btnList = (json['btn_list'] as List<dynamic>?)?.map(
+          (e) => jsonConvert.convert<String>(e) as String).toList();
+  if (btnList != null) {
+    labourReviewListRows.btnList = btnList;
+  }
+  return labourReviewListRows;
+}
+
+Map<String, dynamic> $LabourReviewListRowsToJson(LabourReviewListRows entity) {
+  final Map<String, dynamic> data = <String, dynamic>{};
+  data['record_id'] = entity.recordId;
+  data['request_id'] = entity.requestId;
+  data['job_title'] = entity.jobTitle;
+  data['job_time'] = entity.jobTime;
+  data['department_name'] = entity.departmentName;
+  data['salary_show'] = entity.salaryShow;
+  data['need_num'] = entity.needNum;
+  data['status_show'] = entity.statusShow;
+  data['created_at'] = entity.createdAt;
+  data['btn_list'] = entity.btnList;
+  return data;
+}
+
+extension LabourReviewListRowsExtension on LabourReviewListRows {
+  LabourReviewListRows copyWith({
+    String? recordId,
+    String? requestId,
+    String? jobTitle,
+    String? jobTime,
+    String? departmentName,
+    String? salaryShow,
+    String? needNum,
+    String? statusShow,
+    String? createdAt,
+    List<String>? btnList,
+  }) {
+    return LabourReviewListRows()
+      ..recordId = recordId ?? this.recordId
+      ..requestId = requestId ?? this.requestId
+      ..jobTitle = jobTitle ?? this.jobTitle
+      ..jobTime = jobTime ?? this.jobTime
+      ..departmentName = departmentName ?? this.departmentName
+      ..salaryShow = salaryShow ?? this.salaryShow
+      ..needNum = needNum ?? this.needNum
+      ..statusShow = statusShow ?? this.statusShow
+      ..createdAt = createdAt ?? this.createdAt
+      ..btnList = btnList ?? this.btnList;
+  }
+}

+ 114 - 0
packages/cs_domain/lib/generated/json/labour_review_status_entity.g.dart

@@ -0,0 +1,114 @@
+import 'package:domain/generated/json/base/json_convert_content.dart';
+import 'package:domain/entity/response/labour_review_status_entity.dart';
+
+LabourReviewStatusEntity $LabourReviewStatusEntityFromJson(Map<String, dynamic> json) {
+  final LabourReviewStatusEntity labourReviewStatusEntity = LabourReviewStatusEntity();
+  final int? coDepartmentId = jsonConvert.convert<int>(json['co_department_id']);
+  if (coDepartmentId != null) {
+    labourReviewStatusEntity.coDepartmentId = coDepartmentId;
+  }
+  final List<LabourReviewStatusRecords>? records = (json['records'] as List<dynamic>?)?.map(
+          (e) => jsonConvert.convert<LabourReviewStatusRecords>(e) as LabourReviewStatusRecords).toList();
+  if (records != null) {
+    labourReviewStatusEntity.records = records;
+  }
+  return labourReviewStatusEntity;
+}
+
+Map<String, dynamic> $LabourReviewStatusEntityToJson(LabourReviewStatusEntity entity) {
+  final Map<String, dynamic> data = <String, dynamic>{};
+  data['co_department_id'] = entity.coDepartmentId;
+  data['records'] = entity.records.map((v) => v.toJson()).toList();
+  return data;
+}
+
+extension LabourReviewStatusEntityExtension on LabourReviewStatusEntity {
+  LabourReviewStatusEntity copyWith({
+    int? coDepartmentId,
+    List<LabourReviewStatusRecords>? records,
+  }) {
+    return LabourReviewStatusEntity()
+      ..coDepartmentId = coDepartmentId ?? this.coDepartmentId
+      ..records = records ?? this.records;
+  }
+}
+
+LabourReviewStatusRecords $LabourReviewStatusRecordsFromJson(Map<String, dynamic> json) {
+  final LabourReviewStatusRecords labourReviewStatusRecords = LabourReviewStatusRecords();
+  final String? serialNumber = jsonConvert.convert<String>(json['serial_number']);
+  if (serialNumber != null) {
+    labourReviewStatusRecords.serialNumber = serialNumber;
+  }
+  final String? nodeName = jsonConvert.convert<String>(json['node_name']);
+  if (nodeName != null) {
+    labourReviewStatusRecords.nodeName = nodeName;
+  }
+  final String? statusShow = jsonConvert.convert<String>(json['status_show']);
+  if (statusShow != null) {
+    labourReviewStatusRecords.statusShow = statusShow;
+  }
+  final String? auditName = jsonConvert.convert<String>(json['audit_name']);
+  if (auditName != null) {
+    labourReviewStatusRecords.auditName = auditName;
+  }
+  final String? auditTime = jsonConvert.convert<String>(json['audit_time']);
+  if (auditTime != null) {
+    labourReviewStatusRecords.auditTime = auditTime;
+  }
+  final dynamic auditMark = json['audit_mark'];
+  if (auditMark != null) {
+    labourReviewStatusRecords.auditMark = auditMark;
+  }
+  final String? createdAt = jsonConvert.convert<String>(json['created_at']);
+  if (createdAt != null) {
+    labourReviewStatusRecords.createdAt = createdAt;
+  }
+  final String? assigneeTypeShow = jsonConvert.convert<String>(json['assignee_type_show']);
+  if (assigneeTypeShow != null) {
+    labourReviewStatusRecords.assigneeTypeShow = assigneeTypeShow;
+  }
+  final String? designationShow = jsonConvert.convert<String>(json['designation_show']);
+  if (designationShow != null) {
+    labourReviewStatusRecords.designationShow = designationShow;
+  }
+  return labourReviewStatusRecords;
+}
+
+Map<String, dynamic> $LabourReviewStatusRecordsToJson(LabourReviewStatusRecords entity) {
+  final Map<String, dynamic> data = <String, dynamic>{};
+  data['serial_number'] = entity.serialNumber;
+  data['node_name'] = entity.nodeName;
+  data['status_show'] = entity.statusShow;
+  data['audit_name'] = entity.auditName;
+  data['audit_time'] = entity.auditTime;
+  data['audit_mark'] = entity.auditMark;
+  data['created_at'] = entity.createdAt;
+  data['assignee_type_show'] = entity.assigneeTypeShow;
+  data['designation_show'] = entity.designationShow;
+  return data;
+}
+
+extension LabourReviewStatusRecordsExtension on LabourReviewStatusRecords {
+  LabourReviewStatusRecords copyWith({
+    String? serialNumber,
+    String? nodeName,
+    String? statusShow,
+    String? auditName,
+    String? auditTime,
+    dynamic auditMark,
+    String? createdAt,
+    String? assigneeTypeShow,
+    String? designationShow,
+  }) {
+    return LabourReviewStatusRecords()
+      ..serialNumber = serialNumber ?? this.serialNumber
+      ..nodeName = nodeName ?? this.nodeName
+      ..statusShow = statusShow ?? this.statusShow
+      ..auditName = auditName ?? this.auditName
+      ..auditTime = auditTime ?? this.auditTime
+      ..auditMark = auditMark ?? this.auditMark
+      ..createdAt = createdAt ?? this.createdAt
+      ..assigneeTypeShow = assigneeTypeShow ?? this.assigneeTypeShow
+      ..designationShow = designationShow ?? this.designationShow;
+  }
+}

+ 273 - 20
packages/cs_domain/lib/repository/labour_repository.dart

@@ -10,6 +10,8 @@ import 'package:shared/utils/util.dart';
 
 import '../constants/api_constants.dart';
 import '../entity/response/job_template_edit_index_entity.dart';
+import '../entity/response/labour_review_list_entity.dart';
+import '../entity/response/labour_review_status_entity.dart';
 
 /// 用工请求相关
 class LabourRepository extends GetxService {
@@ -332,9 +334,9 @@ class LabourRepository extends GetxService {
 
   /// 编辑工作模板的详情或选项数据
   Future<HttpResult<JobTemplateEditIndexEntity>> fetchJobTemplateEditIndex(
-      String? templateId, {
-        CancelToken? cancelToken,
-      }) async {
+    String? templateId, {
+    CancelToken? cancelToken,
+  }) async {
     Map<String, String> params = {};
     params["template_id"] = templateId ?? "";
 
@@ -358,14 +360,14 @@ class LabourRepository extends GetxService {
 
   /// 添加工作模板的提交
   Future<HttpResult> addLabourTemplateSubmit(
-      String? name,
-      String? description,
-      String? note,
-      String? age,
-      String? sex,
-      String? language, {
-        CancelToken? cancelToken,
-      }) async {
+    String? name,
+    String? description,
+    String? note,
+    String? age,
+    String? sex,
+    String? language, {
+    CancelToken? cancelToken,
+  }) async {
     //参数
     Map<String, String> params = {};
     params['job_title'] = name ?? "";
@@ -409,15 +411,15 @@ class LabourRepository extends GetxService {
 
   /// 编辑工作模板的提交
   Future<HttpResult> editLabourTemplateSubmit(
-      String? templateId,
-      String? name,
-      String? description,
-      String? note,
-      String? age,
-      String? sex,
-      String? language, {
-        CancelToken? cancelToken,
-      }) async {
+    String? templateId,
+    String? name,
+    String? description,
+    String? note,
+    String? age,
+    String? sex,
+    String? language, {
+    CancelToken? cancelToken,
+  }) async {
     //参数
     Map<String, String> params = {};
     params['job_title'] = name ?? "";
@@ -460,4 +462,255 @@ class LabourRepository extends GetxService {
     return result.convert();
   }
 
+  /// 用工审核选项
+  Future<HttpResult<LabourRequestIndexEntity>> fetchLabourReviewIndex({
+    CancelToken? cancelToken,
+  }) async {
+    final result = await httpProvider.requestNetResult(
+      ApiConstants.apiLabourReviewIndex,
+      cancelToken: cancelToken,
+    );
+
+    //根据返回的结果,封装原始数据为Bean/Entity对象
+    if (result.isSuccess) {
+      //重新赋值data或list
+      final json = result.getDataJson();
+      var data = LabourRequestIndexEntity.fromJson(json!);
+      //重新赋值data或list
+      return result.convert<LabourRequestIndexEntity>(data: data);
+    }
+    return result.convert();
+  }
+
+  /// 用工审核列表
+  Future<HttpResult<LabourReviewListEntity>> fetchLabourReviewList(
+    String? keyword,
+    String? startDate,
+    String? endDate,
+    String? departmentId, {
+    required int curPage,
+    CancelToken? cancelToken,
+  }) async {
+    //参数
+    Map<String, String> params = {};
+    params["cur_page"] = curPage.toString();
+    params["page_size"] = "20";
+
+    if (!Utils.isEmpty(keyword)) {
+      params["job_title"] = keyword!;
+    }
+    if (!Utils.isEmpty(startDate)) {
+      params["job_start"] = startDate!;
+    }
+    if (!Utils.isEmpty(endDate)) {
+      params["job_end"] = endDate!;
+    }
+    if (!Utils.isEmpty(departmentId)) {
+      params["department_id"] = departmentId!;
+    }
+
+    final result = await httpProvider.requestNetResult(
+      ApiConstants.apiLabourReviewTable,
+      params: params,
+      cancelToken: cancelToken,
+    );
+
+    //根据返回的结果,封装原始数据为Bean/Entity对象
+    if (result.isSuccess) {
+      //重新赋值data或list
+      final json = result.getDataJson();
+      var data = LabourReviewListEntity.fromJson(json!);
+      //重新赋值data或list
+      return result.convert<LabourReviewListEntity>(data: data);
+    }
+    return result.convert();
+  }
+
+  /// 根据ID获取主列表的Item数据,用于刷新审核列表Item
+  Future<HttpResult<LabourReviewListEntity>> fetchItemByRecordId(
+    String? recordId, {
+    CancelToken? cancelToken,
+  }) async {
+    //参数
+    Map<String, String> params = {};
+    params["cur_page"] = "1";
+    params["page_size"] = "1";
+
+    if (!Utils.isEmpty(recordId)) {
+      params["record_id"] = recordId!;
+    }
+
+    final result = await httpProvider.requestNetResult(
+      ApiConstants.apiLabourReviewTable,
+      params: params,
+      isShowLoadingDialog: true,
+      cancelToken: cancelToken,
+    );
+
+    //根据返回的结果,封装原始数据为Bean/Entity对象
+    if (result.isSuccess) {
+      //重新赋值data或list
+      final json = result.getDataJson();
+      var data = LabourReviewListEntity.fromJson(json!);
+      //重新赋值data或list
+      return result.convert<LabourReviewListEntity>(data: data);
+    }
+    return result.convert();
+  }
+
+  /// 用工审核的编辑详情
+  Future<HttpResult<LabourRequestEditIndexEntity>> fetchLabourReviewDetail(
+    String? requestId, {
+    CancelToken? cancelToken,
+  }) async {
+    //参数
+    Map<String, String> params = {};
+    params['request_id'] = requestId ?? "";
+
+    final result = await httpProvider.requestNetResult(
+      ApiConstants.apiLabourReviewDetail,
+      params: params,
+      isShowLoadingDialog: true,
+      cancelToken: cancelToken,
+    );
+
+    //根据返回的结果,封装原始数据为Bean/Entity对象
+    if (result.isSuccess) {
+      //重新赋值data或list
+      final json = result.getDataJson();
+      var data = LabourRequestEditIndexEntity.fromJson(json!);
+      //重新赋值data或list
+      return result.convert<LabourRequestEditIndexEntity>(data: data);
+    }
+    return result.convert();
+  }
+
+  /// 用工审核的编辑提交
+  Future<HttpResult> editLabourReviewSubmit(
+    String? requestId,
+    String? templateId,
+    String? jobStart,
+    String? jobEnd,
+    String? departmentId,
+    String? needNum,
+    String? salaryBy,
+    String? amount, {
+    CancelToken? cancelToken,
+  }) async {
+    //参数
+    Map<String, String> params = {};
+    params['request_id'] = requestId ?? "";
+    params['template_id'] = templateId ?? "";
+    params['job_start'] = jobStart ?? "";
+    params['job_end'] = jobEnd ?? "";
+    params['need_num'] = needNum ?? "";
+    if (!Utils.isEmpty(departmentId)) {
+      params["co_department_id"] = departmentId!;
+    }
+
+    params['salary_by'] = salaryBy ?? "";
+
+    if (!Utils.isEmpty(amount)) {
+      params["amount"] = amount!;
+    }
+
+    final result = await httpProvider.requestNetResult(
+      ApiConstants.apiLabourReviewEdit,
+      method: HttpMethod.POST,
+      params: params,
+      networkDebounce: true,
+      isShowLoadingDialog: true,
+      cancelToken: cancelToken,
+    );
+
+    //根据返回的结果,封装原始数据为Bean/Entity对象
+    if (result.isSuccess) {
+      //重新赋值data或list
+      return result.convert();
+    }
+    return result.convert();
+  }
+
+  /// 用工审核的审核流程列表
+  Future<HttpResult<LabourReviewStatusEntity>> fetchLabourReviewStatusView(
+    String? requestId, {
+    CancelToken? cancelToken,
+  }) async {
+    //参数
+    Map<String, String> params = {};
+    params['request_id'] = requestId ?? "";
+
+    final result = await httpProvider.requestNetResult(
+      ApiConstants.apiLabourReviewStatusView,
+      params: params,
+      cancelToken: cancelToken,
+    );
+
+    //根据返回的结果,封装原始数据为Bean/Entity对象
+    if (result.isSuccess) {
+      //重新赋值data或list
+      final json = result.getDataJson();
+      var data = LabourReviewStatusEntity.fromJson(json!);
+      //重新赋值data或list
+      return result.convert<LabourReviewStatusEntity>(data: data);
+    }
+    return result.convert();
+  }
+
+  /// 用工审核的批量同意
+  Future<HttpResult> approveLabourReviews(
+    String? recordIds, {
+    CancelToken? cancelToken,
+  }) async {
+    //参数
+    Map<String, String> params = {};
+    params['record_ids'] = recordIds ?? "";
+
+    final result = await httpProvider.requestNetResult(
+      ApiConstants.apiLabourReviewApprove,
+      method: HttpMethod.POST,
+      params: params,
+      networkDebounce: true,
+      isShowLoadingDialog: true,
+      cancelToken: cancelToken,
+    );
+
+    //根据返回的结果,封装原始数据为Bean/Entity对象
+    if (result.isSuccess) {
+      //重新赋值data或list
+      return result.convert();
+    }
+    return result.convert();
+  }
+
+  /// 用工审核的批量拒绝
+  Future<HttpResult> rejectLabourReviews(
+    String? recordIds,
+    String? reason, {
+    CancelToken? cancelToken,
+  }) async {
+    //参数
+    Map<String, String> params = {};
+    params['record_ids'] = recordIds ?? "";
+
+    if (Utils.isNotEmpty(reason)) {
+      params['audit_mark'] = reason ?? "";
+    }
+
+    final result = await httpProvider.requestNetResult(
+      ApiConstants.apiLabourReviewReject,
+      method: HttpMethod.POST,
+      params: params,
+      networkDebounce: true,
+      isShowLoadingDialog: true,
+      cancelToken: cancelToken,
+    );
+
+    //根据返回的结果,封装原始数据为Bean/Entity对象
+    if (result.isSuccess) {
+      //重新赋值data或list
+      return result.convert();
+    }
+    return result.convert();
+  }
 }

+ 2 - 0
packages/cs_router/lib/componentRouter/labour_service.dart

@@ -7,4 +7,6 @@ abstract class LabourService {
   void startLabourRequestPage();
 
   void startLabourTemplatePage();
+
+  void startLabourReviewPage();
 }

+ 3 - 0
packages/cs_router/lib/path/router_path.dart

@@ -33,6 +33,9 @@ class RouterPath {
   static const jobLabourRequestWorkflow = '/labour/workflow'; //用工请求修改状态的工作流
   static const labourTemplateList = '/labour/template/list'; //模板列表
   static const labourTemplateAdd = '/labour/template/add'; //模板添加
+  static const labourReviewList = '/labour/review/list'; //用工请求审核列表
+  static const labourReviewEdit = '/labour/review/edit'; //用工请求审核编辑
+  static const labourReviewWorkflow = '/labour/review/workflow'; //用工请求审核工作流
 
   //其他模块和报表模块
   static const deviceList = '/device/list'; //雇主绑定的设备列表