yusm 2 дней назад
Родитель
Сommit
de8b4a08f7

+ 29 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/ReportController.java

@@ -10,6 +10,7 @@ import com.management.platform.config.LimitRequest;
 import com.management.platform.constant.Constant;
 import com.management.platform.entity.*;
 import com.management.platform.entity.vo.MonthWorkingTimeVO;
+import com.management.platform.entity.vo.ReportRateTaskVO;
 import com.management.platform.entity.vo.SysRichFunction;
 import com.management.platform.entity.vo.WorktimeItem;
 import com.management.platform.mapper.*;
@@ -3194,6 +3195,34 @@ public class ReportController {
     }
 
 
+    /**
+     *
+     * @param projectId
+     * @param userIds
+     * @param type 0按任务查看 ,1按人员查看
+     * @return
+     */
+    @RequestMapping("/getReportRateOfTask")
+    public HttpRespMsg getReportRateOfTask(Integer projectId,String userIds,Integer type) {
+        User user = userMapper.selectById(request.getHeader("TOKEN"));
+        return reportService.getReportRateOfTask(projectId,userIds,user.getCompanyId(),type);
+    }
+
+
+    /**
+     *
+     * @param projectId
+     * @param userIds
+     * @param type 0按任务查看 ,1按人员查看
+     * @return
+     */
+    @RequestMapping("/exportReportRateOfTask")
+    public HttpRespMsg exportReportRateOfTask(Integer projectId,String userIds,Integer type) {
+        User user = userMapper.selectById(request.getHeader("TOKEN"));
+        return reportService.exportReportRateOfTask(projectId,userIds,user.getCompanyId(),type);
+    }
+
+
 
 }
 

+ 37 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/vo/ReportRateTaskListVO.java

@@ -0,0 +1,37 @@
+package com.management.platform.entity.vo;
+
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.time.LocalDate;
+import java.util.List;
+
+
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+public class ReportRateTaskListVO {
+
+   private String taskName;
+   private String projectName;
+   private List<ReportRateTaskVO> list;
+
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    @DateTimeFormat(pattern = "yyyy-MM-dd")
+    private LocalDate startDate;
+
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    @DateTimeFormat(pattern = "yyyy-MM-dd")
+    private LocalDate endDate;
+
+
+    private String userName;
+
+    private String averagePercentage;
+    private String averageLeavePercentage;
+
+}

+ 40 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/vo/ReportRateTaskVO.java

@@ -0,0 +1,40 @@
+package com.management.platform.entity.vo;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.management.platform.entity.Report;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.time.LocalDate;
+
+
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+public class ReportRateTaskVO{
+
+    private String projectName;//项目名称
+    private String taskName;//任务名称
+    private Integer taskId;
+
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    @DateTimeFormat(pattern = "yyyy-MM-dd")
+    private LocalDate startDate;
+
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    @DateTimeFormat(pattern = "yyyy-MM-dd")
+    private LocalDate endDate;
+
+    private String userName;//用户姓名
+    private String userId;
+    private String jobNumber;//工号
+
+    private String departmentName;//部门名称
+    private String timelinessRate;
+    private String timelinessRateWithLeave;
+
+    private Integer companyId;
+
+}

+ 7 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/mapper/ReportMapper.java

@@ -3,6 +3,7 @@ package com.management.platform.mapper;
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.management.platform.entity.Report;
 import com.management.platform.entity.bo.BonusDataBO;
+import com.management.platform.entity.vo.ReportRateTaskVO;
 import com.management.platform.entity.vo.TisTimeVO;
 import com.management.platform.entity.vo.UserProjectBonusTimeVO;
 import com.management.platform.entity.vo.UserRestTimeVO;
@@ -263,4 +264,10 @@ public interface ReportMapper extends BaseMapper<Report> {
     List<Report> getReportProjectAssistTime(@Param("companyId") Integer companyId,@Param("startDate") LocalDate startDate, @Param("endDate") LocalDate endDate, @Param("groupNameList") List<String> groupNameList);
 
 
+    List<ReportRateTaskVO> getReportRateOfTask(Integer projectId, List<String> userIds, Integer type, Integer companyId);
+
+    int getReportRateOfTaskCount(Integer projectId, List<String> userIds, Integer type, Integer companyId);
+
+    List<Map<String, Object>> getUserReportTimelinessRateWithTask(@Param("companyId")Integer companyId,@Param("taskIds") List<Integer> taskIds);
+
 }

+ 4 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/ReportService.java

@@ -178,4 +178,8 @@ public interface ReportService extends IService<Report> {
     void checkAndAlertFVReportTimeLessThanCardTimeList(LocalDate startDate, LocalDate endDate, Integer companyId);
 
     HttpRespMsg rejectAbnormalReportTime(HttpServletRequest request, String ymonth);
+
+    HttpRespMsg getReportRateOfTask(Integer projectId, String userId, Integer companyId, Integer type);
+
+    HttpRespMsg exportReportRateOfTask(Integer projectId, String userIds, Integer companyId, Integer type);
 }

+ 365 - 1
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/ReportServiceImpl.java

@@ -49,6 +49,7 @@ import java.text.DecimalFormat;
 import java.text.ParseException;
 import java.text.SimpleDateFormat;
 import java.time.*;
+import java.time.chrono.ChronoLocalDate;
 import java.time.format.DateTimeFormatter;
 import java.time.format.DateTimeParseException;
 import java.time.temporal.ChronoUnit;
@@ -58,6 +59,7 @@ import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.Executor;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
+import java.util.concurrent.atomic.AtomicReference;
 import java.util.stream.Collectors;
 
 /**
@@ -10222,7 +10224,7 @@ public class ReportServiceImpl extends ServiceImpl<ReportMapper, Report> impleme
 
     private  List<LocalDate> getDays(LocalDate start, LocalDate end) {
         List<LocalDate> result = new ArrayList();
-        while (start.isBefore(end)) {
+        while (start!=null&&end!=null&& start.isBefore(end)) {
             result.add(start);
             start=start.plusDays(1);
         }
@@ -10953,6 +10955,368 @@ public class ReportServiceImpl extends ServiceImpl<ReportMapper, Report> impleme
         return msg;
     }
 
+    @Override
+    public HttpRespMsg getReportRateOfTask(Integer projectId, String userIds, Integer companyId, Integer type) {
+        HttpRespMsg msg = new HttpRespMsg();
+        DecimalFormat dft =  new DecimalFormat("0%");
+        List<String> collect=new ArrayList<>();
+        if (userIds!=null&&!userIds.isEmpty()){
+            String[] strings = userIds.split(",");
+            collect = Arrays.stream(strings).collect(Collectors.toList());
+        }
+        List<ReportRateTaskVO> reportRateTaskVOList= reportMapper.getReportRateOfTask(projectId, collect, type,companyId);
+
+
+        List<Department> departmentList = departmentMapper.selectList(new QueryWrapper<Department>().eq("company_id", companyId));
+        List<User> userList = userMapper.selectList(new QueryWrapper<User>().eq("company_id", companyId));
+
+        List<Integer> taskIds = reportRateTaskVOList.stream().distinct().map(r -> r.getTaskId()).collect(Collectors.toList());
+        System.out.println(taskIds.toString());
+        taskIds.add(-1);
+        List<Map<String,Object>> reportList=reportMapper.getUserReportTimelinessRateWithTask(companyId,taskIds);
+        Map<Object, List<Map<String, Object>>> listMap = reportList.stream().filter(item->!StringUtils.isEmpty(item.get("userName"))).collect(Collectors.groupingBy(rp -> rp.get("userName")));
+        //获取到公司设置的特殊节假日设置
+        List<HolidaySetting> holidaySettingList = holidaySettingService.list(new LambdaQueryWrapper<HolidaySetting>().eq(HolidaySetting::getCompanyId, companyId).isNotNull(HolidaySetting::getHolidayDate));
+        List<HolidaySetting> allUsersSetting = holidaySettingList.stream().filter(h -> h.getRangeType() == 0).collect(Collectors.toList());
+        List<HolidaySetting> targetUserOrDeptSetting = holidaySettingList.stream().filter(h -> h.getRangeType() == 1).collect(Collectors.toList());
+        TimeType timeType = timeTypeMapper.selectById(companyId);
+        Integer timeliness = timeType.getTimeliness();
+
+        for (ReportRateTaskVO rateTaskVO : reportRateTaskVOList) {
+            Optional<User> first = userList.stream().filter(u -> u.getId().equals(rateTaskVO.getUserId())).findFirst();
+            if (first.isPresent()){
+                User user = first.get();
+                rateTaskVO.setJobNumber(user.getJobNumber());
+                Optional<Department> firstDept = departmentList.stream().filter(d->d.getDepartmentId().equals(user.getDepartmentId())).findFirst();
+                if(firstDept.isPresent()){
+                    Department dept= firstDept.get();
+                    rateTaskVO.setDepartmentName(dept.getDepartmentName());
+                }
+
+                List<Map<String, Object>> mapList = listMap.get(user.getName());
+                LocalDate startDate = rateTaskVO.getStartDate();
+                LocalDate endDate = rateTaskVO.getEndDate();
+                AtomicReference<List<LocalDate>> listAtomicReference = new AtomicReference<>(getDays(startDate, endDate));
+                long days = listAtomicReference.get().size();
+                for (LocalDate localDateTime : listAtomicReference.get()) {
+                    if(mapList!=null){
+                        //在非工作日下 填报了的情况下 及时填报了就算作及时率计算的基数
+                        if(localDateTime!=null&& !WorkDayCalculateUtils.isWorkDay(localDateTime)&&!mapList.stream().anyMatch(ml->{
+                            Integer taskId=ml.get("taskId")!=null?Integer.parseInt(ml.get("taskId").toString()):null;
+                            if (taskId == null || !taskId.equals(rateTaskVO.getTaskId())) {
+                                return false;
+                            }
+                            Date date = (Date) ml.get("createDate");
+                            LocalDate createDate = date != null ? date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate() : null;
+                            return createDate.isEqual(localDateTime);
+                        })){
+                            days-=1;
+                        }
+                    }else {
+                        if(localDateTime!=null&&!WorkDayCalculateUtils.isWorkDay(localDateTime)){
+                            days-=1;
+                        }
+                    }
+                }
+                //获取请假数据
+                List<LeaveSheet> leaveSheetList = leaveSheetMapper.selectList(new LambdaQueryWrapper<LeaveSheet>()
+                        .eq(LeaveSheet::getCompanyId, companyId).le(endDate!=null,LeaveSheet::getStartDate,endDate)
+                        .ge(startDate!=null,LeaveSheet::getEndDate,startDate));
+                List<LeaveSheet> leaveSheets = leaveSheetList.stream().filter(ls -> ls.getOwnerId().equals(user.getId())
+                        &&(endDate!=null &&startDate!=null)
+                        &&((ls.getStartDate().isBefore(ChronoLocalDate.from(endDate))||ls.getStartDate().isEqual(ChronoLocalDate.from(endDate))))
+                        &&((ls.getEndDate().isAfter(ChronoLocalDate.from(startDate))||ls.getEndDate().isEqual(ChronoLocalDate.from(startDate)))))
+                        .collect(Collectors.toList());
+                long daysWithLeave =days;
+                if(leaveSheets.size()>0){
+                    for (LeaveSheet leaveSheet : leaveSheets) {
+                        AtomicReference<List<LocalDateTime>> leaveDateList = new AtomicReference<>(getDays(leaveSheet.getStartDate().atTime(LocalTime.MIN), leaveSheet.getEndDate().atTime(LocalTime.MIN)));
+                        AtomicReference<List<LocalDateTime>> list = new AtomicReference<>(getDays(leaveSheet.getStartDate().atTime(LocalTime.MIN), leaveSheet.getEndDate().atTime(LocalTime.MIN)));
+                        if(allUsersSetting.size()>0){
+                            List<LocalDateTime> holidayDateList = allUsersSetting.stream().map(h->h.getHolidayDate().atTime(LocalTime.MIN)).collect(Collectors.toList());
+                            leaveDateList.set(leaveDateList.get().stream().filter(d -> !holidayDateList.contains(d)).collect(Collectors.toList()));
+                            list.set(list.get().stream().filter(d -> !holidayDateList.contains(d)).collect(Collectors.toList()));
+                        }
+                        if(targetUserOrDeptSetting.size()>0){
+                            targetUserOrDeptSetting.forEach(t->{
+                                LocalDateTime holidayDate = t.getHolidayDate().atTime(LocalTime.MIN);
+                                if(!StringUtils.isEmpty(t.getTargetUsers())&&!t.getTargetUsers().equals("")){
+                                    String[] userSplit = t.getTargetUsers().split(",");
+                                    List<String> userAsList = Arrays.asList(userSplit);
+                                    if(userAsList.contains(user.getId())){
+                                        leaveDateList.set(leaveDateList.get().stream().filter(d -> !d.isEqual(holidayDate)).collect(Collectors.toList()));
+                                        list.set(list.get().stream().filter(d -> !d.isEqual(holidayDate)).collect(Collectors.toList()));
+                                    }
+                                }
+                                if(!StringUtils.isEmpty(t.getTargetDepts())&&!t.getTargetDepts().equals("")){
+                                    String[] deptSplit = t.getTargetDepts().split(",");
+                                    List<String> deptAsList = Arrays.asList(deptSplit);
+                                    for (String deptId : deptAsList) {
+                                        List<Integer> subDeptIds = getBranchDepartment(Integer.valueOf(deptId), departmentList);
+                                        if(deptId.equals(user.getDepartmentId())||subDeptIds.contains(user.getDepartmentId())){
+                                            leaveDateList.set(leaveDateList.get().stream().filter(d -> !d.isEqual(holidayDate)).collect(Collectors.toList()));
+                                            list.set(list.get().stream().filter(d -> !d.isEqual(holidayDate)).collect(Collectors.toList()));
+                                        }
+                                    }
+                                }
+                            });
+                        }
+                        if(list.get().size()>1){
+                            days-= list.get().size();
+                        }else {
+                            days-=1;
+                        }
+                        for (LocalDateTime localDateTime : leaveDateList.get()) {
+                            //todo: 请假区间当中有非工作日在之前被当作 不需填报 所以要加上 保证基数正确
+                            if(localDateTime!=null&&!WorkDayCalculateUtils.isWorkDay(localDateTime.toLocalDate())){
+                                days+=1;
+                                continue;
+                            }
+                            if((startDate!=null&&endDate!=null)&&localDateTime.isBefore(startDate.atStartOfDay())||localDateTime.isAfter(endDate.atStartOfDay().plusDays(1))){
+                                days++;
+                                continue;
+                            }
+                            if(mapList!=null&&mapList.stream().anyMatch(ml->{
+                                Integer taskId=ml.get("taskId")!=null?Integer.parseInt(ml.get("taskId").toString()):null;
+                                if (taskId == null || !taskId.equals(rateTaskVO.getTaskId())) {
+                                    return false;
+                                }
+                                Date date = (Date) ml.get("createDate");
+                                LocalDate createDate = date != null ? date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate() : null;
+                                return createDate.isEqual(localDateTime.toLocalDate());
+                            })){
+                                days++;
+                            }
+                        }
+                    }
+                }
+
+                int num=0;
+                if(mapList!=null){
+                    for (Map<String, Object> map : mapList) {
+                        if (map.get("createDate")!=null && map.get("createTime")!=null) {
+                            Map<String, Object> objectMap = new HashMap<>();
+                            Date date = (Date) map.get("createDate");
+                            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
+                            //去掉sql返回的毫秒值
+                            java.sql.Date createTime = (java.sql.Date) map.get("createTime");
+                            LocalDate createDate = date != null ? date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate() : null;
+                            // 针对美莱德 去除2024-02-09
+                            if (user.getCompanyId() == 876) {
+                                if (createDate.isEqual(LocalDate.parse("2024-02-09"))) {
+                                    continue;
+                                }
+                            }
+                            LocalDate createTimeDate = createTime.toLocalDate();
+                            //根据设置
+                            switch (timeliness) {
+                                case 1:
+                                    createDate = createDate.plusDays(1);
+                                    while (createDate!=null&&!WorkDayCalculateUtils.isWorkDay(createDate)) {
+                                        createDate = createDate.plusDays(1);
+                                    }
+                                    break;
+                                case 2:
+                                    Integer a = 0;
+                                    while (a != 2) {
+                                        createDate = createDate.plusDays(1);
+                                        if (createDate!=null&&WorkDayCalculateUtils.isWorkDay(createDate)) {
+                                            a++;
+                                        }
+                                    }
+                                    break;
+                            }
+                            if (createTimeDate.isBefore(createDate) || createTimeDate.isEqual(createDate)) {
+                                num++;
+                                objectMap.put(simpleDateFormat.format(date), MessageUtils.message("entry.timely") + "/" + MessageUtils.message("entry.SubTime") + createTimeDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
+                            } else {
+                                objectMap.put(simpleDateFormat.format(date), MessageUtils.message("entry.NoTimely") + "/" + MessageUtils.message("entry.SubTime") + createTimeDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
+                            }
+                        }
+
+                    }
+                    //处理漏填的情况,漏填的也算不及时
+                    boolean hasMissReport = false;
+                    for (LocalDate localDateTime : listAtomicReference.get()) {
+                        if(localDateTime!=null&&!WorkDayCalculateUtils.isWorkDay(localDateTime)){
+                            continue;
+                        }
+                        hasMissReport = true;
+                    }
+                    BigDecimal bigDecimal=new BigDecimal(num);
+                    BigDecimal bigDecimalWithLeave=new BigDecimal(num+(daysWithLeave-days));
+                    BigDecimal divide;
+                    BigDecimal divideWithLeave;
+                    if(days!=0){
+                        divide = bigDecimal.divide(BigDecimal.valueOf(days), 2, BigDecimal.ROUND_HALF_UP);
+                    }else if(days==0){
+                        divide=new BigDecimal(1);
+                        //查看当天有请假直接算100%
+                    }else if (days==0&&num!=0&&leaveSheetList.size()>0){
+                        divide=new BigDecimal(1);
+                    }else{
+                        divide=new BigDecimal(0);
+                    }
+                    if(divide.compareTo(new BigDecimal(1))==1){
+                        divide=new BigDecimal(1);
+                        log.error("填报及时率数据异常:==="+user.getName());
+                    }
+                    if(daysWithLeave!=0){
+                        divideWithLeave = bigDecimalWithLeave.divide(BigDecimal.valueOf(daysWithLeave), 2, BigDecimal.ROUND_HALF_UP);
+                    }else if(daysWithLeave==0){
+                        divideWithLeave=new BigDecimal(1);
+                        //查看当天有请假直接算100%
+                    }else if (daysWithLeave==0&&num!=0&&leaveSheetList.size()>0){
+                        divideWithLeave=new BigDecimal(1);
+                    }else{
+                        divideWithLeave=new BigDecimal(0);
+                    }
+                    if(divideWithLeave.compareTo(new BigDecimal(1))==1){
+                        divideWithLeave=new BigDecimal(1);
+                        log.error("填报及时率数据异常:==="+user.getName());
+                    }
+                    String number = dft.format(divide);
+                    String numberWithLeave = dft.format(divideWithLeave);
+                    rateTaskVO.setTimelinessRate(String.valueOf(number));
+                    rateTaskVO.setTimelinessRateWithLeave(String.valueOf(numberWithLeave));
+                }else {
+                    BigDecimal bigDecimal=new BigDecimal(num);
+                    BigDecimal bigDecimalWithLeave=new BigDecimal(num+(daysWithLeave-days));
+                    BigDecimal divide;
+                    BigDecimal divideWithLeave;
+                    if(days!=0){
+                        System.out.println("及时日=="+num+","+days);
+                        divide = bigDecimal.divide(BigDecimal.valueOf(days), 2, BigDecimal.ROUND_HALF_UP);
+                    }else if(days==0){
+                        divide=new BigDecimal(1);
+                        //查看当天有请假直接算100%
+                    }else if (days==0&&num!=0&&leaveSheetList.size()>0){
+                        divide=new BigDecimal(1);
+                    }else if(leaveSheets.size()>0){
+                        divide=new BigDecimal(1);
+                    }else{
+                        divide=new BigDecimal(0);
+                    }
+                    if(divide.compareTo(new BigDecimal(1))==1){
+                        divide=new BigDecimal(1);
+                        log.error("填报及时率数据异常:==="+user.getName());
+                    }
+                    if(daysWithLeave!=0){
+                        divideWithLeave = bigDecimalWithLeave.divide(BigDecimal.valueOf(daysWithLeave), 2, BigDecimal.ROUND_HALF_UP);
+                    }else if(daysWithLeave==0){
+                        divideWithLeave=new BigDecimal(1);
+                        //查看当天有请假直接算100%
+                    }else if (daysWithLeave==0&&num!=0&&leaveSheetList.size()>0){
+                        divideWithLeave=new BigDecimal(1);
+                    }else if(leaveSheets.size()>0){
+                        divideWithLeave=new BigDecimal(1);
+                    }else{
+                        divideWithLeave=new BigDecimal(0);
+                    }
+                    if(divideWithLeave.compareTo(new BigDecimal(1))==1){
+                        divideWithLeave=new BigDecimal(1);
+                        log.error("填报及时率数据异常:==="+user.getName());
+                    }
+                    String number = dft.format(divide);
+                    String numberWithLeave = dft.format(divideWithLeave);
+                    rateTaskVO.setTimelinessRate(String.valueOf(number));
+                    rateTaskVO.setTimelinessRateWithLeave(String.valueOf(numberWithLeave));
+                }
+            }
+        }
+
+        if (type==1) {
+            ArrayList<ReportRateTaskListVO> reportRateTaskListVOS = new ArrayList<>();
+            Map<String, List<ReportRateTaskVO>> groupedByTaskId = reportRateTaskVOList.stream()
+                    .filter(task -> task.getUserId() != null)  // 先过滤掉userId为null的记录
+                    .collect(Collectors.groupingBy(ReportRateTaskVO::getUserId));
+            Set<Map.Entry<String, List<ReportRateTaskVO>>> entries = groupedByTaskId.entrySet();
+            for (Map.Entry<String, List<ReportRateTaskVO>> entry : entries) {
+                ReportRateTaskListVO taskListVO = new ReportRateTaskListVO();
+                List<ReportRateTaskVO> list = entry.getValue();
+                // 过滤并转换百分比字符串为数值
+                List<Double> rates = list.stream()
+                        .filter(l -> l.getTimelinessRate() != null && !l.getTimelinessRate().isEmpty())
+                        .map(l -> {
+                            // 移除百分号并转换为double
+                            String rateStr = l.getTimelinessRate().replace("%", "");
+                            return Double.parseDouble(rateStr) / 100.0;
+                        })
+                        .collect(Collectors.toList());
+
+                // 计算平均值
+                double average = rates.isEmpty() ? 0.0 : rates.stream().mapToDouble(Double::doubleValue).average().orElse(0.0);
+
+                String averagePercentage = dft.format(average);
+
+
+                // 过滤并转换百分比字符串为数值
+                List<Double> ratesLeave = list.stream()
+                        .filter(l -> l.getTimelinessRateWithLeave() != null && !l.getTimelinessRateWithLeave().isEmpty())
+                        .map(l -> {
+                            // 移除百分号并转换为double
+                            String rateStr = l.getTimelinessRateWithLeave().replace("%", "");
+                            return Double.parseDouble(rateStr) / 100.0;
+                        })
+                        .collect(Collectors.toList());
+
+                // 计算平均值
+                double averageLeave = ratesLeave.isEmpty() ? 0.0 : ratesLeave.stream().mapToDouble(Double::doubleValue).average().orElse(0.0);
+                String averageLeavePercentage = dft.format(averageLeave);
+
+
+                taskListVO.setList(list);
+                taskListVO.setUserName(list.get(0).getUserName());
+                taskListVO.setAveragePercentage(averagePercentage);
+                taskListVO.setAverageLeavePercentage(averageLeavePercentage);
+                reportRateTaskListVOS.add(taskListVO);
+            }
+            msg.setData(reportRateTaskListVOS);
+        }else {
+            ArrayList<ReportRateTaskListVO> reportRateTaskListVOS = new ArrayList<>();
+            Map<Integer, List<ReportRateTaskVO>> groupedByTaskId = reportRateTaskVOList.stream()
+                    .filter(task -> task.getTaskId() != null)  // 先过滤掉userId为null的记录
+                    .collect(Collectors.groupingBy(ReportRateTaskVO::getTaskId));
+            Set<Map.Entry<Integer, List<ReportRateTaskVO>>> entries = groupedByTaskId.entrySet();
+            for (Map.Entry<Integer, List<ReportRateTaskVO>> entry : entries) {
+                ReportRateTaskListVO taskListVO = new ReportRateTaskListVO();
+                List<ReportRateTaskVO> list = entry.getValue();
+
+
+
+                taskListVO.setList(list);
+                taskListVO.setTaskName(list.get(0).getTaskName());
+                taskListVO.setProjectName(list.get(0).getProjectName());
+                taskListVO.setStartDate(list.get(0).getStartDate());
+                taskListVO.setEndDate(list.get(0).getEndDate());
+                reportRateTaskListVOS.add(taskListVO);
+            }
+            msg.setData(reportRateTaskListVOS);
+        }
+        return msg;
+    }
+
+    @Override
+    public HttpRespMsg exportReportRateOfTask(Integer projectId, String userIds, Integer companyId, Integer type) {
+        HttpRespMsg msg = new HttpRespMsg();
+        HttpRespMsg respMsg = getReportRateOfTask(projectId, userIds, companyId, type);
+        ArrayList<ReportRateTaskListVO> list = (ArrayList<ReportRateTaskListVO>) respMsg.getData();
+        String resp = ExcelUtil.exportGeneralExcelWithList(type, list, path);
+        msg.setData(resp);
+        return msg;
+    }
+
+
+    private  List<LocalDateTime> getDays(LocalDateTime start, LocalDateTime end) {
+        List<LocalDateTime> result = new ArrayList();
+        while (start.isBefore(end)) {
+            result.add(start);
+            start=start.plusDays(1);
+        }
+        result.add(start);
+        return result;
+    }
+
     @Override
     public List<Map<String, Object>> getReportTimeLessThanCardTimeList(LocalDate firstDay, LocalDate lastDay, Integer deptId, String userId, Integer companyId, boolean getAll) {
         //获取自己的考勤未填满的记录

+ 83 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/resources/mapper/ReportMapper.xml

@@ -1109,6 +1109,24 @@
         group by user.id,rl.create_date
     </select>
 
+
+    <select id="getUserReportTimelinessRateWithTask" resultType="java.util.Map">
+        select `user`.name as userName,t.id taskId, `user`.corpwx_userid as corpwxUserId,`user`.corpwx_deptid as corpwxDeptId,rl.operate_date as createDate,MIN(rl.work_date )as createTime
+        from report_log_detail rl
+        left join `user` on `user`.id=rl.operator_id
+        left join report r on r.id =rl.report_id
+        left join task t on t.id =r.task_id
+        where rl.company_id=#{companyId}
+        and rl.msg like '%提交了%'
+        <if test="taskIds!=null and taskIds.size()>0">
+            and t.id  in
+            <foreach collection="taskIds" item="item" open="(" separator="," close=")">
+                #{item}
+            </foreach>
+        </if>
+        group by t.id
+    </select>
+
     <select id="getDefaultDegree" resultType="java.util.Map">
         select report.degree_id as id FROM report
         WHERE report.company_id = #{companyId}
@@ -1570,4 +1588,69 @@
         group by project_id, extra_field4,extra_field5
     </select>
 
+    <select id="getReportRateOfTask" resultType="com.management.platform.entity.vo.ReportRateTaskVO">
+        SELECT
+            t.id AS taskId,
+            t.name AS taskName,
+            t.start_date AS startDate,
+            t.end_date AS endDate,
+            t.company_id companyId,
+            p.id AS projectId,
+            p.project_name AS projectName,
+            te.executor_id userId,
+            te.executor_name userName
+        FROM
+            task t
+                LEFT JOIN task_executor te on t.id= te.task_id
+                LEFT JOIN project p ON p.id = t.project_id
+
+        <where>
+            <if test="companyId!=null">
+                and t.company_id = #{companyId}
+            </if>
+            <if test="projectId!=null">
+                and p.id = #{projectId}
+            </if>
+            <if test="userIds!=null and userIds.size()>0">
+                and te.executor_id in
+                <foreach collection="userIds" item="item" open="(" separator="," close=")">
+                    #{item}
+                </foreach>
+            </if>
+        </where>
+
+        <if test="type !=null and type ==0">
+            ORDER BY
+            p.id,
+            t.id
+        </if>
+        <if test="type !=null and type ==1">
+            ORDER BY
+            te.executor_id desc,
+            t.id
+        </if>
+    </select>
+    <select id="getReportRateOfTaskCount" resultType="java.lang.Integer">
+        SELECT
+        count(*) total
+        FROM
+        task t
+        LEFT JOIN task_executor te on t.id= te.task_id
+        LEFT JOIN project p ON p.id = t.project_id
+        <where>
+            <if test="companyId!=null">
+                and t.company_id = #{companyId}
+            </if>
+            <if test="projectId!=null">
+                and p.id = #{projectId}
+            </if>
+            <if test="userIds!=null and userIds.size()>0">
+                and te.executor_id in
+                <foreach collection="userIds" item="item" open="(" separator="," close=")">
+                    #{item}
+                </foreach>
+            </if>
+        </where>
+    </select>
+
 </mapper>