Browse Source

UK的门卫签到模快接口逻辑调试完成

liukai 1 week ago
parent
commit
1a0455f6de

+ 33 - 44
packages/cpt_uk/lib/modules/attendance/security_registration/item_security_registration.dart

@@ -1,14 +1,11 @@
 import 'package:cs_resources/constants/color_constants.dart';
-import 'package:cs_resources/generated/assets.dart';
-import 'package:domain/entity/response/attendance_entity.dart';
+import 'package:domain/entity/response/u_k_security_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:shared/utils/util.dart';
 import 'package:widgets/ext/ex_widget.dart';
 import 'package:widgets/my_button.dart';
-import 'package:widgets/my_load_image.dart';
 import 'package:widgets/my_text_view.dart';
 
 /*
@@ -16,7 +13,7 @@ import 'package:widgets/my_text_view.dart';
  */
 class SecurityRegistrationItem extends StatelessWidget {
   final int index;
-  final AttendanceList item;
+  final UKSecurityAttendanceRows item;
   final VoidCallback? onMemberAction;
   final VoidCallback? onEditAction;
 
@@ -40,86 +37,82 @@ class SecurityRegistrationItem extends StatelessWidget {
         mainAxisSize: MainAxisSize.max,
         crossAxisAlignment: CrossAxisAlignment.start,
         children: [
-
-          //考勤对应的工作日期
+          //员工姓名
           Row(
             mainAxisSize: MainAxisSize.max,
             crossAxisAlignment: CrossAxisAlignment.center,
             children: [
               MyTextView(
-                "${"Date".tr}:",
+                "${"Staff Name".tr}:",
                 isFontRegular: true,
                 textColor: ColorConstants.textGrayAECAE5,
                 fontSize: 14,
               ),
 
-              //日期文本
+              //姓名
               MyTextView(
-                item.jobDate ?? "-",
+                item.staffName ?? "-",
                 isFontMedium: true,
-                textColor: Colors.white,
+                textColor: ColorConstants.textYellowFFBB1B,
                 fontSize: 14,
                 marginLeft: 5,
                 marginRight: 5,
+                textDecoration: TextDecoration.underline,
+                decorationColor: ColorConstants.textYellowFFBB1B,
+                // 可选,设置下划线的颜色
+                decorationThickness: 2.0,
+                // 可选,设置下划线的粗细
+                decorationStyle: TextDecorationStyle.solid,
+                onClick: onMemberAction,
               ).expanded(),
-
             ],
-          ),
+          ).marginOnly(top: 12),
 
-          //员工姓名
+          //员工电话
           Row(
             mainAxisSize: MainAxisSize.max,
             crossAxisAlignment: CrossAxisAlignment.center,
             children: [
               MyTextView(
-                "${"Staff Name".tr}:",
+                "${"Mobile".tr}:",
                 isFontRegular: true,
                 textColor: ColorConstants.textGrayAECAE5,
                 fontSize: 14,
               ),
 
-              //姓名
+              //电话文本
               MyTextView(
-                item.staffName ?? "-",
+                item.phone ?? "-",
                 isFontMedium: true,
-                textColor: ColorConstants.textYellowFFBB1B,
+                textColor: Colors.white,
                 fontSize: 14,
                 marginLeft: 5,
                 marginRight: 5,
-                textDecoration: TextDecoration.underline,
-                decorationColor: ColorConstants.textYellowFFBB1B,
-                // 可选,设置下划线的颜色
-                decorationThickness: 2.0,
-                // 可选,设置下划线的粗细
-                decorationStyle: TextDecorationStyle.solid,
-                onClick: onMemberAction,
               ).expanded(),
-
             ],
           ).marginOnly(top: 12),
 
-          //员工电话
+          //工作标题
           Row(
             mainAxisSize: MainAxisSize.max,
             crossAxisAlignment: CrossAxisAlignment.center,
             children: [
               MyTextView(
-                "${"Mobile".tr}:",
+                "${"Title".tr}:",
                 isFontRegular: true,
                 textColor: ColorConstants.textGrayAECAE5,
                 fontSize: 14,
               ),
 
-              //电话文本
+              //文本
               MyTextView(
-                "等待接口返回电话号码",
+                item.jobTitle ?? "-",
                 isFontMedium: true,
                 textColor: Colors.white,
                 fontSize: 14,
                 marginLeft: 5,
                 marginRight: 5,
               ).expanded(),
-
             ],
           ).marginOnly(top: 12),
 
@@ -137,14 +130,13 @@ class SecurityRegistrationItem extends StatelessWidget {
 
               //电话文本
               MyTextView(
-                "等待接口返回部门",
+                item.departmentName ?? "-",
                 isFontMedium: true,
                 textColor: Colors.white,
                 fontSize: 14,
                 marginLeft: 5,
                 marginRight: 5,
               ).expanded(),
-
             ],
           ).marginOnly(top: 12),
 
@@ -162,7 +154,7 @@ class SecurityRegistrationItem extends StatelessWidget {
 
               //时间
               MyTextView(
-                item.startTime ?? "-",
+                item.jobTime?.split(" ")[0] ?? "-",
                 marginLeft: 5,
                 isFontRegular: true,
                 textColor: Colors.white,
@@ -185,7 +177,7 @@ class SecurityRegistrationItem extends StatelessWidget {
 
               //时间
               MyTextView(
-                item.startTime ?? "-",
+                item.jobTime?.split(" ").sublist(1).join(" ") ?? "-",
                 marginLeft: 5,
                 isFontRegular: true,
                 textColor: Colors.white,
@@ -208,16 +200,15 @@ class SecurityRegistrationItem extends StatelessWidget {
 
               //时间
               MyTextView(
-                "等待接口返回的时间",
+                item.securityIn?.time ?? "-",
                 marginLeft: 5,
                 isFontRegular: true,
-                textColor: /* item.securityIn?.changed == 1 ? ColorConstants.textRedFF6262 :*/ Colors.white,
+                textColor: item.securityIn?.changed == 1 ? ColorConstants.textRedFF6262 : Colors.white,
                 fontSize: 14,
               ).expanded(),
             ],
           ).marginOnly(top: 12),
 
-
           // 门卫签出时间
           Row(
             mainAxisSize: MainAxisSize.max,
@@ -232,10 +223,10 @@ class SecurityRegistrationItem extends StatelessWidget {
 
               //时间
               MyTextView(
-                "等待接口返回的时间",
+                item.securityOut?.time ?? "-",
                 marginLeft: 5,
                 isFontRegular: true,
-                textColor: /*item.securityOut?.changed == 1 ? ColorConstants.textRedFF6262 : */Colors.white,
+                textColor: item.securityOut?.changed == 1 ? ColorConstants.textRedFF6262 : Colors.white,
                 fontSize: 14,
               ).expanded(),
             ],
@@ -255,7 +246,7 @@ class SecurityRegistrationItem extends StatelessWidget {
 
               //发布状态
               MyTextView(
-                "等待接口返回的时间",
+                item.appliedAt ?? "-",
                 marginLeft: 5,
                 isFontRegular: true,
                 textColor: Colors.white,
@@ -287,7 +278,7 @@ class SecurityRegistrationItem extends StatelessWidget {
                         ? ColorConstants.textRedFF6262
                         : "Revised" == item.statusShow || "Pending" == item.statusShow || "Approve" == item.statusShow
                             ? ColorConstants.textYellowFFBB1B
-                            : ColorConstants.textBlue06D9FF,  //默认蓝色
+                            : ColorConstants.textBlue06D9FF, //默认蓝色
                 fontSize: 14,
               ).expanded(),
             ],
@@ -316,10 +307,8 @@ class SecurityRegistrationItem extends StatelessWidget {
                   minHeight: 35,
                 ).marginOnly(left: 12),
               ),
-
             ],
           ).marginOnly(top: 15),
-
         ],
       ),
     );

+ 129 - 32
packages/cpt_uk/lib/modules/attendance/security_registration/security_registration_controller.dart

@@ -1,11 +1,16 @@
 import 'dart:typed_data';
 
 import 'package:domain/entity/response/attendance_entity.dart';
+import 'package:domain/entity/response/u_k_security_attendance_entity.dart';
+import 'package:domain/entity/response/u_k_security_attendance_option_entity.dart';
 import 'package:domain/repository/job_repository.dart';
+import 'package:domain/repository/uk_attendance_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';
@@ -16,9 +21,10 @@ import 'security_registration_state.dart';
 import 'widget/security_edit_dialog.dart';
 
 class SecurityRegistrationController extends GetxController with DioCancelableMixin {
-  final JobRepository _jobRepository = Get.find();
+  final UKAttendanceRepository _attendanceRepository = Get.find();
   final EAttendanceListState state = EAttendanceListState();
 
+  var _curPage = 1;
   var _needShowPlaceholder = true;
 
   //页面PlaceHolder的展示
@@ -34,16 +40,24 @@ class SecurityRegistrationController extends GetxController with DioCancelableMi
   // Refresh 控制器
   final EasyRefreshController refreshController = EasyRefreshController(
     controlFinishRefresh: true,
-    controlFinishLoad: false,
+    controlFinishLoad: true,
   );
 
   // Refresh 刷新事件
   Future onRefresh() async {
+    _curPage = 1;
+    fetchAttendanceList();
+  }
+
+  // Refresh 加载事件
+  Future loadMore() async {
+    _curPage++;
     fetchAttendanceList();
   }
 
   // 重试请求
   Future retryRequest() async {
+    _curPage = 1;
     _needShowPlaceholder = true;
     fetchAttendanceList();
   }
@@ -54,40 +68,73 @@ class SecurityRegistrationController extends GetxController with DioCancelableMi
       changeLoadingState(LoadState.State_Loading);
     }
 
-    //获取到数据
-    var result = await _jobRepository.fetchAttendanceList(
-      state.keyword,
-      DateTimeUtils.formatDate(state.selectedStartDate, format: "yyyy-MM-dd"),
-      DateTimeUtils.formatDate(state.selectedEndDate, format: "yyyy-MM-dd"),
-      cancelToken: cancelToken,
-    );
+    // 并发执行两个请求
+    var futures = [
+      _attendanceRepository.fetchSecurityAttendanceList(
+        startDate: DateTimeUtils.formatDate(state.selectedStartDate, format: "yyyy-MM-dd"),
+        endDate: DateTimeUtils.formatDate(state.selectedEndDate, format: "yyyy-MM-dd"),
+        keyword: state.selectedStaffName,
+        departmentId: state.selectedDepartmentId,
+        curPage: _curPage,
+        cancelToken: cancelToken,
+      ),
+      state.indexOptions == null
+          ? _attendanceRepository.fetchSecurityAttendanceOptions(
+              cancelToken: cancelToken,
+            )
+          : Future(() => HttpResult(isSuccess: true).convert(data: state.indexOptions!)),
+    ];
+
+    //拿到结果
+    var results = await Future.wait(futures);
+    var listResult = results[0] as HttpResult<UKSecurityAttendanceEntity>;
+    var optionResult = results[1] as HttpResult<UKSecurityAttendanceOptionEntity>;
+
+    //选项数据
+    if (state.indexOptions == null && optionResult.isSuccess) {
+      state.indexOptions = optionResult.data!;
+    }
 
-    //处理数据
-    if (result.isSuccess) {
-      handleList(result.data?.rows);
-      refreshController.finishRefresh(IndicatorResult.success);
+    // 处理数据
+    if (listResult.isSuccess) {
+      handleList(listResult.data?.rows);
     } else {
-      errorMessage = result.errorMsg;
+      errorMessage = listResult.errorMsg;
       changeLoadingState(LoadState.State_Error);
-      refreshController.finishRefresh(IndicatorResult.fail);
     }
 
-    //最后赋值
+    // 最后赋值
     _needShowPlaceholder = false;
   }
 
   // 处理数据与展示的逻辑
-  void handleList(List<AttendanceList>? list) {
+  void handleList(List<UKSecurityAttendanceRows>? list) {
     if (list != null && list.isNotEmpty) {
       //有数据,判断是刷新还是加载更多的数据
-      state.datas.clear();
-      state.datas.addAll(list);
-      //更新状态
-      changeLoadingState(LoadState.State_Success);
+      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 {
-      //展示无数据的布局
-      state.datas.clear();
-      changeLoadingState(LoadState.State_Empty);
+      if (_curPage == 1) {
+        //展示无数据的布局
+        state.datas.clear();
+        changeLoadingState(LoadState.State_Empty);
+        refreshController.finishRefresh();
+      } else {
+        //展示加载完成,没有更多数据了
+        refreshController.finishLoad(IndicatorResult.noMore);
+      }
     }
   }
 
@@ -105,12 +152,15 @@ class SecurityRegistrationController extends GetxController with DioCancelableMi
 
   /// 展示标题栏的 Filter 弹窗
   void showFilterDialog() {
+    if (state.indexOptions == null) return;
+
     DialogEngine.show(
       widget: JobListFilter(
         selectedStartDate: state.selectedStartDate,
         selectedEndDate: state.selectedEndDate,
         staffName: state.selectedStaffName,
         selectedDepartmentId: state.selectedDepartmentId,
+        departmentList: state.indexOptions?.departmentList,
         onFilterAction: (startDate, endDate, staffName, departmentId) {
           Log.d("startDate:$startDate endDate:$endDate staffName:$staffName departmentId:$departmentId");
 
@@ -129,23 +179,70 @@ class SecurityRegistrationController extends GetxController with DioCancelableMi
   }
 
   //查看UK员工的详情
-  void gotoStaffDetailPage(AttendanceList data) {
-    UKAppliedStaffDetailPage.startInstance(data.staffId.toString());
+  void gotoStaffDetailPage(UKSecurityAttendanceRows data) {
+    // UKAppliedStaffDetailPage.startInstance(data.staffName.toString());
   }
 
   /// 展示编辑的弹窗
-  void showEditDialog(AttendanceList data) {
+  void showEditDialog(UKSecurityAttendanceRows data) {
+    String? dateStr = data.jobTime?.split(" ")[0];
+    String? startStr = data.jobTime?.split(" ").sublist(1).join(" ").split(" ~ ")[0];
+    String? endStr = data.jobTime?.split(" ").sublist(1).join(" ").split(" ~ ")[1];
+
+    if (dateStr == null || startStr == null || endStr == null) return;
+
     DialogEngine.show(
       widget: SecurityEditDialog(
-        startTime: DateTimeUtils.getDateTime(data.startTime ?? ""),
-        endTime: DateTimeUtils.getDateTime(data.endTime ?? ""),
-        securityInTime: DateTimeUtils.getDateTime(data.securityIn ?? ""),
-        securityOutTime: DateTimeUtils.getDateTime(data.securityOut ?? ""),
+        startTime: DateTimeUtils.getDateTime("$dateStr $startStr"),
+        endTime: DateTimeUtils.getDateTime("$dateStr $endStr"),
+        securityInTime: DateTimeUtils.getDateTime(data.securityIn?.time == null ? "" : "$dateStr ${data.securityIn?.time}"),
+        securityOutTime: DateTimeUtils.getDateTime(data.securityOut?.time == null ? "" : "$dateStr ${data.securityOut?.time}"),
         staffName: data.staffName ?? "",
         confirmAction: (inTime, outTime) {
-          ToastEngine.show("编辑了 inTime:$inTime outTime:$outTime");
+          _submitAttendance(data.id, inTime, outTime);
         },
       ),
     );
   }
+
+  /// 请求接口提交门卫签到数据
+  void _submitAttendance(String? appliedId, DateTime? inTime, DateTime? outTime) async {
+    final result = await _attendanceRepository.submitSecurityAttendanceEdit(
+      appliedId: appliedId,
+      formView: "security",
+      securityIn: DateTimeUtils.formatDate(inTime),
+      securityOut: DateTimeUtils.formatDate(outTime),
+      cancelToken: cancelToken,
+    );
+
+    if (result.isSuccess) {
+      NotifyEngine.showSuccess("Successful".tr);
+
+      //把签到的时间赋值给列表
+       _updateItems(appliedId,DateTimeUtils.formatDate(inTime),DateTimeUtils.formatDate(outTime));
+
+    } else {
+      ToastEngine.show(result.errorMsg ?? "Network Load Error".tr);
+    }
+  }
+
+  // 遍历当前列表找到对应的Item更新签到签出的时间
+  void _updateItems(String? appliedId, String inTime, String outTime) {
+    UKSecurityAttendanceRows? element = state.datas.firstWhereOrNull(
+          (element) => element.id == appliedId,
+    );
+
+    if (element != null) {
+      element.securityIn ??= UKSecurityInOut();
+      element.securityIn?.time = inTime;
+      element.securityIn?.changed = 1;
+
+      element.securityOut ??= UKSecurityInOut();
+      element.securityOut?.time = outTime;
+      element.securityOut?.changed = 1;
+
+      update();
+    }
+  }
+
 }

+ 5 - 1
packages/cpt_uk/lib/modules/attendance/security_registration/security_registration_state.dart

@@ -1,4 +1,6 @@
 import 'package:domain/entity/response/attendance_entity.dart';
+import 'package:domain/entity/response/u_k_security_attendance_entity.dart';
+import 'package:domain/entity/response/u_k_security_attendance_option_entity.dart';
 import 'package:flutter/material.dart';
 
 
@@ -6,11 +8,13 @@ class EAttendanceListState {
 
   final TextEditingController searchController = TextEditingController();
   //页面的列表数据
-  List<AttendanceList> datas = [];
+  List<UKSecurityAttendanceRows> datas = [];
   String keyword = "";
   DateTime? selectedStartDate = DateTime.now();
   DateTime? selectedEndDate = DateTime.now();
   String? selectedStaffName;
   String? selectedDepartmentId;
 
+
+  UKSecurityAttendanceOptionEntity? indexOptions;
 }

+ 29 - 27
packages/cpt_uk/lib/modules/attendance/security_registration/widget/job_list_filter.dart

@@ -1,5 +1,6 @@
 import 'dart:ui';
 import 'package:cs_resources/generated/assets.dart';
+import 'package:domain/entity/response/index_option_entity.dart';
 import 'package:domain/entity/response/job_list_index_entity.dart';
 import 'package:flutter/cupertino.dart';
 import 'package:flutter/material.dart';
@@ -29,6 +30,7 @@ class JobListFilter extends StatefulWidget {
   DateTime? selectedEndDate;
   String? staffName;
   String? selectedDepartmentId;
+  List<IndexOptionEntity>? departmentList;  //部门筛选的数据
 
   JobListFilter({
 
@@ -36,6 +38,7 @@ class JobListFilter extends StatefulWidget {
     required this.selectedEndDate,
     required this.staffName,
     required this.selectedDepartmentId,
+    required this.departmentList,
     this.onFilterAction,
   });
 
@@ -149,10 +152,9 @@ class _JobListFilterState extends State<JobListFilter> {
                   mainAxisAlignment: MainAxisAlignment.start,
                   children: [
                     MyTextView(
-                      "等待接口数据的部门",
-                      // selectedDepartmentId == null || selectedDepartmentId == "0"
-                      //     ? ""
-                      //     : widget.optionResult.departmentList!.firstWhere((element) => element.value.toString() == selectedDepartmentId).txt!,
+                      selectedDepartmentId == null || selectedDepartmentId == "0"
+                          ? ""
+                          : widget.departmentList!.firstWhere((element) => element.value.toString() == selectedDepartmentId).txt!,
                       hint: "Choose Outlet".tr,
                       textHintColor: ColorConstants.textBlackHint,
                       fontSize: 14,
@@ -163,7 +165,7 @@ class _JobListFilterState extends State<JobListFilter> {
                   ],
                 ),
               ).onTap(() {
-                // pickerOutlet();
+                pickerOutlet();
               }),
 
               //开始时间
@@ -329,28 +331,28 @@ class _JobListFilterState extends State<JobListFilter> {
   }
 
   /// 筛选部门
-  // 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 pickerOutlet() {
+    int selectedDepartmentIndex;
+    if (selectedDepartmentId == null) {
+      selectedDepartmentIndex = 0;
+    } else {
+      selectedDepartmentIndex = widget.departmentList!.indexWhere((department) => department.value.toString() == selectedDepartmentId);
+    }
+
+    if (selectedDepartmentIndex < 0) {
+      selectedDepartmentIndex = 0;
+    }
+
+    OptionPickerUtil.showCupertinoOptionPicker(
+      items: widget.departmentList!.map((e) => e.txt!).toList(growable: false),
+      initialSelectIndex: selectedDepartmentIndex,
+      onPickerChanged: (_, index) {
+        setState(() {
+          selectedDepartmentId = widget.departmentList![index].value!.toString();
+        });
+      },
+    );
+  }
 
 
 }

+ 4 - 4
packages/cpt_uk/lib/modules/attendance/security_registration/widget/security_edit_dialog.dart

@@ -106,7 +106,7 @@ class _AppliedButchModifyState extends State<SecurityEditDialog> {
                   mainAxisAlignment: MainAxisAlignment.start,
                   children: [
                     MyTextView(
-                      startTime == null ? "2025-03-11 12:00:00" : DateTimeUtils.formatDate(startTime),
+                      startTime == null ? "-" : DateTimeUtils.formatDate(startTime),
                       fontSize: 14,
                       textHintColor: ColorConstants.textBlackHint,
                       isFontRegular: true,
@@ -144,7 +144,7 @@ class _AppliedButchModifyState extends State<SecurityEditDialog> {
                   mainAxisAlignment: MainAxisAlignment.start,
                   children: [
                     MyTextView(
-                      securityInTime == null ? "2025-03-11 12:00:00" : DateTimeUtils.formatDate(securityInTime),
+                      securityInTime == null ? "-" : DateTimeUtils.formatDate(securityInTime),
                       fontSize: 14,
                       textHintColor: ColorConstants.textBlackHint,
                       isFontRegular: true,
@@ -185,7 +185,7 @@ class _AppliedButchModifyState extends State<SecurityEditDialog> {
                   mainAxisAlignment: MainAxisAlignment.start,
                   children: [
                     MyTextView(
-                      endTime == null ? "2025-03-11 12:00:00" : DateTimeUtils.formatDate(endTime),
+                      endTime == null ? "-" : DateTimeUtils.formatDate(endTime),
                       fontSize: 14,
                       textHintColor: ColorConstants.textBlackHint,
                       isFontRegular: true,
@@ -223,7 +223,7 @@ class _AppliedButchModifyState extends State<SecurityEditDialog> {
                   mainAxisAlignment: MainAxisAlignment.start,
                   children: [
                     MyTextView(
-                      securityOutTime == null ? "2025-03-11 12:00:00" : DateTimeUtils.formatDate(securityOutTime),
+                      securityOutTime == null ? "-" : DateTimeUtils.formatDate(securityOutTime),
                       fontSize: 14,
                       textHintColor: ColorConstants.textBlackHint,
                       isFontRegular: true,

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

@@ -278,6 +278,17 @@ class ApiConstants {
   //Revise 的操作日志
   static const apiReviseLogListSG = "/index.php/api/v1/hotel/revise/logs";
 
+  // =========================== 英国特有的一些接口 ↓=========================================
+
+  //门卫的考勤选项
+  static const apiSecurityAttendanceOptionUK = "/index.php/api/v1/hotel/security/index";
+
+  //门卫的考勤列表
+  static const apiSecurityAttendanceListUK = "/index.php/api/v1/hotel/security/table";
+
+  //门卫的考勤编辑
+  static const apiSecurityAttendanceEditUK = "/index.php/api/v1/hotel/applied/security-submit";
+
   // =========================== 报表与其他 ↓=========================================
 
   // 设备列表

+ 77 - 0
packages/cs_domain/lib/entity/response/u_k_security_attendance_entity.dart

@@ -0,0 +1,77 @@
+import 'package:domain/generated/json/base/json_field.dart';
+import 'package:domain/generated/json/u_k_security_attendance_entity.g.dart';
+import 'dart:convert';
+export 'package:domain/generated/json/u_k_security_attendance_entity.g.dart';
+
+@JsonSerializable()
+class UKSecurityAttendanceEntity {
+	int total = 0;
+	List<UKSecurityAttendanceRows> rows = [];
+
+	UKSecurityAttendanceEntity();
+
+	factory UKSecurityAttendanceEntity.fromJson(Map<String, dynamic> json) => $UKSecurityAttendanceEntityFromJson(json);
+
+	Map<String, dynamic> toJson() => $UKSecurityAttendanceEntityToJson(this);
+
+	@override
+	String toString() {
+		return jsonEncode(this);
+	}
+}
+
+@JsonSerializable()
+class UKSecurityAttendanceRows {
+	String? id;
+	@JSONField(name: "staff_name")
+	String? staffName;
+	String? phone;
+	@JSONField(name: "job_title")
+	String? jobTitle;
+	@JSONField(name: "department_name")
+	String? departmentName;
+	@JSONField(name: "job_time")
+	String? jobTime;
+	@JSONField(name: "applied_at")
+	String? appliedAt;
+	int status = 0;
+	@JSONField(name: "status_show")
+	String? statusShow;
+	@JSONField(name: "security_in")
+	UKSecurityInOut? securityIn;
+	@JSONField(name: "security_out")
+	UKSecurityInOut? securityOut;
+	@JSONField(name: "s_in")
+	int sIn = 0;
+	@JSONField(name: "s_out")
+	int sOut = 0;
+
+	UKSecurityAttendanceRows();
+
+	factory UKSecurityAttendanceRows.fromJson(Map<String, dynamic> json) => $UKSecurityAttendanceRowsFromJson(json);
+
+	Map<String, dynamic> toJson() => $UKSecurityAttendanceRowsToJson(this);
+
+	@override
+	String toString() {
+		return jsonEncode(this);
+	}
+}
+
+@JsonSerializable()
+class UKSecurityInOut {
+	String? time;
+	String? image;
+	int changed = 0;
+
+	UKSecurityInOut();
+
+	factory UKSecurityInOut.fromJson(Map<String, dynamic> json) => $UKSecurityInOutFromJson(json);
+
+	Map<String, dynamic> toJson() => $UKSecurityInOutToJson(this);
+
+	@override
+	String toString() {
+		return jsonEncode(this);
+	}
+}

+ 42 - 0
packages/cs_domain/lib/entity/response/u_k_security_attendance_option_entity.dart

@@ -0,0 +1,42 @@
+import 'package:domain/entity/response/index_option_entity.dart';
+import 'package:domain/generated/json/base/json_field.dart';
+import 'package:domain/generated/json/u_k_security_attendance_option_entity.g.dart';
+import 'dart:convert';
+export 'package:domain/generated/json/u_k_security_attendance_option_entity.g.dart';
+
+@JsonSerializable()
+class UKSecurityAttendanceOptionEntity {
+	@JSONField(name: "department_list")
+	List<IndexOptionEntity>? departmentList = [];
+	UKSecurityAttendanceOptionFilter? filter;
+
+	UKSecurityAttendanceOptionEntity();
+
+	factory UKSecurityAttendanceOptionEntity.fromJson(Map<String, dynamic> json) => $UKSecurityAttendanceOptionEntityFromJson(json);
+
+	Map<String, dynamic> toJson() => $UKSecurityAttendanceOptionEntityToJson(this);
+
+	@override
+	String toString() {
+		return jsonEncode(this);
+	}
+}
+
+@JsonSerializable()
+class UKSecurityAttendanceOptionFilter {
+	@JSONField(name: "start_date")
+	String? startDate;
+	@JSONField(name: "end_date")
+	String? endDate;
+
+	UKSecurityAttendanceOptionFilter();
+
+	factory UKSecurityAttendanceOptionFilter.fromJson(Map<String, dynamic> json) => $UKSecurityAttendanceOptionFilterFromJson(json);
+
+	Map<String, dynamic> toJson() => $UKSecurityAttendanceOptionFilterToJson(this);
+
+	@override
+	String toString() {
+		return jsonEncode(this);
+	}
+}

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

@@ -78,6 +78,8 @@ import 'package:domain/entity/response/staff_remark_history_entity.dart';
 import 'package:domain/entity/response/staff_report_v_n_entity.dart';
 import 'package:domain/entity/response/staff_request_report_entity.dart';
 import 'package:domain/entity/response/staff_review_history_s_g_entity.dart';
+import 'package:domain/entity/response/u_k_security_attendance_entity.dart';
+import 'package:domain/entity/response/u_k_security_attendance_option_entity.dart';
 import 'package:domain/entity/server_time.dart';
 
 JsonConvert jsonConvert = JsonConvert();
@@ -673,6 +675,21 @@ class JsonConvert {
     if (<StaffReviewHistorySGReviews>[] is M) {
       return data.map<StaffReviewHistorySGReviews>((Map<String, dynamic> e) => StaffReviewHistorySGReviews.fromJson(e)).toList() as M;
     }
+    if (<UKSecurityAttendanceEntity>[] is M) {
+      return data.map<UKSecurityAttendanceEntity>((Map<String, dynamic> e) => UKSecurityAttendanceEntity.fromJson(e)).toList() as M;
+    }
+    if (<UKSecurityAttendanceRows>[] is M) {
+      return data.map<UKSecurityAttendanceRows>((Map<String, dynamic> e) => UKSecurityAttendanceRows.fromJson(e)).toList() as M;
+    }
+    if (<UKSecurityInOut>[] is M) {
+      return data.map<UKSecurityInOut>((Map<String, dynamic> e) => UKSecurityInOut.fromJson(e)).toList() as M;
+    }
+    if (<UKSecurityAttendanceOptionEntity>[] is M) {
+      return data.map<UKSecurityAttendanceOptionEntity>((Map<String, dynamic> e) => UKSecurityAttendanceOptionEntity.fromJson(e)).toList() as M;
+    }
+    if (<UKSecurityAttendanceOptionFilter>[] is M) {
+      return data.map<UKSecurityAttendanceOptionFilter>((Map<String, dynamic> e) => UKSecurityAttendanceOptionFilter.fromJson(e)).toList() as M;
+    }
     if (<ServerTime>[] is M) {
       return data.map<ServerTime>((Map<String, dynamic> e) => ServerTime.fromJson(e)).toList() as M;
     }
@@ -850,6 +867,11 @@ class JsonConvertClassCollection {
     (StaffRequestReportEntity).toString(): StaffRequestReportEntity.fromJson,
     (StaffReviewHistorySGEntity).toString(): StaffReviewHistorySGEntity.fromJson,
     (StaffReviewHistorySGReviews).toString(): StaffReviewHistorySGReviews.fromJson,
+    (UKSecurityAttendanceEntity).toString(): UKSecurityAttendanceEntity.fromJson,
+    (UKSecurityAttendanceRows).toString(): UKSecurityAttendanceRows.fromJson,
+    (UKSecurityInOut).toString(): UKSecurityInOut.fromJson,
+    (UKSecurityAttendanceOptionEntity).toString(): UKSecurityAttendanceOptionEntity.fromJson,
+    (UKSecurityAttendanceOptionFilter).toString(): UKSecurityAttendanceOptionFilter.fromJson,
     (ServerTime).toString(): ServerTime.fromJson,
   };
 

+ 180 - 0
packages/cs_domain/lib/generated/json/u_k_security_attendance_entity.g.dart

@@ -0,0 +1,180 @@
+import 'package:domain/generated/json/base/json_convert_content.dart';
+import 'package:domain/entity/response/u_k_security_attendance_entity.dart';
+
+UKSecurityAttendanceEntity $UKSecurityAttendanceEntityFromJson(Map<String, dynamic> json) {
+  final UKSecurityAttendanceEntity uKSecurityAttendanceEntity = UKSecurityAttendanceEntity();
+  final int? total = jsonConvert.convert<int>(json['total']);
+  if (total != null) {
+    uKSecurityAttendanceEntity.total = total;
+  }
+  final List<UKSecurityAttendanceRows>? rows = (json['rows'] as List<dynamic>?)?.map(
+          (e) => jsonConvert.convert<UKSecurityAttendanceRows>(e) as UKSecurityAttendanceRows).toList();
+  if (rows != null) {
+    uKSecurityAttendanceEntity.rows = rows;
+  }
+  return uKSecurityAttendanceEntity;
+}
+
+Map<String, dynamic> $UKSecurityAttendanceEntityToJson(UKSecurityAttendanceEntity entity) {
+  final Map<String, dynamic> data = <String, dynamic>{};
+  data['total'] = entity.total;
+  data['rows'] = entity.rows.map((v) => v.toJson()).toList();
+  return data;
+}
+
+extension UKSecurityAttendanceEntityExtension on UKSecurityAttendanceEntity {
+  UKSecurityAttendanceEntity copyWith({
+    int? total,
+    List<UKSecurityAttendanceRows>? rows,
+  }) {
+    return UKSecurityAttendanceEntity()
+      ..total = total ?? this.total
+      ..rows = rows ?? this.rows;
+  }
+}
+
+UKSecurityAttendanceRows $UKSecurityAttendanceRowsFromJson(Map<String, dynamic> json) {
+  final UKSecurityAttendanceRows uKSecurityAttendanceRows = UKSecurityAttendanceRows();
+  final String? id = jsonConvert.convert<String>(json['id']);
+  if (id != null) {
+    uKSecurityAttendanceRows.id = id;
+  }
+  final String? staffName = jsonConvert.convert<String>(json['staff_name']);
+  if (staffName != null) {
+    uKSecurityAttendanceRows.staffName = staffName;
+  }
+  final String? phone = jsonConvert.convert<String>(json['phone']);
+  if (phone != null) {
+    uKSecurityAttendanceRows.phone = phone;
+  }
+  final String? jobTitle = jsonConvert.convert<String>(json['job_title']);
+  if (jobTitle != null) {
+    uKSecurityAttendanceRows.jobTitle = jobTitle;
+  }
+  final String? departmentName = jsonConvert.convert<String>(json['department_name']);
+  if (departmentName != null) {
+    uKSecurityAttendanceRows.departmentName = departmentName;
+  }
+  final String? jobTime = jsonConvert.convert<String>(json['job_time']);
+  if (jobTime != null) {
+    uKSecurityAttendanceRows.jobTime = jobTime;
+  }
+  final String? appliedAt = jsonConvert.convert<String>(json['applied_at']);
+  if (appliedAt != null) {
+    uKSecurityAttendanceRows.appliedAt = appliedAt;
+  }
+  final int? status = jsonConvert.convert<int>(json['status']);
+  if (status != null) {
+    uKSecurityAttendanceRows.status = status;
+  }
+  final String? statusShow = jsonConvert.convert<String>(json['status_show']);
+  if (statusShow != null) {
+    uKSecurityAttendanceRows.statusShow = statusShow;
+  }
+  final UKSecurityInOut? securityIn = jsonConvert.convert<UKSecurityInOut>(json['security_in']);
+  if (securityIn != null) {
+    uKSecurityAttendanceRows.securityIn = securityIn;
+  }
+  final UKSecurityInOut? securityOut = jsonConvert.convert<UKSecurityInOut>(json['security_out']);
+  if (securityOut != null) {
+    uKSecurityAttendanceRows.securityOut = securityOut;
+  }
+  final int? sIn = jsonConvert.convert<int>(json['s_in']);
+  if (sIn != null) {
+    uKSecurityAttendanceRows.sIn = sIn;
+  }
+  final int? sOut = jsonConvert.convert<int>(json['s_out']);
+  if (sOut != null) {
+    uKSecurityAttendanceRows.sOut = sOut;
+  }
+  return uKSecurityAttendanceRows;
+}
+
+Map<String, dynamic> $UKSecurityAttendanceRowsToJson(UKSecurityAttendanceRows entity) {
+  final Map<String, dynamic> data = <String, dynamic>{};
+  data['id'] = entity.id;
+  data['staff_name'] = entity.staffName;
+  data['phone'] = entity.phone;
+  data['job_title'] = entity.jobTitle;
+  data['department_name'] = entity.departmentName;
+  data['job_time'] = entity.jobTime;
+  data['applied_at'] = entity.appliedAt;
+  data['status'] = entity.status;
+  data['status_show'] = entity.statusShow;
+  data['security_in'] = entity.securityIn?.toJson();
+  data['security_out'] = entity.securityOut?.toJson();
+  data['s_in'] = entity.sIn;
+  data['s_out'] = entity.sOut;
+  return data;
+}
+
+extension UKSecurityAttendanceRowsExtension on UKSecurityAttendanceRows {
+  UKSecurityAttendanceRows copyWith({
+    String? id,
+    String? staffName,
+    String? phone,
+    String? jobTitle,
+    String? departmentName,
+    String? jobTime,
+    String? appliedAt,
+    int? status,
+    String? statusShow,
+    UKSecurityInOut? securityIn,
+    UKSecurityInOut? securityOut,
+    int? sIn,
+    int? sOut,
+  }) {
+    return UKSecurityAttendanceRows()
+      ..id = id ?? this.id
+      ..staffName = staffName ?? this.staffName
+      ..phone = phone ?? this.phone
+      ..jobTitle = jobTitle ?? this.jobTitle
+      ..departmentName = departmentName ?? this.departmentName
+      ..jobTime = jobTime ?? this.jobTime
+      ..appliedAt = appliedAt ?? this.appliedAt
+      ..status = status ?? this.status
+      ..statusShow = statusShow ?? this.statusShow
+      ..securityIn = securityIn ?? this.securityIn
+      ..securityOut = securityOut ?? this.securityOut
+      ..sIn = sIn ?? this.sIn
+      ..sOut = sOut ?? this.sOut;
+  }
+}
+
+UKSecurityInOut $UKSecurityInOutFromJson(Map<String, dynamic> json) {
+  final UKSecurityInOut uKSecurityInOut = UKSecurityInOut();
+  final String? time = jsonConvert.convert<String>(json['time']);
+  if (time != null) {
+    uKSecurityInOut.time = time;
+  }
+  final String? image = jsonConvert.convert<String>(json['image']);
+  if (image != null) {
+    uKSecurityInOut.image = image;
+  }
+  final int? changed = jsonConvert.convert<int>(json['changed']);
+  if (changed != null) {
+    uKSecurityInOut.changed = changed;
+  }
+  return uKSecurityInOut;
+}
+
+Map<String, dynamic> $UKSecurityInOutToJson(UKSecurityInOut entity) {
+  final Map<String, dynamic> data = <String, dynamic>{};
+  data['time'] = entity.time;
+  data['image'] = entity.image;
+  data['changed'] = entity.changed;
+  return data;
+}
+
+extension UKSecurityInOutExtension on UKSecurityInOut {
+  UKSecurityInOut copyWith({
+    String? time,
+    String? image,
+    int? changed,
+  }) {
+    return UKSecurityInOut()
+      ..time = time ?? this.time
+      ..image = image ?? this.image
+      ..changed = changed ?? this.changed;
+  }
+}

+ 67 - 0
packages/cs_domain/lib/generated/json/u_k_security_attendance_option_entity.g.dart

@@ -0,0 +1,67 @@
+import 'package:domain/generated/json/base/json_convert_content.dart';
+import 'package:domain/entity/response/u_k_security_attendance_option_entity.dart';
+import 'package:domain/entity/response/index_option_entity.dart';
+
+
+UKSecurityAttendanceOptionEntity $UKSecurityAttendanceOptionEntityFromJson(Map<String, dynamic> json) {
+  final UKSecurityAttendanceOptionEntity uKSecurityAttendanceOptionEntity = UKSecurityAttendanceOptionEntity();
+  final List<IndexOptionEntity>? departmentList = (json['department_list'] as List<dynamic>?)?.map(
+          (e) => jsonConvert.convert<IndexOptionEntity>(e) as IndexOptionEntity).toList();
+  if (departmentList != null) {
+    uKSecurityAttendanceOptionEntity.departmentList = departmentList;
+  }
+  final UKSecurityAttendanceOptionFilter? filter = jsonConvert.convert<UKSecurityAttendanceOptionFilter>(json['filter']);
+  if (filter != null) {
+    uKSecurityAttendanceOptionEntity.filter = filter;
+  }
+  return uKSecurityAttendanceOptionEntity;
+}
+
+Map<String, dynamic> $UKSecurityAttendanceOptionEntityToJson(UKSecurityAttendanceOptionEntity entity) {
+  final Map<String, dynamic> data = <String, dynamic>{};
+  data['department_list'] = entity.departmentList?.map((v) => v.toJson()).toList();
+  data['filter'] = entity.filter?.toJson();
+  return data;
+}
+
+extension UKSecurityAttendanceOptionEntityExtension on UKSecurityAttendanceOptionEntity {
+  UKSecurityAttendanceOptionEntity copyWith({
+    List<IndexOptionEntity>? departmentList,
+    UKSecurityAttendanceOptionFilter? filter,
+  }) {
+    return UKSecurityAttendanceOptionEntity()
+      ..departmentList = departmentList ?? this.departmentList
+      ..filter = filter ?? this.filter;
+  }
+}
+
+UKSecurityAttendanceOptionFilter $UKSecurityAttendanceOptionFilterFromJson(Map<String, dynamic> json) {
+  final UKSecurityAttendanceOptionFilter uKSecurityAttendanceOptionFilter = UKSecurityAttendanceOptionFilter();
+  final String? startDate = jsonConvert.convert<String>(json['start_date']);
+  if (startDate != null) {
+    uKSecurityAttendanceOptionFilter.startDate = startDate;
+  }
+  final String? endDate = jsonConvert.convert<String>(json['end_date']);
+  if (endDate != null) {
+    uKSecurityAttendanceOptionFilter.endDate = endDate;
+  }
+  return uKSecurityAttendanceOptionFilter;
+}
+
+Map<String, dynamic> $UKSecurityAttendanceOptionFilterToJson(UKSecurityAttendanceOptionFilter entity) {
+  final Map<String, dynamic> data = <String, dynamic>{};
+  data['start_date'] = entity.startDate;
+  data['end_date'] = entity.endDate;
+  return data;
+}
+
+extension UKSecurityAttendanceOptionFilterExtension on UKSecurityAttendanceOptionFilter {
+  UKSecurityAttendanceOptionFilter copyWith({
+    String? startDate,
+    String? endDate,
+  }) {
+    return UKSecurityAttendanceOptionFilter()
+      ..startDate = startDate ?? this.startDate
+      ..endDate = endDate ?? this.endDate;
+  }
+}

+ 99 - 1
packages/cs_domain/lib/repository/uk_attendance_repository.dart

@@ -1,5 +1,12 @@
+import 'package:domain/entity/response/u_k_security_attendance_entity.dart';
+import 'package:domain/entity/response/u_k_security_attendance_option_entity.dart';
 import 'package:get/get.dart';
 import 'package:plugin_platform/http/http_provider.dart';
+import 'package:plugin_platform/http/http_result.dart';
+import 'package:plugin_platform/platform_export.dart';
+import 'package:shared/utils/util.dart';
+
+import '../constants/api_constants.dart';
 
 /// UK设备与考勤相关的数据仓库
 class UKAttendanceRepository extends GetxService {
@@ -7,4 +14,95 @@ class UKAttendanceRepository extends GetxService {
 
   UKAttendanceRepository({required this.httpProvider});
 
-}
+  /// 获取当前门卫的考勤筛选选项
+  Future<HttpResult<UKSecurityAttendanceOptionEntity>> fetchSecurityAttendanceOptions({
+    CancelToken? cancelToken,
+  }) async {
+    final result = await httpProvider.requestNetResult(
+      ApiConstants.apiSecurityAttendanceOptionUK,
+      cancelToken: cancelToken,
+    );
+
+    //根据返回的结果,封装原始数据为Bean/Entity对象
+    if (result.isSuccess) {
+      final json = result.getDataJson();
+      var data = UKSecurityAttendanceOptionEntity.fromJson(json!);
+      return result.convert<UKSecurityAttendanceOptionEntity>(data: data);
+    }
+    return result.convert();
+  }
+
+  /// 获取当前门卫的考勤成员列表
+  Future<HttpResult<UKSecurityAttendanceEntity>> fetchSecurityAttendanceList({
+    String? keyword,
+    String? startDate,
+    String? endDate,
+    String? departmentId,
+    int curPage = 1,
+    int pageSize = 10,
+    CancelToken? cancelToken,
+  }) async {
+    Map<String, String> params = {};
+    params["cur_page"] = curPage.toString();
+    params["page_size"] = pageSize.toString();
+
+    if (!Utils.isEmpty(keyword)) {
+      params["staff_name"] = keyword!;
+    }
+    if (!Utils.isEmpty(departmentId)) {
+      params["co_department_id"] = departmentId!;
+    }
+    if (!Utils.isEmpty(startDate)) {
+      params["start_date"] = startDate!;
+    }
+    if (!Utils.isEmpty(endDate)) {
+      params["end_date"] = endDate!;
+    }
+
+    final result = await httpProvider.requestNetResult(
+      ApiConstants.apiSecurityAttendanceListUK,
+      params: params,
+      cancelToken: cancelToken,
+    );
+
+    if (result.isSuccess) {
+      final json = result.getDataJson();
+      var data = UKSecurityAttendanceEntity.fromJson(json!);
+      return result.convert<UKSecurityAttendanceEntity>(data: data);
+    }
+    return result.convert();
+  }
+
+  /// 门卫的考勤的编辑提交
+  Future<HttpResult> submitSecurityAttendanceEdit({
+    required String? appliedId,
+    required String? formView,
+    required String? securityIn,
+    required String? securityOut,
+    String? reason,
+    CancelToken? cancelToken,
+  }) async {
+    //参数
+    Map<String, String> params = {};
+    params['applied_id'] = appliedId ?? "";
+    params['from_view'] = formView ?? "";
+    params['security_in'] = securityIn ?? "";
+    params['security_out'] = securityOut ?? "";
+
+    final result = await httpProvider.requestNetResult(
+      ApiConstants.apiSecurityAttendanceEditUK,
+      method: HttpMethod.POST,
+      params: params,
+      networkDebounce: true,
+      isShowLoadingDialog: true,
+      cancelToken: cancelToken,
+    );
+
+    //根据返回的结果,封装原始数据为Bean/Entity对象
+    if (result.isSuccess) {
+      //重新赋值data或list
+      return result.convert();
+    }
+    return result.convert();
+  }
+}

+ 2 - 3
packages/cs_resources/lib/local/theme/theme_config.dart

@@ -148,9 +148,8 @@ class ThemeConfig {
       statusBarBrightness: Brightness.dark,
       statusBarIconBrightness: Brightness.light,
 
-      systemNavigationBarColor: Colors.transparent, // 保持透明
-      systemNavigationBarIconBrightness: Brightness.light, // 强制浅色图标(白色手势条)
-      systemNavigationBarContrastEnforced: false,   // 允许内容延伸到导航栏
+      systemNavigationBarColor: Colors.white,
+      systemNavigationBarIconBrightness: Brightness.dark,
     );
   }