From 08ef63eb44102f05c21e5370fd096a7f0cfee20c Mon Sep 17 00:00:00 2001
From: 无关风月 <443237572@qq.com>
Date: 星期五, 27 二月 2026 10:05:03 +0800
Subject: [PATCH] Merge remote-tracking branch 'origin/master'

---
 xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/service/impl/XpClockInServiceImpl.java |  230 ++++++++++++++++++++++++++++++++++++++++++++++++++++----
 1 files changed, 211 insertions(+), 19 deletions(-)

diff --git a/xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/service/impl/XpClockInServiceImpl.java b/xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/service/impl/XpClockInServiceImpl.java
index 517f923..c0a1e41 100644
--- a/xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/service/impl/XpClockInServiceImpl.java
+++ b/xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/service/impl/XpClockInServiceImpl.java
@@ -2,18 +2,28 @@
 
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
-import com.xiaopeng.api.model.maintenance.XpCheckLocation;
+import com.xiaopeng.api.feignClient.account.XpOperationUserClient;
+import com.xiaopeng.api.model.account.XpOperationsRole;import com.xiaopeng.api.model.account.XpOperationsUser;import com.xiaopeng.api.model.maintenance.XpCheckLocation;
 import com.xiaopeng.api.model.maintenance.XpClockIn;
 import com.xiaopeng.api.model.maintenance.XpShift;
+import com.xiaopeng.api.vo.account.XpOperationsUserVO;
+import com.xiaopeng.api.vo.account.XpOperationsUserWithRoleVO;import com.xiaopeng.common.core.constant.Constants;
 import com.xiaopeng.common.core.domain.R;
 import com.xiaopeng.common.core.utils.DateUtils;
 import com.xiaopeng.common.core.utils.GeodesyUtil;
+import com.xiaopeng.common.core.utils.StringUtils;
+import com.xiaopeng.common.core.utils.poi.ExcelUtil;
+import com.xiaopeng.common.core.web.page.PageInfo;
 import com.xiaopeng.maintenance.dto.ClockDTO;
+import com.xiaopeng.maintenance.dto.ClockInStatisticsDetailsDto;
+import com.xiaopeng.maintenance.dto.ClockInStatisticsDto;
 import com.xiaopeng.maintenance.dto.VerifyRangeDTO;
 import com.xiaopeng.maintenance.mapper.XpCheckLocationMapper;
 import com.xiaopeng.maintenance.mapper.XpClockInMapper;
 import com.xiaopeng.maintenance.mapper.XpShiftMapper;
 import com.xiaopeng.maintenance.service.IXpClockInService;
+import com.xiaopeng.maintenance.vo.ClockInStatisticsDetailsVo;
+import com.xiaopeng.maintenance.vo.ClockInStatisticsVo;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
@@ -21,15 +31,17 @@
 import java.math.BigDecimal;
 import java.time.LocalDate;
 import java.time.LocalDateTime;
-import java.util.List;
-import java.util.Map;
-import lombok.extern.slf4j.Slf4j;
-import java.util.Objects;
+import java.util.*;
 
+import lombok.extern.slf4j.Slf4j;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletResponse;
 import java.time.LocalDate;
 import java.time.LocalDateTime;
 import java.time.LocalTime;
 import java.util.List;
+import java.util.stream.Collectors;
 
 /**
  * <p>
@@ -43,24 +55,31 @@
 @Service
 public class XpClockInServiceImpl extends ServiceImpl<XpClockInMapper, XpClockIn> implements IXpClockInService {
 
-    @Autowired
+    @Resource
     private XpCheckLocationMapper xpCheckLocationMapper;
-    @Autowired
+    @Resource
     private XpShiftMapper xpShiftMapper;
-    @Autowired
+    @Resource
     private XpClockInMapper xpClockInMapper;
+
+    @Resource
+    private XpOperationUserClient xpOperationUserClient;
+
+
+
+
 
     @Override
     public Boolean verifyRange(VerifyRangeDTO dto) {
 
         XpCheckLocation xpCheckLocation = xpCheckLocationMapper.selectById(dto.getLocationId());
 
-        Map<String, Double> distance = GeodesyUtil.getDistance(dto.getUserLon()+","+dto.getUserLat(), xpCheckLocation.getLocationLon()+","+xpCheckLocation.getLocationLat());
+        Map<String, Double> distance = GeodesyUtil.getDistance(dto.getUserLon() + "," + dto.getUserLat(), xpCheckLocation.getLocationLon() + "," + xpCheckLocation.getLocationLat());
         if (null != distance) {
             Double distance1 = distance.get("WGS84");
-            if (BigDecimal.valueOf(distance1).compareTo(xpCheckLocation.getLocationRange())>0) {
+            if (BigDecimal.valueOf(distance1).compareTo(xpCheckLocation.getLocationRange()) > 0) {
                 return false;
-            }else {
+            } else {
                 return true;
             }
         } else {
@@ -74,13 +93,13 @@
 
         XpCheckLocation xpCheckLocation = xpCheckLocationMapper.selectById(dto.getLocationId());
 
-        Map<String, Double> distance = GeodesyUtil.getDistance(dto.getUserLon()+","+dto.getUserLat(), xpCheckLocation.getLocationLon()+","+xpCheckLocation.getLocationLat());
+        Map<String, Double> distance = GeodesyUtil.getDistance(dto.getUserLon() + "," + dto.getUserLat(), xpCheckLocation.getLocationLon() + "," + xpCheckLocation.getLocationLat());
         if (null != distance) {
             Double distance1 = distance.get("WGS84");
             if (BigDecimal.valueOf(distance1).compareTo(xpCheckLocation.getLocationRange()) > 0) {
                 return R.fail("不在打卡范围内");
             }
-        }else {
+        } else {
             return R.fail("打卡失败");
         }
 
@@ -102,7 +121,7 @@
         xpClockIn.setClockInAddress(dto.getClockInAddress());
         if (xpClockIn.getClockInTime().isAfter(startLocalDateTime)) {
             xpClockIn.setClockInResult(2);
-        }else {
+        } else {
             xpClockIn.setClockInResult(1);
         }
         this.save(xpClockIn);
@@ -113,13 +132,13 @@
     public R<String> clockOut(ClockDTO dto) {
 
         XpCheckLocation xpCheckLocation = xpCheckLocationMapper.selectById(dto.getLocationId());
-        Map<String, Double> distance = GeodesyUtil.getDistance(dto.getUserLon()+","+dto.getUserLat(), xpCheckLocation.getLocationLon()+","+xpCheckLocation.getLocationLat());
+        Map<String, Double> distance = GeodesyUtil.getDistance(dto.getUserLon() + "," + dto.getUserLat(), xpCheckLocation.getLocationLon() + "," + xpCheckLocation.getLocationLat());
         if (null != distance) {
             Double distance1 = distance.get("WGS84");
             if (BigDecimal.valueOf(distance1).compareTo(xpCheckLocation.getLocationRange()) > 0) {
                 return R.fail("不在打卡范围内");
             }
-        }else {
+        } else {
             return R.fail("打卡失败");
         }
 
@@ -128,7 +147,7 @@
                 .eq(XpClockIn::getAppUserId, dto.getOperationsUserId())
                 .likeRight(XpClockIn::getClockInTime, LocalDate.now())
                 .last("LIMIT 1"));
-        if(Objects.isNull(xpClockIn)){
+        if (Objects.isNull(xpClockIn)) {
             return R.fail("请先上班打卡");
         }
 
@@ -147,12 +166,13 @@
         xpClockIn.setClockOutAddress(dto.getClockOutAddress());
         if (xpClockIn.getClockOutTime().isBefore(endLocalDateTime)) {
             xpClockIn.setClockInResult(2);
-        }else {
+        } else {
             xpClockIn.setClockInResult(1);
         }
         this.updateById(xpClockIn);
         return R.ok();
     }
+
     @Override
     public Boolean checkWorkStatus(Long appUserId) {
         if (appUserId == null) {
@@ -167,7 +187,7 @@
 
             // 2. 查询当天打卡记录
             List<XpClockIn> records = baseMapper.selectTodayClockInRecords(
-                 appUserId, startTime, endTime
+                    appUserId, startTime, endTime
             );
 
             // 3. 判断上班状态
@@ -191,4 +211,176 @@
             return false;
         }
     }
+
+
+    /**
+     * 获取打卡统计
+     *
+     * @param query
+     * @return
+     */
+    @Override
+    public PageInfo<ClockInStatisticsDto> getClockInStatistics(ClockInStatisticsVo query) {
+        PageInfo<ClockInStatisticsDto> pageInfo = new PageInfo<>(query.getPageNum(), query.getPageSize());
+        List<Long> appUserIds = new ArrayList<>();
+        //处理查询条件
+        if(StringUtils.isNotEmpty(query.getName())){
+            R<List<XpOperationsUser>> listR = xpOperationUserClient.listByName(query.getName());
+            if(listR.getCode() == Constants.SUCCESS){
+                List<Long> collect = listR.getData().stream().map(XpOperationsUser::getId).collect(Collectors.toList());
+                appUserIds.addAll(collect);
+            }
+
+        }
+        if(null != query.getRoleId()){
+            R<List<XpOperationsRole>> roleByRoleId = xpOperationUserClient.getXpOperationsRoleByRoleId(query.getRoleId());
+            if(roleByRoleId.getCode() == Constants.SUCCESS){
+                List<Long> collect = roleByRoleId.getData().stream().map(XpOperationsRole::getOperationsUserId).collect(Collectors.toList());
+                appUserIds.addAll(collect);
+            }
+        }
+
+        String startTime = "";
+        String endTime = "";
+        if(StringUtils.isNotEmpty(query.getStatisticDate())){
+            String statisticDate = query.getStatisticDate();
+            startTime = statisticDate.split(" - ")[0];
+            endTime = statisticDate.split(" - ")[1];
+        }
+        //查询数据
+        List<ClockInStatisticsDto> clockInStatistics = this.baseMapper.getClockInStatistics(pageInfo, appUserIds, startTime, endTime);
+        List<String> appUserIdList = clockInStatistics.stream().map(ClockInStatisticsDto::getAppUserId).collect(Collectors.toList());
+        List<Long> ids = appUserIdList.stream().map(Long::parseLong).collect(Collectors.toList());
+        List<XpOperationsUserWithRoleVO> data = xpOperationUserClient.listByIdsWithRole(ids).getData();
+        //将查询结果组装成map对象,用于循环中提取数据
+        Map<Long,XpOperationsUserWithRoleVO> map = data.stream().collect(Collectors.toMap(XpOperationsUserWithRoleVO::getId, item->item));
+        for (ClockInStatisticsDto clockInStatistic : clockInStatistics) {
+            String appUserId = clockInStatistic.getAppUserId();
+            XpOperationsUserWithRoleVO xpOperationsUserWithRoleVO = map.get(Long.parseLong(appUserId));
+            clockInStatistic.setName(xpOperationsUserWithRoleVO.getNickName());
+            clockInStatistic.setRoleName(xpOperationsUserWithRoleVO.getRoleName());
+            Integer shouldClockInDays = clockInStatistic.getShouldClockInDays();
+            Integer clockInDays = clockInStatistic.getClockInDays();
+            clockInStatistic.setNotClockInDays(shouldClockInDays - clockInDays);
+        }
+        pageInfo.setRecords(clockInStatistics);
+        return pageInfo;
+    }
+
+
+    /**
+     * 导出打卡统计
+     * @param query
+     * @param response
+     */
+    @Override
+    public void exportClockInStatistics(ClockInStatisticsVo query, HttpServletResponse response) {
+        PageInfo<ClockInStatisticsDto> pageInfo = new PageInfo<>(0, 10000);
+        List<Long> appUserIds = new ArrayList<>();
+        //处理查询条件
+        if(StringUtils.isNotEmpty(query.getName())){
+            R<List<XpOperationsUser>> listR = xpOperationUserClient.listByName(query.getName());
+            if(listR.getCode() == Constants.SUCCESS){
+                List<Long> collect = listR.getData().stream().map(XpOperationsUser::getId).collect(Collectors.toList());
+                appUserIds.addAll(collect);
+            }
+
+        }
+        if(null != query.getRoleId()){
+            R<List<XpOperationsRole>> roleByRoleId = xpOperationUserClient.getXpOperationsRoleByRoleId(query.getRoleId());
+            if(roleByRoleId.getCode() == Constants.SUCCESS){
+                List<Long> collect = roleByRoleId.getData().stream().map(XpOperationsRole::getOperationsUserId).collect(Collectors.toList());
+                appUserIds.addAll(collect);
+            }
+        }
+
+        String startTime = "";
+        String endTime = "";
+        if(StringUtils.isNotEmpty(query.getStatisticDate())){
+            String statisticDate = query.getStatisticDate();
+            startTime = statisticDate.split(" - ")[0];
+            endTime = statisticDate.split(" - ")[1];
+        }
+        //查询数据
+        List<ClockInStatisticsDto> clockInStatistics = this.baseMapper.getClockInStatistics(pageInfo, appUserIds, startTime, endTime);
+        List<String> appUserIdList = clockInStatistics.stream().map(ClockInStatisticsDto::getAppUserId).collect(Collectors.toList());
+        List<Long> ids = appUserIdList.stream().map(Long::parseLong).collect(Collectors.toList());
+        List<XpOperationsUserWithRoleVO> data = xpOperationUserClient.listByIdsWithRole(ids).getData();
+        //将查询结果组装成map对象,用于循环中提取数据
+        Map<Long,XpOperationsUserWithRoleVO> map = data.stream().collect(Collectors.toMap(XpOperationsUserWithRoleVO::getId, item->item));
+        for (ClockInStatisticsDto clockInStatistic : clockInStatistics) {
+            String appUserId = clockInStatistic.getAppUserId();
+            XpOperationsUserWithRoleVO xpOperationsUserWithRoleVO = map.get(Long.parseLong(appUserId));
+            clockInStatistic.setName(xpOperationsUserWithRoleVO.getNickName());
+            clockInStatistic.setRoleName(xpOperationsUserWithRoleVO.getRoleName());
+            Integer shouldClockInDays = clockInStatistic.getShouldClockInDays();
+            Integer clockInDays = clockInStatistic.getClockInDays();
+            clockInStatistic.setNotClockInDays(shouldClockInDays - clockInDays);
+        }
+
+        ExcelUtil<ClockInStatisticsDto> excel = new ExcelUtil<ClockInStatisticsDto>(ClockInStatisticsDto.class);
+        excel.exportExcel(response, clockInStatistics, "打卡统计");
+    }
+
+
+
+
+
+    /**
+     * 获取打卡统计明细
+     * @param query
+     * @return
+     */
+    @Override
+    public PageInfo<ClockInStatisticsDetailsDto> getClockInStatisticsDetails(ClockInStatisticsDetailsVo query) {
+        PageInfo<ClockInStatisticsDetailsDto> pageInfo = new PageInfo<>(query.getPageNum(), query.getPageSize());
+
+        String startTime = "";
+        String endTime = "";
+        if(StringUtils.isNotEmpty(query.getStatisticDate())){
+            String statisticDate = query.getStatisticDate();
+            startTime = statisticDate.split(" - ")[0];
+            endTime = statisticDate.split(" - ")[1];
+        }
+        List<ClockInStatisticsDetailsDto> clockInStatisticsDetails = this.baseMapper.getClockInStatisticsDetails(pageInfo, query.getAppUserId(), startTime, endTime);
+        List<XpOperationsUserWithRoleVO> data = xpOperationUserClient.listByIdsWithRole(Arrays.asList(query.getAppUserId())).getData();
+        XpOperationsUserWithRoleVO xpOperationsUserWithRoleVO = data.get(0);
+        //将查询结果组装成map对象,用于循环中提取数据
+        for (ClockInStatisticsDetailsDto clockInStatistic : clockInStatisticsDetails) {
+            clockInStatistic.setName(xpOperationsUserWithRoleVO.getNickName());
+            clockInStatistic.setRoleName(xpOperationsUserWithRoleVO.getRoleName());
+        }
+        pageInfo.setRecords(clockInStatisticsDetails);
+        return pageInfo;
+    }
+
+
+    /**
+     * 导出打卡统计明细
+     * @param query
+     * @param response
+     */
+    @Override
+    public void exportClockInStatisticsDetails(ClockInStatisticsDetailsVo query, HttpServletResponse response) {
+        PageInfo<ClockInStatisticsDetailsDto> pageInfo = new PageInfo<>(0, 10000);
+
+        String startTime = "";
+        String endTime = "";
+        if(StringUtils.isNotEmpty(query.getStatisticDate())){
+            String statisticDate = query.getStatisticDate();
+            startTime = statisticDate.split(" - ")[0];
+            endTime = statisticDate.split(" - ")[1];
+        }
+        List<ClockInStatisticsDetailsDto> clockInStatisticsDetails = this.baseMapper.getClockInStatisticsDetails(pageInfo, query.getAppUserId(), startTime, endTime);
+        List<XpOperationsUserWithRoleVO> data = xpOperationUserClient.listByIdsWithRole(Arrays.asList(query.getAppUserId())).getData();
+        XpOperationsUserWithRoleVO xpOperationsUserWithRoleVO = data.get(0);
+        //将查询结果组装成map对象,用于循环中提取数据
+        for (ClockInStatisticsDetailsDto clockInStatistic : clockInStatisticsDetails) {
+            clockInStatistic.setName(xpOperationsUserWithRoleVO.getNickName());
+            clockInStatistic.setRoleName(xpOperationsUserWithRoleVO.getRoleName());
+        }
+
+        ExcelUtil<ClockInStatisticsDetailsDto> excel = new ExcelUtil<ClockInStatisticsDetailsDto>(ClockInStatisticsDetailsDto.class);
+        excel.exportExcel(response, clockInStatisticsDetails, "打卡统计明细");
+    }
 }

--
Gitblit v1.7.1