소스 검색

越南的两个报表页面的修改

liukai 6 달 전
부모
커밋
8eeb498020

+ 84 - 0
packages/cpt_report/lib/modules/report_labour_vn/report_labour_vn_controller.dart

@@ -0,0 +1,84 @@
+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_labour_vn_state.dart';
+
+class ReportLabourVNController extends GetxController with DioCancelableMixin {
+  final OtherRepository _otherRepository = Get.find();
+  final ReportLabourVNState state = ReportLabourVNState();
+
+  //页面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.fetchReportLabourVN(
+      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,
+    );
+  }
+}

+ 219 - 0
packages/cpt_report/lib/modules/report_labour_vn/report_labour_vn_item.dart

@@ -0,0 +1,219 @@
+import 'package:cs_resources/constants/color_constants.dart';
+import 'package:domain/entity/response/labour_report_v_n_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 ReportLabourVNItem extends StatelessWidget {
+  LabourReportVNEntity? entity; //主体数据
+  int type; //0  1  2
+
+  ReportLabourVNItem({
+    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),
+          SingleChildScrollView(
+            scrollDirection: Axis.horizontal,
+            child: Row(
+              crossAxisAlignment: CrossAxisAlignment.start,
+              children: [
+                //第一列 部门
+                Column(
+                  crossAxisAlignment: CrossAxisAlignment.start,
+                  children: [
+                    MyTextView(
+                      "Outlet".tr,
+                      fontSize: 14,
+                      textColor: Colors.white,
+                      isFontRegular: true,
+                    ),
+                    MyTextView(
+                      "-",
+                      textColor: Colors.transparent,
+                      fontSize: 14,
+                      isFontRegular: true,
+                    ),
+                    ...(entity?.rows.map((item) {
+                          return MyTextView(
+                            item.outletName ?? "-",
+                            fontSize: 14,
+                            maxLines: 1,
+                            isTextEllipsis: true,
+                            textColor: Colors.white,
+                            isFontRegular: true,
+                            marginTop: 6,
+                            marginBottom: 6,
+                          );
+                        }).toList() ??
+                        []),
+                  ],
+                ).constrained(maxWidth: 100),
+
+                //第二列 小时
+                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,
+                    ),
+                    ...(entity?.rows.map((item) {
+                          return MyTextView(
+                            "${type == 0 ? item.hrs ?? "0" : type == 1 ? item.inHrs ?? "0" : item.totHrs ?? "0"} H",
+                            fontSize: 14,
+                            textColor: Colors.white,
+                            isFontRegular: true,
+                            marginTop: 6,
+                            marginBottom: 6,
+                          );
+                        }).toList() ??
+                        []),
+                  ],
+                ).constrained(maxWidth: 100).marginOnly(left: 25),
+
+                //第三列 房间
+                Column(
+                  crossAxisAlignment: CrossAxisAlignment.start,
+                  children: [
+                    MyTextView("Rooms".tr, textColor: Colors.white, fontSize: 14, isFontRegular: true),
+                    MyTextView(
+                      "(${entity?.total?.rms})",
+                      textColor: type == 0
+                          ? ColorConstants.textGreen0AC074
+                          : type == 1
+                              ? ColorConstants.textBlue06D9FF
+                              : ColorConstants.textRedFF6262,
+                      fontSize: 14,
+                      isFontRegular: true,
+                    ),
+                    ...(entity?.rows.map((item) {
+                          return MyTextView(
+                            type == 0
+                                ? item.rms ?? ""
+                                : type == 1
+                                    ? item.inRms ?? ""
+                                    : item.totRms ?? "",
+                            fontSize: 14,
+                            textColor: Colors.white,
+                            isFontRegular: true,
+                            marginTop: 6,
+                            marginBottom: 6,
+                          );
+                        }).toList() ??
+                        []),
+                  ],
+                ).constrained(maxWidth: 100).marginOnly(left: 25),
+
+                //第四列 数量
+                Column(
+                  crossAxisAlignment: CrossAxisAlignment.start,
+                  children: [
+                    MyTextView("Count".tr, textColor: Colors.white, fontSize: 14, isFontRegular: true),
+                    MyTextView(
+                      "(${entity?.total?.num})",
+                      textColor: type == 0
+                          ? ColorConstants.textGreen0AC074
+                          : type == 1
+                              ? ColorConstants.textBlue06D9FF
+                              : ColorConstants.textRedFF6262,
+                      fontSize: 14,
+                      isFontRegular: true,
+                    ),
+                    ...(entity?.rows.map((item) {
+                          return MyTextView(
+                            type == 0
+                                ? item.num ?? ""
+                                : type == 1
+                                    ? item.inNum ?? ""
+                                    : item.totNum ?? "",
+                            fontSize: 14,
+                            textColor: Colors.white,
+                            isFontRegular: true,
+                            marginTop: 6,
+                            marginBottom: 6,
+                          );
+                        }).toList() ??
+                        []),
+                  ],
+                ).constrained(maxWidth: 100).marginOnly(left: 25),
+
+                //第五列 总金额
+                Column(
+                  crossAxisAlignment: CrossAxisAlignment.start,
+                  children: [
+                    MyTextView("TotalAmt".tr, textColor: Colors.white, fontSize: 14, isFontRegular: true),
+                    MyTextView(
+                      "(${entity?.total?.totAmt})",
+                      textColor: type == 0
+                          ? ColorConstants.textGreen0AC074
+                          : type == 1
+                              ? ColorConstants.textBlue06D9FF
+                              : ColorConstants.textRedFF6262,
+                      fontSize: 14,
+                      isFontRegular: true,
+                    ),
+                    ...(entity?.rows.map((item) {
+                          return MyTextView(
+                            "₫ ${type == 0 ? item.amt ?? "0" : type == 1 ? item.inAmt ?? "0" : item.totAmt ?? "0"}",
+                            fontSize: 14,
+                            textColor: Colors.white,
+                            isFontRegular: true,
+                            marginTop: 6,
+                            marginBottom: 6,
+                          );
+                        }).toList() ??
+                        []),
+                  ],
+                ).constrained(maxWidth: 100).marginOnly(left: 25),
+              ],
+            ).marginOnly(left: 20, right: 20, top: 18, bottom: 2),
+          ),
+        ],
+      ),
+    );
+  }
+}

+ 128 - 0
packages/cpt_report/lib/modules/report_labour_vn/report_labour_vn_page.dart

@@ -0,0 +1,128 @@
+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 'report_labour_vn_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_labour_vn_item.dart';
+import 'report_labour_vn_state.dart';
+
+/*
+ * 越南的用工报表,单独的页面
+ */
+class ReportLabourVNPage extends BaseStatelessPage<ReportLabourVNController> {
+  ReportLabourVNPage({Key? key}) : super(key: key);
+
+  //启动当前页面
+  static void startInstance() {
+    return Get.start(RouterPath.reportLabourVN);
+  }
+
+  late ReportLabourVNState state;
+
+  @override
+  void initState() {
+    state = controller.state;
+  }
+
+  @override
+  ReportLabourVNController createRawController() {
+    return ReportLabourVNController();
+  }
+
+  @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 ReportLabourVNItem(entity: state.entity, type: index);
+                      },
+                      childCount: state.datas.isNotEmpty ? 3 : 0,
+                    ))
+                  ],
+                ).expanded(),
+              ],
+            ),
+          ),
+        ),
+      );
+    });
+  }
+}

+ 10 - 0
packages/cpt_report/lib/modules/report_labour_vn/report_labour_vn_state.dart

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

+ 10 - 1
packages/cpt_report/lib/modules/report_list/report_list_controller.dart

@@ -1,12 +1,14 @@
 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:shared/utils/log_utils.dart';
 
 import '../report_finance/report_finance_page.dart';
 import '../report_labour/report_labour_page.dart';
+import '../report_labour_vn/report_labour_vn_page.dart';
 import '../report_staff_request/report_staff_request_page.dart';
 import 'report_list_state.dart';
 
@@ -56,7 +58,14 @@ class ReportListController extends GetxController {
         ReportFinancePage.startInstance();
         break;
       case 'casLab':
-        ReportLabourPage.startInstance();
+        if (ConfigService.to.curSelectCountry.value ==1){
+          //新加坡
+          ReportLabourPage.startInstance();
+        }else{
+          //越南
+          ReportLabourVNPage.startInstance();
+        }
+
         break;
       case 'monReq':
         ReportStaffRequestPage.startInstance();

+ 8 - 0
packages/cpt_report/lib/router/page_router.dart

@@ -6,6 +6,8 @@ import 'package:cpt_report/modules/report_staff_request/report_staff_request_pag
 import 'package:get/get.dart';
 import 'package:router/path/router_path.dart';
 
+import '../modules/report_labour_vn/report_labour_vn_page.dart';
+
 class ReportPageRouter {
   static final routes = [
     //设备列表
@@ -38,5 +40,11 @@ class ReportPageRouter {
       page: () => ReportLabourPage(),
     ),
 
+    //用工统计(越南单独页面)
+    GetPage(
+      name: RouterPath.reportLabourVN,
+      page: () => ReportLabourVNPage(),
+    ),
+
   ];
 }

+ 99 - 0
packages/cs_domain/lib/entity/response/labour_report_v_n_entity.dart

@@ -0,0 +1,99 @@
+import 'package:domain/generated/json/base/json_field.dart';
+import 'package:domain/generated/json/labour_report_v_n_entity.g.dart';
+import 'dart:convert';
+export 'package:domain/generated/json/labour_report_v_n_entity.g.dart';
+
+@JsonSerializable()
+class LabourReportVNEntity {
+	@JSONField(name: "start_date")
+	String? startDate;
+	@JSONField(name: "end_date")
+	String? endDate;
+	List<LabourReportVNRows> rows = [];
+	LabourReportVNTotal? total;
+
+	LabourReportVNEntity();
+
+	factory LabourReportVNEntity.fromJson(Map<String, dynamic> json) => $LabourReportVNEntityFromJson(json);
+
+	Map<String, dynamic> toJson() => $LabourReportVNEntityToJson(this);
+
+	@override
+	String toString() {
+		return jsonEncode(this);
+	}
+}
+
+@JsonSerializable()
+class LabourReportVNRows {
+	@JSONField(name: "outlet_id")
+	String? outletId;
+	@JSONField(name: "outlet_name")
+	String? outletName;
+	String? num;
+	String? hrs;
+	String? rms;
+	String? amt;
+	@JSONField(name: "in_num")
+	String? inNum;
+	@JSONField(name: "in_hrs")
+	String? inHrs;
+	@JSONField(name: "in_rms")
+	String? inRms;
+	@JSONField(name: "in_amt")
+	String? inAmt;
+	@JSONField(name: "tot_num")
+	String? totNum;
+	@JSONField(name: "tot_hrs")
+	String? totHrs;
+	@JSONField(name: "tot_rms")
+	String? totRms;
+	@JSONField(name: "tot_amt")
+	String? totAmt;
+
+	LabourReportVNRows();
+
+	factory LabourReportVNRows.fromJson(Map<String, dynamic> json) => $LabourReportVNRowsFromJson(json);
+
+	Map<String, dynamic> toJson() => $LabourReportVNRowsToJson(this);
+
+	@override
+	String toString() {
+		return jsonEncode(this);
+	}
+}
+
+@JsonSerializable()
+class LabourReportVNTotal {
+	String? num;
+	double? hrs;
+	String? rms;
+	String? amt;
+	@JSONField(name: "in_num")
+	String? inNum;
+	@JSONField(name: "in_hrs")
+	String? inHrs;
+	@JSONField(name: "in_rms")
+	String? inRms;
+	@JSONField(name: "in_amt")
+	String? inAmt;
+	@JSONField(name: "tot_num")
+	String? totNum;
+	@JSONField(name: "tot_hrs")
+	String? totHrs;
+	@JSONField(name: "tot_rms")
+	String? totRms;
+	@JSONField(name: "tot_amt")
+	String? totAmt;
+
+	LabourReportVNTotal();
+
+	factory LabourReportVNTotal.fromJson(Map<String, dynamic> json) => $LabourReportVNTotalFromJson(json);
+
+	Map<String, dynamic> toJson() => $LabourReportVNTotalToJson(this);
+
+	@override
+	String toString() {
+		return jsonEncode(this);
+	}
+}

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

@@ -34,6 +34,7 @@ import 'package:domain/entity/response/job_template_s_g_entity.dart';
 import 'package:domain/entity/response/job_title_edit_index_entity.dart';
 import 'package:domain/entity/response/job_title_s_g_entity.dart';
 import 'package:domain/entity/response/labour_report_entity.dart';
+import 'package:domain/entity/response/labour_report_v_n_entity.dart';
 import 'package:domain/entity/response/labour_request_edit_index_entity.dart';
 import 'package:domain/entity/response/labour_request_index_entity.dart';
 import 'package:domain/entity/response/labour_request_list_entity.dart';
@@ -374,6 +375,15 @@ class JsonConvert {
     if (<LabourReportTotal>[] is M) {
       return data.map<LabourReportTotal>((Map<String, dynamic> e) => LabourReportTotal.fromJson(e)).toList() as M;
     }
+    if (<LabourReportVNEntity>[] is M) {
+      return data.map<LabourReportVNEntity>((Map<String, dynamic> e) => LabourReportVNEntity.fromJson(e)).toList() as M;
+    }
+    if (<LabourReportVNRows>[] is M) {
+      return data.map<LabourReportVNRows>((Map<String, dynamic> e) => LabourReportVNRows.fromJson(e)).toList() as M;
+    }
+    if (<LabourReportVNTotal>[] is M) {
+      return data.map<LabourReportVNTotal>((Map<String, dynamic> e) => LabourReportVNTotal.fromJson(e)).toList() as M;
+    }
     if (<LabourRequestEditIndexEntity>[] is M) {
       return data.map<LabourRequestEditIndexEntity>((Map<String, dynamic> e) => LabourRequestEditIndexEntity.fromJson(e)).toList() as M;
     }
@@ -582,6 +592,9 @@ class JsonConvertClassCollection {
     (LabourReportEntity).toString(): LabourReportEntity.fromJson,
     (LabourReportRows).toString(): LabourReportRows.fromJson,
     (LabourReportTotal).toString(): LabourReportTotal.fromJson,
+    (LabourReportVNEntity).toString(): LabourReportVNEntity.fromJson,
+    (LabourReportVNRows).toString(): LabourReportVNRows.fromJson,
+    (LabourReportVNTotal).toString(): LabourReportVNTotal.fromJson,
     (LabourRequestEditIndexEntity).toString(): LabourRequestEditIndexEntity.fromJson,
     (LabourRequestEditIndexTemplateList).toString(): LabourRequestEditIndexTemplateList.fromJson,
     (LabourRequestEditIndexDepartmentList).toString(): LabourRequestEditIndexDepartmentList.fromJson,

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

@@ -0,0 +1,264 @@
+import 'package:domain/generated/json/base/json_convert_content.dart';
+import 'package:domain/entity/response/labour_report_v_n_entity.dart';
+
+LabourReportVNEntity $LabourReportVNEntityFromJson(Map<String, dynamic> json) {
+  final LabourReportVNEntity labourReportVNEntity = LabourReportVNEntity();
+  final String? startDate = jsonConvert.convert<String>(json['start_date']);
+  if (startDate != null) {
+    labourReportVNEntity.startDate = startDate;
+  }
+  final String? endDate = jsonConvert.convert<String>(json['end_date']);
+  if (endDate != null) {
+    labourReportVNEntity.endDate = endDate;
+  }
+  final List<LabourReportVNRows>? rows = (json['rows'] as List<dynamic>?)?.map(
+          (e) => jsonConvert.convert<LabourReportVNRows>(e) as LabourReportVNRows).toList();
+  if (rows != null) {
+    labourReportVNEntity.rows = rows;
+  }
+  final LabourReportVNTotal? total = jsonConvert.convert<LabourReportVNTotal>(json['total']);
+  if (total != null) {
+    labourReportVNEntity.total = total;
+  }
+  return labourReportVNEntity;
+}
+
+Map<String, dynamic> $LabourReportVNEntityToJson(LabourReportVNEntity entity) {
+  final Map<String, dynamic> data = <String, dynamic>{};
+  data['start_date'] = entity.startDate;
+  data['end_date'] = entity.endDate;
+  data['rows'] = entity.rows.map((v) => v.toJson()).toList();
+  data['total'] = entity.total?.toJson();
+  return data;
+}
+
+extension LabourReportVNEntityExtension on LabourReportVNEntity {
+  LabourReportVNEntity copyWith({
+    String? startDate,
+    String? endDate,
+    List<LabourReportVNRows>? rows,
+    LabourReportVNTotal? total,
+  }) {
+    return LabourReportVNEntity()
+      ..startDate = startDate ?? this.startDate
+      ..endDate = endDate ?? this.endDate
+      ..rows = rows ?? this.rows
+      ..total = total ?? this.total;
+  }
+}
+
+LabourReportVNRows $LabourReportVNRowsFromJson(Map<String, dynamic> json) {
+  final LabourReportVNRows labourReportVNRows = LabourReportVNRows();
+  final String? outletId = jsonConvert.convert<String>(json['outlet_id']);
+  if (outletId != null) {
+    labourReportVNRows.outletId = outletId;
+  }
+  final String? outletName = jsonConvert.convert<String>(json['outlet_name']);
+  if (outletName != null) {
+    labourReportVNRows.outletName = outletName;
+  }
+  final String? num = jsonConvert.convert<String>(json['num']);
+  if (num != null) {
+    labourReportVNRows.num = num;
+  }
+  final String? hrs = jsonConvert.convert<String>(json['hrs']);
+  if (hrs != null) {
+    labourReportVNRows.hrs = hrs;
+  }
+  final String? rms = jsonConvert.convert<String>(json['rms']);
+  if (rms != null) {
+    labourReportVNRows.rms = rms;
+  }
+  final String? amt = jsonConvert.convert<String>(json['amt']);
+  if (amt != null) {
+    labourReportVNRows.amt = amt;
+  }
+  final String? inNum = jsonConvert.convert<String>(json['in_num']);
+  if (inNum != null) {
+    labourReportVNRows.inNum = inNum;
+  }
+  final String? inHrs = jsonConvert.convert<String>(json['in_hrs']);
+  if (inHrs != null) {
+    labourReportVNRows.inHrs = inHrs;
+  }
+  final String? inRms = jsonConvert.convert<String>(json['in_rms']);
+  if (inRms != null) {
+    labourReportVNRows.inRms = inRms;
+  }
+  final String? inAmt = jsonConvert.convert<String>(json['in_amt']);
+  if (inAmt != null) {
+    labourReportVNRows.inAmt = inAmt;
+  }
+  final String? totNum = jsonConvert.convert<String>(json['tot_num']);
+  if (totNum != null) {
+    labourReportVNRows.totNum = totNum;
+  }
+  final String? totHrs = jsonConvert.convert<String>(json['tot_hrs']);
+  if (totHrs != null) {
+    labourReportVNRows.totHrs = totHrs;
+  }
+  final String? totRms = jsonConvert.convert<String>(json['tot_rms']);
+  if (totRms != null) {
+    labourReportVNRows.totRms = totRms;
+  }
+  final String? totAmt = jsonConvert.convert<String>(json['tot_amt']);
+  if (totAmt != null) {
+    labourReportVNRows.totAmt = totAmt;
+  }
+  return labourReportVNRows;
+}
+
+Map<String, dynamic> $LabourReportVNRowsToJson(LabourReportVNRows entity) {
+  final Map<String, dynamic> data = <String, dynamic>{};
+  data['outlet_id'] = entity.outletId;
+  data['outlet_name'] = entity.outletName;
+  data['num'] = entity.num;
+  data['hrs'] = entity.hrs;
+  data['rms'] = entity.rms;
+  data['amt'] = entity.amt;
+  data['in_num'] = entity.inNum;
+  data['in_hrs'] = entity.inHrs;
+  data['in_rms'] = entity.inRms;
+  data['in_amt'] = entity.inAmt;
+  data['tot_num'] = entity.totNum;
+  data['tot_hrs'] = entity.totHrs;
+  data['tot_rms'] = entity.totRms;
+  data['tot_amt'] = entity.totAmt;
+  return data;
+}
+
+extension LabourReportVNRowsExtension on LabourReportVNRows {
+  LabourReportVNRows copyWith({
+    String? outletId,
+    String? outletName,
+    String? num,
+    String? hrs,
+    String? rms,
+    String? amt,
+    String? inNum,
+    String? inHrs,
+    String? inRms,
+    String? inAmt,
+    String? totNum,
+    String? totHrs,
+    String? totRms,
+    String? totAmt,
+  }) {
+    return LabourReportVNRows()
+      ..outletId = outletId ?? this.outletId
+      ..outletName = outletName ?? this.outletName
+      ..num = num ?? this.num
+      ..hrs = hrs ?? this.hrs
+      ..rms = rms ?? this.rms
+      ..amt = amt ?? this.amt
+      ..inNum = inNum ?? this.inNum
+      ..inHrs = inHrs ?? this.inHrs
+      ..inRms = inRms ?? this.inRms
+      ..inAmt = inAmt ?? this.inAmt
+      ..totNum = totNum ?? this.totNum
+      ..totHrs = totHrs ?? this.totHrs
+      ..totRms = totRms ?? this.totRms
+      ..totAmt = totAmt ?? this.totAmt;
+  }
+}
+
+LabourReportVNTotal $LabourReportVNTotalFromJson(Map<String, dynamic> json) {
+  final LabourReportVNTotal labourReportVNTotal = LabourReportVNTotal();
+  final String? num = jsonConvert.convert<String>(json['num']);
+  if (num != null) {
+    labourReportVNTotal.num = num;
+  }
+  final double? hrs = jsonConvert.convert<double>(json['hrs']);
+  if (hrs != null) {
+    labourReportVNTotal.hrs = hrs;
+  }
+  final String? rms = jsonConvert.convert<String>(json['rms']);
+  if (rms != null) {
+    labourReportVNTotal.rms = rms;
+  }
+  final String? amt = jsonConvert.convert<String>(json['amt']);
+  if (amt != null) {
+    labourReportVNTotal.amt = amt;
+  }
+  final String? inNum = jsonConvert.convert<String>(json['in_num']);
+  if (inNum != null) {
+    labourReportVNTotal.inNum = inNum;
+  }
+  final String? inHrs = jsonConvert.convert<String>(json['in_hrs']);
+  if (inHrs != null) {
+    labourReportVNTotal.inHrs = inHrs;
+  }
+  final String? inRms = jsonConvert.convert<String>(json['in_rms']);
+  if (inRms != null) {
+    labourReportVNTotal.inRms = inRms;
+  }
+  final String? inAmt = jsonConvert.convert<String>(json['in_amt']);
+  if (inAmt != null) {
+    labourReportVNTotal.inAmt = inAmt;
+  }
+  final String? totNum = jsonConvert.convert<String>(json['tot_num']);
+  if (totNum != null) {
+    labourReportVNTotal.totNum = totNum;
+  }
+  final String? totHrs = jsonConvert.convert<String>(json['tot_hrs']);
+  if (totHrs != null) {
+    labourReportVNTotal.totHrs = totHrs;
+  }
+  final String? totRms = jsonConvert.convert<String>(json['tot_rms']);
+  if (totRms != null) {
+    labourReportVNTotal.totRms = totRms;
+  }
+  final String? totAmt = jsonConvert.convert<String>(json['tot_amt']);
+  if (totAmt != null) {
+    labourReportVNTotal.totAmt = totAmt;
+  }
+  return labourReportVNTotal;
+}
+
+Map<String, dynamic> $LabourReportVNTotalToJson(LabourReportVNTotal entity) {
+  final Map<String, dynamic> data = <String, dynamic>{};
+  data['num'] = entity.num;
+  data['hrs'] = entity.hrs;
+  data['rms'] = entity.rms;
+  data['amt'] = entity.amt;
+  data['in_num'] = entity.inNum;
+  data['in_hrs'] = entity.inHrs;
+  data['in_rms'] = entity.inRms;
+  data['in_amt'] = entity.inAmt;
+  data['tot_num'] = entity.totNum;
+  data['tot_hrs'] = entity.totHrs;
+  data['tot_rms'] = entity.totRms;
+  data['tot_amt'] = entity.totAmt;
+  return data;
+}
+
+extension LabourReportVNTotalExtension on LabourReportVNTotal {
+  LabourReportVNTotal copyWith({
+    String? num,
+    double? hrs,
+    String? rms,
+    String? amt,
+    String? inNum,
+    String? inHrs,
+    String? inRms,
+    String? inAmt,
+    String? totNum,
+    String? totHrs,
+    String? totRms,
+    String? totAmt,
+  }) {
+    return LabourReportVNTotal()
+      ..num = num ?? this.num
+      ..hrs = hrs ?? this.hrs
+      ..rms = rms ?? this.rms
+      ..amt = amt ?? this.amt
+      ..inNum = inNum ?? this.inNum
+      ..inHrs = inHrs ?? this.inHrs
+      ..inRms = inRms ?? this.inRms
+      ..inAmt = inAmt ?? this.inAmt
+      ..totNum = totNum ?? this.totNum
+      ..totHrs = totHrs ?? this.totHrs
+      ..totRms = totRms ?? this.totRms
+      ..totAmt = totAmt ?? this.totAmt;
+  }
+}

+ 33 - 0
packages/cs_domain/lib/repository/other_repository.dart

@@ -10,6 +10,7 @@ import 'package:shared/utils/log_utils.dart';
 import 'package:shared/utils/util.dart';
 
 import '../constants/api_constants.dart';
+import '../entity/response/labour_report_v_n_entity.dart';
 import '../entity/response/staff_report_v_n_entity.dart';
 
 /// 报表与其他的相关数据
@@ -180,4 +181,36 @@ class OtherRepository extends GetxService {
     return result.convert();
   }
 
+  /// 越南的用工报表
+  Future<HttpResult<LabourReportVNEntity>> fetchReportLabourVN(
+      String? startDate,
+      String? endDate, {
+        CancelToken? cancelToken,
+      }) async {
+    //参数
+    Map<String, String> params = {};
+    if (Utils.isNotEmpty(startDate)) {
+      params["start_date"] = startDate!;
+    }
+    if (Utils.isNotEmpty(endDate)) {
+      params["end_date"] = endDate!;
+    }
+
+    final result = await httpProvider.requestNetResult(
+      ApiConstants.apiReportLabour,
+      params: params,
+      cancelToken: cancelToken,
+    );
+
+    //根据返回的结果,封装原始数据为Bean/Entity对象
+    if (result.isSuccess) {
+      //重新赋值data或list
+      final json = result.getDataJson();
+      var data = LabourReportVNEntity.fromJson(json!);
+      //重新赋值data或list
+      return result.convert<LabourReportVNEntity>(data: data);
+    }
+    return result.convert();
+  }
+
 }

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

@@ -37,6 +37,7 @@ class RouterPath {
   static const reportList = '/report/list'; //报表的选项
   static const reportFinance = '/report/finance'; //金额报表
   static const reportCasualLabour = '/report/labour'; //用工请求报表
+  static const reportLabourVN = '/report/labour/vn'; //用工请求报表(越南的单独页面)
   static const reportStaffRequest = '/report/staff/request'; //员工申请报表
 
   //新加坡的用工请求