Procházet zdrojové kódy

Attendance Review 的相关页面与逻辑

liukai před 3 dny
rodič
revize
8c042b0332
30 změnil soubory, kde provedl 2444 přidání a 390 odebrání
  1. 3 3
      packages/cpt_sg/lib/modules/job/job_applied/dialog_applied_modify.dart
  2. 16 11
      packages/cpt_sg/lib/modules/job/job_applied/job_applied_controller.dart
  3. 1 1
      packages/cpt_sg/lib/modules/job/job_applied/job_applied_page.dart
  4. 35 12
      packages/cpt_sg/lib/modules/job/job_list/job_list_item.dart
  5. 103 17
      packages/cpt_sg/lib/modules/review/attendance_review_list/attendance_review_controller.dart
  6. 362 0
      packages/cpt_sg/lib/modules/review/attendance_review_list/attendance_review_filter.dart
  7. 133 120
      packages/cpt_sg/lib/modules/review/attendance_review_list/attendance_review_item.dart
  8. 19 2
      packages/cpt_sg/lib/modules/review/attendance_review_list/attendance_review_page.dart
  9. 0 187
      packages/cpt_sg/lib/modules/review/attendance_review_list/attendance_review_reject_dialog.dart
  10. 9 3
      packages/cpt_sg/lib/modules/review/attendance_review_list/attendance_review_state.dart
  11. 97 0
      packages/cpt_sg/lib/modules/review/attendance_review_workflow/attendance_review_workflow_controller.dart
  12. 229 0
      packages/cpt_sg/lib/modules/review/attendance_review_workflow/attendance_review_workflow_item.dart
  13. 102 0
      packages/cpt_sg/lib/modules/review/attendance_review_workflow/attendance_review_workflow_page.dart
  14. 10 0
      packages/cpt_sg/lib/modules/review/attendance_review_workflow/attendance_review_workflow_state.dart
  15. 7 0
      packages/cpt_sg/lib/router/sg_router.dart
  16. 16 2
      packages/cs_domain/lib/constants/api_constants.dart
  17. 1 0
      packages/cs_domain/lib/entity/response/job_list_s_g_entity.dart
  18. 1 1
      packages/cs_domain/lib/entity/response/labour_review_status_entity.dart
  19. 24 0
      packages/cs_domain/lib/entity/response/s_g_attendance_review_option_entity.dart
  20. 102 0
      packages/cs_domain/lib/entity/response/s_g_attendance_review_table_entity.dart
  21. 167 0
      packages/cs_domain/lib/entity/response/s_g_attendance_review_workflow_entity.dart
  22. 31 0
      packages/cs_domain/lib/generated/json/base/json_convert_content.dart
  23. 7 0
      packages/cs_domain/lib/generated/json/job_list_s_g_entity.g.dart
  24. 2 2
      packages/cs_domain/lib/generated/json/labour_review_status_entity.g.dart
  25. 37 0
      packages/cs_domain/lib/generated/json/s_g_attendance_review_option_entity.g.dart
  26. 264 0
      packages/cs_domain/lib/generated/json/s_g_attendance_review_table_entity.g.dart
  27. 481 0
      packages/cs_domain/lib/generated/json/s_g_attendance_review_workflow_entity.g.dart
  28. 8 1
      packages/cs_domain/lib/generated/json/s_g_labour_review_table_entity.g.dart
  29. 172 23
      packages/cs_domain/lib/repository/job_sg_repository.dart
  30. 5 5
      packages/cs_domain/lib/repository/labour_sg_repository.dart

+ 3 - 3
packages/cpt_sg/lib/modules/job/job_applied/dialog_applied_modify.dart

@@ -19,7 +19,7 @@ import 'package:widgets/picker/date_picker_util.dart';
 import 'package:widgets/shatter/custom_radio_check.dart';
 import 'package:widgets/shatter/custom_radio_check.dart';
 import 'package:widgets/widget_export.dart';
 import 'package:widgets/widget_export.dart';
 
 
-/**
+/*
  * 修改员工的信息的弹窗
  * 修改员工的信息的弹窗
  */
  */
 class DialogAppliedModify extends StatefulWidget {
 class DialogAppliedModify extends StatefulWidget {
@@ -299,7 +299,7 @@ class _DialogAppliedModifyState extends State<DialogAppliedModify> {
                         isFontMedium: true,
                         isFontMedium: true,
                         textColor: ColorConstants.black33,
                         textColor: ColorConstants.black33,
                       ).expanded(),
                       ).expanded(),
-                      MyAssetImage(Assets.baseServiceTriangleDropDownIcon, width: 11.5, height: 6.28),
+                      const MyAssetImage(Assets.baseServiceTriangleDropDownIcon, width: 11.5, height: 6.28),
                     ],
                     ],
                   ),
                   ),
                 ).onTap(() {
                 ).onTap(() {
@@ -339,7 +339,7 @@ class _DialogAppliedModifyState extends State<DialogAppliedModify> {
                       fontSize: 14,
                       fontSize: 14,
                       fontWeight: FontWeight.w400,
                       fontWeight: FontWeight.w400,
                     ),
                     ),
-                    inputType: TextInputType.numberWithOptions(signed: true, decimal: true),
+                    inputType: const TextInputType.numberWithOptions(signed: true, decimal: true),
                     textInputAction: TextInputAction.next,
                     textInputAction: TextInputAction.next,
                     enabled: true,
                     enabled: true,
                     onSubmit: (key, value) {},
                     onSubmit: (key, value) {},

+ 16 - 11
packages/cpt_sg/lib/modules/job/job_applied/job_applied_controller.dart

@@ -390,20 +390,25 @@ class JobAppliedController extends GetxController with DioCancelableMixin {
       return;
       return;
     }
     }
 
 
-    DialogEngine.show(
-      widget: AppDefaultDialog(
-          title: "Notice".tr,
-          message: "Are you sure you want to send the e-attendance to agency?".tr,
-          confirmAction: () {
-            _requestSendEAttendance();
-          }),
-    );
+    //找出已经选中的员工
+    var selectedList = state.datas.where((element) => element.isSelected).toList(growable: false);
+    if (selectedList.isNotEmpty) {
+
+      var ids = selectedList.map((e) => e.appliedId.toString()).toList(growable: false);
+      var separatedIds = ids.join(',');
+
+      //调用接口-发送到 Attendance Review 列表
+      _requestSendEAttendance(separatedIds);
+
+    } else {
+      ToastEngine.show("Please select the applied record".tr);
+    }
   }
   }
 
 
   //发送接口
   //发送接口
-  void _requestSendEAttendance() async {
-    var result = await _labourRepository.confirmJobList(
-      state.jobId,
+  void _requestSendEAttendance(String appliedIds) async {
+    var result = await _labourRepository.approveAppliedJob(
+      appliedIds,
       cancelToken: cancelToken,
       cancelToken: cancelToken,
     );
     );
 
 

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

@@ -163,7 +163,7 @@ class _JobAppliedState extends BaseState<JobAppliedPage, JobAppliedController> {
                       controller.confirmJob();
                       controller.confirmJob();
                     },
                     },
                     padding: const EdgeInsets.symmetric(horizontal: 5.0),
                     padding: const EdgeInsets.symmetric(horizontal: 5.0),
-                    text: "Send E-Attendance".tr,
+                    text: "Operation Approve".tr,
                     textColor: ColorConstants.white,
                     textColor: ColorConstants.white,
                     fontSize: 16,
                     fontSize: 16,
                     radius: 20,
                     radius: 20,

+ 35 - 12
packages/cpt_sg/lib/modules/job/job_list/job_list_item.dart

@@ -8,7 +8,7 @@ import 'package:widgets/ext/ex_widget.dart';
 import 'package:widgets/my_button.dart';
 import 'package:widgets/my_button.dart';
 import 'package:widgets/my_text_view.dart';
 import 'package:widgets/my_text_view.dart';
 
 
-/**
+/*
  * 用工请求的主页面列表Item
  * 用工请求的主页面列表Item
  */
  */
 class JobListItem extends StatelessWidget {
 class JobListItem extends StatelessWidget {
@@ -33,10 +33,10 @@ class JobListItem extends StatelessWidget {
   @override
   @override
   Widget build(BuildContext context) {
   Widget build(BuildContext context) {
     return Container(
     return Container(
-      padding: EdgeInsets.symmetric(vertical: 23, horizontal: 21),
-      margin: EdgeInsets.only(left: 15, right: 15, top: 5, bottom: 5),
+      padding: const EdgeInsets.symmetric(vertical: 23, horizontal: 21),
+      margin: const EdgeInsets.only(left: 15, right: 15, top: 5, bottom: 5),
       decoration: BoxDecoration(
       decoration: BoxDecoration(
-        color: Color(0xFF4DCFF6).withOpacity(0.2), // 设置背景颜色和不透明度
+        color: const Color(0xFF4DCFF6).withOpacity(0.2), // 设置背景颜色和不透明度
         borderRadius: BorderRadius.circular(5), // 设置圆角
         borderRadius: BorderRadius.circular(5), // 设置圆角
       ),
       ),
       child: Column(
       child: Column(
@@ -45,7 +45,7 @@ class JobListItem extends StatelessWidget {
         children: [
         children: [
           //工作标题
           //工作标题
           MyTextView(
           MyTextView(
-            item.jobTitle ?? "-",
+            item.source ?? "-",
             isFontMedium: true,
             isFontMedium: true,
             textColor: ColorConstants.textYellowFFBB1B,
             textColor: ColorConstants.textYellowFFBB1B,
             fontSize: 14,
             fontSize: 14,
@@ -63,7 +63,7 @@ class JobListItem extends StatelessWidget {
             crossAxisAlignment: CrossAxisAlignment.center,
             crossAxisAlignment: CrossAxisAlignment.center,
             children: [
             children: [
               MyTextView(
               MyTextView(
-                "Job Date".tr + ":",
+                "${"Job Date".tr}:",
                 isFontRegular: true,
                 isFontRegular: true,
                 textColor: ColorConstants.textGrayAECAE5,
                 textColor: ColorConstants.textGrayAECAE5,
                 fontSize: 14,
                 fontSize: 14,
@@ -78,7 +78,7 @@ class JobListItem extends StatelessWidget {
                 fontSize: 14,
                 fontSize: 14,
               ).expanded(),
               ).expanded(),
             ],
             ],
-          ).marginOnly(top: 15),
+          ).marginOnly(top: 11),
 
 
           // 部门
           // 部门
           Row(
           Row(
@@ -101,7 +101,30 @@ class JobListItem extends StatelessWidget {
                 fontSize: 14,
                 fontSize: 14,
               ).expanded(),
               ).expanded(),
             ],
             ],
-          ).marginOnly(top: 15),
+          ).marginOnly(top: 11),
+
+          // 工作标题
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "${"Job Title".tr}:",
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+
+              //文本
+              MyTextView(
+                item.jobTitle ?? "-",
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor: Colors.white,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ).marginOnly(top: 11),
 
 
           // 工作开始时间
           // 工作开始时间
           Row(
           Row(
@@ -109,7 +132,7 @@ class JobListItem extends StatelessWidget {
             crossAxisAlignment: CrossAxisAlignment.center,
             crossAxisAlignment: CrossAxisAlignment.center,
             children: [
             children: [
               MyTextView(
               MyTextView(
-                "Job Time".tr + ":",
+                "${"Job Time".tr}:",
                 isFontRegular: true,
                 isFontRegular: true,
                 textColor: ColorConstants.textGrayAECAE5,
                 textColor: ColorConstants.textGrayAECAE5,
                 fontSize: 14,
                 fontSize: 14,
@@ -124,7 +147,7 @@ class JobListItem extends StatelessWidget {
                 fontSize: 14,
                 fontSize: 14,
               ).expanded(),
               ).expanded(),
             ],
             ],
-          ).marginOnly(top: 15),
+          ).marginOnly(top: 11),
 
 
           // 人数
           // 人数
           Row(
           Row(
@@ -147,7 +170,7 @@ class JobListItem extends StatelessWidget {
                 fontSize: 14,
                 fontSize: 14,
               ).expanded(),
               ).expanded(),
             ],
             ],
-          ).marginOnly(top: 15),
+          ).marginOnly(top: 11),
 
 
           // 状态
           // 状态
           Row(
           Row(
@@ -176,7 +199,7 @@ class JobListItem extends StatelessWidget {
                 fontSize: 14,
                 fontSize: 14,
               ).expanded(),
               ).expanded(),
             ],
             ],
-          ).marginOnly(top: 15),
+          ).marginOnly(top: 11),
 
 
           //按钮组
           //按钮组
           Visibility(
           Visibility(

+ 103 - 17
packages/cpt_sg/lib/modules/review/attendance_review_list/attendance_review_controller.dart

@@ -1,21 +1,24 @@
-import 'package:domain/entity/response/attendance_review_entity.dart';
-import 'package:domain/repository/job_repository.dart';
+import 'package:domain/entity/response/s_g_attendance_review_option_entity.dart';
+import 'package:domain/entity/response/s_g_attendance_review_table_entity.dart';
+import 'package:domain/repository/job_sg_repository.dart';
 import 'package:get/get.dart';
 import 'package:get/get.dart';
 import 'package:plugin_platform/engine/dialog/dialog_engine.dart';
 import 'package:plugin_platform/engine/dialog/dialog_engine.dart';
 import 'package:plugin_platform/engine/notify/notify_engine.dart';
 import 'package:plugin_platform/engine/notify/notify_engine.dart';
 import 'package:plugin_platform/engine/toast/toast_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/dio/dio_cancelable_mixin.dart';
-
+import 'package:plugin_platform/http/http_result.dart';
+import 'package:shared/utils/date_time_utils.dart';
 import 'package:shared/utils/log_utils.dart';
 import 'package:shared/utils/log_utils.dart';
 import 'package:widgets/dialog/app_default_dialog.dart';
 import 'package:widgets/dialog/app_default_dialog.dart';
 import 'package:widgets/load_state_layout.dart';
 import 'package:widgets/load_state_layout.dart';
 import 'package:widgets/widget_export.dart';
 import 'package:widgets/widget_export.dart';
-
-import 'attendance_review_reject_dialog.dart';
+import '../attendance_review_workflow/attendance_review_workflow_page.dart';
+import '../labour_review_list/labour_review_reject_dialog.dart';
+import 'attendance_review_filter.dart';
 import 'attendance_review_state.dart';
 import 'attendance_review_state.dart';
 
 
 class AttendanceReviewController extends GetxController with DioCancelableMixin {
 class AttendanceReviewController extends GetxController with DioCancelableMixin {
-  final JobRepository _jobRepository = Get.find();
+  final JobSGRepository _jobRepository = Get.find();
   final AttendanceReviewState state = AttendanceReviewState();
   final AttendanceReviewState state = AttendanceReviewState();
 
 
   var _curPage = 1;
   var _curPage = 1;
@@ -63,11 +66,32 @@ class AttendanceReviewController extends GetxController with DioCancelableMixin
     }
     }
 
 
     // 并发执行两个请求
     // 并发执行两个请求
-    final listResult = await _jobRepository.fetchAttendanceReviewList(
-      state.keyword,
-      curPage: _curPage,
-      cancelToken: cancelToken,
-    );
+    var futures = [
+      _jobRepository.fetchAttendanceReviewTable(
+        keyword: state.keyword,
+        startDate: DateTimeUtils.formatDate(state.selectedStartDate, format: "yyyy-MM-dd"),
+        endDate: DateTimeUtils.formatDate(state.selectedEndDate, format: "yyyy-MM-dd"),
+        outletId: state.selectedDepartmentId,
+        agencyId: state.selectedSourceId,
+        curPage: _curPage,
+        cancelToken: cancelToken,
+      ),
+      state.indexOptions == null
+          ? _jobRepository.fetchAttendanceReviewOption(
+              cancelToken: cancelToken,
+            )
+          : Future(() => HttpResult(isSuccess: true).convert(data: state.indexOptions!)),
+    ];
+
+    //拿到结果
+    var results = await Future.wait(futures);
+    var listResult = results[0] as HttpResult<SGAttendanceReviewTableEntity>;
+    var optionResult = results[1] as HttpResult<SGAttendanceReviewOptionEntity>;
+
+    //选项数据
+    if (state.indexOptions == null && optionResult.isSuccess) {
+      state.indexOptions = optionResult.data!;
+    }
 
 
     // 处理数据
     // 处理数据
     if (listResult.isSuccess) {
     if (listResult.isSuccess) {
@@ -82,7 +106,7 @@ class AttendanceReviewController extends GetxController with DioCancelableMixin
   }
   }
 
 
   // 处理数据与展示的逻辑
   // 处理数据与展示的逻辑
-  void handleList(List<AttendanceReviewRows>? list) {
+  void handleList(List<SGAttendanceReviewTableRows>? list) {
     if (list != null && list.isNotEmpty) {
     if (list != null && list.isNotEmpty) {
       //有数据,判断是刷新还是加载更多的数据
       //有数据,判断是刷新还是加载更多的数据
       if (_curPage == 1) {
       if (_curPage == 1) {
@@ -135,13 +159,17 @@ class AttendanceReviewController extends GetxController with DioCancelableMixin
   void resetFiltering() {
   void resetFiltering() {
     state.keyword = "";
     state.keyword = "";
     state.searchController.text = "";
     state.searchController.text = "";
+    state.selectedStartDate = null;
+    state.selectedEndDate = null;
+    state.selectedDepartmentId = null;
+    state.selectedSourceId = null;
 
 
     //赋值之后刷新
     //赋值之后刷新
     refreshController.callRefresh();
     refreshController.callRefresh();
   }
   }
 
 
   /// Item选中与未选中设置
   /// Item选中与未选中设置
-  void doSelectedOrNot(AttendanceReviewRows data) {
+  void doSelectedOrNot(SGAttendanceReviewTableRows data) {
     data.isSelected = !data.isSelected;
     data.isSelected = !data.isSelected;
     Log.d("isSelected:${data.isSelected}");
     Log.d("isSelected:${data.isSelected}");
     update();
     update();
@@ -169,7 +197,7 @@ class AttendanceReviewController extends GetxController with DioCancelableMixin
   /// 执行批量拒绝
   /// 执行批量拒绝
   void _requestBatchReject(String recordIds, String? reason) async {
   void _requestBatchReject(String recordIds, String? reason) async {
     //执行请求
     //执行请求
-    var result = await _jobRepository.rejectLabourReviews(
+    var result = await _jobRepository.rejectAttendanceReviews(
       recordIds,
       recordIds,
       reason,
       reason,
       cancelToken: cancelToken,
       cancelToken: cancelToken,
@@ -219,7 +247,7 @@ class AttendanceReviewController extends GetxController with DioCancelableMixin
 
 
       // Are you sure 的弹窗
       // Are you sure 的弹窗
       DialogEngine.show(
       DialogEngine.show(
-        widget: AttendaceReviewRejectDialog(
+        widget: LabourReviewRejectDialog(
           confirmAction: (reason) {
           confirmAction: (reason) {
             //请求接口,提交评论
             //请求接口,提交评论
             _requestBatchReject(recordIds, reason);
             _requestBatchReject(recordIds, reason);
@@ -242,8 +270,66 @@ class AttendanceReviewController extends GetxController with DioCancelableMixin
     update();
     update();
   }
   }
 
 
+  /// 展示顶部的筛选
+  void showFilterDialog() {
+    if (state.indexOptions != null) {
+      DialogEngine.show(
+        widget: LabourReviewFilter(
+          optionResult: state.indexOptions!,
+          selectedStartDate: state.selectedStartDate,
+          selectedEndDate: state.selectedEndDate,
+          outletId: state.selectedDepartmentId,
+          sourceId: state.selectedSourceId,
+          onFilterAction: (startDate, endDate, outletId, sourceId) {
+            state.selectedStartDate = startDate;
+            state.selectedEndDate = endDate;
+            state.selectedDepartmentId = outletId;
+            state.selectedSourceId = sourceId;
+
+            //赋值之后刷新
+            refreshController.callRefresh();
+          },
+        ),
+        position: DialogPosition.top,
+        animType: DialogAnimation.fade,
+      );
+    }
+  }
+
   /// 去用工审核流程页面
   /// 去用工审核流程页面
-  void gotoStatusViewPage(AttendanceReviewRows data) {
-    ToastEngine.show("去工作流页面");
+  void gotoStatusViewPage(SGAttendanceReviewTableRows data) {
+    SGAttendanceReviewWorkflowPage.startInstance(data.appliedId);
+  }
+
+  /// 根据ID获取Item对象,用于刷新
+  void fetchItemByIdAndRefreshItem(String? recordId) async {
+    var result = await _jobRepository.fetchAttendanceReviewTable(
+      recordId: recordId,
+      curPage: 1,
+      cancelToken: cancelToken,
+    );
+
+    //处理数据
+    if (result.isSuccess) {
+      var data = result.data;
+      if (data != null && data.rows.isNotEmpty) {
+        List<SGAttendanceReviewTableRows> newItem = data.rows;
+
+        // 创建一个 Map 来加速查找
+        Map<String, SGAttendanceReviewTableRows> newItemMap = {for (var item in newItem) item.recordId ?? "": item};
+
+        // 遍历 state.datas 进行替换
+        for (int i = 0; i < state.datas.length; i++) {
+          if (newItemMap.containsKey(state.datas[i].recordId)) {
+            state.datas[i] = newItemMap[state.datas[i].recordId]!;
+          }
+        }
+
+        //刷新
+        update();
+      }
+    } else {
+      ToastEngine.show(result.errorMsg ?? "Network Load Error".tr);
+    }
   }
   }
 }
 }

+ 362 - 0
packages/cpt_sg/lib/modules/review/attendance_review_list/attendance_review_filter.dart

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

+ 133 - 120
packages/cpt_sg/lib/modules/review/attendance_review_list/attendance_review_item.dart

@@ -1,12 +1,14 @@
 import 'package:cs_resources/constants/color_constants.dart';
 import 'package:cs_resources/constants/color_constants.dart';
 import 'package:cs_resources/generated/assets.dart';
 import 'package:cs_resources/generated/assets.dart';
-import 'package:domain/entity/response/attendance_review_entity.dart';
+import 'package:domain/entity/response/s_g_attendance_review_table_entity.dart';
+import 'package:domain/entity/response/s_g_labour_review_table_entity.dart';
 import 'package:flutter/cupertino.dart';
 import 'package:flutter/cupertino.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter/widgets.dart';
 import 'package:flutter/widgets.dart';
 import 'package:plugin_basic/basic_export.dart';
 import 'package:plugin_basic/basic_export.dart';
 import 'package:shared/utils/util.dart';
 import 'package:shared/utils/util.dart';
 import 'package:widgets/ext/ex_widget.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_load_image.dart';
 import 'package:widgets/my_text_view.dart';
 import 'package:widgets/my_text_view.dart';
 
 
@@ -15,15 +17,17 @@ import 'package:widgets/my_text_view.dart';
  */
  */
 class AttendanceReviewItem extends StatelessWidget {
 class AttendanceReviewItem extends StatelessWidget {
   final int index;
   final int index;
-  final AttendanceReviewRows item;
+  final SGAttendanceReviewTableRows item;
   final VoidCallback? onStatusAction;
   final VoidCallback? onStatusAction;
   final VoidCallback? onItemAction;
   final VoidCallback? onItemAction;
+  final void Function(String? img)? onImagePreviewAction;
 
 
   AttendanceReviewItem({
   AttendanceReviewItem({
     required this.index,
     required this.index,
     required this.item,
     required this.item,
     this.onStatusAction,
     this.onStatusAction,
     this.onItemAction,
     this.onItemAction,
+    this.onImagePreviewAction,
   });
   });
 
 
   @override
   @override
@@ -38,7 +42,39 @@ class AttendanceReviewItem extends StatelessWidget {
       child: Column(
       child: Column(
         mainAxisSize: MainAxisSize.max,
         mainAxisSize: MainAxisSize.max,
         crossAxisAlignment: CrossAxisAlignment.start,
         crossAxisAlignment: CrossAxisAlignment.start,
-        children:[
+        children: [
+          // Source
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "${"Source".tr}:",
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+              MyTextView(
+                item.source ?? "-",
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor: Colors.white,
+                fontSize: 14,
+              ).expanded(),
+
+              //是否选中
+              Visibility(
+                visible: true,
+                child: MyAssetImage(
+                  item.isSelected ? Assets.baseServiceItemSelectedIcon : Assets.baseServiceItemUnselectedIcon,
+                  width: 20.5,
+                  height: 20.5,
+                ),
+              ),
+
+            ],
+          ).marginOnly(top: 12),
+
           //员工姓名
           //员工姓名
           Row(
           Row(
             mainAxisSize: MainAxisSize.max,
             mainAxisSize: MainAxisSize.max,
@@ -54,36 +90,28 @@ class AttendanceReviewItem extends StatelessWidget {
               //姓名
               //姓名
               MyTextView(
               MyTextView(
                 item.staffName ?? "-",
                 item.staffName ?? "-",
-                isFontRegular: true,
+                isFontMedium: true,
                 textColor: ColorConstants.white,
                 textColor: ColorConstants.white,
                 fontSize: 14,
                 fontSize: 14,
                 marginLeft: 5,
                 marginLeft: 5,
                 marginRight: 5,
                 marginRight: 5,
               ).expanded(),
               ).expanded(),
-
-              //是否选中
-              MyAssetImage(
-                item.isSelected ? Assets.baseServiceItemSelectedIcon : Assets.baseServiceItemUnselectedIcon,
-                width: 20.5,
-                height: 20.5,
-              ),
             ],
             ],
-          ),
+          ).marginOnly(top: 12),
 
 
-          // 工作标题
+          // 工作日期
           Row(
           Row(
             mainAxisSize: MainAxisSize.max,
             mainAxisSize: MainAxisSize.max,
             crossAxisAlignment: CrossAxisAlignment.center,
             crossAxisAlignment: CrossAxisAlignment.center,
             children: [
             children: [
               MyTextView(
               MyTextView(
-                "${"Title".tr}:",
+                "Job Date".tr+":",
                 isFontRegular: true,
                 isFontRegular: true,
                 textColor: ColorConstants.textGrayAECAE5,
                 textColor: ColorConstants.textGrayAECAE5,
                 fontSize: 14,
                 fontSize: 14,
               ),
               ),
-
               MyTextView(
               MyTextView(
-                item.jobTitle ?? "-",
+                item.jobDate ?? "-",
                 marginLeft: 5,
                 marginLeft: 5,
                 isFontRegular: true,
                 isFontRegular: true,
                 textColor: Colors.white,
                 textColor: Colors.white,
@@ -92,20 +120,20 @@ class AttendanceReviewItem extends StatelessWidget {
             ],
             ],
           ).marginOnly(top: 12),
           ).marginOnly(top: 12),
 
 
-          // 部门
+
+          // 工作时间
           Row(
           Row(
             mainAxisSize: MainAxisSize.max,
             mainAxisSize: MainAxisSize.max,
             crossAxisAlignment: CrossAxisAlignment.center,
             crossAxisAlignment: CrossAxisAlignment.center,
             children: [
             children: [
               MyTextView(
               MyTextView(
-                "${"Outlet".tr}:",
+                "Job Time".tr+":",
                 isFontRegular: true,
                 isFontRegular: true,
                 textColor: ColorConstants.textGrayAECAE5,
                 textColor: ColorConstants.textGrayAECAE5,
                 fontSize: 14,
                 fontSize: 14,
               ),
               ),
-
               MyTextView(
               MyTextView(
-                item.departmentName ?? "-",
+                item.jobTime ?? "-",
                 marginLeft: 5,
                 marginLeft: 5,
                 isFontRegular: true,
                 isFontRegular: true,
                 textColor: Colors.white,
                 textColor: Colors.white,
@@ -114,20 +142,20 @@ class AttendanceReviewItem extends StatelessWidget {
             ],
             ],
           ).marginOnly(top: 12),
           ).marginOnly(top: 12),
 
 
-          // 工作时间
+
+          // 部门
           Row(
           Row(
             mainAxisSize: MainAxisSize.max,
             mainAxisSize: MainAxisSize.max,
             crossAxisAlignment: CrossAxisAlignment.center,
             crossAxisAlignment: CrossAxisAlignment.center,
             children: [
             children: [
               MyTextView(
               MyTextView(
-                "DateTime:".tr,
+                "${"Outlet".tr}:",
                 isFontRegular: true,
                 isFontRegular: true,
                 textColor: ColorConstants.textGrayAECAE5,
                 textColor: ColorConstants.textGrayAECAE5,
                 fontSize: 14,
                 fontSize: 14,
               ),
               ),
-
               MyTextView(
               MyTextView(
-                item.jobTime ?? "-",
+                item.outletName ?? "-",
                 marginLeft: 5,
                 marginLeft: 5,
                 isFontRegular: true,
                 isFontRegular: true,
                 textColor: Colors.white,
                 textColor: Colors.white,
@@ -136,13 +164,14 @@ class AttendanceReviewItem extends StatelessWidget {
             ],
             ],
           ).marginOnly(top: 12),
           ).marginOnly(top: 12),
 
 
-          //考勤时间
+
+          // 工作签到时间
           Row(
           Row(
             mainAxisSize: MainAxisSize.max,
             mainAxisSize: MainAxisSize.max,
             crossAxisAlignment: CrossAxisAlignment.center,
             crossAxisAlignment: CrossAxisAlignment.center,
             children: [
             children: [
               MyTextView(
               MyTextView(
-                "${"Clock Time".tr}:",
+                "${"Work Clock In".tr}:",
                 isFontRegular: true,
                 isFontRegular: true,
                 textColor: ColorConstants.textGrayAECAE5,
                 textColor: ColorConstants.textGrayAECAE5,
                 fontSize: 14,
                 fontSize: 14,
@@ -150,46 +179,56 @@ class AttendanceReviewItem extends StatelessWidget {
 
 
               //时间
               //时间
               MyTextView(
               MyTextView(
-                "${item.clockIn} - ${item.clockOut}",
+                item.workIn?.time ?? "-",
                 marginLeft: 5,
                 marginLeft: 5,
                 isFontRegular: true,
                 isFontRegular: true,
-                textColor: Colors.white,
+                textColor: item.workIn?.color == null ? Colors.white : hexToColor(item.workIn!.color!),
                 fontSize: 14,
                 fontSize: 14,
+                decorationStyle: item.workIn?.image == null ? null : TextDecorationStyle.solid,
+                decorationColor: item.workIn?.color == null ? Colors.white : hexToColor(item.workIn!.color!),
+                onClick: (){
+                  onImagePreviewAction?.call(item.workIn?.image);
+                },
               ).expanded(),
               ).expanded(),
             ],
             ],
           ).marginOnly(top: 12),
           ).marginOnly(top: 12),
 
 
-
-          // + - Hours
+          // 工作签出时间
           Row(
           Row(
             mainAxisSize: MainAxisSize.max,
             mainAxisSize: MainAxisSize.max,
             crossAxisAlignment: CrossAxisAlignment.center,
             crossAxisAlignment: CrossAxisAlignment.center,
             children: [
             children: [
               MyTextView(
               MyTextView(
-                "+/- Hours:".tr,
+                "${"Work Clock Out".tr}:",
                 isFontRegular: true,
                 isFontRegular: true,
                 textColor: ColorConstants.textGrayAECAE5,
                 textColor: ColorConstants.textGrayAECAE5,
                 fontSize: 14,
                 fontSize: 14,
               ),
               ),
 
 
-              //
+              //时
               MyTextView(
               MyTextView(
-                Utils.isNotEmpty(item.adjustShow) ? item.adjustShow! : "0",
+                item.workOut?.time ?? "-",
                 marginLeft: 5,
                 marginLeft: 5,
                 isFontRegular: true,
                 isFontRegular: true,
-                textColor: Colors.white,
+                textColor: item.workOut?.color == null ? Colors.white : hexToColor(item.workOut!.color!),
                 fontSize: 14,
                 fontSize: 14,
+                decorationStyle: item.workOut?.image == null ? null : TextDecorationStyle.solid,
+                decorationColor: item.workOut?.color == null ? Colors.white : hexToColor(item.workOut!.color!),
+                decorationThickness: 2.0,
+                onClick: (){
+                  onImagePreviewAction?.call(item.workOut?.image);
+                },
               ).expanded(),
               ).expanded(),
             ],
             ],
           ).marginOnly(top: 12),
           ).marginOnly(top: 12),
 
 
-          // Total Hours
+          // + - Hours
           Row(
           Row(
             mainAxisSize: MainAxisSize.max,
             mainAxisSize: MainAxisSize.max,
             crossAxisAlignment: CrossAxisAlignment.center,
             crossAxisAlignment: CrossAxisAlignment.center,
             children: [
             children: [
               MyTextView(
               MyTextView(
-                "${"Total (Hrs/Rms)".tr}:",
+                "+/- Hours:".tr,
                 isFontRegular: true,
                 isFontRegular: true,
                 textColor: ColorConstants.textGrayAECAE5,
                 textColor: ColorConstants.textGrayAECAE5,
                 fontSize: 14,
                 fontSize: 14,
@@ -197,7 +236,7 @@ class AttendanceReviewItem extends StatelessWidget {
 
 
               //小时
               //小时
               MyTextView(
               MyTextView(
-                item.totalShow.toString(),
+                item.adjustHours ?? "",
                 marginLeft: 5,
                 marginLeft: 5,
                 isFontRegular: true,
                 isFontRegular: true,
                 textColor: Colors.white,
                 textColor: Colors.white,
@@ -206,49 +245,42 @@ class AttendanceReviewItem extends StatelessWidget {
             ],
             ],
           ).marginOnly(top: 12),
           ).marginOnly(top: 12),
 
 
-          // 状态
+          // Total Hours
           Row(
           Row(
             mainAxisSize: MainAxisSize.max,
             mainAxisSize: MainAxisSize.max,
             crossAxisAlignment: CrossAxisAlignment.center,
             crossAxisAlignment: CrossAxisAlignment.center,
             children: [
             children: [
               MyTextView(
               MyTextView(
-                "Status:".tr,
+                "Total Hours:".tr,
                 isFontRegular: true,
                 isFontRegular: true,
                 textColor: ColorConstants.textGrayAECAE5,
                 textColor: ColorConstants.textGrayAECAE5,
                 fontSize: 14,
                 fontSize: 14,
               ),
               ),
 
 
-              //发布状态
+              //小时
               MyTextView(
               MyTextView(
-                item.statusShow ?? "-",
+                item.totalHours ?? "",
                 marginLeft: 5,
                 marginLeft: 5,
                 isFontRegular: true,
                 isFontRegular: true,
-                textColor: "Completed" == item.statusShow
-                    ? ColorConstants.textGreen05DC82
-                    : "Cancelled" == item.statusShow || "Rejected" == item.statusShow
-                    ? ColorConstants.textRedFF6262
-                    : "Revised" == item.statusShow || "Pending" == item.statusShow || "Approve" == item.statusShow
-                    ? ColorConstants.textYellowFFBB1B
-                    : ColorConstants.textBlue06D9FF,  //默认蓝色
+                textColor: Colors.white,
                 fontSize: 14,
                 fontSize: 14,
               ).expanded(),
               ).expanded(),
             ],
             ],
           ).marginOnly(top: 12),
           ).marginOnly(top: 12),
 
 
-          // 创建时间
+          // 状态
           Row(
           Row(
-            mainAxisSize: MainAxisSize.max,
-            crossAxisAlignment: CrossAxisAlignment.center,
             children: [
             children: [
               MyTextView(
               MyTextView(
-                "Created At:".tr,
+                "Status:".tr,
                 isFontRegular: true,
                 isFontRegular: true,
                 textColor: ColorConstants.textGrayAECAE5,
                 textColor: ColorConstants.textGrayAECAE5,
                 fontSize: 14,
                 fontSize: 14,
               ),
               ),
 
 
+              //文本
               MyTextView(
               MyTextView(
-                item.createdAt ?? "-",
+                item.statusShow ?? "",
                 marginLeft: 5,
                 marginLeft: 5,
                 isFontRegular: true,
                 isFontRegular: true,
                 textColor: Colors.white,
                 textColor: Colors.white,
@@ -257,73 +289,54 @@ class AttendanceReviewItem extends StatelessWidget {
             ],
             ],
           ).marginOnly(top: 12),
           ).marginOnly(top: 12),
 
 
-          // //按钮组
-          // Visibility(
-          //   visible: item.actionList?.isNotEmpty ?? false,
-          //   child: Row(
-          //     mainAxisSize: MainAxisSize.max,
-          //     mainAxisAlignment: MainAxisAlignment.end,
-          //     crossAxisAlignment: CrossAxisAlignment.center,
-          //     children: [
-          //       //编辑按钮
-          //       Visibility(
-          //         visible: item.actionList?.contains("edit") ?? false,
-          //         child: MyButton(
-          //           onPressed: () {
-          //             FocusScope.of(context).unfocus();
-          //             onEditAction?.call();
-          //           },
-          //           text: "Edit".tr,
-          //           textColor: ColorConstants.white,
-          //           backgroundColor: hexToColor(
-          //             "#FFBB1B",
-          //           ),
-          //           radius: 17.25,
-          //           minWidth: 60,
-          //           minHeight: 35,
-          //         ).marginOnly(left: 12),
-          //       ),
-          //
-          //       //状态工作流按钮
-          //       Visibility(
-          //         visible: item.actionList?.contains("status") ?? false,
-          //         child: MyButton(
-          //           onPressed: () {
-          //             FocusScope.of(context).unfocus();
-          //             onStatusAction?.call();
-          //           },
-          //           text: "Status".tr,
-          //           textColor: ColorConstants.white,
-          //           backgroundColor: hexToColor("#0AC074"),
-          //           radius: 17.25,
-          //           minWidth: 60,
-          //           minHeight: 35,
-          //         ).marginOnly(left: 12),
-          //       ),
-          //
-          //       //Remark按钮
-          //       Visibility(
-          //         visible: item.actionList?.contains("remarks") ?? false,
-          //         child: MyButton(
-          //           onPressed: () {
-          //             FocusScope.of(context).unfocus();
-          //             onRemarkAction?.call();
-          //           },
-          //           text: "Remarks".tr,
-          //           textColor: ColorConstants.white,
-          //           backgroundColor: hexToColor("#56AAFF"),
-          //           radius: 17.25,
-          //           minWidth: 60,
-          //           minHeight: 35,
-          //         ).marginOnly(left: 12),
-          //       ),
-          //     ],
-          //   ).marginOnly(top: 15),
-          // ),
+          //按钮组
+          Visibility(
+            visible: true,
+            child: Row(
+              mainAxisSize: MainAxisSize.max,
+              mainAxisAlignment: MainAxisAlignment.end,
+              crossAxisAlignment: CrossAxisAlignment.center,
+              children: [
+
+                //状态工作流按钮
+                Visibility(
+                  visible: true,
+                  child: MyButton(
+                    onPressed: () {
+                      FocusScope.of(context).unfocus();
+                      onStatusAction?.call();
+                    },
+                    text: "Status".tr,
+                    textColor: ColorConstants.white,
+                    backgroundColor: ColorConstants.textGreen0AC074,
+                    radius: 17.25,
+                    minWidth: 60,
+                    minHeight: 35,
+                  ).marginOnly(left: 12),
+                ),
+
+                //Remark按钮
+                Visibility(
+                  visible: false,
+                  child: MyButton(
+                    onPressed: () {
+                      FocusScope.of(context).unfocus();
+                    },
+                    text: "Remarks".tr,
+                    textColor: ColorConstants.white,
+                    backgroundColor: ColorConstants.textBlue56AAFF,
+                    radius: 17.25,
+                    minWidth: 60,
+                    minHeight: 35,
+                  ).marginOnly(left: 12),
+                ),
+              ],
+            ).marginOnly(top: 15),
+          ),
         ],
         ],
-      ),
-    ).onTap(() {
-      onItemAction?.call();
-    });
+      ).onTap((){
+        onItemAction?.call();
+      }),
+    );
   }
   }
 }
 }

+ 19 - 2
packages/cpt_sg/lib/modules/review/attendance_review_list/attendance_review_page.dart

@@ -3,9 +3,12 @@ import 'package:cs_resources/generated/assets.dart';
 import 'package:flutter/cupertino.dart';
 import 'package:flutter/cupertino.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter/material.dart';
 import 'package:get/get.dart';
 import 'package:get/get.dart';
+import 'package:plugin_platform/engine/image/image_preview.dart';
+import 'package:shared/utils/util.dart';
 import 'package:widgets/ext/ex_widget.dart';
 import 'package:widgets/ext/ex_widget.dart';
 import 'package:widgets/load_state_layout.dart';
 import 'package:widgets/load_state_layout.dart';
 import 'package:widgets/my_button.dart';
 import 'package:widgets/my_button.dart';
+import 'package:widgets/my_load_image.dart';
 import 'package:widgets/my_text_view.dart';
 import 'package:widgets/my_text_view.dart';
 import 'package:widgets/widget_export.dart';
 import 'package:widgets/widget_export.dart';
 
 
@@ -21,7 +24,7 @@ import 'package:widgets/my_appbar.dart';
 import 'attendance_review_state.dart';
 import 'attendance_review_state.dart';
 
 
 /*
 /*
- * 工作考勤的审核列表
+ * 用工请求审核的列表
  */
  */
 class SGAttendanceReviewPage extends BaseStatefulPage<AttendanceReviewController> {
 class SGAttendanceReviewPage extends BaseStatefulPage<AttendanceReviewController> {
   SGAttendanceReviewPage({Key? key}) : super(key: key);
   SGAttendanceReviewPage({Key? key}) : super(key: key);
@@ -95,6 +98,15 @@ class _LabourReviewState extends BaseState<SGAttendanceReviewPage, AttendanceRev
                     minHeight: 35,
                     minHeight: 35,
                   ).marginOnly(right: 15),
                   ).marginOnly(right: 15),
 
 
+                  //筛选图标
+                  const MyAssetImage(
+                    Assets.baseServiceTitleBarFilterIcon,
+                    width: 24,
+                    height: 16.5,
+                  ).onTap(() {
+                    FocusScope.of(context).unfocus();
+                    controller.showFilterDialog();
+                  }).marginOnly(right: 15),
                 ],
                 ],
               ),
               ),
 
 
@@ -117,11 +129,16 @@ class _LabourReviewState extends BaseState<SGAttendanceReviewPage, AttendanceRev
                           index: index,
                           index: index,
                           item: state.datas[index],
                           item: state.datas[index],
                           onStatusAction: () {
                           onStatusAction: () {
-
+                            controller.gotoStatusViewPage(state.datas[index]);
                           },
                           },
                           onItemAction: () {
                           onItemAction: () {
                             controller.doSelectedOrNot(state.datas[index]);
                             controller.doSelectedOrNot(state.datas[index]);
                           },
                           },
+                          onImagePreviewAction: (imageUrl) {
+                            if (Utils.isNotEmpty(imageUrl)) {
+                              ImagePreviewEngine.singleImagePreview(context, imageUrl!);
+                            }
+                          },
                         );
                         );
                       },
                       },
                       childCount: state.datas.length,
                       childCount: state.datas.length,

+ 0 - 187
packages/cpt_sg/lib/modules/review/attendance_review_list/attendance_review_reject_dialog.dart

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

+ 9 - 3
packages/cpt_sg/lib/modules/review/attendance_review_list/attendance_review_state.dart

@@ -1,12 +1,18 @@
-import 'package:domain/entity/response/attendance_review_entity.dart';
+
+import 'package:domain/entity/response/s_g_attendance_review_option_entity.dart';
+import 'package:domain/entity/response/s_g_attendance_review_table_entity.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter/material.dart';
 
 
 class AttendanceReviewState {
 class AttendanceReviewState {
   //筛选条件
   //筛选条件
   final TextEditingController searchController = TextEditingController();
   final TextEditingController searchController = TextEditingController();
   String keyword = "";
   String keyword = "";
+  DateTime? selectedStartDate;
+  DateTime? selectedEndDate;
+  String? selectedDepartmentId;
+  String? selectedSourceId;
 
 
   //页面的列表数据
   //页面的列表数据
-  List<AttendanceReviewRows> datas = [];
-
+  List<SGAttendanceReviewTableRows> datas = [];
+  SGAttendanceReviewOptionEntity? indexOptions;
 }
 }

+ 97 - 0
packages/cpt_sg/lib/modules/review/attendance_review_workflow/attendance_review_workflow_controller.dart

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

+ 229 - 0
packages/cpt_sg/lib/modules/review/attendance_review_workflow/attendance_review_workflow_item.dart

@@ -0,0 +1,229 @@
+import 'package:cs_resources/constants/color_constants.dart';
+import 'package:domain/entity/response/labour_review_status_entity.dart';
+import 'package:domain/entity/response/s_g_attendance_review_workflow_entity.dart';
+import 'package:flutter/cupertino.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter/widgets.dart';
+import 'package:plugin_basic/basic_export.dart';
+import 'package:widgets/ext/ex_widget.dart';
+import 'package:widgets/my_text_view.dart';
+
+/*
+ * 用请求的审核工作流Item
+ */
+class AttendanceReviewWorkflowItem extends StatelessWidget {
+  final int index;
+  final SGAttendanceReviewWorkflowRecords item;
+
+  AttendanceReviewWorkflowItem({
+    required this.index,
+    required this.item,
+  });
+
+  @override
+  Widget build(BuildContext context) {
+    return Container(
+      padding: const EdgeInsets.symmetric(vertical: 23, horizontal: 21),
+      margin: const EdgeInsets.only(left: 15, right: 15, top: 5, bottom: 5),
+      decoration: BoxDecoration(
+        color: const Color(0xFF4DCFF6).withOpacity(0.2), // 设置背景颜色和不透明度
+        borderRadius: BorderRadius.circular(5), // 设置圆角
+      ),
+      child: Column(
+        mainAxisSize: MainAxisSize.max,
+        crossAxisAlignment: CrossAxisAlignment.start,
+        children: [
+          //Node
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "Node:".tr,
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+
+              MyTextView(
+                item.nodeName ?? "-",
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor: Colors.white,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ),
+
+          // assigneeType
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "Type:".tr,
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+
+              //日期时间
+              MyTextView(
+                item.assigneeTypeShow ?? "-",
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor: Colors.white,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ).marginOnly(top: 15),
+
+          // Designation
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "Designation:".tr,
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+
+              //人数
+              MyTextView(
+                item.designationShow ?? "-",
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor: Colors.white,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ).marginOnly(top: 15),
+
+          // 状态
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "Status:".tr,
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+
+              //状态
+              MyTextView(
+                item.statusShow == null ? "" : item.statusShow!.tr,
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor: "Approved" == item.statusShow
+                    ? ColorConstants.textGreen05DC82
+                    : "Rejected" == item.statusShow
+                    ? ColorConstants.textRedFF6262
+                    : "Recall" == item.statusShow
+                    ? ColorConstants.textYellowFFBB1B
+                    : ColorConstants.textBlue06D9FF,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ).marginOnly(top: 15),
+
+          // Operator
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "Operator:".tr,
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+
+              //发布状态
+              MyTextView(
+                item.auditName ?? "-",
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor: Colors.white,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ).marginOnly(top: 15),
+
+          // 操作时间
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "Audit Time:".tr,
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+
+              //时间
+              MyTextView(
+                item.auditTime ?? "-",
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor: Colors.white,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ).marginOnly(top: 15),
+
+          // 创建时间
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "Created At:".tr,
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+
+              //时间
+              MyTextView(
+                item.createdAt ?? "-",
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor: Colors.white,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ).marginOnly(top: 15),
+
+          // Remark
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "Remark:".tr,
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+
+              //时间
+              MyTextView(
+                item.auditMark ?? "-",
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor: Colors.white,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ).marginOnly(top: 15),
+
+        ],
+      ),
+    );
+  }
+}

+ 102 - 0
packages/cpt_sg/lib/modules/review/attendance_review_workflow/attendance_review_workflow_page.dart

@@ -0,0 +1,102 @@
+
+import 'package:cpt_sg/modules/review/attendance_review_workflow/attendance_review_workflow_item.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/widget_export.dart';
+
+import 'attendance_review_workflow_controller.dart';
+import 'attendance_review_workflow_state.dart';
+
+/*
+ * 用工请求审核-状态工作流列表
+ */
+class SGAttendanceReviewWorkflowPage extends BaseStatefulPage<AttendanceReviewWorkflowController> {
+  SGAttendanceReviewWorkflowPage({Key? key}) : super(key: key);
+
+  //启动当前页面
+  static void startInstance(String? appliedId) {
+    return Get.start(RouterPath.SGAttendanceReviewWorkflow,arguments: {'appliedId': appliedId});
+  }
+
+  @override
+  AttendanceReviewWorkflowController createRawController() {
+    return AttendanceReviewWorkflowController();
+  }
+
+  @override
+  State<SGAttendanceReviewWorkflowPage> createState() => _LabourReviewWorkflowState();
+
+}
+
+class _LabourReviewWorkflowState extends BaseState<SGAttendanceReviewWorkflowPage, AttendanceReviewWorkflowController> {
+
+  late AttendanceReviewWorkflowState state;
+
+  @override
+  void initState() {
+    super.initState();
+    state = controller.state;
+    state.appliedId = Get.arguments['appliedId'];
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return autoCtlGetBuilder(builder: (controller) {
+      return  SafeArea(
+          bottom: true,
+          top: false,
+          child: Container(
+            width: double.infinity,
+            height: double.infinity,
+            padding: EdgeInsets.only(top: ScreenUtil.getStatusBarH(context)),
+            decoration: const BoxDecoration(
+              gradient: LinearGradient(
+                colors: [
+                  Color(0xFF091D44),
+                  Color(0xFF245A8A),
+                  Color(0xFF7F7CEC),
+                ],
+                begin: Alignment.topCenter,
+                end: Alignment.bottomCenter,
+              ),
+            ),
+            child: Column(
+              children: [
+                MyAppBar.titleBar(context, "Workflow".tr),
+
+                EasyRefresh(
+                  controller: controller.refreshController,
+                  onRefresh: controller.onRefresh,
+                  child: LoadStateLayout(
+                    state: controller.loadingState,
+                    errorMessage: controller.errorMessage,
+                    errorRetry: () {
+                      controller.retryRequest();
+                    },
+                    successSliverWidget: [
+                      SliverList(
+                          delegate: SliverChildBuilderDelegate((context, index) {
+                              return AttendanceReviewWorkflowItem(index: index,item: state.datas[index]);
+                            },
+                            childCount: state.datas.length,
+                          ))
+                    ],
+                  ),
+                ).expanded(),
+              ],
+            ).marginOnly(top: 10),
+          ),
+        );
+    });
+  }
+}
+
+

+ 10 - 0
packages/cpt_sg/lib/modules/review/attendance_review_workflow/attendance_review_workflow_state.dart

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

+ 7 - 0
packages/cpt_sg/lib/router/sg_router.dart

@@ -9,6 +9,7 @@ import 'package:cpt_sg/modules/agency/contract_rate_specific_day/contract_rate_s
 import 'package:cpt_sg/modules/agency/position_add/position_add_page.dart';
 import 'package:cpt_sg/modules/agency/position_add/position_add_page.dart';
 import 'package:cpt_sg/modules/agency/position_list/position_list_page.dart';
 import 'package:cpt_sg/modules/agency/position_list/position_list_page.dart';
 import 'package:cpt_sg/modules/main/main_page.dart';
 import 'package:cpt_sg/modules/main/main_page.dart';
+import 'package:cpt_sg/modules/review/attendance_review_workflow/attendance_review_workflow_page.dart';
 import 'package:get/get.dart';
 import 'package:get/get.dart';
 import 'package:router/path/router_path.dart';
 import 'package:router/path/router_path.dart';
 
 
@@ -190,6 +191,12 @@ class SGPageRouter {
       page: () => SGAttendanceReviewPage(),
       page: () => SGAttendanceReviewPage(),
     ),
     ),
 
 
+    //考勤的审核列表
+    GetPage(
+      name: RouterPath.SGAttendanceReviewWorkflow,
+      page: () => SGAttendanceReviewWorkflowPage(),
+    ),
+
     //新加坡中介模块的分类
     //新加坡中介模块的分类
     GetPage(
     GetPage(
       name: RouterPath.SGAgencyCategory,
       name: RouterPath.SGAgencyCategory,

+ 16 - 2
packages/cs_domain/lib/constants/api_constants.dart

@@ -203,8 +203,8 @@ class ApiConstants {
   //用工请求的删除(Job List)
   //用工请求的删除(Job List)
   static const apiJobListDeleteSG = "/index.php/api/v1/hotel/job/delete";
   static const apiJobListDeleteSG = "/index.php/api/v1/hotel/job/delete";
 
 
-  //用工请求的考勤确认(Job List)
-  static const apiJobListConfirmSG = "/index.php/api/v1/hotel/job/confirm";
+  //用工请求的考勤确认(Job List)现在是发送到 Attendance Review 列表中
+  static const apiJobAppliedApproveSG = "/index.php/api/v2/hotel/applied/batch-approve";
 
 
 
 
   // =========================== 新加坡工作相关 ↓=========================================
   // =========================== 新加坡工作相关 ↓=========================================
@@ -431,4 +431,18 @@ class ApiConstants {
   //新加坡 V2 Labour Request Review 编辑提交
   //新加坡 V2 Labour Request Review 编辑提交
   static const apiLabourRequestReviewEditSubmitSG = "/index.php/api/v2/hotel/lab-review/edit-submit";
   static const apiLabourRequestReviewEditSubmitSG = "/index.php/api/v2/hotel/lab-review/edit-submit";
 
 
+  //新加坡 V2 Job Attendance Review 选项
+  static const apiAttendanceReviewOptionSG = "/index.php/api/v2/hotel/att-review/index";
+
+  //新加坡 V2 Job Attendance Review 列表
+  static const apiAttendanceReviewTableSG = "/index.php/api/v2/hotel/att-review/table";
+
+  //新加坡 V2 Attendance Review 批量批准
+  static const apiAttendanceReviewApproveSG = "/index.php/api/v2/hotel/att-review/batch-approve";
+
+  //新加坡 V2 Attendance Review 批量拒绝
+  static const apiAttendanceReviewRejectSG = "/index.php/api/v2/hotel/att-review/batch-reject";
+
+  //新加坡 V2 Attendance Review 状态流
+  static const apiAttendanceReviewWorkflowSG = "/index.php/api/v2/hotel/att-review/status-view";
 }
 }

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

@@ -22,6 +22,7 @@ class JobListSGEntity {
 
 
 @JsonSerializable()
 @JsonSerializable()
 class JobListSGRows {
 class JobListSGRows {
+	String? source = null;
 	@JSONField(name: "job_id")
 	@JSONField(name: "job_id")
 	String? jobId = null;
 	String? jobId = null;
 	@JSONField(name: "job_date")
 	@JSONField(name: "job_date")

+ 1 - 1
packages/cs_domain/lib/entity/response/labour_review_status_entity.dart

@@ -34,7 +34,7 @@ class LabourReviewStatusRecords {
 	@JSONField(name: "audit_time")
 	@JSONField(name: "audit_time")
 	String? auditTime;
 	String? auditTime;
 	@JSONField(name: "audit_mark")
 	@JSONField(name: "audit_mark")
-	dynamic auditMark;
+	String? auditMark;
 	@JSONField(name: "created_at")
 	@JSONField(name: "created_at")
 	String? createdAt;
 	String? createdAt;
 	@JSONField(name: "assignee_type_show")
 	@JSONField(name: "assignee_type_show")

+ 24 - 0
packages/cs_domain/lib/entity/response/s_g_attendance_review_option_entity.dart

@@ -0,0 +1,24 @@
+import 'package:domain/entity/response/index_option_entity.dart';
+import 'package:domain/generated/json/base/json_field.dart';
+import 'package:domain/generated/json/s_g_attendance_review_option_entity.g.dart';
+import 'dart:convert';
+export 'package:domain/generated/json/s_g_attendance_review_option_entity.g.dart';
+
+@JsonSerializable()
+class SGAttendanceReviewOptionEntity {
+	@JSONField(name: "source_list")
+	List<IndexOptionEntity> sourceList = [];
+	@JSONField(name: "outlet_list")
+	List<IndexOptionEntity> outletList = [];
+
+	SGAttendanceReviewOptionEntity();
+
+	factory SGAttendanceReviewOptionEntity.fromJson(Map<String, dynamic> json) => $SGAttendanceReviewOptionEntityFromJson(json);
+
+	Map<String, dynamic> toJson() => $SGAttendanceReviewOptionEntityToJson(this);
+
+	@override
+	String toString() {
+		return jsonEncode(this);
+	}
+}

+ 102 - 0
packages/cs_domain/lib/entity/response/s_g_attendance_review_table_entity.dart

@@ -0,0 +1,102 @@
+import 'package:domain/generated/json/base/json_field.dart';
+import 'package:domain/generated/json/s_g_attendance_review_table_entity.g.dart';
+import 'dart:convert';
+export 'package:domain/generated/json/s_g_attendance_review_table_entity.g.dart';
+
+@JsonSerializable()
+class SGAttendanceReviewTableEntity {
+	int total = 0;
+	List<SGAttendanceReviewTableRows> rows = [];
+
+	SGAttendanceReviewTableEntity();
+
+	factory SGAttendanceReviewTableEntity.fromJson(Map<String, dynamic> json) => $SGAttendanceReviewTableEntityFromJson(json);
+
+	Map<String, dynamic> toJson() => $SGAttendanceReviewTableEntityToJson(this);
+
+	@override
+	String toString() {
+		return jsonEncode(this);
+	}
+}
+
+@JsonSerializable()
+class SGAttendanceReviewTableRows {
+	@JSONField(name: "record_id")
+	String? recordId;
+	@JSONField(name: "order_id")
+	String? orderId;
+	@JSONField(name: "applied_id")
+	String? appliedId;
+	@JSONField(name: "staff_name")
+	String? staffName;
+	String? source;
+	@JSONField(name: "status_show")
+	String? statusShow;
+	@JSONField(name: "created_at")
+	String? createdAt;
+	@JSONField(name: "job_date")
+	String? jobDate;
+	@JSONField(name: "outlet_name")
+	String? outletName;
+	@JSONField(name: "job_title")
+	String? jobTitle;
+	@JSONField(name: "job_time")
+	String? jobTime;
+	@JSONField(name: "adjust_hours")
+	String? adjustHours;
+	@JSONField(name: "total_hours")
+	String? totalHours;
+
+	@JSONField(name: "security_in")
+	SGAttendanceReviewTableRowsCheck? securityIn;
+	@JSONField(name: "security_out")
+	SGAttendanceReviewTableRowsCheck? securityOut;
+	@JSONField(name: "work_in")
+	SGAttendanceReviewTableRowsCheck? workIn;
+	@JSONField(name: "work_out")
+	SGAttendanceReviewTableRowsCheck? workOut;
+
+	@JSONField(name: "s_in")
+	int? sIn;
+	@JSONField(name: "s_out")
+	int? sOut;
+	@JSONField(name: "w_in")
+	int? wIn;
+	@JSONField(name: "w_out")
+	int? wOut;
+
+	bool isSelected = false;
+
+	SGAttendanceReviewTableRows();
+
+	factory SGAttendanceReviewTableRows.fromJson(Map<String, dynamic> json) => $SGAttendanceReviewTableRowsFromJson(json);
+
+	Map<String, dynamic> toJson() => $SGAttendanceReviewTableRowsToJson(this);
+
+	@override
+	String toString() {
+		return jsonEncode(this);
+	}
+}
+
+@JsonSerializable()
+class SGAttendanceReviewTableRowsCheck {
+	String? time;
+	String? temp;
+	String? image;
+	int? changed;
+	String? key;
+	String? color;
+
+	SGAttendanceReviewTableRowsCheck();
+
+	factory SGAttendanceReviewTableRowsCheck.fromJson(Map<String, dynamic> json) => $SGAttendanceReviewTableRowsCheckFromJson(json);
+
+	Map<String, dynamic> toJson() => $SGAttendanceReviewTableRowsCheckToJson(this);
+
+	@override
+	String toString() {
+		return jsonEncode(this);
+	}
+}

+ 167 - 0
packages/cs_domain/lib/entity/response/s_g_attendance_review_workflow_entity.dart

@@ -0,0 +1,167 @@
+import 'package:domain/generated/json/base/json_field.dart';
+import 'package:domain/generated/json/s_g_attendance_review_workflow_entity.g.dart';
+import 'dart:convert';
+export 'package:domain/generated/json/s_g_attendance_review_workflow_entity.g.dart';
+
+@JsonSerializable()
+class SGAttendanceReviewWorkflowEntity {
+	SGAttendanceReviewWorkflowRow? row;
+	@JSONField(name: "outlet_id")
+	String? outletId;
+	List<SGAttendanceReviewWorkflowRecords>?records = [];
+
+	SGAttendanceReviewWorkflowEntity();
+
+	factory SGAttendanceReviewWorkflowEntity.fromJson(Map<String, dynamic> json) => $SGAttendanceReviewWorkflowEntityFromJson(json);
+
+	Map<String, dynamic> toJson() => $SGAttendanceReviewWorkflowEntityToJson(this);
+
+	@override
+	String toString() {
+		return jsonEncode(this);
+	}
+}
+
+@JsonSerializable()
+class SGAttendanceReviewWorkflowRow {
+	String? id;
+	@JSONField(name: "job_id")
+	String? jobId;
+	@JSONField(name: "s_id")
+	String? sId;
+	@JSONField(name: "member_id")
+	String? memberId;
+	@JSONField(name: "labourer_id")
+	String? labourerId;
+	@JSONField(name: "labourer_name")
+	String? labourerName;
+	@JSONField(name: "labourer_nric")
+	String? labourerNric;
+	@JSONField(name: "source_type")
+	int? sourceType;
+	@JSONField(name: "employer_id")
+	int? employerId;
+	@JSONField(name: "employer_name")
+	String? employerName;
+	@JSONField(name: "agency_id")
+	int? agencyId;
+	@JSONField(name: "agency_name")
+	String? agencyName;
+	@JSONField(name: "job_title")
+	String? jobTitle;
+	@JSONField(name: "outlet_id")
+	String? outletId;
+	@JSONField(name: "outlet_name")
+	String? outletName;
+	@JSONField(name: "ballroom_id")
+	String? ballroomId;
+	@JSONField(name: "ballroom_name")
+	String? ballroomName;
+	@JSONField(name: "job_date")
+	String? jobDate;
+	@JSONField(name: "start_time")
+	int? startTime;
+	@JSONField(name: "end_time")
+	int? endTime;
+	@JSONField(name: "working_hours")
+	String? workingHours;
+	@JSONField(name: "adjust_hours")
+	String? adjustHours;
+	@JSONField(name: "total_hours")
+	String? totalHours;
+	@JSONField(name: "hourly_rate")
+	String? hourlyRate;
+	@JSONField(name: "gross_wage")
+	String? grossWage;
+	@JSONField(name: "security_clock_in")
+	int? securityClockIn;
+	@JSONField(name: "security_clock_out")
+	int? securityClockOut;
+	@JSONField(name: "work_clock_in")
+	int? workClockIn;
+	@JSONField(name: "work_clock_out")
+	int? workClockOut;
+	@JSONField(name: "security_in")
+	int? securityIn;
+	@JSONField(name: "security_out")
+	int? securityOut;
+	@JSONField(name: "work_in")
+	int? workIn;
+	@JSONField(name: "work_out")
+	int? workOut;
+	int? status;
+	@JSONField(name: "remark_status")
+	int? remarkStatus;
+	@JSONField(name: "created_at")
+	String? createdAt;
+	@JSONField(name: "updated_at")
+	String? updatedAt;
+	@JSONField(name: "agency_rate")
+	String? agencyRate;
+	@JSONField(name: "agency_wage")
+	String? agencyWage;
+	@JSONField(name: "amend_att")
+	int? amendAtt;
+	@JSONField(name: "target_top")
+	int? targetTop;
+	@JSONField(name: "reject_msg")
+	String? rejectMsg;
+	@JSONField(name: "revise_hours")
+	String? reviseHours;
+	@JSONField(name: "revise_gross_wage")
+	String? reviseGrossWage;
+	@JSONField(name: "revise_agency_wage")
+	String? reviseAgencyWage;
+	@JSONField(name: "skilled_worker")
+	int? skilledWorker;
+	@JSONField(name: "hotel_staff")
+	int? hotelStaff;
+	@JSONField(name: "salary_structure")
+	int? salaryStructure;
+
+	SGAttendanceReviewWorkflowRow();
+
+	factory SGAttendanceReviewWorkflowRow.fromJson(Map<String, dynamic> json) => $SGAttendanceReviewWorkflowRowFromJson(json);
+
+	Map<String, dynamic> toJson() => $SGAttendanceReviewWorkflowRowToJson(this);
+
+	@override
+	String toString() {
+		return jsonEncode(this);
+	}
+}
+
+@JsonSerializable()
+class SGAttendanceReviewWorkflowRecords {
+	@JSONField(name: "serial_number")
+	String? serialNumber;
+	@JSONField(name: "node_name")
+	String? nodeName;
+	@JSONField(name: "node_type_show")
+	String? nodeTypeShow;
+	@JSONField(name: "status_show")
+	String? statusShow;
+	@JSONField(name: "audit_name")
+	String? auditName;
+	@JSONField(name: "audit_time")
+	String? auditTime;
+	@JSONField(name: "audit_mark")
+	String? auditMark;
+	@JSONField(name: "created_at")
+	String? createdAt;
+	@JSONField(name: "assignee_type_show")
+	String? assigneeTypeShow;
+	@JSONField(name: "designation_show")
+	String? designationShow;
+
+	SGAttendanceReviewWorkflowRecords();
+
+	factory SGAttendanceReviewWorkflowRecords.fromJson(Map<String, dynamic> json) => $SGAttendanceReviewWorkflowRecordsFromJson(json);
+
+	Map<String, dynamic> toJson() => $SGAttendanceReviewWorkflowRecordsToJson(this);
+
+	@override
+	String toString() {
+		return jsonEncode(this);
+	}
+}

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

@@ -59,6 +59,9 @@ import 'package:domain/entity/response/position_table_entity.dart';
 import 'package:domain/entity/response/revise_index_s_g_entity.dart';
 import 'package:domain/entity/response/revise_index_s_g_entity.dart';
 import 'package:domain/entity/response/revise_list_s_g_entity.dart';
 import 'package:domain/entity/response/revise_list_s_g_entity.dart';
 import 'package:domain/entity/response/revise_log_s_g_entity.dart';
 import 'package:domain/entity/response/revise_log_s_g_entity.dart';
+import 'package:domain/entity/response/s_g_attendance_review_option_entity.dart';
+import 'package:domain/entity/response/s_g_attendance_review_table_entity.dart';
+import 'package:domain/entity/response/s_g_attendance_review_workflow_entity.dart';
 import 'package:domain/entity/response/s_g_labour_request_add_option_entity.dart';
 import 'package:domain/entity/response/s_g_labour_request_add_option_entity.dart';
 import 'package:domain/entity/response/s_g_labour_request_detail_entity.dart';
 import 'package:domain/entity/response/s_g_labour_request_detail_entity.dart';
 import 'package:domain/entity/response/s_g_labour_request_option_entity.dart';
 import 'package:domain/entity/response/s_g_labour_request_option_entity.dart';
@@ -546,6 +549,27 @@ class JsonConvert {
     if (<ReviseLogSGRecordsOption>[] is M) {
     if (<ReviseLogSGRecordsOption>[] is M) {
       return data.map<ReviseLogSGRecordsOption>((Map<String, dynamic> e) => ReviseLogSGRecordsOption.fromJson(e)).toList() as M;
       return data.map<ReviseLogSGRecordsOption>((Map<String, dynamic> e) => ReviseLogSGRecordsOption.fromJson(e)).toList() as M;
     }
     }
+    if (<SGAttendanceReviewOptionEntity>[] is M) {
+      return data.map<SGAttendanceReviewOptionEntity>((Map<String, dynamic> e) => SGAttendanceReviewOptionEntity.fromJson(e)).toList() as M;
+    }
+    if (<SGAttendanceReviewTableEntity>[] is M) {
+      return data.map<SGAttendanceReviewTableEntity>((Map<String, dynamic> e) => SGAttendanceReviewTableEntity.fromJson(e)).toList() as M;
+    }
+    if (<SGAttendanceReviewTableRows>[] is M) {
+      return data.map<SGAttendanceReviewTableRows>((Map<String, dynamic> e) => SGAttendanceReviewTableRows.fromJson(e)).toList() as M;
+    }
+    if (<SGAttendanceReviewTableRowsCheck>[] is M) {
+      return data.map<SGAttendanceReviewTableRowsCheck>((Map<String, dynamic> e) => SGAttendanceReviewTableRowsCheck.fromJson(e)).toList() as M;
+    }
+    if (<SGAttendanceReviewWorkflowEntity>[] is M) {
+      return data.map<SGAttendanceReviewWorkflowEntity>((Map<String, dynamic> e) => SGAttendanceReviewWorkflowEntity.fromJson(e)).toList() as M;
+    }
+    if (<SGAttendanceReviewWorkflowRow>[] is M) {
+      return data.map<SGAttendanceReviewWorkflowRow>((Map<String, dynamic> e) => SGAttendanceReviewWorkflowRow.fromJson(e)).toList() as M;
+    }
+    if (<SGAttendanceReviewWorkflowRecords>[] is M) {
+      return data.map<SGAttendanceReviewWorkflowRecords>((Map<String, dynamic> e) => SGAttendanceReviewWorkflowRecords.fromJson(e)).toList() as M;
+    }
     if (<SGLabourRequestAddOptionEntity>[] is M) {
     if (<SGLabourRequestAddOptionEntity>[] is M) {
       return data.map<SGLabourRequestAddOptionEntity>((Map<String, dynamic> e) => SGLabourRequestAddOptionEntity.fromJson(e)).toList() as M;
       return data.map<SGLabourRequestAddOptionEntity>((Map<String, dynamic> e) => SGLabourRequestAddOptionEntity.fromJson(e)).toList() as M;
     }
     }
@@ -775,6 +799,13 @@ class JsonConvertClassCollection {
     (ReviseLogSGRecords).toString(): ReviseLogSGRecords.fromJson,
     (ReviseLogSGRecords).toString(): ReviseLogSGRecords.fromJson,
     (ReviseLogSGRecordsContent).toString(): ReviseLogSGRecordsContent.fromJson,
     (ReviseLogSGRecordsContent).toString(): ReviseLogSGRecordsContent.fromJson,
     (ReviseLogSGRecordsOption).toString(): ReviseLogSGRecordsOption.fromJson,
     (ReviseLogSGRecordsOption).toString(): ReviseLogSGRecordsOption.fromJson,
+    (SGAttendanceReviewOptionEntity).toString(): SGAttendanceReviewOptionEntity.fromJson,
+    (SGAttendanceReviewTableEntity).toString(): SGAttendanceReviewTableEntity.fromJson,
+    (SGAttendanceReviewTableRows).toString(): SGAttendanceReviewTableRows.fromJson,
+    (SGAttendanceReviewTableRowsCheck).toString(): SGAttendanceReviewTableRowsCheck.fromJson,
+    (SGAttendanceReviewWorkflowEntity).toString(): SGAttendanceReviewWorkflowEntity.fromJson,
+    (SGAttendanceReviewWorkflowRow).toString(): SGAttendanceReviewWorkflowRow.fromJson,
+    (SGAttendanceReviewWorkflowRecords).toString(): SGAttendanceReviewWorkflowRecords.fromJson,
     (SGLabourRequestAddOptionEntity).toString(): SGLabourRequestAddOptionEntity.fromJson,
     (SGLabourRequestAddOptionEntity).toString(): SGLabourRequestAddOptionEntity.fromJson,
     (LabourRequestAgencyEntity).toString(): LabourRequestAgencyEntity.fromJson,
     (LabourRequestAgencyEntity).toString(): LabourRequestAgencyEntity.fromJson,
     (SGLabourRequestDetailEntity).toString(): SGLabourRequestDetailEntity.fromJson,
     (SGLabourRequestDetailEntity).toString(): SGLabourRequestDetailEntity.fromJson,

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

@@ -35,6 +35,10 @@ extension JobListSGEntityExtension on JobListSGEntity {
 
 
 JobListSGRows $JobListSGRowsFromJson(Map<String, dynamic> json) {
 JobListSGRows $JobListSGRowsFromJson(Map<String, dynamic> json) {
   final JobListSGRows jobListSGRows = JobListSGRows();
   final JobListSGRows jobListSGRows = JobListSGRows();
+  final String? source = jsonConvert.convert<String>(json['source']);
+  if (source != null) {
+    jobListSGRows.source = source;
+  }
   final String? jobId = jsonConvert.convert<String>(json['job_id']);
   final String? jobId = jsonConvert.convert<String>(json['job_id']);
   if (jobId != null) {
   if (jobId != null) {
     jobListSGRows.jobId = jobId;
     jobListSGRows.jobId = jobId;
@@ -85,6 +89,7 @@ JobListSGRows $JobListSGRowsFromJson(Map<String, dynamic> json) {
 
 
 Map<String, dynamic> $JobListSGRowsToJson(JobListSGRows entity) {
 Map<String, dynamic> $JobListSGRowsToJson(JobListSGRows entity) {
   final Map<String, dynamic> data = <String, dynamic>{};
   final Map<String, dynamic> data = <String, dynamic>{};
+  data['source'] = entity.source;
   data['job_id'] = entity.jobId;
   data['job_id'] = entity.jobId;
   data['job_date'] = entity.jobDate;
   data['job_date'] = entity.jobDate;
   data['outlet_name'] = entity.outletName;
   data['outlet_name'] = entity.outletName;
@@ -101,6 +106,7 @@ Map<String, dynamic> $JobListSGRowsToJson(JobListSGRows entity) {
 
 
 extension JobListSGRowsExtension on JobListSGRows {
 extension JobListSGRowsExtension on JobListSGRows {
   JobListSGRows copyWith({
   JobListSGRows copyWith({
+    String? source,
     String? jobId,
     String? jobId,
     String? jobDate,
     String? jobDate,
     String? outletName,
     String? outletName,
@@ -114,6 +120,7 @@ extension JobListSGRowsExtension on JobListSGRows {
     List<String>? actionList,
     List<String>? actionList,
   }) {
   }) {
     return JobListSGRows()
     return JobListSGRows()
+      ..source = source ?? this.source
       ..jobId = jobId ?? this.jobId
       ..jobId = jobId ?? this.jobId
       ..jobDate = jobDate ?? this.jobDate
       ..jobDate = jobDate ?? this.jobDate
       ..outletName = outletName ?? this.outletName
       ..outletName = outletName ?? this.outletName

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

@@ -55,7 +55,7 @@ LabourReviewStatusRecords $LabourReviewStatusRecordsFromJson(Map<String, dynamic
   if (auditTime != null) {
   if (auditTime != null) {
     labourReviewStatusRecords.auditTime = auditTime;
     labourReviewStatusRecords.auditTime = auditTime;
   }
   }
-  final dynamic auditMark = json['audit_mark'];
+  final String? auditMark = jsonConvert.convert<String>(json['audit_mark']);
   if (auditMark != null) {
   if (auditMark != null) {
     labourReviewStatusRecords.auditMark = auditMark;
     labourReviewStatusRecords.auditMark = auditMark;
   }
   }
@@ -95,7 +95,7 @@ extension LabourReviewStatusRecordsExtension on LabourReviewStatusRecords {
     String? statusShow,
     String? statusShow,
     String? auditName,
     String? auditName,
     String? auditTime,
     String? auditTime,
-    dynamic auditMark,
+    String? auditMark,
     String? createdAt,
     String? createdAt,
     String? assigneeTypeShow,
     String? assigneeTypeShow,
     String? designationShow,
     String? designationShow,

+ 37 - 0
packages/cs_domain/lib/generated/json/s_g_attendance_review_option_entity.g.dart

@@ -0,0 +1,37 @@
+import 'package:domain/generated/json/base/json_convert_content.dart';
+import 'package:domain/entity/response/s_g_attendance_review_option_entity.dart';
+import 'package:domain/entity/response/index_option_entity.dart';
+
+
+SGAttendanceReviewOptionEntity $SGAttendanceReviewOptionEntityFromJson(Map<String, dynamic> json) {
+  final SGAttendanceReviewOptionEntity sGAttendanceReviewOptionEntity = SGAttendanceReviewOptionEntity();
+  final List<IndexOptionEntity>? sourceList = (json['source_list'] as List<dynamic>?)?.map(
+          (e) => jsonConvert.convert<IndexOptionEntity>(e) as IndexOptionEntity).toList();
+  if (sourceList != null) {
+    sGAttendanceReviewOptionEntity.sourceList = sourceList;
+  }
+  final List<IndexOptionEntity>? outletList = (json['outlet_list'] as List<dynamic>?)?.map(
+          (e) => jsonConvert.convert<IndexOptionEntity>(e) as IndexOptionEntity).toList();
+  if (outletList != null) {
+    sGAttendanceReviewOptionEntity.outletList = outletList;
+  }
+  return sGAttendanceReviewOptionEntity;
+}
+
+Map<String, dynamic> $SGAttendanceReviewOptionEntityToJson(SGAttendanceReviewOptionEntity entity) {
+  final Map<String, dynamic> data = <String, dynamic>{};
+  data['source_list'] = entity.sourceList.map((v) => v.toJson()).toList();
+  data['outlet_list'] = entity.outletList.map((v) => v.toJson()).toList();
+  return data;
+}
+
+extension SGAttendanceReviewOptionEntityExtension on SGAttendanceReviewOptionEntity {
+  SGAttendanceReviewOptionEntity copyWith({
+    List<IndexOptionEntity>? sourceList,
+    List<IndexOptionEntity>? outletList,
+  }) {
+    return SGAttendanceReviewOptionEntity()
+      ..sourceList = sourceList ?? this.sourceList
+      ..outletList = outletList ?? this.outletList;
+  }
+}

+ 264 - 0
packages/cs_domain/lib/generated/json/s_g_attendance_review_table_entity.g.dart

@@ -0,0 +1,264 @@
+import 'package:domain/generated/json/base/json_convert_content.dart';
+import 'package:domain/entity/response/s_g_attendance_review_table_entity.dart';
+
+SGAttendanceReviewTableEntity $SGAttendanceReviewTableEntityFromJson(Map<String, dynamic> json) {
+  final SGAttendanceReviewTableEntity sGAttendanceReviewTableEntity = SGAttendanceReviewTableEntity();
+  final int? total = jsonConvert.convert<int>(json['total']);
+  if (total != null) {
+    sGAttendanceReviewTableEntity.total = total;
+  }
+  final List<SGAttendanceReviewTableRows>? rows = (json['rows'] as List<dynamic>?)?.map(
+          (e) => jsonConvert.convert<SGAttendanceReviewTableRows>(e) as SGAttendanceReviewTableRows).toList();
+  if (rows != null) {
+    sGAttendanceReviewTableEntity.rows = rows;
+  }
+  return sGAttendanceReviewTableEntity;
+}
+
+Map<String, dynamic> $SGAttendanceReviewTableEntityToJson(SGAttendanceReviewTableEntity entity) {
+  final Map<String, dynamic> data = <String, dynamic>{};
+  data['total'] = entity.total;
+  data['rows'] = entity.rows.map((v) => v.toJson()).toList();
+  return data;
+}
+
+extension SGAttendanceReviewTableEntityExtension on SGAttendanceReviewTableEntity {
+  SGAttendanceReviewTableEntity copyWith({
+    int? total,
+    List<SGAttendanceReviewTableRows>? rows,
+  }) {
+    return SGAttendanceReviewTableEntity()
+      ..total = total ?? this.total
+      ..rows = rows ?? this.rows;
+  }
+}
+
+SGAttendanceReviewTableRows $SGAttendanceReviewTableRowsFromJson(Map<String, dynamic> json) {
+  final SGAttendanceReviewTableRows sGAttendanceReviewTableRows = SGAttendanceReviewTableRows();
+  final String? recordId = jsonConvert.convert<String>(json['record_id']);
+  if (recordId != null) {
+    sGAttendanceReviewTableRows.recordId = recordId;
+  }
+  final String? orderId = jsonConvert.convert<String>(json['order_id']);
+  if (orderId != null) {
+    sGAttendanceReviewTableRows.orderId = orderId;
+  }
+  final String? appliedId = jsonConvert.convert<String>(json['applied_id']);
+  if (appliedId != null) {
+    sGAttendanceReviewTableRows.appliedId = appliedId;
+  }
+  final String? staffName = jsonConvert.convert<String>(json['staff_name']);
+  if (staffName != null) {
+    sGAttendanceReviewTableRows.staffName = staffName;
+  }
+  final String? source = jsonConvert.convert<String>(json['source']);
+  if (source != null) {
+    sGAttendanceReviewTableRows.source = source;
+  }
+  final String? statusShow = jsonConvert.convert<String>(json['status_show']);
+  if (statusShow != null) {
+    sGAttendanceReviewTableRows.statusShow = statusShow;
+  }
+  final String? createdAt = jsonConvert.convert<String>(json['created_at']);
+  if (createdAt != null) {
+    sGAttendanceReviewTableRows.createdAt = createdAt;
+  }
+  final String? jobDate = jsonConvert.convert<String>(json['job_date']);
+  if (jobDate != null) {
+    sGAttendanceReviewTableRows.jobDate = jobDate;
+  }
+  final String? outletName = jsonConvert.convert<String>(json['outlet_name']);
+  if (outletName != null) {
+    sGAttendanceReviewTableRows.outletName = outletName;
+  }
+  final String? jobTitle = jsonConvert.convert<String>(json['job_title']);
+  if (jobTitle != null) {
+    sGAttendanceReviewTableRows.jobTitle = jobTitle;
+  }
+  final String? jobTime = jsonConvert.convert<String>(json['job_time']);
+  if (jobTime != null) {
+    sGAttendanceReviewTableRows.jobTime = jobTime;
+  }
+  final String? adjustHours = jsonConvert.convert<String>(json['adjust_hours']);
+  if (adjustHours != null) {
+    sGAttendanceReviewTableRows.adjustHours = adjustHours;
+  }
+  final String? totalHours = jsonConvert.convert<String>(json['total_hours']);
+  if (totalHours != null) {
+    sGAttendanceReviewTableRows.totalHours = totalHours;
+  }
+  final SGAttendanceReviewTableRowsCheck? securityIn = jsonConvert.convert<SGAttendanceReviewTableRowsCheck>(json['security_in']);
+  if (securityIn != null) {
+    sGAttendanceReviewTableRows.securityIn = securityIn;
+  }
+  final SGAttendanceReviewTableRowsCheck? securityOut = jsonConvert.convert<SGAttendanceReviewTableRowsCheck>(json['security_out']);
+  if (securityOut != null) {
+    sGAttendanceReviewTableRows.securityOut = securityOut;
+  }
+  final SGAttendanceReviewTableRowsCheck? workIn = jsonConvert.convert<SGAttendanceReviewTableRowsCheck>(json['work_in']);
+  if (workIn != null) {
+    sGAttendanceReviewTableRows.workIn = workIn;
+  }
+  final SGAttendanceReviewTableRowsCheck? workOut = jsonConvert.convert<SGAttendanceReviewTableRowsCheck>(json['work_out']);
+  if (workOut != null) {
+    sGAttendanceReviewTableRows.workOut = workOut;
+  }
+  final int? sIn = jsonConvert.convert<int>(json['s_in']);
+  if (sIn != null) {
+    sGAttendanceReviewTableRows.sIn = sIn;
+  }
+  final int? sOut = jsonConvert.convert<int>(json['s_out']);
+  if (sOut != null) {
+    sGAttendanceReviewTableRows.sOut = sOut;
+  }
+  final int? wIn = jsonConvert.convert<int>(json['w_in']);
+  if (wIn != null) {
+    sGAttendanceReviewTableRows.wIn = wIn;
+  }
+  final int? wOut = jsonConvert.convert<int>(json['w_out']);
+  if (wOut != null) {
+    sGAttendanceReviewTableRows.wOut = wOut;
+  }
+  final bool? isSelected = jsonConvert.convert<bool>(json['isSelected']);
+  if (isSelected != null) {
+    sGAttendanceReviewTableRows.isSelected = isSelected;
+  }
+  return sGAttendanceReviewTableRows;
+}
+
+Map<String, dynamic> $SGAttendanceReviewTableRowsToJson(SGAttendanceReviewTableRows entity) {
+  final Map<String, dynamic> data = <String, dynamic>{};
+  data['record_id'] = entity.recordId;
+  data['order_id'] = entity.orderId;
+  data['applied_id'] = entity.appliedId;
+  data['staff_name'] = entity.staffName;
+  data['source'] = entity.source;
+  data['status_show'] = entity.statusShow;
+  data['created_at'] = entity.createdAt;
+  data['job_date'] = entity.jobDate;
+  data['outlet_name'] = entity.outletName;
+  data['job_title'] = entity.jobTitle;
+  data['job_time'] = entity.jobTime;
+  data['adjust_hours'] = entity.adjustHours;
+  data['total_hours'] = entity.totalHours;
+  data['security_in'] = entity.securityIn?.toJson();
+  data['security_out'] = entity.securityOut?.toJson();
+  data['work_in'] = entity.workIn?.toJson();
+  data['work_out'] = entity.workOut?.toJson();
+  data['s_in'] = entity.sIn;
+  data['s_out'] = entity.sOut;
+  data['w_in'] = entity.wIn;
+  data['w_out'] = entity.wOut;
+  data['isSelected'] = entity.isSelected;
+  return data;
+}
+
+extension SGAttendanceReviewTableRowsExtension on SGAttendanceReviewTableRows {
+  SGAttendanceReviewTableRows copyWith({
+    String? recordId,
+    String? orderId,
+    String? appliedId,
+    String? staffName,
+    String? source,
+    String? statusShow,
+    String? createdAt,
+    String? jobDate,
+    String? outletName,
+    String? jobTitle,
+    String? jobTime,
+    String? adjustHours,
+    String? totalHours,
+    SGAttendanceReviewTableRowsCheck? securityIn,
+    SGAttendanceReviewTableRowsCheck? securityOut,
+    SGAttendanceReviewTableRowsCheck? workIn,
+    SGAttendanceReviewTableRowsCheck? workOut,
+    int? sIn,
+    int? sOut,
+    int? wIn,
+    int? wOut,
+    bool? isSelected,
+  }) {
+    return SGAttendanceReviewTableRows()
+      ..recordId = recordId ?? this.recordId
+      ..orderId = orderId ?? this.orderId
+      ..appliedId = appliedId ?? this.appliedId
+      ..staffName = staffName ?? this.staffName
+      ..source = source ?? this.source
+      ..statusShow = statusShow ?? this.statusShow
+      ..createdAt = createdAt ?? this.createdAt
+      ..jobDate = jobDate ?? this.jobDate
+      ..outletName = outletName ?? this.outletName
+      ..jobTitle = jobTitle ?? this.jobTitle
+      ..jobTime = jobTime ?? this.jobTime
+      ..adjustHours = adjustHours ?? this.adjustHours
+      ..totalHours = totalHours ?? this.totalHours
+      ..securityIn = securityIn ?? this.securityIn
+      ..securityOut = securityOut ?? this.securityOut
+      ..workIn = workIn ?? this.workIn
+      ..workOut = workOut ?? this.workOut
+      ..sIn = sIn ?? this.sIn
+      ..sOut = sOut ?? this.sOut
+      ..wIn = wIn ?? this.wIn
+      ..wOut = wOut ?? this.wOut
+      ..isSelected = isSelected ?? this.isSelected;
+  }
+}
+
+SGAttendanceReviewTableRowsCheck $SGAttendanceReviewTableRowsCheckFromJson(Map<String, dynamic> json) {
+  final SGAttendanceReviewTableRowsCheck sGAttendanceReviewTableRowsCheck = SGAttendanceReviewTableRowsCheck();
+  final String? time = jsonConvert.convert<String>(json['time']);
+  if (time != null) {
+    sGAttendanceReviewTableRowsCheck.time = time;
+  }
+  final String? temp = jsonConvert.convert<String>(json['temp']);
+  if (temp != null) {
+    sGAttendanceReviewTableRowsCheck.temp = temp;
+  }
+  final String? image = jsonConvert.convert<String>(json['image']);
+  if (image != null) {
+    sGAttendanceReviewTableRowsCheck.image = image;
+  }
+  final int? changed = jsonConvert.convert<int>(json['changed']);
+  if (changed != null) {
+    sGAttendanceReviewTableRowsCheck.changed = changed;
+  }
+  final String? key = jsonConvert.convert<String>(json['key']);
+  if (key != null) {
+    sGAttendanceReviewTableRowsCheck.key = key;
+  }
+  final String? color = jsonConvert.convert<String>(json['color']);
+  if (color != null) {
+    sGAttendanceReviewTableRowsCheck.color = color;
+  }
+  return sGAttendanceReviewTableRowsCheck;
+}
+
+Map<String, dynamic> $SGAttendanceReviewTableRowsCheckToJson(SGAttendanceReviewTableRowsCheck entity) {
+  final Map<String, dynamic> data = <String, dynamic>{};
+  data['time'] = entity.time;
+  data['temp'] = entity.temp;
+  data['image'] = entity.image;
+  data['changed'] = entity.changed;
+  data['key'] = entity.key;
+  data['color'] = entity.color;
+  return data;
+}
+
+extension SGAttendanceReviewTableRowsCheckExtension on SGAttendanceReviewTableRowsCheck {
+  SGAttendanceReviewTableRowsCheck copyWith({
+    String? time,
+    String? temp,
+    String? image,
+    int? changed,
+    String? key,
+    String? color,
+  }) {
+    return SGAttendanceReviewTableRowsCheck()
+      ..time = time ?? this.time
+      ..temp = temp ?? this.temp
+      ..image = image ?? this.image
+      ..changed = changed ?? this.changed
+      ..key = key ?? this.key
+      ..color = color ?? this.color;
+  }
+}

+ 481 - 0
packages/cs_domain/lib/generated/json/s_g_attendance_review_workflow_entity.g.dart

@@ -0,0 +1,481 @@
+import 'package:domain/generated/json/base/json_convert_content.dart';
+import 'package:domain/entity/response/s_g_attendance_review_workflow_entity.dart';
+
+SGAttendanceReviewWorkflowEntity $SGAttendanceReviewWorkflowEntityFromJson(Map<String, dynamic> json) {
+  final SGAttendanceReviewWorkflowEntity sGAttendanceReviewWorkflowEntity = SGAttendanceReviewWorkflowEntity();
+  final SGAttendanceReviewWorkflowRow? row = jsonConvert.convert<SGAttendanceReviewWorkflowRow>(json['row']);
+  if (row != null) {
+    sGAttendanceReviewWorkflowEntity.row = row;
+  }
+  final String? outletId = jsonConvert.convert<String>(json['outlet_id']);
+  if (outletId != null) {
+    sGAttendanceReviewWorkflowEntity.outletId = outletId;
+  }
+  final List<SGAttendanceReviewWorkflowRecords>? records = (json['records'] as List<dynamic>?)?.map(
+          (e) => jsonConvert.convert<SGAttendanceReviewWorkflowRecords>(e) as SGAttendanceReviewWorkflowRecords).toList();
+  if (records != null) {
+    sGAttendanceReviewWorkflowEntity.records = records;
+  }
+  return sGAttendanceReviewWorkflowEntity;
+}
+
+Map<String, dynamic> $SGAttendanceReviewWorkflowEntityToJson(SGAttendanceReviewWorkflowEntity entity) {
+  final Map<String, dynamic> data = <String, dynamic>{};
+  data['row'] = entity.row?.toJson();
+  data['outlet_id'] = entity.outletId;
+  data['records'] = entity.records?.map((v) => v.toJson()).toList();
+  return data;
+}
+
+extension SGAttendanceReviewWorkflowEntityExtension on SGAttendanceReviewWorkflowEntity {
+  SGAttendanceReviewWorkflowEntity copyWith({
+    SGAttendanceReviewWorkflowRow? row,
+    String? outletId,
+    List<SGAttendanceReviewWorkflowRecords>? records,
+  }) {
+    return SGAttendanceReviewWorkflowEntity()
+      ..row = row ?? this.row
+      ..outletId = outletId ?? this.outletId
+      ..records = records ?? this.records;
+  }
+}
+
+SGAttendanceReviewWorkflowRow $SGAttendanceReviewWorkflowRowFromJson(Map<String, dynamic> json) {
+  final SGAttendanceReviewWorkflowRow sGAttendanceReviewWorkflowRow = SGAttendanceReviewWorkflowRow();
+  final String? id = jsonConvert.convert<String>(json['id']);
+  if (id != null) {
+    sGAttendanceReviewWorkflowRow.id = id;
+  }
+  final String? jobId = jsonConvert.convert<String>(json['job_id']);
+  if (jobId != null) {
+    sGAttendanceReviewWorkflowRow.jobId = jobId;
+  }
+  final String? sId = jsonConvert.convert<String>(json['s_id']);
+  if (sId != null) {
+    sGAttendanceReviewWorkflowRow.sId = sId;
+  }
+  final String? memberId = jsonConvert.convert<String>(json['member_id']);
+  if (memberId != null) {
+    sGAttendanceReviewWorkflowRow.memberId = memberId;
+  }
+  final String? labourerId = jsonConvert.convert<String>(json['labourer_id']);
+  if (labourerId != null) {
+    sGAttendanceReviewWorkflowRow.labourerId = labourerId;
+  }
+  final String? labourerName = jsonConvert.convert<String>(json['labourer_name']);
+  if (labourerName != null) {
+    sGAttendanceReviewWorkflowRow.labourerName = labourerName;
+  }
+  final String? labourerNric = jsonConvert.convert<String>(json['labourer_nric']);
+  if (labourerNric != null) {
+    sGAttendanceReviewWorkflowRow.labourerNric = labourerNric;
+  }
+  final int? sourceType = jsonConvert.convert<int>(json['source_type']);
+  if (sourceType != null) {
+    sGAttendanceReviewWorkflowRow.sourceType = sourceType;
+  }
+  final int? employerId = jsonConvert.convert<int>(json['employer_id']);
+  if (employerId != null) {
+    sGAttendanceReviewWorkflowRow.employerId = employerId;
+  }
+  final String? employerName = jsonConvert.convert<String>(json['employer_name']);
+  if (employerName != null) {
+    sGAttendanceReviewWorkflowRow.employerName = employerName;
+  }
+  final int? agencyId = jsonConvert.convert<int>(json['agency_id']);
+  if (agencyId != null) {
+    sGAttendanceReviewWorkflowRow.agencyId = agencyId;
+  }
+  final String? agencyName = jsonConvert.convert<String>(json['agency_name']);
+  if (agencyName != null) {
+    sGAttendanceReviewWorkflowRow.agencyName = agencyName;
+  }
+  final String? jobTitle = jsonConvert.convert<String>(json['job_title']);
+  if (jobTitle != null) {
+    sGAttendanceReviewWorkflowRow.jobTitle = jobTitle;
+  }
+  final String? outletId = jsonConvert.convert<String>(json['outlet_id']);
+  if (outletId != null) {
+    sGAttendanceReviewWorkflowRow.outletId = outletId;
+  }
+  final String? outletName = jsonConvert.convert<String>(json['outlet_name']);
+  if (outletName != null) {
+    sGAttendanceReviewWorkflowRow.outletName = outletName;
+  }
+  final String? ballroomId = jsonConvert.convert<String>(json['ballroom_id']);
+  if (ballroomId != null) {
+    sGAttendanceReviewWorkflowRow.ballroomId = ballroomId;
+  }
+  final String? ballroomName = jsonConvert.convert<String>(json['ballroom_name']);
+  if (ballroomName != null) {
+    sGAttendanceReviewWorkflowRow.ballroomName = ballroomName;
+  }
+  final String? jobDate = jsonConvert.convert<String>(json['job_date']);
+  if (jobDate != null) {
+    sGAttendanceReviewWorkflowRow.jobDate = jobDate;
+  }
+  final int? startTime = jsonConvert.convert<int>(json['start_time']);
+  if (startTime != null) {
+    sGAttendanceReviewWorkflowRow.startTime = startTime;
+  }
+  final int? endTime = jsonConvert.convert<int>(json['end_time']);
+  if (endTime != null) {
+    sGAttendanceReviewWorkflowRow.endTime = endTime;
+  }
+  final String? workingHours = jsonConvert.convert<String>(json['working_hours']);
+  if (workingHours != null) {
+    sGAttendanceReviewWorkflowRow.workingHours = workingHours;
+  }
+  final String? adjustHours = jsonConvert.convert<String>(json['adjust_hours']);
+  if (adjustHours != null) {
+    sGAttendanceReviewWorkflowRow.adjustHours = adjustHours;
+  }
+  final String? totalHours = jsonConvert.convert<String>(json['total_hours']);
+  if (totalHours != null) {
+    sGAttendanceReviewWorkflowRow.totalHours = totalHours;
+  }
+  final String? hourlyRate = jsonConvert.convert<String>(json['hourly_rate']);
+  if (hourlyRate != null) {
+    sGAttendanceReviewWorkflowRow.hourlyRate = hourlyRate;
+  }
+  final String? grossWage = jsonConvert.convert<String>(json['gross_wage']);
+  if (grossWage != null) {
+    sGAttendanceReviewWorkflowRow.grossWage = grossWage;
+  }
+  final int? securityClockIn = jsonConvert.convert<int>(json['security_clock_in']);
+  if (securityClockIn != null) {
+    sGAttendanceReviewWorkflowRow.securityClockIn = securityClockIn;
+  }
+  final int? securityClockOut = jsonConvert.convert<int>(json['security_clock_out']);
+  if (securityClockOut != null) {
+    sGAttendanceReviewWorkflowRow.securityClockOut = securityClockOut;
+  }
+  final int? workClockIn = jsonConvert.convert<int>(json['work_clock_in']);
+  if (workClockIn != null) {
+    sGAttendanceReviewWorkflowRow.workClockIn = workClockIn;
+  }
+  final int? workClockOut = jsonConvert.convert<int>(json['work_clock_out']);
+  if (workClockOut != null) {
+    sGAttendanceReviewWorkflowRow.workClockOut = workClockOut;
+  }
+  final int? securityIn = jsonConvert.convert<int>(json['security_in']);
+  if (securityIn != null) {
+    sGAttendanceReviewWorkflowRow.securityIn = securityIn;
+  }
+  final int? securityOut = jsonConvert.convert<int>(json['security_out']);
+  if (securityOut != null) {
+    sGAttendanceReviewWorkflowRow.securityOut = securityOut;
+  }
+  final int? workIn = jsonConvert.convert<int>(json['work_in']);
+  if (workIn != null) {
+    sGAttendanceReviewWorkflowRow.workIn = workIn;
+  }
+  final int? workOut = jsonConvert.convert<int>(json['work_out']);
+  if (workOut != null) {
+    sGAttendanceReviewWorkflowRow.workOut = workOut;
+  }
+  final int? status = jsonConvert.convert<int>(json['status']);
+  if (status != null) {
+    sGAttendanceReviewWorkflowRow.status = status;
+  }
+  final int? remarkStatus = jsonConvert.convert<int>(json['remark_status']);
+  if (remarkStatus != null) {
+    sGAttendanceReviewWorkflowRow.remarkStatus = remarkStatus;
+  }
+  final String? createdAt = jsonConvert.convert<String>(json['created_at']);
+  if (createdAt != null) {
+    sGAttendanceReviewWorkflowRow.createdAt = createdAt;
+  }
+  final String? updatedAt = jsonConvert.convert<String>(json['updated_at']);
+  if (updatedAt != null) {
+    sGAttendanceReviewWorkflowRow.updatedAt = updatedAt;
+  }
+  final String? agencyRate = jsonConvert.convert<String>(json['agency_rate']);
+  if (agencyRate != null) {
+    sGAttendanceReviewWorkflowRow.agencyRate = agencyRate;
+  }
+  final String? agencyWage = jsonConvert.convert<String>(json['agency_wage']);
+  if (agencyWage != null) {
+    sGAttendanceReviewWorkflowRow.agencyWage = agencyWage;
+  }
+  final int? amendAtt = jsonConvert.convert<int>(json['amend_att']);
+  if (amendAtt != null) {
+    sGAttendanceReviewWorkflowRow.amendAtt = amendAtt;
+  }
+  final int? targetTop = jsonConvert.convert<int>(json['target_top']);
+  if (targetTop != null) {
+    sGAttendanceReviewWorkflowRow.targetTop = targetTop;
+  }
+  final String? rejectMsg = jsonConvert.convert<String>(json['reject_msg']);
+  if (rejectMsg != null) {
+    sGAttendanceReviewWorkflowRow.rejectMsg = rejectMsg;
+  }
+  final String? reviseHours = jsonConvert.convert<String>(json['revise_hours']);
+  if (reviseHours != null) {
+    sGAttendanceReviewWorkflowRow.reviseHours = reviseHours;
+  }
+  final String? reviseGrossWage = jsonConvert.convert<String>(json['revise_gross_wage']);
+  if (reviseGrossWage != null) {
+    sGAttendanceReviewWorkflowRow.reviseGrossWage = reviseGrossWage;
+  }
+  final String? reviseAgencyWage = jsonConvert.convert<String>(json['revise_agency_wage']);
+  if (reviseAgencyWage != null) {
+    sGAttendanceReviewWorkflowRow.reviseAgencyWage = reviseAgencyWage;
+  }
+  final int? skilledWorker = jsonConvert.convert<int>(json['skilled_worker']);
+  if (skilledWorker != null) {
+    sGAttendanceReviewWorkflowRow.skilledWorker = skilledWorker;
+  }
+  final int? hotelStaff = jsonConvert.convert<int>(json['hotel_staff']);
+  if (hotelStaff != null) {
+    sGAttendanceReviewWorkflowRow.hotelStaff = hotelStaff;
+  }
+  final int? salaryStructure = jsonConvert.convert<int>(json['salary_structure']);
+  if (salaryStructure != null) {
+    sGAttendanceReviewWorkflowRow.salaryStructure = salaryStructure;
+  }
+  return sGAttendanceReviewWorkflowRow;
+}
+
+Map<String, dynamic> $SGAttendanceReviewWorkflowRowToJson(SGAttendanceReviewWorkflowRow entity) {
+  final Map<String, dynamic> data = <String, dynamic>{};
+  data['id'] = entity.id;
+  data['job_id'] = entity.jobId;
+  data['s_id'] = entity.sId;
+  data['member_id'] = entity.memberId;
+  data['labourer_id'] = entity.labourerId;
+  data['labourer_name'] = entity.labourerName;
+  data['labourer_nric'] = entity.labourerNric;
+  data['source_type'] = entity.sourceType;
+  data['employer_id'] = entity.employerId;
+  data['employer_name'] = entity.employerName;
+  data['agency_id'] = entity.agencyId;
+  data['agency_name'] = entity.agencyName;
+  data['job_title'] = entity.jobTitle;
+  data['outlet_id'] = entity.outletId;
+  data['outlet_name'] = entity.outletName;
+  data['ballroom_id'] = entity.ballroomId;
+  data['ballroom_name'] = entity.ballroomName;
+  data['job_date'] = entity.jobDate;
+  data['start_time'] = entity.startTime;
+  data['end_time'] = entity.endTime;
+  data['working_hours'] = entity.workingHours;
+  data['adjust_hours'] = entity.adjustHours;
+  data['total_hours'] = entity.totalHours;
+  data['hourly_rate'] = entity.hourlyRate;
+  data['gross_wage'] = entity.grossWage;
+  data['security_clock_in'] = entity.securityClockIn;
+  data['security_clock_out'] = entity.securityClockOut;
+  data['work_clock_in'] = entity.workClockIn;
+  data['work_clock_out'] = entity.workClockOut;
+  data['security_in'] = entity.securityIn;
+  data['security_out'] = entity.securityOut;
+  data['work_in'] = entity.workIn;
+  data['work_out'] = entity.workOut;
+  data['status'] = entity.status;
+  data['remark_status'] = entity.remarkStatus;
+  data['created_at'] = entity.createdAt;
+  data['updated_at'] = entity.updatedAt;
+  data['agency_rate'] = entity.agencyRate;
+  data['agency_wage'] = entity.agencyWage;
+  data['amend_att'] = entity.amendAtt;
+  data['target_top'] = entity.targetTop;
+  data['reject_msg'] = entity.rejectMsg;
+  data['revise_hours'] = entity.reviseHours;
+  data['revise_gross_wage'] = entity.reviseGrossWage;
+  data['revise_agency_wage'] = entity.reviseAgencyWage;
+  data['skilled_worker'] = entity.skilledWorker;
+  data['hotel_staff'] = entity.hotelStaff;
+  data['salary_structure'] = entity.salaryStructure;
+  return data;
+}
+
+extension SGAttendanceReviewWorkflowRowExtension on SGAttendanceReviewWorkflowRow {
+  SGAttendanceReviewWorkflowRow copyWith({
+    String? id,
+    String? jobId,
+    String? sId,
+    String? memberId,
+    String? labourerId,
+    String? labourerName,
+    String? labourerNric,
+    int? sourceType,
+    int? employerId,
+    String? employerName,
+    int? agencyId,
+    String? agencyName,
+    String? jobTitle,
+    String? outletId,
+    String? outletName,
+    String? ballroomId,
+    String? ballroomName,
+    String? jobDate,
+    int? startTime,
+    int? endTime,
+    String? workingHours,
+    String? adjustHours,
+    String? totalHours,
+    String? hourlyRate,
+    String? grossWage,
+    int? securityClockIn,
+    int? securityClockOut,
+    int? workClockIn,
+    int? workClockOut,
+    int? securityIn,
+    int? securityOut,
+    int? workIn,
+    int? workOut,
+    int? status,
+    int? remarkStatus,
+    String? createdAt,
+    String? updatedAt,
+    String? agencyRate,
+    String? agencyWage,
+    int? amendAtt,
+    int? targetTop,
+    String? rejectMsg,
+    String? reviseHours,
+    String? reviseGrossWage,
+    String? reviseAgencyWage,
+    int? skilledWorker,
+    int? hotelStaff,
+    int? salaryStructure,
+  }) {
+    return SGAttendanceReviewWorkflowRow()
+      ..id = id ?? this.id
+      ..jobId = jobId ?? this.jobId
+      ..sId = sId ?? this.sId
+      ..memberId = memberId ?? this.memberId
+      ..labourerId = labourerId ?? this.labourerId
+      ..labourerName = labourerName ?? this.labourerName
+      ..labourerNric = labourerNric ?? this.labourerNric
+      ..sourceType = sourceType ?? this.sourceType
+      ..employerId = employerId ?? this.employerId
+      ..employerName = employerName ?? this.employerName
+      ..agencyId = agencyId ?? this.agencyId
+      ..agencyName = agencyName ?? this.agencyName
+      ..jobTitle = jobTitle ?? this.jobTitle
+      ..outletId = outletId ?? this.outletId
+      ..outletName = outletName ?? this.outletName
+      ..ballroomId = ballroomId ?? this.ballroomId
+      ..ballroomName = ballroomName ?? this.ballroomName
+      ..jobDate = jobDate ?? this.jobDate
+      ..startTime = startTime ?? this.startTime
+      ..endTime = endTime ?? this.endTime
+      ..workingHours = workingHours ?? this.workingHours
+      ..adjustHours = adjustHours ?? this.adjustHours
+      ..totalHours = totalHours ?? this.totalHours
+      ..hourlyRate = hourlyRate ?? this.hourlyRate
+      ..grossWage = grossWage ?? this.grossWage
+      ..securityClockIn = securityClockIn ?? this.securityClockIn
+      ..securityClockOut = securityClockOut ?? this.securityClockOut
+      ..workClockIn = workClockIn ?? this.workClockIn
+      ..workClockOut = workClockOut ?? this.workClockOut
+      ..securityIn = securityIn ?? this.securityIn
+      ..securityOut = securityOut ?? this.securityOut
+      ..workIn = workIn ?? this.workIn
+      ..workOut = workOut ?? this.workOut
+      ..status = status ?? this.status
+      ..remarkStatus = remarkStatus ?? this.remarkStatus
+      ..createdAt = createdAt ?? this.createdAt
+      ..updatedAt = updatedAt ?? this.updatedAt
+      ..agencyRate = agencyRate ?? this.agencyRate
+      ..agencyWage = agencyWage ?? this.agencyWage
+      ..amendAtt = amendAtt ?? this.amendAtt
+      ..targetTop = targetTop ?? this.targetTop
+      ..rejectMsg = rejectMsg ?? this.rejectMsg
+      ..reviseHours = reviseHours ?? this.reviseHours
+      ..reviseGrossWage = reviseGrossWage ?? this.reviseGrossWage
+      ..reviseAgencyWage = reviseAgencyWage ?? this.reviseAgencyWage
+      ..skilledWorker = skilledWorker ?? this.skilledWorker
+      ..hotelStaff = hotelStaff ?? this.hotelStaff
+      ..salaryStructure = salaryStructure ?? this.salaryStructure;
+  }
+}
+
+SGAttendanceReviewWorkflowRecords $SGAttendanceReviewWorkflowRecordsFromJson(Map<String, dynamic> json) {
+  final SGAttendanceReviewWorkflowRecords sGAttendanceReviewWorkflowRecords = SGAttendanceReviewWorkflowRecords();
+  final String? serialNumber = jsonConvert.convert<String>(json['serial_number']);
+  if (serialNumber != null) {
+    sGAttendanceReviewWorkflowRecords.serialNumber = serialNumber;
+  }
+  final String? nodeName = jsonConvert.convert<String>(json['node_name']);
+  if (nodeName != null) {
+    sGAttendanceReviewWorkflowRecords.nodeName = nodeName;
+  }
+  final String? nodeTypeShow = jsonConvert.convert<String>(json['node_type_show']);
+  if (nodeTypeShow != null) {
+    sGAttendanceReviewWorkflowRecords.nodeTypeShow = nodeTypeShow;
+  }
+  final String? statusShow = jsonConvert.convert<String>(json['status_show']);
+  if (statusShow != null) {
+    sGAttendanceReviewWorkflowRecords.statusShow = statusShow;
+  }
+  final String? auditName = jsonConvert.convert<String>(json['audit_name']);
+  if (auditName != null) {
+    sGAttendanceReviewWorkflowRecords.auditName = auditName;
+  }
+  final String? auditTime = jsonConvert.convert<String>(json['audit_time']);
+  if (auditTime != null) {
+    sGAttendanceReviewWorkflowRecords.auditTime = auditTime;
+  }
+  final String? auditMark = jsonConvert.convert<String>(json['audit_mark']);
+  if (auditMark != null) {
+    sGAttendanceReviewWorkflowRecords.auditMark = auditMark;
+  }
+  final String? createdAt = jsonConvert.convert<String>(json['created_at']);
+  if (createdAt != null) {
+    sGAttendanceReviewWorkflowRecords.createdAt = createdAt;
+  }
+  final String? assigneeTypeShow = jsonConvert.convert<String>(json['assignee_type_show']);
+  if (assigneeTypeShow != null) {
+    sGAttendanceReviewWorkflowRecords.assigneeTypeShow = assigneeTypeShow;
+  }
+  final String? designationShow = jsonConvert.convert<String>(json['designation_show']);
+  if (designationShow != null) {
+    sGAttendanceReviewWorkflowRecords.designationShow = designationShow;
+  }
+  return sGAttendanceReviewWorkflowRecords;
+}
+
+Map<String, dynamic> $SGAttendanceReviewWorkflowRecordsToJson(SGAttendanceReviewWorkflowRecords entity) {
+  final Map<String, dynamic> data = <String, dynamic>{};
+  data['serial_number'] = entity.serialNumber;
+  data['node_name'] = entity.nodeName;
+  data['node_type_show'] = entity.nodeTypeShow;
+  data['status_show'] = entity.statusShow;
+  data['audit_name'] = entity.auditName;
+  data['audit_time'] = entity.auditTime;
+  data['audit_mark'] = entity.auditMark;
+  data['created_at'] = entity.createdAt;
+  data['assignee_type_show'] = entity.assigneeTypeShow;
+  data['designation_show'] = entity.designationShow;
+  return data;
+}
+
+extension SGAttendanceReviewWorkflowRecordsExtension on SGAttendanceReviewWorkflowRecords {
+  SGAttendanceReviewWorkflowRecords copyWith({
+    String? serialNumber,
+    String? nodeName,
+    String? nodeTypeShow,
+    String? statusShow,
+    String? auditName,
+    String? auditTime,
+    String? auditMark,
+    String? createdAt,
+    String? assigneeTypeShow,
+    String? designationShow,
+  }) {
+    return SGAttendanceReviewWorkflowRecords()
+      ..serialNumber = serialNumber ?? this.serialNumber
+      ..nodeName = nodeName ?? this.nodeName
+      ..nodeTypeShow = nodeTypeShow ?? this.nodeTypeShow
+      ..statusShow = statusShow ?? this.statusShow
+      ..auditName = auditName ?? this.auditName
+      ..auditTime = auditTime ?? this.auditTime
+      ..auditMark = auditMark ?? this.auditMark
+      ..createdAt = createdAt ?? this.createdAt
+      ..assigneeTypeShow = assigneeTypeShow ?? this.assigneeTypeShow
+      ..designationShow = designationShow ?? this.designationShow;
+  }
+}

+ 8 - 1
packages/cs_domain/lib/generated/json/s_g_labour_review_table_entity.g.dart

@@ -83,6 +83,10 @@ SGLabourReviewTableRows $SGLabourReviewTableRowsFromJson(Map<String, dynamic> js
   if (hiringNum != null) {
   if (hiringNum != null) {
     sGLabourReviewTableRows.hiringNum = hiringNum;
     sGLabourReviewTableRows.hiringNum = hiringNum;
   }
   }
+  final bool? isSelected = jsonConvert.convert<bool>(json['isSelected']);
+  if (isSelected != null) {
+    sGLabourReviewTableRows.isSelected = isSelected;
+  }
   return sGLabourReviewTableRows;
   return sGLabourReviewTableRows;
 }
 }
 
 
@@ -100,6 +104,7 @@ Map<String, dynamic> $SGLabourReviewTableRowsToJson(SGLabourReviewTableRows enti
   data['job_time'] = entity.jobTime;
   data['job_time'] = entity.jobTime;
   data['working_hours'] = entity.workingHours;
   data['working_hours'] = entity.workingHours;
   data['hiring_num'] = entity.hiringNum;
   data['hiring_num'] = entity.hiringNum;
+  data['isSelected'] = entity.isSelected;
   return data;
   return data;
 }
 }
 
 
@@ -117,6 +122,7 @@ extension SGLabourReviewTableRowsExtension on SGLabourReviewTableRows {
     String? jobTime,
     String? jobTime,
     String? workingHours,
     String? workingHours,
     String? hiringNum,
     String? hiringNum,
+    bool? isSelected,
   }) {
   }) {
     return SGLabourReviewTableRows()
     return SGLabourReviewTableRows()
       ..recordId = recordId ?? this.recordId
       ..recordId = recordId ?? this.recordId
@@ -130,6 +136,7 @@ extension SGLabourReviewTableRowsExtension on SGLabourReviewTableRows {
       ..jobTitle = jobTitle ?? this.jobTitle
       ..jobTitle = jobTitle ?? this.jobTitle
       ..jobTime = jobTime ?? this.jobTime
       ..jobTime = jobTime ?? this.jobTime
       ..workingHours = workingHours ?? this.workingHours
       ..workingHours = workingHours ?? this.workingHours
-      ..hiringNum = hiringNum ?? this.hiringNum;
+      ..hiringNum = hiringNum ?? this.hiringNum
+      ..isSelected = isSelected ?? this.isSelected;
   }
   }
 }
 }

+ 172 - 23
packages/cs_domain/lib/repository/job_sg_repository.dart

@@ -1,37 +1,24 @@
 import 'dart:typed_data';
 import 'dart:typed_data';
-
 import 'package:domain/entity/response/job_applied_index_s_g_entity.dart';
 import 'package:domain/entity/response/job_applied_index_s_g_entity.dart';
 import 'package:domain/entity/response/job_applied_list_s_g_entity.dart';
 import 'package:domain/entity/response/job_applied_list_s_g_entity.dart';
-import 'package:domain/entity/response/job_list_add_staff_entity.dart';
-import 'package:domain/entity/response/job_list_applied_edit_entity.dart';
-import 'package:domain/entity/response/job_list_applied_info_entity.dart';
-import 'package:domain/entity/response/job_list_applied_staff_list_entity.dart';
-import 'package:domain/entity/response/job_list_applied_staff_search_entity.dart';
-import 'package:domain/entity/response/job_list_detail_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_remark_view_entity.dart';
 import 'package:domain/entity/response/revise_list_s_g_entity.dart';
 import 'package:domain/entity/response/revise_list_s_g_entity.dart';
 import 'package:domain/entity/response/revise_log_s_g_entity.dart';
 import 'package:domain/entity/response/revise_log_s_g_entity.dart';
-import 'package:domain/entity/response/staff_detail_entity.dart';
+import 'package:domain/entity/response/s_g_attendance_review_option_entity.dart';
+import 'package:domain/entity/response/s_g_attendance_review_table_entity.dart';
+import 'package:domain/entity/response/s_g_attendance_review_workflow_entity.dart';
 import 'package:domain/entity/response/staff_detail_s_g_entity.dart';
 import 'package:domain/entity/response/staff_detail_s_g_entity.dart';
-import 'package:domain/entity/response/staff_labour_history_entity.dart';
-import 'package:domain/entity/response/staff_remark_history_entity.dart';
 import 'package:domain/entity/response/staff_review_history_s_g_entity.dart';
 import 'package:domain/entity/response/staff_review_history_s_g_entity.dart';
 import 'package:get/get.dart';
 import 'package:get/get.dart';
 import 'package:plugin_platform/platform_export.dart';
 import 'package:plugin_platform/platform_export.dart';
 import 'package:plugin_platform/http/http_provider.dart';
 import 'package:plugin_platform/http/http_provider.dart';
 import 'package:plugin_platform/http/http_result.dart';
 import 'package:plugin_platform/http/http_result.dart';
+import 'package:shared/utils/date_time_utils.dart';
 import 'package:shared/utils/util.dart';
 import 'package:shared/utils/util.dart';
-
 import '../constants/api_constants.dart';
 import '../constants/api_constants.dart';
 import '../entity/response/add_edit_revise_view_s_g_entity.dart';
 import '../entity/response/add_edit_revise_view_s_g_entity.dart';
-import '../entity/response/attendance_entity.dart';
-import '../entity/response/check_success_entity.dart';
 import '../entity/response/job_applied_edit_index_s_g_entity.dart';
 import '../entity/response/job_applied_edit_index_s_g_entity.dart';
 import '../entity/response/job_applied_remark_view_s_g_entity.dart';
 import '../entity/response/job_applied_remark_view_s_g_entity.dart';
 import '../entity/response/job_applied_staff_s_g_entity.dart';
 import '../entity/response/job_applied_staff_s_g_entity.dart';
-import '../entity/response/job_list_applied_work_flow_entity.dart';
 import '../entity/response/revise_index_s_g_entity.dart';
 import '../entity/response/revise_index_s_g_entity.dart';
 import '../entity/response/staff_job_history_s_g_entity.dart';
 import '../entity/response/staff_job_history_s_g_entity.dart';
 
 
@@ -293,20 +280,20 @@ class JobSGRepository extends GetxService {
     //参数
     //参数
     Map<String, String> params = {};
     Map<String, String> params = {};
     params['applied_id'] = appliedId ?? "";
     params['applied_id'] = appliedId ?? "";
-    params['start_time'] = startTime ?? "";
-    params['end_time'] = endTime ?? "";
+    params['start_time'] = DateTimeUtils.formatDateStr(startTime!, format: 'HH:mm:ss') ?? "";
+    params['end_time'] = DateTimeUtils.formatDateStr(endTime!, format: 'HH:mm:ss') ?? "";
 
 
     if (!Utils.isEmpty(security_in)) {
     if (!Utils.isEmpty(security_in)) {
-      params['security_in'] = security_in ?? "";
+      params['security_in'] = DateTimeUtils.formatDateStr(security_in!, format: 'HH:mm:ss');
     }
     }
     if (!Utils.isEmpty(security_out)) {
     if (!Utils.isEmpty(security_out)) {
-      params['security_out'] = security_out ?? "";
+      params['security_out'] = DateTimeUtils.formatDateStr(security_out!, format: 'HH:mm:ss');
     }
     }
     if (!Utils.isEmpty(work_in)) {
     if (!Utils.isEmpty(work_in)) {
-      params['work_in'] = work_in ?? "";
+      params['work_in'] = DateTimeUtils.formatDateStr(work_in!, format: 'HH:mm:ss');
     }
     }
     if (!Utils.isEmpty(work_out)) {
     if (!Utils.isEmpty(work_out)) {
-      params['work_out'] = work_out ?? "";
+      params['work_out'] = DateTimeUtils.formatDateStr(work_out!, format: 'HH:mm:ss');
     }
     }
     if (!Utils.isEmpty(adjustHours)) {
     if (!Utils.isEmpty(adjustHours)) {
       params['adjust_hours'] = adjustHours ?? "";
       params['adjust_hours'] = adjustHours ?? "";
@@ -836,4 +823,166 @@ class JobSGRepository extends GetxService {
     }
     }
     return result.convert();
     return result.convert();
   }
   }
+
+  // ===================================  SG 的 Job Attendance Review 相关接口  ↓  ===================================
+
+  /// 考勤审核列表的选项数据
+  Future<HttpResult<SGAttendanceReviewOptionEntity>> fetchAttendanceReviewOption({
+    CancelToken? cancelToken,
+  }) async {
+    final result = await httpProvider.requestNetResult(
+      ApiConstants.apiAttendanceReviewOptionSG,
+      cancelToken: cancelToken,
+    );
+
+    //根据返回的结果,封装原始数据为Bean/Entity对象
+    if (result.isSuccess) {
+      //重新赋值data或list
+      final json = result.getDataJson();
+      var data = SGAttendanceReviewOptionEntity.fromJson(json!);
+      //重新赋值data或list
+      return result.convert<SGAttendanceReviewOptionEntity>(data: data);
+    }
+    return result.convert();
+  }
+
+  /// 考勤审核列表 Table
+  Future<HttpResult<SGAttendanceReviewTableEntity>> fetchAttendanceReviewTable({
+    String? recordId,
+    String? agencyId,
+    String? startDate,
+    String? endDate,
+    String? outletId,
+    String? keyword,
+    String? status,
+    required int curPage,
+    CancelToken? cancelToken,
+  }) async {
+    Map<String, String> params = {};
+    params['cur_page'] = curPage.toString();
+    params['page_size'] = "10";
+
+    if (Utils.isNotEmpty(recordId)) {
+      params['record_id'] = recordId ?? "";
+    }
+    if (Utils.isNotEmpty(agencyId)) {
+      params['agency_id'] = agencyId ?? "";
+    }
+    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 ?? "";
+    }
+    if (Utils.isNotEmpty(keyword)) {
+      params['job_title'] = keyword ?? "";
+    }
+
+    final result = await httpProvider.requestNetResult(
+      ApiConstants.apiAttendanceReviewTableSG,
+      params: params,
+      cancelToken: cancelToken,
+    );
+
+    //根据返回的结果,封装原始数据为Bean/Entity对象
+    if (result.isSuccess) {
+      //重新赋值data或list
+      final json = result.getDataJson();
+      var data = SGAttendanceReviewTableEntity.fromJson(json!);
+      //重新赋值data或list
+      return result.convert<SGAttendanceReviewTableEntity>(data: data);
+    }
+    return result.convert();
+  }
+
+  /// 考勤审核的批量同意
+  Future<HttpResult> approveAttendanceReviews(
+    String? recordIds, {
+    CancelToken? cancelToken,
+  }) async {
+    //参数
+    Map<String, String> params = {};
+    params['record_ids'] = recordIds ?? "";
+
+    final result = await httpProvider.requestNetResult(
+      ApiConstants.apiAttendanceReviewApproveSG,
+      method: HttpMethod.POST,
+      params: params,
+      networkDebounce: true,
+      isShowLoadingDialog: true,
+      cancelToken: cancelToken,
+    );
+
+    //根据返回的结果,封装原始数据为Bean/Entity对象
+    if (result.isSuccess) {
+      //重新赋值data或list
+      return result.convert();
+    }
+    return result.convert();
+  }
+
+  /// 考勤审核的批量拒绝
+  Future<HttpResult> rejectAttendanceReviews(
+    String? recordIds,
+    String? reason, {
+    CancelToken? cancelToken,
+  }) async {
+    //参数
+    Map<String, String> params = {};
+    params['record_ids'] = recordIds ?? "";
+
+    if (Utils.isNotEmpty(reason)) {
+      params['audit_mark'] = reason ?? "";
+    }
+
+    final result = await httpProvider.requestNetResult(
+      ApiConstants.apiAttendanceReviewRejectSG,
+      method: HttpMethod.POST,
+      params: params,
+      networkDebounce: true,
+      isShowLoadingDialog: true,
+      cancelToken: cancelToken,
+    );
+
+    //根据返回的结果,封装原始数据为Bean/Entity对象
+    if (result.isSuccess) {
+      //重新赋值data或list
+      return result.convert();
+    }
+    return result.convert();
+  }
+
+  /// 考勤审核的状态流
+  Future<HttpResult<SGAttendanceReviewWorkflowEntity>> fetchAttendanceReviewWorkFlow(
+      String? appliedId, {
+        CancelToken? cancelToken,
+      }) async {
+    //参数
+    Map<String, String> params = {};
+    params['applied_id'] = appliedId ?? "";
+
+    final result = await httpProvider.requestNetResult(
+      ApiConstants.apiAttendanceReviewWorkflowSG,
+      params: params,
+      isShowLoadingDialog: true,
+      cancelToken: cancelToken,
+    );
+
+    //根据返回的结果,封装原始数据为Bean/Entity对象
+    if (result.isSuccess) {
+      //重新赋值data或list
+      final json = result.getDataJson();
+      var data = SGAttendanceReviewWorkflowEntity.fromJson(json!);
+      //重新赋值data或list
+      return result.convert<SGAttendanceReviewWorkflowEntity>(data: data);
+    }
+    return result.convert();
+  }
+
 }
 }

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

@@ -1095,17 +1095,17 @@ class LabourSGRepository extends GetxService {
     return result.convert();
     return result.convert();
   }
   }
 
 
-  //用工请求的考勤确认(Job List)
-  Future<HttpResult> confirmJobList(
-    String? jobId, {
+  //用工请求的考勤确认(Job List)发送到考勤
+  Future<HttpResult> approveAppliedJob(
+    String? appliedIds, {
     CancelToken? cancelToken,
     CancelToken? cancelToken,
   }) async {
   }) async {
     //参数
     //参数
     Map<String, String> params = {};
     Map<String, String> params = {};
-    params['job_id'] = jobId ?? "";
+    params['applied_ids'] = appliedIds ?? "";
 
 
     final result = await httpProvider.requestNetResult(
     final result = await httpProvider.requestNetResult(
-      ApiConstants.apiJobListConfirmSG,
+      ApiConstants.apiJobAppliedApproveSG,
       method: HttpMethod.POST,
       method: HttpMethod.POST,
       params: params,
       params: params,
       networkDebounce: true,
       networkDebounce: true,