Explorar o código

新加坡的部分新模块的布局与路由完成

liukai hai 2 semanas
pai
achega
be4a717bae
Modificáronse 70 ficheiros con 6860 adicións e 522 borrados
  1. 1 1
      app/android/app/src/main/AndroidManifest.xml
  2. 134 0
      packages/cpt_sg/lib/modules/agency/agency_add/agency_add_controller.dart
  3. 262 0
      packages/cpt_sg/lib/modules/agency/agency_add/agency_add_page.dart
  4. 58 0
      packages/cpt_sg/lib/modules/agency/agency_add/agency_add_state.dart
  5. 48 0
      packages/cpt_sg/lib/modules/agency/agency_category/agency_category_controller.dart
  6. 96 0
      packages/cpt_sg/lib/modules/agency/agency_category/agency_category_page.dart
  7. 12 0
      packages/cpt_sg/lib/modules/agency/agency_category/agency_category_state.dart
  8. 65 0
      packages/cpt_sg/lib/modules/agency/agency_category/item_agency_category.dart
  9. 0 0
      packages/cpt_sg/lib/modules/agency/agency_export.dart
  10. 264 0
      packages/cpt_sg/lib/modules/agency/agency_list/agency_item.dart
  11. 248 0
      packages/cpt_sg/lib/modules/agency/agency_list/agency_list_controller.dart
  12. 235 0
      packages/cpt_sg/lib/modules/agency/agency_list/agency_list_page.dart
  13. 15 0
      packages/cpt_sg/lib/modules/agency/agency_list/agency_list_state.dart
  14. 171 0
      packages/cpt_sg/lib/modules/agency/contract_add/contract_add_controller.dart
  15. 232 0
      packages/cpt_sg/lib/modules/agency/contract_add/contract_add_page.dart
  16. 16 0
      packages/cpt_sg/lib/modules/agency/contract_add/contract_add_state.dart
  17. 339 0
      packages/cpt_sg/lib/modules/agency/contract_list/contract_item.dart
  18. 218 0
      packages/cpt_sg/lib/modules/agency/contract_list/contract_list_controller.dart
  19. 214 0
      packages/cpt_sg/lib/modules/agency/contract_list/contract_list_page.dart
  20. 15 0
      packages/cpt_sg/lib/modules/agency/contract_list/contract_list_state.dart
  21. 235 0
      packages/cpt_sg/lib/modules/agency/contract_rate_edit_list/contract_rate_edit_item.dart
  22. 190 0
      packages/cpt_sg/lib/modules/agency/contract_rate_edit_list/contract_rate_edit_list_controller.dart
  23. 153 0
      packages/cpt_sg/lib/modules/agency/contract_rate_edit_list/contract_rate_edit_list_page.dart
  24. 8 0
      packages/cpt_sg/lib/modules/agency/contract_rate_edit_list/contract_rate_edit_list_state.dart
  25. 179 0
      packages/cpt_sg/lib/modules/agency/contract_rate_edit_list/dialog/dialog_edit_rate.dart
  26. 194 0
      packages/cpt_sg/lib/modules/agency/contract_rate_list/contract_rate_item.dart
  27. 138 0
      packages/cpt_sg/lib/modules/agency/contract_rate_list/contract_rate_list_controller.dart
  28. 127 0
      packages/cpt_sg/lib/modules/agency/contract_rate_list/contract_rate_list_page.dart
  29. 8 0
      packages/cpt_sg/lib/modules/agency/contract_rate_list/contract_rate_list_state.dart
  30. 161 0
      packages/cpt_sg/lib/modules/agency/contract_rate_setting/contract_rate_setting_controller.dart
  31. 536 0
      packages/cpt_sg/lib/modules/agency/contract_rate_setting/contract_rate_setting_page.dart
  32. 109 0
      packages/cpt_sg/lib/modules/agency/contract_rate_setting/contract_rate_setting_state.dart
  33. 152 0
      packages/cpt_sg/lib/modules/agency/contract_rate_specific_day/contract_rate_specific_controller.dart
  34. 208 0
      packages/cpt_sg/lib/modules/agency/contract_rate_specific_day/contract_rate_specific_page.dart
  35. 35 0
      packages/cpt_sg/lib/modules/agency/contract_rate_specific_day/contract_rate_specific_state.dart
  36. 134 0
      packages/cpt_sg/lib/modules/agency/position_add/position_add_controller.dart
  37. 125 0
      packages/cpt_sg/lib/modules/agency/position_add/position_add_page.dart
  38. 21 0
      packages/cpt_sg/lib/modules/agency/position_add/position_add_state.dart
  39. 169 0
      packages/cpt_sg/lib/modules/agency/position_list/position_item.dart
  40. 240 0
      packages/cpt_sg/lib/modules/agency/position_list/position_list_controller.dart
  41. 202 0
      packages/cpt_sg/lib/modules/agency/position_list/position_list_page.dart
  42. 14 0
      packages/cpt_sg/lib/modules/agency/position_list/position_list_state.dart
  43. 2 1
      packages/cpt_sg/lib/modules/main/main_controller.dart
  44. 76 2
      packages/cpt_sg/lib/router/sg_router.dart
  45. 1 1
      packages/cs_domain/lib/repository/auth_repository.dart
  46. 1 1
      packages/cs_domain/lib/repository/job_repository.dart
  47. 1 1
      packages/cs_domain/lib/repository/job_sg_repository.dart
  48. 1 1
      packages/cs_domain/lib/repository/labour_repository.dart
  49. 1 1
      packages/cs_domain/lib/repository/labour_sg_repository.dart
  50. 1 1
      packages/cs_domain/lib/repository/other_repository.dart
  51. 1 1
      packages/cs_plugin_basic/lib/dio_interceptors/interceptor_status_code_dio.dart
  52. 0 1
      packages/cs_plugin_platform/lib/dio_export.dart
  53. 141 0
      packages/cs_plugin_platform/lib/engine/image/image_nine_grid.dart
  54. 101 102
      packages/cs_plugin_platform/lib/engine/media/album_engine.dart
  55. 56 57
      packages/cs_plugin_platform/lib/engine/media/camera_engine.dart
  56. 41 43
      packages/cs_plugin_platform/lib/engine/media/image_crop_engine.dart
  57. 101 102
      packages/cs_plugin_platform/lib/engine/media/image_picker_utils.dart
  58. 254 199
      packages/cs_plugin_platform/lib/engine/permission/permission_engine.dart
  59. 4 0
      packages/cs_plugin_platform/lib/platform_export.dart
  60. 5 5
      packages/cs_plugin_platform/pubspec.yaml
  61. BIN=BIN
      packages/cs_resources/assets/agency/category_agency.webp
  62. BIN=BIN
      packages/cs_resources/assets/agency/category_contract.webp
  63. BIN=BIN
      packages/cs_resources/assets/agency/category_posotion.webp
  64. BIN=BIN
      packages/cs_resources/assets/agency/contract_file_icon.webp
  65. BIN=BIN
      packages/cs_resources/assets/base_service/image_add_icon.webp
  66. 5 0
      packages/cs_resources/lib/generated/assets.dart
  67. 35 0
      packages/cs_resources/lib/local/language/en_US.dart
  68. 37 2
      packages/cs_resources/lib/local/language/zh_CN.dart
  69. 1 0
      packages/cs_resources/pubspec.yaml
  70. 13 0
      packages/cs_router/lib/path/router_path.dart

+ 1 - 1
app/android/app/src/main/AndroidManifest.xml

@@ -12,7 +12,7 @@
     <uses-permission android:name="android.permission.RECORD_AUDIO" />
     <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
     <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
-<!--    <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />-->
+    <uses-permission android:name="android.permission.CALL_PHONE" />
 
     <!-- Provide required visibility configuration for API level 30 and above -->
     <queries>

+ 134 - 0
packages/cpt_sg/lib/modules/agency/agency_add/agency_add_controller.dart

@@ -0,0 +1,134 @@
+import 'package:domain/repository/labour_sg_repository.dart';
+import 'package:get/get.dart';
+import 'package:plugin_platform/engine/toast/toast_engine.dart';
+import 'package:plugin_platform/http/dio/dio_cancelable_mixin.dart';
+import 'package:shared/utils/util.dart';
+
+import 'agency_add_state.dart';
+
+class AgencyAddController extends GetxController with DioCancelableMixin {
+  final LabourSGRepository _labourRepository = Get.find();
+  final AgencyAddState state = AgencyAddState();
+
+  // 获取添加或者编辑的详情
+  void _fetchAddEditIndexDetail() async {
+    // //获取到数据
+    // Future<HttpResult<JobTemplateEditIndexEntity>> taskFuture;
+    // if (Utils.isNotEmpty(state.templateId) && state.templateId != "0") {
+    //   //编辑
+    //   taskFuture = _labourRepository.fetchJobTemplateEditIndex(state.templateId, cancelToken: cancelToken);
+    // } else {
+    //   //新增
+    //   taskFuture = _labourRepository.fetchJobTemplateAddIndex(cancelToken: cancelToken);
+    // }
+    //
+    // var result = await taskFuture;
+    //
+    // //处理数据
+    // if (result.isSuccess) {
+    //   state.indexEntity = result.data;
+    //
+    //   var templateNameController = state.formData['template_name']!['controller'];
+    //   var descController = state.formData['desc']!['controller'];
+    //   var contactController = state.formData['contact']!['controller'];
+    //   var contactNoController = state.formData['contact_no']!['controller'];
+    //   var noteController = state.formData['note']!['controller'];
+    //   templateNameController.text = state.indexEntity?.name ?? "";
+    //   descController.text = state.indexEntity?.description ?? "";
+    //   contactController.text = state.indexEntity?.contact ?? "";
+    //   contactNoController.text = state.indexEntity?.contactNo ?? "";
+    //   noteController.text = state.indexEntity?.note ?? "";
+    //
+    //   //默认赋值
+    //   state.selectedAgeList = state.indexEntity?.ageList.where((e) => e.checked == "checked").map((e) => e.value!).toList() ?? [];
+    //   Log.d("当前选中的年龄1:${ state.selectedAgeList}");
+    //   state.selectedLanguageList = state.indexEntity?.languageList.where((e) => e.checked == "checked").map((e) => e.value!).toList() ?? [];
+    //   Log.d("当前选中的语言1:${ state.selectedLanguageList}");
+    //   state.foodCert = state.indexEntity?.withFoodCert.toString();
+    //
+    //   update();
+    // } else {
+    //   ToastEngine.show(result.errorMsg ?? "Network Load Error".tr);
+    // }
+  }
+
+  /// 提交
+  void doSubmit() async {
+
+
+    var agencyNameController = state.formData['agency_name']!['controller'];
+    var acraController = state.formData['acra']!['controller'];
+    var personController = state.formData['person_in_charge']!['controller'];
+    var addressController = state.formData['address']!['controller'];
+    var emailController = state.formData['email']!['controller'];
+    var phoneController = state.formData['phone']!['controller'];
+
+    String agencyName = agencyNameController.text.toString();
+    String acra = acraController.text.toString();
+    String personName = personController.text.toString();
+    String address = addressController.text.toString();
+    String email = emailController.text.toString();
+    String phone = phoneController.text.toString();
+
+    //校验必填项
+    if (Utils.isEmpty(agencyName)) {
+      ToastEngine.show("Enter Agency Name".tr);
+      return;
+    }
+
+    if (Utils.isEmpty(acra)) {
+      ToastEngine.show("Enter ACRA NO".tr);
+      return;
+    }
+
+    // Future<HttpResult> taskFuture;
+    // if (Utils.isNotEmpty(state.templateId) && state.templateId != "0") {
+    //   taskFuture = _labourRepository.editJobTemplateSubmit(
+    //     state.templateId,
+    //     templateName,
+    //     contact,
+    //     contactNo,
+    //     desc,
+    //     note,
+    //     state.selectedAgeList.join(","),
+    //     state.gender,
+    //     state.foodCert,
+    //     state.selectedLanguageList.join(","),
+    //     cancelToken: cancelToken,
+    //   );
+    // } else {
+    //   taskFuture = _labourRepository.addJobTemplateSubmit(
+    //     templateName,
+    //     contact,
+    //     contactNo,
+    //     desc,
+    //     note,
+    //     state.selectedAgeList.join(","),
+    //     state.gender,
+    //     state.foodCert,
+    //     state.selectedLanguageList.join(","),
+    //     cancelToken: cancelToken,
+    //   );
+    // }
+    //
+    // var result = await taskFuture;
+    //
+    // //处理数据
+    // if (result.isSuccess) {
+    //   NotifyEngine.showSuccess("Successful".tr);
+    //
+    //   //根据类型刷新
+    //   state.cb?.call(state.templateId);
+    //
+    //   Get.back();
+    // } else {
+    //   ToastEngine.show(result.errorMsg ?? "Network Load Error".tr);
+    // }
+  }
+
+  @override
+  void onReady() {
+    super.onReady();
+    _fetchAddEditIndexDetail();
+  }
+}

+ 262 - 0
packages/cpt_sg/lib/modules/agency/agency_add/agency_add_page.dart

@@ -0,0 +1,262 @@
+import 'package:cs_resources/constants/color_constants.dart';
+import 'package:flutter/material.dart';
+import 'package:get/get.dart';
+import 'package:shared/utils/log_utils.dart';
+import 'package:shared/utils/screen_util.dart';
+import 'package:shared/utils/util.dart';
+import 'package:widgets/ext/ex_widget.dart';
+import 'package:widgets/my_appbar.dart';
+import 'package:widgets/my_button.dart';
+import 'package:widgets/my_text_view.dart';
+import 'package:widgets/no_shadow_scroll_behavior.dart';
+import 'package:widgets/shatter/custom_check_box.dart';
+import 'package:widgets/shatter/custom_radio_check.dart';
+import 'package:widgets/shatter/form_require_text.dart';
+import 'package:widgets/shatter/round_my_text_field.dart';
+import 'package:widgets/widget_export.dart';
+
+import 'agency_add_controller.dart';
+
+import 'package:plugin_basic/base/base_stateless_page.dart';
+import 'package:plugin_basic/utils/ext_get_nav.dart';
+import 'package:router/path/router_path.dart';
+
+import 'agency_add_state.dart';
+
+/*
+ * 中介的添加与编辑
+ */
+class SGAgencyAddPage extends BaseStatelessPage<AgencyAddController> {
+  SGAgencyAddPage({Key? key}) : super(key: key);
+
+  //启动当前页面
+  static void startInstance(
+    String agentId,
+    void Function(dynamic value)? cb,
+  ) {
+    return Get.start(RouterPath.SGAgencyAdd, arguments: {'agentId': agentId, 'cb': cb});
+  }
+
+  late AgencyAddState state;
+
+  @override
+  void initState() {
+    state = controller.state;
+    state.agentId = Get.arguments['agentId'];
+    state.cb = Get.arguments['cb'] as void Function(dynamic)?;
+  }
+
+  @override
+  AgencyAddController createRawController() {
+    return AgencyAddController();
+  }
+
+  @override
+  Widget buildWidget(BuildContext context) {
+    return autoCtlGetBuilder(builder: (controller) {
+      return Scaffold(
+        extendBodyBehindAppBar: true,
+        appBar: MyAppBar.appBar(context, Utils.isEmpty(state.agentId) ? "Add Agency".tr : "Edit Agency".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: "Agency Name".tr).marginOnly(left: 15, top: 19),
+
+                      CustomTextField(
+                        formKey: "agency_name",
+                        formData: state.formData,
+                        height: 46,
+                        fontSize: 14,
+                        onSubmit: (key, value) {
+                          state.formData[key]!['focusNode'].unfocus();
+                          FocusScope.of(context).requestFocus(state.formData['acra']!['focusNode']);
+                        },
+                        marginTop: 10,
+                      ),
+
+                      //必填 - 中介商家编码
+                      FormRequireText(text: "ACRA NO".tr).marginOnly(left: 15, top: 15),
+
+                      CustomTextField(
+                        formKey: "acra",
+                        formData: state.formData,
+                        height: 46,
+                        fontSize: 14,
+                        onSubmit: (key, value) {
+                          state.formData[key]!['focusNode'].unfocus();
+                          FocusScope.of(context).requestFocus(state.formData['person_in_charge']!['focusNode']);
+                        },
+                        marginTop: 10,
+                      ),
+
+                      // 负责人
+                      MyTextView(
+                        "Person in Charge".tr,
+                        textColor: Colors.white,
+                        fontSize: 14,
+                        isFontRegular: true,
+                        marginLeft: 15,
+                        marginTop: 15,
+                      ),
+
+                      // 输入框
+                      CustomTextField(
+                        formKey: "person_in_charge",
+                        formData: state.formData,
+                        height: 46,
+                        fontSize: 14,
+                        onSubmit: (key, value) {
+                          state.formData[key]!['focusNode'].unfocus();
+                          FocusScope.of(context).requestFocus(state.formData['address']!['focusNode']);
+                        },
+                        marginTop: 10,
+                      ),
+
+                      // 公司地址
+                      MyTextView(
+                        "Company Address".tr,
+                        textColor: Colors.white,
+                        fontSize: 14,
+                        isFontRegular: true,
+                        marginLeft: 15,
+                        marginTop: 15,
+                      ),
+
+                      // 输入框
+                      CustomTextField(
+                        formKey: "address",
+                        formData: state.formData,
+                        height: 46,
+                        fontSize: 14,
+                        onSubmit: (key, value) {
+                          state.formData[key]!['focusNode'].unfocus();
+                          FocusScope.of(context).requestFocus(state.formData['email']!['focusNode']);
+                        },
+                        marginTop: 10,
+                      ),
+
+                      // 公司邮箱
+                      MyTextView(
+                        "Contact Email".tr,
+                        textColor: Colors.white,
+                        fontSize: 14,
+                        isFontRegular: true,
+                        marginLeft: 15,
+                        marginTop: 15,
+                      ),
+
+                      // 输入框
+                      CustomTextField(
+                        formKey: "email",
+                        formData: state.formData,
+                        height: 46,
+                        fontSize: 14,
+                        textInputType: TextInputType.emailAddress,
+                        onSubmit: (key, value) {
+                          state.formData[key]!['focusNode'].unfocus();
+                          FocusScope.of(context).requestFocus(state.formData['phone']!['focusNode']);
+                        },
+                        marginTop: 10,
+                      ),
+
+                      // 公司电话
+                      MyTextView(
+                        "Contact NO".tr,
+                        textColor: Colors.white,
+                        fontSize: 14,
+                        isFontRegular: true,
+                        marginLeft: 15,
+                        marginTop: 15,
+                      ),
+
+                      // 输入框
+                      CustomTextField(
+                        formKey: "phone",
+                        formData: state.formData,
+                        height: 46,
+                        fontSize: 14,
+                        textInputType: TextInputType.phone,
+                        textInputAction: TextInputAction.done,
+                        onSubmit: (key, value) {
+                          FocusScope.of(context).unfocus();
+                          controller.doSubmit();
+                        },
+                        marginTop: 10,
+                      ),
+
+                      //修改状态
+                      Visibility(
+                        visible: Utils.isNotEmpty(state.agentId),
+                        child: MyTextView(
+                          "Status".tr,
+                          textColor: Colors.white,
+                          fontSize: 14,
+                          isFontRegular: true,
+                          marginLeft: 15,
+                          marginTop: 15,
+                        ),
+                      ),
+
+                      //单选
+                      Visibility(
+                        visible: Utils.isNotEmpty(state.agentId),
+                        child: CustomRadioCheck(
+                          options: state.statusOption,
+                          onOptionSelected: (index, text) {
+                            state.statusId = index == 0 ? "1" : "0";
+                          },
+                          selectedPosition: 0,
+                        ).marginOnly(left: 15, right: 15, top: 10),
+                      ),
+
+                      //提交按钮
+                      MyButton(
+                        type: ClickType.throttle,
+                        milliseconds: 500,
+                        onPressed: () {
+                          FocusScope.of(context).unfocus();
+                          controller.doSubmit();
+                        },
+                        text: "Submit".tr,
+                        textColor: ColorConstants.white,
+                        fontSize: 16,
+                        radius: 20,
+                        backgroundColor: ColorConstants.textYellowFFBB1B,
+                        fontWeight: FontWeight.w500,
+                      ).marginSymmetric(vertical: 25, horizontal: 15),
+                    ],
+                  ),
+                ),
+              ),
+            ),
+          ),
+        ),
+      );
+    });
+  }
+}

+ 58 - 0
packages/cpt_sg/lib/modules/agency/agency_add/agency_add_state.dart

@@ -0,0 +1,58 @@
+import 'package:domain/entity/response/job_template_edit_index_entity.dart';
+import 'package:flutter/material.dart';
+import 'package:plugin_basic/basic_export.dart';
+
+class AgencyAddState {
+  //表单的校验与数据
+  Map<String, Map<String, dynamic>> formData = {
+    'agency_name': {
+      'value': '',
+      'controller': TextEditingController(),
+      'focusNode': FocusNode(),
+      'hintText': 'Enter...'.tr,
+      'obsecure': false,
+    },
+    'acra': {
+      'value': '',
+      'controller': TextEditingController(),
+      'focusNode': FocusNode(),
+      'hintText': 'Enter...'.tr,
+      'obsecure': false,
+    },
+    'person_in_charge': {
+      'value': '',
+      'controller': TextEditingController(),
+      'focusNode': FocusNode(),
+      'hintText': 'Enter...'.tr,
+      'obsecure': false,
+    },
+    'address': {
+      'value': '',
+      'controller': TextEditingController(),
+      'focusNode': FocusNode(),
+      'hintText': 'Enter...'.tr,
+      'obsecure': false,
+    },
+    'email': {
+      'value': '',
+      'controller': TextEditingController(),
+      'focusNode': FocusNode(),
+      'hintText': 'Enter...'.tr,
+      'obsecure': false,
+    },
+    'phone': {
+      'value': '',
+      'controller': TextEditingController(),
+      'focusNode': FocusNode(),
+      'hintText': 'Enter...'.tr,
+      'obsecure': false,
+    },
+  };
+
+  final statusOption = ["Active".tr, "Inactive".tr];
+  String? statusId;
+
+  String? agentId;
+  void Function(dynamic value)? cb;
+
+}

+ 48 - 0
packages/cpt_sg/lib/modules/agency/agency_category/agency_category_controller.dart

@@ -0,0 +1,48 @@
+import 'package:domain/entity/home_module.dart';
+import 'package:get/get.dart';
+import 'package:plugin_platform/http/dio/dio_cancelable_mixin.dart';
+import 'package:widgets/widget_export.dart';
+import '../agency_list/agency_list_page.dart';
+import '../contract_list/contract_list_page.dart';
+import '../position_list/position_list_page.dart';
+import 'agency_category_state.dart';
+
+/*
+ * 中介相关的子模块分类列表
+ */
+class AgencyCategoryController extends GetxController with DioCancelableMixin {
+  final AgencyCategoryState state = AgencyCategoryState();
+
+  // Refresh 控制器
+  final EasyRefreshController refreshController = EasyRefreshController(
+    controlFinishRefresh: false,
+    controlFinishLoad: false,
+  );
+
+  @override
+  void onReady() {
+    super.onReady();
+  }
+
+  /// 跳转到指定的模块中去
+  void gotoModulePage(HomeModule module) {
+    switch (module.key) {
+      case 'agency':
+        SGAgencyListPage.startInstance();
+        break;
+      case 'contract':
+        SGContractListPage.startInstance();
+        break;
+      case 'position':
+        SGPositionListPage.startInstance();
+        break;
+
+    }
+  }
+
+  @override
+  void onClose() {
+    state.datas.clear();
+    super.onClose();
+  }
+}

+ 96 - 0
packages/cpt_sg/lib/modules/agency/agency_category/agency_category_page.dart

@@ -0,0 +1,96 @@
+
+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/my_appbar.dart';
+import 'package:widgets/widget_export.dart';
+import 'item_agency_category.dart';
+import 'agency_category_controller.dart';
+import 'agency_category_state.dart';
+
+/*
+ * 中介下面的子模块分类列表
+ */
+class SGAgencyCategoryPage extends BaseStatefulPage<AgencyCategoryController> {
+  SGAgencyCategoryPage({Key? key}) : super(key: key);
+
+  //启动当前页面
+  static void startInstance() {
+    return Get.start(RouterPath.SGAgencyCategory);
+  }
+
+  @override
+  AgencyCategoryController createRawController() {
+    return AgencyCategoryController();
+  }
+
+  @override
+  State<SGAgencyCategoryPage> createState() => _LabourRequestListState();
+}
+
+class _LabourRequestListState extends BaseState<SGAgencyCategoryPage, AgencyCategoryController> {
+  late AgencyCategoryState 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.titleBar(context, "Agency".tr),
+
+              //底部的列表
+              EasyRefresh(
+                controller: controller.refreshController,
+                onRefresh: null,
+                onLoad: null,
+                child: ListView.builder(
+                  padding: const EdgeInsets.only(top: 8),
+                  itemCount: state.datas.length,
+                  itemBuilder: (_, int index) {
+                    //Item布局
+                    return AgencyCategoryItem(
+                      item: state.datas[index],
+                      onClickAction: () {
+                        controller.gotoModulePage(state.datas[index]);
+                      },
+                    );
+                  },
+                ),
+              ).expanded(),
+
+            ],
+          ),
+        ),
+      );
+    });
+  }
+}

+ 12 - 0
packages/cpt_sg/lib/modules/agency/agency_category/agency_category_state.dart

@@ -0,0 +1,12 @@
+import 'package:cs_resources/generated/assets.dart';
+import 'package:domain/entity/home_module.dart';
+import 'package:plugin_basic/basic_export.dart';
+
+class AgencyCategoryState {
+  //全部的模块
+  final List<HomeModule> datas = [
+    HomeModule(key: 'agency', moduleName: 'Agency List'.tr, moduleIconPath: Assets. agencyCategoryAgency, iconWidth: 40, iconHeight: 40),
+    HomeModule(key: 'contract', moduleName: 'Contract Management'.tr, moduleIconPath: Assets.agencyCategoryContract, iconWidth: 40, iconHeight: 40),
+    HomeModule(key: 'position', moduleName: 'Position List'.tr, moduleIconPath: Assets.agencyCategoryPosotion, iconWidth: 40, iconHeight: 40),
+  ];
+}

+ 65 - 0
packages/cpt_sg/lib/modules/agency/agency_category/item_agency_category.dart

@@ -0,0 +1,65 @@
+import 'package:cs_resources/constants/color_constants.dart';
+import 'package:cs_resources/generated/assets.dart';
+import 'package:domain/entity/home_module.dart';
+import 'package:domain/entity/response/labour_request_list_entity.dart';
+import 'package:flutter/cupertino.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter/widgets.dart';
+import 'package:widgets/ext/ex_widget.dart';
+import 'package:widgets/my_load_image.dart';
+import 'package:widgets/my_text_view.dart';
+
+/*
+ * Item布局
+ */
+class AgencyCategoryItem extends StatelessWidget {
+  final HomeModule item;
+  final VoidCallback? onClickAction;
+
+  AgencyCategoryItem({
+    required this.item,
+    this.onClickAction,
+  });
+
+  @override
+  Widget build(BuildContext context) {
+    return Container(
+      padding: const EdgeInsets.symmetric(vertical: 15, horizontal: 15),
+      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: Row(
+        children: [
+          //图标
+          MyAssetImage(
+            item.moduleIconPath,
+            width: item.iconWidth,
+            height: item.iconHeight,
+          ),
+
+          //名称
+          MyTextView(
+            item.moduleName,
+            isFontRegular: true,
+            marginLeft: 10,
+            textColor: ColorConstants.textGrayAECAE5,
+            fontSize: 14,
+          ),
+
+          const Spacer(),
+
+          //箭头
+          const MyAssetImage(
+            Assets.mainItemMoreIcon,
+            width: 7.5,
+            height: 13.5,
+          ),
+        ],
+      ),
+    ).onTap(() {
+      onClickAction?.call();
+    });
+  }
+}

+ 0 - 0
packages/cpt_sg/lib/modules/agency/agency_export.dart


+ 264 - 0
packages/cpt_sg/lib/modules/agency/agency_list/agency_item.dart

@@ -0,0 +1,264 @@
+import 'package:cs_resources/constants/color_constants.dart';
+import 'package:domain/entity/response/labour_request_list_entity.dart';
+import 'package:domain/entity/response/labour_request_s_g_list_entity.dart';
+import 'package:flutter/cupertino.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter/widgets.dart';
+import 'package:plugin_basic/basic_export.dart';
+import 'package:widgets/ext/ex_widget.dart';
+import 'package:widgets/my_button.dart';
+import 'package:widgets/my_text_view.dart';
+
+/*
+ * 列表Item
+ */
+class AgencyItem extends StatelessWidget {
+  final int index;
+  final LabourRequestSGListRows item;
+  final VoidCallback? onDeleteAction;
+  final VoidCallback? onDetailAction;
+  final VoidCallback? onEditAction;
+
+  AgencyItem({
+    required this.index,
+    required this.item,
+    this.onDeleteAction,
+    this.onDetailAction,
+    this.onEditAction,
+  });
+
+  @override
+  Widget build(BuildContext context) {
+    return Container(
+      padding: const EdgeInsets.symmetric(vertical: 23, horizontal: 21),
+      margin: const EdgeInsets.only(left: 15, right: 15, top: 5, bottom: 5),
+      decoration: BoxDecoration(
+        color: const Color(0xFF4DCFF6).withOpacity(0.2), // 设置背景颜色和不透明度
+        borderRadius: BorderRadius.circular(5), // 设置圆角
+      ),
+      child: Column(
+        mainAxisSize: MainAxisSize.max,
+        crossAxisAlignment: CrossAxisAlignment.start,
+        children: [
+
+
+          // 中介商名称
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "${"Agency Name".tr}:",
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+
+              //文本
+              MyTextView(
+                item.jobTitle ?? "-",
+                marginLeft: 5,
+                isFontMedium: true,
+                textColor: ColorConstants.textYellowFFBB1B,
+                fontSize: 14,
+                textDecoration: TextDecoration.underline,
+                decorationColor: ColorConstants.textYellowFFBB1B,
+                // 可选,设置下划线的颜色
+                decorationThickness: 2.0,
+                // 可选,设置下划线的粗细
+                decorationStyle: TextDecorationStyle.solid, // 可选,设置下划线的样式
+              ).expanded(),
+            ],
+          ),
+
+          // 编码
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "${"ACRA NO".tr}:",
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+
+              //文本
+              MyTextView(
+                item.outletName ?? "-",
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor: Colors.white,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ).marginOnly(top: 12),
+
+          // 负责人
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "${"Person in Charge".tr}:",
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+
+              //文本
+              MyTextView(
+                item.outletName ?? "-",
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor: Colors.white,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ).marginOnly(top: 12),
+
+          // 邮箱
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "${"Contact Email".tr}:",
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+
+              //文本
+              MyTextView(
+                item.needNum.toString(),
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor: Colors.white,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ).marginOnly(top: 12),
+
+          // 电话
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "${"Contact No".tr}:",
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+
+              //文本
+              MyTextView(
+                item.needNum.toString(),
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor: Colors.white,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ).marginOnly(top: 12),
+
+
+          // 状态
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "Status:".tr,
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+
+              //状态
+              MyTextView(
+                item.status == null ? "" : item.status!.tr,
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor: "Applied" == item.status
+                    ? ColorConstants.textGreen05DC82
+                    : "No Register" == item.status
+                    ? ColorConstants.textRedFF6262
+                    : "Pending" == item.status
+                    ? ColorConstants.textYellowFFBB1B
+                    : ColorConstants.white,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ).marginOnly(top: 12),
+
+          //按钮组
+          Visibility(
+            visible: item.actionList?.isNotEmpty ?? false,
+            child: Row(
+              mainAxisSize: MainAxisSize.max,
+              mainAxisAlignment: MainAxisAlignment.end,
+              crossAxisAlignment: CrossAxisAlignment.center,
+              children: [
+                //详情按钮
+                Visibility(
+                  visible: item.actionList?.contains("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),
+                ),
+
+                //Delete按钮
+                Visibility(
+                  visible: item.actionList?.contains("delete") ?? false,
+                  child: MyButton(
+                    onPressed: () {
+                      FocusScope.of(context).unfocus();
+                      onDeleteAction?.call();
+                    },
+                    text: "Delete".tr,
+                    textColor: ColorConstants.white,
+                    backgroundColor: ColorConstants.textRedFF6262,
+                    radius: 17.25,
+                    minWidth: 60,
+                    minHeight: 35,
+                  ).marginOnly(left: 12),
+                ),
+
+                //Edit按钮
+                Visibility(
+                  visible: item.actionList?.contains("edit") ?? false,
+                  child: MyButton(
+                    onPressed: () {
+                      FocusScope.of(context).unfocus();
+                      onEditAction?.call();
+                    },
+                    text: "Edit".tr,
+                    textColor: ColorConstants.white,
+                    backgroundColor: hexToColor("#FFBB1B"),
+                    radius: 17.25,
+                    minWidth: 60,
+                    minHeight: 35,
+                  ).marginOnly(left: 12),
+                ),
+
+              ],
+            ).marginOnly(top: 15, bottom: 2),
+          ),
+        ],
+      ),
+    );
+  }
+}

+ 248 - 0
packages/cpt_sg/lib/modules/agency/agency_list/agency_list_controller.dart

@@ -0,0 +1,248 @@
+import 'package:domain/entity/response/labour_request_s_g_list_entity.dart';
+import 'package:domain/repository/labour_sg_repository.dart';
+
+import 'package:domain/entity/response/labour_request_index_entity.dart';
+import 'package:get/get.dart';
+import 'package:plugin_basic/constants/app_constant.dart';
+import 'package:plugin_platform/engine/dialog/dialog_engine.dart';
+import 'package:plugin_platform/engine/notify/notify_engine.dart';
+import 'package:plugin_platform/engine/toast/toast_engine.dart';
+import 'package:plugin_platform/http/dio/dio_cancelable_mixin.dart';
+import 'package:plugin_platform/http/http_result.dart';
+import 'package:shared/utils/date_time_utils.dart';
+import 'package:shared/utils/event_bus.dart';
+import 'package:shared/utils/util.dart';
+import 'package:widgets/dialog/app_default_dialog.dart';
+import 'package:widgets/load_state_layout.dart';
+import 'package:widgets/widget_export.dart';
+
+import '../agency_add/agency_add_page.dart';
+import 'agency_list_state.dart';
+
+class AgencyListController extends GetxController with DioCancelableMixin {
+  final LabourSGRepository _labourRepository = Get.find();
+  final AgencyListState state = AgencyListState();
+
+  var _curPage = 1;
+  var _needShowPlaceholder = true;
+
+  //页面PlaceHolder的展示
+  LoadState loadingState = LoadState.State_Success;
+  String? errorMessage;
+
+  //刷新页面状态
+  void changeLoadingState(LoadState state) {
+    loadingState = state;
+    update();
+  }
+
+  // Refresh 控制器
+  final EasyRefreshController refreshController = EasyRefreshController(
+    controlFinishRefresh: true,
+    controlFinishLoad: true,
+  );
+
+  // Refresh 刷新事件
+  Future onRefresh() async {
+    _curPage = 1;
+    fetchLabourRequestList();
+  }
+
+  // Refresh 加载事件
+  Future loadMore() async {
+    _curPage++;
+    fetchLabourRequestList();
+  }
+
+  // 重试请求
+  Future retryRequest() async {
+    _curPage = 1;
+    _needShowPlaceholder = true;
+    fetchLabourRequestList();
+  }
+
+  /// 获取列表数据
+  Future fetchLabourRequestList() async {
+    if (_needShowPlaceholder) {
+      changeLoadingState(LoadState.State_Loading);
+    }
+
+    // 并发执行两个请求
+    var futures = [
+      _labourRepository.fetchLabourRequestSGList(
+        state.keyword,
+        "",
+        "",
+        state.selectedStatusId,
+        "",
+        curPage: _curPage,
+        cancelToken: cancelToken,
+      ),
+      state.indexOptions == null
+          ? _labourRepository.fetchLabourRequestSGIndex(
+              cancelToken: cancelToken,
+            )
+          : Future(() => HttpResult(isSuccess: true).convert(data: state.indexOptions!)),
+    ];
+
+    //拿到结果
+    var results = await Future.wait(futures);
+    var listResult = results[0] as HttpResult<LabourRequestSGListEntity>;
+    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<LabourRequestSGListRows>? list) {
+    if (list != null && list.isNotEmpty) {
+      //有数据,判断是刷新还是加载更多的数据
+      if (_curPage == 1) {
+        //刷新的方式
+        state.datas.clear();
+        state.datas.addAll(list);
+        refreshController.finishRefresh();
+
+        //更新展示的状态
+        changeLoadingState(LoadState.State_Success);
+      } else {
+        //加载更多
+        state.datas.addAll(list);
+        refreshController.finishLoad();
+        update();
+      }
+    } else {
+      if (_curPage == 1) {
+        //展示无数据的布局
+        state.datas.clear();
+        changeLoadingState(LoadState.State_Empty);
+        refreshController.finishRefresh();
+      } else {
+        //展示加载完成,没有更多数据了
+        refreshController.finishLoad(IndicatorResult.noMore);
+      }
+    }
+  }
+
+  // 执行搜索
+  void doSearch(String keyword) {
+    state.keyword = keyword;
+    //赋值之后刷新
+    refreshController.callRefresh();
+  }
+
+  // 清空搜索条件
+  void resetFiltering() {
+    state.keyword = "";
+    state.searchController.text = "";
+    state.selectedStatusId = null;
+
+    //赋值之后刷新
+    refreshController.callRefresh();
+  }
+
+  /// 根据ID获取Item对象,用于刷新
+  void fetchItemByIdAndRefreshItem(String requestId) async {
+    var result = await _labourRepository.fetchItemByRequestId(
+      requestId,
+      cancelToken: cancelToken,
+    );
+
+    //处理数据
+    if (result.isSuccess) {
+      var data = result.data;
+      if (data != null && data.rows != null && data.rows!.isNotEmpty) {
+        final requestItem = data.rows![0];
+
+        //找到当前数据中的此 requestId,并替换对象,再刷新
+        var index = state.datas.indexWhere((element) => element.requestId == requestItem.requestId);
+        if (index >= 0) {
+          state.datas[index] = requestItem;
+          update();
+        }
+      }
+    } else {
+      ToastEngine.show(result.errorMsg ?? "Network Load Error".tr);
+    }
+  }
+
+  @override
+  void onReady() {
+    super.onReady();
+    fetchLabourRequestList();
+  }
+
+  @override
+  void onClose() {
+    state.datas.clear();
+    super.onClose();
+  }
+
+
+  //跳转到添加页面
+  void gotoAddAgencyPage() {
+    SGAgencyAddPage.startInstance("", (result) {
+      if (result != null) {
+        refreshController.callRefresh();
+      }
+    });
+  }
+
+  //去详情页面
+  void gotoDetailPage(LabourRequestSGListRows data) {}
+
+  //去编辑页面
+  void gotoEditPage(LabourRequestSGListRows data) {
+    SGAgencyAddPage.startInstance("123", (result) {
+      if (result != null) {
+        fetchItemByIdAndRefreshItem(data.requestId.toString());
+      }
+    });
+  }
+
+  //删除labourRequest
+  void doDelete(String? requestId, int index) {
+    DialogEngine.show(
+        widget: AppDefaultDialog(
+      title: "Confirmation".tr,
+      message: "Are you sure you want to delete this agency?".tr,
+      confirmAction: () {
+        _submitDeleteRequest(requestId, index);
+      },
+    ));
+  }
+
+  void _submitDeleteRequest(String? requestId, int index) async {
+    var result = await _labourRepository.deleteLabourRequestSG(requestId, cancelToken: cancelToken);
+
+    if (result.isSuccess) {
+      NotifyEngine.showSuccess("Successful".tr);
+
+      if (state.datas.length <= 1) {
+        refreshController.callRefresh();
+      } else {
+        state.datas.removeAt(index);
+        update();
+      }
+    } else {
+      ToastEngine.show(result.errorMsg ?? "Network Load Error".tr);
+    }
+  }
+
+  /// 选择中介公司状态
+  void pickAgencyStatus() {}
+}

+ 235 - 0
packages/cpt_sg/lib/modules/agency/agency_list/agency_list_page.dart

@@ -0,0 +1,235 @@
+import 'package:cs_resources/constants/color_constants.dart';
+import 'package:cs_resources/generated/assets.dart';
+import 'package:flutter/material.dart';
+import 'package:get/get.dart';
+import 'package:plugin_basic/base/base_state.dart';
+import 'package:plugin_basic/base/base_stateful_page.dart';
+import 'package: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/my_button.dart';
+import 'package:widgets/my_load_image.dart';
+import 'package:widgets/my_text_view.dart';
+import 'package:widgets/widget_export.dart';
+
+import 'agency_item.dart';
+import 'agency_list_controller.dart';
+import 'agency_list_state.dart';
+
+/*
+ * 新加坡的中介公司列表
+ */
+class SGAgencyListPage extends BaseStatefulPage<AgencyListController> {
+  SGAgencyListPage({Key? key}) : super(key: key);
+
+  //启动当前页面
+  static void startInstance() {
+    return Get.start(RouterPath.SGAgencyList);
+  }
+
+  @override
+  AgencyListController createRawController() {
+    return AgencyListController();
+  }
+
+  @override
+  State<SGAgencyListPage> createState() => _LabourRequestListState();
+}
+
+class _LabourRequestListState extends BaseState<SGAgencyListPage, AgencyListController> {
+  late AgencyListState 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.titleBar(context, "Agency List".tr),
+
+              //搜索的条件
+              Row(
+                children: [
+                  //下拉选
+                  Container(
+                    padding: const EdgeInsets.only(left: 12, right: 10),
+                    margin: const EdgeInsets.only(right: 10),
+                    height: 40,
+                    decoration: BoxDecoration(
+                      color: const Color(0xFF4DCFF6).withOpacity(0.2),
+                      borderRadius: const BorderRadius.all(Radius.circular(20)),
+                    ),
+                    child: Row(
+                      mainAxisSize: MainAxisSize.max,
+                      crossAxisAlignment: CrossAxisAlignment.center,
+                      mainAxisAlignment: MainAxisAlignment.start,
+                      children: [
+                        MyTextView(
+                          "",
+                          fontSize: 14,
+                          hint: "Status".tr,
+                          textHintColor: ColorConstants.textGrayAECAE5,
+                          textColor: ColorConstants.white,
+                        ).expanded(),
+
+                        //下拉选图标
+                        const MyAssetImage(Assets.baseServiceTriangleDropDownIcon, width: 11.5, height: 6.28),
+                      ],
+                    ),
+                  ).onTap(() {
+                    FocusScope.of(context).unfocus();
+                    controller.pickAgencyStatus();
+                  }).expanded(flex: 1),
+
+                  //搜索框
+                  Container(
+                    height: 40,
+                    margin: const EdgeInsets.only(right: 10),
+                    padding: const EdgeInsets.only(left: 12, right: 10),
+                    decoration: BoxDecoration(
+                      color: const Color(0xFF4DCFF6).withOpacity(0.2),
+                      borderRadius: const BorderRadius.all(Radius.circular(20)),
+                    ),
+                    child: Row(
+                      mainAxisSize: MainAxisSize.max,
+                      crossAxisAlignment: CrossAxisAlignment.center,
+                      children: [
+                        IgnoreKeyboardDismiss(
+                          child: TextField(
+                            cursorColor: Colors.white,
+                            cursorWidth: 1.5,
+                            autofocus: false,
+                            maxLines: 1,
+                            minLines: 1,
+                            focusNode: state.focusNode,
+                            controller: state.searchController,
+                            decoration: InputDecoration(
+                              isDense: true,
+                              //清除垂直方向的填充
+                              isCollapsed: true,
+                              //让文字垂直居中
+                              border: InputBorder.none,
+                              hintText: 'Agency Name'.tr,
+                              hintStyle: const TextStyle(
+                                color: ColorConstants.textGrayAECAE5,
+                                fontSize: 14.0,
+                                fontWeight: FontWeight.w400,
+                              ),
+                            ),
+                            style: const TextStyle(
+                              color: ColorConstants.white,
+                              fontSize: 14.0,
+                              fontWeight: FontWeight.w400,
+                            ),
+                            onSubmitted: (value){
+                              controller.doSearch(value);
+                            },
+                            // 键盘动作右下角图标
+                            textInputAction: TextInputAction.search,
+                            textAlignVertical: TextAlignVertical.center,
+                          ),
+                        ).expanded(),
+                      ],
+                    ),
+                  ).expanded(flex: 1),
+
+                  //筛选按钮
+                  MyButton(
+                    onPressed: () {
+                      FocusScope.of(context).unfocus();
+                      controller.resetFiltering();
+                    },
+                    text: "Reset".tr,
+                    textColor: ColorConstants.white,
+                    backgroundColor: hexToColor("#2BA9F9", opacity: 0.5),
+                    radius: 20,
+                    minWidth: 60,
+                    minHeight: 35,
+                  ),
+                ],
+              ).marginOnly(top: 10, left: 15, right: 15),
+
+              // 添加按钮
+              MyButton(
+                type: ClickType.throttle,
+                milliseconds: 500,
+                onPressed: () {
+                  FocusScope.of(context).unfocus();
+                  controller.gotoAddAgencyPage();
+                },
+                text: "Add Agency".tr,
+                textColor: ColorConstants.white,
+                fontSize: 16,
+                radius: 20,
+                backgroundColor: hexToColor("#FFBB1B"),
+                fontWeight: FontWeight.w500,
+              ).marginSymmetric(horizontal: 15, vertical: 10),
+
+              //底部的列表
+              EasyRefresh(
+                controller: controller.refreshController,
+                onRefresh: controller.onRefresh,
+                onLoad: controller.loadMore,
+                child: LoadStateLayout(
+                  state: controller.loadingState,
+                  errorMessage: controller.errorMessage,
+                  errorRetry: () {
+                    controller.retryRequest();
+                  },
+                  successSliverWidget: [
+                    SliverList(
+                        delegate: SliverChildBuilderDelegate(
+                      (context, index) {
+                        return AgencyItem(
+                          index: index,
+                          item: state.datas[index],
+                          onDetailAction: () {
+                            controller.gotoDetailPage(state.datas[index]);
+                          },
+                          onDeleteAction: () {
+                            controller.doDelete(state.datas[index].requestId,index);
+                          },
+                          onEditAction: () {
+                            controller.gotoEditPage(state.datas[index]);
+                          },
+
+                        );
+                      },
+                      childCount: state.datas.length,
+                    ))
+                  ],
+                ),
+              ).expanded(),
+            ],
+          ),
+        ),
+      );
+    });
+  }
+}

+ 15 - 0
packages/cpt_sg/lib/modules/agency/agency_list/agency_list_state.dart

@@ -0,0 +1,15 @@
+import 'package:domain/entity/response/labour_request_index_entity.dart';
+import 'package:domain/entity/response/labour_request_s_g_list_entity.dart';
+import 'package:flutter/material.dart';
+
+class AgencyListState {
+  //筛选条件
+  final TextEditingController searchController = TextEditingController();
+  final FocusNode focusNode = FocusNode();
+  String keyword = "";
+  String? selectedStatusId;
+
+  //页面的列表数据
+  List<LabourRequestSGListRows> datas = [];
+  LabourRequestIndexEntity? indexOptions;
+}

+ 171 - 0
packages/cpt_sg/lib/modules/agency/contract_add/contract_add_controller.dart

@@ -0,0 +1,171 @@
+import 'package:domain/repository/labour_sg_repository.dart';
+import 'package:flutter/cupertino.dart';
+import 'package:get/get.dart';
+import 'package:plugin_platform/http/dio/dio_cancelable_mixin.dart';
+import 'package:shared/utils/util.dart';
+import 'package:widgets/picker/date_picker_util.dart';
+import 'package:widgets/picker/option_pick_util.dart';
+
+import 'contract_add_state.dart';
+
+class ContractAddController extends GetxController with DioCancelableMixin {
+  final LabourSGRepository _labourRepository = Get.find();
+  final ContractAddState state = ContractAddState();
+
+  // 获取添加或者编辑的详情
+  void _fetchAddEditIndexDetail() async {
+    // //获取到数据
+    // Future<HttpResult<JobTemplateEditIndexEntity>> taskFuture;
+    // if (Utils.isNotEmpty(state.templateId) && state.templateId != "0") {
+    //   //编辑
+    //   taskFuture = _labourRepository.fetchJobTemplateEditIndex(state.templateId, cancelToken: cancelToken);
+    // } else {
+    //   //新增
+    //   taskFuture = _labourRepository.fetchJobTemplateAddIndex(cancelToken: cancelToken);
+    // }
+    //
+    // var result = await taskFuture;
+    //
+    // //处理数据
+    // if (result.isSuccess) {
+    //   state.indexEntity = result.data;
+    //
+    //   var templateNameController = state.formData['template_name']!['controller'];
+    //   var descController = state.formData['desc']!['controller'];
+    //   var contactController = state.formData['contact']!['controller'];
+    //   var contactNoController = state.formData['contact_no']!['controller'];
+    //   var noteController = state.formData['note']!['controller'];
+    //   templateNameController.text = state.indexEntity?.name ?? "";
+    //   descController.text = state.indexEntity?.description ?? "";
+    //   contactController.text = state.indexEntity?.contact ?? "";
+    //   contactNoController.text = state.indexEntity?.contactNo ?? "";
+    //   noteController.text = state.indexEntity?.note ?? "";
+    //
+    //   //默认赋值
+    //   state.selectedAgeList = state.indexEntity?.ageList.where((e) => e.checked == "checked").map((e) => e.value!).toList() ?? [];
+    //   Log.d("当前选中的年龄1:${ state.selectedAgeList}");
+    //   state.selectedLanguageList = state.indexEntity?.languageList.where((e) => e.checked == "checked").map((e) => e.value!).toList() ?? [];
+    //   Log.d("当前选中的语言1:${ state.selectedLanguageList}");
+    //   state.foodCert = state.indexEntity?.withFoodCert.toString();
+    //
+    //   update();
+    // } else {
+    //   ToastEngine.show(result.errorMsg ?? "Network Load Error".tr);
+    // }
+  }
+
+  /// 提交
+  void doSubmit() async {
+
+
+    // Future<HttpResult> taskFuture;
+    // if (Utils.isNotEmpty(state.templateId) && state.templateId != "0") {
+    //   taskFuture = _labourRepository.editJobTemplateSubmit(
+    //     state.templateId,
+    //     templateName,
+    //     contact,
+    //     contactNo,
+    //     desc,
+    //     note,
+    //     state.selectedAgeList.join(","),
+    //     state.gender,
+    //     state.foodCert,
+    //     state.selectedLanguageList.join(","),
+    //     cancelToken: cancelToken,
+    //   );
+    // } else {
+    //   taskFuture = _labourRepository.addJobTemplateSubmit(
+    //     templateName,
+    //     contact,
+    //     contactNo,
+    //     desc,
+    //     note,
+    //     state.selectedAgeList.join(","),
+    //     state.gender,
+    //     state.foodCert,
+    //     state.selectedLanguageList.join(","),
+    //     cancelToken: cancelToken,
+    //   );
+    // }
+    //
+    // var result = await taskFuture;
+    //
+    // //处理数据
+    // if (result.isSuccess) {
+    //   NotifyEngine.showSuccess("Successful".tr);
+    //
+    //   //根据类型刷新
+    //   state.cb?.call(state.templateId);
+    //
+    //   Get.back();
+    // } else {
+    //   ToastEngine.show(result.errorMsg ?? "Network Load Error".tr);
+    // }
+  }
+
+  @override
+  void onReady() {
+    super.onReady();
+    _fetchAddEditIndexDetail();
+  }
+
+  //选择开始时间
+  void pickStartTime() {
+
+    DatePickerUtil.showCupertinoDatePicker(
+      selectedDateTime: state.selectedStartTime,
+      mode: CupertinoDatePickerMode.date,
+      onDateTimeChanged: (date) {
+        state.selectedStartTime = date;
+        update();
+      },
+      title: "Start Time".tr,
+    );
+  }
+
+  // 选择结束时间
+  void pickEndTime() {
+
+    DatePickerUtil.showCupertinoDatePicker(
+      selectedDateTime: state.selectedEndTime ?? state.selectedStartTime,
+      mode: CupertinoDatePickerMode.date,
+      onDateTimeChanged: (date) {
+        state.selectedEndTime = date;
+        update();
+      },
+      title: "End Time".tr,
+    );
+  }
+
+  // 选择中介商
+  void pickAgency() {
+
+    // int selectedTemplateIndex;
+    // if (state.selectedJobTitleId == null) {
+    //   selectedTemplateIndex = 0;
+    // } else {
+    //   selectedTemplateIndex = state.indexEntity!.titleList.indexWhere((department) => department.value.toString() == state.selectedJobTitleId);
+    // }
+    //
+    // if (selectedTemplateIndex < 0) {
+    //   selectedTemplateIndex = 0;
+    // }
+
+    OptionPickerUtil.showCupertinoOptionPicker(
+      items: state.agencyList,
+      initialSelectIndex: 0,
+      onPickerChanged: (_, index) {
+        state.selectedAgency =  state.agencyList[index];
+        state.selectedAgencyId = index.toString();
+        update();
+      },
+    );
+  }
+
+  //设置选中的文件路径数组
+  void setDocList(List<String> list) {
+    state.selectedPaths = list;
+    update();
+  }
+
+}

+ 232 - 0
packages/cpt_sg/lib/modules/agency/contract_add/contract_add_page.dart

@@ -0,0 +1,232 @@
+import 'package:cs_resources/constants/color_constants.dart';
+import 'package:cs_resources/generated/assets.dart';
+import 'package:flutter/material.dart';
+import 'package:get/get.dart';
+import 'package:shared/utils/date_time_utils.dart';
+import 'package:shared/utils/log_utils.dart';
+import 'package:shared/utils/screen_util.dart';
+import 'package:shared/utils/util.dart';
+import 'package:widgets/ext/ex_widget.dart';
+import 'package:widgets/my_appbar.dart';
+import 'package:widgets/my_button.dart';
+import 'package:widgets/my_load_image.dart';
+import 'package:widgets/my_text_view.dart';
+import 'package:widgets/no_shadow_scroll_behavior.dart';
+import 'package:widgets/shatter/form_require_text.dart';
+import 'contract_add_controller.dart';
+import 'package:plugin_basic/base/base_stateless_page.dart';
+import 'package:plugin_basic/utils/ext_get_nav.dart';
+import 'package:router/path/router_path.dart';
+import 'package:plugin_platform/platform_export.dart';
+
+import 'contract_add_state.dart';
+
+/*
+ * 合同的添加与编辑
+ */
+class SGContractAddPage extends BaseStatelessPage<ContractAddController> {
+  SGContractAddPage({Key? key}) : super(key: key);
+
+  //启动当前页面
+  static void startInstance(
+    String agentId,
+    void Function(dynamic value)? cb,
+  ) {
+    return Get.start(RouterPath.SGContractAdd, arguments: {'agentId': agentId, 'cb': cb});
+  }
+
+  late ContractAddState state;
+
+  @override
+  void initState() {
+    state = controller.state;
+    state.agentId = Get.arguments['agentId'];
+    state.cb = Get.arguments['cb'] as void Function(dynamic)?;
+  }
+
+  @override
+  ContractAddController createRawController() {
+    return ContractAddController();
+  }
+
+  @override
+  Widget buildWidget(BuildContext context) {
+    return autoCtlGetBuilder(builder: (controller) {
+      return Scaffold(
+        extendBodyBehindAppBar: true,
+        appBar: MyAppBar.appBar(context, Utils.isEmpty(state.agentId) ? "Add Contract".tr : "Edit Contract".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: "Agency Name".tr).marginOnly(left: 15, top: 19),
+
+                      //下拉选
+                      Container(
+                        padding: const EdgeInsets.only(left: 16, right: 10),
+                        margin: const EdgeInsets.only(top: 10, left: 15, right: 15),
+                        height: 48,
+                        decoration: BoxDecoration(
+                          color: const Color(0xFF4DCFF6).withOpacity(0.2),
+                          borderRadius: const BorderRadius.all(Radius.circular(5)),
+                        ),
+                        child: Row(
+                          mainAxisSize: MainAxisSize.max,
+                          crossAxisAlignment: CrossAxisAlignment.center,
+                          mainAxisAlignment: MainAxisAlignment.start,
+                          children: [
+                            MyTextView(
+                              state.selectedAgency ?? "",
+                              fontSize: 14,
+                              hint: "Choose Job Title".tr,
+                              textHintColor: ColorConstants.textGrayAECAE5,
+                              isFontMedium: true,
+                              textColor: ColorConstants.white,
+                            ).expanded(),
+
+                            //下拉选图标
+                            const MyAssetImage(Assets.baseServiceTriangleDropDownIcon, width: 11.5, height: 6.28),
+                          ],
+                        ),
+                      ).onTap(() {
+                        FocusScope.of(context).unfocus();
+                        controller.pickAgency();
+                      }),
+
+                      //必填 - 合同开始时间
+                      FormRequireText(text: "Contract Start Date".tr).marginOnly(left: 15, top: 15),
+
+                      Container(
+                        padding: const EdgeInsets.only(left: 16, right: 10),
+                        margin: const EdgeInsets.only(top: 10, left: 15, right: 15),
+                        height: 48,
+                        decoration: BoxDecoration(
+                          color: const Color(0xFF4DCFF6).withOpacity(0.2),
+                          borderRadius: const BorderRadius.all(Radius.circular(5)),
+                        ),
+                        child: Row(
+                          mainAxisSize: MainAxisSize.max,
+                          crossAxisAlignment: CrossAxisAlignment.center,
+                          mainAxisAlignment: MainAxisAlignment.start,
+                          children: [
+                            MyTextView(
+                              state.selectedStartTime == null ? "" : DateTimeUtils.formatDate(state.selectedStartTime, format: "yyyy-MM-dd"),
+                              fontSize: 14,
+                              hint: "Start Time".tr,
+                              textHintColor: ColorConstants.textGrayAECAE5,
+                              isFontMedium: true,
+                              textColor: ColorConstants.white,
+                            ).expanded(),
+                            //下拉选图标
+                            const MyAssetImage(Assets.baseServiceTriangleDropDownIcon, width: 11.5, height: 6.28),
+                          ],
+                        ),
+                      ).onTap(() {
+                        FocusScope.of(context).unfocus();
+                        controller.pickStartTime();
+                      }),
+
+                      //必填 - 合同结束时间
+                      FormRequireText(text: "Contract End Date".tr).marginOnly(left: 15, top: 15),
+
+                      Container(
+                        padding: const EdgeInsets.only(left: 16, right: 10),
+                        margin: const EdgeInsets.only(top: 10, left: 15, right: 15),
+                        height: 48,
+                        decoration: BoxDecoration(
+                          color: const Color(0xFF4DCFF6).withOpacity(0.2),
+                          borderRadius: const BorderRadius.all(Radius.circular(5)),
+                        ),
+                        child: Row(
+                          mainAxisSize: MainAxisSize.max,
+                          crossAxisAlignment: CrossAxisAlignment.center,
+                          mainAxisAlignment: MainAxisAlignment.start,
+                          children: [
+                            MyTextView(
+                              state.selectedEndTime == null ? "" : DateTimeUtils.formatDate(state.selectedEndTime, format: "yyyy-MM-dd"),
+                              fontSize: 14,
+                              hint: "End Time".tr,
+                              textHintColor: ColorConstants.textGrayAECAE5,
+                              isFontMedium: true,
+                              textColor: ColorConstants.white,
+                            ).expanded(),
+                            //下拉选图标
+                            const MyAssetImage(Assets.baseServiceTriangleDropDownIcon, width: 11.5, height: 6.28),
+                          ],
+                        ),
+                      ).onTap(() {
+                        FocusScope.of(context).unfocus();
+                        controller.pickEndTime();
+                      }),
+
+                      //附件
+                      MyTextView(
+                        "Attachment".tr,
+                        textColor: Colors.white,
+                        fontSize: 14,
+                        isFontRegular: true,
+                        marginLeft: 15,
+                        marginTop: 15,
+                      ),
+
+                      //九宫格图片选择
+                      ImageNineGrid(
+                        isSelectEnable: true,
+                        maxImages: 9,
+                        spacing: 15,
+                        initialImages: state.selectedPaths,
+                        onImagesChanged: (list) {
+                          controller.setDocList(list);
+                        },
+                      ).marginOnly(left: 15, right: 15, top: 10),
+
+                      //提交按钮
+                      MyButton(
+                        type: ClickType.throttle,
+                        milliseconds: 500,
+                        onPressed: () {
+                          FocusScope.of(context).unfocus();
+                          controller.doSubmit();
+                        },
+                        text: "Submit".tr,
+                        textColor: ColorConstants.white,
+                        fontSize: 16,
+                        radius: 20,
+                        backgroundColor: ColorConstants.textYellowFFBB1B,
+                        fontWeight: FontWeight.w500,
+                      ).marginSymmetric(vertical: 25, horizontal: 15),
+                    ],
+                  ),
+                ),
+              ),
+            ),
+          ),
+        ),
+      );
+    });
+  }
+}

+ 16 - 0
packages/cpt_sg/lib/modules/agency/contract_add/contract_add_state.dart

@@ -0,0 +1,16 @@
+
+class ContractAddState {
+
+  DateTime? selectedStartTime;
+  DateTime? selectedEndTime;
+
+  List<String> agencyList = ["瓜豆1", "瓜豆2", "瓜豆3"];
+  String? selectedAgency;
+  String? selectedAgencyId;
+
+  List<String> selectedPaths = [];  //选择的文件路径
+
+  String? agentId;
+  void Function(dynamic value)? cb;
+
+}

+ 339 - 0
packages/cpt_sg/lib/modules/agency/contract_list/contract_item.dart

@@ -0,0 +1,339 @@
+import 'package:cs_resources/constants/color_constants.dart';
+import 'package:cs_resources/generated/assets.dart';
+import 'package:domain/entity/response/labour_request_list_entity.dart';
+import 'package:domain/entity/response/labour_request_s_g_list_entity.dart';
+import 'package:flutter/cupertino.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter/widgets.dart';
+import 'package:plugin_basic/basic_export.dart';
+import 'package:widgets/ext/ex_widget.dart';
+import 'package:widgets/my_button.dart';
+import 'package:widgets/my_load_image.dart';
+import 'package:widgets/my_text_view.dart';
+
+/*
+ * 列表Item
+ */
+class ContractItem extends StatelessWidget {
+  final int index;
+  final LabourRequestSGListRows item;
+  final VoidCallback? onRenewAction;
+  final VoidCallback? onDetailAction;
+  final VoidCallback? onEditAction;
+
+  ContractItem({
+    required this.index,
+    required this.item,
+    this.onRenewAction,
+    this.onDetailAction,
+    this.onEditAction,
+  });
+
+  @override
+  Widget build(BuildContext context) {
+    return Container(
+      padding: const EdgeInsets.symmetric(vertical: 23, horizontal: 21),
+      margin: const EdgeInsets.only(left: 15, right: 15, top: 5, bottom: 5),
+      decoration: BoxDecoration(
+        color: const Color(0xFF4DCFF6).withOpacity(0.2), // 设置背景颜色和不透明度
+        borderRadius: BorderRadius.circular(5), // 设置圆角
+      ),
+      child: Column(
+        mainAxisSize: MainAxisSize.max,
+        crossAxisAlignment: CrossAxisAlignment.start,
+        children: [
+          // 中介商名称
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "${"Agency Name".tr}:",
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+
+              //文本
+              MyTextView(
+                item.jobTitle ?? "-",
+                marginLeft: 5,
+                isFontMedium: true,
+                textColor: ColorConstants.textYellowFFBB1B,
+                fontSize: 14,
+                textDecoration: TextDecoration.underline,
+                decorationColor: ColorConstants.textYellowFFBB1B,
+                // 可选,设置下划线的颜色
+                decorationThickness: 2.0,
+                // 可选,设置下划线的粗细
+                decorationStyle: TextDecorationStyle.solid, // 可选,设置下划线的样式
+              ).expanded(),
+            ],
+          ),
+
+          // 编码
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "${"ACRA NO".tr}:",
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+
+              //文本
+              MyTextView(
+                item.outletName ?? "-",
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor: Colors.white,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ).marginOnly(top: 12),
+
+          // 负责人
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "${"Person in Charge".tr}:",
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+
+              //文本
+              MyTextView(
+                item.outletName ?? "-",
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor: Colors.white,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ).marginOnly(top: 12),
+
+          // 职位数量
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "${"Position".tr}:",
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+
+              //文本
+              MyTextView(
+                "1",
+                backgroundColor: ColorConstants.textGreen0AC074,
+                cornerRadius: 20,
+                marginLeft: 5,
+                paddingTop: 0,
+                paddingLeft: 14,
+                paddingRight: 14,
+                paddingBottom: 0,
+                isFontRegular: true,
+                textColor: Colors.white,
+                fontSize: 14,
+              ),
+            ],
+          ).marginOnly(top: 12),
+
+          // 合同开始时间
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "${"Contract Start Date".tr}:",
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+
+              //文本
+              MyTextView(
+                " 2024-01-01",
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor: Colors.white,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ).marginOnly(top: 12),
+
+          // 合同结束时间
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "${"Contract End Date".tr}:",
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+
+              //文本
+              MyTextView(
+                " 2025-01-01",
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor: Colors.white,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ).marginOnly(top: 12),
+
+          // 附件
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "${"Contract".tr}:",
+                isFontRegular: true,
+                marginRight: 5,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+
+              //文本
+              const MyAssetImage(
+                Assets.agencyContractFileIcon,
+                width: 15,
+                height: 13.5,
+              ),
+            ],
+          ).marginOnly(top: 12),
+
+          // 状态
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "Status:".tr,
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+
+              //状态
+              MyTextView(
+                item.status == null ? "" : item.status!.tr,
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor: "Applied" == item.status
+                    ? ColorConstants.textGreen05DC82
+                    : "No Register" == item.status
+                        ? ColorConstants.textRedFF6262
+                        : "Pending" == item.status
+                            ? ColorConstants.textYellowFFBB1B
+                            : ColorConstants.white,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ).marginOnly(top: 12),
+
+          // 创建时间
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "Created At:".tr,
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+
+              //文本
+              MyTextView(
+                "2024-01-01 17:46:19",
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor: Colors.white,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ).marginOnly(top: 12),
+
+          //按钮组
+          Visibility(
+            visible: item.actionList.isNotEmpty,
+            child: Row(
+              mainAxisSize: MainAxisSize.max,
+              mainAxisAlignment: MainAxisAlignment.end,
+              crossAxisAlignment: CrossAxisAlignment.center,
+              children: [
+                //详情按钮
+                Visibility(
+                  visible: item.actionList.contains("detail"),
+                  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),
+                ),
+
+                //Delete按钮
+                Visibility(
+                  visible: item.actionList.contains("renew") ?? false,
+                  child: MyButton(
+                    onPressed: () {
+                      FocusScope.of(context).unfocus();
+                      onRenewAction?.call();
+                    },
+                    text: "Renew".tr,
+                    textColor: ColorConstants.white,
+                    backgroundColor: ColorConstants.textRedFF6262,
+                    radius: 17.25,
+                    minWidth: 60,
+                    minHeight: 35,
+                  ).marginOnly(left: 12),
+                ),
+
+                //Edit按钮
+                Visibility(
+                  visible: item.actionList.contains("edit") ?? false,
+                  child: MyButton(
+                    onPressed: () {
+                      FocusScope.of(context).unfocus();
+                      onEditAction?.call();
+                    },
+                    text: "Edit".tr,
+                    textColor: ColorConstants.white,
+                    backgroundColor: hexToColor("#FFBB1B"),
+                    radius: 17.25,
+                    minWidth: 60,
+                    minHeight: 35,
+                  ).marginOnly(left: 12),
+                ),
+              ],
+            ).marginOnly(top: 15, bottom: 2),
+          ),
+        ],
+      ),
+    ).onTap(() {
+      FocusScope.of(context).unfocus();
+      onDetailAction?.call();
+    });
+  }
+}

+ 218 - 0
packages/cpt_sg/lib/modules/agency/contract_list/contract_list_controller.dart

@@ -0,0 +1,218 @@
+import 'package:cpt_sg/modules/agency/contract_add/contract_add_page.dart';
+import 'package:cpt_sg/modules/agency/contract_rate_list/contract_rate_list_page.dart';
+import 'package:domain/entity/response/labour_request_s_g_list_entity.dart';
+import 'package:domain/repository/labour_sg_repository.dart';
+
+import 'package:domain/entity/response/labour_request_index_entity.dart';
+import 'package:get/get.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:widgets/load_state_layout.dart';
+import 'package:widgets/widget_export.dart';
+import 'contract_list_state.dart';
+
+class ContractListController extends GetxController with DioCancelableMixin {
+  final LabourSGRepository _labourRepository = Get.find();
+  final ContractListState state = ContractListState();
+
+  var _curPage = 1;
+  var _needShowPlaceholder = true;
+
+  //页面PlaceHolder的展示
+  LoadState loadingState = LoadState.State_Success;
+  String? errorMessage;
+
+  //刷新页面状态
+  void changeLoadingState(LoadState state) {
+    loadingState = state;
+    update();
+  }
+
+  // Refresh 控制器
+  final EasyRefreshController refreshController = EasyRefreshController(
+    controlFinishRefresh: true,
+    controlFinishLoad: true,
+  );
+
+  // Refresh 刷新事件
+  Future onRefresh() async {
+    _curPage = 1;
+    fetchLabourRequestList();
+  }
+
+  // Refresh 加载事件
+  Future loadMore() async {
+    _curPage++;
+    fetchLabourRequestList();
+  }
+
+  // 重试请求
+  Future retryRequest() async {
+    _curPage = 1;
+    _needShowPlaceholder = true;
+    fetchLabourRequestList();
+  }
+
+  /// 获取列表数据
+  Future fetchLabourRequestList() async {
+    if (_needShowPlaceholder) {
+      changeLoadingState(LoadState.State_Loading);
+    }
+
+    // 并发执行两个请求
+    var futures = [
+      _labourRepository.fetchLabourRequestSGList(
+        state.keyword,
+        "",
+        "",
+        state.selectedStatusId,
+        "",
+        curPage: _curPage,
+        cancelToken: cancelToken,
+      ),
+      state.indexOptions == null
+          ? _labourRepository.fetchLabourRequestSGIndex(
+              cancelToken: cancelToken,
+            )
+          : Future(() => HttpResult(isSuccess: true).convert(data: state.indexOptions!)),
+    ];
+
+    //拿到结果
+    var results = await Future.wait(futures);
+    var listResult = results[0] as HttpResult<LabourRequestSGListEntity>;
+    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<LabourRequestSGListRows>? list) {
+    if (list != null && list.isNotEmpty) {
+      //有数据,判断是刷新还是加载更多的数据
+      if (_curPage == 1) {
+        //刷新的方式
+        state.datas.clear();
+        state.datas.addAll(list);
+        refreshController.finishRefresh();
+
+        //更新展示的状态
+        changeLoadingState(LoadState.State_Success);
+      } else {
+        //加载更多
+        state.datas.addAll(list);
+        refreshController.finishLoad();
+        update();
+      }
+    } else {
+      if (_curPage == 1) {
+        //展示无数据的布局
+        state.datas.clear();
+        changeLoadingState(LoadState.State_Empty);
+        refreshController.finishRefresh();
+      } else {
+        //展示加载完成,没有更多数据了
+        refreshController.finishLoad(IndicatorResult.noMore);
+      }
+    }
+  }
+
+  // 执行搜索
+  void doSearch(String keyword) {
+    state.keyword = keyword;
+    //赋值之后刷新
+    refreshController.callRefresh();
+  }
+
+  // 清空搜索条件
+  void resetFiltering() {
+    state.keyword = "";
+    state.searchController.text = "";
+    state.selectedStatusId = null;
+
+    //赋值之后刷新
+    refreshController.callRefresh();
+  }
+
+  /// 根据ID获取Item对象,用于刷新
+  void fetchItemByIdAndRefreshItem(String requestId) async {
+    var result = await _labourRepository.fetchItemByRequestId(
+      requestId,
+      cancelToken: cancelToken,
+    );
+
+    //处理数据
+    if (result.isSuccess) {
+      var data = result.data;
+      if (data != null && data.rows != null && data.rows!.isNotEmpty) {
+        final requestItem = data.rows![0];
+
+        //找到当前数据中的此 requestId,并替换对象,再刷新
+        var index = state.datas.indexWhere((element) => element.requestId == requestItem.requestId);
+        if (index >= 0) {
+          state.datas[index] = requestItem;
+          update();
+        }
+      }
+    } else {
+      ToastEngine.show(result.errorMsg ?? "Network Load Error".tr);
+    }
+  }
+
+  @override
+  void onReady() {
+    super.onReady();
+    fetchLabourRequestList();
+  }
+
+  @override
+  void onClose() {
+    state.datas.clear();
+    super.onClose();
+  }
+
+  //跳转到添加页面
+  void gotoAddPage() {
+    SGContractAddPage.startInstance("", (result) {
+      if (result != null) {
+        refreshController.callRefresh();
+      }
+    });
+  }
+
+  //去详情页面
+  void gotoDetailPage(LabourRequestSGListRows data) {
+    SGContractRateListPage.startInstance();
+  }
+
+  //去编辑页面
+  void gotoEditPage(LabourRequestSGListRows data) {
+    SGContractAddPage.startInstance("123", (result) {
+      if (result != null) {
+        fetchItemByIdAndRefreshItem(data.requestId.toString());
+      }
+    });
+  }
+  /// 选择状态
+  void pickStatus() {}
+
+  /// 选择中介
+  void pickAgency() {
+
+  }
+
+}

+ 214 - 0
packages/cpt_sg/lib/modules/agency/contract_list/contract_list_page.dart

@@ -0,0 +1,214 @@
+import 'package:cs_resources/constants/color_constants.dart';
+import 'package:cs_resources/generated/assets.dart';
+import 'package:flutter/material.dart';
+import 'package:get/get.dart';
+import 'package:plugin_basic/base/base_state.dart';
+import 'package:plugin_basic/base/base_stateful_page.dart';
+import 'package: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/my_button.dart';
+import 'package:widgets/my_load_image.dart';
+import 'package:widgets/my_text_view.dart';
+import 'package:widgets/widget_export.dart';
+
+import 'contract_item.dart';
+import 'contract_list_controller.dart';
+import 'contract_list_state.dart';
+
+/*
+ * 新加坡的合同列表
+ */
+class SGContractListPage extends BaseStatefulPage<ContractListController> {
+  SGContractListPage({Key? key}) : super(key: key);
+
+  //启动当前页面
+  static void startInstance() {
+    return Get.start(RouterPath.SGContractList);
+  }
+
+  @override
+  ContractListController createRawController() {
+    return ContractListController();
+  }
+
+  @override
+  State<SGContractListPage> createState() => _LabourRequestListState();
+}
+
+class _LabourRequestListState extends BaseState<SGContractListPage, ContractListController> {
+  late ContractListState 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.titleBar(context, "Contract Management".tr),
+
+              //搜索的条件
+              Row(
+                children: [
+                  //下拉选-中介
+                  Container(
+                    padding: const EdgeInsets.only(left: 12, right: 10),
+                    margin: const EdgeInsets.only(right: 10),
+                    height: 40,
+                    decoration: BoxDecoration(
+                      color: const Color(0xFF4DCFF6).withOpacity(0.2),
+                      borderRadius: const BorderRadius.all(Radius.circular(20)),
+                    ),
+                    child: Row(
+                      mainAxisSize: MainAxisSize.max,
+                      crossAxisAlignment: CrossAxisAlignment.center,
+                      mainAxisAlignment: MainAxisAlignment.start,
+                      children: [
+                        MyTextView(
+                          "",
+                          fontSize: 14,
+                          hint: "Agency".tr,
+                          textHintColor: ColorConstants.textGrayAECAE5,
+                          textColor: ColorConstants.white,
+                        ).expanded(),
+
+                        //下拉选图标
+                        const MyAssetImage(Assets.baseServiceTriangleDropDownIcon, width: 11.5, height: 6.28),
+                      ],
+                    ),
+                  ).onTap(() {
+                    FocusScope.of(context).unfocus();
+                    controller.pickAgency();
+                  }).expanded(flex: 1),
+
+                  //下拉选-状态
+                  Container(
+                    padding: const EdgeInsets.only(left: 12, right: 10),
+                    margin: const EdgeInsets.only(right: 10),
+                    height: 40,
+                    decoration: BoxDecoration(
+                      color: const Color(0xFF4DCFF6).withOpacity(0.2),
+                      borderRadius: const BorderRadius.all(Radius.circular(20)),
+                    ),
+                    child: Row(
+                      mainAxisSize: MainAxisSize.max,
+                      crossAxisAlignment: CrossAxisAlignment.center,
+                      mainAxisAlignment: MainAxisAlignment.start,
+                      children: [
+                        MyTextView(
+                          "",
+                          fontSize: 14,
+                          hint: "Status".tr,
+                          textHintColor: ColorConstants.textGrayAECAE5,
+                          textColor: ColorConstants.white,
+                        ).expanded(),
+
+                        //下拉选图标
+                        const MyAssetImage(Assets.baseServiceTriangleDropDownIcon, width: 11.5, height: 6.28),
+                      ],
+                    ),
+                  ).onTap(() {
+                    FocusScope.of(context).unfocus();
+                    controller.pickStatus();
+                  }).expanded(flex: 1),
+
+                  //筛选按钮
+                  MyButton(
+                    onPressed: () {
+                      FocusScope.of(context).unfocus();
+                      controller.resetFiltering();
+                    },
+                    text: "Reset".tr,
+                    textColor: ColorConstants.white,
+                    backgroundColor: hexToColor("#2BA9F9", opacity: 0.5),
+                    radius: 20,
+                    minWidth: 60,
+                    minHeight: 35,
+                  ),
+                ],
+              ).marginOnly(top: 10, left: 15, right: 15),
+
+              // 添加按钮
+              MyButton(
+                type: ClickType.throttle,
+                milliseconds: 500,
+                onPressed: () {
+                  FocusScope.of(context).unfocus();
+                  controller.gotoAddPage();
+                },
+                text: "Add Contract".tr,
+                textColor: ColorConstants.white,
+                fontSize: 16,
+                radius: 20,
+                backgroundColor: hexToColor("#FFBB1B"),
+                fontWeight: FontWeight.w500,
+              ).marginSymmetric(horizontal: 15, vertical: 10),
+
+              //底部的列表
+              EasyRefresh(
+                controller: controller.refreshController,
+                onRefresh: controller.onRefresh,
+                onLoad: controller.loadMore,
+                child: LoadStateLayout(
+                  state: controller.loadingState,
+                  errorMessage: controller.errorMessage,
+                  errorRetry: () {
+                    controller.retryRequest();
+                  },
+                  successSliverWidget: [
+                    SliverList(
+                        delegate: SliverChildBuilderDelegate(
+                      (context, index) {
+                        return ContractItem(
+                          index: index,
+                          item: state.datas[index],
+                          onDetailAction: () {
+                            controller.gotoDetailPage(state.datas[index]);
+                          },
+                          onRenewAction: () {
+
+                          },
+                          onEditAction: () {
+                            controller.gotoEditPage(state.datas[index]);
+                          },
+
+                        );
+                      },
+                      childCount: state.datas.length,
+                    ))
+                  ],
+                ),
+              ).expanded(),
+            ],
+          ),
+        ),
+      );
+    });
+  }
+}

+ 15 - 0
packages/cpt_sg/lib/modules/agency/contract_list/contract_list_state.dart

@@ -0,0 +1,15 @@
+import 'package:domain/entity/response/labour_request_index_entity.dart';
+import 'package:domain/entity/response/labour_request_s_g_list_entity.dart';
+import 'package:flutter/material.dart';
+
+class ContractListState {
+  //筛选条件
+  final TextEditingController searchController = TextEditingController();
+  final FocusNode focusNode = FocusNode();
+  String keyword = "";
+  String? selectedStatusId;
+
+  //页面的列表数据
+  List<LabourRequestSGListRows> datas = [];
+  LabourRequestIndexEntity? indexOptions;
+}

+ 235 - 0
packages/cpt_sg/lib/modules/agency/contract_rate_edit_list/contract_rate_edit_item.dart

@@ -0,0 +1,235 @@
+import 'package:cs_resources/constants/color_constants.dart';
+import 'package:domain/entity/response/labour_request_s_g_list_entity.dart';
+import 'package:flutter/cupertino.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter/widgets.dart';
+import 'package:plugin_basic/basic_export.dart';
+import 'package:widgets/ext/ex_widget.dart';
+import 'package:widgets/my_button.dart';
+import 'package:widgets/my_text_view.dart';
+
+/*
+ * 列表Item
+ */
+class ContractRateEditItem extends StatelessWidget {
+  final int index;
+  final LabourRequestSGListRows item;
+  final VoidCallback? onEditAction;
+  final VoidCallback? onDeleteAction;
+
+  ContractRateEditItem({
+    required this.index,
+    required this.item,
+    this.onEditAction,
+    this.onDeleteAction,
+  });
+
+  @override
+  Widget build(BuildContext context) {
+    return Container(
+      padding: const EdgeInsets.symmetric(vertical: 23, horizontal: 21),
+      margin: const EdgeInsets.only(left: 15, right: 15, top: 5, bottom: 5),
+      decoration: BoxDecoration(
+        color: const Color(0xFF4DCFF6).withOpacity(0.2), // 设置背景颜色和不透明度
+        borderRadius: BorderRadius.circular(5), // 设置圆角
+      ),
+      child: Column(
+        mainAxisSize: MainAxisSize.max,
+        crossAxisAlignment: CrossAxisAlignment.start,
+        children: [
+
+          // 中介商名称
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "${"Agency Name".tr}:",
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+
+              //文本
+              MyTextView(
+                item.jobTitle ?? "-",
+                marginLeft: 5,
+                isFontMedium: true,
+                textColor: ColorConstants.textYellowFFBB1B,
+                fontSize: 14,
+                textDecoration: TextDecoration.underline,
+                decorationColor: ColorConstants.textYellowFFBB1B,
+                // 可选,设置下划线的颜色
+                decorationThickness: 2.0,
+                // 可选,设置下划线的粗细
+                decorationStyle: TextDecorationStyle.solid, // 可选,设置下划线的样式
+              ).expanded(),
+            ],
+          ),
+
+          // 职位
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "${"Position".tr}:",
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+
+              //文本
+              MyTextView(
+                item.outletName ?? "-",
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor: Colors.white,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ).marginOnly(top: 12),
+
+          // 日期
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "${"Date".tr}:",
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+
+              //文本
+              MyTextView(
+                item.createdAt ?? "-",
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor: Colors.white,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ).marginOnly(top: 12),
+
+          // 时薪
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "${"Hourly Rate".tr}:",
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+
+              //文本
+              MyTextView(
+                item.needNum.toString(),
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor: Colors.white,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ).marginOnly(top: 12),
+
+          // 创建时间
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "Created At:".tr,
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+
+              //文本
+              MyTextView(
+                item.createdAt.toString(),
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor: Colors.white,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ).marginOnly(top: 12),
+
+          // 更新时间
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+               "Updated At:".tr,
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+
+              //文本
+              MyTextView(
+                item.createdAt.toString(),
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor: Colors.white,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ).marginOnly(top: 12),
+
+          //按钮组
+          Visibility(
+            visible: item.actionList.isNotEmpty,
+            child: Row(
+              mainAxisSize: MainAxisSize.max,
+              mainAxisAlignment: MainAxisAlignment.end,
+              crossAxisAlignment: CrossAxisAlignment.center,
+              children: [
+
+                //Edit按钮
+                Visibility(
+                  visible: item.actionList.contains("edit"),
+                  child: MyButton(
+                    onPressed: () {
+                      FocusScope.of(context).unfocus();
+                      onEditAction?.call();
+                    },
+                    text: "Edit".tr,
+                    textColor: ColorConstants.white,
+                    backgroundColor: ColorConstants.textGreen0AC074,
+                    radius: 17.25,
+                    minWidth: 60,
+                    minHeight: 35,
+                  ).marginOnly(left: 12),
+                ),
+
+                //Delete按钮
+                Visibility(
+                  visible: item.actionList.contains("delete"),
+                  child: MyButton(
+                    onPressed: () {
+                      FocusScope.of(context).unfocus();
+                      onDeleteAction?.call();
+                    },
+                    text: "Delete".tr,
+                    textColor: ColorConstants.white,
+                    backgroundColor: ColorConstants.textRedFF6262,
+                    radius: 17.25,
+                    minWidth: 60,
+                    minHeight: 35,
+                  ).marginOnly(left: 12),
+                ),
+
+              ],
+            ).marginOnly(top: 15, bottom: 2),
+          ),
+        ],
+      ),
+    );
+  }
+}

+ 190 - 0
packages/cpt_sg/lib/modules/agency/contract_rate_edit_list/contract_rate_edit_list_controller.dart

@@ -0,0 +1,190 @@
+import 'package:domain/entity/response/labour_request_s_g_list_entity.dart';
+import 'package:domain/repository/labour_sg_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:widgets/dialog/app_default_dialog.dart';
+import 'package:widgets/load_state_layout.dart';
+import 'package:widgets/widget_export.dart';
+
+import '../contract_rate_setting/contract_rate_setting_page.dart';
+import '../contract_rate_specific_day/contract_rate_specific_page.dart';
+import 'contract_rate_edit_list_state.dart';
+import 'dialog/dialog_edit_rate.dart';
+
+class ContractRateEditListController extends GetxController with DioCancelableMixin {
+  final LabourSGRepository _labourRepository = Get.find();
+  final ContractRateEditListState state = ContractRateEditListState();
+
+  var _curPage = 1;
+  var _needShowPlaceholder = true;
+
+  //页面PlaceHolder的展示
+  LoadState loadingState = LoadState.State_Success;
+  String? errorMessage;
+
+  //刷新页面状态
+  void changeLoadingState(LoadState state) {
+    loadingState = state;
+    update();
+  }
+
+  // Refresh 控制器
+  final EasyRefreshController refreshController = EasyRefreshController(
+    controlFinishRefresh: true,
+    controlFinishLoad: true,
+  );
+
+  // Refresh 刷新事件
+  Future onRefresh() async {
+    _curPage = 1;
+    fetchLabourRequestList();
+  }
+
+  // Refresh 加载事件
+  Future loadMore() async {
+    _curPage++;
+    fetchLabourRequestList();
+  }
+
+  // 重试请求
+  Future retryRequest() async {
+    _curPage = 1;
+    _needShowPlaceholder = true;
+    fetchLabourRequestList();
+  }
+
+  /// 获取列表数据
+  Future fetchLabourRequestList() async {
+    if (_needShowPlaceholder) {
+      changeLoadingState(LoadState.State_Loading);
+    }
+
+    // 并发执行两个请求
+
+    var listResult = await _labourRepository.fetchLabourRequestSGList(
+      "",
+      "",
+      "",
+      "",
+      "",
+      curPage: _curPage,
+      cancelToken: cancelToken,
+    );
+
+    // 处理数据
+    if (listResult.isSuccess) {
+      handleList(listResult.data?.rows);
+    } else {
+      errorMessage = listResult.errorMsg;
+      changeLoadingState(LoadState.State_Error);
+    }
+
+    // 最后赋值
+    _needShowPlaceholder = false;
+  }
+
+  // 处理数据与展示的逻辑
+  void handleList(List<LabourRequestSGListRows>? 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();
+    fetchLabourRequestList();
+  }
+
+  @override
+  void onClose() {
+    state.datas.clear();
+    super.onClose();
+  }
+
+  //去详情页面
+  void gotoSettingPage() {
+    ContractRateSettingPage.startInstance("123", (result) {
+
+    });
+  }
+
+  //去设置特殊的日期
+  void gotoAddSpecificPage() {
+    SGContractRateSpecificPage.startInstance((result){
+
+    });
+  }
+
+  /// 展示这个日期的编辑弹窗
+  void showEditDialog(LabourRequestSGListRows data) {
+
+    DialogEngine.show(
+      widget: EditRateDialog(
+        rate:"10",
+        confirmAction: (rate) {
+         ToastEngine.show("输入的时薪为:$rate");
+        },
+      ),
+    );
+
+  }
+
+  /// 删除的确认弹窗
+  void showDeleteDialog(LabourRequestSGListRows data,int index) {
+    DialogEngine.show(
+        widget: AppDefaultDialog(
+          title: "Confirmation".tr,
+          message: "Are you sure you want to delete this Rate?".tr,
+          confirmAction: () {
+            _submitDeleteRequest(data.requestId.toString(),index);
+          },
+        ));
+  }
+
+  void _submitDeleteRequest(String? requestId, int index) async {
+    var result = await _labourRepository.deleteLabourRequestSG(requestId, cancelToken: cancelToken);
+
+    if (result.isSuccess) {
+      NotifyEngine.showSuccess("Successful".tr);
+
+      if (state.datas.length <= 1) {
+        refreshController.callRefresh();
+      } else {
+        state.datas.removeAt(index);
+        update();
+      }
+    } else {
+      ToastEngine.show(result.errorMsg ?? "Network Load Error".tr);
+    }
+  }
+
+}

+ 153 - 0
packages/cpt_sg/lib/modules/agency/contract_rate_edit_list/contract_rate_edit_list_page.dart

@@ -0,0 +1,153 @@
+import 'package:cs_resources/constants/color_constants.dart';
+import 'package:cs_resources/generated/assets.dart';
+import 'package:flutter/material.dart';
+import 'package:get/get.dart';
+import 'package:plugin_basic/base/base_state.dart';
+import 'package:plugin_basic/base/base_stateful_page.dart';
+import 'package: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/my_button.dart';
+import 'package:widgets/my_load_image.dart';
+import 'package:widgets/my_text_view.dart';
+import 'package:widgets/widget_export.dart';
+
+import 'contract_rate_edit_item.dart';
+import 'contract_rate_edit_list_controller.dart';
+import 'contract_rate_edit_list_state.dart';
+
+/*
+ * 新加坡的指定合同的时薪管理列表的详情
+ * 其实就是SGContractRateListPage的详情页面
+ */
+class SGContractRateEditListPage extends BaseStatefulPage<ContractRateEditListController> {
+  SGContractRateEditListPage({Key? key}) : super(key: key);
+
+  //启动当前页面
+  static void startInstance() {
+    return Get.start(RouterPath.SGContractRateDayEdit);
+  }
+
+  @override
+  ContractRateEditListController createRawController() {
+    return ContractRateEditListController();
+  }
+
+  @override
+  State<SGContractRateEditListPage> createState() => _LabourRequestListState();
+}
+
+class _LabourRequestListState extends BaseState<SGContractRateEditListPage, ContractRateEditListController> {
+  late ContractRateEditListState 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.titleBar(context, "Edit".tr),
+
+              // 添加按钮
+              Row(
+                children: [
+                  //设置
+                  MyButton(
+                    type: ClickType.throttle,
+                    milliseconds: 500,
+                    onPressed: () {
+                      FocusScope.of(context).unfocus();
+                      controller.gotoSettingPage();
+                    },
+                    text: "Setting".tr,
+                    textColor: ColorConstants.white,
+                    fontSize: 16,
+                    radius: 20,
+                    backgroundColor: hexToColor("#56AAFF"),
+                    fontWeight: FontWeight.w500,
+                  ).expanded(),
+
+                  const SizedBox(width: 15),
+
+                  //特殊日期
+                  MyButton(
+                    type: ClickType.throttle,
+                    milliseconds: 500,
+                    onPressed: () {
+                      FocusScope.of(context).unfocus();
+                      controller.gotoAddSpecificPage();
+                    },
+                    text: "Specific Day".tr,
+                    textColor: ColorConstants.white,
+                    fontSize: 16,
+                    radius: 20,
+                    backgroundColor: hexToColor("#0AC074"),
+                    fontWeight: FontWeight.w500,
+                  ).expanded(),
+                ],
+              ).marginSymmetric(horizontal: 15, vertical: 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 ContractRateEditItem(
+                          index: index,
+                          item: state.datas[index],
+                          onEditAction: () {
+                            controller.showEditDialog(state.datas[index]);
+                          },
+                          onDeleteAction: () {
+                            controller.showDeleteDialog(state.datas[index], index);
+                          },
+                        );
+                      },
+                      childCount: state.datas.length,
+                    ))
+                  ],
+                ),
+              ).expanded(),
+            ],
+          ),
+        ),
+      );
+    });
+  }
+}

+ 8 - 0
packages/cpt_sg/lib/modules/agency/contract_rate_edit_list/contract_rate_edit_list_state.dart

@@ -0,0 +1,8 @@
+import 'package:domain/entity/response/labour_request_s_g_list_entity.dart';
+
+class ContractRateEditListState {
+
+  //页面的列表数据
+  List<LabourRequestSGListRows> datas = [];
+
+}

+ 179 - 0
packages/cpt_sg/lib/modules/agency/contract_rate_edit_list/dialog/dialog_edit_rate.dart

@@ -0,0 +1,179 @@
+import 'dart:typed_data';
+import 'dart:ui';
+
+import 'package:cs_resources/generated/assets.dart';
+import 'package:domain/entity/response/job_applied_edit_index_s_g_entity.dart';
+import 'package:flutter/cupertino.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter/widgets.dart';
+import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
+import 'package:get/get.dart';
+import 'package:shared/utils/date_time_utils.dart';
+import 'package:shared/utils/util.dart';
+import 'package:widgets/ext/ex_widget.dart';
+import 'package:cs_resources/constants/color_constants.dart';
+import 'package:widgets/my_load_image.dart';
+import 'package:widgets/my_text_field.dart';
+import 'package:widgets/my_text_view.dart';
+import 'package:widgets/picker/date_picker_util.dart';
+import 'package:widgets/shatter/custom_radio_check.dart';
+import 'package:widgets/widget_export.dart';
+
+/*
+ * 修改对应日期的时薪弹窗
+ */
+class EditRateDialog extends StatefulWidget {
+  String? rate;
+  void Function(String? rate)? confirmAction;
+
+  EditRateDialog({this.rate, this.confirmAction});
+
+  @override
+  State<EditRateDialog> createState() => _DialogAppliedModifyState();
+}
+
+class _DialogAppliedModifyState extends State<EditRateDialog> {
+  String? rate;
+  late TextEditingController controller;
+  late FocusNode focusNode;
+
+  @override
+  void initState() {
+    super.initState();
+    rate = widget.rate;
+    controller = TextEditingController();
+    if (Utils.isNotEmpty(rate)) {
+      controller.text = rate!;
+    }
+    focusNode = FocusNode();
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return Padding(
+      padding: EdgeInsets.only(
+        bottom: MediaQuery.of(context).viewInsets.bottom,  //加上 Padding 与 MediaQuery的配置可以让 Dialog 弹出时,自动居中适配
+      ),
+      child: Container(
+        padding: const EdgeInsets.symmetric(horizontal: 16.5),
+        width: 285,
+        decoration: const BoxDecoration(
+          color: Colors.white,
+          borderRadius: BorderRadius.all(Radius.circular(15)),
+        ),
+        child: Column(
+          crossAxisAlignment: CrossAxisAlignment.start,
+          mainAxisSize: MainAxisSize.min,
+          children: [
+            Center(
+              // 标题
+              child: MyTextView(
+                "Hourly Rate".tr,
+                fontSize: 19,
+                isFontMedium: true,
+                textColor: ColorConstants.black,
+                marginTop: 22,
+                marginBottom: 20,
+              ),
+            ),
+
+            IgnoreKeyboardDismiss(
+              child: MyTextField(
+                "hourly_rate",
+                rate ?? "",
+                hintText: "Enter...".tr,
+                hintStyle: const TextStyle(
+                  color: ColorConstants.gray88,
+                  fontSize: 14,
+                  fontWeight: FontWeight.w400,
+                ),
+                controller: controller,
+                focusNode: focusNode,
+                margin: const EdgeInsets.only(left: 0, right: 0, top: 8),
+                showDivider: false,
+                fillBackgroundColor: ColorConstants.grayECECEC,
+                fillCornerRadius: 5,
+                padding: const EdgeInsets.only(left: 16, right: 16, top: 0, bottom: 0),
+                height: 40,
+                style: const TextStyle(
+                  color: ColorConstants.black33,
+                  fontSize: 14,
+                  fontWeight: FontWeight.w400,
+                ),
+                inputType: TextInputType.number,
+                textInputAction: TextInputAction.done,
+                enabled: true,
+                onSubmit: (key, value) {
+                  FocusScope.of(context).unfocus();
+                  //输入框需要手动赋值
+                  rate = controller.text;
+                  widget.confirmAction?.call(rate);
+                  onCancel();
+                },
+                cursorColor: ColorConstants.black33,
+                showLeftIcon: false,
+                showRightIcon: false,
+              ),
+            ),
+
+            //分割线
+            Container(
+              margin: const EdgeInsets.only(top: 25),
+              color: const Color(0XFFCECECE),
+              height: 0.5,
+            ),
+            Row(
+              children: [
+                Expanded(
+                    flex: 1,
+                    child: InkWell(
+                      onTap: () {
+                        onCancel();
+                      },
+                      child: MyTextView(
+                        "Cancel".tr,
+                        fontSize: 17.5,
+                        isFontMedium: true,
+                        textAlign: TextAlign.center,
+                        textColor: const Color(0XFF0085C4),
+                        cornerRadius: 3,
+                        borderWidth: 1,
+                      ),
+                    )),
+                Container(
+                  color: const Color(0xff09141F).withOpacity(0.13),
+                  width: 0.5,
+                ),
+                Expanded(
+                    flex: 1,
+                    child: InkWell(
+                      onTap: () async {
+                        FocusScope.of(context).unfocus();
+                        //输入框需要手动赋值
+                        rate = controller.text;
+                        widget.confirmAction?.call(rate);
+                        onCancel();
+                      },
+                      child: MyTextView(
+                        "Submit".tr,
+                        marginLeft: 10,
+                        fontSize: 17.5,
+                        isFontMedium: true,
+                        textAlign: TextAlign.center,
+                        textColor: const Color(0XFF0085C4),
+                        cornerRadius: 3,
+                      ),
+                    )),
+              ],
+            ).constrained(height: 46),
+          ],
+        ),
+      ),
+    );
+  }
+
+  //取消弹框
+  void onCancel() async {
+    SmartDialog.dismiss();
+  }
+}

+ 194 - 0
packages/cpt_sg/lib/modules/agency/contract_rate_list/contract_rate_item.dart

@@ -0,0 +1,194 @@
+import 'package:cs_resources/constants/color_constants.dart';
+import 'package:domain/entity/response/labour_request_s_g_list_entity.dart';
+import 'package:flutter/cupertino.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter/widgets.dart';
+import 'package:plugin_basic/basic_export.dart';
+import 'package:widgets/ext/ex_widget.dart';
+import 'package:widgets/my_button.dart';
+import 'package:widgets/my_text_view.dart';
+
+/*
+ * 列表Item
+ */
+class ContractRateItem extends StatelessWidget {
+  final int index;
+  final LabourRequestSGListRows item;
+  final VoidCallback? onEditAction;
+
+  ContractRateItem({
+    required this.index,
+    required this.item,
+    this.onEditAction,
+  });
+
+  @override
+  Widget build(BuildContext context) {
+    return Container(
+      padding: const EdgeInsets.symmetric(vertical: 23, horizontal: 21),
+      margin: const EdgeInsets.only(left: 15, right: 15, top: 5, bottom: 5),
+      decoration: BoxDecoration(
+        color: const Color(0xFF4DCFF6).withOpacity(0.2), // 设置背景颜色和不透明度
+        borderRadius: BorderRadius.circular(5), // 设置圆角
+      ),
+      child: Column(
+        mainAxisSize: MainAxisSize.max,
+        crossAxisAlignment: CrossAxisAlignment.start,
+        children: [
+
+          // 中介商名称
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "${"Agency Name".tr}:",
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+
+              //文本
+              MyTextView(
+                item.jobTitle ?? "-",
+                marginLeft: 5,
+                isFontMedium: true,
+                textColor: ColorConstants.textYellowFFBB1B,
+                fontSize: 14,
+                textDecoration: TextDecoration.underline,
+                decorationColor: ColorConstants.textYellowFFBB1B,
+                // 可选,设置下划线的颜色
+                decorationThickness: 2.0,
+                // 可选,设置下划线的粗细
+                decorationStyle: TextDecorationStyle.solid, // 可选,设置下划线的样式
+              ).expanded(),
+            ],
+          ),
+
+          // 职位
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "${"Position".tr}:",
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+
+              //文本
+              MyTextView(
+                item.outletName ?? "-",
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor: Colors.white,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ).marginOnly(top: 12),
+
+          // 时薪
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "${"Hourly Rate".tr}:",
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+
+              //文本
+              MyTextView(
+                item.needNum.toString(),
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor: Colors.white,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ).marginOnly(top: 12),
+
+          // 合同
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "${"Contract".tr}:",
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+
+              //文本
+              MyTextView(
+                item.createdAt.toString(),
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor: Colors.white,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ).marginOnly(top: 12),
+
+          // 创建时间
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "Created At:".tr,
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+
+              //文本
+              MyTextView(
+                item.createdAt.toString(),
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor: Colors.white,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ).marginOnly(top: 12),
+
+
+          //按钮组
+          Visibility(
+            visible: item.actionList.isNotEmpty,
+            child: Row(
+              mainAxisSize: MainAxisSize.max,
+              mainAxisAlignment: MainAxisAlignment.end,
+              crossAxisAlignment: CrossAxisAlignment.center,
+              children: [
+
+                //Edit按钮
+                Visibility(
+                  visible: item.actionList.contains("edit"),
+                  child: MyButton(
+                    onPressed: () {
+                      FocusScope.of(context).unfocus();
+                      onEditAction?.call();
+                    },
+                    text: "Edit".tr,
+                    textColor: ColorConstants.white,
+                    backgroundColor: ColorConstants.textGreen0AC074,
+                    radius: 17.25,
+                    minWidth: 60,
+                    minHeight: 35,
+                  ).marginOnly(left: 12),
+                ),
+
+              ],
+            ).marginOnly(top: 15, bottom: 2),
+          ),
+        ],
+      ),
+    );
+  }
+}

+ 138 - 0
packages/cpt_sg/lib/modules/agency/contract_rate_list/contract_rate_list_controller.dart

@@ -0,0 +1,138 @@
+import 'package:domain/entity/response/labour_request_s_g_list_entity.dart';
+import 'package:domain/repository/labour_sg_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 '../contract_rate_edit_list/contract_rate_edit_list_page.dart';
+import '../contract_rate_setting/contract_rate_setting_page.dart';
+import 'contract_rate_list_state.dart';
+
+class ContractRateListController extends GetxController with DioCancelableMixin {
+  final LabourSGRepository _labourRepository = Get.find();
+  final ContractRateListState state = ContractRateListState();
+
+  var _curPage = 1;
+  var _needShowPlaceholder = true;
+
+  //页面PlaceHolder的展示
+  LoadState loadingState = LoadState.State_Success;
+  String? errorMessage;
+
+  //刷新页面状态
+  void changeLoadingState(LoadState state) {
+    loadingState = state;
+    update();
+  }
+
+  // Refresh 控制器
+  final EasyRefreshController refreshController = EasyRefreshController(
+    controlFinishRefresh: true,
+    controlFinishLoad: true,
+  );
+
+  // Refresh 刷新事件
+  Future onRefresh() async {
+    _curPage = 1;
+    fetchLabourRequestList();
+  }
+
+  // Refresh 加载事件
+  Future loadMore() async {
+    _curPage++;
+    fetchLabourRequestList();
+  }
+
+  // 重试请求
+  Future retryRequest() async {
+    _curPage = 1;
+    _needShowPlaceholder = true;
+    fetchLabourRequestList();
+  }
+
+  /// 获取列表数据
+  Future fetchLabourRequestList() async {
+    if (_needShowPlaceholder) {
+      changeLoadingState(LoadState.State_Loading);
+    }
+
+    // 并发执行两个请求
+
+    var listResult = await _labourRepository.fetchLabourRequestSGList(
+      "",
+      "",
+      "",
+      "",
+      "",
+      curPage: _curPage,
+      cancelToken: cancelToken,
+    );
+
+    // 处理数据
+    if (listResult.isSuccess) {
+      handleList(listResult.data?.rows);
+    } else {
+      errorMessage = listResult.errorMsg;
+      changeLoadingState(LoadState.State_Error);
+    }
+
+    // 最后赋值
+    _needShowPlaceholder = false;
+  }
+
+  // 处理数据与展示的逻辑
+  void handleList(List<LabourRequestSGListRows>? 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();
+    fetchLabourRequestList();
+  }
+
+  @override
+  void onClose() {
+    state.datas.clear();
+    super.onClose();
+  }
+
+  //去详情页面
+  void gotoAddPage() {
+    ContractRateSettingPage.startInstance("", (result){
+
+    });
+  }
+
+  //去编辑页面
+  void gotoEditPage(LabourRequestSGListRows data) {
+    SGContractRateEditListPage.startInstance();
+  }
+}

+ 127 - 0
packages/cpt_sg/lib/modules/agency/contract_rate_list/contract_rate_list_page.dart

@@ -0,0 +1,127 @@
+import 'package:cs_resources/constants/color_constants.dart';
+import 'package:cs_resources/generated/assets.dart';
+import 'package:flutter/material.dart';
+import 'package:get/get.dart';
+import 'package:plugin_basic/base/base_state.dart';
+import 'package:plugin_basic/base/base_stateful_page.dart';
+import 'package: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/my_button.dart';
+import 'package:widgets/my_load_image.dart';
+import 'package:widgets/my_text_view.dart';
+import 'package:widgets/widget_export.dart';
+
+import 'contract_rate_item.dart';
+import 'contract_rate_list_controller.dart';
+import 'contract_rate_list_state.dart';
+
+/*
+ * 新加坡的指定合同的时薪管理列表
+ */
+class SGContractRateListPage extends BaseStatefulPage<ContractRateListController> {
+  SGContractRateListPage({Key? key}) : super(key: key);
+
+  //启动当前页面
+  static void startInstance() {
+    return Get.start(RouterPath.SGContractRateList);
+  }
+
+  @override
+  ContractRateListController createRawController() {
+    return ContractRateListController();
+  }
+
+  @override
+  State<SGContractRateListPage> createState() => _LabourRequestListState();
+}
+
+class _LabourRequestListState extends BaseState<SGContractRateListPage, ContractRateListController> {
+  late ContractRateListState 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.titleBar(context, "Contract Rate Management".tr),
+
+              // 添加按钮
+              MyButton(
+                type: ClickType.throttle,
+                milliseconds: 500,
+                onPressed: () {
+                  FocusScope.of(context).unfocus();
+                  controller.gotoAddPage();
+                },
+                text: "Add New".tr,
+                textColor: ColorConstants.white,
+                fontSize: 16,
+                radius: 20,
+                backgroundColor: hexToColor("#FFBB1B"),
+                fontWeight: FontWeight.w500,
+              ).marginSymmetric(horizontal: 15, vertical: 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 ContractRateItem(
+                          index: index,
+                          item: state.datas[index],
+                          onEditAction: () {
+                            controller.gotoEditPage(state.datas[index]);
+                          },
+
+                        );
+                      },
+                      childCount: state.datas.length,
+                    ))
+                  ],
+                ),
+              ).expanded(),
+            ],
+          ),
+        ),
+      );
+    });
+  }
+}

+ 8 - 0
packages/cpt_sg/lib/modules/agency/contract_rate_list/contract_rate_list_state.dart

@@ -0,0 +1,8 @@
+import 'package:domain/entity/response/labour_request_s_g_list_entity.dart';
+
+class ContractRateListState {
+
+  //页面的列表数据
+  List<LabourRequestSGListRows> datas = [];
+
+}

+ 161 - 0
packages/cpt_sg/lib/modules/agency/contract_rate_setting/contract_rate_setting_controller.dart

@@ -0,0 +1,161 @@
+import 'package:domain/repository/labour_sg_repository.dart';
+import 'package:flutter/cupertino.dart';
+import 'package:get/get.dart';
+import 'package:plugin_platform/engine/toast/toast_engine.dart';
+import 'package:plugin_platform/http/dio/dio_cancelable_mixin.dart';
+import 'package:shared/utils/util.dart';
+import 'package:widgets/picker/option_pick_util.dart';
+
+import 'contract_rate_setting_state.dart';
+
+class ContractRateSettingController extends GetxController with DioCancelableMixin {
+  final LabourSGRepository _labourRepository = Get.find();
+  final ContractRateSettingState state = ContractRateSettingState();
+
+  // 获取添加或者编辑的详情
+  void _fetchAddEditIndexDetail() async {
+    // //获取到数据
+    // Future<HttpResult<JobTemplateEditIndexEntity>> taskFuture;
+    // if (Utils.isNotEmpty(state.templateId) && state.templateId != "0") {
+    //   //编辑
+    //   taskFuture = _labourRepository.fetchJobTemplateEditIndex(state.templateId, cancelToken: cancelToken);
+    // } else {
+    //   //新增
+    //   taskFuture = _labourRepository.fetchJobTemplateAddIndex(cancelToken: cancelToken);
+    // }
+    //
+    // var result = await taskFuture;
+    //
+    // //处理数据
+    // if (result.isSuccess) {
+    //   state.indexEntity = result.data;
+    //
+    //   var templateNameController = state.formData['template_name']!['controller'];
+    //   var descController = state.formData['desc']!['controller'];
+    //   var contactController = state.formData['contact']!['controller'];
+    //   var contactNoController = state.formData['contact_no']!['controller'];
+    //   var noteController = state.formData['note']!['controller'];
+    //   templateNameController.text = state.indexEntity?.name ?? "";
+    //   descController.text = state.indexEntity?.description ?? "";
+    //   contactController.text = state.indexEntity?.contact ?? "";
+    //   contactNoController.text = state.indexEntity?.contactNo ?? "";
+    //   noteController.text = state.indexEntity?.note ?? "";
+    //
+    //   //默认赋值
+    //   state.selectedAgeList = state.indexEntity?.ageList.where((e) => e.checked == "checked").map((e) => e.value!).toList() ?? [];
+    //   Log.d("当前选中的年龄1:${ state.selectedAgeList}");
+    //   state.selectedLanguageList = state.indexEntity?.languageList.where((e) => e.checked == "checked").map((e) => e.value!).toList() ?? [];
+    //   Log.d("当前选中的语言1:${ state.selectedLanguageList}");
+    //   state.foodCert = state.indexEntity?.withFoodCert.toString();
+    //
+    //   update();
+    // } else {
+    //   ToastEngine.show(result.errorMsg ?? "Network Load Error".tr);
+    // }
+
+    TextEditingController agencyController = state.formData['agency_name']!['controller'];
+    agencyController.text = "Hong Ye Group";
+  }
+
+  /// 提交
+  void doSubmit() async {
+    var agencyNameController = state.formData['agency_name']!['controller'];
+    var acraController = state.formData['acra']!['controller'];
+    var personController = state.formData['person_in_charge']!['controller'];
+    var addressController = state.formData['address']!['controller'];
+    var emailController = state.formData['email']!['controller'];
+    var phoneController = state.formData['phone']!['controller'];
+
+    String agencyName = agencyNameController.text.toString();
+    String acra = acraController.text.toString();
+    String personName = personController.text.toString();
+    String address = addressController.text.toString();
+    String email = emailController.text.toString();
+    String phone = phoneController.text.toString();
+
+    // //校验必填项
+    // if (Utils.isEmpty(agencyName)) {
+    //   ToastEngine.show("Enter Agency Name".tr);
+    //   return;
+    // }
+    //
+    // if (Utils.isEmpty(acra)) {
+    //   ToastEngine.show("Enter ACRA NO".tr);
+    //   return;
+    // }
+
+    // Future<HttpResult> taskFuture;
+    // if (Utils.isNotEmpty(state.templateId) && state.templateId != "0") {
+    //   taskFuture = _labourRepository.editJobTemplateSubmit(
+    //     state.templateId,
+    //     templateName,
+    //     contact,
+    //     contactNo,
+    //     desc,
+    //     note,
+    //     state.selectedAgeList.join(","),
+    //     state.gender,
+    //     state.foodCert,
+    //     state.selectedLanguageList.join(","),
+    //     cancelToken: cancelToken,
+    //   );
+    // } else {
+    //   taskFuture = _labourRepository.addJobTemplateSubmit(
+    //     templateName,
+    //     contact,
+    //     contactNo,
+    //     desc,
+    //     note,
+    //     state.selectedAgeList.join(","),
+    //     state.gender,
+    //     state.foodCert,
+    //     state.selectedLanguageList.join(","),
+    //     cancelToken: cancelToken,
+    //   );
+    // }
+    //
+    // var result = await taskFuture;
+    //
+    // //处理数据
+    // if (result.isSuccess) {
+    //   NotifyEngine.showSuccess("Successful".tr);
+    //
+    //   //根据类型刷新
+    //   state.cb?.call(state.templateId);
+    //
+    //   Get.back();
+    // } else {
+    //   ToastEngine.show(result.errorMsg ?? "Network Load Error".tr);
+    // }
+  }
+
+  @override
+  void onReady() {
+    super.onReady();
+    _fetchAddEditIndexDetail();
+  }
+
+  // 选择职位
+  void pickPosition() {
+    // int selectedTemplateIndex;
+    // if (state.selectedJobTitleId == null) {
+    //   selectedTemplateIndex = 0;
+    // } else {
+    //   selectedTemplateIndex = state.indexEntity!.titleList.indexWhere((department) => department.value.toString() == state.selectedJobTitleId);
+    // }
+    //
+    // if (selectedTemplateIndex < 0) {
+    //   selectedTemplateIndex = 0;
+    // }
+
+    OptionPickerUtil.showCupertinoOptionPicker(
+      items: state.positionList,
+      initialSelectIndex: 0,
+      onPickerChanged: (_, index) {
+        state.selectedPosition = state.positionList[index];
+        state.selectedPositionId = index.toString();
+        update();
+      },
+    );
+  }
+}

+ 536 - 0
packages/cpt_sg/lib/modules/agency/contract_rate_setting/contract_rate_setting_page.dart

@@ -0,0 +1,536 @@
+import 'package:cs_resources/constants/color_constants.dart';
+import 'package:cs_resources/generated/assets.dart';
+import 'package:flutter/material.dart';
+import 'package:get/get.dart';
+import 'package:shared/utils/screen_util.dart';
+import 'package:shared/utils/util.dart';
+import 'package:widgets/ext/ex_widget.dart';
+import 'package:widgets/my_appbar.dart';
+import 'package:widgets/my_button.dart';
+import 'package:widgets/my_load_image.dart';
+import 'package:widgets/my_text_view.dart';
+import 'package:widgets/no_shadow_scroll_behavior.dart';
+import 'package:widgets/shatter/form_require_text.dart';
+import 'package:widgets/shatter/round_my_text_field.dart';
+
+import 'package:plugin_basic/base/base_stateless_page.dart';
+import 'package:plugin_basic/utils/ext_get_nav.dart';
+import 'package:router/path/router_path.dart';
+
+import 'contract_rate_setting_controller.dart';
+import 'contract_rate_setting_state.dart';
+
+/*
+ * 设置不同时间的时薪
+ * 设置与修改页面
+ */
+class ContractRateSettingPage extends BaseStatelessPage<ContractRateSettingController> {
+  ContractRateSettingPage({Key? key}) : super(key: key);
+
+  //启动当前页面
+  static void startInstance(
+    String agentId,
+    void Function(dynamic value)? cb,
+  ) {
+    return Get.start(RouterPath.SGContractRateSetting, arguments: {'agentId': agentId, 'cb': cb});
+  }
+
+  late ContractRateSettingState state;
+
+  @override
+  void initState() {
+    state = controller.state;
+    state.agentId = Get.arguments['agentId'];
+    state.cb = Get.arguments['cb'] as void Function(dynamic)?;
+  }
+
+  @override
+  ContractRateSettingController createRawController() {
+    return ContractRateSettingController();
+  }
+
+  @override
+  Widget buildWidget(BuildContext context) {
+    return autoCtlGetBuilder(builder: (controller) {
+      return Scaffold(
+        extendBodyBehindAppBar: true,
+        appBar: MyAppBar.appBar(context, Utils.isEmpty(state.agentId) ? "Add New".tr : "Edit".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: [
+                      MyTextView(
+                        "Agency".tr,
+                        textColor: Colors.white,
+                        fontSize: 14,
+                        isFontRegular: true,
+                        marginLeft: 15,
+                        marginTop: 10,
+                      ),
+
+                      CustomTextField(
+                        formKey: "agency_name",
+                        formData: state.formData,
+                        height: 45,
+                        enabled: false,
+                        fillBackgroundColor: const Color(0xFF4DCFF6).withOpacity(0.5),
+                        fontSize: 14,
+                        textInputType: TextInputType.number,
+                        onSubmit: (key, value) {
+                          state.formData[key]!['focusNode'].unfocus();
+                          FocusScope.of(context).requestFocus(state.formData['hourly_rate']!['focusNode']);
+                        },
+                        marginTop: 5,
+                      ),
+
+                      //必选 - 选择职位
+                      FormRequireText(text: "agency_position".tr).marginOnly(left: 15, top: 10),
+
+                      //下拉选
+                      Container(
+                        padding: const EdgeInsets.only(left: 16, right: 10),
+                        margin: const EdgeInsets.only(top: 5, left: 15, right: 15),
+                        height: 45,
+                        decoration: BoxDecoration(
+                          color: const Color(0xFF4DCFF6).withOpacity(0.2),
+                          borderRadius: const BorderRadius.all(Radius.circular(5)),
+                        ),
+                        child: Row(
+                          mainAxisSize: MainAxisSize.max,
+                          crossAxisAlignment: CrossAxisAlignment.center,
+                          mainAxisAlignment: MainAxisAlignment.start,
+                          children: [
+                            MyTextView(
+                              state.selectedPosition ?? "",
+                              fontSize: 14,
+                              hint: "Choose Position".tr,
+                              textHintColor: ColorConstants.textGrayAECAE5,
+                              isFontMedium: true,
+                              textColor: ColorConstants.white,
+                            ).expanded(),
+
+                            //下拉选图标
+                            const MyAssetImage(Assets.baseServiceTriangleDropDownIcon, width: 11.5, height: 6.28),
+                          ],
+                        ),
+                      ).onTap(() {
+                        FocusScope.of(context).unfocus();
+                        controller.pickPosition();
+                      }),
+
+                      //必填 - 默认时薪
+                      FormRequireText(text: "Hourly Rate".tr).marginOnly(left: 15, top: 10),
+
+                      CustomTextField(
+                        formKey: "hourly_rate",
+                        formData: state.formData,
+                        height: 45,
+                        fontSize: 14,
+                        textInputType: TextInputType.number,
+                        onSubmit: (key, value) {
+                          state.formData[key]!['focusNode'].unfocus();
+                          FocusScope.of(context).requestFocus(state.formData['weekdays']!['focusNode']);
+                        },
+                        marginTop: 5,
+                      ),
+
+                      // 工作日与周末
+                      Row(
+                        children: [
+                          Column(
+                            crossAxisAlignment: CrossAxisAlignment.start,
+                            children: [
+                              // 工作日
+                              MyTextView(
+                                "Weekdays".tr,
+                                textColor: Colors.white,
+                                fontSize: 14,
+                                isFontRegular: true,
+                                marginLeft: 15,
+                                marginTop: 10,
+                              ),
+
+                              // 输入框
+                              CustomTextField(
+                                formKey: "weekdays",
+                                formData: state.formData,
+                                height: 45,
+                                fontSize: 14,
+                                textInputType: TextInputType.number,
+                                onSubmit: (key, value) {
+                                  state.formData[key]!['focusNode'].unfocus();
+                                  FocusScope.of(context).requestFocus(state.formData['weekends']!['focusNode']);
+                                },
+                                marginTop: 5,
+                              ),
+                            ],
+                          ).expanded(),
+                          Column(
+                            crossAxisAlignment: CrossAxisAlignment.start,
+                            children: [
+                              // 周末
+                              MyTextView(
+                                "Weekends".tr,
+                                textColor: Colors.white,
+                                fontSize: 14,
+                                isFontRegular: true,
+                                marginLeft: 10,
+                                marginTop: 10,
+                              ),
+
+                              // 输入框
+                              CustomTextField(
+                                formKey: "weekends",
+                                formData: state.formData,
+                                height: 45,
+                                marginLeft: 10,
+                                fontSize: 14,
+                                textInputType: TextInputType.number,
+                                onSubmit: (key, value) {
+                                  state.formData[key]!['focusNode'].unfocus();
+                                  FocusScope.of(context).requestFocus(state.formData['monday']!['focusNode']);
+                                },
+                                marginTop: 5,
+                              ),
+                            ],
+                          ).expanded(),
+                        ],
+                      ),
+
+                      // 周一,周二
+                      Row(
+                        children: [
+                          Column(
+                            crossAxisAlignment: CrossAxisAlignment.start,
+                            children: [
+                              // 周一
+                              MyTextView(
+                                "Monday".tr,
+                                textColor: Colors.white,
+                                fontSize: 14,
+                                isFontRegular: true,
+                                marginLeft: 15,
+                                marginTop: 10,
+                              ),
+
+                              // 输入框
+                              CustomTextField(
+                                formKey: "monday",
+                                formData: state.formData,
+                                height: 45,
+                                fontSize: 14,
+                                textInputType: TextInputType.number,
+                                onSubmit: (key, value) {
+                                  state.formData[key]!['focusNode'].unfocus();
+                                  FocusScope.of(context).requestFocus(state.formData['tuesday']!['focusNode']);
+                                },
+                                marginTop: 5,
+                              ),
+                            ],
+                          ).expanded(),
+                          Column(
+                            crossAxisAlignment: CrossAxisAlignment.start,
+                            children: [
+                              // 周二
+                              MyTextView(
+                                "Tuesday".tr,
+                                textColor: Colors.white,
+                                fontSize: 14,
+                                isFontRegular: true,
+                                marginLeft: 10,
+                                marginTop: 10,
+                              ),
+
+                              // 输入框
+                              CustomTextField(
+                                formKey: "tuesday",
+                                formData: state.formData,
+                                marginLeft: 10,
+                                height: 45,
+                                fontSize: 14,
+                                textInputType: TextInputType.number,
+                                onSubmit: (key, value) {
+                                  state.formData[key]!['focusNode'].unfocus();
+                                  FocusScope.of(context).requestFocus(state.formData['wednesday']!['focusNode']);
+                                },
+                                marginTop: 5,
+                              ),
+                            ],
+                          ).expanded(),
+                        ],
+                      ),
+
+                      // 周三,周四
+                      Row(
+                        children: [
+                          Column(
+                            crossAxisAlignment: CrossAxisAlignment.start,
+                            children: [
+                              // 周三
+                              MyTextView(
+                                "Wednesday".tr,
+                                textColor: Colors.white,
+                                fontSize: 14,
+                                isFontRegular: true,
+                                marginLeft: 15,
+                                marginTop: 10,
+                              ),
+
+                              // 输入框
+                              CustomTextField(
+                                formKey: "wednesday",
+                                formData: state.formData,
+                                height: 45,
+                                fontSize: 14,
+                                textInputType: TextInputType.number,
+                                onSubmit: (key, value) {
+                                  state.formData[key]!['focusNode'].unfocus();
+                                  FocusScope.of(context).requestFocus(state.formData['thursday']!['focusNode']);
+                                },
+                                marginTop: 5,
+                              ),
+                            ],
+                          ).expanded(),
+                          Column(
+                            crossAxisAlignment: CrossAxisAlignment.start,
+                            children: [
+                              // 周四
+                              MyTextView(
+                                "Thursday".tr,
+                                textColor: Colors.white,
+                                fontSize: 14,
+                                isFontRegular: true,
+                                marginLeft: 10,
+                                marginTop: 10,
+                              ),
+
+                              // 输入框
+                              CustomTextField(
+                                formKey: "thursday",
+                                formData: state.formData,
+                                marginLeft: 10,
+                                height: 45,
+                                fontSize: 14,
+                                textInputType: TextInputType.number,
+                                onSubmit: (key, value) {
+                                  state.formData[key]!['focusNode'].unfocus();
+                                  FocusScope.of(context).requestFocus(state.formData['friday']!['focusNode']);
+                                },
+                                marginTop: 5,
+                              ),
+                            ],
+                          ).expanded(),
+                        ],
+                      ),
+
+                      //周五
+                      Row(
+                        children: [
+                          Column(
+                            crossAxisAlignment: CrossAxisAlignment.start,
+                            children: [
+                              // 周五
+                              MyTextView(
+                                "Friday".tr,
+                                textColor: Colors.white,
+                                fontSize: 14,
+                                isFontRegular: true,
+                                marginLeft: 15,
+                                marginTop: 10,
+                              ),
+
+                              // 输入框
+                              CustomTextField(
+                                formKey: "friday",
+                                formData: state.formData,
+                                height: 45,
+                                fontSize: 14,
+                                textInputType: TextInputType.number,
+                                onSubmit: (key, value) {
+                                  state.formData[key]!['focusNode'].unfocus();
+                                  FocusScope.of(context).requestFocus(state.formData['saturday']!['focusNode']);
+                                },
+                                marginTop: 5,
+                              ),
+                            ],
+                          ).expanded(),
+                          const SizedBox(height: 1).expanded(),
+                        ],
+                      ),
+
+                      //周六,周日
+                      Row(
+                        children: [
+                          Column(
+                            crossAxisAlignment: CrossAxisAlignment.start,
+                            children: [
+                              // 周六
+                              MyTextView(
+                                "Saturday".tr,
+                                textColor: Colors.white,
+                                fontSize: 14,
+                                isFontRegular: true,
+                                marginLeft: 15,
+                                marginTop: 10,
+                              ),
+
+                              // 输入框
+                              CustomTextField(
+                                formKey: "saturday",
+                                formData: state.formData,
+                                height: 45,
+                                fontSize: 14,
+                                textInputType: TextInputType.number,
+                                onSubmit: (key, value) {
+                                  state.formData[key]!['focusNode'].unfocus();
+                                  FocusScope.of(context).requestFocus(state.formData['sunday']!['focusNode']);
+                                },
+                                marginTop: 5,
+                              ),
+                            ],
+                          ).expanded(),
+                          Column(
+                            crossAxisAlignment: CrossAxisAlignment.start,
+                            children: [
+                              // 周日
+                              MyTextView(
+                                "Sunday".tr,
+                                textColor: Colors.white,
+                                fontSize: 14,
+                                isFontRegular: true,
+                                marginLeft: 10,
+                                marginTop: 10,
+                              ),
+
+                              // 输入框
+                              CustomTextField(
+                                formKey: "sunday",
+                                formData: state.formData,
+                                marginLeft: 10,
+                                height: 45,
+                                fontSize: 14,
+                                textInputType: TextInputType.number,
+                                onSubmit: (key, value) {
+                                  state.formData[key]!['focusNode'].unfocus();
+                                  FocusScope.of(context).requestFocus(state.formData['eve_of_ph_day']!['focusNode']);
+                                },
+                                marginTop: 5,
+                              ),
+                            ],
+                          ).expanded(),
+                        ],
+                      ),
+
+                      //法定节假日
+                      Row(
+                        children: [
+                          Column(
+                            crossAxisAlignment: CrossAxisAlignment.start,
+                            children: [
+                              // 前夕
+                              MyTextView(
+                                "Eve of PH day".tr,
+                                textColor: Colors.white,
+                                fontSize: 14,
+                                isFontRegular: true,
+                                marginLeft: 15,
+                                marginTop: 10,
+                              ),
+
+                              // 输入框
+                              CustomTextField(
+                                formKey: "eve_of_ph_day",
+                                formData: state.formData,
+                                height: 45,
+                                fontSize: 14,
+                                textInputType: TextInputType.number,
+                                onSubmit: (key, value) {
+                                  state.formData[key]!['focusNode'].unfocus();
+                                  FocusScope.of(context).requestFocus(state.formData['ph_days']!['focusNode']);
+                                },
+                                marginTop: 5,
+                              ),
+                            ],
+                          ).expanded(),
+                          Column(
+                            crossAxisAlignment: CrossAxisAlignment.start,
+                            children: [
+                              // 假日
+                              MyTextView(
+                                "PH Days".tr,
+                                textColor: Colors.white,
+                                fontSize: 14,
+                                isFontRegular: true,
+                                marginLeft: 10,
+                                marginTop: 10,
+                              ),
+
+                              // 输入框
+                              CustomTextField(
+                                formKey: "ph_days",
+                                formData: state.formData,
+                                marginLeft: 10,
+                                height: 45,
+                                textInputAction: TextInputAction.done,
+                                fontSize: 14,
+                                textInputType: TextInputType.number,
+                                onSubmit: (key, value) {
+                                  FocusScope.of(context).unfocus();
+                                  controller.doSubmit();
+                                },
+                                marginTop: 5,
+                              ),
+                            ],
+                          ).expanded(),
+                        ],
+                      ),
+
+                      //提交按钮
+                      MyButton(
+                        type: ClickType.throttle,
+                        milliseconds: 500,
+                        onPressed: () {
+                          FocusScope.of(context).unfocus();
+                          controller.doSubmit();
+                        },
+                        text: "Submit".tr,
+                        textColor: ColorConstants.white,
+                        fontSize: 16,
+                        radius: 20,
+                        backgroundColor: ColorConstants.textYellowFFBB1B,
+                        fontWeight: FontWeight.w500,
+                      ).marginSymmetric(vertical: 25, horizontal: 15),
+                    ],
+                  ),
+                ),
+              ),
+            ),
+          ),
+        ),
+      );
+    });
+  }
+}

+ 109 - 0
packages/cpt_sg/lib/modules/agency/contract_rate_setting/contract_rate_setting_state.dart

@@ -0,0 +1,109 @@
+import 'package:domain/entity/response/job_template_edit_index_entity.dart';
+import 'package:flutter/material.dart';
+import 'package:plugin_basic/basic_export.dart';
+
+class ContractRateSettingState {
+  //表单的校验与数据
+  Map<String, Map<String, dynamic>> formData = {
+    'agency_name': {
+      'value': '',
+      'controller': TextEditingController(),
+      'focusNode': FocusNode(),
+      'hintText': 'Enter...'.tr,
+      'obsecure': false,
+    },
+    'hourly_rate': {
+      'value': '',
+      'controller': TextEditingController(),
+      'focusNode': FocusNode(),
+      'hintText': 'Enter...'.tr,
+      'obsecure': false,
+    },
+    'weekdays': {
+      'value': '',
+      'controller': TextEditingController(),
+      'focusNode': FocusNode(),
+      'hintText': 'Enter...'.tr,
+      'obsecure': false,
+    },
+    'weekends': {
+      'value': '',
+      'controller': TextEditingController(),
+      'focusNode': FocusNode(),
+      'hintText': 'Enter...'.tr,
+      'obsecure': false,
+    },
+    'monday': {
+      'value': '',
+      'controller': TextEditingController(),
+      'focusNode': FocusNode(),
+      'hintText': 'Enter...'.tr,
+      'obsecure': false,
+    },
+    'tuesday': {
+      'value': '',
+      'controller': TextEditingController(),
+      'focusNode': FocusNode(),
+      'hintText': 'Enter...'.tr,
+      'obsecure': false,
+    },
+    'wednesday': {
+      'value': '',
+      'controller': TextEditingController(),
+      'focusNode': FocusNode(),
+      'hintText': 'Enter...'.tr,
+      'obsecure': false,
+    },
+    'thursday': {
+      'value': '',
+      'controller': TextEditingController(),
+      'focusNode': FocusNode(),
+      'hintText': 'Enter...'.tr,
+      'obsecure': false,
+    },
+    'friday': {
+      'value': '',
+      'controller': TextEditingController(),
+      'focusNode': FocusNode(),
+      'hintText': 'Enter...'.tr,
+      'obsecure': false,
+    },
+    'saturday': {
+      'value': '',
+      'controller': TextEditingController(),
+      'focusNode': FocusNode(),
+      'hintText': 'Enter...'.tr,
+      'obsecure': false,
+    },
+    'sunday': {
+      'value': '',
+      'controller': TextEditingController(),
+      'focusNode': FocusNode(),
+      'hintText': 'Enter...'.tr,
+      'obsecure': false,
+    },
+    'eve_of_ph_day': {
+      'value': '',
+      'controller': TextEditingController(),
+      'focusNode': FocusNode(),
+      'hintText': 'Enter...'.tr,
+      'obsecure': false,
+    },
+    'ph_days': {
+      'value': '',
+      'controller': TextEditingController(),
+      'focusNode': FocusNode(),
+      'hintText': 'Enter...'.tr,
+      'obsecure': false,
+    },
+  };
+
+  List<String> positionList = ["瓜豆1", "瓜豆2", "瓜豆3"];
+  String? selectedPosition;
+  String? selectedPositionId;
+
+  String? agentId;
+
+  void Function(dynamic value)? cb;
+
+}

+ 152 - 0
packages/cpt_sg/lib/modules/agency/contract_rate_specific_day/contract_rate_specific_controller.dart

@@ -0,0 +1,152 @@
+import 'package:domain/repository/labour_sg_repository.dart';
+import 'package:flutter/cupertino.dart';
+import 'package:get/get.dart';
+import 'package:plugin_platform/engine/toast/toast_engine.dart';
+import 'package:plugin_platform/http/dio/dio_cancelable_mixin.dart';
+import 'package:shared/utils/util.dart';
+import 'package:widgets/picker/date_picker_util.dart';
+import 'package:widgets/picker/option_pick_util.dart';
+
+import 'contract_rate_specific_state.dart';
+
+class ContractRateSpecificController extends GetxController with DioCancelableMixin {
+  final LabourSGRepository _labourRepository = Get.find();
+  final ContractRateSpecificState state = ContractRateSpecificState();
+
+  // 获取添加或者编辑的详情
+  void _fetchAddEditIndexDetail() async {
+    // //获取到数据
+    // Future<HttpResult<JobTemplateEditIndexEntity>> taskFuture;
+    // if (Utils.isNotEmpty(state.templateId) && state.templateId != "0") {
+    //   //编辑
+    //   taskFuture = _labourRepository.fetchJobTemplateEditIndex(state.templateId, cancelToken: cancelToken);
+    // } else {
+    //   //新增
+    //   taskFuture = _labourRepository.fetchJobTemplateAddIndex(cancelToken: cancelToken);
+    // }
+    //
+    // var result = await taskFuture;
+    //
+    // //处理数据
+    // if (result.isSuccess) {
+    //   state.indexEntity = result.data;
+    //
+    //   var templateNameController = state.formData['template_name']!['controller'];
+    //   var descController = state.formData['desc']!['controller'];
+    //   var contactController = state.formData['contact']!['controller'];
+    //   var contactNoController = state.formData['contact_no']!['controller'];
+    //   var noteController = state.formData['note']!['controller'];
+    //   templateNameController.text = state.indexEntity?.name ?? "";
+    //   descController.text = state.indexEntity?.description ?? "";
+    //   contactController.text = state.indexEntity?.contact ?? "";
+    //   contactNoController.text = state.indexEntity?.contactNo ?? "";
+    //   noteController.text = state.indexEntity?.note ?? "";
+    //
+    //   //默认赋值
+    //   state.selectedAgeList = state.indexEntity?.ageList.where((e) => e.checked == "checked").map((e) => e.value!).toList() ?? [];
+    //   Log.d("当前选中的年龄1:${ state.selectedAgeList}");
+    //   state.selectedLanguageList = state.indexEntity?.languageList.where((e) => e.checked == "checked").map((e) => e.value!).toList() ?? [];
+    //   Log.d("当前选中的语言1:${ state.selectedLanguageList}");
+    //   state.foodCert = state.indexEntity?.withFoodCert.toString();
+    //
+    //   update();
+    // } else {
+    //   ToastEngine.show(result.errorMsg ?? "Network Load Error".tr);
+    // }
+
+    TextEditingController agencyController = state.formData['agency_name']!['controller'];
+    TextEditingController positionController = state.formData['position']!['controller'];
+    agencyController.text = "Hong Ye Group";
+    positionController.text = "Clean";
+  }
+
+  /// 提交
+  void doSubmit() async {
+    var agencyNameController = state.formData['agency_name']!['controller'];
+    var acraController = state.formData['acra']!['controller'];
+    var personController = state.formData['person_in_charge']!['controller'];
+    var addressController = state.formData['address']!['controller'];
+    var emailController = state.formData['email']!['controller'];
+    var phoneController = state.formData['phone']!['controller'];
+
+    String agencyName = agencyNameController.text.toString();
+    String acra = acraController.text.toString();
+    String personName = personController.text.toString();
+    String address = addressController.text.toString();
+    String email = emailController.text.toString();
+    String phone = phoneController.text.toString();
+
+    // //校验必填项
+    // if (Utils.isEmpty(agencyName)) {
+    //   ToastEngine.show("Enter Agency Name".tr);
+    //   return;
+    // }
+    //
+    // if (Utils.isEmpty(acra)) {
+    //   ToastEngine.show("Enter ACRA NO".tr);
+    //   return;
+    // }
+
+    // Future<HttpResult> taskFuture;
+    // if (Utils.isNotEmpty(state.templateId) && state.templateId != "0") {
+    //   taskFuture = _labourRepository.editJobTemplateSubmit(
+    //     state.templateId,
+    //     templateName,
+    //     contact,
+    //     contactNo,
+    //     desc,
+    //     note,
+    //     state.selectedAgeList.join(","),
+    //     state.gender,
+    //     state.foodCert,
+    //     state.selectedLanguageList.join(","),
+    //     cancelToken: cancelToken,
+    //   );
+    // } else {
+    //   taskFuture = _labourRepository.addJobTemplateSubmit(
+    //     templateName,
+    //     contact,
+    //     contactNo,
+    //     desc,
+    //     note,
+    //     state.selectedAgeList.join(","),
+    //     state.gender,
+    //     state.foodCert,
+    //     state.selectedLanguageList.join(","),
+    //     cancelToken: cancelToken,
+    //   );
+    // }
+    //
+    // var result = await taskFuture;
+    //
+    // //处理数据
+    // if (result.isSuccess) {
+    //   NotifyEngine.showSuccess("Successful".tr);
+    //
+    //   //根据类型刷新
+    //   state.cb?.call(state.templateId);
+    //
+    //   Get.back();
+    // } else {
+    //   ToastEngine.show(result.errorMsg ?? "Network Load Error".tr);
+    // }
+  }
+
+  @override
+  void onReady() {
+    super.onReady();
+    _fetchAddEditIndexDetail();
+  }
+
+  /// 选择具体的日期
+  void pickDate() {
+    DatePickerUtil.showCupertinoDatePicker(
+      selectedDateTime: state.selectedDate ?? DateTime.now(),
+      onDateTimeChanged: (date) {
+        state.selectedDate = date;
+        update();
+      },
+      title: "Select Date".tr,
+    );
+  }
+}

+ 208 - 0
packages/cpt_sg/lib/modules/agency/contract_rate_specific_day/contract_rate_specific_page.dart

@@ -0,0 +1,208 @@
+import 'package:cs_resources/constants/color_constants.dart';
+import 'package:cs_resources/generated/assets.dart';
+import 'package:flutter/material.dart';
+import 'package:get/get.dart';
+import 'package:shared/utils/date_time_utils.dart';
+import 'package:shared/utils/screen_util.dart';
+import 'package:shared/utils/util.dart';
+import 'package:widgets/ext/ex_widget.dart';
+import 'package:widgets/my_appbar.dart';
+import 'package:widgets/my_button.dart';
+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/form_require_text.dart';
+import 'package:widgets/shatter/round_my_text_field.dart';
+
+import 'package:plugin_basic/base/base_stateless_page.dart';
+import 'package:plugin_basic/utils/ext_get_nav.dart';
+import 'package:router/path/router_path.dart';
+
+import 'contract_rate_specific_controller.dart';
+import 'contract_rate_specific_state.dart';
+
+/*
+ * 设置指定日期的时薪
+ */
+class SGContractRateSpecificPage extends BaseStatelessPage<ContractRateSpecificController> {
+  SGContractRateSpecificPage({Key? key}) : super(key: key);
+
+  //启动当前页面
+  static void startInstance(
+    void Function(dynamic value)? cb,
+  ) {
+    return Get.start(RouterPath.SGContractRateSpecificDay, arguments: {'cb': cb});
+  }
+
+  late ContractRateSpecificState state;
+
+  @override
+  void initState() {
+    state = controller.state;
+    state.cb = Get.arguments['cb'] as void Function(dynamic)?;
+  }
+
+  @override
+  ContractRateSpecificController createRawController() {
+    return ContractRateSpecificController();
+  }
+
+  @override
+  Widget buildWidget(BuildContext context) {
+    return autoCtlGetBuilder(builder: (controller) {
+      return Scaffold(
+        extendBodyBehindAppBar: true,
+        appBar: MyAppBar.appBar(context, "Specific Day".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: [
+                      MyTextView(
+                        "Agency".tr,
+                        textColor: Colors.white,
+                        fontSize: 14,
+                        isFontRegular: true,
+                        marginLeft: 15,
+                        marginTop: 10,
+                      ),
+
+                      CustomTextField(
+                        formKey: "agency_name",
+                        formData: state.formData,
+                        height: 45,
+                        enabled: false,
+                        fillBackgroundColor: const Color(0xFF4DCFF6).withOpacity(0.5),
+                        fontSize: 14,
+                        textInputType: TextInputType.number,
+                        onSubmit: (key, value) {
+                          state.formData[key]!['focusNode'].unfocus();
+                          FocusScope.of(context).requestFocus(state.formData['position']!['focusNode']);
+                        },
+                        marginTop: 5,
+                      ),
+
+                      //职位
+                      MyTextView(
+                        "Position".tr,
+                        textColor: Colors.white,
+                        fontSize: 14,
+                        isFontRegular: true,
+                        marginLeft: 15,
+                        marginTop: 10,
+                      ),
+
+                      CustomTextField(
+                        formKey: "position",
+                        formData: state.formData,
+                        height: 45,
+                        enabled: false,
+                        fillBackgroundColor: const Color(0xFF4DCFF6).withOpacity(0.5),
+                        fontSize: 14,
+                        textInputType: TextInputType.number,
+                        onSubmit: (key, value) {
+                          state.formData[key]!['focusNode'].unfocus();
+                          FocusScope.of(context).requestFocus(state.formData['date']!['focusNode']);
+                        },
+                        marginTop: 5,
+                      ),
+
+                      //必选 - 选择职位
+                      FormRequireText(text: "Date".tr).marginOnly(left: 15, top: 10),
+
+                      //下拉选
+                      Container(
+                        padding: const EdgeInsets.only(left: 16, right: 10),
+                        margin: const EdgeInsets.only(top: 5, left: 15, right: 15),
+                        height: 45,
+                        decoration: BoxDecoration(
+                          color: const Color(0xFF4DCFF6).withOpacity(0.2),
+                          borderRadius: const BorderRadius.all(Radius.circular(5)),
+                        ),
+                        child: Row(
+                          mainAxisSize: MainAxisSize.max,
+                          crossAxisAlignment: CrossAxisAlignment.center,
+                          mainAxisAlignment: MainAxisAlignment.start,
+                          children: [
+                            MyTextView(
+                              state.selectedDate == null ? "" : DateTimeUtils.formatDate(state.selectedDate!, format: "yyyy-MM-dd"),
+                              fontSize: 14,
+                              hint: "Select Date".tr,
+                              textHintColor: ColorConstants.textGrayAECAE5,
+                              isFontMedium: true,
+                              textColor: ColorConstants.white,
+                            ).expanded(),
+
+                            //下拉选图标
+                            const MyAssetImage(Assets.baseServiceTriangleDropDownIcon, width: 11.5, height: 6.28),
+                          ],
+                        ),
+                      ).onTap(() {
+                        FocusScope.of(context).unfocus();
+                        controller.pickDate();
+                      }),
+
+                      //必填 - 默认时薪
+                      FormRequireText(text: "Hourly Rate".tr).marginOnly(left: 15, top: 10),
+
+                      CustomTextField(
+                        formKey: "hourly_rate",
+                        formData: state.formData,
+                        height: 45,
+                        fontSize: 14,
+                        textInputType: TextInputType.number,
+                        onSubmit: (key, value) {
+                          state.formData[key]!['focusNode'].unfocus();
+                          FocusScope.of(context).requestFocus(state.formData['weekdays']!['focusNode']);
+                        },
+                        marginTop: 5,
+                      ),
+
+                      //提交按钮
+                      MyButton(
+                        type: ClickType.throttle,
+                        milliseconds: 500,
+                        onPressed: () {
+                          FocusScope.of(context).unfocus();
+                          controller.doSubmit();
+                        },
+                        text: "Submit".tr,
+                        textColor: ColorConstants.white,
+                        fontSize: 16,
+                        radius: 20,
+                        backgroundColor: ColorConstants.textYellowFFBB1B,
+                        fontWeight: FontWeight.w500,
+                      ).marginSymmetric(vertical: 25, horizontal: 15),
+                    ],
+                  ),
+                ),
+              ),
+            ),
+          ),
+        ),
+      );
+    });
+  }
+}

+ 35 - 0
packages/cpt_sg/lib/modules/agency/contract_rate_specific_day/contract_rate_specific_state.dart

@@ -0,0 +1,35 @@
+import 'package:domain/entity/response/job_template_edit_index_entity.dart';
+import 'package:flutter/material.dart';
+import 'package:plugin_basic/basic_export.dart';
+
+class ContractRateSpecificState {
+  //表单的校验与数据
+  Map<String, Map<String, dynamic>> formData = {
+    'agency_name': {
+      'value': '',
+      'controller': TextEditingController(),
+      'focusNode': FocusNode(),
+      'hintText': 'Enter...'.tr,
+      'obsecure': false,
+    },
+    'position': {
+      'value': '',
+      'controller': TextEditingController(),
+      'focusNode': FocusNode(),
+      'hintText': 'Enter...'.tr,
+      'obsecure': false,
+    },
+    'hourly_rate': {
+      'value': '',
+      'controller': TextEditingController(),
+      'focusNode': FocusNode(),
+      'hintText': 'Enter...'.tr,
+      'obsecure': false,
+    },
+  };
+
+  DateTime? selectedDate;
+
+  void Function(dynamic value)? cb;
+
+}

+ 134 - 0
packages/cpt_sg/lib/modules/agency/position_add/position_add_controller.dart

@@ -0,0 +1,134 @@
+import 'package:domain/repository/labour_sg_repository.dart';
+import 'package:get/get.dart';
+import 'package:plugin_platform/engine/toast/toast_engine.dart';
+import 'package:plugin_platform/http/dio/dio_cancelable_mixin.dart';
+import 'package:shared/utils/util.dart';
+
+import 'position_add_state.dart';
+
+class PositionAddController extends GetxController with DioCancelableMixin {
+  final LabourSGRepository _labourRepository = Get.find();
+  final PositionAddState state = PositionAddState();
+
+  // 获取添加或者编辑的详情
+  void _fetchAddEditIndexDetail() async {
+    // //获取到数据
+    // Future<HttpResult<JobTemplateEditIndexEntity>> taskFuture;
+    // if (Utils.isNotEmpty(state.templateId) && state.templateId != "0") {
+    //   //编辑
+    //   taskFuture = _labourRepository.fetchJobTemplateEditIndex(state.templateId, cancelToken: cancelToken);
+    // } else {
+    //   //新增
+    //   taskFuture = _labourRepository.fetchJobTemplateAddIndex(cancelToken: cancelToken);
+    // }
+    //
+    // var result = await taskFuture;
+    //
+    // //处理数据
+    // if (result.isSuccess) {
+    //   state.indexEntity = result.data;
+    //
+    //   var templateNameController = state.formData['template_name']!['controller'];
+    //   var descController = state.formData['desc']!['controller'];
+    //   var contactController = state.formData['contact']!['controller'];
+    //   var contactNoController = state.formData['contact_no']!['controller'];
+    //   var noteController = state.formData['note']!['controller'];
+    //   templateNameController.text = state.indexEntity?.name ?? "";
+    //   descController.text = state.indexEntity?.description ?? "";
+    //   contactController.text = state.indexEntity?.contact ?? "";
+    //   contactNoController.text = state.indexEntity?.contactNo ?? "";
+    //   noteController.text = state.indexEntity?.note ?? "";
+    //
+    //   //默认赋值
+    //   state.selectedAgeList = state.indexEntity?.ageList.where((e) => e.checked == "checked").map((e) => e.value!).toList() ?? [];
+    //   Log.d("当前选中的年龄1:${ state.selectedAgeList}");
+    //   state.selectedLanguageList = state.indexEntity?.languageList.where((e) => e.checked == "checked").map((e) => e.value!).toList() ?? [];
+    //   Log.d("当前选中的语言1:${ state.selectedLanguageList}");
+    //   state.foodCert = state.indexEntity?.withFoodCert.toString();
+    //
+    //   update();
+    // } else {
+    //   ToastEngine.show(result.errorMsg ?? "Network Load Error".tr);
+    // }
+  }
+
+  /// 提交
+  void doSubmit() async {
+
+
+    var agencyNameController = state.formData['agency_name']!['controller'];
+    var acraController = state.formData['acra']!['controller'];
+    var personController = state.formData['person_in_charge']!['controller'];
+    var addressController = state.formData['address']!['controller'];
+    var emailController = state.formData['email']!['controller'];
+    var phoneController = state.formData['phone']!['controller'];
+
+    String agencyName = agencyNameController.text.toString();
+    String acra = acraController.text.toString();
+    String personName = personController.text.toString();
+    String address = addressController.text.toString();
+    String email = emailController.text.toString();
+    String phone = phoneController.text.toString();
+
+    //校验必填项
+    if (Utils.isEmpty(agencyName)) {
+      ToastEngine.show("Enter Agency Name".tr);
+      return;
+    }
+
+    if (Utils.isEmpty(acra)) {
+      ToastEngine.show("Enter ACRA NO".tr);
+      return;
+    }
+
+    // Future<HttpResult> taskFuture;
+    // if (Utils.isNotEmpty(state.templateId) && state.templateId != "0") {
+    //   taskFuture = _labourRepository.editJobTemplateSubmit(
+    //     state.templateId,
+    //     templateName,
+    //     contact,
+    //     contactNo,
+    //     desc,
+    //     note,
+    //     state.selectedAgeList.join(","),
+    //     state.gender,
+    //     state.foodCert,
+    //     state.selectedLanguageList.join(","),
+    //     cancelToken: cancelToken,
+    //   );
+    // } else {
+    //   taskFuture = _labourRepository.addJobTemplateSubmit(
+    //     templateName,
+    //     contact,
+    //     contactNo,
+    //     desc,
+    //     note,
+    //     state.selectedAgeList.join(","),
+    //     state.gender,
+    //     state.foodCert,
+    //     state.selectedLanguageList.join(","),
+    //     cancelToken: cancelToken,
+    //   );
+    // }
+    //
+    // var result = await taskFuture;
+    //
+    // //处理数据
+    // if (result.isSuccess) {
+    //   NotifyEngine.showSuccess("Successful".tr);
+    //
+    //   //根据类型刷新
+    //   state.cb?.call(state.templateId);
+    //
+    //   Get.back();
+    // } else {
+    //   ToastEngine.show(result.errorMsg ?? "Network Load Error".tr);
+    // }
+  }
+
+  @override
+  void onReady() {
+    super.onReady();
+    _fetchAddEditIndexDetail();
+  }
+}

+ 125 - 0
packages/cpt_sg/lib/modules/agency/position_add/position_add_page.dart

@@ -0,0 +1,125 @@
+import 'package:cpt_sg/modules/agency/position_add/position_add_controller.dart';
+import 'package:cpt_sg/modules/agency/position_add/position_add_state.dart';
+import 'package:cs_resources/constants/color_constants.dart';
+import 'package:flutter/material.dart';
+import 'package:get/get.dart';
+import 'package:shared/utils/screen_util.dart';
+import 'package:shared/utils/util.dart';
+import 'package:widgets/ext/ex_widget.dart';
+import 'package:widgets/my_appbar.dart';
+import 'package:widgets/my_button.dart';
+import 'package:widgets/my_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 'package:plugin_basic/base/base_stateless_page.dart';
+import 'package:plugin_basic/utils/ext_get_nav.dart';
+import 'package:router/path/router_path.dart';
+
+
+/*
+ * 中介的添加与编辑
+ */
+class SGPositionAddPage extends BaseStatelessPage<PositionAddController> {
+  SGPositionAddPage({Key? key}) : super(key: key);
+
+  //启动当前页面
+  static void startInstance(
+    String? positionId,
+    void Function(dynamic value)? cb,
+  ) {
+    return Get.start(RouterPath.SGPositionAdd, arguments: {'positionId': positionId, 'cb': cb});
+  }
+
+  late PositionAddState state;
+
+  @override
+  void initState() {
+    state = controller.state;
+    state.positionId = Get.arguments['positionId'];
+    state.cb = Get.arguments['cb'] as void Function(dynamic)?;
+  }
+
+  @override
+  PositionAddController createRawController() {
+    return PositionAddController();
+  }
+
+  @override
+  Widget buildWidget(BuildContext context) {
+    return autoCtlGetBuilder(builder: (controller) {
+      return Scaffold(
+        extendBodyBehindAppBar: true,
+        appBar: MyAppBar.appBar(context, Utils.isEmpty(state.positionId) ? "Add Position".tr : "Edit Position".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: "agency_position".tr).marginOnly(left: 15, top: 19),
+
+                      CustomTextField(
+                        formKey: "position",
+                        formData: state.formData,
+                        height: 46,
+                        fontSize: 14,
+                        textInputAction: TextInputAction.done,
+                        onSubmit: (key, value) {
+                          FocusScope.of(context).unfocus();
+                          controller.doSubmit();
+                        },
+                        marginTop: 10,
+                      ),
+
+
+                      //提交按钮
+                      MyButton(
+                        type: ClickType.throttle,
+                        milliseconds: 500,
+                        onPressed: () {
+                          FocusScope.of(context).unfocus();
+                          controller.doSubmit();
+                        },
+                        text: "Submit".tr,
+                        textColor: ColorConstants.white,
+                        fontSize: 16,
+                        radius: 20,
+                        backgroundColor: ColorConstants.textYellowFFBB1B,
+                        fontWeight: FontWeight.w500,
+                      ).marginSymmetric(vertical: 25, horizontal: 15),
+                    ],
+                  ),
+                ),
+              ),
+            ),
+          ),
+        ),
+      );
+    });
+  }
+}

+ 21 - 0
packages/cpt_sg/lib/modules/agency/position_add/position_add_state.dart

@@ -0,0 +1,21 @@
+import 'package:domain/entity/response/job_template_edit_index_entity.dart';
+import 'package:flutter/material.dart';
+import 'package:plugin_basic/basic_export.dart';
+
+class PositionAddState {
+  //表单的校验与数据
+  Map<String, Map<String, dynamic>> formData = {
+    'position': {
+      'value': '',
+      'controller': TextEditingController(),
+      'focusNode': FocusNode(),
+      'hintText': 'Enter...'.tr,
+      'obsecure': false,
+    },
+
+  };
+
+  String? positionId;
+  void Function(dynamic value)? cb;
+
+}

+ 169 - 0
packages/cpt_sg/lib/modules/agency/position_list/position_item.dart

@@ -0,0 +1,169 @@
+import 'package:cs_resources/constants/color_constants.dart';
+import 'package:domain/entity/response/labour_request_list_entity.dart';
+import 'package:domain/entity/response/labour_request_s_g_list_entity.dart';
+import 'package:flutter/cupertino.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter/widgets.dart';
+import 'package:plugin_basic/basic_export.dart';
+import 'package:widgets/ext/ex_widget.dart';
+import 'package:widgets/my_button.dart';
+import 'package:widgets/my_text_view.dart';
+
+/*
+ * 列表Item
+ */
+class PositionItem extends StatelessWidget {
+  final int index;
+  final LabourRequestSGListRows item;
+  final VoidCallback? onDeleteAction;
+  final VoidCallback? onEditAction;
+
+  PositionItem({
+    required this.index,
+    required this.item,
+    this.onDeleteAction,
+    this.onEditAction,
+  });
+
+  @override
+  Widget build(BuildContext context) {
+    return Container(
+      padding: const EdgeInsets.symmetric(vertical: 23, horizontal: 21),
+      margin: const EdgeInsets.only(left: 15, right: 15, top: 5, bottom: 5),
+      decoration: BoxDecoration(
+        color: const Color(0xFF4DCFF6).withOpacity(0.2), // 设置背景颜色和不透明度
+        borderRadius: BorderRadius.circular(5), // 设置圆角
+      ),
+      child: Column(
+        mainAxisSize: MainAxisSize.max,
+        crossAxisAlignment: CrossAxisAlignment.start,
+        children: [
+
+
+          // 中介商名称
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "Name:".tr,
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+
+              //文本
+              MyTextView(
+                item.jobTitle ?? "-",
+                marginLeft: 5,
+                isFontMedium: true,
+                textColor: ColorConstants.textYellowFFBB1B,
+                fontSize: 14,
+                textDecoration: TextDecoration.underline,
+                decorationColor: ColorConstants.textYellowFFBB1B,
+                // 可选,设置下划线的颜色
+                decorationThickness: 2.0,
+                // 可选,设置下划线的粗细
+                decorationStyle: TextDecorationStyle.solid, // 可选,设置下划线的样式
+              ).expanded(),
+            ],
+          ),
+
+          // 创建时间
+          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: 12),
+
+          // 更新时间
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "${"Updated At".tr}:",
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+
+              //文本
+              MyTextView(
+                item.createdAt ?? "-",
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor: Colors.white,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ).marginOnly(top: 12),
+
+
+          //按钮组
+          Visibility(
+            visible: item.actionList.isNotEmpty ?? false,
+            child: Row(
+              mainAxisSize: MainAxisSize.max,
+              mainAxisAlignment: MainAxisAlignment.end,
+              crossAxisAlignment: CrossAxisAlignment.center,
+              children: [
+
+                //Edit按钮
+                Visibility(
+                  visible: item.actionList.contains("edit"),
+                  child: MyButton(
+                    onPressed: () {
+                      FocusScope.of(context).unfocus();
+                      onEditAction?.call();
+                    },
+                    text: "Edit".tr,
+                    textColor: ColorConstants.white,
+                    backgroundColor: ColorConstants.textGreen0AC074,
+                    radius: 17.25,
+                    minWidth: 60,
+                    minHeight: 35,
+                  ).marginOnly(left: 12),
+                ),
+
+                //Delete按钮
+                Visibility(
+                  visible: item.actionList.contains("delete"),
+                  child: MyButton(
+                    onPressed: () {
+                      FocusScope.of(context).unfocus();
+                      onDeleteAction?.call();
+                    },
+                    text: "Delete".tr,
+                    textColor: ColorConstants.white,
+                    backgroundColor: ColorConstants.textRedFF6262,
+                    radius: 17.25,
+                    minWidth: 60,
+                    minHeight: 35,
+                  ).marginOnly(left: 12),
+                ),
+
+              ],
+            ).marginOnly(top: 15, bottom: 2),
+          ),
+        ],
+      ),
+    );
+  }
+}

+ 240 - 0
packages/cpt_sg/lib/modules/agency/position_list/position_list_controller.dart

@@ -0,0 +1,240 @@
+import 'package:domain/entity/response/labour_request_s_g_list_entity.dart';
+import 'package:domain/repository/labour_sg_repository.dart';
+
+import 'package:domain/entity/response/labour_request_index_entity.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:widgets/dialog/app_default_dialog.dart';
+import 'package:widgets/load_state_layout.dart';
+import 'package:widgets/widget_export.dart';
+
+import '../agency_add/agency_add_page.dart';
+import '../position_add/position_add_page.dart';
+import 'position_list_state.dart';
+
+class PositionListController extends GetxController with DioCancelableMixin {
+  final LabourSGRepository _labourRepository = Get.find();
+  final PositionListState state = PositionListState();
+
+  var _curPage = 1;
+  var _needShowPlaceholder = true;
+
+  //页面PlaceHolder的展示
+  LoadState loadingState = LoadState.State_Success;
+  String? errorMessage;
+
+  //刷新页面状态
+  void changeLoadingState(LoadState state) {
+    loadingState = state;
+    update();
+  }
+
+  // Refresh 控制器
+  final EasyRefreshController refreshController = EasyRefreshController(
+    controlFinishRefresh: true,
+    controlFinishLoad: true,
+  );
+
+  // Refresh 刷新事件
+  Future onRefresh() async {
+    _curPage = 1;
+    fetchLabourRequestList();
+  }
+
+  // Refresh 加载事件
+  Future loadMore() async {
+    _curPage++;
+    fetchLabourRequestList();
+  }
+
+  // 重试请求
+  Future retryRequest() async {
+    _curPage = 1;
+    _needShowPlaceholder = true;
+    fetchLabourRequestList();
+  }
+
+  /// 获取列表数据
+  Future fetchLabourRequestList() async {
+    if (_needShowPlaceholder) {
+      changeLoadingState(LoadState.State_Loading);
+    }
+
+    // 并发执行两个请求
+    var futures = [
+      _labourRepository.fetchLabourRequestSGList(
+        state.keyword,
+        "",
+        "",
+        "",
+        "",
+        curPage: _curPage,
+        cancelToken: cancelToken,
+      ),
+      state.indexOptions == null
+          ? _labourRepository.fetchLabourRequestSGIndex(
+              cancelToken: cancelToken,
+            )
+          : Future(() => HttpResult(isSuccess: true).convert(data: state.indexOptions!)),
+    ];
+
+    //拿到结果
+    var results = await Future.wait(futures);
+    var listResult = results[0] as HttpResult<LabourRequestSGListEntity>;
+    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<LabourRequestSGListRows>? list) {
+    if (list != null && list.isNotEmpty) {
+      //有数据,判断是刷新还是加载更多的数据
+      if (_curPage == 1) {
+        //刷新的方式
+        state.datas.clear();
+        state.datas.addAll(list);
+        refreshController.finishRefresh();
+
+        //更新展示的状态
+        changeLoadingState(LoadState.State_Success);
+      } else {
+        //加载更多
+        state.datas.addAll(list);
+        refreshController.finishLoad();
+        update();
+      }
+    } else {
+      if (_curPage == 1) {
+        //展示无数据的布局
+        state.datas.clear();
+        changeLoadingState(LoadState.State_Empty);
+        refreshController.finishRefresh();
+      } else {
+        //展示加载完成,没有更多数据了
+        refreshController.finishLoad(IndicatorResult.noMore);
+      }
+    }
+  }
+
+  // 执行搜索
+  void doSearch(String keyword) {
+    state.keyword = keyword;
+    //赋值之后刷新
+    refreshController.callRefresh();
+  }
+
+  // 清空搜索条件
+  void resetFiltering() {
+    state.keyword = "";
+    state.searchController.text = "";
+
+    //赋值之后刷新
+    refreshController.callRefresh();
+  }
+
+  /// 根据ID获取Item对象,用于刷新
+  void fetchItemByIdAndRefreshItem(String requestId) async {
+    var result = await _labourRepository.fetchItemByRequestId(
+      requestId,
+      cancelToken: cancelToken,
+    );
+
+    //处理数据
+    if (result.isSuccess) {
+      var data = result.data;
+      if (data != null && data.rows != null && data.rows!.isNotEmpty) {
+        final requestItem = data.rows![0];
+
+        //找到当前数据中的此 requestId,并替换对象,再刷新
+        var index = state.datas.indexWhere((element) => element.requestId == requestItem.requestId);
+        if (index >= 0) {
+          state.datas[index] = requestItem;
+          update();
+        }
+      }
+    } else {
+      ToastEngine.show(result.errorMsg ?? "Network Load Error".tr);
+    }
+  }
+
+  @override
+  void onReady() {
+    super.onReady();
+    fetchLabourRequestList();
+  }
+
+  @override
+  void onClose() {
+    state.datas.clear();
+    super.onClose();
+  }
+
+
+  //跳转到添加页面
+  void gotoAddAgencyPage() {
+    SGPositionAddPage.startInstance("", (result) {
+      if (result != null) {
+        refreshController.callRefresh();
+      }
+    });
+  }
+
+
+  //去编辑页面
+  void gotoEditPage(LabourRequestSGListRows data) {
+    SGPositionAddPage.startInstance(data.requestId, (result) {
+      if (result != null) {
+
+      }
+    });
+  }
+
+  //删除labourRequest
+  void doDelete(String? requestId, int index) {
+    DialogEngine.show(
+        widget: AppDefaultDialog(
+      title: "Confirmation".tr,
+      message: "Are you sure you want to delete this position?".tr,
+      confirmAction: () {
+        _submitDeleteRequest(requestId, index);
+      },
+    ));
+  }
+
+  void _submitDeleteRequest(String? requestId, int index) async {
+    var result = await _labourRepository.deleteLabourRequestSG(requestId, cancelToken: cancelToken);
+
+    if (result.isSuccess) {
+      NotifyEngine.showSuccess("Successful".tr);
+
+      if (state.datas.length <= 1) {
+        refreshController.callRefresh();
+      } else {
+        state.datas.removeAt(index);
+        update();
+      }
+    } else {
+      ToastEngine.show(result.errorMsg ?? "Network Load Error".tr);
+    }
+  }
+
+}

+ 202 - 0
packages/cpt_sg/lib/modules/agency/position_list/position_list_page.dart

@@ -0,0 +1,202 @@
+import 'package:cs_resources/constants/color_constants.dart';
+import 'package:cs_resources/generated/assets.dart';
+import 'package:flutter/material.dart';
+import 'package:get/get.dart';
+import 'package:plugin_basic/base/base_state.dart';
+import 'package:plugin_basic/base/base_stateful_page.dart';
+import 'package: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/my_button.dart';
+import 'package:widgets/my_load_image.dart';
+import 'package:widgets/my_text_view.dart';
+import 'package:widgets/widget_export.dart';
+
+import 'position_item.dart';
+import 'position_list_controller.dart';
+import 'position_list_state.dart';
+
+/*
+ * 新加坡的中介公司列表
+ */
+class SGPositionListPage extends BaseStatefulPage<PositionListController> {
+  SGPositionListPage({Key? key}) : super(key: key);
+
+  //启动当前页面
+  static void startInstance() {
+    return Get.start(RouterPath.SGPositionList);
+  }
+
+  @override
+  PositionListController createRawController() {
+    return PositionListController();
+  }
+
+  @override
+  State<SGPositionListPage> createState() => _LabourRequestListState();
+}
+
+class _LabourRequestListState extends BaseState<SGPositionListPage, PositionListController> {
+  late PositionListState 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.titleBar(context, "Position List".tr),
+
+              //搜索的条件
+              Row(
+                children: [
+
+                  //搜索框
+                  Container(
+                    height: 40,
+                    margin: const EdgeInsets.only(right: 10),
+                    padding: const EdgeInsets.only(left: 12, right: 10),
+                    decoration: BoxDecoration(
+                      color: const Color(0xFF4DCFF6).withOpacity(0.2),
+                      borderRadius: const BorderRadius.all(Radius.circular(20)),
+                    ),
+                    child: Row(
+                      mainAxisSize: MainAxisSize.max,
+                      crossAxisAlignment: CrossAxisAlignment.center,
+                      children: [
+                        IgnoreKeyboardDismiss(
+                          child: TextField(
+                            cursorColor: Colors.white,
+                            cursorWidth: 1.5,
+                            autofocus: false,
+                            maxLines: 1,
+                            minLines: 1,
+                            focusNode: state.focusNode,
+                            controller: state.searchController,
+                            decoration: InputDecoration(
+                              isDense: true,
+                              //清除垂直方向的填充
+                              isCollapsed: true,
+                              //让文字垂直居中
+                              border: InputBorder.none,
+                              hintText: 'Agency Name'.tr,
+                              hintStyle: const TextStyle(
+                                color: ColorConstants.textGrayAECAE5,
+                                fontSize: 14.0,
+                                fontWeight: FontWeight.w400,
+                              ),
+                            ),
+                            style: const TextStyle(
+                              color: ColorConstants.white,
+                              fontSize: 14.0,
+                              fontWeight: FontWeight.w400,
+                            ),
+                            onSubmitted: (value){
+                              controller.doSearch(value);
+                            },
+                            // 键盘动作右下角图标
+                            textInputAction: TextInputAction.search,
+                            textAlignVertical: TextAlignVertical.center,
+                          ),
+                        ).expanded(),
+                      ],
+                    ),
+                  ).expanded(flex: 1),
+
+                  //筛选按钮
+                  MyButton(
+                    onPressed: () {
+                      FocusScope.of(context).unfocus();
+                      controller.resetFiltering();
+                    },
+                    text: "Reset".tr,
+                    textColor: ColorConstants.white,
+                    backgroundColor: hexToColor("#2BA9F9", opacity: 0.5),
+                    radius: 20,
+                    minWidth: 60,
+                    minHeight: 35,
+                  ),
+                ],
+              ).marginOnly(top: 10, left: 15, right: 15),
+
+              // 添加按钮
+              MyButton(
+                type: ClickType.throttle,
+                milliseconds: 500,
+                onPressed: () {
+                  FocusScope.of(context).unfocus();
+                  controller.gotoAddAgencyPage();
+                },
+                text: "Add New".tr,
+                textColor: ColorConstants.white,
+                fontSize: 16,
+                radius: 20,
+                backgroundColor: hexToColor("#FFBB1B"),
+                fontWeight: FontWeight.w500,
+              ).marginSymmetric(horizontal: 15, vertical: 10),
+
+              //底部的列表
+              EasyRefresh(
+                controller: controller.refreshController,
+                onRefresh: controller.onRefresh,
+                onLoad: controller.loadMore,
+                child: LoadStateLayout(
+                  state: controller.loadingState,
+                  errorMessage: controller.errorMessage,
+                  errorRetry: () {
+                    controller.retryRequest();
+                  },
+                  successSliverWidget: [
+                    SliverList(
+                        delegate: SliverChildBuilderDelegate(
+                      (context, index) {
+                        return PositionItem(
+                          index: index,
+                          item: state.datas[index],
+                          onDeleteAction: () {
+                            controller.doDelete(state.datas[index].requestId,index);
+                          },
+                          onEditAction: () {
+                            controller.gotoEditPage(state.datas[index]);
+                          },
+
+                        );
+                      },
+                      childCount: state.datas.length,
+                    ))
+                  ],
+                ),
+              ).expanded(),
+            ],
+          ),
+        ),
+      );
+    });
+  }
+}

+ 14 - 0
packages/cpt_sg/lib/modules/agency/position_list/position_list_state.dart

@@ -0,0 +1,14 @@
+import 'package:domain/entity/response/labour_request_index_entity.dart';
+import 'package:domain/entity/response/labour_request_s_g_list_entity.dart';
+import 'package:flutter/material.dart';
+
+class PositionListState {
+  //筛选条件
+  final TextEditingController searchController = TextEditingController();
+  final FocusNode focusNode = FocusNode();
+  String keyword = "";
+
+  //页面的列表数据
+  List<LabourRequestSGListRows> datas = [];
+  LabourRequestIndexEntity? indexOptions;
+}

+ 2 - 1
packages/cpt_sg/lib/modules/main/main_controller.dart

@@ -20,6 +20,7 @@ import 'package:router/componentRouter/component_router_service.dart';
 import 'package:widgets/load_state_layout.dart';
 import 'package:widgets/widget_export.dart';
 
+import '../agency/agency_category/agency_category_page.dart';
 import 'main_state.dart';
 
 class MainController extends GetxController {
@@ -133,7 +134,7 @@ class MainController extends GetxController {
         ToastEngine.show("进入 dashboard");
         break;
       case 'agency':
-        ToastEngine.show("进入 agency");
+        SGAgencyCategoryPage.startInstance();
         break;
       case 'labReq':
         LabourRequestListPage.startInstance();

+ 76 - 2
packages/cpt_sg/lib/router/sg_router.dart

@@ -1,7 +1,18 @@
+import 'package:cpt_sg/modules/agency/agency_add/agency_add_page.dart';
+import 'package:cpt_sg/modules/agency/agency_category/agency_category_page.dart';
+import 'package:cpt_sg/modules/agency/agency_list/agency_list_page.dart';
+import 'package:cpt_sg/modules/agency/contract_add/contract_add_page.dart';
+import 'package:cpt_sg/modules/agency/contract_list/contract_list_page.dart';
+import 'package:cpt_sg/modules/agency/contract_rate_edit_list/contract_rate_edit_list_page.dart';
+import 'package:cpt_sg/modules/agency/contract_rate_list/contract_rate_list_page.dart';
+import 'package:cpt_sg/modules/agency/contract_rate_specific_day/contract_rate_specific_page.dart';
+import 'package:cpt_sg/modules/agency/position_add/position_add_page.dart';
+import 'package:cpt_sg/modules/agency/position_list/position_list_page.dart';
 import 'package:cpt_sg/modules/main/main_page.dart';
 import 'package:get/get.dart';
 import 'package:router/path/router_path.dart';
 
+import '../modules/agency/contract_rate_setting/contract_rate_setting_page.dart';
 import '../modules/job/applied_staff/applied_staff_page.dart';
 import '../modules/job/applied_staff_detail/applied_staff_detail_page.dart';
 import '../modules/job/applied_staff_reviews/applied_staff_reviews_page.dart';
@@ -28,11 +39,9 @@ import '../modules/review/labour_review_edit/labour_review_edit_page.dart';
 import '../modules/review/labour_review_list/labour_review_page.dart';
 import '../modules/review/labour_review_workflow/labour_request_workflow_page.dart';
 
-
 /// SG模块路由配置
 class SGPageRouter {
   static final routes = <GetPage<dynamic>>[
-
     GetPage(
       name: RouterPath.SGMain,
       page: () => SGMainPage(),
@@ -181,5 +190,70 @@ class SGPageRouter {
       page: () => SGAttendanceReviewPage(),
     ),
 
+    //新加坡中介模块的分类
+    GetPage(
+      name: RouterPath.SGAgencyCategory,
+      page: () => SGAgencyCategoryPage(),
+    ),
+
+    //新加坡中介公司列表
+    GetPage(
+      name: RouterPath.SGAgencyList,
+      page: () => SGAgencyListPage(),
+    ),
+
+    //新加坡中介公司添加与编辑
+    GetPage(
+      name: RouterPath.SGAgencyAdd,
+      page: () => SGAgencyAddPage(),
+    ),
+
+    //新加坡的合同列表
+    GetPage(
+      name: RouterPath.SGContractList,
+      page: () => SGContractListPage(),
+    ),
+
+    //新加坡的合同列表添加与编辑
+    GetPage(
+      name: RouterPath.SGContractAdd,
+      page: () => SGContractAddPage(),
+    ),
+
+    //新加坡的指定合同的时薪管理列表
+    GetPage(
+      name: RouterPath.SGContractRateList,
+      page: () => SGContractRateListPage(),
+    ),
+
+    //新加坡的指定合同的时薪管理的具体日期列表
+    GetPage(
+      name: RouterPath.SGContractRateDayEdit,
+      page: () => SGContractRateEditListPage(),
+    ),
+
+    //新加坡的指定合同的时薪管理的具体日期列表
+    GetPage(
+      name: RouterPath.SGContractRateSetting,
+      page: () => ContractRateSettingPage(),
+    ),
+
+    //设置指定日期的时薪
+    GetPage(
+      name: RouterPath.SGContractRateSpecificDay,
+      page: () => SGContractRateSpecificPage(),
+    ),
+
+    //职位列表
+    GetPage(
+      name: RouterPath.SGPositionList,
+      page: () => SGPositionListPage(),
+    ),
+
+    //职位的添加与编辑
+    GetPage(
+      name: RouterPath.SGPositionAdd,
+      page: () => SGPositionAddPage(),
+    ),
   ];
 }

+ 1 - 1
packages/cs_domain/lib/repository/auth_repository.dart

@@ -1,6 +1,6 @@
 import 'package:domain/entity/response/hotel_info_entity.dart';
 import 'package:get/get.dart';
-import 'package:plugin_platform/dio_export.dart';
+import 'package:plugin_platform/platform_export.dart';
 import 'package:plugin_platform/http/http_provider.dart';
 import 'package:plugin_platform/http/http_result.dart';
 

+ 1 - 1
packages/cs_domain/lib/repository/job_repository.dart

@@ -13,7 +13,7 @@ import 'package:domain/entity/response/staff_detail_entity.dart';
 import 'package:domain/entity/response/staff_labour_history_entity.dart';
 import 'package:domain/entity/response/staff_remark_history_entity.dart';
 import 'package:get/get.dart';
-import 'package:plugin_platform/dio_export.dart';
+import 'package:plugin_platform/platform_export.dart';
 import 'package:plugin_platform/http/http_provider.dart';
 import 'package:plugin_platform/http/http_result.dart';
 import 'package:shared/utils/util.dart';

+ 1 - 1
packages/cs_domain/lib/repository/job_sg_repository.dart

@@ -19,7 +19,7 @@ import 'package:domain/entity/response/staff_labour_history_entity.dart';
 import 'package:domain/entity/response/staff_remark_history_entity.dart';
 import 'package:domain/entity/response/staff_review_history_s_g_entity.dart';
 import 'package:get/get.dart';
-import 'package:plugin_platform/dio_export.dart';
+import 'package:plugin_platform/platform_export.dart';
 import 'package:plugin_platform/http/http_provider.dart';
 import 'package:plugin_platform/http/http_result.dart';
 import 'package:shared/utils/util.dart';

+ 1 - 1
packages/cs_domain/lib/repository/labour_repository.dart

@@ -3,7 +3,7 @@ import 'package:domain/entity/response/labour_request_index_entity.dart';
 import 'package:domain/entity/response/labour_request_list_entity.dart';
 import 'package:domain/entity/response/labour_request_work_flow_entity.dart';
 import 'package:get/get.dart';
-import 'package:plugin_platform/dio_export.dart';
+import 'package:plugin_platform/platform_export.dart';
 import 'package:plugin_platform/http/http_provider.dart';
 import 'package:plugin_platform/http/http_result.dart';
 import 'package:shared/utils/util.dart';

+ 1 - 1
packages/cs_domain/lib/repository/labour_sg_repository.dart

@@ -9,7 +9,7 @@ import 'package:domain/entity/response/job_title_s_g_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:get/get.dart';
-import 'package:plugin_platform/dio_export.dart';
+import 'package:plugin_platform/platform_export.dart';
 import 'package:plugin_platform/http/http_provider.dart';
 import 'package:plugin_platform/http/http_result.dart';
 import 'package:shared/utils/util.dart';

+ 1 - 1
packages/cs_domain/lib/repository/other_repository.dart

@@ -3,7 +3,7 @@ import 'package:domain/entity/response/fiance_report_entity.dart';
 import 'package:domain/entity/response/labour_report_entity.dart';
 import 'package:domain/entity/response/staff_request_report_entity.dart';
 import 'package:get/get.dart';
-import 'package:plugin_platform/dio_export.dart';
+import 'package:plugin_platform/platform_export.dart';
 import 'package:plugin_platform/http/http_provider.dart';
 import 'package:plugin_platform/http/http_result.dart';
 import 'package:shared/utils/log_utils.dart';

+ 1 - 1
packages/cs_plugin_basic/lib/dio_interceptors/interceptor_status_code_dio.dart

@@ -1,5 +1,5 @@
 import 'package:get/utils.dart';
-import 'package:plugin_platform/dio_export.dart';
+import 'package:plugin_platform/platform_export.dart';
 import 'package:plugin_platform/engine/dialog/dialog_engine.dart';
 import 'package:router/componentRouter/component_router_service.dart';
 import 'package:widgets/dialog/app_default_dialog.dart';

+ 0 - 1
packages/cs_plugin_platform/lib/dio_export.dart

@@ -1 +0,0 @@
-export 'package:dio/dio.dart';

+ 141 - 0
packages/cs_plugin_platform/lib/engine/image/image_nine_grid.dart

@@ -0,0 +1,141 @@
+import 'package:cs_resources/generated/assets.dart';
+import 'package:flutter/material.dart';
+import 'package:plugin_platform/engine/media/image_picker_utils.dart';
+import 'package:shared/utils/util.dart';
+import 'package:widgets/ext/ex_widget.dart';
+import 'package:widgets/my_load_image.dart';
+import 'image_preview.dart';
+
+/// 九宫格的图片选择与图片展示
+class ImageNineGrid extends StatefulWidget {
+  final bool isSelectEnable; // 是否能选择
+  final List<String> initialImages; // 初始化图片集合
+  final int maxImages; // 最多选择的图片
+  final double aspectRatio; // 宽高比
+  final double spacing; // 横向竖向的间距
+  final double borderRadius; //整体边框圆角
+  final Function(List<String>) onImagesChanged;
+
+  const ImageNineGrid({
+    Key? key,
+    this.isSelectEnable = true,
+    this.maxImages = 9,
+    this.aspectRatio = 1.0,
+    this.spacing = 8,
+    this.borderRadius = 5.0,
+    required this.initialImages,
+    required this.onImagesChanged,
+  }) : super(key: key);
+
+  @override
+  _ImageNineGridState createState() => _ImageNineGridState();
+}
+
+class _ImageNineGridState extends State<ImageNineGrid> {
+  late List<String> _images;
+
+  @override
+  void initState() {
+    super.initState();
+    _images = List.from(widget.initialImages);
+  }
+
+  @override
+  void didUpdateWidget(covariant ImageNineGrid oldWidget) {
+    super.didUpdateWidget(oldWidget);
+    if (oldWidget.initialImages != widget.initialImages) {
+      _images = List.from(widget.initialImages);
+    }
+  }
+
+  // 选择图片
+  Future<void> _pickImage() async {
+    ImagePickerUtils().show(context, (filePath) {
+      if (Utils.isNotEmpty(filePath)) {
+        setState(() {
+          _images.add(filePath);
+        });
+        widget.onImagesChanged(_images);
+      }
+    });
+  }
+
+  // 删除图片
+  void _removeImage(int index) {
+    setState(() {
+      _images.removeAt(index);
+    });
+    widget.onImagesChanged(_images);
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    final gridChildren = List<Widget>.generate(
+      _images.length,
+      (index) => Stack(
+        children: [
+          ClipRRect(
+            borderRadius: BorderRadius.circular(widget.borderRadius), // 圆角半径
+            child: Hero(
+              tag: _images[index],
+              child: MyLoadImage(
+                _images[index],
+                width: double.infinity,
+                height: double.infinity,
+                fit: BoxFit.cover,
+              ).onTap(() {
+                //预览图片
+                ImagePreviewEngine.singleImagePreview(context, _images[index], heroTag: _images[index]);
+              }),
+            ),
+          ),
+          Positioned(
+            top: 0,
+            right: 0,
+            child: Visibility(
+              visible: widget.isSelectEnable,
+              child: const MyAssetImage(Assets.baseLibDialogDeleteIcon, width: 24, height: 24).onTap(
+                () {
+                  if (widget.isSelectEnable) {
+                    _removeImage(index);
+                  }
+                },
+              ).padding(top: 5, right: 5, bottom: 5, left: 5),
+            ),
+          ),
+        ],
+      ),
+    );
+
+    if (widget.isSelectEnable && _images.length < widget.maxImages) {
+      gridChildren.add(
+        GestureDetector(
+          onTap: _pickImage,
+          child: Container(
+            decoration: BoxDecoration(
+              color: const Color(0xFF4DCFF6).withOpacity(0.2),
+              borderRadius: BorderRadius.circular(widget.borderRadius), // 圆角半径
+            ),
+            child: const Center(
+              child: MyAssetImage(Assets.baseServiceImageAddIcon, width: 20, height: 20),
+            ),
+          ),
+        ),
+      );
+    }
+
+    return GridView.builder(
+      padding: EdgeInsets.zero, // 设置为零,消除任何内边距
+      shrinkWrap: true,
+      physics: const NeverScrollableScrollPhysics(),
+      gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
+        crossAxisCount: 3,
+        childAspectRatio: widget.aspectRatio,
+        mainAxisSpacing: widget.spacing,
+        crossAxisSpacing: widget.spacing,
+      ),
+      itemCount: gridChildren.length,
+      itemBuilder: (context, index) => gridChildren[index],
+    );
+  }
+}

+ 101 - 102
packages/cs_plugin_platform/lib/engine/media/album_engine.dart

@@ -1,102 +1,101 @@
-// import 'package:flutter/material.dart';
-// import 'package:flutter/services.dart';
-// import 'package:get/get.dart';
-// import 'package:wechat_assets_picker/wechat_assets_picker.dart';
-//
-// /*
-//  * 本地图库的引擎封装,目前用的 wechat_assets_picker 插件
-//  */
-// class AlbumEngine {
-//   /// 选择图片
-//   static Future<List<AssetEntity>?> selectImage(
-//     BuildContext context, {
-//     int maxAssets = 9,
-//     List<AssetEntity>? selected,
-//     int filterMinWidth = 100,
-//     int filterMaxWidth = 100000,
-//     int filterMinHeight = 100,
-//     int filterMaxHeight = 100000,
-//   }) async {
-//     FilterOptionGroup filterOptions = FilterOptionGroup()
-//       ..setOption(
-//         AssetType.image,
-//         FilterOption(
-//           sizeConstraint: SizeConstraint(
-//             minWidth: filterMinWidth,
-//             maxWidth: filterMaxWidth,
-//             minHeight: filterMinHeight,
-//             maxHeight: filterMaxHeight,
-//           ),
-//         ),
-//       );
-//
-//     return AssetPicker.pickAssets(
-//       context,
-//       pickerConfig: AssetPickerConfig(
-//         requestType: RequestType.image,
-//         selectedAssets: selected,
-//         maxAssets: maxAssets,
-//         filterOptions: filterOptions,
-//         gridCount: 4,
-//         pageSize: 40,
-//         pickerTheme: ThemeData(
-//           brightness: Brightness.dark,
-//           appBarTheme: AppBarTheme(
-//             systemOverlayStyle: SystemUiOverlayStyle.dark.copyWith(
-//                     statusBarColor: Colors.transparent,
-//                     statusBarBrightness: Brightness.dark,
-//                     statusBarIconBrightness: Brightness.light,
-//                   ),
-//           ),
-//         ),
-//       ),
-//     );
-//   }
-//
-//   /// 选择视频
-//   static Future<List<AssetEntity>?> selectVideo(
-//     BuildContext context, {
-//     int maxAssets = 1,
-//     List<AssetEntity>? selected,
-//     int filterMinWidth = 100,
-//     int filterMaxWidth = 100000,
-//     int filterMinHeight = 100,
-//     int filterMaxHeight = 100000,
-//     int filterMaxSeconds = 60, //默认能选择60秒以内的视频
-//   }) async {
-//     FilterOptionGroup filterOptions = FilterOptionGroup()
-//       ..setOption(
-//         AssetType.video,
-//         FilterOption(
-//             sizeConstraint: SizeConstraint(
-//               minWidth: filterMinWidth,
-//               maxWidth: filterMaxWidth,
-//               minHeight: filterMinHeight,
-//               maxHeight: filterMaxHeight,
-//             ),
-//             durationConstraint: DurationConstraint(max: Duration(seconds: filterMaxSeconds))),
-//       );
-//
-//     return AssetPicker.pickAssets(
-//       context,
-//       pickerConfig: AssetPickerConfig(
-//         requestType: RequestType.video,
-//         selectedAssets: selected,
-//         maxAssets: maxAssets,
-//         filterOptions: filterOptions,
-//         gridCount: 4,
-//         pageSize: 40,
-//         pickerTheme: ThemeData(
-//           brightness: Brightness.dark,
-//           appBarTheme: AppBarTheme(
-//             systemOverlayStyle: SystemUiOverlayStyle.dark.copyWith(
-//               statusBarColor: Colors.transparent,
-//               statusBarBrightness: Brightness.dark,
-//               statusBarIconBrightness: Brightness.light,
-//             ),
-//           ),
-//         ),
-//       ),
-//     );
-//   }
-// }
+import 'package:flutter/material.dart';
+import 'package:flutter/services.dart';
+import 'package:wechat_assets_picker/wechat_assets_picker.dart';
+
+/*
+ * 本地图库的引擎封装,目前用的 wechat_assets_picker 插件
+ */
+class AlbumEngine {
+  /// 选择图片
+  static Future<List<AssetEntity>?> selectImage(
+    BuildContext context, {
+    int maxAssets = 9,
+    List<AssetEntity>? selected,
+    int filterMinWidth = 100,
+    int filterMaxWidth = 100000,
+    int filterMinHeight = 100,
+    int filterMaxHeight = 100000,
+  }) async {
+    FilterOptionGroup filterOptions = FilterOptionGroup()
+      ..setOption(
+        AssetType.image,
+        FilterOption(
+          sizeConstraint: SizeConstraint(
+            minWidth: filterMinWidth,
+            maxWidth: filterMaxWidth,
+            minHeight: filterMinHeight,
+            maxHeight: filterMaxHeight,
+          ),
+        ),
+      );
+
+    return AssetPicker.pickAssets(
+      context,
+      pickerConfig: AssetPickerConfig(
+        requestType: RequestType.image,
+        selectedAssets: selected,
+        maxAssets: maxAssets,
+        filterOptions: filterOptions,
+        gridCount: 4,
+        pageSize: 40,
+        pickerTheme: ThemeData(
+          brightness: Brightness.dark,
+          appBarTheme: AppBarTheme(
+            systemOverlayStyle: SystemUiOverlayStyle.dark.copyWith(
+                    statusBarColor: Colors.transparent,
+                    statusBarBrightness: Brightness.dark,
+                    statusBarIconBrightness: Brightness.light,
+                  ),
+          ),
+        ),
+      ),
+    );
+  }
+
+  /// 选择视频
+  static Future<List<AssetEntity>?> selectVideo(
+    BuildContext context, {
+    int maxAssets = 1,
+    List<AssetEntity>? selected,
+    int filterMinWidth = 100,
+    int filterMaxWidth = 100000,
+    int filterMinHeight = 100,
+    int filterMaxHeight = 100000,
+    int filterMaxSeconds = 60, //默认能选择60秒以内的视频
+  }) async {
+    FilterOptionGroup filterOptions = FilterOptionGroup()
+      ..setOption(
+        AssetType.video,
+        FilterOption(
+            sizeConstraint: SizeConstraint(
+              minWidth: filterMinWidth,
+              maxWidth: filterMaxWidth,
+              minHeight: filterMinHeight,
+              maxHeight: filterMaxHeight,
+            ),
+            durationConstraint: DurationConstraint(max: Duration(seconds: filterMaxSeconds))),
+      );
+
+    return AssetPicker.pickAssets(
+      context,
+      pickerConfig: AssetPickerConfig(
+        requestType: RequestType.video,
+        selectedAssets: selected,
+        maxAssets: maxAssets,
+        filterOptions: filterOptions,
+        gridCount: 4,
+        pageSize: 40,
+        pickerTheme: ThemeData(
+          brightness: Brightness.dark,
+          appBarTheme: AppBarTheme(
+            systemOverlayStyle: SystemUiOverlayStyle.dark.copyWith(
+              statusBarColor: Colors.transparent,
+              statusBarBrightness: Brightness.dark,
+              statusBarIconBrightness: Brightness.light,
+            ),
+          ),
+        ),
+      ),
+    );
+  }
+}

+ 56 - 57
packages/cs_plugin_platform/lib/engine/media/camera_engine.dart

@@ -1,57 +1,56 @@
-// import 'package:flutter/material.dart';
-// import 'package:wechat_camera_picker/wechat_camera_picker.dart';
-// import 'package:flutter/services.dart';
-// import 'package:get/get.dart';
-//
-// /*
-//  * 照相机的引擎封装,目前用的 CameraPicker 插件
-//  */
-// class CameraEngine {
-//   /// 拍照
-//   static Future<AssetEntity?> takePhoto(BuildContext context) async {
-//     return await CameraPicker.pickFromCamera(
-//       context,
-//       pickerConfig: CameraPickerConfig(
-//         enableRecording: false,
-//         theme: ThemeData(
-//           brightness: Brightness.dark,
-//           appBarTheme: AppBarTheme(
-//             systemOverlayStyle: SystemUiOverlayStyle.dark.copyWith(
-//               statusBarColor: Colors.transparent,
-//               statusBarBrightness: Brightness.dark,
-//               statusBarIconBrightness: Brightness.light,
-//             ),
-//           ),
-//         ),
-//       ),
-//     );
-//   }
-//
-//   /// 录制视频
-//   static Future<AssetEntity?> takeVideo(
-//     BuildContext context, {
-//     int maxRecordInSeconds = 30,
-//   }) async {
-//     return await CameraPicker.pickFromCamera(
-//       context,
-//       pickerConfig: CameraPickerConfig(
-//         enableRecording: true,
-//         onlyEnableRecording: true,
-//         enableTapRecording: false,
-//         enableAudio: true,
-//         shouldAutoPreviewVideo: true,
-//         maximumRecordingDuration: Duration(seconds: maxRecordInSeconds),
-//         theme: ThemeData(
-//           brightness: Brightness.dark,
-//           appBarTheme: AppBarTheme(
-//             systemOverlayStyle: SystemUiOverlayStyle.dark.copyWith(
-//               statusBarColor: Colors.transparent,
-//               statusBarBrightness: Brightness.dark,
-//               statusBarIconBrightness: Brightness.light,
-//             ),
-//           ),
-//         ),
-//       ),
-//     );
-//   }
-// }
+import 'package:flutter/material.dart';
+import 'package:wechat_camera_picker/wechat_camera_picker.dart';
+import 'package:flutter/services.dart';
+
+/*
+ * 照相机的引擎封装,目前用的 CameraPicker 插件
+ */
+class CameraEngine {
+  /// 拍照
+  static Future<AssetEntity?> takePhoto(BuildContext context) async {
+    return await CameraPicker.pickFromCamera(
+      context,
+      pickerConfig: CameraPickerConfig(
+        enableRecording: false,
+        theme: ThemeData(
+          brightness: Brightness.dark,
+          appBarTheme: AppBarTheme(
+            systemOverlayStyle: SystemUiOverlayStyle.dark.copyWith(
+              statusBarColor: Colors.transparent,
+              statusBarBrightness: Brightness.dark,
+              statusBarIconBrightness: Brightness.light,
+            ),
+          ),
+        ),
+      ),
+    );
+  }
+
+  /// 录制视频
+  static Future<AssetEntity?> takeVideo(
+    BuildContext context, {
+    int maxRecordInSeconds = 30,
+  }) async {
+    return await CameraPicker.pickFromCamera(
+      context,
+      pickerConfig: CameraPickerConfig(
+        enableRecording: true,
+        onlyEnableRecording: true,
+        enableTapRecording: false,
+        enableAudio: true,
+        shouldAutoPreviewVideo: true,
+        maximumRecordingDuration: Duration(seconds: maxRecordInSeconds),
+        theme: ThemeData(
+          brightness: Brightness.dark,
+          appBarTheme: AppBarTheme(
+            systemOverlayStyle: SystemUiOverlayStyle.dark.copyWith(
+              statusBarColor: Colors.transparent,
+              statusBarBrightness: Brightness.dark,
+              statusBarIconBrightness: Brightness.light,
+            ),
+          ),
+        ),
+      ),
+    );
+  }
+}

+ 41 - 43
packages/cs_plugin_platform/lib/engine/media/image_crop_engine.dart

@@ -1,43 +1,41 @@
-// import 'package:flutter/material.dart';
-//
-// import 'package:get/get.dart';
-// import 'package:image_cropper/image_cropper.dart';
-//
-// /*
-//  * 图片裁剪引擎封装,目前使用的是 UCorp 框架
-//  */
-// class ImageCropEngine {
-//   /// 开启图片裁剪 - 返回裁剪后的图片的路径 (默认裁剪后的路径在App/Data/Cache目录下)
-//   static Future<String?> imageCrop(
-//     BuildContext context,
-//     String filePath, {
-//     CropAspectRatioPreset aspect = CropAspectRatioPreset.square,
-//   }) async {
-//     CroppedFile? croppedFile = await ImageCropper().cropImage(
-//       sourcePath: filePath,
-//       aspectRatioPresets: [
-//         aspect,
-//       ],
-//       uiSettings: [
-//         AndroidUiSettings(
-//             toolbarTitle: '图片裁剪'.tr,
-//             toolbarColor: const Color(0xff212121),
-//             statusBarColor: const Color(0xff212121),
-//             toolbarWidgetColor: Colors.white,
-//             initAspectRatio: CropAspectRatioPreset.original,
-//             lockAspectRatio: false),
-//         IOSUiSettings(
-//           title: '图片裁剪'.tr,
-//         ),
-//         WebUiSettings(
-//           context: context,
-//         ),
-//       ],
-//     );
-//
-//     if (croppedFile != null) {
-//       return croppedFile.path;
-//     }
-//     return null;
-//   }
-// }
+import 'package:flutter/material.dart';
+import 'package:image_cropper/image_cropper.dart';
+
+/*
+ * 图片裁剪引擎封装,目前使用的是 UCorp 框架
+ */
+class ImageCropEngine {
+  /// 开启图片裁剪 - 返回裁剪后的图片的路径 (默认裁剪后的路径在App/Data/Cache目录下)
+  static Future<String?> imageCrop(
+    BuildContext context,
+    String filePath, {
+    CropAspectRatioPreset aspect = CropAspectRatioPreset.square,
+  }) async {
+    CroppedFile? croppedFile = await ImageCropper().cropImage(
+      sourcePath: filePath,
+      aspectRatioPresets: [
+        aspect,
+      ],
+      uiSettings: [
+        AndroidUiSettings(
+            toolbarTitle: 'Image Crop',
+            toolbarColor: const Color(0xff212121),
+            statusBarColor: const Color(0xff212121),
+            toolbarWidgetColor: Colors.white,
+            initAspectRatio: CropAspectRatioPreset.original,
+            lockAspectRatio: false),
+        IOSUiSettings(
+          title: 'Image Crop',
+        ),
+        WebUiSettings(
+          context: context,
+        ),
+      ],
+    );
+
+    if (croppedFile != null) {
+      return croppedFile.path;
+    }
+    return null;
+  }
+}

+ 101 - 102
packages/cs_plugin_platform/lib/engine/media/image_picker_utils.dart

@@ -1,102 +1,101 @@
-// import 'package:flutter/material.dart';
-// import 'package:get/get.dart';
-// import 'package:image_cropper/image_cropper.dart';
-// import 'package:wechat_assets_picker/wechat_assets_picker.dart';
-// import 'package:widgets/dialog/album_default_select_dialog.dart';
-//
-// import '../permission/permission_engine.dart';
-// import 'album_engine.dart';
-// import 'camera_engine.dart';
-// import '../dialog/dialog_engine.dart';
-// import 'image_crop_engine.dart';
-//
-//
-// /*
-//     相机相册选择的封装
-//
-//     1.相机相册的选择弹框
-//     2.相机相册权限提示详情描述弹窗
-//     3.调用相机相册的引擎封装类 CameraEngine  AlbumEngine  ImageCropEngine 的使用
-//  */
-// class ImagePickerUtils {
-//   // 私有构造函数
-//   ImagePickerUtils._privateConstructor();
-//
-//   // 单例实例
-//   static final ImagePickerUtils _instance = ImagePickerUtils._privateConstructor();
-//
-//   // 获取单例实例的访问点
-//   factory ImagePickerUtils() {
-//     return _instance;
-//   }
-//
-//   /// 入口
-//   void show(
-//     void Function(String filePath) complete, {
-//     bool isCropped = false,
-//     CropAspectRatioPreset aspect = CropAspectRatioPreset.square,
-//   }) {
-//     DialogEngine.show(
-//         position: DialogPosition.bottom,
-//         widget: AlbumDefaultSelectDialog(cameraAction: () {
-//           //相机的选项
-//           PermissionEngine().requestCameraPermission(() {
-//             //调用相机引擎读取图片
-//             _selectFormCamera(Get.context!, (filePath) {
-//               complete(filePath);
-//             }, isCropped: isCropped, aspect: aspect);
-//           });
-//         }, albumAction: () {
-//           //相册的选项
-//           PermissionEngine().requestPhotosPermission(() {
-//             //调用相册引擎读取图片
-//             _selectFormAlbum(Get.context!, (filePath) {
-//               complete(filePath);
-//             }, isCropped: isCropped, aspect: aspect);
-//           });
-//         }));
-//   }
-//
-//   /// 从相机中选择
-//   Future _selectFormCamera(
-//     BuildContext context,
-//     void Function(String filePath) complete, {
-//     bool isCropped = false,
-//     CropAspectRatioPreset aspect = CropAspectRatioPreset.square,
-//   }) async {
-//     final AssetEntity? result = await CameraEngine.takePhoto(context);
-//
-//     if (result != null) {
-//       final file = await result.file;
-//       final filePath = file?.path;
-//
-//       if (filePath != null && isCropped == true) {
-//         final croppedPath = await ImageCropEngine.imageCrop(context, filePath, aspect: aspect);
-//         complete(croppedPath!);
-//       } else {
-//         complete(filePath!);
-//       }
-//     }
-//   }
-//
-//   /// 从相册中选择
-//   Future _selectFormAlbum(
-//     BuildContext context,
-//     void Function(String filePath) complete, {
-//     bool isCropped = false,
-//     CropAspectRatioPreset aspect = CropAspectRatioPreset.square,
-//   }) async {
-//     final List<AssetEntity>? result = await AlbumEngine.selectImage(context, maxAssets: 1);
-//     if (result != null && result.isNotEmpty) {
-//       final file = await result[0].file;
-//       final filePath = file?.path;
-//
-//       if (filePath != null && isCropped == true) {
-//         final croppedPath = await ImageCropEngine.imageCrop(context, filePath, aspect: aspect);
-//         complete(croppedPath!);
-//       } else {
-//         complete(filePath!);
-//       }
-//     }
-//   }
-// }
+import 'package:flutter/material.dart';
+import 'package:image_cropper/image_cropper.dart';
+import 'package:wechat_assets_picker/wechat_assets_picker.dart';
+import 'package:widgets/dialog/album_default_select_dialog.dart';
+
+import '../permission/permission_engine.dart';
+import 'album_engine.dart';
+import 'camera_engine.dart';
+import '../dialog/dialog_engine.dart';
+import 'image_crop_engine.dart';
+
+/*
+    相机相册选择的封装
+
+    1.相机相册的选择弹框
+    2.相机相册权限提示详情描述弹窗
+    3.调用相机相册的引擎封装类 CameraEngine  AlbumEngine  ImageCropEngine 的使用
+ */
+class ImagePickerUtils {
+  // 私有构造函数
+  ImagePickerUtils._privateConstructor();
+
+  // 单例实例
+  static final ImagePickerUtils _instance = ImagePickerUtils._privateConstructor();
+
+  // 获取单例实例的访问点
+  factory ImagePickerUtils() {
+    return _instance;
+  }
+
+  /// 入口
+  void show(
+    BuildContext context,
+    void Function(String filePath) complete, {
+    bool isCropped = false,
+    CropAspectRatioPreset aspect = CropAspectRatioPreset.square,
+  }) {
+    DialogEngine.show(
+        position: DialogPosition.bottom,
+        widget: AlbumDefaultSelectDialog(cameraAction: () {
+          //相机的选项
+          PermissionEngine().requestCameraPermission(() {
+            //调用相机引擎读取图片
+            _selectFormCamera(context, (filePath) {
+              complete(filePath);
+            }, isCropped: isCropped, aspect: aspect);
+          });
+        }, albumAction: () {
+          //相册的选项
+          PermissionEngine().requestPhotosPermission(() {
+            //调用相册引擎读取图片
+            _selectFormAlbum(context, (filePath) {
+              complete(filePath);
+            }, isCropped: isCropped, aspect: aspect);
+          });
+        }));
+  }
+
+  /// 从相机中选择
+  Future _selectFormCamera(
+    BuildContext context,
+    void Function(String filePath) complete, {
+    bool isCropped = false,
+    CropAspectRatioPreset aspect = CropAspectRatioPreset.square,
+  }) async {
+    final AssetEntity? result = await CameraEngine.takePhoto(context);
+
+    if (result != null) {
+      final file = await result.file;
+      final filePath = file?.path;
+
+      if (filePath != null && isCropped == true) {
+        final croppedPath = await ImageCropEngine.imageCrop(context, filePath, aspect: aspect);
+        complete(croppedPath!);
+      } else {
+        complete(filePath!);
+      }
+    }
+  }
+
+  /// 从相册中选择
+  Future _selectFormAlbum(
+    BuildContext context,
+    void Function(String filePath) complete, {
+    bool isCropped = false,
+    CropAspectRatioPreset aspect = CropAspectRatioPreset.square,
+  }) async {
+    final List<AssetEntity>? result = await AlbumEngine.selectImage(context, maxAssets: 1);
+    if (result != null && result.isNotEmpty) {
+      final file = await result[0].file;
+      final filePath = file?.path;
+
+      if (filePath != null && isCropped == true) {
+        final croppedPath = await ImageCropEngine.imageCrop(context, filePath, aspect: aspect);
+        complete(croppedPath!);
+      } else {
+        complete(filePath!);
+      }
+    }
+  }
+}

+ 254 - 199
packages/cs_plugin_platform/lib/engine/permission/permission_engine.dart

@@ -1,199 +1,254 @@
-//
-// import 'package:flutter/material.dart';
-// import 'package:permission_handler/permission_handler.dart';
-// import 'package:photo_manager/photo_manager.dart';
-// import 'package:shared/utils/device_utils.dart';
-// import 'package:shared/utils/log_utils.dart';
-// import 'package:widgets/dialog/app_default_dialog.dart';
-// import 'package:widgets/dialog/permission_desc_dialog.dart';
-//
-// import '../dialog/dialog_engine.dart';
-//
-//
-// /**
-//  * 动态权限的申请与校验
-//  */
-// class PermissionEngine {
-//   // 私有构造函数
-//   PermissionEngine._privateConstructor();
-//
-//   // 单例实例
-//   static final PermissionEngine _instance = PermissionEngine._privateConstructor();
-//
-//   // 获取单例实例的访问点
-//   factory PermissionEngine() {
-//     return _instance;
-//   }
-//
-//   /// 申请多媒体相册权限
-//   void requestPhotosPermission(void Function() success) async {
-//     //相册的选项
-//     if (DeviceUtils.isIOS) {
-//       //申请授权
-//       final value = await PhotoManager.requestPermissionExtend();
-//       if (value.hasAccess) {
-//         //已授权
-//         Log.d("相册已授权");
-//         success();
-//       } else if (value == PermissionState.limited) {
-//         Log.d("相册访问受限,去设置受限");
-//         PhotoManager.presentLimited();
-//       } else {
-//         Log.d("相册无授权,去设置");
-//         DialogEngine.show(
-//           widget: AppDefaultDialog(
-//             "无相册权限,前往设置",
-//             confirmAction: () {
-//               PhotoManager.openSetting();
-//             },
-//           ),
-//         );
-//       }
-//     } else {
-//       //Android是否有SD卡权限
-//       var status = await Permission.storage.status;
-//       late PermissionState ps;
-//       if (status.isGranted) {
-//         // 已经授权
-//         success();
-//       } else {
-//         // 未授权,则准备发起一次申请
-//         var permissionRequestFuture = PhotoManager.requestPermissionExtend();
-//
-//         // 延迟500毫秒的Future
-//         var delayFuture = Future.delayed(Duration(milliseconds: 500), () => 'delay');
-//
-//         // 使用Future.any等待上述两个Future中的任何一个完成
-//         var firstCompleted = await Future.any([permissionRequestFuture, delayFuture]);
-//
-//         // 判断响应结果
-//         if (firstCompleted == 'delay') {
-//           Log.d("判断响应结果:1");
-//           // 如果是延迟Future完成了,表示500毫秒内没有获得权限响应,显示对话框
-//           _showPermissionDialog("“YYBusiness”想访问你的多媒体相册 用于图片上传,图片保存等功能,请允许我获取您的权限");
-//           // 再次等待权限请求结果
-//           ps = await permissionRequestFuture;
-//           DialogEngine.dismiss(tag: "permission");
-//         } else {
-//           Log.d("判断响应结果:2");
-//           // 权限请求已完成,立刻取消对话框展示(如果已经展示的话)
-//           DialogEngine.dismiss(tag: "permission");
-//           ps = firstCompleted as PermissionState;
-//         }
-//
-//         if (ps.isAuth) {
-//           // 用户授权
-//           success();
-//         } else {
-//           // 权限被拒绝
-//           await DialogEngine.show(
-//             widget: AppDefaultDialog("请到您的手机设置打开相册的权限", title: "提醒", confirmText: "去设置", confirmAction: () {
-//               openAppSettings();
-//             }),
-//           );
-//         }
-//       }
-//     }
-//   }
-//
-//   /// 申请相机权限
-//   void requestCameraPermission(void Function() success) async {
-//     // 获取当前的权限
-//     var status = await Permission.camera.status;
-//     if (status.isGranted) {
-//       // 已经授权
-//       success();
-//     } else {
-//       // 未授权,则准备发起一次申请
-//       var permissionRequestFuture = Permission.camera.request();
-//
-//       // 延迟500毫秒的Future
-//       var delayFuture = Future.delayed(Duration(milliseconds: 500), () => 'delay');
-//
-//       // 使用Future.any等待上述两个Future中的任何一个完成
-//       var firstCompleted = await Future.any([permissionRequestFuture, delayFuture]);
-//
-//       // 判断响应结果
-//       if (firstCompleted == 'delay') {
-//         // 如果是延迟Future完成了,表示500毫秒内没有获得权限响应,显示对话框
-//         _showPermissionDialog("“YYBusiness”申请调用您的相机权限 用于使用拍摄头像,图片上传保存等功能,请允许我获取您的权限");
-//         // 再次等待权限请求结果
-//         status = await permissionRequestFuture;
-//         DialogEngine.dismiss(tag: "permission");
-//       } else {
-//         // 权限请求已完成,立刻取消对话框展示(如果已经展示的话)
-//         DialogEngine.dismiss(tag: "permission");
-//         status = firstCompleted as PermissionStatus;
-//       }
-//
-//       if (status.isGranted) {
-//         // 用户授权
-//         success();
-//       } else {
-//         // 权限被拒绝
-//         await DialogEngine.show(
-//           widget: AppDefaultDialog("请到您的手机设置打开相机的权限", title: "提醒", confirmText: "去设置", confirmAction: () {
-//             openAppSettings();
-//           }),
-//         );
-//       }
-//     }
-//   }
-//
-//   /// 校验并申请定位权限
-//   Future<bool> requestLocationPermission() async {
-//     // 获取当前的权限
-//     var status = await Permission.location.status;
-//     if (status.isGranted) {
-//       // 已经授权
-//       return true;
-//     } else {
-//       // 未授权,则准备发起一次申请
-//       var permissionRequestFuture = Permission.location.request();
-//
-//       // 延迟500毫秒的Future
-//       var delayFuture = Future.delayed(Duration(milliseconds: 500), () => 'delay');
-//
-//       // 使用Future.any等待上述两个Future中的任何一个完成
-//       var firstCompleted = await Future.any([permissionRequestFuture, delayFuture]);
-//
-//       // 判断响应结果
-//       if (firstCompleted == 'delay') {
-//         // 如果是延迟Future完成了,表示500毫秒内没有获得权限响应,显示对话框
-//         _showPermissionDialog("“YYBusiness”想访问您的定位权限获取您的位置来推荐附近的工作");
-//         // 再次等待权限请求结果
-//         status = await permissionRequestFuture;
-//         DialogEngine.dismiss(tag: "permission");
-//       } else {
-//         Log.d("权限请求已完成,立刻取消对话框展示");
-//         // 权限请求已完成,立刻取消对话框展示(如果已经展示的话)
-//         DialogEngine.dismiss(tag: "permission");
-//         status = firstCompleted as PermissionStatus;
-//       }
-//
-//       if (status.isGranted) {
-//         // 用户授权
-//         return true;
-//       } else {
-//         // 权限被拒绝
-//         await DialogEngine.show(
-//           widget: AppDefaultDialog("请到您的手机设置打开定位的权限", title: "提醒", confirmText: "去设置", confirmAction: () {
-//             openAppSettings();
-//           }),
-//         );
-//         return false;
-//       }
-//     }
-//   }
-//
-//   //顶部展示权限声明详情弹窗
-//   void _showPermissionDialog(String desc) {
-//     DialogEngine.show(
-//       clickMaskDismiss: false,
-//       backDismiss: true,
-//       tag: "permission",
-//       maskColor: Colors.transparent,
-//       widget: PermissionDescDialog(desc),
-//     );
-//   }
-// }
+import 'package:flutter/material.dart';
+import 'package:permission_handler/permission_handler.dart';
+import 'package:photo_manager/photo_manager.dart';
+import 'package:shared/utils/device_utils.dart';
+import 'package:shared/utils/log_utils.dart';
+import 'package:widgets/dialog/app_default_dialog.dart';
+import 'package:widgets/dialog/permission_desc_dialog.dart';
+
+import '../dialog/dialog_engine.dart';
+
+/*
+ * 动态权限的申请与校验
+ */
+class PermissionEngine {
+  // 私有构造函数
+  PermissionEngine._privateConstructor();
+
+  // 单例实例
+  static final PermissionEngine _instance = PermissionEngine._privateConstructor();
+
+  // 获取单例实例的访问点
+  factory PermissionEngine() {
+    return _instance;
+  }
+
+  /// 申请多媒体相册权限
+  void requestPhotosPermission(void Function() success) async {
+    //相册的选项
+    if (DeviceUtils.isIOS) {
+      //申请授权
+      final value = await PhotoManager.requestPermissionExtend();
+      if (value.hasAccess) {
+        //已授权
+        Log.d("相册已授权");
+        success();
+      } else if (value == PermissionState.limited) {
+        Log.d("相册访问受限,去设置受限");
+        PhotoManager.presentLimited();
+      } else {
+        Log.d("相册无授权,去设置");
+        DialogEngine.show(
+          widget: AppDefaultDialog(
+            title: "Alert",
+            message: 'No album permission, go to settings?',
+            confirmAction: () {
+              PhotoManager.openSetting();
+            },
+          ),
+        );
+      }
+    } else {
+      //Android是否有SD卡权限
+      var status = await Permission.storage.status;
+      late PermissionState ps;
+      if (status.isGranted) {
+        // 已经授权
+        success();
+      } else {
+        // 未授权,则准备发起一次申请
+        var permissionRequestFuture = PhotoManager.requestPermissionExtend();
+
+        // 延迟500毫秒的Future
+        var delayFuture = Future.delayed(const Duration(milliseconds: 500), () => 'delay');
+
+        // 使用Future.any等待上述两个Future中的任何一个完成
+        var firstCompleted = await Future.any([permissionRequestFuture, delayFuture]);
+
+        // 判断响应结果
+        if (firstCompleted == 'delay') {
+          Log.d("判断响应结果:1");
+          // 如果是延迟Future完成了,表示500毫秒内没有获得权限响应,显示对话框
+          _showPermissionDialog("“YY Employer” would like to access your multimedia album for functions such as image uploading and saving. Please allow me to obtain your permission");
+          // 再次等待权限请求结果
+          ps = await permissionRequestFuture;
+          DialogEngine.dismiss(tag: "permission");
+        } else {
+          Log.d("判断响应结果:2");
+          // 权限请求已完成,立刻取消对话框展示(如果已经展示的话)
+          DialogEngine.dismiss(tag: "permission");
+          ps = firstCompleted as PermissionState;
+        }
+
+        if (ps.isAuth) {
+          // 用户授权
+          success();
+        } else {
+          // 权限被拒绝
+          await DialogEngine.show(
+            widget: AppDefaultDialog(
+                message: "Please set the permission to open the photo album on your phone",
+                title: "Alert",
+                confirmAction: () {
+                  openAppSettings();
+                }),
+          );
+        }
+      }
+    }
+  }
+
+  /// 申请相机权限
+  void requestCameraPermission(void Function() success) async {
+    // 获取当前的权限
+    var status = await Permission.camera.status;
+    if (status.isGranted) {
+      // 已经授权
+      success();
+    } else {
+      // 未授权,则准备发起一次申请
+      var permissionRequestFuture = Permission.camera.request();
+
+      // 延迟500毫秒的Future
+      var delayFuture = Future.delayed(const Duration(milliseconds: 500), () => 'delay');
+
+      // 使用Future.any等待上述两个Future中的任何一个完成
+      var firstCompleted = await Future.any([permissionRequestFuture, delayFuture]);
+
+      // 判断响应结果
+      if (firstCompleted == 'delay') {
+        // 如果是延迟Future完成了,表示500毫秒内没有获得权限响应,显示对话框
+        _showPermissionDialog("“YY Employer” requests to use your camera permission for functions such as taking avatars, uploading and saving images. Please allow me to obtain your permission");
+        // 再次等待权限请求结果
+        status = await permissionRequestFuture;
+        DialogEngine.dismiss(tag: "permission");
+      } else {
+        // 权限请求已完成,立刻取消对话框展示(如果已经展示的话)
+        DialogEngine.dismiss(tag: "permission");
+        status = firstCompleted as PermissionStatus;
+      }
+
+      if (status.isGranted) {
+        // 用户授权
+        success();
+      } else {
+        // 权限被拒绝
+        await DialogEngine.show(
+          widget: AppDefaultDialog(
+              message: "Please set the permission to open the camera on your phone",
+              title: "Alert",
+              confirmAction: () {
+                openAppSettings();
+              }),
+        );
+      }
+    }
+  }
+
+  /// 校验并申请定位权限
+  Future<bool> requestLocationPermission() async {
+    // 获取当前的权限
+    var status = await Permission.location.status;
+    if (status.isGranted) {
+      // 已经授权
+      return true;
+    } else {
+      // 未授权,则准备发起一次申请
+      var permissionRequestFuture = Permission.location.request();
+
+      // 延迟500毫秒的Future
+      var delayFuture = Future.delayed(const Duration(milliseconds: 500), () => 'delay');
+
+      // 使用Future.any等待上述两个Future中的任何一个完成
+      var firstCompleted = await Future.any([permissionRequestFuture, delayFuture]);
+
+      // 判断响应结果
+      if (firstCompleted == 'delay') {
+        // 如果是延迟Future完成了,表示500毫秒内没有获得权限响应,显示对话框
+        _showPermissionDialog("“YY Employer” want to access your location permission to obtain your location and recommend nearby information");
+        // 再次等待权限请求结果
+        status = await permissionRequestFuture;
+        DialogEngine.dismiss(tag: "permission");
+      } else {
+        Log.d("权限请求已完成,立刻取消对话框展示");
+        // 权限请求已完成,立刻取消对话框展示(如果已经展示的话)
+        DialogEngine.dismiss(tag: "permission");
+        status = firstCompleted as PermissionStatus;
+      }
+
+      if (status.isGranted) {
+        // 用户授权
+        return true;
+      } else {
+        // 权限被拒绝
+        await DialogEngine.show(
+          widget: AppDefaultDialog(
+              message: "Please go to your phone settings to enable location permission",
+              title: "Alert",
+              confirmAction: () {
+                openAppSettings();
+              }),
+        );
+        return false;
+      }
+    }
+  }
+
+  /// 申请拨打电话权限
+  void requestCallPhonePermission(void Function() success) async {
+    // 获取当前的权限
+    var status = await Permission.phone.status;
+    if (status.isGranted) {
+      // 已经授权
+      success();
+    } else {
+      // 未授权,则准备发起一次申请
+      var permissionRequestFuture = Permission.phone.request();
+
+      // 延迟500毫秒的Future
+      var delayFuture = Future.delayed(const Duration(milliseconds: 500), () => 'delay');
+
+      // 使用Future.any等待上述两个Future中的任何一个完成
+      var firstCompleted = await Future.any([permissionRequestFuture, delayFuture]);
+
+      // 判断响应结果
+      if (firstCompleted == 'delay') {
+        // 如果是延迟Future完成了,表示500毫秒内没有获得权限响应,显示对话框
+        _showPermissionDialog("“YY Employer”requires permission to make phone calls for communication. Please allow access to this permission");
+        // 再次等待权限请求结果
+        status = await permissionRequestFuture;
+        DialogEngine.dismiss(tag: "permission");
+      } else {
+        // 权限请求已完成,立刻取消对话框展示(如果已经展示的话)
+        DialogEngine.dismiss(tag: "permission");
+        status = firstCompleted as PermissionStatus;
+      }
+
+      if (status.isGranted) {
+        // 用户授权
+        success();
+      } else {
+        // 权限被拒绝
+        await DialogEngine.show(
+          widget: AppDefaultDialog(
+              message: "Please go to your phone settings to enable phone calls permission",
+              title: "Alert",
+              confirmAction: () {
+                openAppSettings();
+              }),
+        );
+      }
+    }
+  }
+
+  //顶部展示权限声明详情弹窗
+  void _showPermissionDialog(String desc) {
+    DialogEngine.show(
+      clickMaskDismiss: false,
+      backDismiss: true,
+      tag: "permission",
+      maskColor: Colors.transparent,
+      widget: PermissionDescDialog(desc),
+    );
+  }
+}

+ 4 - 0
packages/cs_plugin_platform/lib/platform_export.dart

@@ -0,0 +1,4 @@
+export 'package:dio/dio.dart';
+export 'package:permission_handler/permission_handler.dart';
+export 'engine/image/image_nine_grid.dart';
+export 'engine/media/image_picker_utils.dart';

+ 5 - 5
packages/cs_plugin_platform/pubspec.yaml

@@ -35,23 +35,23 @@ dependencies:
   permission_handler: 11.3.1
 
   # 图片选择  https://github.com/fluttercandies/flutter_wechat_assets_picker/blob/main/README-ZH.md
-#  wechat_assets_picker: 9.0.2
+  wechat_assets_picker: ^9.2.2
   # 图片加载框架 https://github.com/fluttercandies/extended_image/blob/master/README-ZH.md
   # 封装在 MyLoadImage 控件中,推荐图片全部用 MyLoadImage
-  # wechat_assets_picker 内部已经依赖了 extended_image 框架!无需再次依赖
+  # wechatAssetsPicker 内部已经依赖了 extended_image 框架!无需再次依赖
 
   # 相机选择器 https://github.com/fluttercandies/flutter_wechat_camera_picker/blob/main/README-ZH.md
   # 与上面图片选择配套的相机模块,基于 wechat_assets_picker 与 camera 依赖实现的
-#  wechat_camera_picker: 4.2.1
+  wechat_camera_picker: ^4.3.4
 
   # 图片裁剪  https://github.com/hnvn/flutter_image_cropper
   # 与上面图片选择或相机拍照结合使用,裁剪图片为1:1或4:3或16:9的比例
-#  image_cropper: 5.0.1
+  image_cropper: 5.0.1
 
   # 图片压缩 https://github.com/fluttercandies/flutter_image_compress
   #          https://pub.dev/packages/flutter_image_compress
   # 用于最终的图片压缩,在网络请求上传文件的基类 ApiProvider 中统一处理图片的压缩逻辑,业务层不需要处理
-  flutter_image_compress: 2.2.0
+  flutter_image_compress: 2.3.0
 
   # 弹窗控件 https://github.com/CNAD666/flutter_smart_dialog
   # 内部包含吐司气泡 弹窗 下拉选等

BIN=BIN
packages/cs_resources/assets/agency/category_agency.webp


BIN=BIN
packages/cs_resources/assets/agency/category_contract.webp


BIN=BIN
packages/cs_resources/assets/agency/category_posotion.webp


BIN=BIN
packages/cs_resources/assets/agency/contract_file_icon.webp


BIN=BIN
packages/cs_resources/assets/base_service/image_add_icon.webp


+ 5 - 0
packages/cs_resources/lib/generated/assets.dart

@@ -2,6 +2,10 @@
 class Assets {
   Assets._();
 
+  static const String agencyCategoryAgency = 'assets/agency/category_agency.webp';
+  static const String agencyCategoryContract = 'assets/agency/category_contract.webp';
+  static const String agencyCategoryPosotion = 'assets/agency/category_posotion.webp';
+  static const String agencyContractFileIcon = 'assets/agency/contract_file_icon.webp';
   static const String assetsYyBusinessTopLogo = 'assets/yy_business_top_logo.webp';
   static const String baseLibBlackBack = 'assets/base_lib/black_back.webp';
   static const String baseLibDialogBlueDeleteIcon = 'assets/base_lib/dialog_blue_delete_icon.webp';
@@ -12,6 +16,7 @@ class Assets {
   static const String baseServiceCheckBoxChecked = 'assets/base_service/check_box_checked.webp';
   static const String baseServiceCheckBoxUncheck = 'assets/base_service/check_box_uncheck.webp';
   static const String baseServiceDialogDeleteIcon = 'assets/base_service/dialog_delete_icon.webp';
+  static const String baseServiceImageAddIcon = 'assets/base_service/image_add_icon.webp';
   static const String baseServiceItemSelectedIcon = 'assets/base_service/item_selected_icon.webp';
   static const String baseServiceItemUnselectedGrayIcon = 'assets/base_service/item_unselected_gray_icon.webp';
   static const String baseServiceItemUnselectedIcon = 'assets/base_service/item_unselected_icon.webp';

+ 35 - 0
packages/cs_resources/lib/local/language/en_US.dart

@@ -255,6 +255,41 @@ const Map<String, String> en_US = {
   'Completed Num': 'Completed Num',
   'Dashboard': 'Dashboard',
   'Agency': 'Agency',
+  'Agency List': 'Agency List',
+  'Contract Management': 'Contract Management',
+  'Position List': 'Position List',
+  'Agency Name': 'Agency Name',
+  'Add Agency': 'Add Agency',
+  'Edit Agency': 'Edit Agency',
+  'ACRA NO': 'ACRA NO',
+  'Person in Charge': 'Person in Charge',
+  'Company Address': 'Company Address',
+  'Contact Email': 'Contact Email',
+  'Add Contract': 'Add Contract',
+  'Edit Contract': 'Edit Contract',
+  'Contract Start Date': 'Contract Start Date',
+  'Contract End Date': 'Contract End Date',
+  'Attachment': 'Attachment',
+  'Inactive': 'Inactive',
+  'Contract': 'Contract',
+  'Are you sure you want to delete this agency?': 'Are you sure you want to delete this agency?',
+  'Are you sure you want to delete this position?': 'Are you sure you want to delete this position?',
+  'agency_position': 'Position',
+  'Add Position': 'Add Position',
+  'Edit Position': 'Edit Position',
+  'Choose Position': 'Choose Position',
+  'Weekdays': 'Weekdays',
+  'Weekends': 'Weekends',
+  'Monday': 'Monday',
+  'Tuesday': 'Tuesday',
+  'Wednesday': 'Wednesday',
+  'Thursday': 'Thursday',
+  'Friday': 'Friday',
+  'Saturday': 'Saturday',
+  'Sunday': 'Sunday',
+  'Eve of PH day': 'Eve of PH day',
+  'PH Days': 'PH Days',
+  'Contract Rate Management': 'Contract Rate Management',
 
   //插件的国际化
   'Pull to refresh': 'Pull to refresh',

+ 37 - 2
packages/cs_resources/lib/local/language/zh_CN.dart

@@ -50,7 +50,7 @@ const Map<String, String> zh_CN = {
   'Notice': '提示',
   'Are you sure you need to exit the system?': '你是否确定要退出系统?',
   'Are you sure you want to deactivate your account? You will not be able to login into the app once you proceed with the request.':
-  '你确定要停用你的帐户吗?一旦您继续请求,您将无法登录到该应用程序。',
+      '你确定要停用你的帐户吗?一旦您继续请求,您将无法登录到该应用程序。',
   'Welcome': '欢迎你',
   'Switch Projects': '切换项目',
   'Account Deactivation': '停用账户',
@@ -255,6 +255,41 @@ const Map<String, String> zh_CN = {
   'Completed Num': '完成人数',
   'Dashboard': '控制面板',
   'Agency': '中介',
+  'Agency List': '中介列表',
+  'Contract Management': '合同管理',
+  'Position List': '职位列表',
+  'Agency Name': '中介名称',
+  'Add Agency': '添加中介',
+  'Edit Agency': '编辑中介',
+  'ACRA NO': 'ACRA 编号',
+  'Person in Charge': '负责人',
+  'Company Address': '公司地址',
+  'Contact Email': '公司邮箱',
+  'Add Contract': '添加合同',
+  'Edit Contract': '编辑合同',
+  'Contract Start Date': '合同开始日期',
+  'Contract End Date': '合同结束日期',
+  'Attachment': '附件',
+  'Inactive': '不可用',
+  'Contract': '合同',
+  'Are you sure you want to delete this agency?': '你确定要删除此中介吗?',
+  'Are you sure you want to delete this position?': '你确定要删除此职位吗?',
+  'agency_position': '职位',
+  'Add Position': '添加职位',
+  'Edit Position': '编辑职位',
+  'Choose Position': '选择职位',
+  'Weekdays': '工作日',
+  'Weekends': '周末',
+  'Monday': '星期一',
+  'Tuesday': '星期二',
+  'Wednesday': '星期三',
+  'Thursday': '星期四',
+  'Friday': '星期五',
+  'Saturday': '星期六',
+  'Sunday': '星期天',
+  'Eve of PH day': '法定假日前夕',
+  'PH Days': '法定假日',
+  'Contract Rate Management': '合同时薪管理',
 
   //插件的国际化
   'Pull to refresh': '下拉刷新',
@@ -272,4 +307,4 @@ const Map<String, String> zh_CN = {
   'Click again and exit the app': '再次点击,退出应用',
   'The login credential have expired, please log in again.': '您的登录凭证已过期,请重新登录。',
   'Successful': '成功',
-};
+};

+ 1 - 0
packages/cs_resources/pubspec.yaml

@@ -28,3 +28,4 @@ flutter:
     - assets/cpt_job/
     - assets/cpt_report/
     - assets/main/
+    - assets/agency/

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

@@ -120,6 +120,19 @@ class RouterPath {
   static const SGAttendanceReviewList= '/sg/attendance/review/list';   //SG的考勤审核的操作流
   static const SGAttendanceReviewWorkflow= '/sg/attendance/review/workflow';   //SG的考勤审核的操作流
 
+  //新加坡的中介相关
+  static const SGAgencyCategory= '/sg/agency/category';   //SG的中介分类列表
+  static const SGAgencyList= '/sg/agency/list';   //SG的中介列表
+  static const SGAgencyAdd= '/sg/agency/add';   //SG的中介添加/编辑
+  static const SGContractList = '/sg/contract/list';   //SG的中介的合同管理列表
+  static const SGContractAdd = '/sg/contract/add';   //SG的中介的合同添加与编辑
+  static const SGContractRateList = '/sg/contract/rate/list';   //SG的中介的合同的时薪管理列表(算是合同详情)
+  static const SGContractRateSetting = '/sg/contract/rate/setting';   //SG的中介的合同的时薪添加或编辑
+  static const SGContractRateDayEdit = '/sg/contract/rate/date/edit';   //SG的中介的合同的时薪的具体日期列表
+  static const SGContractRateSpecificDay = '/sg/contract/rate/specific/day';   //SG的中介的合同的时薪的特色日子设置
+  static const SGPositionList = '/sg/position/list';   //SG的中介的职位列表
+  static const SGPositionAdd = '/sg/position/add';   //SG的中介的职位添加
+
   //Runalone
   static const runAloneMain = '/runalone/main'; //独立运行的入口页面