Browse Source

工作列表与工作列表的详情与编辑

liukai 7 months ago
parent
commit
12cc80fe14
28 changed files with 2583 additions and 11 deletions
  1. 1 1
      packages/cpt_auth/lib/modules/main/main_controller.dart
  2. 0 4
      packages/cpt_job/lib/modules/applied_staff_detail/staff_detail_widget.dart
  3. 271 0
      packages/cpt_labour_sg/lib/modules/job_list/job_list_controller.dart
  4. 361 0
      packages/cpt_labour_sg/lib/modules/job_list/job_list_filter.dart
  5. 258 0
      packages/cpt_labour_sg/lib/modules/job_list/job_list_item.dart
  6. 149 0
      packages/cpt_labour_sg/lib/modules/job_list/job_list_page.dart
  7. 15 0
      packages/cpt_labour_sg/lib/modules/job_list/job_list_state.dart
  8. 178 0
      packages/cpt_labour_sg/lib/modules/job_list_edit/job_list_edit_controller.dart
  9. 428 0
      packages/cpt_labour_sg/lib/modules/job_list_edit/job_list_edit_page.dart
  10. 53 0
      packages/cpt_labour_sg/lib/modules/job_list_edit/job_list_edit_state.dart
  11. 0 1
      packages/cpt_labour_sg/lib/modules/job_template_add/job_template_add_page.dart
  12. 6 0
      packages/cpt_labour_sg/lib/router/labour_sg_service_impl.dart
  13. 14 0
      packages/cpt_labour_sg/lib/router/page_router.dart
  14. 21 0
      packages/cs_domain/lib/constants/api_constants.dart
  15. 65 0
      packages/cs_domain/lib/entity/response/job_list_edit_index_s_g_entity.dart
  16. 45 0
      packages/cs_domain/lib/entity/response/job_list_index_s_g_entity.dart
  17. 57 0
      packages/cs_domain/lib/entity/response/job_list_s_g_entity.dart
  18. 27 0
      packages/cs_domain/lib/generated/json/base/json_convert_content.dart
  19. 165 0
      packages/cs_domain/lib/generated/json/job_list_edit_index_s_g_entity.g.dart
  20. 87 0
      packages/cs_domain/lib/generated/json/job_list_index_s_g_entity.g.dart
  21. 129 0
      packages/cs_domain/lib/generated/json/job_list_s_g_entity.g.dart
  22. 231 0
      packages/cs_domain/lib/repository/labour_sg_repository.dart
  23. 3 0
      packages/cs_resources/lib/local/language/en_US.dart
  24. 3 0
      packages/cs_resources/lib/local/language/vi_VN.dart
  25. 3 0
      packages/cs_resources/lib/local/language/zh_CN.dart
  26. 1 0
      packages/cs_router/lib/componentRouter/labour_sg_service.dart
  27. 2 0
      packages/cs_router/lib/path/router_path.dart
  28. 10 5
      packages/cs_widgets/lib/shatter/custom_radio_check.dart

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

@@ -129,7 +129,7 @@ class MainController extends GetxController {
         break;
       case 'jobList':
         if (ConfigService.to.curSelectCountry.value == 1) {
-          ToastEngine.show("进入新加坡的工作列表模块");
+          ComponentRouterServices.labourSGService.startJobListPage();
         } else {
           //越南的工作列表
           ComponentRouterServices.jobService.startJobListPage();

+ 0 - 4
packages/cpt_job/lib/modules/applied_staff_detail/staff_detail_widget.dart

@@ -1,14 +1,10 @@
 import 'package:cs_resources/constants/color_constants.dart';
-import 'package:cs_resources/generated/assets.dart';
 import 'package:domain/entity/response/staff_detail_entity.dart';
-import 'package:domain/entity/response/staff_labour_history_entity.dart';
 import 'package:flutter/cupertino.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter/widgets.dart';
 import 'package:plugin_basic/basic_export.dart';
-import 'package:shared/utils/util.dart';
 import 'package:widgets/ext/ex_widget.dart';
-import 'package:widgets/my_button.dart';
 import 'package:widgets/my_load_image.dart';
 import 'package:widgets/my_text_view.dart';
 

+ 271 - 0
packages/cpt_labour_sg/lib/modules/job_list/job_list_controller.dart

@@ -0,0 +1,271 @@
+import 'package:cpt_labour_sg/modules/labour_request_add/labour_request_add_page.dart';
+import 'package:domain/entity/response/job_list_entity.dart';
+import 'package:domain/entity/response/job_list_index_entity.dart';
+import 'package:domain/entity/response/job_list_index_s_g_entity.dart';
+import 'package:domain/entity/response/job_list_s_g_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:plugin_platform/http/http_result.dart';
+import 'package:shared/utils/date_time_utils.dart';
+import 'package:widgets/dialog/app_default_dialog.dart';
+import 'package:widgets/load_state_layout.dart';
+import 'package:widgets/widget_export.dart';
+
+import '../job_list_edit/job_list_edit_page.dart';
+import 'job_list_filter.dart';
+import 'job_list_state.dart';
+
+class JobListController extends GetxController with DioCancelableMixin {
+  final LabourSGRepository _jobRepository = Get.find();
+  final JobListState state = JobListState();
+
+  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;
+    fetchNotifyList();
+  }
+
+  // Refresh 加载事件
+  Future loadMore() async {
+    _curPage++;
+    fetchNotifyList();
+  }
+
+  // 重试请求
+  Future retryRequest() async {
+    _curPage = 1;
+    _needShowPlaceholder = true;
+    fetchNotifyList();
+  }
+
+  /// 获取服务器数据,通知消息列表
+  Future fetchNotifyList() async {
+    if (_needShowPlaceholder) {
+      changeLoadingState(LoadState.State_Loading);
+    }
+
+    // 并发执行两个请求
+    var futures = [
+      _jobRepository.fetchJobListTable(
+        DateTimeUtils.formatDate(state.selectedStartDate, format: "yyyy-MM-dd"),
+        DateTimeUtils.formatDate(state.selectedEndDate, format: "yyyy-MM-dd"),
+        state.selectedStatusId,
+        state.selectedOutletId,
+        curPage: _curPage,
+        cancelToken: cancelToken,
+      ),
+      state.indexOptions == null
+          ? _jobRepository.fetchJobListIndex(
+              cancelToken: cancelToken,
+            )
+          : Future(() => HttpResult(isSuccess: true).convert(data: state.indexOptions!)),
+    ];
+
+    //拿到结果
+    var results = await Future.wait(futures);
+    var listResult = results[0] as HttpResult<JobListSGEntity>;
+    var optionResult = results[1] as HttpResult<JobListIndexSGEntity>;
+
+    //选项数据
+    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<JobListSGRows>? 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 resetFiltering() {
+    state.selectedStartDate = null;
+    state.selectedEndDate = null;
+    state.selectedStatusId = null;
+    state.selectedOutletId = null;
+
+    //赋值之后刷新
+    refreshController.callRefresh();
+  }
+
+  //展示筛选的弹窗
+  void showFilterDialog() {
+    if (state.indexOptions != null) {
+      DialogEngine.show(
+        widget: JobListFilter(
+          optionResult: state.indexOptions!,
+          selectedStartDate: state.selectedStartDate,
+          selectedEndDate: state.selectedEndDate,
+          selectedStatusId: state.selectedStatusId,
+          selectedOutletId: state.selectedOutletId,
+          onFilterAction: (startDate, endDate, statusId, outletId) {
+            state.selectedStartDate = startDate;
+            state.selectedEndDate = endDate;
+            state.selectedStatusId = statusId;
+            state.selectedOutletId = outletId;
+
+            //赋值之后刷新
+            refreshController.callRefresh();
+          },
+        ),
+        position: DialogPosition.top,
+        animType: DialogAnimation.fade,
+      );
+    }
+  }
+
+  @override
+  void onReady() {
+    super.onReady();
+    fetchNotifyList();
+  }
+
+  @override
+  void onClose() {
+    state.datas.clear();
+    super.onClose();
+  }
+
+  /// 去详情页面
+  void gotoJobDetailPage(int index) {
+    JobListEditPage.startInstance(false, state.datas[index].jobId, null);
+  }
+
+  // 执行编辑操作
+  void doEditAction(int index) {
+    JobListEditPage.startInstance(true, state.datas[index].jobId, (result) {
+
+    });
+  }
+
+  /// 去已申请的成员列表
+  void gotoJobAppliedPage(int index) {
+    ToastEngine.show("去已申请的成员列表");
+  }
+
+  //执行取消操作
+  void doCancelAction(int index) {
+    DialogEngine.show(
+        widget: AppDefaultDialog(
+      title: "Confirmation".tr,
+      message: "Are you sure you want to cancel this job?".tr,
+      confirmAction: () {
+        _requestCancel(index);
+      },
+    ));
+  }
+
+  //执行删除操作
+  void doDeleteAction(int index) {
+    DialogEngine.show(
+        widget: AppDefaultDialog(
+      title: "Confirmation".tr,
+      message: "Are you sure you want to delete this job?".tr,
+      confirmAction: () {
+        _requestDeactivate(index);
+      },
+    ));
+  }
+
+  // 请求接口删除Job
+  void _requestDeactivate(int index) async {
+    final item = state.datas[index];
+    var result = await _jobRepository.deleteJobList(item.jobId, 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 _requestCancel(int index) async {
+    final item = state.datas[index];
+    var result = await _jobRepository.cancelJobList(item.jobId, cancelToken: cancelToken);
+
+    if (result.isSuccess) {
+      NotifyEngine.showSuccess("Successful".tr);
+
+      //todo 需要单个刷新啊
+    } else {
+      ToastEngine.show(result.errorMsg ?? "Network Load Error".tr);
+    }
+  }
+
+  //添加新的工作
+  void gotoLabourRequestAddPage() {
+    LabourRequestAddPage.startInstance((result) {
+      if (result is bool) {
+        //添加成功之后刷新
+        refreshController.callRefresh();
+      }
+    });
+  }
+}

+ 361 - 0
packages/cpt_labour_sg/lib/modules/job_list/job_list_filter.dart

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

+ 258 - 0
packages/cpt_labour_sg/lib/modules/job_list/job_list_item.dart

@@ -0,0 +1,258 @@
+import 'package:cs_resources/constants/color_constants.dart';
+import 'package:domain/entity/response/job_list_s_g_entity.dart';
+import 'package:flutter/cupertino.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter/widgets.dart';
+import 'package:plugin_basic/basic_export.dart';
+import 'package:widgets/ext/ex_widget.dart';
+import 'package:widgets/my_button.dart';
+import 'package:widgets/my_text_view.dart';
+
+/**
+ * 用工请求的主页面列表Item
+ */
+class JobListItem extends StatelessWidget {
+  final int index;
+  final JobListSGRows item;
+  final VoidCallback? onDetailAction;
+  final VoidCallback? onEditAction;
+  final VoidCallback? onCancelAction;
+  final VoidCallback? onDeleteAction;
+  final VoidCallback? onAppliedAction;
+
+  JobListItem({
+    required this.index,
+    required this.item,
+    this.onDetailAction,
+    this.onEditAction,
+    this.onCancelAction,
+    this.onDeleteAction,
+    this.onAppliedAction,
+  });
+
+  @override
+  Widget build(BuildContext context) {
+    return Container(
+      padding: EdgeInsets.symmetric(vertical: 23, horizontal: 21),
+      margin: EdgeInsets.only(left: 15, right: 15, top: 5, bottom: 5),
+      decoration: BoxDecoration(
+        color: Color(0xFF4DCFF6).withOpacity(0.2), // 设置背景颜色和不透明度
+        borderRadius: BorderRadius.circular(5), // 设置圆角
+      ),
+      child: Column(
+        mainAxisSize: MainAxisSize.max,
+        crossAxisAlignment: CrossAxisAlignment.start,
+        children: [
+          //工作标题
+          MyTextView(
+            item.jobTitle ?? "-",
+            isFontMedium: true,
+            textColor: ColorConstants.textYellowFFBB1B,
+            fontSize: 14,
+            textDecoration: TextDecoration.underline,
+            decorationColor: ColorConstants.textYellowFFBB1B,
+            // 可选,设置下划线的颜色
+            decorationThickness: 2.0,
+            // 可选,设置下划线的粗细
+            decorationStyle: TextDecorationStyle.solid, // 可选,设置下划线的样式
+          ),
+
+          // 工作日期
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "Job Date:".tr,
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+
+              //日期时间
+              MyTextView(
+                item.jobDate ?? "-",
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor: Colors.white,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ).marginOnly(top: 15),
+
+          // 部门
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "Outlet:".tr,
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+
+              //部门
+              MyTextView(
+                item.outletName ?? "-",
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor: Colors.white,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ).marginOnly(top: 15),
+
+          // 工作开始时间
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "Job Time".tr + ":",
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+
+              //日期时间
+              MyTextView(
+                "${item.startTime} - ${item.endTime}",
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor: Colors.white,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ).marginOnly(top: 15),
+
+          // 人数
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "No. of Staff:".tr,
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+
+              //人数
+              MyTextView(
+                item.hiringNum ?? "",
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor: ColorConstants.textYellowFFBB1B,
+                fontSize: 14,
+                onClick: onAppliedAction,
+              ).expanded(),
+            ],
+          ).marginOnly(top: 15),
+
+          // 状态
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "Status:".tr,
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+
+              //状态
+              MyTextView(
+                item.statusShow == null ? "" : item.statusShow!.tr,
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor: "Completed" == item.statusShow
+                    ? ColorConstants.textGreen05DC82
+                    : "Cancelled" == item.statusShow
+                        ? ColorConstants.textRedFF6262
+                        : "Revised" == item.statusShow || "Pending" == item.statusShow
+                            ? ColorConstants.textYellowFFBB1B
+                            : ColorConstants.textBlue06D9FF,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ).marginOnly(top: 15),
+
+          //按钮组
+          Visibility(
+            visible: item.actionList?.isNotEmpty ?? false,
+            child: Row(
+              mainAxisSize: MainAxisSize.max,
+              mainAxisAlignment: MainAxisAlignment.end,
+              crossAxisAlignment: CrossAxisAlignment.center,
+              children: [
+                //详情按钮
+                Visibility(
+                  visible: item.actionList.contains("detail"),
+                  child: MyButton(
+                    onPressed: () {
+                      FocusScope.of(context).unfocus();
+                      onDetailAction?.call();
+                    },
+                    text: "Detail".tr,
+                    textColor: ColorConstants.white,
+                    backgroundColor: ColorConstants.textYellowFFBB1B,
+                    radius: 17.25,
+                    minWidth: 60,
+                    minHeight: 35,
+                  ).marginOnly(left: 12),
+                ),
+                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),
+                ),
+                Visibility(
+                  visible: item.actionList.contains("cancel"),
+                  child: MyButton(
+                    onPressed: () {
+                      FocusScope.of(context).unfocus();
+                      onCancelAction?.call();
+                    },
+                    text: "Cancel".tr,
+                    textColor: ColorConstants.white,
+                    backgroundColor: ColorConstants.textYellowFFBB1B,
+                    radius: 17.25,
+                    minWidth: 60,
+                    minHeight: 35,
+                  ).marginOnly(left: 12),
+                ),
+                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: 18, bottom: 2),
+          ),
+        ],
+      ),
+    );
+  }
+}

+ 149 - 0
packages/cpt_labour_sg/lib/modules/job_list/job_list_page.dart

@@ -0,0 +1,149 @@
+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/widget_export.dart';
+
+import 'job_list_item.dart';
+import 'job_list_controller.dart';
+import 'job_list_state.dart';
+
+/**
+ * 新加坡的JobList其实就是Labour的查询
+ */
+class JobListPage extends BaseStatefulPage<JobListController> {
+  JobListPage({Key? key}) : super(key: key);
+
+  //启动当前页面
+  static void startInstance() {
+    return Get.start(RouterPath.JOB_LIST_SG);
+  }
+
+  @override
+  JobListController createRawController() {
+    return JobListController();
+  }
+
+  @override
+  State<JobListPage> createState() => _JobListState();
+}
+
+class _JobListState extends BaseState<JobListPage, JobListController> {
+  late JobListState state;
+
+  @override
+  void initState() {
+    super.initState();
+    state = controller.state;
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return autoCtlGetBuilder(builder: (controller) {
+      return Scaffold(
+        extendBodyBehindAppBar: true,
+        appBar: MyAppBar.appBar(context, "Job List".tr, actions: [
+          //筛选图标
+          MyAssetImage(
+            Assets.baseServiceTitleBarFilterIcon,
+            width: 24,
+            height: 16.5,
+          ).onTap(() {
+            FocusScope.of(context).unfocus();
+            controller.showFilterDialog();
+          }).marginOnly(right: 15),
+        ]),
+        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: Column(
+              children: [
+                //添加用工请求按钮
+                MyButton(
+                  type: ClickType.throttle,
+                  milliseconds: 500,
+                  onPressed: () {
+                    FocusScope.of(context).unfocus();
+                    controller.gotoLabourRequestAddPage();
+                  },
+                  text: "Create New Job".tr,
+                  textColor: ColorConstants.white,
+                  fontSize: 16,
+                  radius: 20,
+                  backgroundColor: hexToColor("#FFBB1B"),
+                  fontWeight: FontWeight.w500,
+                ).marginOnly(left: 15, right: 15, top: 15, bottom: 5),
+
+                //底部的列表
+                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 JobListItem(
+                            index: index,
+                            item: state.datas[index],
+                            onDetailAction: () {
+                              controller.gotoJobDetailPage(index);
+                            },
+                            onEditAction: () {
+                              controller.doEditAction(index);
+                            },
+                            onCancelAction: () {
+                              controller.doCancelAction(index);
+                            },
+                            onDeleteAction: () {
+                              controller.doDeleteAction(index);
+                            },
+                            onAppliedAction: () {
+                              controller.gotoJobAppliedPage(index);
+                            },
+                          );
+                        },
+                        childCount: state.datas.length,
+                      ))
+                    ],
+                  ),
+                ).marginOnly(top: 5, bottom: 5).expanded(),
+              ],
+            ),
+          ),
+        ),
+      );
+    });
+  }
+}

+ 15 - 0
packages/cpt_labour_sg/lib/modules/job_list/job_list_state.dart

@@ -0,0 +1,15 @@
+
+import 'package:domain/entity/response/job_list_index_s_g_entity.dart';
+import 'package:domain/entity/response/job_list_s_g_entity.dart';
+
+class JobListState {
+
+  DateTime? selectedStartDate;
+  DateTime? selectedEndDate;
+  String? selectedStatusId;
+  String? selectedOutletId;
+
+  //页面的列表数据
+  List<JobListSGRows> datas = [];
+  JobListIndexSGEntity? indexOptions;
+}

+ 178 - 0
packages/cpt_labour_sg/lib/modules/job_list_edit/job_list_edit_controller.dart

@@ -0,0 +1,178 @@
+import 'package:domain/repository/labour_sg_repository.dart';
+import 'package:flutter/cupertino.dart';
+import 'package:get/get.dart';
+import 'package:plugin_platform/engine/notify/notify_engine.dart';
+import 'package:plugin_platform/engine/toast/toast_engine.dart';
+import 'package:plugin_platform/http/dio/dio_cancelable_mixin.dart';
+import 'package:shared/utils/date_time_utils.dart';
+import 'package:shared/utils/util.dart';
+import 'package:widgets/picker/date_picker_util.dart';
+import 'package:widgets/picker/option_pick_util.dart';
+
+import 'job_list_edit_state.dart';
+
+class JobListEditController extends GetxController with DioCancelableMixin {
+  final LabourSGRepository _labourRepository = Get.find();
+  final JobListEditState state = JobListEditState();
+
+  // 获取添加选项数据
+  void fetchLabourRequestEditIndex() async {
+    var result = await _labourRepository.fetchJobListEditIndex(
+      state.jobId,
+      cancelToken: cancelToken,
+    );
+
+    if (result.isSuccess) {
+      state.editEntity = result.data;
+
+      var maleNoController = state.formData['need_male']!['controller'];
+      var femaleNoController = state.formData['need_female']!['controller'];
+      var needNoController = state.formData['need_no']!['controller'];
+      var remarkController = state.formData['remark']!['controller'];
+
+      //赋值展示
+      state.selectedOutlet = state.editEntity?.outletList.firstWhere((e) => e.selected == "selected").txt;
+      state.selectedOutletId = state.editEntity?.outletList.firstWhere((e) => e.selected == "selected").value;
+      state.genderOptionType = state.editEntity?.sexLimit ?? 0;
+      state.selectRequestTypeIndex = state.editEntity!.requestType.indexWhere((e) => e.checked == "checked");
+      
+      update();
+    } else {
+      ToastEngine.show(result.errorMsg ?? "Network Load Error".tr);
+    }
+  }
+
+  @override
+  void onReady() {
+    super.onReady();
+    fetchLabourRequestEditIndex();
+  }
+
+  //选择开始时间
+  void pickStartTime() {
+    if (state.editEntity == null) {
+      return;
+    }
+
+    DatePickerUtil.showCupertinoDatePicker(
+      selectedDateTime: state.selectedStartTime,
+      mode: CupertinoDatePickerMode.dateAndTime,
+      onDateTimeChanged: (date) {
+        state.selectedStartTime = date;
+        update();
+      },
+      title: "Start Time".tr,
+    );
+  }
+
+  // 选择结束时间
+  void pickEndTime() {
+    if (state.editEntity == null) {
+      return;
+    }
+
+    DatePickerUtil.showCupertinoDatePicker(
+      selectedDateTime: state.selectedEndTime ?? state.selectedStartTime,
+      mode: CupertinoDatePickerMode.dateAndTime,
+      onDateTimeChanged: (date) {
+        state.selectedEndTime = date;
+        update();
+      },
+      title: "End Time".tr,
+    );
+  }
+
+  //选择部门
+  void pickOutlet() {
+    if (state.editEntity == null) {
+      return;
+    }
+
+    int selectedIndex;
+    if (state.selectedOutletId == null) {
+      selectedIndex = 0;
+    } else {
+      selectedIndex = state.editEntity!.outletList.indexWhere((department) => department.value.toString() == state.selectedOutletId);
+    }
+
+    if (selectedIndex < 0) {
+      selectedIndex = 0;
+    }
+
+    OptionPickerUtil.showCupertinoOptionPicker(
+      items: state.editEntity!.outletList.map((e) => e.txt!).toList(growable: false),
+      initialSelectIndex: selectedIndex,
+      onPickerChanged: (_, index) {
+        state.selectedOutletId = state.editEntity!.outletList[index].value!.toString();
+        state.selectedOutlet = state.editEntity!.outletList[index].txt!.toString();
+        update();
+      },
+    );
+  }
+
+  // 提交表单
+  void doSubmit() async {
+    var maleNoController = state.formData['need_male']!['controller'];
+    var femaleNoController = state.formData['need_female']!['controller'];
+    var needNoController = state.formData['need_no']!['controller'];
+    var remarkController = state.formData['remark']!['controller'];
+
+    String maleNo = maleNoController.text.toString();
+    String femaleNo = femaleNoController.text.toString();
+    String needNo = needNoController.text.toString();
+    String remark = remarkController.text.toString();
+
+    if (state.selectedStartTime == null) {
+      ToastEngine.show("Select Job Start Time".tr);
+      return;
+    }
+
+    if (state.selectedEndTime == null) {
+      ToastEngine.show("Select Job End Time".tr);
+      return;
+    }
+
+    if (Utils.isEmpty(state.selectedOutletId)) {
+      ToastEngine.show("Choose Outlet".tr);
+      return;
+    }
+
+    if (state.genderOptionType == 0) {
+      if (Utils.isEmpty(needNo)) {
+        ToastEngine.show("Enter No. of Staff".tr);
+        return;
+      }
+    } else {
+      if (Utils.isEmpty(maleNo) || Utils.isEmpty(femaleNo)) {
+        ToastEngine.show("Enter No. of Staff of The Corresponding Gender".tr);
+        return;
+      }
+    }
+
+    var result = await _labourRepository.editJobListSubmit(
+      state.jobId,
+      DateTimeUtils.formatDate(state.selectedStartTime),
+      DateTimeUtils.formatDate(state.selectedEndTime),
+      state.selectedOutletId,
+      state.genderOptionType,
+      maleNo,
+      femaleNo,
+      needNo,
+      state.editEntity?.requestType[state.selectRequestTypeIndex].value,
+      remark,
+      cancelToken: cancelToken,
+    );
+
+    //处理数据
+    if (result.isSuccess) {
+      NotifyEngine.showSuccess("Successful".tr);
+
+      //根据类型刷新
+      state.cb?.call(true);
+
+      Get.back();
+    } else {
+      ToastEngine.show(result.errorMsg ?? "Network Load Error".tr);
+    }
+  }
+}

+ 428 - 0
packages/cpt_labour_sg/lib/modules/job_list_edit/job_list_edit_page.dart

@@ -0,0 +1,428 @@
+import 'package:cs_resources/constants/color_constants.dart';
+import 'package:cs_resources/generated/assets.dart';
+import 'package:flutter/cupertino.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter/services.dart';
+import 'package:flutter/widgets.dart';
+import 'package:get/get.dart';
+import 'package:shared/utils/date_time_utils.dart';
+import 'package:shared/utils/screen_util.dart';
+import 'package:widgets/ext/ex_widget.dart';
+import 'package:widgets/my_appbar.dart';
+import 'package:widgets/my_button.dart';
+import 'package:widgets/my_load_image.dart';
+import 'package:widgets/my_text_view.dart';
+import 'package:widgets/no_shadow_scroll_behavior.dart';
+import 'package:widgets/shatter/custom_radio_check.dart';
+import 'package:widgets/shatter/form_require_text.dart';
+import 'package:widgets/shatter/round_my_text_field.dart';
+import 'package:widgets/widget_export.dart';
+import 'job_list_edit_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 'job_list_edit_state.dart';
+
+/**
+ * 新加坡的工作详情,其实就是LabourRequest的详情和编辑
+ */
+class JobListEditPage extends BaseStatelessPage<JobListEditController> {
+  JobListEditPage({Key? key}) : super(key: key);
+
+  //启动当前页面
+  static void startInstance(bool isEditType, String? jobId, void Function(dynamic value)? cb) {
+    return Get.start(RouterPath.JOB_LIST_EDIT, arguments: {'isEditType': isEditType, 'jobId': jobId, 'cb': cb});
+  }
+
+  late JobListEditState state;
+
+  @override
+  void initState() {
+    state = controller.state;
+    state.isEditType = Get.arguments['isEditType'];
+    state.jobId = Get.arguments['jobId'];
+    state.cb = Get.arguments['cb'] as void Function(dynamic)?;
+  }
+
+  @override
+  JobListEditController createRawController() {
+    return JobListEditController();
+  }
+
+  @override
+  Widget buildWidget(BuildContext context) {
+    return autoCtlGetBuilder(builder: (controller) {
+      return Scaffold(
+        extendBodyBehindAppBar: true,
+        appBar: MyAppBar.appBar(context, state.isEditType ? "Edit".tr : "Detail".tr),
+        body: SafeArea(
+          bottom: true,
+          top: false,
+          child: Container(
+            width: double.infinity,
+            height: double.infinity,
+            padding: EdgeInsets.only(top: kToolbarHeight + ScreenUtil.getStatusBarH(context) + 1),
+            decoration: const BoxDecoration(
+              gradient: LinearGradient(
+                colors: [
+                  Color(0xFF091D44),
+                  Color(0xFF245A8A),
+                  Color(0xFF7F7CEC),
+                ],
+                begin: Alignment.topCenter,
+                end: Alignment.bottomCenter,
+              ),
+            ),
+            child: Scrollbar(
+              child: ScrollConfiguration(
+                behavior: NoShadowScrollBehavior(),
+                child: SingleChildScrollView(
+                  scrollDirection: Axis.vertical,
+                  physics: const BouncingScrollPhysics(),
+                  child: Column(
+                    crossAxisAlignment: CrossAxisAlignment.start,
+                    children: [
+                      //工作标题,选择模板
+                      FormRequireText(
+                        text: "Job Title".tr,
+                      ).marginOnly(top: 15),
+
+                      //工作标题
+                      Container(
+                        padding: EdgeInsets.only(left: 16, right: 10),
+                        margin: EdgeInsets.only(top: 10),
+                        height: 45,
+                        decoration: BoxDecoration(
+                          color: Color(0xFF4DCFF6).withOpacity(0.5),
+                          borderRadius: const BorderRadius.all(Radius.circular(5)),
+                        ),
+                        child: Row(
+                          mainAxisSize: MainAxisSize.max,
+                          crossAxisAlignment: CrossAxisAlignment.center,
+                          mainAxisAlignment: MainAxisAlignment.start,
+                          children: [
+                            MyTextView(
+                              state.editEntity?.jobTitle ?? "",
+                              fontSize: 14,
+                              textHintColor: ColorConstants.textGrayAECAE5,
+                              isFontMedium: true,
+                              textColor: ColorConstants.white,
+                            ).expanded(),
+                          ],
+                        ),
+                      ),
+
+                      //选择工作时间
+                      FormRequireText(
+                        text: "Job Time".tr,
+                      ).marginOnly(top: 15),
+
+                      Row(
+                        mainAxisSize: MainAxisSize.max,
+                        crossAxisAlignment: CrossAxisAlignment.center,
+                        mainAxisAlignment: MainAxisAlignment.start,
+                        children: [
+                          //选择开始时间
+                          Expanded(
+                            child: Container(
+                              padding: EdgeInsets.only(left: 16, right: 10),
+                              height: 45,
+                              decoration: BoxDecoration(
+                                color: Color(0xFF4DCFF6).withOpacity(state.isEditType ? 0.2 : 0.5),
+                                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 HH:mm"),
+                                    fontSize: 14,
+                                    hint: "Job Start Time".tr,
+                                    textHintColor: ColorConstants.textGrayAECAE5,
+                                    isFontMedium: true,
+                                    textColor: ColorConstants.white,
+                                  ).expanded(),
+                                  //下拉选图标
+                                  Visibility(
+                                    visible: state.isEditType,
+                                    child: MyAssetImage(Assets.baseServiceTriangleDropDownIcon, width: 11.5, height: 6.28),
+                                  ),
+                                ],
+                              ),
+                            ).onTap(() {
+                              FocusScope.of(context).unfocus();
+                              controller.pickStartTime();
+                            }),
+                          ),
+
+                          // //选择结束时间
+                          Expanded(
+                            child: Container(
+                              padding: EdgeInsets.only(left: 16, right: 10),
+                              margin: EdgeInsets.only(left: 10),
+                              height: 45,
+                              decoration: BoxDecoration(
+                                color: Color(0xFF4DCFF6).withOpacity(state.isEditType ? 0.2 : 0.5),
+                                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 HH:mm"),
+                                    fontSize: 14,
+                                    hint: "Job End Time".tr,
+                                    textHintColor: ColorConstants.textGrayAECAE5,
+                                    isFontMedium: true,
+                                    textColor: ColorConstants.white,
+                                  ).expanded(),
+                                  //下拉选图标
+                                  Visibility(
+                                    visible: state.isEditType,
+                                    child: MyAssetImage(Assets.baseServiceTriangleDropDownIcon, width: 11.5, height: 6.28),
+                                  ),
+                                ],
+                              ),
+                            ).onTap(() {
+                              FocusScope.of(context).unfocus();
+                              controller.pickEndTime();
+                            }),
+                          ),
+                        ],
+                      ).marginOnly(top: 10),
+
+                      //工作选择部门
+                      FormRequireText(
+                        text: "Outlet".tr,
+                      ).marginOnly(top: 15),
+
+                      //选择部门
+                      Container(
+                        padding: EdgeInsets.only(left: 16, right: 10),
+                        margin: EdgeInsets.only(top: 10),
+                        height: 45,
+                        decoration: BoxDecoration(
+                          color: Color(0xFF4DCFF6).withOpacity(state.isEditType ? 0.2 : 0.5),
+                          borderRadius: const BorderRadius.all(Radius.circular(5)),
+                        ),
+                        child: Row(
+                          mainAxisSize: MainAxisSize.max,
+                          crossAxisAlignment: CrossAxisAlignment.center,
+                          mainAxisAlignment: MainAxisAlignment.start,
+                          children: [
+                            MyTextView(
+                              state.selectedOutlet ?? "",
+                              fontSize: 14,
+                              hint: "Choose Outlet".tr,
+                              textHintColor: ColorConstants.textGrayAECAE5,
+                              isFontMedium: true,
+                              textColor: ColorConstants.white,
+                            ).expanded(),
+                            Visibility(
+                              visible: state.isEditType,
+                              child: MyAssetImage(Assets.baseServiceTriangleDropDownIcon, width: 11.5, height: 6.28),
+                            ),
+                          ],
+                        ),
+                      ).onTap(() {
+                        FocusScope.of(context).unfocus();
+                        controller.pickOutlet();
+                      }),
+
+                      //需要的人数
+                      FormRequireText(
+                        text: "No. of Staff".tr,
+                      ).marginOnly(top: 15),
+
+                      //选择人数类型单选
+                      CustomRadioCheck(
+                        options: state.editEntity?.limitList.map((e) => e.txt!).toList() ?? [],
+                        onOptionSelected: (index, text) {
+                          state.genderOptionType = index;
+                          controller.update();
+                        },
+                        enable: state.isEditType,
+                        selectedPosition: state.editEntity == null ? -1 : state.genderOptionType,
+                      ).marginOnly(top: 10),
+
+                      //输入框(只允许输入数字)
+                      Visibility(
+                        visible: state.genderOptionType == 0,
+                        child: CustomTextField(
+                          formKey: "need_no",
+                          marginLeft: 0,
+                          marginRight: 0,
+                          paddingTop: 0,
+                          paddingBottom: 0,
+                          height: 45,
+                          enabled: state.isEditType,
+                          fillBackgroundColor: Color(0xFF4DCFF6).withOpacity(state.isEditType ? 0.2 : 0.5),
+                          inputFormatters: <TextInputFormatter>[FilteringTextInputFormatter.digitsOnly],
+                          textInputType: TextInputType.number,
+                          formData: state.formData,
+                          textInputAction: TextInputAction.done,
+                          onSubmit: (key, value) {
+                            FocusScope.of(context).unfocus();
+                          },
+                          marginTop: 10,
+                        ),
+                      ),
+
+                      Visibility(
+                        visible: state.genderOptionType != 0,
+                        child: Row(
+                          children: [
+                            MyTextView(
+                              "Male".tr,
+                              fontSize: 15,
+                              isFontRegular: true,
+                              marginRight: 10,
+                              textColor: ColorConstants.textGrayAECAE5,
+                            ),
+                            CustomTextField(
+                              formKey: "need_male",
+                              marginLeft: 0,
+                              marginRight: 0,
+                              paddingTop: 0,
+                              paddingBottom: 0,
+                              height: 45,
+                              enabled: state.isEditType,
+                              fillBackgroundColor: Color(0xFF4DCFF6).withOpacity(state.isEditType ? 0.2 : 0.5),
+                              inputFormatters: <TextInputFormatter>[FilteringTextInputFormatter.digitsOnly],
+                              textInputType: TextInputType.number,
+                              formData: state.formData,
+                              textInputAction: TextInputAction.done,
+                              onSubmit: (key, value) {
+                                FocusScope.of(context).unfocus();
+                              },
+                            ).expanded(),
+                            MyTextView(
+                              "Female".tr,
+                              fontSize: 15,
+                              isFontRegular: true,
+                              marginLeft: 12,
+                              marginRight: 10,
+                              textColor: ColorConstants.textGrayAECAE5,
+                            ),
+                            CustomTextField(
+                              formKey: "need_female",
+                              marginLeft: 0,
+                              marginRight: 0,
+                              paddingTop: 0,
+                              paddingBottom: 0,
+                              height: 45,
+                              enabled: state.isEditType,
+                              fillBackgroundColor: Color(0xFF4DCFF6).withOpacity(state.isEditType ? 0.2 : 0.5),
+                              inputFormatters: <TextInputFormatter>[FilteringTextInputFormatter.digitsOnly],
+                              textInputType: TextInputType.number,
+                              formData: state.formData,
+                              textInputAction: TextInputAction.done,
+                              onSubmit: (key, value) {
+                                FocusScope.of(context).unfocus();
+                              },
+                            ).expanded(),
+                          ],
+                        ).marginOnly(top: 10),
+                      ),
+
+                      //Request Type
+                      MyTextView(
+                        "Request Type".tr,
+                        fontSize: 15,
+                        isFontRegular: true,
+                        textColor: Colors.white,
+                        marginTop: 15,
+                      ),
+
+                      //Request Type单选
+                      CustomRadioCheck(
+                        options: state.editEntity?.requestType.map((e) => e.txt!).toList() ?? [],
+                        onOptionSelected: (index, text) {
+                          state.selectRequestTypeIndex = index;
+                        },
+                        enable: state.isEditType,
+                        selectedPosition: state.editEntity == null ? -1 : state.selectRequestTypeIndex,
+                      ).marginOnly(top: 10),
+
+                      //输入Remark
+                      MyTextView(
+                        "Remark".tr,
+                        fontSize: 15,
+                        isFontRegular: true,
+                        textColor: Colors.white,
+                        marginTop: 15,
+                      ),
+
+                      IgnoreKeyboardDismiss(
+                        child: Container(
+                          height: 160,
+                          margin: EdgeInsets.only(top: 10),
+                          padding: EdgeInsets.symmetric(vertical: 15, horizontal: 15),
+                          decoration: BoxDecoration(
+                            color: Color(0xFF4DCFF6).withOpacity(state.isEditType ? 0.2 : 0.5),
+                            borderRadius: BorderRadius.all(Radius.circular(5)),
+                          ),
+                          child: TextField(
+                            cursorColor: ColorConstants.white,
+                            cursorWidth: 1.5,
+                            autofocus: false,
+                            enabled: state.isEditType,
+                            focusNode: state.formData["remark"]!['focusNode'],
+                            controller: state.formData["remark"]!['controller'],
+                            // 装饰
+                            decoration: InputDecoration(
+                              isDense: true,
+                              isCollapsed: true,
+                              border: InputBorder.none,
+                              hintText: state.formData["remark"]!['hintText'],
+                              hintStyle: TextStyle(
+                                color: ColorConstants.textGrayAECAE5,
+                                fontSize: 15.0,
+                                fontWeight: FontWeight.w400,
+                              ),
+                            ),
+                            style: TextStyle(
+                              color: ColorConstants.white,
+                              fontSize: 15.0,
+                              fontWeight: FontWeight.w400,
+                            ),
+                            // 键盘动作右下角图标
+                            textInputAction: TextInputAction.done,
+                            onSubmitted: (value) {
+                              FocusScope.of(context).unfocus();
+                            },
+                          ),
+                        ),
+                      ),
+
+                      //提交按钮
+                      MyButton(
+                        type: ClickType.throttle,
+                        milliseconds: 500,
+                        onPressed: () {
+                          FocusScope.of(context).unfocus();
+                          controller.doSubmit();
+                        },
+                        text: "Submit".tr,
+                        textColor: ColorConstants.white,
+                        fontSize: 16,
+                        radius: 22.5,
+                        backgroundColor: hexToColor("#FFBB1B"),
+                        fontWeight: FontWeight.w500,
+                      ).marginSymmetric(horizontal: 0, vertical: 30),
+                    ],
+                  ).paddingOnly(left: 15, right: 15),
+                ),
+              ),
+            ),
+          ),
+        ),
+      );
+    });
+  }
+}

+ 53 - 0
packages/cpt_labour_sg/lib/modules/job_list_edit/job_list_edit_state.dart

@@ -0,0 +1,53 @@
+import 'package:domain/entity/response/job_list_edit_index_s_g_entity.dart';
+import 'package:flutter/material.dart';
+import 'package:plugin_basic/basic_export.dart';
+
+class JobListEditState {
+  //表单的校验与数据
+  Map<String, Map<String, dynamic>> formData = {
+    'need_male': {
+      'value': '',
+      'controller': TextEditingController(),
+      'focusNode': FocusNode(),
+      'hintText': 'Needs Num'.tr,
+      'obsecure': false,
+    },
+    'need_female': {
+      'value': '',
+      'controller': TextEditingController(),
+      'focusNode': FocusNode(),
+      'hintText': 'Needs Num'.tr,
+      'obsecure': false,
+    },
+    'need_no': {
+      'value': '',
+      'controller': TextEditingController(),
+      'focusNode': FocusNode(),
+      'hintText': 'Needs Num'.tr,
+      'obsecure': false,
+    },
+    'remark': {
+      'value': '',
+      'controller': TextEditingController(),
+      'focusNode': FocusNode(),
+      'hintText': 'Enter...'.tr,
+      'obsecure': false,
+    },
+  };
+
+  bool isEditType = false;
+  String? jobId;
+  void Function(dynamic value)? cb;
+
+  int genderOptionType = 0;  //使用哪一种类型限制
+
+  JobListEditIndexSGEntity? editEntity;
+
+  DateTime? selectedStartTime;
+  DateTime? selectedEndTime;
+
+  String? selectedOutlet;
+  String? selectedOutletId;
+
+  int selectRequestTypeIndex = 0;
+}

+ 0 - 1
packages/cpt_labour_sg/lib/modules/job_template_add/job_template_add_page.dart

@@ -44,7 +44,6 @@ class JobTemplateAddPage extends BaseStatelessPage<JobTemplateAddController> {
     state = controller.state;
     state.templateId = Get.arguments['templateId'];
     state.cb = Get.arguments['cb'] as void Function(dynamic)?;
-    Log.d("templateId:${state.templateId} cb:${state.cb.toString()}");
   }
 
   @override

+ 6 - 0
packages/cpt_labour_sg/lib/router/labour_sg_service_impl.dart

@@ -1,3 +1,4 @@
+import 'package:cpt_labour_sg/modules/job_list/job_list_page.dart';
 import 'package:cpt_labour_sg/modules/job_title_list/job_title_list_page.dart';
 import 'package:cpt_labour_sg/modules/labour_request/labour_request_page.dart';
 import 'package:plugin_basic/basic_export.dart';
@@ -26,4 +27,9 @@ class LabourSGServiceImpl extends GetxService implements LabourSGService {
   void startJobTitlePage() {
     JobTitleListPage.startInstance();
   }
+
+  @override
+  void startJobListPage() {
+    JobListPage.startInstance();
+  }
 }

+ 14 - 0
packages/cpt_labour_sg/lib/router/page_router.dart

@@ -6,6 +6,8 @@ import 'package:flutter/material.dart';
 import 'package:get/get.dart';
 import 'package:router/path/router_path.dart';
 
+import '../modules/job_list/job_list_page.dart';
+import '../modules/job_list_edit/job_list_edit_page.dart';
 import '../modules/labour_request/labour_request_page.dart';
 import '../modules/labour_request_add/labour_request_add_page.dart';
 
@@ -44,5 +46,17 @@ class LabourSGPageRouter {
       page: () => LabourRequestAddPage(),
     ),
 
+    // 新加坡工作列表
+    GetPage(
+      name: RouterPath.JOB_LIST_SG,
+      page: () => JobListPage(),
+    ),
+
+    // 新加坡工作列表编辑
+    GetPage(
+      name: RouterPath.JOB_LIST_EDIT,
+      page: () => JobListEditPage(),
+    ),
+
   ];
 }

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

@@ -164,6 +164,27 @@ class ApiConstants {
   //用工请求的添加提交
   static const apiLabourRequestAddSubmitSG = "/index.php/api/v1/hotel/lab-req/add-submit";
 
+  //用工请求的查询选项(Job List)
+  static const apiJobListIndexSG = "/index.php/api/v1/hotel/job/index";
+
+  //用工请求的查询列表(Job List)
+  static const apiJobListTableSG = "/index.php/api/v1/hotel/job/table";
+
+  //用工请求的编辑详情(Job List)
+  static const apiJobListEditIndexSG = "/index.php/api/v1/hotel/job/edit-view";
+
+  //用工请求的编辑提交(Job List)
+  static const apiJobListEditSubmitSG = "/index.php/api/v1/hotel/job/edit-submit";
+
+  //用工请求的取消(Job List)
+  static const apiJobListCancelSG = "/index.php/api/v1/hotel/job/cancel";
+
+  //用工请求的删除(Job List)
+  static const apiJobListDeleteSG = "/index.php/api/v1/hotel/job/delete";
+
+  //用工请求的考勤确认(Job List)
+  static const apiJobListConfirmSG = "/index.php/api/v1/hotel/job/confirm";
+
   // =========================== 新加坡工作相关 ↓=========================================
 
 

+ 65 - 0
packages/cs_domain/lib/entity/response/job_list_edit_index_s_g_entity.dart

@@ -0,0 +1,65 @@
+import 'package:domain/generated/json/base/json_field.dart';
+import 'package:domain/generated/json/job_list_edit_index_s_g_entity.g.dart';
+import 'dart:convert';
+export 'package:domain/generated/json/job_list_edit_index_s_g_entity.g.dart';
+
+@JsonSerializable()
+class JobListEditIndexSGEntity {
+	@JSONField(name: "job_id")
+	String? jobId = null;
+	@JSONField(name: "job_title")
+	String? jobTitle = null;
+	@JSONField(name: "outlet_id")
+	int outletId = 0;
+	@JSONField(name: "req_type")
+	int reqType = 0;
+	@JSONField(name: "start_time")
+	String? startTime = null;
+	@JSONField(name: "end_time")
+	String? endTime = null;
+	@JSONField(name: "sex_limit")
+	int sexLimit = 0;
+	@JSONField(name: "male_limit")
+	int maleLimit = 0;
+	@JSONField(name: "female_limit")
+	int femaleLimit = 0;
+	@JSONField(name: "need_num")
+	int needNum = 0;
+	String? remark = null;
+	@JSONField(name: "outlet_list")
+	List<JobListEditIndexOption> outletList = [];
+	@JSONField(name: "request_type")
+	List<JobListEditIndexOption> requestType = [];
+	@JSONField(name: "limit_list")
+	List<JobListEditIndexOption> limitList = [];
+
+	JobListEditIndexSGEntity();
+
+	factory JobListEditIndexSGEntity.fromJson(Map<String, dynamic> json) => $JobListEditIndexSGEntityFromJson(json);
+
+	Map<String, dynamic> toJson() => $JobListEditIndexSGEntityToJson(this);
+
+	@override
+	String toString() {
+		return jsonEncode(this);
+	}
+}
+
+@JsonSerializable()
+class JobListEditIndexOption {
+	String? value = null;
+	String? txt = null;
+	String? selected = null;
+	String? checked = null;
+
+	JobListEditIndexOption();
+
+	factory JobListEditIndexOption.fromJson(Map<String, dynamic> json) => $JobListEditIndexOptionFromJson(json);
+
+	Map<String, dynamic> toJson() => $JobListEditIndexOptionToJson(this);
+
+	@override
+	String toString() {
+		return jsonEncode(this);
+	}
+}

+ 45 - 0
packages/cs_domain/lib/entity/response/job_list_index_s_g_entity.dart

@@ -0,0 +1,45 @@
+import 'package:domain/generated/json/base/json_field.dart';
+import 'package:domain/generated/json/job_list_index_s_g_entity.g.dart';
+import 'dart:convert';
+export 'package:domain/generated/json/job_list_index_s_g_entity.g.dart';
+
+@JsonSerializable()
+class JobListIndexSGEntity {
+  @JSONField(name: "start_date")
+  String? startDate = null;
+  @JSONField(name: "end_date")
+  String? endDate = null;
+  @JSONField(name: "outlet_list")
+  List<JobListIndexSGOption> outletList = [];
+  @JSONField(name: "status_list")
+  List<JobListIndexSGOption> statusList = [];
+
+  JobListIndexSGEntity();
+
+  factory JobListIndexSGEntity.fromJson(Map<String, dynamic> json) => $JobListIndexSGEntityFromJson(json);
+
+  Map<String, dynamic> toJson() => $JobListIndexSGEntityToJson(this);
+
+  @override
+  String toString() {
+    return jsonEncode(this);
+  }
+}
+
+@JsonSerializable()
+class JobListIndexSGOption {
+  String? value = null;
+  String? txt = null;
+  String? selected = null;
+
+  JobListIndexSGOption();
+
+  factory JobListIndexSGOption.fromJson(Map<String, dynamic> json) => $JobListIndexSGOptionFromJson(json);
+
+  Map<String, dynamic> toJson() => $JobListIndexSGOptionToJson(this);
+
+  @override
+  String toString() {
+    return jsonEncode(this);
+  }
+}

+ 57 - 0
packages/cs_domain/lib/entity/response/job_list_s_g_entity.dart

@@ -0,0 +1,57 @@
+import 'package:domain/generated/json/base/json_field.dart';
+import 'package:domain/generated/json/job_list_s_g_entity.g.dart';
+import 'dart:convert';
+export 'package:domain/generated/json/job_list_s_g_entity.g.dart';
+
+@JsonSerializable()
+class JobListSGEntity {
+	int total = 0;
+	List<JobListSGRows> rows = [];
+
+	JobListSGEntity();
+
+	factory JobListSGEntity.fromJson(Map<String, dynamic> json) => $JobListSGEntityFromJson(json);
+
+	Map<String, dynamic> toJson() => $JobListSGEntityToJson(this);
+
+	@override
+	String toString() {
+		return jsonEncode(this);
+	}
+}
+
+@JsonSerializable()
+class JobListSGRows {
+	@JSONField(name: "job_id")
+	String? jobId = null;
+	@JSONField(name: "job_date")
+	String? jobDate = null;
+	@JSONField(name: "outlet_name")
+	String? outletName = null;
+	@JSONField(name: "job_title")
+	String? jobTitle = null;
+	@JSONField(name: "start_time")
+	String? startTime = null;
+	@JSONField(name: "end_time")
+	String? endTime = null;
+	int status = 0;
+	@JSONField(name: "status_show")
+	String? statusShow = null;
+	@JSONField(name: "hiring_num")
+	String? hiringNum = null;
+	@JSONField(name: "created_at")
+	String? createdAt = null;
+	@JSONField(name: "action_list")
+	List<String> actionList = [];
+
+	JobListSGRows();
+
+	factory JobListSGRows.fromJson(Map<String, dynamic> json) => $JobListSGRowsFromJson(json);
+
+	Map<String, dynamic> toJson() => $JobListSGRowsToJson(this);
+
+	@override
+	String toString() {
+		return jsonEncode(this);
+	}
+}

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

@@ -16,9 +16,12 @@ import 'package:domain/entity/response/job_list_applied_staff_list_entity.dart';
 import 'package:domain/entity/response/job_list_applied_staff_search_entity.dart';
 import 'package:domain/entity/response/job_list_applied_work_flow_entity.dart';
 import 'package:domain/entity/response/job_list_detail_entity.dart';
+import 'package:domain/entity/response/job_list_edit_index_s_g_entity.dart';
 import 'package:domain/entity/response/job_list_entity.dart';
 import 'package:domain/entity/response/job_list_index_entity.dart';
+import 'package:domain/entity/response/job_list_index_s_g_entity.dart';
 import 'package:domain/entity/response/job_list_remark_view_entity.dart';
+import 'package:domain/entity/response/job_list_s_g_entity.dart';
 import 'package:domain/entity/response/job_template_edit_index_entity.dart';
 import 'package:domain/entity/response/job_template_s_g_entity.dart';
 import 'package:domain/entity/response/job_title_edit_index_entity.dart';
@@ -238,6 +241,12 @@ class JsonConvert {
     if (<JobListDetailDepartmentList>[] is M) {
       return data.map<JobListDetailDepartmentList>((Map<String, dynamic> e) => JobListDetailDepartmentList.fromJson(e)).toList() as M;
     }
+    if (<JobListEditIndexSGEntity>[] is M) {
+      return data.map<JobListEditIndexSGEntity>((Map<String, dynamic> e) => JobListEditIndexSGEntity.fromJson(e)).toList() as M;
+    }
+    if (<JobListEditIndexOption>[] is M) {
+      return data.map<JobListEditIndexOption>((Map<String, dynamic> e) => JobListEditIndexOption.fromJson(e)).toList() as M;
+    }
     if (<JobListEntity>[] is M) {
       return data.map<JobListEntity>((Map<String, dynamic> e) => JobListEntity.fromJson(e)).toList() as M;
     }
@@ -253,9 +262,21 @@ class JsonConvert {
     if (<JobListIndexStatusList>[] is M) {
       return data.map<JobListIndexStatusList>((Map<String, dynamic> e) => JobListIndexStatusList.fromJson(e)).toList() as M;
     }
+    if (<JobListIndexSGEntity>[] is M) {
+      return data.map<JobListIndexSGEntity>((Map<String, dynamic> e) => JobListIndexSGEntity.fromJson(e)).toList() as M;
+    }
+    if (<JobListIndexSGOption>[] is M) {
+      return data.map<JobListIndexSGOption>((Map<String, dynamic> e) => JobListIndexSGOption.fromJson(e)).toList() as M;
+    }
     if (<JobListRemarkViewEntity>[] is M) {
       return data.map<JobListRemarkViewEntity>((Map<String, dynamic> e) => JobListRemarkViewEntity.fromJson(e)).toList() as M;
     }
+    if (<JobListSGEntity>[] is M) {
+      return data.map<JobListSGEntity>((Map<String, dynamic> e) => JobListSGEntity.fromJson(e)).toList() as M;
+    }
+    if (<JobListSGRows>[] is M) {
+      return data.map<JobListSGRows>((Map<String, dynamic> e) => JobListSGRows.fromJson(e)).toList() as M;
+    }
     if (<JobTemplateEditIndexEntity>[] is M) {
       return data.map<JobTemplateEditIndexEntity>((Map<String, dynamic> e) => JobTemplateEditIndexEntity.fromJson(e)).toList() as M;
     }
@@ -404,12 +425,18 @@ class JsonConvertClassCollection {
     (JobListAppliedWorkFlowRecords).toString(): JobListAppliedWorkFlowRecords.fromJson,
     (JobListDetailEntity).toString(): JobListDetailEntity.fromJson,
     (JobListDetailDepartmentList).toString(): JobListDetailDepartmentList.fromJson,
+    (JobListEditIndexSGEntity).toString(): JobListEditIndexSGEntity.fromJson,
+    (JobListEditIndexOption).toString(): JobListEditIndexOption.fromJson,
     (JobListEntity).toString(): JobListEntity.fromJson,
     (JobListRows).toString(): JobListRows.fromJson,
     (JobListIndexEntity).toString(): JobListIndexEntity.fromJson,
     (JobListIndexDepartmentList).toString(): JobListIndexDepartmentList.fromJson,
     (JobListIndexStatusList).toString(): JobListIndexStatusList.fromJson,
+    (JobListIndexSGEntity).toString(): JobListIndexSGEntity.fromJson,
+    (JobListIndexSGOption).toString(): JobListIndexSGOption.fromJson,
     (JobListRemarkViewEntity).toString(): JobListRemarkViewEntity.fromJson,
+    (JobListSGEntity).toString(): JobListSGEntity.fromJson,
+    (JobListSGRows).toString(): JobListSGRows.fromJson,
     (JobTemplateEditIndexEntity).toString(): JobTemplateEditIndexEntity.fromJson,
     (JobTemplateEditIndexAgeList).toString(): JobTemplateEditIndexAgeList.fromJson,
     (JobTemplateEditIndexSexList).toString(): JobTemplateEditIndexSexList.fromJson,

+ 165 - 0
packages/cs_domain/lib/generated/json/job_list_edit_index_s_g_entity.g.dart

@@ -0,0 +1,165 @@
+import 'package:domain/generated/json/base/json_convert_content.dart';
+import 'package:domain/entity/response/job_list_edit_index_s_g_entity.dart';
+
+JobListEditIndexSGEntity $JobListEditIndexSGEntityFromJson(Map<String, dynamic> json) {
+  final JobListEditIndexSGEntity jobListEditIndexSGEntity = JobListEditIndexSGEntity();
+  final String? jobId = jsonConvert.convert<String>(json['job_id']);
+  if (jobId != null) {
+    jobListEditIndexSGEntity.jobId = jobId;
+  }
+  final String? jobTitle = jsonConvert.convert<String>(json['job_title']);
+  if (jobTitle != null) {
+    jobListEditIndexSGEntity.jobTitle = jobTitle;
+  }
+  final int? outletId = jsonConvert.convert<int>(json['outlet_id']);
+  if (outletId != null) {
+    jobListEditIndexSGEntity.outletId = outletId;
+  }
+  final int? reqType = jsonConvert.convert<int>(json['req_type']);
+  if (reqType != null) {
+    jobListEditIndexSGEntity.reqType = reqType;
+  }
+  final String? startTime = jsonConvert.convert<String>(json['start_time']);
+  if (startTime != null) {
+    jobListEditIndexSGEntity.startTime = startTime;
+  }
+  final String? endTime = jsonConvert.convert<String>(json['end_time']);
+  if (endTime != null) {
+    jobListEditIndexSGEntity.endTime = endTime;
+  }
+  final int? sexLimit = jsonConvert.convert<int>(json['sex_limit']);
+  if (sexLimit != null) {
+    jobListEditIndexSGEntity.sexLimit = sexLimit;
+  }
+  final int? maleLimit = jsonConvert.convert<int>(json['male_limit']);
+  if (maleLimit != null) {
+    jobListEditIndexSGEntity.maleLimit = maleLimit;
+  }
+  final int? femaleLimit = jsonConvert.convert<int>(json['female_limit']);
+  if (femaleLimit != null) {
+    jobListEditIndexSGEntity.femaleLimit = femaleLimit;
+  }
+  final int? needNum = jsonConvert.convert<int>(json['need_num']);
+  if (needNum != null) {
+    jobListEditIndexSGEntity.needNum = needNum;
+  }
+  final String? remark = jsonConvert.convert<String>(json['remark']);
+  if (remark != null) {
+    jobListEditIndexSGEntity.remark = remark;
+  }
+  final List<JobListEditIndexOption>? outletList = (json['outlet_list'] as List<dynamic>?)?.map(
+          (e) => jsonConvert.convert<JobListEditIndexOption>(e) as JobListEditIndexOption).toList();
+  if (outletList != null) {
+    jobListEditIndexSGEntity.outletList = outletList;
+  }
+  final List<JobListEditIndexOption>? requestType = (json['request_type'] as List<dynamic>?)?.map(
+          (e) => jsonConvert.convert<JobListEditIndexOption>(e) as JobListEditIndexOption).toList();
+  if (requestType != null) {
+    jobListEditIndexSGEntity.requestType = requestType;
+  }
+  final List<JobListEditIndexOption>? limitList = (json['limit_list'] as List<dynamic>?)?.map(
+          (e) => jsonConvert.convert<JobListEditIndexOption>(e) as JobListEditIndexOption).toList();
+  if (limitList != null) {
+    jobListEditIndexSGEntity.limitList = limitList;
+  }
+  return jobListEditIndexSGEntity;
+}
+
+Map<String, dynamic> $JobListEditIndexSGEntityToJson(JobListEditIndexSGEntity entity) {
+  final Map<String, dynamic> data = <String, dynamic>{};
+  data['job_id'] = entity.jobId;
+  data['job_title'] = entity.jobTitle;
+  data['outlet_id'] = entity.outletId;
+  data['req_type'] = entity.reqType;
+  data['start_time'] = entity.startTime;
+  data['end_time'] = entity.endTime;
+  data['sex_limit'] = entity.sexLimit;
+  data['male_limit'] = entity.maleLimit;
+  data['female_limit'] = entity.femaleLimit;
+  data['need_num'] = entity.needNum;
+  data['remark'] = entity.remark;
+  data['outlet_list'] = entity.outletList.map((v) => v.toJson()).toList();
+  data['request_type'] = entity.requestType.map((v) => v.toJson()).toList();
+  data['limit_list'] = entity.limitList.map((v) => v.toJson()).toList();
+  return data;
+}
+
+extension JobListEditIndexSGEntityExtension on JobListEditIndexSGEntity {
+  JobListEditIndexSGEntity copyWith({
+    String? jobId,
+    String? jobTitle,
+    int? outletId,
+    int? reqType,
+    String? startTime,
+    String? endTime,
+    int? sexLimit,
+    int? maleLimit,
+    int? femaleLimit,
+    int? needNum,
+    String? remark,
+    List<JobListEditIndexOption>? outletList,
+    List<JobListEditIndexOption>? requestType,
+    List<JobListEditIndexOption>? limitList,
+  }) {
+    return JobListEditIndexSGEntity()
+      ..jobId = jobId ?? this.jobId
+      ..jobTitle = jobTitle ?? this.jobTitle
+      ..outletId = outletId ?? this.outletId
+      ..reqType = reqType ?? this.reqType
+      ..startTime = startTime ?? this.startTime
+      ..endTime = endTime ?? this.endTime
+      ..sexLimit = sexLimit ?? this.sexLimit
+      ..maleLimit = maleLimit ?? this.maleLimit
+      ..femaleLimit = femaleLimit ?? this.femaleLimit
+      ..needNum = needNum ?? this.needNum
+      ..remark = remark ?? this.remark
+      ..outletList = outletList ?? this.outletList
+      ..requestType = requestType ?? this.requestType
+      ..limitList = limitList ?? this.limitList;
+  }
+}
+
+JobListEditIndexOption $JobListEditIndexOptionFromJson(Map<String, dynamic> json) {
+  final JobListEditIndexOption jobListEditIndexOption = JobListEditIndexOption();
+  final String? value = jsonConvert.convert<String>(json['value']);
+  if (value != null) {
+    jobListEditIndexOption.value = value;
+  }
+  final String? txt = jsonConvert.convert<String>(json['txt']);
+  if (txt != null) {
+    jobListEditIndexOption.txt = txt;
+  }
+  final String? selected = jsonConvert.convert<String>(json['selected']);
+  if (selected != null) {
+    jobListEditIndexOption.selected = selected;
+  }
+  final String? checked = jsonConvert.convert<String>(json['checked']);
+  if (checked != null) {
+    jobListEditIndexOption.checked = checked;
+  }
+  return jobListEditIndexOption;
+}
+
+Map<String, dynamic> $JobListEditIndexOptionToJson(JobListEditIndexOption entity) {
+  final Map<String, dynamic> data = <String, dynamic>{};
+  data['value'] = entity.value;
+  data['txt'] = entity.txt;
+  data['selected'] = entity.selected;
+  data['checked'] = entity.checked;
+  return data;
+}
+
+extension JobListEditIndexOptionExtension on JobListEditIndexOption {
+  JobListEditIndexOption copyWith({
+    String? value,
+    String? txt,
+    String? selected,
+    String? checked,
+  }) {
+    return JobListEditIndexOption()
+      ..value = value ?? this.value
+      ..txt = txt ?? this.txt
+      ..selected = selected ?? this.selected
+      ..checked = checked ?? this.checked;
+  }
+}

+ 87 - 0
packages/cs_domain/lib/generated/json/job_list_index_s_g_entity.g.dart

@@ -0,0 +1,87 @@
+import 'package:domain/generated/json/base/json_convert_content.dart';
+import 'package:domain/entity/response/job_list_index_s_g_entity.dart';
+
+JobListIndexSGEntity $JobListIndexSGEntityFromJson(Map<String, dynamic> json) {
+  final JobListIndexSGEntity jobListIndexSGEntity = JobListIndexSGEntity();
+  final String? startDate = jsonConvert.convert<String>(json['start_date']);
+  if (startDate != null) {
+    jobListIndexSGEntity.startDate = startDate;
+  }
+  final String? endDate = jsonConvert.convert<String>(json['end_date']);
+  if (endDate != null) {
+    jobListIndexSGEntity.endDate = endDate;
+  }
+  final List<JobListIndexSGOption>? outletList = (json['outlet_list'] as List<dynamic>?)?.map(
+          (e) => jsonConvert.convert<JobListIndexSGOption>(e) as JobListIndexSGOption).toList();
+  if (outletList != null) {
+    jobListIndexSGEntity.outletList = outletList;
+  }
+  final List<JobListIndexSGOption>? statusList = (json['status_list'] as List<dynamic>?)?.map(
+          (e) => jsonConvert.convert<JobListIndexSGOption>(e) as JobListIndexSGOption).toList();
+  if (statusList != null) {
+    jobListIndexSGEntity.statusList = statusList;
+  }
+  return jobListIndexSGEntity;
+}
+
+Map<String, dynamic> $JobListIndexSGEntityToJson(JobListIndexSGEntity entity) {
+  final Map<String, dynamic> data = <String, dynamic>{};
+  data['start_date'] = entity.startDate;
+  data['end_date'] = entity.endDate;
+  data['outlet_list'] = entity.outletList.map((v) => v.toJson()).toList();
+  data['status_list'] = entity.statusList.map((v) => v.toJson()).toList();
+  return data;
+}
+
+extension JobListIndexSGEntityExtension on JobListIndexSGEntity {
+  JobListIndexSGEntity copyWith({
+    String? startDate,
+    String? endDate,
+    List<JobListIndexSGOption>? outletList,
+    List<JobListIndexSGOption>? statusList,
+  }) {
+    return JobListIndexSGEntity()
+      ..startDate = startDate ?? this.startDate
+      ..endDate = endDate ?? this.endDate
+      ..outletList = outletList ?? this.outletList
+      ..statusList = statusList ?? this.statusList;
+  }
+}
+
+JobListIndexSGOption $JobListIndexSGOptionFromJson(Map<String, dynamic> json) {
+  final JobListIndexSGOption jobListIndexSGOption = JobListIndexSGOption();
+  final String? value = jsonConvert.convert<String>(json['value']);
+  if (value != null) {
+    jobListIndexSGOption.value = value;
+  }
+  final String? txt = jsonConvert.convert<String>(json['txt']);
+  if (txt != null) {
+    jobListIndexSGOption.txt = txt;
+  }
+  final String? selected = jsonConvert.convert<String>(json['selected']);
+  if (selected != null) {
+    jobListIndexSGOption.selected = selected;
+  }
+  return jobListIndexSGOption;
+}
+
+Map<String, dynamic> $JobListIndexSGOptionToJson(JobListIndexSGOption entity) {
+  final Map<String, dynamic> data = <String, dynamic>{};
+  data['value'] = entity.value;
+  data['txt'] = entity.txt;
+  data['selected'] = entity.selected;
+  return data;
+}
+
+extension JobListIndexSGOptionExtension on JobListIndexSGOption {
+  JobListIndexSGOption copyWith({
+    String? value,
+    String? txt,
+    String? selected,
+  }) {
+    return JobListIndexSGOption()
+      ..value = value ?? this.value
+      ..txt = txt ?? this.txt
+      ..selected = selected ?? this.selected;
+  }
+}

+ 129 - 0
packages/cs_domain/lib/generated/json/job_list_s_g_entity.g.dart

@@ -0,0 +1,129 @@
+import 'package:domain/generated/json/base/json_convert_content.dart';
+import 'package:domain/entity/response/job_list_s_g_entity.dart';
+
+JobListSGEntity $JobListSGEntityFromJson(Map<String, dynamic> json) {
+  final JobListSGEntity jobListSGEntity = JobListSGEntity();
+  final int? total = jsonConvert.convert<int>(json['total']);
+  if (total != null) {
+    jobListSGEntity.total = total;
+  }
+  final List<JobListSGRows>? rows = (json['rows'] as List<dynamic>?)?.map(
+          (e) => jsonConvert.convert<JobListSGRows>(e) as JobListSGRows).toList();
+  if (rows != null) {
+    jobListSGEntity.rows = rows;
+  }
+  return jobListSGEntity;
+}
+
+Map<String, dynamic> $JobListSGEntityToJson(JobListSGEntity entity) {
+  final Map<String, dynamic> data = <String, dynamic>{};
+  data['total'] = entity.total;
+  data['rows'] = entity.rows.map((v) => v.toJson()).toList();
+  return data;
+}
+
+extension JobListSGEntityExtension on JobListSGEntity {
+  JobListSGEntity copyWith({
+    int? total,
+    List<JobListSGRows>? rows,
+  }) {
+    return JobListSGEntity()
+      ..total = total ?? this.total
+      ..rows = rows ?? this.rows;
+  }
+}
+
+JobListSGRows $JobListSGRowsFromJson(Map<String, dynamic> json) {
+  final JobListSGRows jobListSGRows = JobListSGRows();
+  final String? jobId = jsonConvert.convert<String>(json['job_id']);
+  if (jobId != null) {
+    jobListSGRows.jobId = jobId;
+  }
+  final String? jobDate = jsonConvert.convert<String>(json['job_date']);
+  if (jobDate != null) {
+    jobListSGRows.jobDate = jobDate;
+  }
+  final String? outletName = jsonConvert.convert<String>(json['outlet_name']);
+  if (outletName != null) {
+    jobListSGRows.outletName = outletName;
+  }
+  final String? jobTitle = jsonConvert.convert<String>(json['job_title']);
+  if (jobTitle != null) {
+    jobListSGRows.jobTitle = jobTitle;
+  }
+  final String? startTime = jsonConvert.convert<String>(json['start_time']);
+  if (startTime != null) {
+    jobListSGRows.startTime = startTime;
+  }
+  final String? endTime = jsonConvert.convert<String>(json['end_time']);
+  if (endTime != null) {
+    jobListSGRows.endTime = endTime;
+  }
+  final int? status = jsonConvert.convert<int>(json['status']);
+  if (status != null) {
+    jobListSGRows.status = status;
+  }
+  final String? statusShow = jsonConvert.convert<String>(json['status_show']);
+  if (statusShow != null) {
+    jobListSGRows.statusShow = statusShow;
+  }
+  final String? hiringNum = jsonConvert.convert<String>(json['hiring_num']);
+  if (hiringNum != null) {
+    jobListSGRows.hiringNum = hiringNum;
+  }
+  final String? createdAt = jsonConvert.convert<String>(json['created_at']);
+  if (createdAt != null) {
+    jobListSGRows.createdAt = createdAt;
+  }
+  final List<String>? actionList = (json['action_list'] as List<dynamic>?)?.map(
+          (e) => jsonConvert.convert<String>(e) as String).toList();
+  if (actionList != null) {
+    jobListSGRows.actionList = actionList;
+  }
+  return jobListSGRows;
+}
+
+Map<String, dynamic> $JobListSGRowsToJson(JobListSGRows entity) {
+  final Map<String, dynamic> data = <String, dynamic>{};
+  data['job_id'] = entity.jobId;
+  data['job_date'] = entity.jobDate;
+  data['outlet_name'] = entity.outletName;
+  data['job_title'] = entity.jobTitle;
+  data['start_time'] = entity.startTime;
+  data['end_time'] = entity.endTime;
+  data['status'] = entity.status;
+  data['status_show'] = entity.statusShow;
+  data['hiring_num'] = entity.hiringNum;
+  data['created_at'] = entity.createdAt;
+  data['action_list'] = entity.actionList;
+  return data;
+}
+
+extension JobListSGRowsExtension on JobListSGRows {
+  JobListSGRows copyWith({
+    String? jobId,
+    String? jobDate,
+    String? outletName,
+    String? jobTitle,
+    String? startTime,
+    String? endTime,
+    int? status,
+    String? statusShow,
+    String? hiringNum,
+    String? createdAt,
+    List<String>? actionList,
+  }) {
+    return JobListSGRows()
+      ..jobId = jobId ?? this.jobId
+      ..jobDate = jobDate ?? this.jobDate
+      ..outletName = outletName ?? this.outletName
+      ..jobTitle = jobTitle ?? this.jobTitle
+      ..startTime = startTime ?? this.startTime
+      ..endTime = endTime ?? this.endTime
+      ..status = status ?? this.status
+      ..statusShow = statusShow ?? this.statusShow
+      ..hiringNum = hiringNum ?? this.hiringNum
+      ..createdAt = createdAt ?? this.createdAt
+      ..actionList = actionList ?? this.actionList;
+  }
+}

+ 231 - 0
packages/cs_domain/lib/repository/labour_sg_repository.dart

@@ -1,5 +1,7 @@
 import 'dart:typed_data';
 
+import 'package:domain/entity/response/job_list_edit_index_s_g_entity.dart';
+import 'package:domain/entity/response/job_list_index_s_g_entity.dart';
 import 'package:domain/entity/response/job_template_edit_index_entity.dart';
 import 'package:domain/entity/response/job_template_s_g_entity.dart';
 import 'package:domain/entity/response/job_title_edit_index_entity.dart';
@@ -13,6 +15,7 @@ import 'package:plugin_platform/http/http_result.dart';
 import 'package:shared/utils/util.dart';
 
 import '../constants/api_constants.dart';
+import '../entity/response/job_list_s_g_entity.dart';
 
 /// 用工相关(新加坡)
 class LabourSGRepository extends GetxService {
@@ -621,4 +624,232 @@ class LabourSGRepository extends GetxService {
     }
     return result.convert();
   }
+
+  //用工请求的查询选项(Job List)
+  Future<HttpResult<JobListIndexSGEntity>> fetchJobListIndex({
+    CancelToken? cancelToken,
+  }) async {
+    final result = await httpProvider.requestNetResult(
+      ApiConstants.apiJobListIndexSG,
+      cancelToken: cancelToken,
+    );
+
+    //根据返回的结果,封装原始数据为Bean/Entity对象
+    if (result.isSuccess) {
+      //重新赋值data或list
+      final json = result.getDataJson();
+      var data = JobListIndexSGEntity.fromJson(json!);
+      //重新赋值data或list
+      return result.convert<JobListIndexSGEntity>(data: data);
+    }
+    return result.convert();
+  }
+
+  //用工请求的查询列表(Job List)
+  Future<HttpResult<JobListSGEntity>> fetchJobListTable(
+    String? startDate,
+    String? endDate,
+    String? status,
+    String? outletId, {
+    required int curPage,
+    CancelToken? cancelToken,
+  }) async {
+    Map<String, String> params = {};
+
+    if (Utils.isNotEmpty(startDate)) {
+      params['start_date'] = startDate ?? "";
+    }
+
+    if (Utils.isNotEmpty(endDate)) {
+      params['end_date'] = endDate ?? "";
+    }
+
+    if (Utils.isNotEmpty(status)) {
+      params['status'] = status ?? "";
+    }
+
+    if (Utils.isNotEmpty(outletId)) {
+      params['outlet_id'] = outletId ?? "";
+    }
+
+    params['cur_page'] = curPage.toString();
+    params['page_size'] = "10";
+
+    final result = await httpProvider.requestNetResult(
+      ApiConstants.apiJobListTableSG,
+      params: params,
+      cancelToken: cancelToken,
+    );
+
+    //根据返回的结果,封装原始数据为Bean/Entity对象
+    if (result.isSuccess) {
+      //重新赋值data或list
+      final json = result.getDataJson();
+      var data = JobListSGEntity.fromJson(json!);
+      //重新赋值data或list
+      return result.convert<JobListSGEntity>(data: data);
+    }
+    return result.convert();
+  }
+
+  //用工请求的编辑详情(Job List)
+  Future<HttpResult<JobListEditIndexSGEntity>> fetchJobListEditIndex(
+    String? jobId, {
+    CancelToken? cancelToken,
+  }) async {
+    Map<String, String> params = {};
+    params['job_id'] = jobId ?? "";
+
+    final result = await httpProvider.requestNetResult(
+      ApiConstants.apiJobListEditIndexSG,
+      params: params,
+      isShowLoadingDialog: true,
+      cancelToken: cancelToken,
+    );
+
+    //根据返回的结果,封装原始数据为Bean/Entity对象
+    if (result.isSuccess) {
+      //重新赋值data或list
+      final json = result.getDataJson();
+      var data = JobListEditIndexSGEntity.fromJson(json!);
+      //重新赋值data或list
+      return result.convert<JobListEditIndexSGEntity>(data: data);
+    }
+    return result.convert();
+  }
+
+  //用工请求的编辑提交(Job List)
+  Future<HttpResult> editJobListSubmit(
+    String? jobId,
+    String? startTime,
+    String? endTime,
+    String? outletId,
+    int sexLimit,
+    String? maleLimit,
+    String? femaleLimit,
+    String? needNum,
+    String? requestType,
+    String? remark, {
+    CancelToken? cancelToken,
+  }) async {
+    //参数
+    Map<String, String> params = {};
+
+    params['job_id'] = jobId ?? "";
+    params['start_time'] = startTime ?? "";
+    params['end_time'] = endTime ?? "";
+    params['outlet_id'] = outletId ?? "";
+
+    params['sexLimit'] = sexLimit.toString();
+
+    if (sexLimit == 1) {
+      params['male_limit'] = maleLimit ?? "0";
+      params['female_limit'] = femaleLimit ?? "0";
+      params['need_num'] = (int.parse(maleLimit ?? "0") + int.parse(femaleLimit ?? "0")).toString();
+    } else {
+      params['need_num'] = needNum ?? "0";
+    }
+
+    if (Utils.isNotEmpty(requestType)) {
+      params['request_type'] = requestType ?? "";
+    }
+
+    if (Utils.isNotEmpty(remark)) {
+      params['remark'] = remark ?? "";
+    }
+
+    final result = await httpProvider.requestNetResult(
+      ApiConstants.apiJobListEditSubmitSG,
+      method: HttpMethod.POST,
+      params: params,
+      networkDebounce: true,
+      isShowLoadingDialog: true,
+      cancelToken: cancelToken,
+    );
+
+    //根据返回的结果,封装原始数据为Bean/Entity对象
+    if (result.isSuccess) {
+      //重新赋值data或list
+      return result.convert();
+    }
+    return result.convert();
+  }
+
+  //用工请求的取消(Job List)
+  Future<HttpResult> cancelJobList(
+    String? jobId, {
+    CancelToken? cancelToken,
+  }) async {
+    //参数
+    Map<String, String> params = {};
+    params['job_id'] = jobId ?? "";
+
+    final result = await httpProvider.requestNetResult(
+      ApiConstants.apiJobListCancelSG,
+      method: HttpMethod.POST,
+      params: params,
+      networkDebounce: true,
+      isShowLoadingDialog: true,
+      cancelToken: cancelToken,
+    );
+
+    //根据返回的结果,封装原始数据为Bean/Entity对象
+    if (result.isSuccess) {
+      //重新赋值data或list
+      return result.convert();
+    }
+    return result.convert();
+  }
+
+  //用工请求的删除(Job List)
+  Future<HttpResult> deleteJobList(
+    String? jobId, {
+    CancelToken? cancelToken,
+  }) async {
+    //参数
+    Map<String, String> params = {};
+    params['job_id'] = jobId ?? "";
+
+    final result = await httpProvider.requestNetResult(
+      ApiConstants.apiJobListDeleteSG,
+      method: HttpMethod.POST,
+      params: params,
+      networkDebounce: true,
+      isShowLoadingDialog: true,
+      cancelToken: cancelToken,
+    );
+
+    //根据返回的结果,封装原始数据为Bean/Entity对象
+    if (result.isSuccess) {
+      //重新赋值data或list
+      return result.convert();
+    }
+    return result.convert();
+  }
+
+  //用工请求的考勤确认(Job List)
+  Future<HttpResult> confirmJobList(
+    String? jobId, {
+    CancelToken? cancelToken,
+  }) async {
+    //参数
+    Map<String, String> params = {};
+    params['job_id'] = jobId ?? "";
+
+    final result = await httpProvider.requestNetResult(
+      ApiConstants.apiJobListConfirmSG,
+      method: HttpMethod.POST,
+      params: params,
+      networkDebounce: true,
+      isShowLoadingDialog: true,
+      cancelToken: cancelToken,
+    );
+
+    //根据返回的结果,封装原始数据为Bean/Entity对象
+    if (result.isSuccess) {
+      //重新赋值data或list
+      return result.convert();
+    }
+    return result.convert();
+  }
 }

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

@@ -196,6 +196,9 @@ const Map<String, String> en_US = {
   'Needs Num': 'Needs Num',
   'Request Type': 'Request Type',
   'Remark': 'Remark',
+  'Are you sure you want to cancel this job?': 'Are you sure you want to cancel this job?',
+  'Are you sure you want to delete this job?': 'Are you sure you want to delete this job?',
+  'Are you sure you want to confirm this job?': 'Are you sure you want to confirm this job?',
 
   //插件的国际化
   'Pull to refresh': 'Pull to refresh',

+ 3 - 0
packages/cs_resources/lib/local/language/vi_VN.dart

@@ -196,6 +196,9 @@ const Map<String, String> vi_VN = {
   'Needs Num': 'Số lượng cần thiết',
   'Request Type': 'Loại yêu cầu',
   'Remark': 'Ghi chú',
+  'Are you sure you want to cancel this job?': 'Bạn có chắc chắn muốn hủy bỏ công việc này?',
+  'Are you sure you want to delete this job?': 'Bạn có chắc chắn muốn xóa công việc này?',
+  'Are you sure you want to confirm this job?': 'Bạn có chắc chắn muốn xác nhận công việc này?',
 
   //插件的国际化
   "Pull to refresh": "Kéo để làm mới",

+ 3 - 0
packages/cs_resources/lib/local/language/zh_CN.dart

@@ -196,6 +196,9 @@ const Map<String, String> zh_CN = {
   'Needs Num': '需要的数量',
   'Request Type': '请求类型',
   'Remark': '备注',
+  'Are you sure you want to cancel this job?': '你确定要取消此工作吗?',
+  'Are you sure you want to delete this job?': '你确定要删除此工作吗?',
+  'Are you sure you want to confirm this job?': '你确定要完成此工作吗?',
 
   //插件的国际化
   'Pull to refresh': '下拉刷新',

+ 1 - 0
packages/cs_router/lib/componentRouter/labour_sg_service.dart

@@ -8,4 +8,5 @@ abstract class LabourSGService {
 
   void startJobTitlePage();
 
+  void startJobListPage();
 }

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

@@ -44,6 +44,8 @@ class RouterPath {
 
   //新加坡的工作列表
   static const JOB_LIST_SG = '/job/list/sg'; //工作列表(新加坡)
+  static const JOB_LIST_EDIT = '/job/list/edit'; //工作列表编辑与详情(新加坡)
+
 
   //全局其他
   static const PREVIEW_IMAGE = '/preview/image'; //预览图片

+ 10 - 5
packages/cs_widgets/lib/shatter/custom_radio_check.dart

@@ -14,11 +14,13 @@ class CustomRadioCheck extends StatefulWidget {
   final List<String> options;
   int? selectedPosition;
   final Function(int index, String text) onOptionSelected;
+  final bool enable;
 
   CustomRadioCheck({
     required this.options,
     required this.onOptionSelected,
     this.selectedPosition = 0,
+    this.enable = true, // 默认可用
   });
 
   @override
@@ -61,13 +63,13 @@ class _CustomRadioCheckState extends State<CustomRadioCheck> {
           path: option == _selectedOption ? Assets.cptAuthLoginRadioChecked : Assets.cptAuthLoginRadioUncheck,
           text: option,
           value: option == _selectedOption,
-          onChanged: (value) {
+          onChanged: widget.enable ? (value) { // 只在可用状态下响应点击
             setState(() {
               _selectedOption = option;
               int selectedIndex = widget.options.indexOf(option);
               widget.onOptionSelected(selectedIndex, option);
             });
-          },
+          } : null, // 如果不可用则不设置回调
         );
       }).toList(),
     );
@@ -77,7 +79,7 @@ class _CustomRadioCheckState extends State<CustomRadioCheck> {
     required String path,
     required String text,
     required bool value,
-    required Function(bool) onChanged,
+    required Function(bool)? onChanged, // 允许 onChanged 为 null
   }) {
     return Row(
       mainAxisSize: MainAxisSize.min,
@@ -86,14 +88,17 @@ class _CustomRadioCheckState extends State<CustomRadioCheck> {
         SizedBox(width: 10),
         MyTextView(
           text.tr,
-          textColor: ColorConstants.white,
+          textColor: widget.enable ? ColorConstants.white : ColorConstants.gray, // 根据 enable 改变文本颜色
           fontSize: 14,
           isFontRegular: true,
         ),
       ],
     ).marginOnly(right: 20, bottom: 5).onTap(() {
-      onChanged(true);
+      if (onChanged != null) { // 只有在可用状态下才触发
+        onChanged(true);
+      }
     });
   }
 }
 
+