liukai 6 giorni fa
parent
commit
5ec898ae92
36 ha cambiato i file con 3320 aggiunte e 26 eliminazioni
  1. 1 1
      packages/cpt_report/lib/modules/report_labour/report_labour_item.dart
  2. 179 0
      packages/cpt_uk/lib/modules/report/attendance_report/attendance_report_controller.dart
  3. 245 0
      packages/cpt_uk/lib/modules/report/attendance_report/attendance_report_item.dart
  4. 124 0
      packages/cpt_uk/lib/modules/report/attendance_report/attendance_report_page.dart
  5. 13 0
      packages/cpt_uk/lib/modules/report/attendance_report/attendance_report_state.dart
  6. 364 0
      packages/cpt_uk/lib/modules/report/attendance_report/widget/attendance_report_filter.dart
  7. 85 0
      packages/cpt_uk/lib/modules/report/casual_payout_report/casual_payout_report_controller.dart
  8. 142 0
      packages/cpt_uk/lib/modules/report/casual_payout_report/casual_payout_report_item.dart
  9. 125 0
      packages/cpt_uk/lib/modules/report/casual_payout_report/casual_payout_report_page.dart
  10. 10 0
      packages/cpt_uk/lib/modules/report/casual_payout_report/casual_payout_report_state.dart
  11. 147 0
      packages/cpt_uk/lib/modules/report/casual_report/casual_report_controller.dart
  12. 108 0
      packages/cpt_uk/lib/modules/report/casual_report/casual_report_item.dart
  13. 129 0
      packages/cpt_uk/lib/modules/report/casual_report/casual_report_page.dart
  14. 9 0
      packages/cpt_uk/lib/modules/report/casual_report/casual_report_state.dart
  15. 81 0
      packages/cpt_uk/lib/modules/report/finance_report/report_finance_controller.dart
  16. 111 0
      packages/cpt_uk/lib/modules/report/finance_report/report_finance_item.dart
  17. 190 0
      packages/cpt_uk/lib/modules/report/finance_report/report_finance_page.dart
  18. 11 0
      packages/cpt_uk/lib/modules/report/finance_report/report_finance_state.dart
  19. 2 2
      packages/cpt_uk/lib/modules/report/labour_report/labour_report_item.dart
  20. 1 1
      packages/cpt_uk/lib/modules/report/labour_report/labour_report_page.dart
  21. 0 1
      packages/cpt_uk/lib/modules/report/labour_report/widget/labour_report_filter.dart
  22. 105 0
      packages/cpt_uk/lib/modules/report/outlet_staff_report/outlet_staff_report_controller.dart
  23. 76 0
      packages/cpt_uk/lib/modules/report/outlet_staff_report/outlet_staff_report_item.dart
  24. 144 0
      packages/cpt_uk/lib/modules/report/outlet_staff_report/outlet_staff_report_page.dart
  25. 9 0
      packages/cpt_uk/lib/modules/report/outlet_staff_report/outlet_staff_report_state.dart
  26. 13 6
      packages/cpt_uk/lib/modules/report/report_list/report_list_controller.dart
  27. 318 0
      packages/cpt_uk/lib/modules/report/working_hours_report/widget/working_hours_filter.dart
  28. 172 0
      packages/cpt_uk/lib/modules/report/working_hours_report/working_hours_report_controller.dart
  29. 200 0
      packages/cpt_uk/lib/modules/report/working_hours_report/working_hours_report_item.dart
  30. 124 0
      packages/cpt_uk/lib/modules/report/working_hours_report/working_hours_report_page.dart
  31. 12 0
      packages/cpt_uk/lib/modules/report/working_hours_report/working_hours_report_state.dart
  32. 42 0
      packages/cpt_uk/lib/router/uk_router.dart
  33. 15 14
      packages/cs_domain/lib/repository/job_repository.dart
  34. 3 0
      packages/cs_resources/lib/local/language/en_US.dart
  35. 4 1
      packages/cs_resources/lib/local/language/zh_CN.dart
  36. 6 0
      packages/cs_router/lib/path/router_path.dart

+ 1 - 1
packages/cpt_report/lib/modules/report_labour/report_labour_item.dart

@@ -10,7 +10,7 @@ import 'package:widgets/my_text_view.dart';
 
 class ReportLabourItem extends StatelessWidget {
   LabourReportEntity? entity; //主体数据
-  int type; //0  1  2
+  int type; //0 Completed  1 Incomplete  2 Completed + Incomplete
 
   ReportLabourItem({
     required this.entity,

+ 179 - 0
packages/cpt_uk/lib/modules/report/attendance_report/attendance_report_controller.dart

@@ -0,0 +1,179 @@
+import 'package:domain/entity/response/attendance_entity.dart';
+import 'package:domain/entity/response/labour_request_index_entity.dart';
+import 'package:domain/entity/response/labour_review_list_entity.dart';
+import 'package:domain/repository/job_repository.dart';
+import 'package:domain/repository/labour_repository.dart';
+import 'package:get/get.dart';
+import 'package:plugin_platform/engine/dialog/dialog_engine.dart';
+import 'package:plugin_platform/engine/notify/notify_engine.dart';
+import 'package:plugin_platform/engine/toast/toast_engine.dart';
+import 'package:plugin_platform/http/dio/dio_cancelable_mixin.dart';
+import 'package:plugin_platform/http/http_result.dart';
+import 'package:shared/utils/date_time_utils.dart';
+import 'package:shared/utils/log_utils.dart';
+import 'package:shared/utils/util.dart';
+import 'package:widgets/dialog/app_default_dialog.dart';
+import 'package:widgets/load_state_layout.dart';
+import 'package:widgets/widget_export.dart';
+import 'widget/attendance_report_filter.dart';
+import 'attendance_report_state.dart';
+
+class AttendanceReportController extends GetxController with DioCancelableMixin {
+  final LabourRepository _labourRepository = Get.find();
+  final JobRepository _jobRepository = Get.find();
+  final AttendanceReportState state = AttendanceReportState();
+
+  var _curPage = 1;
+  var _needShowPlaceholder = true;
+
+  //页面PlaceHolder的展示
+  LoadState loadingState = LoadState.State_Success;
+  String? errorMessage;
+
+  //刷新页面状态
+  void changeLoadingState(LoadState state) {
+    loadingState = state;
+    update();
+  }
+
+  // Refresh 控制器
+  final EasyRefreshController refreshController = EasyRefreshController(
+    controlFinishRefresh: true,
+    controlFinishLoad: true,
+  );
+
+  // Refresh 刷新事件
+  Future onRefresh() async {
+    _curPage = 1;
+    fetchAppliedStaffList();
+  }
+
+  // Refresh 加载事件
+  Future loadMore() async {
+    _curPage++;
+    fetchAppliedStaffList();
+  }
+
+  // 重试请求
+  Future retryRequest() async {
+    _curPage = 1;
+    _needShowPlaceholder = true;
+    fetchAppliedStaffList();
+  }
+
+  /// 获取服务器数据,通知消息列表
+  Future fetchAppliedStaffList() async {
+    if (_needShowPlaceholder) {
+      changeLoadingState(LoadState.State_Loading);
+    }
+
+    // 并发执行两个请求,拿到选项数据与列表数据
+    var futures = [
+      _jobRepository.fetchAttendanceList(
+        state.staffName,
+        DateTimeUtils.formatDate(state.selectedStartDate, format: "yyyy-MM-dd"),
+        DateTimeUtils.formatDate(state.selectedEndDate, format: "yyyy-MM-dd"),
+        curPage: _curPage,
+        pageSize: 10,
+        cancelToken: cancelToken,
+      ),
+      state.indexOptions == null
+          ? _labourRepository.fetchLabourReviewIndex(
+              cancelToken: cancelToken,
+            )
+          : Future(() => HttpResult(isSuccess: true).convert(data: state.indexOptions!)),
+    ];
+
+    //拿到结果
+    var results = await Future.wait(futures);
+    var listResult = results[0] as HttpResult<AttendanceEntity>;
+    var optionResult = results[1] as HttpResult<LabourRequestIndexEntity>;
+
+    //选项数据
+    if (state.indexOptions == null && optionResult.isSuccess) {
+      state.indexOptions = optionResult.data!;
+    }
+
+    // 处理数据
+    if (listResult.isSuccess) {
+      handleList(listResult.data?.rows);
+    } else {
+      errorMessage = listResult.errorMsg;
+      changeLoadingState(LoadState.State_Error);
+    }
+
+    // 最后赋值
+    _needShowPlaceholder = false;
+  }
+
+  // 处理数据与展示的逻辑
+  void handleList(List<AttendanceList>? list) {
+    if (list != null && list.isNotEmpty) {
+      //有数据,判断是刷新还是加载更多的数据
+      if (_curPage == 1) {
+        //刷新的方式
+        state.datas.clear();
+        state.datas.addAll(list);
+        refreshController.finishRefresh();
+
+        //更新展示的状态
+        changeLoadingState(LoadState.State_Success);
+      } else {
+        //加载更多
+        state.datas.addAll(list);
+        refreshController.finishLoad();
+        update();
+      }
+    } else {
+      if (_curPage == 1) {
+        //展示无数据的布局
+        state.datas.clear();
+        changeLoadingState(LoadState.State_Empty);
+        refreshController.finishRefresh();
+      } else {
+        //展示加载完成,没有更多数据了
+        refreshController.finishLoad(IndicatorResult.noMore);
+      }
+    }
+  }
+
+  @override
+  void onReady() {
+    super.onReady();
+    fetchAppliedStaffList();
+  }
+
+  @override
+  void onClose() {
+    state.datas.clear();
+    super.onClose();
+  }
+
+  /// 展示顶部的筛选
+  void showFilterDialog() {
+    if (state.indexOptions != null) {
+      DialogEngine.show(
+        widget: AttendanceReportFilter(
+          optionResult: state.indexOptions!,
+          selectedStartDate: state.selectedStartDate,
+          selectedEndDate: state.selectedEndDate,
+          selectedDepartmentId: state.selectedDepartmentId,
+          staffName: state.staffName,
+          onFilterAction: (startDate, endDate, departmentId,staffName) {
+            state.selectedStartDate = startDate;
+            state.selectedEndDate = endDate;
+            state.selectedDepartmentId = departmentId;
+            state.staffName = staffName;
+
+            Log.d("筛选的值为:startDate:$startDate endDate:$endDate departmentId:$departmentId staffName:$staffName");
+
+            //赋值之后刷新
+            refreshController.callRefresh();
+          },
+        ),
+        position: DialogPosition.top,
+        animType: DialogAnimation.fade,
+      );
+    }
+  }
+}

+ 245 - 0
packages/cpt_uk/lib/modules/report/attendance_report/attendance_report_item.dart

@@ -0,0 +1,245 @@
+import 'package:cs_resources/constants/color_constants.dart';
+import 'package:domain/entity/response/attendance_entity.dart';
+import 'package:flutter/cupertino.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter/widgets.dart';
+import 'package:plugin_basic/basic_export.dart';
+import 'package:widgets/ext/ex_widget.dart';
+import 'package:widgets/my_text_view.dart';
+
+/*
+ * 考勤列表
+ */
+class AttendanceReportItem extends StatelessWidget {
+  final int index;
+  final AttendanceList item;
+
+  AttendanceReportItem({
+    required this.index,
+    required this.item,
+  });
+
+  @override
+  Widget build(BuildContext context) {
+    return Container(
+      padding: const EdgeInsets.symmetric(vertical: 23, horizontal: 21),
+      margin: const EdgeInsets.only(left: 15, right: 15, top: 5, bottom: 5),
+      decoration: BoxDecoration(
+        color: const Color(0xFF4DCFF6).withOpacity(0.2), // 设置背景颜色和不透明度
+        borderRadius: BorderRadius.circular(5), // 设置圆角
+      ),
+      child: Column(
+        mainAxisSize: MainAxisSize.max,
+        crossAxisAlignment: CrossAxisAlignment.start,
+        children: [
+          // 工作日期
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "${"Job Date".tr}:",
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+
+              //日期
+              MyTextView(
+                item.jobDate ?? "-",
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor: Colors.white,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ),
+
+          // 部门
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "Outlet:".tr,
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+
+              //部门
+              MyTextView(
+                "等待部门返回字段",
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor: Colors.white,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ).marginOnly(top: 15),
+
+          // 员工姓名
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "${"Staff Name".tr}:",
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+
+              // 员工姓名
+              MyTextView(
+                item.staffName ?? "-",
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor: Colors.white,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ).marginOnly(top: 15),
+
+          // 开始时间
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "Start Time:".tr,
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+
+              //日期时间
+              MyTextView(
+                item.startTime ?? "-",
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor: Colors.white,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ).marginOnly(top: 15),
+
+          // 结束时间
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "End Time:".tr,
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+
+              //日期时间
+              MyTextView(
+                item.endTime ?? "-",
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor: Colors.white,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ).marginOnly(top: 15),
+
+          // 签到时间
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "Work In:".tr,
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+
+              //文本
+              MyTextView(
+                item.checkInTime.toString(),
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor: Colors.white,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ).marginOnly(top: 15),
+
+          // 签出时间
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "Work Out:".tr,
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+
+              //文本
+              MyTextView(
+                item.checkOutTime ?? "-",
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor: Colors.white,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ).marginOnly(top: 15),
+
+          // 加减时间
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "+/- Hours:".tr,
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+
+              //文本
+              MyTextView(
+               "等待修改时间的字段",
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor: Colors.white,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ).marginOnly(top: 15),
+
+          // 总时间
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "Total Hours:".tr,
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+
+              //文本
+              MyTextView(
+                 "等待总时长的字段",
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor: Colors.white,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ).marginOnly(top: 15),
+        ],
+      ),
+    );
+  }
+}

+ 124 - 0
packages/cpt_uk/lib/modules/report/attendance_report/attendance_report_page.dart

@@ -0,0 +1,124 @@
+import 'package:cs_resources/constants/color_constants.dart';
+import 'package:cs_resources/generated/assets.dart';
+import 'package:flutter/cupertino.dart';
+import 'package:flutter/material.dart';
+import 'package:get/get.dart';
+import 'package:widgets/ext/ex_widget.dart';
+import 'package:widgets/load_state_layout.dart';
+import 'package:widgets/my_button.dart';
+import 'package:widgets/my_load_image.dart';
+import 'package:widgets/my_text_view.dart';
+import 'package:widgets/widget_export.dart';
+
+import 'attendance_report_item.dart';
+import 'attendance_report_controller.dart';
+
+import 'package:plugin_basic/base/base_state.dart';
+import 'package:plugin_basic/base/base_stateful_page.dart';
+import 'package:plugin_basic/utils/ext_get_nav.dart';
+import 'package:router/path/router_path.dart';
+import 'package:shared/utils/screen_util.dart';
+import 'package:widgets/my_appbar.dart';
+import 'attendance_report_state.dart';
+
+/*
+ * 考勤报表
+ */
+class UKAttendanceReportPage extends BaseStatefulPage<AttendanceReportController> {
+  UKAttendanceReportPage({Key? key}) : super(key: key);
+
+  //启动当前页面
+  static void startInstance() {
+    return Get.start(RouterPath.UKReportAttendance);
+  }
+
+  @override
+  AttendanceReportController createRawController() {
+    return AttendanceReportController();
+  }
+
+  @override
+  State<UKAttendanceReportPage> createState() => _LabourReviewState();
+}
+
+class _LabourReviewState extends BaseState<UKAttendanceReportPage, AttendanceReportController> {
+  late AttendanceReportState state;
+
+  @override
+  void initState() {
+    super.initState();
+    state = controller.state;
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return autoCtlGetBuilder(builder: (controller) {
+      return SafeArea(
+        bottom: true,
+        top: false,
+        child: Container(
+          width: double.infinity,
+          height: double.infinity,
+          padding: EdgeInsets.only(top: ScreenUtil.getStatusBarH(context)),
+          decoration: const BoxDecoration(
+            gradient: LinearGradient(
+              colors: [
+                Color(0xFF091D44),
+                Color(0xFF245A8A),
+                Color(0xFF7F7CEC),
+              ],
+              begin: Alignment.topCenter,
+              end: Alignment.bottomCenter,
+            ),
+          ),
+          child: Column(
+            children: [
+              MyAppBar.titleBar(
+                context,
+                "E-Attendance".tr,
+                actions: [
+                  //筛选图标
+                  const MyAssetImage(
+                    Assets.baseServiceTitleBarFilterIcon,
+                    width: 24,
+                    height: 16.5,
+                  ).onTap(() {
+                    FocusScope.of(context).unfocus();
+                    controller.showFilterDialog();
+                  }).marginOnly(right: 15),
+                ],
+              ),
+
+              //底部的列表
+              EasyRefresh(
+                controller: controller.refreshController,
+                onRefresh: controller.onRefresh,
+                onLoad: controller.loadMore,
+                child: LoadStateLayout(
+                  state: controller.loadingState,
+                  errorMessage: controller.errorMessage,
+                  errorRetry: () {
+                    controller.retryRequest();
+                  },
+                  successSliverWidget: [
+                    SliverList(
+                        delegate: SliverChildBuilderDelegate(
+                      (context, index) {
+                        return AttendanceReportItem(
+                          index: index,
+                          item: state.datas[index],
+                        );
+                      },
+                      childCount: state.datas.length,
+                    ))
+                  ],
+                ),
+              ).expanded(),
+
+            ],
+          ),
+        ),
+      );
+    });
+  }
+}

+ 13 - 0
packages/cpt_uk/lib/modules/report/attendance_report/attendance_report_state.dart

@@ -0,0 +1,13 @@
+import 'package:domain/entity/response/attendance_entity.dart';
+import 'package:domain/entity/response/labour_request_index_entity.dart';
+
+class AttendanceReportState {
+  String? staffName;
+  DateTime? selectedStartDate;
+  DateTime? selectedEndDate;
+  String? selectedDepartmentId;
+
+  //页面的列表数据
+  List<AttendanceList> datas = [];
+  LabourRequestIndexEntity? indexOptions;
+}

+ 364 - 0
packages/cpt_uk/lib/modules/report/attendance_report/widget/attendance_report_filter.dart

@@ -0,0 +1,364 @@
+import 'dart:typed_data';
+import 'dart:ui';
+import 'package:cs_resources/generated/assets.dart';
+import 'package:domain/entity/response/labour_request_index_entity.dart';
+import 'package:flutter/cupertino.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter/widgets.dart';
+import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
+import 'package:get/get.dart';
+import 'package:plugin_platform/engine/toast/toast_engine.dart';
+import 'package:shared/utils/date_time_utils.dart';
+import 'package:shared/utils/screen_util.dart';
+import 'package:shared/utils/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_field.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 AttendanceReportFilter extends StatefulWidget {
+  void Function(DateTime? selectedStartDate, DateTime? selectedEndDate, String? selectedDepartmentId, String? staffName)? onFilterAction;
+  LabourRequestIndexEntity optionResult;
+  DateTime? selectedStartDate;
+  DateTime? selectedEndDate;
+  String? selectedDepartmentId;
+  String? staffName;
+
+  AttendanceReportFilter({
+    required this.optionResult,
+    required this.selectedStartDate,
+    required this.selectedEndDate,
+    required this.selectedDepartmentId,
+    required this.staffName,
+    this.onFilterAction,
+  });
+
+  @override
+  State<AttendanceReportFilter> createState() => _LabourReviewFilterState();
+}
+
+class _LabourReviewFilterState extends State<AttendanceReportFilter> {
+  DateTime? selectedStartDate;
+  DateTime? selectedEndDate;
+  String? selectedStatusId;
+  String? selectedDepartmentId;
+  String? staffName;
+  late TextEditingController textController;
+  late FocusNode textFocusNode;
+
+  @override
+  void initState() {
+    super.initState();
+    this.selectedStartDate = widget.selectedStartDate;
+    this.selectedEndDate = widget.selectedEndDate;
+    this.selectedDepartmentId = widget.selectedDepartmentId;
+    this.staffName = widget.staffName;
+    textController = TextEditingController();
+    textFocusNode = FocusNode();
+    if (Utils.isNotEmpty(staffName)) {
+      textController.text = staffName!;
+    }
+  }
+
+  @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(
+                "Staff Name".tr,
+                fontSize: 14,
+                isFontMedium: true,
+                textColor: ColorConstants.black33,
+              ),
+
+              //输入标题搜索
+              IgnoreKeyboardDismiss(
+                child: MyTextField(
+                  "staff",
+                  staffName == null ? "" : staffName!,
+                  hintText: "Enter...".tr,
+                  hintStyle: const TextStyle(
+                    color: ColorConstants.gray88,
+                    fontSize: 14,
+                    fontWeight: FontWeight.w400,
+                  ),
+                  controller: textController,
+                  focusNode: textFocusNode,
+                  margin: const EdgeInsets.only(left: 0, right: 0, top: 8),
+                  showDivider: false,
+                  fillBackgroundColor: ColorConstants.grayECECEC,
+                  fillCornerRadius: 5,
+                  padding: const EdgeInsets.only(left: 16, right: 16, top: 0, bottom: 0),
+                  height: 40,
+                  style: const TextStyle(
+                    color: ColorConstants.black33,
+                    fontSize: 14,
+                    fontWeight: FontWeight.w400,
+                  ),
+                  inputType: TextInputType.text,
+                  textInputAction: TextInputAction.done,
+                  enabled: true,
+                  onSubmit: (key, value) {},
+                  cursorColor: ColorConstants.black33,
+                  showLeftIcon: false,
+                  showRightIcon: false,
+                ),
+              ),
+
+              //部门
+              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(
+                      selectedDepartmentId == null || selectedDepartmentId == "0"
+                          ? ""
+                          : widget.optionResult.departmentList!.firstWhere((element) => element.value.toString() == selectedDepartmentId).txt!,
+                      hint: "Choose Outlet".tr,
+                      textHintColor: ColorConstants.textBlackHint,
+                      fontSize: 14,
+                      isFontMedium: true,
+                      textColor: ColorConstants.black33,
+                    ).expanded(),
+                    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.selectedDepartmentId = null;
+                      widget.staffName = null;
+
+                      setState(() {
+                        selectedStartDate = null;
+                        selectedEndDate = null;
+                        selectedStatusId = null;
+                        selectedDepartmentId = null;
+                        staffName = null;
+                        textController.text = "";
+                      });
+                    },
+                    text: "Reset".tr,
+                    textColor: ColorConstants.white,
+                    backgroundColor: hexToColor("#FFBB1B"),
+                    radius: 17.25,
+                    minWidth: 60,
+                    minHeight: 36,
+                  ).expanded(),
+                  const SizedBox(width: 15),
+                  MyButton(
+                    onPressed: () {
+                      onCancel();
+                      //取消软键盘
+                      textFocusNode.unfocus();
+                      //确定的时候取输入框的值
+                      staffName = textController.text;
+                      widget.onFilterAction?.call(selectedStartDate, selectedEndDate, selectedDepartmentId, staffName);
+                    },
+                    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() {
+   FocusScope.of(context).unfocus();
+
+    DatePickerUtil.showCupertinoDatePicker(
+      selectedDateTime: selectedStartDate,
+      onDateTimeChanged: (date) {
+        setState(() {
+          selectedStartDate = date;
+        });
+      },
+      title: "Start Date".tr,
+    );
+  }
+
+  /// 筛选结束日期
+  void pickerEndDate() {
+    FocusScope.of(context).unfocus();
+
+    DatePickerUtil.showCupertinoDatePicker(
+      selectedDateTime: selectedEndDate ?? selectedStartDate,
+      onDateTimeChanged: (date) {
+        setState(() {
+          selectedEndDate = date;
+        });
+      },
+      title: "End Date".tr,
+    );
+  }
+
+  /// 筛选部门
+  void pickerOutlet() {
+    FocusScope.of(context).unfocus();
+
+    int selectedDepartmentIndex;
+    if (selectedDepartmentId == null) {
+      selectedDepartmentIndex = 0;
+    } else {
+      selectedDepartmentIndex = widget.optionResult.departmentList!.indexWhere((department) => department.value.toString() == selectedDepartmentId);
+    }
+
+    if (selectedDepartmentIndex < 0) {
+      selectedDepartmentIndex = 0;
+    }
+
+    OptionPickerUtil.showCupertinoOptionPicker(
+      items: widget.optionResult.departmentList!.map((e) => e.txt!).toList(growable: false),
+      initialSelectIndex: selectedDepartmentIndex,
+      onPickerChanged: (_, index) {
+        setState(() {
+          selectedDepartmentId = widget.optionResult.departmentList![index].value!.toString();
+        });
+      },
+    );
+  }
+
+}

+ 85 - 0
packages/cpt_uk/lib/modules/report/casual_payout_report/casual_payout_report_controller.dart

@@ -0,0 +1,85 @@
+import 'package:domain/entity/response/staff_request_report_entity.dart';
+import 'package:domain/repository/other_repository.dart';
+import 'package:get/get.dart';
+import 'package:plugin_platform/http/dio/dio_cancelable_mixin.dart';
+import 'package:shared/utils/date_time_utils.dart';
+import 'package:widgets/load_state_layout.dart';
+import 'package:widgets/picker/date_picker_util.dart';
+
+import 'casual_payout_report_state.dart';
+
+class CasualPayoutReportController extends GetxController with DioCancelableMixin {
+  final OtherRepository _otherRepository = Get.find();
+  final CasualPayoutReportState state = CasualPayoutReportState();
+
+  //页面PlaceHolder的展示
+  LoadState loadingState = LoadState.State_Loading;
+  String? errorMessage;
+
+  //刷新页面状态
+  void changeLoadingState(LoadState state) {
+    loadingState = state;
+    update();
+  }
+
+  //重试
+  void retryRequest() {
+    fetchReportData();
+  }
+
+  // 获取当前列表数据
+  void fetchReportData() async {
+    changeLoadingState(LoadState.State_Loading);
+
+    var result = await _otherRepository.fetchReportLabour(
+      DateTimeUtils.formatDate(state.startDateTime, format: "yyyy-MM-dd"),
+      DateTimeUtils.formatDate(state.endDateTime, format: "yyyy-MM-dd"),
+      cancelToken: cancelToken,
+    );
+
+    if (result.isSuccess) {
+      state.entity = result.data;
+      state.datas = result.data?.rows ?? [];
+      if (state.datas.isNotEmpty) {
+        changeLoadingState(LoadState.State_Success);
+      } else {
+        changeLoadingState(LoadState.State_Empty);
+      }
+    } else {
+      errorMessage = result.errorMsg ?? "Network Load Error".tr;
+      changeLoadingState(LoadState.State_Error);
+    }
+  }
+
+  @override
+  void onReady() {
+    super.onReady();
+    fetchReportData();
+  }
+
+  /// 筛选开始日期
+  void pickerStartDate() {
+    DatePickerUtil.showCupertinoDatePicker(
+      selectedDateTime: state.startDateTime,
+      onDateTimeChanged: (date) {
+        state.startDateTime = date;
+        update();
+        fetchReportData();
+      },
+      title: "Start Date".tr,
+    );
+  }
+
+  /// 筛选结束日期
+  void pickerEndDate() {
+    DatePickerUtil.showCupertinoDatePicker(
+      selectedDateTime: state.endDateTime ?? state.startDateTime,
+      onDateTimeChanged: (date) {
+        state.endDateTime = date;
+        update();
+        fetchReportData();
+      },
+      title: "End Date".tr,
+    );
+  }
+}

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

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

+ 125 - 0
packages/cpt_uk/lib/modules/report/casual_payout_report/casual_payout_report_page.dart

@@ -0,0 +1,125 @@
+import 'package:cs_resources/constants/color_constants.dart';
+import 'package:flutter/material.dart';
+import 'package:get/get.dart';
+import 'package:shared/utils/date_time_utils.dart';
+import 'package:shared/utils/screen_util.dart';
+import 'package:widgets/ext/ex_widget.dart';
+import 'package:widgets/load_state_layout.dart';
+import 'package:widgets/my_appbar.dart';
+import 'package:widgets/my_text_view.dart';
+
+import 'casual_payout_report_controller.dart';
+
+import 'package:plugin_basic/base/base_stateless_page.dart';
+import 'package:plugin_basic/utils/ext_get_nav.dart';
+import 'package:router/path/router_path.dart';
+
+import 'casual_payout_report_item.dart';
+import 'casual_payout_report_state.dart';
+
+class UKCasualPayoutReportPage extends BaseStatelessPage<CasualPayoutReportController> {
+  UKCasualPayoutReportPage({Key? key}) : super(key: key);
+
+  //启动当前页面
+  static void startInstance() {
+    return Get.start(RouterPath.UKReportCasualPayout);
+  }
+
+  late CasualPayoutReportState state;
+
+  @override
+  void initState() {
+    state = controller.state;
+  }
+
+  @override
+  CasualPayoutReportController createRawController() {
+    return CasualPayoutReportController();
+  }
+
+  @override
+  Widget buildWidget(BuildContext context) {
+    return autoCtlGetBuilder(builder: (controller) {
+      return Scaffold(
+        extendBodyBehindAppBar: true,
+        appBar: MyAppBar.appBar(context, "YY Casual Labour Report".tr),
+        body: SafeArea(
+          bottom: true,
+          top: false,
+          child: Container(
+            width: double.infinity,
+            height: double.infinity,
+            padding: EdgeInsets.only(top: kToolbarHeight + ScreenUtil.getStatusBarH(context) + 1),
+            decoration: const BoxDecoration(
+              gradient: LinearGradient(
+                colors: [
+                  Color(0xFF091D44),
+                  Color(0xFF245A8A),
+                  Color(0xFF7F7CEC),
+                ],
+                begin: Alignment.topCenter,
+                end: Alignment.bottomCenter,
+              ),
+            ),
+            child: Column(
+              children: [
+                // 时间筛选
+                Container(
+                    width: double.infinity,
+                    height: 36,
+                    margin: const EdgeInsets.symmetric(vertical: 10, horizontal: 15),
+                    decoration: BoxDecoration(
+                      color: const Color(0xFF4DCFF6).withOpacity(0.2), // 设置背景颜色和不透明度
+                      borderRadius: BorderRadius.circular(20.0), // 设置圆角
+                    ),
+                    child: Row(
+                      children: [
+                        MyTextView(
+                          DateTimeUtils.formatDate(state.startDateTime, format: "yyyy-MM-dd"),
+                          hint: "Start Date".tr,
+                          textHintColor: ColorConstants.textGrayAECAE5,
+                          fontSize: 15,
+                          textAlign: TextAlign.center,
+                          isFontRegular: true,
+                          onClick: controller.pickerStartDate,
+                          textColor: ColorConstants.textGrayAECAE5,
+                        ).expanded(),
+                        Container(color: ColorConstants.dividerBar, height: 21.5, width: 0.5),
+                        MyTextView(
+                          DateTimeUtils.formatDate(state.endDateTime, format: "yyyy-MM-dd"),
+                          hint: "End Date".tr,
+                          textHintColor: ColorConstants.textGrayAECAE5,
+                          fontSize: 15,
+                          textAlign: TextAlign.center,
+                          isFontRegular: true,
+                          onClick: controller.pickerEndDate,
+                          textColor: ColorConstants.textGrayAECAE5,
+                        ).expanded(),
+                      ],
+                    )),
+
+                //动态列表
+                LoadStateLayout(
+                  state: controller.loadingState,
+                  errorMessage: controller.errorMessage,
+                  errorRetry: () {
+                    controller.retryRequest();
+                  },
+                  successSliverWidget: [
+
+                    SliverList(delegate: SliverChildBuilderDelegate((context, index) {
+                        return ReportLabourItem(entity: state.entity, type: index);
+                      },
+                      childCount: state.datas.isNotEmpty ? 3 : 0,
+                    ))
+
+                  ],
+                ).expanded(),
+              ],
+            ),
+          ),
+        ),
+      );
+    });
+  }
+}

+ 10 - 0
packages/cpt_uk/lib/modules/report/casual_payout_report/casual_payout_report_state.dart

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

+ 147 - 0
packages/cpt_uk/lib/modules/report/casual_report/casual_report_controller.dart

@@ -0,0 +1,147 @@
+import 'package:domain/entity/response/labour_request_index_entity.dart';
+import 'package:domain/entity/response/labour_review_list_entity.dart';
+import 'package:domain/repository/labour_repository.dart';
+import 'package:flutter/cupertino.dart';
+import 'package:get/get.dart';
+import 'package:plugin_platform/engine/dialog/dialog_engine.dart';
+import 'package:plugin_platform/engine/notify/notify_engine.dart';
+import 'package:plugin_platform/engine/toast/toast_engine.dart';
+import 'package:plugin_platform/http/dio/dio_cancelable_mixin.dart';
+import 'package:plugin_platform/http/http_result.dart';
+import 'package:shared/utils/date_time_utils.dart';
+import 'package:shared/utils/log_utils.dart';
+import 'package:shared/utils/util.dart';
+import 'package:widgets/dialog/app_default_dialog.dart';
+import 'package:widgets/load_state_layout.dart';
+import 'package:widgets/picker/date_picker_util.dart';
+import 'package:widgets/widget_export.dart';
+import 'casual_report_state.dart';
+
+class CasualReportController extends GetxController with DioCancelableMixin {
+  final LabourRepository _labourRepository = Get.find();
+  final CasualReportState state = CasualReportState();
+
+  var _curPage = 1;
+  var _needShowPlaceholder = true;
+
+  //页面PlaceHolder的展示
+  LoadState loadingState = LoadState.State_Success;
+  String? errorMessage;
+
+  //刷新页面状态
+  void changeLoadingState(LoadState state) {
+    loadingState = state;
+    update();
+  }
+
+  // Refresh 控制器
+  final EasyRefreshController refreshController = EasyRefreshController(
+    controlFinishRefresh: true,
+    controlFinishLoad: true,
+  );
+
+  // Refresh 刷新事件
+  Future onRefresh() async {
+    _curPage = 1;
+    fetchList();
+  }
+
+  // Refresh 加载事件
+  Future loadMore() async {
+    _curPage++;
+    fetchList();
+  }
+
+  // 重试请求
+  Future retryRequest() async {
+    _curPage = 1;
+    _needShowPlaceholder = true;
+    fetchList();
+  }
+
+  /// 获取服务器数据,通知消息列表
+  Future fetchList() async {
+    if (_needShowPlaceholder) {
+      changeLoadingState(LoadState.State_Loading);
+    }
+
+    //请求列表数据
+    var listResult = await _labourRepository.fetchLabourReviewList(
+      "",
+      DateTimeUtils.formatDate(state.selectedDate, format: "yyyy-MM-dd"),
+      DateTimeUtils.formatDate(state.selectedDate, format: "yyyy-MM-dd"),
+      "",
+      curPage: _curPage,
+      cancelToken: cancelToken,
+    );
+    
+    // 处理数据
+    if (listResult.isSuccess) {
+      handleList(listResult.data?.rows);
+    } else {
+      errorMessage = listResult.errorMsg;
+      changeLoadingState(LoadState.State_Error);
+    }
+
+    // 最后赋值
+    _needShowPlaceholder = false;
+  }
+
+  // 处理数据与展示的逻辑
+  void handleList(List<LabourReviewListRows>? list) {
+    if (list != null && list.isNotEmpty) {
+      //有数据,判断是刷新还是加载更多的数据
+      if (_curPage == 1) {
+        //刷新的方式
+        state.datas.clear();
+        state.datas.addAll(list);
+        refreshController.finishRefresh();
+
+        //更新展示的状态
+        changeLoadingState(LoadState.State_Success);
+      } else {
+        //加载更多
+        state.datas.addAll(list);
+        refreshController.finishLoad();
+        update();
+      }
+    } else {
+      if (_curPage == 1) {
+        //展示无数据的布局
+        state.datas.clear();
+        changeLoadingState(LoadState.State_Empty);
+        refreshController.finishRefresh();
+      } else {
+        //展示加载完成,没有更多数据了
+        refreshController.finishLoad(IndicatorResult.noMore);
+      }
+    }
+  }
+
+  @override
+  void onReady() {
+    super.onReady();
+    fetchList();
+  }
+
+  @override
+  void onClose() {
+    state.datas.clear();
+    super.onClose();
+  }
+
+  /// 年月的日期筛选
+  void showDatePicker() {
+
+    DatePickerUtil.showCupertinoDatePicker(
+      selectedDateTime: state.selectedDate ?? DateTime.now(),
+      mode: CupertinoDatePickerMode.monthYear,
+      onDateTimeChanged: (date) {
+        state.selectedDate = date;
+        update();
+      },
+      title: "Select Date".tr,
+    );
+  }
+
+}

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

@@ -0,0 +1,108 @@
+import 'package:cs_resources/constants/color_constants.dart';
+import 'package:cs_resources/generated/assets.dart';
+import 'package:domain/entity/response/labour_review_list_entity.dart';
+import 'package:flutter/cupertino.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter/widgets.dart';
+import 'package:plugin_basic/basic_export.dart';
+import 'package:widgets/ext/ex_widget.dart';
+import 'package:widgets/my_text_view.dart';
+
+/*
+ * 用工的列表
+ */
+class CasualReportItem extends StatelessWidget {
+  final int index;
+  final LabourReviewListRows item;
+
+  CasualReportItem({
+    required this.index,
+    required this.item,
+  });
+
+  @override
+  Widget build(BuildContext context) {
+    return Container(
+      padding: const EdgeInsets.symmetric(vertical: 23, horizontal: 21),
+      margin: const EdgeInsets.only(left: 15, right: 15, top: 5, bottom: 5),
+      decoration: BoxDecoration(
+        color: const Color(0xFF4DCFF6).withOpacity(0.2), // 设置背景颜色和不透明度
+        borderRadius: BorderRadius.circular(5), // 设置圆角
+      ),
+      child: Column(
+        mainAxisSize: MainAxisSize.max,
+        crossAxisAlignment: CrossAxisAlignment.start,
+        children: [
+          // 部门
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "Outlet:".tr,
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+
+              //部门
+              MyTextView(
+                item.departmentName ?? "-",
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor: Colors.white,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ),
+
+          // 小时
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "Hours(2):",
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+
+              //文本
+              MyTextView(
+                "2h",
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor: Colors.white,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ).marginOnly(top: 15),
+
+          // 总金额
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "TotalAmt(0):",
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+
+              //文本
+              MyTextView(
+                "£ 0",
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor: Colors.white,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ).marginOnly(top: 15),
+        ],
+      ),
+    );
+  }
+}

+ 129 - 0
packages/cpt_uk/lib/modules/report/casual_report/casual_report_page.dart

@@ -0,0 +1,129 @@
+import 'package:flutter/cupertino.dart';
+import 'package:flutter/material.dart';
+import 'package:get/get.dart';
+import 'package:shared/utils/date_time_utils.dart';
+import 'package:widgets/ext/ex_widget.dart';
+import 'package:widgets/load_state_layout.dart';
+import 'package:widgets/my_text_view.dart';
+import 'package:widgets/widget_export.dart';
+
+import 'casual_report_item.dart';
+import 'casual_report_controller.dart';
+
+import 'package:plugin_basic/base/base_state.dart';
+import 'package:plugin_basic/base/base_stateful_page.dart';
+import 'package:plugin_basic/utils/ext_get_nav.dart';
+import 'package:router/path/router_path.dart';
+import 'package:shared/utils/screen_util.dart';
+import 'package:widgets/my_appbar.dart';
+import 'casual_report_state.dart';
+
+/*
+ * 最后一个Casual的月度报表
+ */
+class UKCasualReportPage extends BaseStatefulPage<CasualReportController> {
+  UKCasualReportPage({Key? key}) : super(key: key);
+
+  //启动当前页面
+  static void startInstance() {
+    return Get.start(RouterPath.UKReportCasualMonthly);
+  }
+
+  @override
+  CasualReportController createRawController() {
+    return CasualReportController();
+  }
+
+  @override
+  State<UKCasualReportPage> createState() => _LabourReviewState();
+}
+
+class _LabourReviewState extends BaseState<UKCasualReportPage, CasualReportController> {
+  late CasualReportState state;
+
+  @override
+  void initState() {
+    super.initState();
+    state = controller.state;
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return autoCtlGetBuilder(builder: (controller) {
+      return SafeArea(
+        bottom: true,
+        top: false,
+        child: Container(
+          width: double.infinity,
+          height: double.infinity,
+          padding: EdgeInsets.only(top: ScreenUtil.getStatusBarH(context)),
+          decoration: const BoxDecoration(
+            gradient: LinearGradient(
+              colors: [
+                Color(0xFF091D44),
+                Color(0xFF245A8A),
+                Color(0xFF7F7CEC),
+              ],
+              begin: Alignment.topCenter,
+              end: Alignment.bottomCenter,
+            ),
+          ),
+          child: Column(
+            children: [
+              MyAppBar.titleBar(context, "Casual Report".tr),
+
+              //选择时间
+              Container(
+                width: double.infinity,
+                height: 42,
+                padding: const EdgeInsets.symmetric(horizontal: 14),
+                margin: const EdgeInsets.only(left: 15, right: 15, top: 10, bottom: 5),
+                decoration: BoxDecoration(
+                  color: const Color(0xFF4DCFF6).withOpacity(0.2), // 设置背景颜色和不透明度
+                  borderRadius: BorderRadius.circular(20), // 设置圆角
+                ),
+                child:Align(
+                  alignment: Alignment.centerLeft, // 左侧对齐
+                  child: MyTextView(
+                    DateTimeUtils.formatDate(state.selectedDate??DateTime.now(),format: "yyyy-MM"),
+                    textColor: Colors.white,
+                    fontSize: 15,
+                    isFontRegular: true,
+                  ),
+                ),
+              ).onTap((){
+                controller.showDatePicker();
+              }),
+
+              //底部的列表
+              EasyRefresh(
+                controller: controller.refreshController,
+                onRefresh: controller.onRefresh,
+                onLoad: controller.loadMore,
+                child: LoadStateLayout(
+                  state: controller.loadingState,
+                  errorMessage: controller.errorMessage,
+                  errorRetry: () {
+                    controller.retryRequest();
+                  },
+                  successSliverWidget: [
+                    SliverList(
+                        delegate: SliverChildBuilderDelegate(
+                      (context, index) {
+                        return CasualReportItem(
+                          index: index,
+                          item: state.datas[index],
+                        );
+                      },
+                      childCount: state.datas.length,
+                    ))
+                  ],
+                ),
+              ).expanded(),
+            ],
+          ),
+        ),
+      );
+    });
+  }
+}

+ 9 - 0
packages/cpt_uk/lib/modules/report/casual_report/casual_report_state.dart

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

+ 81 - 0
packages/cpt_uk/lib/modules/report/finance_report/report_finance_controller.dart

@@ -0,0 +1,81 @@
+import 'package:domain/repository/other_repository.dart';
+import 'package:get/get.dart';
+import 'package:plugin_platform/http/dio/dio_cancelable_mixin.dart';
+import 'package:shared/utils/date_time_utils.dart';
+import 'package:widgets/load_state_layout.dart';
+import 'package:widgets/picker/date_picker_util.dart';
+
+import 'report_finance_state.dart';
+
+class ReportFinanceController extends GetxController with DioCancelableMixin {
+  final OtherRepository _otherRepository = Get.find();
+  final ReportFinanceState state = ReportFinanceState();
+
+  //页面PlaceHolder的展示
+  LoadState loadingState = LoadState.State_Success;
+  String? errorMessage;
+
+  //刷新页面状态
+  void changeLoadingState(LoadState state) {
+    loadingState = state;
+    update();
+  }
+
+  //重试
+  void retryRequest() {
+    fetchReportData();
+  }
+
+  // 获取列表数据
+  void fetchReportData() async {
+    changeLoadingState(LoadState.State_Loading);
+
+    var result = await _otherRepository.fetchReportFiance(
+      DateTimeUtils.formatDate(state.startDateTime, format: "yyyy-MM-dd"),
+      DateTimeUtils.formatDate(state.endDateTime, format: "yyyy-MM-dd"),
+      cancelToken: cancelToken,
+    );
+
+    if (result.isSuccess) {
+      state.entity = result.data;
+      state.datas = result.data?.rateList ?? [];
+      changeLoadingState(LoadState.State_Success);
+    } else {
+      errorMessage = result.errorMsg ?? "Network Load Error".tr;
+      changeLoadingState(LoadState.State_Error);
+    }
+  }
+
+  @override
+  void onReady() {
+    super.onReady();
+    fetchReportData();
+  }
+
+  /// 筛选开始日期
+  void pickerStartDate() {
+    DatePickerUtil.showCupertinoDatePicker(
+      selectedDateTime: state.startDateTime,
+      onDateTimeChanged: (date) {
+        state.startDateTime = date;
+        update();
+        fetchReportData();
+      },
+      title: "Start Date".tr,
+    );
+  }
+
+  /// 筛选结束日期
+  void pickerEndDate() {
+    DatePickerUtil.showCupertinoDatePicker(
+      selectedDateTime: state.endDateTime??state.startDateTime,
+      onDateTimeChanged: (date) {
+        state.endDateTime = date;
+        update();
+        fetchReportData();
+      },
+      title: "End Date".tr,
+    );
+  }
+
+}

+ 111 - 0
packages/cpt_uk/lib/modules/report/finance_report/report_finance_item.dart

@@ -0,0 +1,111 @@
+import 'package:cs_resources/constants/color_constants.dart';
+import 'package:cs_resources/generated/assets.dart';
+import 'package:domain/entity/response/fiance_report_entity.dart';
+import 'package:flutter/cupertino.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter/widgets.dart';
+import 'package:plugin_basic/basic_export.dart';
+import 'package:widgets/ext/ex_widget.dart';
+import 'package:widgets/my_load_image.dart';
+import 'package:widgets/my_text_view.dart';
+
+class ReportFinanceItem extends StatelessWidget {
+  final FianceReportRateList item;
+
+  ReportFinanceItem({
+    required this.item,
+  });
+
+  @override
+  Widget build(BuildContext context) {
+    return Container(
+      decoration: BoxDecoration(
+        color: const Color(0xFF4DCFF6).withOpacity(0.2), // 设置背景颜色和不透明度
+        borderRadius: BorderRadius.circular(7.5), // 设置圆角
+      ),
+      child: Column(
+        crossAxisAlignment: CrossAxisAlignment.start,
+        children: [
+          //星期与日期
+          Row(
+            children: [
+              MyAssetImage(
+                  item.weekNum == "1"
+                      ? Assets.cptReportWeekNum1
+                      : item.weekNum == "2"
+                          ? Assets.cptReportWeekNum2
+                          : item.weekNum == "3"
+                              ? Assets.cptReportWeekNum3
+                              : item.weekNum == "4"
+                                  ? Assets.cptReportWeekNum4
+                                  : item.weekNum == "5"
+                                      ? Assets.cptReportWeekNum5
+                                      : item.weekNum == "6"
+                                          ? Assets.cptReportWeekNum6
+                                          : Assets.cptReportWeekNum7,
+                  width: 29,
+                  height: 29),
+              MyTextView(item.day ?? "", textColor: Colors.white, fontSize: 13.3, isFontBold: true, marginLeft: 13.5),
+            ],
+          ).marginOnly(left: 15, top: 16, bottom: 14),
+
+          Row(
+            children: [
+              Column(
+                children: [
+                  MyTextView(
+                    "RQST",
+                    textColor: ColorConstants.textGrayAECAE5,
+                    fontSize: 11.7,
+                    isFontRegular: true,
+                  ),
+                  MyTextView(
+                    item.request.toString(),
+                    textColor: ColorConstants.textYellowF8AE00,
+                    fontSize: 11,
+                    isFontRegular: true,
+                  ),
+                ],
+              ),
+
+              Column(
+                children: [
+                  MyTextView(
+                    "Actual",
+                    textColor: ColorConstants.textGrayAECAE5,
+                    fontSize: 11.7,
+                    isFontRegular: true,
+                  ),
+
+                  MyTextView(
+                    item.actual.toString(),
+                    textColor: ColorConstants.textGreen00FB92,
+                    fontSize: 13,
+                    isFontBold: true,
+                  ),
+                ],
+              ).marginOnly(left: 5,right: 5),
+
+              Column(
+                children: [
+                  MyTextView(
+                    "Percentage",
+                    textColor: ColorConstants.textGrayAECAE5,
+                    fontSize: 11.7,
+                    isFontRegular: true,
+                  ),
+                  MyTextView(
+                    item.ratio ?? "-",
+                    textColor: ColorConstants.textPurpleFF35EE,
+                    fontSize: 13,
+                    isFontBold: true,
+                  ),
+                ],
+              ).expanded(),
+            ],
+          ).paddingOnly(left: 10,right: 10).expanded(),
+        ],
+      ),
+    );
+  }
+}

+ 190 - 0
packages/cpt_uk/lib/modules/report/finance_report/report_finance_page.dart

@@ -0,0 +1,190 @@
+import 'package:cs_resources/constants/color_constants.dart';
+import 'package:cs_resources/generated/assets.dart';
+import 'package:flutter/material.dart';
+import 'package:get/get.dart';
+import 'package:shared/utils/date_time_utils.dart';
+import 'package:shared/utils/screen_util.dart';
+import 'package:widgets/ext/ex_widget.dart';
+import 'package:widgets/load_state_layout.dart';
+import 'package:widgets/my_appbar.dart';
+import 'package:widgets/my_text_view.dart';
+
+import 'report_finance_controller.dart';
+
+import 'package:plugin_basic/base/base_stateless_page.dart';
+import 'package:plugin_basic/utils/ext_get_nav.dart';
+import 'package:router/path/router_path.dart';
+
+import 'report_finance_item.dart';
+import 'report_finance_state.dart';
+
+/*
+ * 财务报表还是终极报表
+ */
+class UKReportFinancePage extends BaseStatelessPage<ReportFinanceController> {
+  UKReportFinancePage({Key? key}) : super(key: key);
+
+  //启动当前页面
+  static void startInstance() {
+    return Get.start(RouterPath.UKReportfinance);
+  }
+
+  late ReportFinanceState state;
+
+  @override
+  void initState() {
+    state = controller.state;
+  }
+
+  @override
+  ReportFinanceController createRawController() {
+    return ReportFinanceController();
+  }
+
+  @override
+  Widget buildWidget(BuildContext context) {
+    return autoCtlGetBuilder(builder: (controller) {
+      return Scaffold(
+        extendBodyBehindAppBar: true,
+        appBar: MyAppBar.appBar(context, "Finance Report".tr),
+        body: SafeArea(
+          bottom: true,
+          top: false,
+          child: Container(
+            width: double.infinity,
+            height: double.infinity,
+            padding: EdgeInsets.only(top: kToolbarHeight + ScreenUtil.getStatusBarH(context) + 1),
+            decoration: const BoxDecoration(
+              gradient: LinearGradient(
+                colors: [
+                  Color(0xFF091D44),
+                  Color(0xFF245A8A),
+                  Color(0xFF7F7CEC),
+                ],
+                begin: Alignment.topCenter,
+                end: Alignment.bottomCenter,
+              ),
+            ),
+            child: Column(
+              children: [
+                // 时间筛选
+                Container(
+                    width: double.infinity,
+                    height: 36,
+                    margin: const EdgeInsets.symmetric(vertical: 10, horizontal: 15),
+                    decoration: BoxDecoration(
+                      color: const Color(0xFF4DCFF6).withOpacity(0.2), // 设置背景颜色和不透明度
+                      borderRadius: BorderRadius.circular(20.0), // 设置圆角
+                    ),
+                    child: Row(
+                      children: [
+                        MyTextView(
+                          DateTimeUtils.formatDate(state.startDateTime, format: "yyyy-MM-dd"),
+                          hint: "Start Date".tr,
+                          textHintColor: ColorConstants.textGrayAECAE5,
+                          fontSize: 15,
+                          textAlign: TextAlign.center,
+                          isFontRegular: true,
+                          onClick: controller.pickerStartDate,
+                          textColor: ColorConstants.textGrayAECAE5,
+                        ).expanded(),
+                        Container(color: ColorConstants.dividerBar, height: 21.5, width: 0.5),
+                        MyTextView(
+                          DateTimeUtils.formatDate(state.endDateTime, format: "yyyy-MM-dd"),
+                          hint: "End Date".tr,
+                          textHintColor: ColorConstants.textGrayAECAE5,
+                          fontSize: 15,
+                          textAlign: TextAlign.center,
+                          isFontRegular: true,
+                          onClick: controller.pickerEndDate,
+                          textColor: ColorConstants.textGrayAECAE5,
+                        ).expanded(),
+                      ],
+                    )),
+
+                //总数据
+                Container(
+                    margin: const EdgeInsets.only(left: 15, right: 15),
+                    width: double.infinity,
+                    height: 45,
+                    decoration: BoxDecoration(
+                      color: const Color(0xFF4DCFF6).withOpacity(0.2), // 设置背景颜色和不透明度
+                      borderRadius: BorderRadius.circular(5), // 设置圆角
+                    ),
+                    child: Row(
+                      children: [
+                        Row(
+                          mainAxisAlignment: MainAxisAlignment.center,
+                          crossAxisAlignment: CrossAxisAlignment.center,
+                          children: [
+                            MyTextView(
+                              "Total RQST:",
+                              fontSize: 14,
+                              isFontRegular: true,
+                              onClick: controller.pickerStartDate,
+                              textColor: ColorConstants.textGrayAECAE5,
+                            ),
+                            MyTextView(
+                              state.entity?.requestTotal.toString() ?? "",
+                              fontSize: 14,
+                              marginLeft: 5,
+                              isFontRegular: true,
+                              textColor: ColorConstants.white,
+                            ),
+                          ],
+                        ).expanded(),
+                        Row(
+                          mainAxisAlignment: MainAxisAlignment.center,
+                          crossAxisAlignment: CrossAxisAlignment.center,
+                          children: [
+                            MyTextView(
+                              "Total Actual:",
+                              fontSize: 14,
+                              isFontRegular: true,
+                              onClick: controller.pickerStartDate,
+                              textColor: ColorConstants.textGrayAECAE5,
+                            ),
+                            MyTextView(
+                              state.entity?.actualTotal.toString() ?? "",
+                              fontSize: 14,
+                              marginLeft: 5,
+                              isFontRegular: true,
+                              textColor: ColorConstants.white,
+                            ),
+                          ],
+                        ).expanded(),
+                      ],
+                    )),
+
+                //动态列表
+                LoadStateLayout(
+                  state: controller.loadingState,
+                  errorMessage: controller.errorMessage,
+                  errorRetry: () {
+                    controller.retryRequest();
+                  },
+                  successSliverWidget: [
+                    SliverGrid(
+                      delegate: SliverChildBuilderDelegate(
+                        (context, index) {
+                          return ReportFinanceItem(item: state.datas[index]);
+                        },
+                        childCount: state.datas.length,
+                      ),
+                      gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
+                        crossAxisCount: 2, // 每行2个项目
+                        mainAxisSpacing: 8.5, // 主轴方向的间距
+                        crossAxisSpacing: 9.5, // 交叉轴方向的间距
+                        childAspectRatio: 168.16 / 107.22, // 子项目的宽高比
+                      ),
+                    )
+                  ],
+                ).marginOnly(left: 15, right: 15, top: 10).expanded(),
+              ],
+            ),
+          ),
+        ),
+      );
+    });
+  }
+}

+ 11 - 0
packages/cpt_uk/lib/modules/report/finance_report/report_finance_state.dart

@@ -0,0 +1,11 @@
+import 'package:domain/entity/response/fiance_report_entity.dart';
+
+class ReportFinanceState {
+
+  DateTime? startDateTime;
+  DateTime? endDateTime;
+
+  FianceReportEntity? entity;  //页面数据
+
+  List<FianceReportRateList> datas = [];  //列表数据
+}

+ 2 - 2
packages/cpt_uk/lib/modules/report/labour_report/labour_report_item.dart

@@ -156,7 +156,7 @@ class LabourReportItem extends StatelessWidget {
             crossAxisAlignment: CrossAxisAlignment.center,
             children: [
               MyTextView(
-                "${"Manpower Needed:".tr}:",
+                "${"Manpower Needed".tr}:",
                 isFontRegular: true,
                 textColor: ColorConstants.textGrayAECAE5,
                 fontSize: 14,
@@ -179,7 +179,7 @@ class LabourReportItem extends StatelessWidget {
             crossAxisAlignment: CrossAxisAlignment.center,
             children: [
               MyTextView(
-                "${"Actual Num:".tr}:",
+                "${"Actual Num".tr}:",
                 isFontRegular: true,
                 textColor: ColorConstants.textGrayAECAE5,
                 fontSize: 14,

+ 1 - 1
packages/cpt_uk/lib/modules/report/labour_report/labour_report_page.dart

@@ -75,7 +75,7 @@ class _LabourReviewState extends BaseState<UKLabourReportPage, LabourReportContr
             children: [
               MyAppBar.titleBar(
                 context,
-                "Labour Request",
+                "Labour Request".tr,
                 actions: [
                   //筛选图标
                   const MyAssetImage(

+ 0 - 1
packages/cpt_uk/lib/modules/report/labour_report/widget/labour_report_filter.dart

@@ -361,5 +361,4 @@ class _LabourReviewFilterState extends State<LabourReportFilter> {
     );
   }
 
-
 }

+ 105 - 0
packages/cpt_uk/lib/modules/report/outlet_staff_report/outlet_staff_report_controller.dart

@@ -0,0 +1,105 @@
+import 'package:domain/entity/response/staff_request_report_entity.dart';
+import 'package:domain/repository/other_repository.dart';
+import 'package:get/get.dart';
+import 'package:plugin_basic/service/app_config_service.dart';
+import 'package:plugin_platform/http/dio/dio_cancelable_mixin.dart';
+import 'package:shared/utils/date_time_utils.dart';
+import 'package:shared/utils/log_utils.dart';
+import 'package:widgets/load_state_layout.dart';
+import 'package:widgets/picker/date_picker_util.dart';
+
+import 'outlet_staff_report_state.dart';
+
+class OutletStaffReportController extends GetxController with DioCancelableMixin {
+  final OtherRepository _otherRepository = Get.find();
+  final OutletStaffReportState state = OutletStaffReportState();
+
+  //页面PlaceHolder的展示
+  LoadState loadingState = LoadState.State_Loading;
+  String? errorMessage;
+
+  //刷新页面状态
+  void changeLoadingState(LoadState state) {
+    loadingState = state;
+    update();
+  }
+
+  //重试
+  void retryRequest() {
+    fetchReportData();
+  }
+
+  // 获取当前列表数据
+  void fetchReportData() async {
+    changeLoadingState(LoadState.State_Loading);
+
+    //根据不同的国家,调用不同的接口
+    if (ConfigService.to.selectCountry.value == 1) {
+      //如果是新加坡版本的
+      var result = await _otherRepository.fetchReportStaffRequest(
+        DateTimeUtils.formatDate(state.startDateTime, format: "yyyy-MM-dd"),
+        DateTimeUtils.formatDate(state.endDateTime, format: "yyyy-MM-dd"),
+        cancelToken: cancelToken,
+      );
+      if (result.isSuccess) {
+        state.datas = result.list
+                ?.whereType<StaffRequestReportEntity>() // 直接过滤出非 null 的 StaffRequestReportEntity
+                .toList() ??
+            [];
+        changeLoadingState(LoadState.State_Success);
+      } else {
+        errorMessage = result.errorMsg ?? "Network Load Error".tr;
+        changeLoadingState(LoadState.State_Error);
+      }
+    } else {
+      //如果是越南的版本
+      var result = await _otherRepository.fetchStaffReportVN(
+        DateTimeUtils.formatDate(state.startDateTime, format: "yyyy-MM-dd"),
+        DateTimeUtils.formatDate(state.endDateTime, format: "yyyy-MM-dd"),
+        cancelToken: cancelToken,
+      );
+      if (result.isSuccess) {
+        state.datas = result.data?.requestList
+                .whereType<StaffRequestReportEntity>() // 直接过滤出非 null 的 StaffRequestReportEntity
+                .toList() ??
+            [];
+        changeLoadingState(LoadState.State_Success);
+      } else {
+        errorMessage = result.errorMsg ?? "Network Load Error".tr;
+        changeLoadingState(LoadState.State_Error);
+      }
+    }
+  }
+
+  @override
+  void onReady() {
+    super.onReady();
+    fetchReportData();
+  }
+
+  /// 筛选开始日期
+  void pickerStartDate() {
+    DatePickerUtil.showCupertinoDatePicker(
+      selectedDateTime: state.startDateTime,
+      onDateTimeChanged: (date) {
+        state.startDateTime = date;
+        update();
+        fetchReportData();
+      },
+      title: "Start Date".tr,
+    );
+  }
+
+  /// 筛选结束日期
+  void pickerEndDate() {
+    DatePickerUtil.showCupertinoDatePicker(
+      selectedDateTime: state.endDateTime ?? state.startDateTime,
+      onDateTimeChanged: (date) {
+        state.endDateTime = date;
+        update();
+        fetchReportData();
+      },
+      title: "End Date".tr,
+    );
+  }
+}

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

@@ -0,0 +1,76 @@
+import 'package:cs_resources/constants/color_constants.dart';
+import 'package:domain/entity/response/staff_request_report_entity.dart';
+import 'package:flutter/cupertino.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter/widgets.dart';
+import 'package:plugin_basic/basic_export.dart';
+import 'package:shared/utils/util.dart';
+
+import 'package:widgets/my_text_view.dart';
+import 'package:widgets/shatter/custom_progress_bar.dart';
+
+class OutletStaffReportItem extends StatelessWidget {
+  final StaffRequestReportEntity item;
+
+  OutletStaffReportItem({
+    required this.item,
+  });
+
+  @override
+  Widget build(BuildContext context) {
+    return Column(
+      crossAxisAlignment: CrossAxisAlignment.start,
+      children: [
+        Row(
+          children: [
+            MyTextView(
+              item.name ?? "",
+              fontSize: 14,
+              textColor: Colors.white,
+              isFontRegular: true,
+            ),
+            MyTextView(
+              "(${item.num})",
+              marginLeft: 3,
+              textColor: ColorConstants.textYellowF8AE00,
+              fontSize: 14,
+              isFontRegular: true,
+            ),
+          ],
+        ),
+        CustomProgressBar(
+          progress: _convertProgress(item.ratio),
+          color: item.bg == "rec-primary"
+              ? hexToColor("#228FFE")
+              : item.bg == "rec-success"
+                  ? hexToColor("#01A5A7")
+                  : item.bg == "rec-warning"
+                      ? hexToColor("#E0A721")
+                      : item.bg == "rec-orange"
+                          ? hexToColor("#DD592C")
+                          : item.bg == "rec-danger"
+                              ? hexToColor("#FE3737")
+                              : hexToColor("#943EFF"),
+        ).marginOnly(top: 6),
+      ],
+    ).paddingOnly(left: 22.5, right: 22.5, top: 8, bottom: 8);
+  }
+
+  // 进度的转换
+  double _convertProgress(String? percentageString) {
+    try {
+      if (Utils.isEmpty(percentageString)) {
+        return 0.0;
+      }
+
+      // 去掉百分号
+      String cleanedString = percentageString!.replaceAll('%', '');
+
+      // 将字符串转换为 double
+      return double.parse(cleanedString) / 100;
+    } catch (e) {
+      print('转换失败: $e');
+      return 0.0;
+    }
+  }
+}

+ 144 - 0
packages/cpt_uk/lib/modules/report/outlet_staff_report/outlet_staff_report_page.dart

@@ -0,0 +1,144 @@
+import 'package:cs_resources/constants/color_constants.dart';
+import 'package:flutter/material.dart';
+import 'package:get/get.dart';
+import 'package:shared/utils/date_time_utils.dart';
+import 'package:shared/utils/screen_util.dart';
+import 'package:widgets/ext/ex_widget.dart';
+import 'package:widgets/load_state_layout.dart';
+import 'package:widgets/my_appbar.dart';
+import 'package:widgets/my_text_view.dart';
+
+import 'outlet_staff_report_controller.dart';
+
+import 'package:plugin_basic/base/base_stateless_page.dart';
+import 'package:plugin_basic/utils/ext_get_nav.dart';
+import 'package:router/path/router_path.dart';
+
+import 'outlet_staff_report_item.dart';
+import 'outlet_staff_report_state.dart';
+
+/*
+ * 部门的员工的月度统计
+ */
+class UKOutletStaffReportPage extends BaseStatelessPage<OutletStaffReportController> {
+  UKOutletStaffReportPage({Key? key}) : super(key: key);
+
+  //启动当前页面
+  static void startInstance() {
+    return Get.start(RouterPath.UKReportOutlet);
+  }
+
+  late OutletStaffReportState state;
+
+  @override
+  void initState() {
+    state = controller.state;
+  }
+
+  @override
+  OutletStaffReportController createRawController() {
+    return OutletStaffReportController();
+  }
+
+  @override
+  Widget buildWidget(BuildContext context) {
+    return autoCtlGetBuilder(builder: (controller) {
+      return Scaffold(
+        extendBodyBehindAppBar: true,
+        appBar: MyAppBar.appBar(context, "Monthly Staff Request Report".tr),
+        body: SafeArea(
+          bottom: true,
+          top: false,
+          child: Container(
+            width: double.infinity,
+            height: double.infinity,
+            padding: EdgeInsets.only(top: kToolbarHeight + ScreenUtil.getStatusBarH(context) + 1),
+            decoration: const BoxDecoration(
+              gradient: LinearGradient(
+                colors: [
+                  Color(0xFF091D44),
+                  Color(0xFF245A8A),
+                  Color(0xFF7F7CEC),
+                ],
+                begin: Alignment.topCenter,
+                end: Alignment.bottomCenter,
+              ),
+            ),
+            child: Column(
+              children: [
+                // 时间筛选
+                Container(
+                    width: double.infinity,
+                    height: 36,
+                    margin: const EdgeInsets.symmetric(vertical: 10, horizontal: 15),
+                    decoration: BoxDecoration(
+                      color: const Color(0xFF4DCFF6).withOpacity(0.2), // 设置背景颜色和不透明度
+                      borderRadius: BorderRadius.circular(20.0), // 设置圆角
+                    ),
+                    child: Row(
+                      children: [
+                        MyTextView(
+                          DateTimeUtils.formatDate(state.startDateTime, format: "yyyy-MM-dd"),
+                          hint: "Start Date".tr,
+                          textHintColor: ColorConstants.textGrayAECAE5,
+                          fontSize: 15,
+                          textAlign: TextAlign.center,
+                          isFontRegular: true,
+                          onClick: controller.pickerStartDate,
+                          textColor: ColorConstants.textGrayAECAE5,
+                        ).expanded(),
+                        Container(color: ColorConstants.dividerBar, height: 21.5, width: 0.5),
+                        MyTextView(
+                          DateTimeUtils.formatDate(state.endDateTime, format: "yyyy-MM-dd"),
+                          hint: "End Date".tr,
+                          textHintColor: ColorConstants.textGrayAECAE5,
+                          fontSize: 15,
+                          textAlign: TextAlign.center,
+                          isFontRegular: true,
+                          onClick: controller.pickerEndDate,
+                          textColor: ColorConstants.textGrayAECAE5,
+                        ).expanded(),
+                      ],
+                    )),
+
+                //动态列表
+                LoadStateLayout(
+                  state: controller.loadingState,
+                  errorMessage: controller.errorMessage,
+                  errorRetry: () {
+                    controller.retryRequest();
+                  },
+                  successSliverWidget: [
+                    SliverPadding(
+                      padding: const EdgeInsets.only(left: 15, right: 15, bottom: 15),
+                      sliver: DecoratedSliver(
+                        decoration: BoxDecoration(
+                          color: const Color(0xFF4DCFF6).withOpacity(0.2), // 设置背景颜色和不透明度
+                          borderRadius: BorderRadius.circular(5), // 设置圆角
+                        ),
+                        sliver: SliverList(
+                          delegate: SliverChildBuilderDelegate(
+                            (context, index) {
+                              if (index == 0) {
+                                return const SizedBox(height: 16); // 添加顶部间距
+                              } else if (index == state.datas.length + 1) {
+                                return const SizedBox(height: 20); // 添加底部间距
+                              } else {
+                                return OutletStaffReportItem(item: state.datas[index - 1]); // 注意这里的 index - 1
+                              }
+                            },
+                            childCount: state.datas.length + 2,
+                          ),
+                        ),
+                      ),
+                    ),
+                  ],
+                ).expanded(),
+              ],
+            ),
+          ),
+        ),
+      );
+    });
+  }
+}

+ 9 - 0
packages/cpt_uk/lib/modules/report/outlet_staff_report/outlet_staff_report_state.dart

@@ -0,0 +1,9 @@
+import 'package:domain/entity/response/staff_request_report_entity.dart';
+
+class OutletStaffReportState {
+
+  DateTime? startDateTime;
+  DateTime? endDateTime;
+
+  List<StaffRequestReportEntity> datas = [];  //列表数据
+}

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

@@ -1,12 +1,19 @@
+import 'package:cpt_uk/modules/report/attendance_report/attendance_report_page.dart';
 import 'package:cpt_uk/modules/report/labour_report/labour_report_page.dart';
+import 'package:cpt_uk/modules/report/outlet_staff_report/outlet_staff_report_page.dart';
+import 'package:cpt_uk/modules/report/working_hours_report/working_hours_report_page.dart';
 import 'package:domain/entity/home_module.dart';
 import 'package:domain/entity/response/hotel_info_entity.dart';
 import 'package:get/get.dart';
 import 'package:plugin_basic/service/app_config_service.dart';
 import 'package:plugin_basic/service/user_service.dart';
 import 'package:plugin_platform/engine/toast/toast_engine.dart';
+import 'package:router/componentRouter/component_router_service.dart';
 import 'package:shared/utils/log_utils.dart';
 
+import '../casual_payout_report/casual_payout_report_page.dart';
+import '../casual_report/casual_report_page.dart';
+import '../finance_report/report_finance_page.dart';
 import 'report_list_state.dart';
 
 class ReportListController extends GetxController {
@@ -58,22 +65,22 @@ class ReportListController extends GetxController {
         UKLabourReportPage.startInstance();
         break;
       case 'outlet':
-        ToastEngine.show("outlet");
+        UKOutletStaffReportPage.startInstance();
         break;
       case 'finale':
-        ToastEngine.show("finale");
+        UKReportFinancePage.startInstance();
         break;
       case 'hours':
-        ToastEngine.show("hours");
+        UKWorkingHoursReportPage.startInstance();
         break;
       case 'attendance':
-        ToastEngine.show("attendance");
+        UKAttendanceReportPage.startInstance();
         break;
       case 'payout':
-        ToastEngine.show("payout");
+        UKCasualPayoutReportPage.startInstance();
         break;
       case 'casual':
-        ToastEngine.show("casual");
+        UKCasualReportPage.startInstance();
         break;
     }
   }

+ 318 - 0
packages/cpt_uk/lib/modules/report/working_hours_report/widget/working_hours_filter.dart

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

+ 172 - 0
packages/cpt_uk/lib/modules/report/working_hours_report/working_hours_report_controller.dart

@@ -0,0 +1,172 @@
+import 'package:cpt_uk/modules/report/working_hours_report/widget/working_hours_filter.dart';
+import 'package:domain/entity/response/labour_request_index_entity.dart';
+import 'package:domain/entity/response/labour_review_list_entity.dart';
+import 'package:domain/repository/labour_repository.dart';
+import 'package:get/get.dart';
+import 'package:plugin_platform/engine/dialog/dialog_engine.dart';
+import 'package:plugin_platform/engine/notify/notify_engine.dart';
+import 'package:plugin_platform/engine/toast/toast_engine.dart';
+import 'package:plugin_platform/http/dio/dio_cancelable_mixin.dart';
+import 'package:plugin_platform/http/http_result.dart';
+import 'package:shared/utils/date_time_utils.dart';
+import 'package:shared/utils/log_utils.dart';
+import 'package:widgets/load_state_layout.dart';
+import 'package:widgets/widget_export.dart';
+import 'working_hours_report_state.dart';
+
+class WorkingHoursReportController extends GetxController with DioCancelableMixin {
+  final LabourRepository _labourRepository = Get.find();
+  final WorkingHoursReportState state = WorkingHoursReportState();
+
+  var _curPage = 1;
+  var _needShowPlaceholder = true;
+
+  //页面PlaceHolder的展示
+  LoadState loadingState = LoadState.State_Success;
+  String? errorMessage;
+
+  //刷新页面状态
+  void changeLoadingState(LoadState state) {
+    loadingState = state;
+    update();
+  }
+
+  // Refresh 控制器
+  final EasyRefreshController refreshController = EasyRefreshController(
+    controlFinishRefresh: true,
+    controlFinishLoad: true,
+  );
+
+  // Refresh 刷新事件
+  Future onRefresh() async {
+    _curPage = 1;
+    fetchAppliedStaffList();
+  }
+
+  // Refresh 加载事件
+  Future loadMore() async {
+    _curPage++;
+    fetchAppliedStaffList();
+  }
+
+  // 重试请求
+  Future retryRequest() async {
+    _curPage = 1;
+    _needShowPlaceholder = true;
+    fetchAppliedStaffList();
+  }
+
+  /// 获取服务器数据,通知消息列表
+  Future fetchAppliedStaffList() async {
+    if (_needShowPlaceholder) {
+      changeLoadingState(LoadState.State_Loading);
+    }
+
+    // 并发执行两个请求,拿到选项数据与列表数据
+    var futures = [
+      _labourRepository.fetchLabourReviewList(
+        "",
+        DateTimeUtils.formatDate(state.selectedStartDate, format: "yyyy-MM-dd"),
+        DateTimeUtils.formatDate(state.selectedEndDate, format: "yyyy-MM-dd"),
+        state.selectedDepartmentId,
+        curPage: _curPage,
+        cancelToken: cancelToken,
+      ),
+      state.indexOptions == null
+          ? _labourRepository.fetchLabourReviewIndex(
+              cancelToken: cancelToken,
+            )
+          : Future(() => HttpResult(isSuccess: true).convert(data: state.indexOptions!)),
+    ];
+
+    //拿到结果
+    var results = await Future.wait(futures);
+    var listResult = results[0] as HttpResult<LabourReviewListEntity>;
+    var optionResult = results[1] as HttpResult<LabourRequestIndexEntity>;
+
+    //选项数据
+    if (state.indexOptions == null && optionResult.isSuccess) {
+      state.indexOptions = optionResult.data!;
+    }
+
+    // 处理数据
+    if (listResult.isSuccess) {
+      handleList(listResult.data?.rows);
+    } else {
+      errorMessage = listResult.errorMsg;
+      changeLoadingState(LoadState.State_Error);
+    }
+
+    // 最后赋值
+    _needShowPlaceholder = false;
+  }
+
+  // 处理数据与展示的逻辑
+  void handleList(List<LabourReviewListRows>? list) {
+    if (list != null && list.isNotEmpty) {
+      //有数据,判断是刷新还是加载更多的数据
+      if (_curPage == 1) {
+        //刷新的方式
+        state.datas.clear();
+        state.datas.addAll(list);
+        refreshController.finishRefresh();
+
+        //更新展示的状态
+        changeLoadingState(LoadState.State_Success);
+      } else {
+        //加载更多
+        state.datas.addAll(list);
+        refreshController.finishLoad();
+        update();
+      }
+    } else {
+      if (_curPage == 1) {
+        //展示无数据的布局
+        state.datas.clear();
+        changeLoadingState(LoadState.State_Empty);
+        refreshController.finishRefresh();
+      } else {
+        //展示加载完成,没有更多数据了
+        refreshController.finishLoad(IndicatorResult.noMore);
+      }
+    }
+  }
+
+  @override
+  void onReady() {
+    super.onReady();
+    fetchAppliedStaffList();
+  }
+
+  @override
+  void onClose() {
+    state.datas.clear();
+    super.onClose();
+  }
+
+  /// 展示顶部的筛选
+  void showFilterDialog() {
+    if (state.indexOptions != null) {
+      DialogEngine.show(
+        widget: WorkingHoursFilter(
+          optionResult: state.indexOptions!,
+          selectedStartDate: state.selectedStartDate,
+          selectedEndDate: state.selectedEndDate,
+          selectedDepartmentId: state.selectedDepartmentId,
+          onFilterAction: (startDate, endDate, departmentId) {
+            state.selectedStartDate = startDate;
+            state.selectedEndDate = endDate;
+            state.selectedDepartmentId = departmentId;
+
+            Log.d("筛选的值为:startDate:$startDate endDate:$endDate departmentId:$departmentId");
+
+            //赋值之后刷新
+            refreshController.callRefresh();
+          },
+        ),
+        position: DialogPosition.top,
+        animType: DialogAnimation.fade,
+      );
+    }
+  }
+}

+ 200 - 0
packages/cpt_uk/lib/modules/report/working_hours_report/working_hours_report_item.dart

@@ -0,0 +1,200 @@
+import 'package:cs_resources/constants/color_constants.dart';
+import 'package:domain/entity/response/labour_review_list_entity.dart';
+import 'package:flutter/cupertino.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter/widgets.dart';
+import 'package:plugin_basic/basic_export.dart';
+import 'package:widgets/ext/ex_widget.dart';
+
+import 'package:widgets/my_text_view.dart';
+
+/*
+ * 列表Item
+ */
+class WorkingHoursReportItem extends StatelessWidget {
+  final int index;
+  final LabourReviewListRows item;
+
+  WorkingHoursReportItem({
+    required this.index,
+    required this.item,
+  });
+
+  @override
+  Widget build(BuildContext context) {
+    return Container(
+      padding: const EdgeInsets.symmetric(vertical: 23, horizontal: 21),
+      margin: const EdgeInsets.only(left: 15, right: 15, top: 5, bottom: 5),
+      decoration: BoxDecoration(
+        color: const Color(0xFF4DCFF6).withOpacity(0.2), // 设置背景颜色和不透明度
+        borderRadius: BorderRadius.circular(5), // 设置圆角
+      ),
+      child: Column(
+        mainAxisSize: MainAxisSize.max,
+        crossAxisAlignment: CrossAxisAlignment.start,
+        children: [
+          // 工作日期
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "${"Job Date".tr}:",
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+
+              //部门
+              MyTextView(
+                item.jobTime ?? "-",
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor: Colors.white,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ),
+
+          // 部门
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "Outlet:".tr,
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+
+              //部门
+              MyTextView(
+                item.departmentName ?? "-",
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor: Colors.white,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ).marginOnly(top: 15),
+
+          // 标题
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "${"Title".tr}:",
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+
+              //部门
+              MyTextView(
+                item.jobTitle ?? "-",
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor: Colors.white,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ).marginOnly(top: 15),
+
+          // 开始时间
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "Start Time:".tr,
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+
+              //日期时间
+              MyTextView(
+                item.jobTime ?? "-",
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor: Colors.white,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ).marginOnly(top: 15),
+
+          // 结束时间
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "End Time:".tr,
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+
+              //日期时间
+              MyTextView(
+                item.jobTime ?? "-",
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor: Colors.white,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ).marginOnly(top: 15),
+
+          // 以做工完成的人数
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "${"Completed Num".tr}:",
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+
+              //发布状态
+              MyTextView(
+                item.needNum ?? "-",
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor: Colors.white,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ).marginOnly(top: 15),
+
+          // 工作时长
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "${"Working Hours".tr}:",
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+
+              //发布状态
+              MyTextView(
+                "8",
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor: Colors.white,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ).marginOnly(top: 15),
+        ],
+      ),
+    );
+  }
+}

+ 124 - 0
packages/cpt_uk/lib/modules/report/working_hours_report/working_hours_report_page.dart

@@ -0,0 +1,124 @@
+import 'package:cs_resources/constants/color_constants.dart';
+import 'package:cs_resources/generated/assets.dart';
+import 'package:flutter/cupertino.dart';
+import 'package:flutter/material.dart';
+import 'package:get/get.dart';
+import 'package:widgets/ext/ex_widget.dart';
+import 'package:widgets/load_state_layout.dart';
+import 'package:widgets/my_button.dart';
+import 'package:widgets/my_load_image.dart';
+import 'package:widgets/my_text_view.dart';
+import 'package:widgets/widget_export.dart';
+
+import 'working_hours_report_item.dart';
+import 'working_hours_report_controller.dart';
+
+import 'package:plugin_basic/base/base_state.dart';
+import 'package:plugin_basic/base/base_stateful_page.dart';
+import 'package:plugin_basic/utils/ext_get_nav.dart';
+import 'package:router/path/router_path.dart';
+import 'package:shared/utils/screen_util.dart';
+import 'package:widgets/my_appbar.dart';
+import 'working_hours_report_state.dart';
+
+/*
+ * 工作时长的报表
+ */
+class UKWorkingHoursReportPage extends BaseStatefulPage<WorkingHoursReportController> {
+  UKWorkingHoursReportPage({Key? key}) : super(key: key);
+
+  //启动当前页面
+  static void startInstance() {
+    return Get.start(RouterPath.UKReportWorkingHours);
+  }
+
+  @override
+  WorkingHoursReportController createRawController() {
+    return WorkingHoursReportController();
+  }
+
+  @override
+  State<UKWorkingHoursReportPage> createState() => _LabourReviewState();
+}
+
+class _LabourReviewState extends BaseState<UKWorkingHoursReportPage, WorkingHoursReportController> {
+  late WorkingHoursReportState state;
+
+  @override
+  void initState() {
+    super.initState();
+    state = controller.state;
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return autoCtlGetBuilder(builder: (controller) {
+      return SafeArea(
+        bottom: true,
+        top: false,
+        child: Container(
+          width: double.infinity,
+          height: double.infinity,
+          padding: EdgeInsets.only(top: ScreenUtil.getStatusBarH(context)),
+          decoration: const BoxDecoration(
+            gradient: LinearGradient(
+              colors: [
+                Color(0xFF091D44),
+                Color(0xFF245A8A),
+                Color(0xFF7F7CEC),
+              ],
+              begin: Alignment.topCenter,
+              end: Alignment.bottomCenter,
+            ),
+          ),
+          child: Column(
+            children: [
+              MyAppBar.titleBar(
+                context,
+                "Working Hours".tr,
+                actions: [
+                  //筛选图标
+                  const MyAssetImage(
+                    Assets.baseServiceTitleBarFilterIcon,
+                    width: 24,
+                    height: 16.5,
+                  ).onTap(() {
+                    FocusScope.of(context).unfocus();
+                    controller.showFilterDialog();
+                  }).marginOnly(right: 15),
+                ],
+              ),
+
+              //底部的列表
+              EasyRefresh(
+                controller: controller.refreshController,
+                onRefresh: controller.onRefresh,
+                onLoad: controller.loadMore,
+                child: LoadStateLayout(
+                  state: controller.loadingState,
+                  errorMessage: controller.errorMessage,
+                  errorRetry: () {
+                    controller.retryRequest();
+                  },
+                  successSliverWidget: [
+                    SliverList(
+                        delegate: SliverChildBuilderDelegate(
+                      (context, index) {
+                        return WorkingHoursReportItem(
+                          index: index,
+                          item: state.datas[index],
+                        );
+                      },
+                      childCount: state.datas.length,
+                    ))
+                  ],
+                ),
+              ).expanded(),
+
+            ],
+          ),
+        ),
+      );
+    });
+  }
+}

+ 12 - 0
packages/cpt_uk/lib/modules/report/working_hours_report/working_hours_report_state.dart

@@ -0,0 +1,12 @@
+import 'package:domain/entity/response/labour_request_index_entity.dart';
+import 'package:domain/entity/response/labour_review_list_entity.dart';
+
+class WorkingHoursReportState {
+  DateTime? selectedStartDate;
+  DateTime? selectedEndDate;
+  String? selectedDepartmentId;
+
+  //页面的列表数据
+  List<LabourReviewListRows> datas = [];
+  LabourRequestIndexEntity? indexOptions;
+}

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

@@ -13,13 +13,19 @@ import 'package:cpt_uk/modules/job/labour_request_workflow/labour_request_workfl
 import 'package:cpt_uk/modules/job/template_add/template_add_page.dart';
 import 'package:cpt_uk/modules/job/template_list/template_list_page.dart';
 import 'package:cpt_uk/modules/main/main_page.dart';
+import 'package:cpt_uk/modules/report/casual_payout_report/casual_payout_report_page.dart';
+import 'package:cpt_uk/modules/report/casual_report/casual_report_page.dart';
+import 'package:cpt_uk/modules/report/finance_report/report_finance_page.dart';
 import 'package:cpt_uk/modules/report/labour_report/labour_report_page.dart';
+import 'package:cpt_uk/modules/report/outlet_staff_report/outlet_staff_report_page.dart';
 import 'package:cpt_uk/modules/report/report_list/report_list_page.dart';
+import 'package:cpt_uk/modules/report/working_hours_report/working_hours_report_page.dart';
 import 'package:get/get.dart';
 import 'package:router/path/router_path.dart';
 
 import '../modules/job/job_applied/job_applied_page.dart';
 import '../modules/job/job_applied_edit/job_applied_edit_page.dart';
+import '../modules/report/attendance_report/attendance_report_page.dart';
 import '../modules/review/attendance_review_list/attendance_review_page.dart';
 import '../modules/review/labour_review_edit/labour_review_edit_page.dart';
 import '../modules/review/labour_review_list/labour_review_page.dart';
@@ -166,5 +172,41 @@ class UKPageRouter {
       page: () => UKLabourReportPage(),
     ),
 
+    //报表 - 部门的员工的月度统计
+    GetPage(
+      name: RouterPath.UKReportOutlet,
+      page: () => UKOutletStaffReportPage(),
+    ),
+
+    //报表 - 财务报表还是终极报表
+    GetPage(
+      name: RouterPath.UKReportfinance,
+      page: () => UKReportFinancePage(),
+    ),
+
+    //报表 - 工作时长报告
+    GetPage(
+      name: RouterPath.UKReportWorkingHours,
+      page: () => UKWorkingHoursReportPage(),
+    ),
+
+    //报表 - 电子考勤
+    GetPage(
+      name: RouterPath.UKReportAttendance,
+      page: () => UKAttendanceReportPage(),
+    ),
+
+    //报表 - 临时工作付款统计
+    GetPage(
+      name: RouterPath.UKReportCasualPayout,
+      page: () => UKCasualPayoutReportPage(),
+    ),
+
+    //报表 - 临时工月度报表
+    GetPage(
+      name: RouterPath.UKReportCasualMonthly,
+      page: () => UKCasualReportPage(),
+    ),
+
   ];
 }

+ 15 - 14
packages/cs_domain/lib/repository/job_repository.dart

@@ -35,11 +35,13 @@ class JobRepository extends GetxService {
     String? keyword,
     String? startDate,
     String? endDate, {
+    int curPage = 1,
+    int pageSize = 9999,
     CancelToken? cancelToken,
   }) async {
     Map<String, String> params = {};
-    params["cur_page"] = "1";
-    params["page_size"] = "9999";
+    params["cur_page"] = curPage.toString();
+    params["page_size"] = pageSize.toString();
 
     if (!Utils.isEmpty(keyword)) {
       params["keyword"] = keyword!;
@@ -734,10 +736,10 @@ class JobRepository extends GetxService {
 
   /// 考勤审核列表
   Future<HttpResult<AttendanceReviewEntity>> fetchAttendanceReviewList(
-      String? keyword, {
-        required int curPage,
-        CancelToken? cancelToken,
-      }) async {
+    String? keyword, {
+    required int curPage,
+    CancelToken? cancelToken,
+  }) async {
     //参数
     Map<String, String> params = {};
     params["cur_page"] = curPage.toString();
@@ -766,9 +768,9 @@ class JobRepository extends GetxService {
 
   /// 考勤的批量同意
   Future<HttpResult> approveAttendanceReviews(
-      String? recordIds, {
-        CancelToken? cancelToken,
-      }) async {
+    String? recordIds, {
+    CancelToken? cancelToken,
+  }) async {
     //参数
     Map<String, String> params = {};
     params['record_ids'] = recordIds ?? "";
@@ -792,10 +794,10 @@ class JobRepository extends GetxService {
 
   /// 考勤的批量拒绝
   Future<HttpResult> rejectLabourReviews(
-      String? recordIds,
-      String? reason, {
-        CancelToken? cancelToken,
-      }) async {
+    String? recordIds,
+    String? reason, {
+    CancelToken? cancelToken,
+  }) async {
     //参数
     Map<String, String> params = {};
     params['record_ids'] = recordIds ?? "";
@@ -820,5 +822,4 @@ class JobRepository extends GetxService {
     }
     return result.convert();
   }
-
 }

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

@@ -250,6 +250,9 @@ const Map<String, String> en_US = {
   'Working Hours': 'Working Hours',
   'Casual Payout': 'Casual Payout',
   'Casual Report': 'Casual Report',
+  'Manpower Needed': 'Manpower Needed',
+  'Actual Num': 'Actual Num',
+  'Completed Num': 'Completed Num',
 
   //插件的国际化
   'Pull to refresh': 'Pull to refresh',

+ 4 - 1
packages/cs_resources/lib/local/language/zh_CN.dart

@@ -246,10 +246,13 @@ const Map<String, String> zh_CN = {
   'Batch Confirm': '批量确认',
   'Batch Reject': '批量拒绝',
   'Device': '设备',
-  'Outlet Request': '部门需求',
+  'Outlet Request': '部门统计',
   'Working Hours': '工作时长',
   'Casual Payout': '临时工支付',
   'Casual Report': '临时工报告',
+  'Manpower Needed': '所需人数',
+  'Actual Num': '实际人数',
+  'Completed Num': '完成人数',
 
   //插件的国际化
   'Pull to refresh': '下拉刷新',

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

@@ -96,6 +96,12 @@ class RouterPath {
   static const UKSecurityRegistration= '/uk/security/registration';   //UK卫门报道
   static const UKReportList= '/uk/report/list';   //UK报表分类列表
   static const UKReportLabour= '/uk/report/labour';   //UK报表-Labour
+  static const UKReportOutlet= '/uk/report/outlet';   //UK报表-部门员工月度统计
+  static const UKReportfinance= '/uk/report/finance';   //UK报表-财务报表?终极报表?
+  static const UKReportWorkingHours= '/uk/report/working/hours';   //UK报表-工作时长
+  static const UKReportAttendance= '/uk/report/attendance';   //UK报表-电子考勤
+  static const UKReportCasualPayout= '/uk/report/casual/payout';   //UK报表-临时工作付款统计
+  static const UKReportCasualMonthly= '/uk/report/casual/monthly';   //UK报表-临时工月度报表
 
   //Runalone
   static const runAloneMain = '/runalone/main'; //独立运行的入口页面