Min há 9 meses atrás
pai
commit
61a44d7409

+ 6 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/ProjectController.java

@@ -1477,6 +1477,12 @@ public class ProjectController {
         return projectService.groupExpendProcessList(startDate,endDate,projectId,pageIndex,pageSize);
     }
 
+    //依斯倍定制 分组耗用进度表
+    @RequestMapping("/groupExpendProcessListForChart")
+    public HttpRespMsg groupExpendProcessListForChart(String startDate,String endDate,String projectIds,String groupNames){
+        return projectService.groupExpendProcessListForChart(startDate,endDate,projectIds,groupNames);
+    }
+
     //依斯倍定制 导出分组耗用进度表
     @RequestMapping("/exportGroupExpendProcessList")
     public HttpRespMsg exportGroupExpendProcessList(String startDate,String endDate,Integer projectId){

+ 32 - 287
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/UserWithBeisenController.java

@@ -148,223 +148,56 @@ public class UserWithBeisenController {
     @RequestMapping("/syncAttendanceFromBeisen")
     @Transactional(rollbackFor = Exception.class)
     public HttpRespMsg syncAttendanceFromBeisen(String startDate,String endDate){
+        Integer companyId = userMapper.selectById(request.getHeader("token")).getCompanyId();
+        return userWithBeisenService.syncAttendanceFromBeisen(startDate,endDate,companyId);
+    }
+
+
+    @RequestMapping("/getAttendanceStatisticWithUser")
+    public HttpRespMsg getAttendanceStatisticWithUser(String userId,String createDate){
         HttpRespMsg msg=new HttpRespMsg();
         DateTimeFormatter df=DateTimeFormatter.ofPattern("yyyy-MM-dd");
         DateTimeFormatter df1=DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
         DateTimeFormatter df2=DateTimeFormatter.ofPattern("HH:mm");
         DateTimeFormatter df3=DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
         DateTimeFormatter df4=DateTimeFormatter.ofPattern("HH:mm:ss");
-        Integer companyId = userMapper.selectById(request.getHeader("token")).getCompanyId();
+        if(StringUtils.isEmpty(userId)){
+            userId=request.getHeader("token");
+        }
+        User user = userMapper.selectById(userId);
+        Integer companyId = user.getCompanyId();
         TimeType timeType = timeTypeMapper.selectById(companyId);
         List<User> userList = userMapper.selectList(new LambdaQueryWrapper<User>().eq(User::getCompanyId, companyId));
         List<UserWithBeisen> userWithBeisenList = userWithBeisenService.list(new LambdaQueryWrapper<UserWithBeisen>().eq(UserWithBeisen::getCompanyId, companyId));
         BeisenConfig beisenConfig = beisenConfigMapper.selectById(companyId);
-        //获取特殊节假日设置
-        List<HolidaySetting> holidaySettings = holidaySettingService.list(new LambdaQueryWrapper<HolidaySetting>().eq(HolidaySetting::getCompanyId, companyId));
         if(beisenConfig==null){
             msg.setError("北森基础数据配置未完成,请联系服务商完成配置");
             return msg;
         }
+        Optional<UserWithBeisen> withBeisen = userWithBeisenList.stream().filter(u ->u.getJobNumber()!=null&& u.getJobNumber().equals(user.getJobNumber())).findFirst();
+        if(!withBeisen.isPresent()){
+            msg.setError("当前员工在北森系统中不存在,请完成录入员工信息");
+            return msg;
+        }
         //todo 获取到指定日期的考勤数据
-        JSONArray attendanceStatistics=new JSONArray();
+        JSONObject item = BeiSenUtils.getAttendanceStatisticWithUser(createDate,withBeisen.get().getUserId(), beisenConfig.getAppKey(), beisenConfig.getAppSecret());
         //todo 获取到指定日期的加班数据
-        List<LocalDate> workDaysListInRange = WorkDayCalculateUtils.getWorkDaysListInRange(startDate, endDate, 1);
-        JSONArray allOverTimeList=new JSONArray();
-        JSONArray allVacationList=new JSONArray();
-        List<LeaveSheet> leaveSheetList=new ArrayList<>();
-        List<UserFvTime> userFvTimeList=new ArrayList<>();
-        for (LocalDate localDate : workDaysListInRange) {
-            JSONArray statisticList = BeiSenUtils.getAttendanceStatistics(df.format(localDate), df.format(localDate), beisenConfig.getAppKey(), beisenConfig.getAppSecret(), 1, 100);
-            JSONArray overTimeList = BeiSenUtils.getOverTimeList(df.format(localDate), beisenConfig.getAppKey(), beisenConfig.getAppSecret(), 1, 100);
-            JSONArray vacationList = BeiSenUtils.getVacationList(df.format(localDate), beisenConfig.getAppKey(), beisenConfig.getAppSecret(),1,100);
-            allOverTimeList.addAll(overTimeList);
-            attendanceStatistics.addAll(statisticList);
-            allVacationList.addAll(vacationList);
-        }
-        for (LocalDate localDate : workDaysListInRange) {
-            Stream<JSONObject> swipingCardsStream = attendanceStatistics.stream().map(item -> (JSONObject) item);
-            //todo: 获取当天的考勤数据
-            List<JSONObject> swipingCardDateList = swipingCardsStream.filter(i -> LocalDateTime.parse(i.getString("SwipingCardDate"),df1).toLocalDate().equals(localDate)).collect(Collectors.toList());
-            for (JSONObject item : swipingCardDateList) {
-                //获取当前数据下的人员工号对应到工时管家
-                String cardNumber = item.getString("CardNumber");
-                Optional<User> first = userList.stream().filter(f -> f.getJobNumber().equals(cardNumber)).findFirst();
-                //todo: 获取考勤打卡时间集合
-                JSONArray times = item.getJSONArray("Times");
-                Stream<JSONObject> timeStream = times.stream().map(time -> (JSONObject) time);
-                Stream<JSONObject> timeStream1 = times.stream().map(time -> (JSONObject) time);
-                //获取最早上班打卡时间
-                List<LocalTime> minLocalTimeList = timeStream.filter(t -> t.getIntValue("Type") == 1).map(i -> LocalDateTime.parse(i.getString("ActualTime"),df1).toLocalTime()).collect(Collectors.toList());
-                Optional<LocalTime> minOp = minLocalTimeList.stream().min(LocalTime::compareTo);
-                //获取最晚下班时间
-                List<LocalTime> maxLocalTimeList = timeStream1.filter(t -> t.getIntValue("Type") == 9).map(i -> LocalDateTime.parse(i.getString("ActualTime"),df1).toLocalTime()).collect(Collectors.toList());
-                Optional<LocalTime> maxOp = maxLocalTimeList.stream().max(LocalTime::compareTo);
-                if(first.isPresent()){
-                    boolean workDay = WorkDayCalculateUtils.isWorkDay(localDate);
-                    //todo:针对景昱 工作日默认以8小时工作制度加上加班时长 非工作日以加班时长为准
-                    Double workTime;
-                    LocalTime min = minOp.get();
-                    LocalTime max = maxOp.get();
-                    Duration between = Duration.between(min,max);
-                    if(between.toHours()<=0){
-                        continue;
-                    }else {
-                        if(workDay){
-                            //去掉休息时长
-                            workTime=8.0;
-                        }else {
-                            //去掉休息时长
-                            workTime=0.0;
-                        }
-                    }
-                    Stream<JSONObject> overTimeStream = allOverTimeList.stream().map(elment -> (JSONObject) elment);
-                    Stream<JSONObject> vacationStream = allVacationList.stream().map(elment -> (JSONObject) elment);
-                    Optional<UserWithBeisen> beisen = userWithBeisenList.stream().filter(u -> u.getJobNumber() != null && u.getJobNumber().equals(first.get().getJobNumber())).findFirst();
-                    if(beisen.isPresent()){
-                        //todo:之前的逻辑
-//                        List<JSONObject> overTimeList = overTimeStream.filter(a -> a.getString("StaffId").equals(beisen.get().getUserId())
-//                                && (a.getIntValue("ApproveStatus") == 2||a.getIntValue("ApproveStatus") == 1)
-//                                &&LocalDateTime.parse(a.getString("StartDate"),df1).toLocalDate().isEqual(localDate)).collect(Collectors.toList());
-                        List<JSONObject> overTimeList = overTimeStream.filter(a -> a.getString("StaffId").equals(beisen.get().getUserId())
-                                && (a.getIntValue("ApproveStatus") == 2||a.getIntValue("ApproveStatus") == 1)).collect(Collectors.toList());
-                        //加班数据可能存在结束日期是当前日期的情况的情况
-                        BigDecimal overTimeBigDecimal= new BigDecimal(0);
-                        //计算加班时长 工作日打卡超过19:00:00算加班那 非工作日全天算加班
-                        if(workDay){
-                            //工作日打卡超过19:00:00算加班那 非工作日全天算加班
-                            if(max.isAfter(LocalTime.parse("19:00:00", df4))){
-                                overTimeBigDecimal = new BigDecimal(Duration.between(LocalTime.parse("18:00:00", df4),max).toMinutes());
-                            }
-                        }else {
-                            //非工作日全天 去掉休息时长 都算加班
-                            overTimeBigDecimal=new BigDecimal(Duration.between(min, max).toMinutes()) ;
-                            long rest1 = DateTimeUtil.calculateOverlap(min, max, LocalTime.parse("12:00:00", df4), LocalTime.parse("13:00:00", df4));
-                            long rest2 = DateTimeUtil.calculateOverlap(min, max, LocalTime.parse("17:30:00", df4), LocalTime.parse("18:00:00", df4));
-                            overTimeBigDecimal=overTimeBigDecimal.subtract(new BigDecimal(rest1)).subtract(new BigDecimal(rest2));
-                        }
-                        for (JSONObject o : overTimeList) {
-                            //存在开始日期为当前日期的数据以及结束日期为当天日期的数据 分开计算
-                            if(LocalDateTime.parse(o.getString("StartDate"),df1).toLocalDate().isEqual(localDate)){
-                                //存在开始日期为当天的数据
-                                if(LocalDateTime.parse(o.getString("StartDate"),df1).toLocalDate().isEqual(LocalDateTime.parse(o.getString("StopDate"),df1).toLocalDate())){
-                                    //开始日期和结束日期是相同的情况 说明是加班区间只存在于当天的情况
-                                    //对比打卡体现的加班时长和加班单时长取小
-                                    BigDecimal divide = overTimeBigDecimal.divide(new BigDecimal(60), 1, RoundingMode.HALF_DOWN);
-                                    if(divide.doubleValue()>o.getDouble("OverTimeDuration")){
-                                        //打卡获取到的加班时长大于加班单时长 需要在打卡体现的时长-打卡体现的加班时长+加班单时长
-                                        workTime=workTime+o.getDouble("OverTimeDuration");
-                                    }else{
-                                        workTime=workTime+round(divide.doubleValue(),0.5);
-                                    }
-                                }else {
-                                    //开始日期和结束日期是不相同的情况 说明是加班区间存在加班到第二天的情况
-                                    LocalDateTime start = LocalDateTime.parse(o.getString("StartDate"), df1);
-                                    LocalDateTime stop = start.toLocalDate().atTime(LocalTime.MAX);
-                                    Duration duration = Duration.between(start, stop);
-                                    BigDecimal decimal = new BigDecimal(duration.toMinutes());
-                                    decimal=decimal.divide(new BigDecimal(60),1,RoundingMode.HALF_DOWN);
-                                    double l = decimal.doubleValue();
-                                    //对比打卡体现的加班时长和加班单时长取小
-                                    BigDecimal divide = overTimeBigDecimal.divide(new BigDecimal(60), 1, RoundingMode.HALF_DOWN);
-                                    if(divide.doubleValue()>l){
-                                        //打卡获取到的加班时长大于加班单时长 需要在打卡体现的时长-打卡体现的加班时长+加班单时长
-                                        workTime=workTime+l;
-                                    }else {
-                                        workTime=workTime+round(divide.doubleValue(),0.5);
-                                    }
-                                }
-                            }else if(LocalDateTime.parse(o.getString("StopDate"),df1).toLocalDate().isEqual(localDate)){
-                                //存在结束日期为当天的数据
-                                if(LocalDateTime.parse(o.getString("StartDate"),df1).toLocalDate().isEqual(LocalDateTime.parse(o.getString("StopDate"),df1).toLocalDate())){
-                                    //开始日期和结束日期是相同的情况 说明是加班区间只存在于当天的情况
-                                    //判断打卡时间是不是大于19:00 通过打卡计算加班时长 与加班单作比较 取小
-                                    BigDecimal divide = overTimeBigDecimal.divide(new BigDecimal(60), 1, RoundingMode.HALF_DOWN);
-                                    if(divide.doubleValue()>o.getDouble("OverTimeDuration")){
-                                        //打卡获取到的加班时长大于加班单时长 需要在打卡体现的时长-打卡体现的加班时长+加班单时长
-                                        workTime=workTime+o.getDouble("OverTimeDuration");
-                                    }else {
-                                        workTime=workTime+round(divide.doubleValue(),0.5);
-                                    }
-                                }else {
-                                    //开始日期和结束日期是不相同的情况 说明是加班区间存在加班到第二天的情况
-                                    LocalDateTime stop = LocalDateTime.parse(o.getString("StopDate"), df1);
-                                    LocalDateTime start = stop.toLocalDate().atTime(LocalTime.MIN);
-                                    Duration duration = Duration.between(start, stop);
-                                    BigDecimal decimal = new BigDecimal(duration.toMinutes());
-                                    decimal=decimal.divide(new BigDecimal(60),1,RoundingMode.HALF_DOWN);
-                                    double l = decimal.doubleValue();
-                                    //对比打卡体现的加班时长和加班单时长取小
-                                    BigDecimal divide = overTimeBigDecimal.divide(new BigDecimal(60), 1, RoundingMode.HALF_DOWN);
-                                    if(divide.doubleValue()>l){
-                                        //打卡获取到的加班时长大于加班单时长 需要在打卡体现的时长-打卡体现的加班时长+加班单时长
-                                        workTime=workTime+l;
-                                    }else {
-                                        workTime=workTime+round(divide.doubleValue(),0.5);
-                                    }
-                                }
-                            }
-                        }
-                        //处理修改
-                        List<JSONObject> vacationList = vacationStream.filter(a ->{
-                            LocalDate vacationStartDate = LocalDateTime.parse(a.getString("VacationStartDateTime"), df3).toLocalDate();
-                            LocalDate vacationStopDate = LocalDateTime.parse(a.getString("VacationStopDateTime"), df3).toLocalDate();
-                            boolean b=false;
-                            if((localDate.isAfter(vacationStartDate)||localDate.isEqual(vacationStartDate))
-                                    &&(localDate.isBefore(vacationStopDate)||localDate.isEqual(vacationStopDate))){
-                                b=true;
-                            }
-                            if(a.getString("StaffId").equals(beisen.get().getUserId())
-                                    && b
-                                    &&a.getString("DocumentType").equals("请假")
-                                    &&  (a.getString("ApproveStatus").equals("通过") || a.getString("ApproveStatus").equals("审批中"))){
-                                return true;
-                            }
-                            return false;
-                        }).collect(Collectors.toList());
-                        if(vacationList.size()>0){
-                            double vacationDuration = vacationList.stream().mapToDouble(i -> i.getDouble("VacationDuration")).sum();
-                            BigDecimal decimal = new BigDecimal(vacationDuration);
-                            decimal=decimal.divide(new BigDecimal(60),1,RoundingMode.HALF_DOWN);
-//                            //可能存在休假多天 只减去一天
-                            if(decimal.doubleValue()>=8){
-                                workTime= workTime-8;
-                            }else {
-                                workTime= workTime-decimal.doubleValue();
-                            }
-                        }
-                    }
-                    UserFvTime userFvTime=new UserFvTime();
-                    userFvTime.setWorkDate(localDate);
-                    userFvTime.setStartTime(df2.format(min));
-                    userFvTime.setEndTime(df2.format(max));
-                    userFvTime.setUserId(first.get().getId());
-                    userFvTime.setCompanyId(companyId);
-                    userFvTime.setWorkHours(workTime.floatValue());
-                    UserFvTime one = userFvTimeService.getOne(new LambdaQueryWrapper<UserFvTime>().eq(UserFvTime::getCompanyId, companyId).eq(UserFvTime::getUserId, first.get().getId()).eq(UserFvTime::getWorkDate, localDate));
-                    if(one!=null){
-                        userFvTime.setId(one.getId());
-                    }
-                    userFvTimeList.add(userFvTime);
-                }
-            }
-        }
-        if(userFvTimeList.size()>0){
-            if(!userFvTimeService.saveOrUpdateBatch(userFvTimeList)){
-                msg.setError("同步验证失败");
-            }
-        }
+        JSONArray allOverTimeList = BeiSenUtils.getOverTimeList(createDate,beisenConfig.getAppKey(),beisenConfig.getAppSecret(),1,100);
+        //todo 获取到指定日期的休假数据
+        JSONArray vacationList = BeiSenUtils.getVacationList(createDate, beisenConfig.getAppKey(), beisenConfig.getAppSecret(),1,100);
         //同步休假数据到工时管家
-        for (int i = 0; i < allVacationList.size(); i++) {
-            JSONObject jsonObject = allVacationList.getJSONObject(i);
-            Optional<UserWithBeisen> beisen = userWithBeisenList.stream().filter(b -> b.getUserId().equals(jsonObject.getString("StaffId"))).findFirst();
-            if(beisen.isPresent()){
-                Optional<User> first = userList.stream().filter(u -> u.getJobNumber().equals(beisen.get().getJobNumber())).findFirst();
-                if(first.isPresent()){
+        List<LeaveSheet> leaveSheetList=new ArrayList<>();
+        for (int i = 0; i < vacationList.size(); i++) {
+            JSONObject jsonObject = vacationList.getJSONObject(i);
+            Optional<UserWithBeisen> beisen1 = userWithBeisenList.stream().filter(b -> b.getUserId().equals(jsonObject.getString("StaffId"))).findFirst();
+            if(beisen1.isPresent()){
+                Optional<User> first1 = userList.stream().filter(u -> u.getJobNumber().equals(beisen1.get().getJobNumber())).findFirst();
+                if(first1.isPresent()){
                     LeaveSheet leaveSheet=new LeaveSheet();
                     leaveSheet.setCompanyId(beisenConfig.getCompanyId());
                     leaveSheet.setStatus(0);
-                    leaveSheet.setOwnerId(first.get().getId());
-                    leaveSheet.setOwnerName(first.get().getName());
+                    leaveSheet.setOwnerId(first1.get().getId());
+                    leaveSheet.setOwnerName(first1.get().getName());
                     leaveSheet.setStartDate(LocalDateTime.parse(String.valueOf(jsonObject.get("VacationStartDateTime")),df3).toLocalDate());
                     leaveSheet.setEndDate(LocalDateTime.parse(String.valueOf(jsonObject.get("VacationStopDateTime")),df3).toLocalDate());
                     leaveSheet.setTimeType(1);
@@ -394,8 +227,8 @@ public class UserWithBeisenController {
                     leaveSheet.setRemark(jsonObject.getString("Reason"));
                     leaveSheet.setStatus(jsonObject.getString("ApproveStatus").equals("通过")?0:jsonObject.getString("ApproveStatus").equals("审批中")?1:2);
                     leaveSheet.setProcinstId(jsonObject.getString("VacationId"));
-                    LeaveSheet one = leaveSheetService.getOne(new LambdaQueryWrapper<LeaveSheet>().eq(LeaveSheet::getProcinstId,leaveSheet.getProcinstId()).eq(LeaveSheet::getOwnerId, first.get().getId()).eq(LeaveSheet::getStartDate, leaveSheet.getStartDate()).eq(LeaveSheet::getEndDate, leaveSheet.getEndDate()));
-                    if(one==null){
+                    LeaveSheet one1 = leaveSheetService.getOne(new LambdaQueryWrapper<LeaveSheet>().eq(LeaveSheet::getOwnerId, first1.get().getId()).eq(LeaveSheet::getStartDate, leaveSheet.getStartDate()).eq(LeaveSheet::getProcinstId,leaveSheet.getProcinstId()).eq(LeaveSheet::getEndDate, leaveSheet.getEndDate()));
+                    if(one1==null){
                         leaveSheetList.add(leaveSheet);
                     }
                 }
@@ -404,42 +237,6 @@ public class UserWithBeisenController {
         if(leaveSheetList.size()>0){
             leaveSheetService.saveOrUpdateBatch(leaveSheetList);
         }
-        return msg;
-    }
-
-
-    @RequestMapping("/getAttendanceStatisticWithUser")
-    public HttpRespMsg getAttendanceStatisticWithUser(String userId,String createDate){
-        HttpRespMsg msg=new HttpRespMsg();
-        DateTimeFormatter df=DateTimeFormatter.ofPattern("yyyy-MM-dd");
-        DateTimeFormatter df1=DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
-        DateTimeFormatter df2=DateTimeFormatter.ofPattern("HH:mm");
-        DateTimeFormatter df3=DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
-        DateTimeFormatter df4=DateTimeFormatter.ofPattern("HH:mm:ss");
-        if(StringUtils.isEmpty(userId)){
-            userId=request.getHeader("token");
-        }
-        User user = userMapper.selectById(userId);
-        Integer companyId = user.getCompanyId();
-        TimeType timeType = timeTypeMapper.selectById(companyId);
-        List<User> userList = userMapper.selectList(new LambdaQueryWrapper<User>().eq(User::getCompanyId, companyId));
-        List<UserWithBeisen> userWithBeisenList = userWithBeisenService.list(new LambdaQueryWrapper<UserWithBeisen>().eq(UserWithBeisen::getCompanyId, companyId));
-        BeisenConfig beisenConfig = beisenConfigMapper.selectById(companyId);
-        if(beisenConfig==null){
-            msg.setError("北森基础数据配置未完成,请联系服务商完成配置");
-            return msg;
-        }
-        Optional<UserWithBeisen> withBeisen = userWithBeisenList.stream().filter(u ->u.getJobNumber()!=null&& u.getJobNumber().equals(user.getJobNumber())).findFirst();
-        if(!withBeisen.isPresent()){
-            msg.setError("当前员工在北森系统中不存在,请完成录入员工信息");
-            return msg;
-        }
-        //todo 获取到指定日期的考勤数据
-        JSONObject item = BeiSenUtils.getAttendanceStatisticWithUser(createDate,withBeisen.get().getUserId(), beisenConfig.getAppKey(), beisenConfig.getAppSecret());
-        //todo 获取到指定日期的加班数据
-        JSONArray allOverTimeList = BeiSenUtils.getOverTimeList(createDate,beisenConfig.getAppKey(),beisenConfig.getAppSecret(),1,100);
-        //todo 获取到指定日期的休假数据
-        JSONArray vacationList = BeiSenUtils.getVacationList(createDate, beisenConfig.getAppKey(), beisenConfig.getAppSecret(),1,100);
         //获取当前数据下的人员工号对应到工时管家
         Optional<User> first = userList.stream().filter(f -> f.getJobNumber().equals(withBeisen.get().getJobNumber())).findFirst();
         System.out.println("考勤数据:"+item.toString());
@@ -601,58 +398,6 @@ public class UserWithBeisenController {
                 userFvTime.setId(one.getId());
             }
             userFvTimeService.saveOrUpdate(userFvTime);
-            //同步休假数据到工时管家
-            List<LeaveSheet> leaveSheetList=new ArrayList<>();
-            for (int i = 0; i < vacationList.size(); i++) {
-                JSONObject jsonObject = vacationList.getJSONObject(i);
-                Optional<UserWithBeisen> beisen1 = userWithBeisenList.stream().filter(b -> b.getUserId().equals(jsonObject.getString("StaffId"))).findFirst();
-                if(beisen.isPresent()){
-                    Optional<User> first1 = userList.stream().filter(u -> u.getJobNumber().equals(beisen.get().getJobNumber())).findFirst();
-                    if(first.isPresent()){
-                        LeaveSheet leaveSheet=new LeaveSheet();
-                        leaveSheet.setCompanyId(beisenConfig.getCompanyId());
-                        leaveSheet.setStatus(0);
-                        leaveSheet.setOwnerId(first.get().getId());
-                        leaveSheet.setOwnerName(first.get().getName());
-                        leaveSheet.setStartDate(LocalDateTime.parse(String.valueOf(jsonObject.get("VacationStartDateTime")),df3).toLocalDate());
-                        leaveSheet.setEndDate(LocalDateTime.parse(String.valueOf(jsonObject.get("VacationStopDateTime")),df3).toLocalDate());
-                        leaveSheet.setTimeType(1);
-                        leaveSheet.setTimeDays(jsonObject.getFloatValue("DayValueOfDuration"));
-                        leaveSheet.setTimeHours(jsonObject.getFloatValue("VacationDuration")/60);
-                        Integer leaveType;
-                        switch (jsonObject.getString("VacationType")){
-                            case "事假":leaveType=0;
-                                break;
-                            case "病假":leaveType=1;
-                                break;
-                            case "年假":leaveType=2;
-                                break;
-                            case "产假":leaveType=3;
-                                break;
-                            case "婚假":leaveType=4;
-                                break;
-                            case "丧假":leaveType=5;
-                                break;
-                            case "调休":leaveType=6;
-                                break;
-                            case "陪产假":leaveType=7;
-                                break;
-                            default:leaveType=8;
-                        }
-                        leaveSheet.setLeaveType(leaveType);
-                        leaveSheet.setRemark(jsonObject.getString("Reason"));
-                        leaveSheet.setStatus(jsonObject.getString("ApproveStatus").equals("通过")?0:jsonObject.getString("ApproveStatus").equals("审批中")?1:2);
-                        leaveSheet.setProcinstId(jsonObject.getString("VacationId"));
-                        LeaveSheet one1 = leaveSheetService.getOne(new LambdaQueryWrapper<LeaveSheet>().eq(LeaveSheet::getOwnerId, first.get().getId()).eq(LeaveSheet::getStartDate, leaveSheet.getStartDate()).eq(LeaveSheet::getProcinstId,leaveSheet.getProcinstId()).eq(LeaveSheet::getEndDate, leaveSheet.getEndDate()));
-                        if(one1==null){
-                            leaveSheetList.add(leaveSheet);
-                        }
-                    }
-                }
-            }
-            if(leaveSheetList.size()>0){
-                leaveSheetService.saveOrUpdateBatch(leaveSheetList);
-            }
             msg.setData(userFvTime);
         } else {
             msg.setError("未找到对应员工信息:staffId="+withBeisen.get().getUserId());

+ 2 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/mapper/ProjectMapper.java

@@ -184,4 +184,6 @@ public interface ProjectMapper extends BaseMapper<Project> {
     Long userTaskProcessListCount(Integer deptId, String userId, Integer projectId, Integer companyId, @Param("list") List<Integer> deptIds,String startDate,String endDate,@Param("listSecond") List<Integer> regularDeptIds);
     @Update("update project set reviwer_id=null where id=#{id}")
     void removeReviwer(Integer id);
+
+    List<Map<String, Object>> groupExpendProcessListForChart(String userId, Integer companyId, String startDate, String endDate,@Param("list") List<Integer> deptIds,@Param("listSecond") List<Integer> regularDeptIds,@Param("listThird") List<Integer> projectIdList,@Param("listFour") List<String> groupNameList);
 }

+ 2 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/ProjectService.java

@@ -298,4 +298,6 @@ public interface ProjectService extends IService<Project> {
     HttpRespMsg batchChangeStage(String projectIdArray, Integer stageId, String stageName, HttpServletRequest request);
 
     HttpRespMsg batchSetProjectTaskExecutor(String projectIds, String userIds);
+
+    HttpRespMsg groupExpendProcessListForChart(String startDate, String endDate, String projectIds, String groupNames);
 }

+ 2 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/UserWithBeisenService.java

@@ -2,6 +2,7 @@ package com.management.platform.service;
 
 import com.management.platform.entity.UserWithBeisen;
 import com.baomidou.mybatisplus.extension.service.IService;
+import com.management.platform.util.HttpRespMsg;
 
 /**
  * <p>
@@ -13,4 +14,5 @@ import com.baomidou.mybatisplus.extension.service.IService;
  */
 public interface UserWithBeisenService extends IService<UserWithBeisen> {
 
+    HttpRespMsg syncAttendanceFromBeisen(String startDate, String endDate,Integer companyId);
 }

+ 61 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/ProjectServiceImpl.java

@@ -14345,4 +14345,65 @@ public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project> impl
         }
         return msg;
     }
+
+    @Override
+    public HttpRespMsg groupExpendProcessListForChart(String startDate, String endDate, String projectIds, String groupNames) {
+        HttpRespMsg msg=new HttpRespMsg();
+        User user = userMapper.selectById(request.getHeader("token"));
+        NumberFormat percentFormat = NumberFormat.getPercentInstance();
+        percentFormat.setMaximumFractionDigits(2);
+        Integer companyId = user.getCompanyId();
+        List<String> groupNameList=new ArrayList<>();
+        List<Integer> projectIdList=new ArrayList<>();
+        if(!StringUtils.isEmpty(groupNames)){
+            groupNameList = Arrays.asList(groupNames.split(","));
+        }
+        if(!StringUtils.isEmpty(projectIds)){
+            projectIdList=Arrays.asList(projectIds.split(",")).stream().map(i->Integer.valueOf(i)).collect(Collectors.toList());
+        }
+        boolean viewAll = sysFunctionService.hasPriviledge(user.getRoleId(), "全部分组耗用进度表");
+        boolean incharger = sysFunctionService.hasPriviledge(user.getRoleId(), "负责部门分组耗用进度表");
+        List<Department> allDeptList = departmentMapper.selectList(new LambdaQueryWrapper<Department>().eq(Department::getCompanyId, companyId));
+        List<Map<String,Object>> resultList;
+        //是否具有查看全部数据的权限
+        //针对依斯呗 指定部门
+        List<Integer> regularDeptIds=new ArrayList<>();
+        if(user.getCompanyId()==3092){
+            List<String> nameString=new ArrayList<>();
+            nameString.add("4");
+            nameString.add("46");
+            nameString.add("45");
+            List<Department> departmentList = departmentMapper.selectList(new LambdaQueryWrapper<Department>().eq(Department::getCompanyId, user.getCompanyId()).in(Department::getDepartmentName, nameString));
+            List<Integer> theCollect = departmentList.stream().map(dm -> dm.getDepartmentId()).distinct().collect(Collectors.toList());
+            theCollect.add(-1);
+            for (Integer integer : theCollect) {
+                List<Integer> branchDepartment = getBranchDepartment(integer, allDeptList);
+                regularDeptIds.addAll(branchDepartment);
+            }
+        }
+        if(!viewAll){
+            if(!incharger){
+                //只能查看本人的数据
+                resultList=projectMapper.groupExpendProcessListForChart(user.getId(),companyId,startDate,endDate,null,null,projectIdList,groupNameList);
+            }else {
+                List<Department> departmentList = departmentMapper.selectList(new LambdaQueryWrapper<Department>().select(Department::getDepartmentId).eq(Department::getManagerId, user.getId()));
+                List<DepartmentOtherManager> departmentOtherManagerList = departmentOtherManagerMapper.selectList(new QueryWrapper<DepartmentOtherManager>().eq("other_manager_id", user.getId()));
+                List<Integer> deptIds=new ArrayList<>();
+                List<Integer> theCollect = departmentList.stream().map(dm -> dm.getDepartmentId()).distinct().collect(Collectors.toList());
+                theCollect.add(-1);
+                List<Integer> otherCollect = departmentOtherManagerList.stream().map(dom -> dom.getDepartmentId()).distinct().collect(Collectors.toList());
+                otherCollect.add(-1);
+                theCollect.addAll(otherCollect);
+                for (Integer integer : theCollect) {
+                    List<Integer> branchDepartment = getBranchDepartment(integer, allDeptList);
+                    deptIds.addAll(branchDepartment);
+                }
+                resultList=projectMapper.groupExpendProcessListForChart(null,companyId,startDate,endDate,deptIds,regularDeptIds,projectIdList,groupNameList);
+            }
+        }else {
+            resultList=projectMapper.groupExpendProcessListForChart(null,companyId,startDate,endDate,null,regularDeptIds,projectIdList,groupNameList);
+        }
+        msg.setData(resultList);
+        return msg;
+    }
 }

+ 314 - 1
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/UserWithBeisenServiceImpl.java

@@ -1,11 +1,38 @@
 package com.management.platform.service.impl;
 
-import com.management.platform.entity.UserWithBeisen;
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.management.platform.entity.*;
+import com.management.platform.mapper.BeisenConfigMapper;
+import com.management.platform.mapper.TimeTypeMapper;
+import com.management.platform.mapper.UserMapper;
 import com.management.platform.mapper.UserWithBeisenMapper;
+import com.management.platform.service.HolidaySettingService;
+import com.management.platform.service.LeaveSheetService;
+import com.management.platform.service.UserFvTimeService;
 import com.management.platform.service.UserWithBeisenService;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.management.platform.util.BeiSenUtils;
+import com.management.platform.util.DateTimeUtil;
+import com.management.platform.util.HttpRespMsg;
+import com.management.platform.util.WorkDayCalculateUtils;
 import org.springframework.stereotype.Service;
 
+import javax.servlet.http.HttpServletRequest;
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.time.Duration;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.format.DateTimeFormatter;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
 /**
  * <p>
  *  服务实现类
@@ -17,4 +44,290 @@ import org.springframework.stereotype.Service;
 @Service
 public class UserWithBeisenServiceImpl extends ServiceImpl<UserWithBeisenMapper, UserWithBeisen> implements UserWithBeisenService {
 
+    private UserFvTimeService userFvTimeService;
+    private UserMapper userMapper;
+    private TimeTypeMapper timeTypeMapper;
+    private HttpServletRequest request;
+    private UserWithBeisenService userWithBeisenService;
+    private BeisenConfigMapper beisenConfigMapper;
+    private HolidaySettingService holidaySettingService;
+    private LeaveSheetService leaveSheetService;
+
+    @Override
+    public HttpRespMsg syncAttendanceFromBeisen(String startDate, String endDate,Integer companyId) {
+        HttpRespMsg msg=new HttpRespMsg();
+        DateTimeFormatter df=DateTimeFormatter.ofPattern("yyyy-MM-dd");
+        DateTimeFormatter df1=DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
+        DateTimeFormatter df2=DateTimeFormatter.ofPattern("HH:mm");
+        DateTimeFormatter df3=DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
+        DateTimeFormatter df4=DateTimeFormatter.ofPattern("HH:mm:ss");
+        TimeType timeType = timeTypeMapper.selectById(companyId);
+        List<User> userList = userMapper.selectList(new LambdaQueryWrapper<User>().eq(User::getCompanyId, companyId));
+        List<UserWithBeisen> userWithBeisenList = userWithBeisenService.list(new LambdaQueryWrapper<UserWithBeisen>().eq(UserWithBeisen::getCompanyId, companyId));
+        BeisenConfig beisenConfig = beisenConfigMapper.selectById(companyId);
+        //获取特殊节假日设置
+        List<HolidaySetting> holidaySettings = holidaySettingService.list(new LambdaQueryWrapper<HolidaySetting>().eq(HolidaySetting::getCompanyId, companyId));
+        if(beisenConfig==null){
+            msg.setError("北森基础数据配置未完成,请联系服务商完成配置");
+            return msg;
+        }
+        //todo 获取到指定日期的考勤数据
+        JSONArray attendanceStatistics=new JSONArray();
+        //todo 获取到指定日期的加班数据
+        List<LocalDate> workDaysListInRange = WorkDayCalculateUtils.getWorkDaysListInRange(startDate, endDate, 1);
+        JSONArray allOverTimeList=new JSONArray();
+        JSONArray allVacationList=new JSONArray();
+        List<LeaveSheet> leaveSheetList=new ArrayList<>();
+        //同步休假数据到工时管家
+        for (int i = 0; i < allVacationList.size(); i++) {
+            JSONObject jsonObject = allVacationList.getJSONObject(i);
+            Optional<UserWithBeisen> beisen = userWithBeisenList.stream().filter(b -> b.getUserId().equals(jsonObject.getString("StaffId"))).findFirst();
+            if(beisen.isPresent()){
+                Optional<User> first = userList.stream().filter(u -> u.getJobNumber().equals(beisen.get().getJobNumber())).findFirst();
+                if(first.isPresent()){
+                    LeaveSheet leaveSheet=new LeaveSheet();
+                    leaveSheet.setCompanyId(beisenConfig.getCompanyId());
+                    leaveSheet.setStatus(0);
+                    leaveSheet.setOwnerId(first.get().getId());
+                    leaveSheet.setOwnerName(first.get().getName());
+                    leaveSheet.setStartDate(LocalDateTime.parse(String.valueOf(jsonObject.get("VacationStartDateTime")),df3).toLocalDate());
+                    leaveSheet.setEndDate(LocalDateTime.parse(String.valueOf(jsonObject.get("VacationStopDateTime")),df3).toLocalDate());
+                    leaveSheet.setTimeType(1);
+                    leaveSheet.setTimeDays(jsonObject.getFloatValue("DayValueOfDuration"));
+                    leaveSheet.setTimeHours(jsonObject.getFloatValue("VacationDuration")/60);
+                    Integer leaveType;
+                    switch (jsonObject.getString("VacationType")){
+                        case "事假":leaveType=0;
+                            break;
+                        case "病假":leaveType=1;
+                            break;
+                        case "年假":leaveType=2;
+                            break;
+                        case "产假":leaveType=3;
+                            break;
+                        case "婚假":leaveType=4;
+                            break;
+                        case "丧假":leaveType=5;
+                            break;
+                        case "调休":leaveType=6;
+                            break;
+                        case "陪产假":leaveType=7;
+                            break;
+                        default:leaveType=8;
+                    }
+                    leaveSheet.setLeaveType(leaveType);
+                    leaveSheet.setRemark(jsonObject.getString("Reason"));
+                    leaveSheet.setStatus(jsonObject.getString("ApproveStatus").equals("通过")?0:jsonObject.getString("ApproveStatus").equals("审批中")?1:2);
+                    leaveSheet.setProcinstId(jsonObject.getString("VacationId"));
+                    LeaveSheet one = leaveSheetService.getOne(new LambdaQueryWrapper<LeaveSheet>().eq(LeaveSheet::getProcinstId,leaveSheet.getProcinstId()).eq(LeaveSheet::getOwnerId, first.get().getId()).eq(LeaveSheet::getStartDate, leaveSheet.getStartDate()).eq(LeaveSheet::getEndDate, leaveSheet.getEndDate()));
+                    if(one==null){
+                        leaveSheetList.add(leaveSheet);
+                    }
+                }
+            }
+        }
+        if(leaveSheetList.size()>0){
+            leaveSheetService.saveOrUpdateBatch(leaveSheetList);
+        }
+        List<UserFvTime> userFvTimeList=new ArrayList<>();
+        for (LocalDate localDate : workDaysListInRange) {
+            JSONArray statisticList = BeiSenUtils.getAttendanceStatistics(df.format(localDate), df.format(localDate), beisenConfig.getAppKey(), beisenConfig.getAppSecret(), 1, 100);
+            JSONArray overTimeList = BeiSenUtils.getOverTimeList(df.format(localDate), beisenConfig.getAppKey(), beisenConfig.getAppSecret(), 1, 100);
+            JSONArray vacationList = BeiSenUtils.getVacationList(df.format(localDate), beisenConfig.getAppKey(), beisenConfig.getAppSecret(),1,100);
+            allOverTimeList.addAll(overTimeList);
+            attendanceStatistics.addAll(statisticList);
+            allVacationList.addAll(vacationList);
+        }
+        for (LocalDate localDate : workDaysListInRange) {
+            Stream<JSONObject> swipingCardsStream = attendanceStatistics.stream().map(item -> (JSONObject) item);
+            //todo: 获取当天的考勤数据
+            List<JSONObject> swipingCardDateList = swipingCardsStream.filter(i -> LocalDateTime.parse(i.getString("SwipingCardDate"),df1).toLocalDate().equals(localDate)).collect(Collectors.toList());
+            for (JSONObject item : swipingCardDateList) {
+                //获取当前数据下的人员工号对应到工时管家
+                String cardNumber = item.getString("CardNumber");
+                Optional<User> first = userList.stream().filter(f -> f.getJobNumber().equals(cardNumber)).findFirst();
+                //todo: 获取考勤打卡时间集合
+                JSONArray times = item.getJSONArray("Times");
+                Stream<JSONObject> timeStream = times.stream().map(time -> (JSONObject) time);
+                Stream<JSONObject> timeStream1 = times.stream().map(time -> (JSONObject) time);
+                //获取最早上班打卡时间
+                List<LocalTime> minLocalTimeList = timeStream.filter(t -> t.getIntValue("Type") == 1).map(i -> LocalDateTime.parse(i.getString("ActualTime"),df1).toLocalTime()).collect(Collectors.toList());
+                Optional<LocalTime> minOp = minLocalTimeList.stream().min(LocalTime::compareTo);
+                //获取最晚下班时间
+                List<LocalTime> maxLocalTimeList = timeStream1.filter(t -> t.getIntValue("Type") == 9).map(i -> LocalDateTime.parse(i.getString("ActualTime"),df1).toLocalTime()).collect(Collectors.toList());
+                Optional<LocalTime> maxOp = maxLocalTimeList.stream().max(LocalTime::compareTo);
+                if(first.isPresent()){
+                    boolean workDay = WorkDayCalculateUtils.isWorkDay(localDate);
+                    //todo:针对景昱 工作日默认以8小时工作制度加上加班时长 非工作日以加班时长为准
+                    Double workTime;
+                    LocalTime min = minOp.get();
+                    LocalTime max = maxOp.get();
+                    Duration between = Duration.between(min,max);
+                    if(between.toHours()<=0){
+                        continue;
+                    }else {
+                        if(workDay){
+                            //去掉休息时长
+                            workTime=8.0;
+                        }else {
+                            //去掉休息时长
+                            workTime=0.0;
+                        }
+                    }
+                    Stream<JSONObject> overTimeStream = allOverTimeList.stream().map(elment -> (JSONObject) elment);
+                    Stream<JSONObject> vacationStream = allVacationList.stream().map(elment -> (JSONObject) elment);
+                    Optional<UserWithBeisen> beisen = userWithBeisenList.stream().filter(u -> u.getJobNumber() != null && u.getJobNumber().equals(first.get().getJobNumber())).findFirst();
+                    if(beisen.isPresent()){
+                        //todo:之前的逻辑
+//                        List<JSONObject> overTimeList = overTimeStream.filter(a -> a.getString("StaffId").equals(beisen.get().getUserId())
+//                                && (a.getIntValue("ApproveStatus") == 2||a.getIntValue("ApproveStatus") == 1)
+//                                &&LocalDateTime.parse(a.getString("StartDate"),df1).toLocalDate().isEqual(localDate)).collect(Collectors.toList());
+                        List<JSONObject> overTimeList = overTimeStream.filter(a -> a.getString("StaffId").equals(beisen.get().getUserId())
+                                && (a.getIntValue("ApproveStatus") == 2||a.getIntValue("ApproveStatus") == 1)).collect(Collectors.toList());
+                        //加班数据可能存在结束日期是当前日期的情况的情况
+                        BigDecimal overTimeBigDecimal= new BigDecimal(0);
+                        //计算加班时长 工作日打卡超过19:00:00算加班那 非工作日全天算加班
+                        if(workDay){
+                            //工作日打卡超过19:00:00算加班那 非工作日全天算加班
+                            if(max.isAfter(LocalTime.parse("19:00:00", df4))){
+                                overTimeBigDecimal = new BigDecimal(Duration.between(LocalTime.parse("18:00:00", df4),max).toMinutes());
+                            }
+                        }else {
+                            //非工作日全天 去掉休息时长 都算加班
+                            overTimeBigDecimal=new BigDecimal(Duration.between(min, max).toMinutes()) ;
+                            long rest1 = DateTimeUtil.calculateOverlap(min, max, LocalTime.parse("12:00:00", df4), LocalTime.parse("13:00:00", df4));
+                            long rest2 = DateTimeUtil.calculateOverlap(min, max, LocalTime.parse("17:30:00", df4), LocalTime.parse("18:00:00", df4));
+                            overTimeBigDecimal=overTimeBigDecimal.subtract(new BigDecimal(rest1)).subtract(new BigDecimal(rest2));
+                        }
+                        for (JSONObject o : overTimeList) {
+                            //存在开始日期为当前日期的数据以及结束日期为当天日期的数据 分开计算
+                            if(LocalDateTime.parse(o.getString("StartDate"),df1).toLocalDate().isEqual(localDate)){
+                                //存在开始日期为当天的数据
+                                if(LocalDateTime.parse(o.getString("StartDate"),df1).toLocalDate().isEqual(LocalDateTime.parse(o.getString("StopDate"),df1).toLocalDate())){
+                                    //开始日期和结束日期是相同的情况 说明是加班区间只存在于当天的情况
+                                    //对比打卡体现的加班时长和加班单时长取小
+                                    BigDecimal divide = overTimeBigDecimal.divide(new BigDecimal(60), 1, RoundingMode.HALF_DOWN);
+                                    if(divide.doubleValue()>o.getDouble("OverTimeDuration")){
+                                        //打卡获取到的加班时长大于加班单时长 需要在打卡体现的时长-打卡体现的加班时长+加班单时长
+                                        workTime=workTime+o.getDouble("OverTimeDuration");
+                                    }else{
+                                        workTime=workTime+round(divide.doubleValue(),0.5);
+                                    }
+                                }else {
+                                    //开始日期和结束日期是不相同的情况 说明是加班区间存在加班到第二天的情况
+                                    LocalDateTime start = LocalDateTime.parse(o.getString("StartDate"), df1);
+                                    LocalDateTime stop = start.toLocalDate().atTime(LocalTime.MAX);
+                                    Duration duration = Duration.between(start, stop);
+                                    BigDecimal decimal = new BigDecimal(duration.toMinutes());
+                                    decimal=decimal.divide(new BigDecimal(60),1,RoundingMode.HALF_DOWN);
+                                    double l = decimal.doubleValue();
+                                    //对比打卡体现的加班时长和加班单时长取小
+                                    BigDecimal divide = overTimeBigDecimal.divide(new BigDecimal(60), 1, RoundingMode.HALF_DOWN);
+                                    if(divide.doubleValue()>l){
+                                        //打卡获取到的加班时长大于加班单时长 需要在打卡体现的时长-打卡体现的加班时长+加班单时长
+                                        workTime=workTime+l;
+                                    }else {
+                                        workTime=workTime+round(divide.doubleValue(),0.5);
+                                    }
+                                }
+                            }else if(LocalDateTime.parse(o.getString("StopDate"),df1).toLocalDate().isEqual(localDate)){
+                                //存在结束日期为当天的数据
+                                if(LocalDateTime.parse(o.getString("StartDate"),df1).toLocalDate().isEqual(LocalDateTime.parse(o.getString("StopDate"),df1).toLocalDate())){
+                                    //开始日期和结束日期是相同的情况 说明是加班区间只存在于当天的情况
+                                    //判断打卡时间是不是大于19:00 通过打卡计算加班时长 与加班单作比较 取小
+                                    BigDecimal divide = overTimeBigDecimal.divide(new BigDecimal(60), 1, RoundingMode.HALF_DOWN);
+                                    if(divide.doubleValue()>o.getDouble("OverTimeDuration")){
+                                        //打卡获取到的加班时长大于加班单时长 需要在打卡体现的时长-打卡体现的加班时长+加班单时长
+                                        workTime=workTime+o.getDouble("OverTimeDuration");
+                                    }else {
+                                        workTime=workTime+round(divide.doubleValue(),0.5);
+                                    }
+                                }else {
+                                    //开始日期和结束日期是不相同的情况 说明是加班区间存在加班到第二天的情况
+                                    LocalDateTime stop = LocalDateTime.parse(o.getString("StopDate"), df1);
+                                    LocalDateTime start = stop.toLocalDate().atTime(LocalTime.MIN);
+                                    Duration duration = Duration.between(start, stop);
+                                    BigDecimal decimal = new BigDecimal(duration.toMinutes());
+                                    decimal=decimal.divide(new BigDecimal(60),1,RoundingMode.HALF_DOWN);
+                                    double l = decimal.doubleValue();
+                                    //对比打卡体现的加班时长和加班单时长取小
+                                    BigDecimal divide = overTimeBigDecimal.divide(new BigDecimal(60), 1, RoundingMode.HALF_DOWN);
+                                    if(divide.doubleValue()>l){
+                                        //打卡获取到的加班时长大于加班单时长 需要在打卡体现的时长-打卡体现的加班时长+加班单时长
+                                        workTime=workTime+l;
+                                    }else {
+                                        workTime=workTime+round(divide.doubleValue(),0.5);
+                                    }
+                                }
+                            }
+                        }
+                        //处理修改
+                        List<JSONObject> vacationList = vacationStream.filter(a ->{
+                            LocalDate vacationStartDate = LocalDateTime.parse(a.getString("VacationStartDateTime"), df3).toLocalDate();
+                            LocalDate vacationStopDate = LocalDateTime.parse(a.getString("VacationStopDateTime"), df3).toLocalDate();
+                            boolean b=false;
+                            if((localDate.isAfter(vacationStartDate)||localDate.isEqual(vacationStartDate))
+                                    &&(localDate.isBefore(vacationStopDate)||localDate.isEqual(vacationStopDate))){
+                                b=true;
+                            }
+                            if(a.getString("StaffId").equals(beisen.get().getUserId())
+                                    && b
+                                    &&a.getString("DocumentType").equals("请假")
+                                    &&  (a.getString("ApproveStatus").equals("通过") || a.getString("ApproveStatus").equals("审批中"))){
+                                return true;
+                            }
+                            return false;
+                        }).collect(Collectors.toList());
+                        if(vacationList.size()>0){
+                            double vacationDuration = vacationList.stream().mapToDouble(i -> i.getDouble("VacationDuration")).sum();
+                            BigDecimal decimal = new BigDecimal(vacationDuration);
+                            decimal=decimal.divide(new BigDecimal(60),1,RoundingMode.HALF_DOWN);
+//                            //可能存在休假多天 只减去一天
+                            if(decimal.doubleValue()>=8){
+                                workTime= workTime-8;
+                            }else {
+                                workTime= workTime-decimal.doubleValue();
+                            }
+                        }else {
+//                            //在工时管家已经同步到的请假数据中找到当前人员的所有请假数据
+//                            List<LeaveSheet> list = leaveSheetService.list(new LambdaQueryWrapper<LeaveSheet>().eq(LeaveSheet::getOwnerId, beisen.get().getUserId()));
+//                            //当前考勤日期在工时同步到的请假数据开始请假和结束日期区间的数据
+//                            List<LeaveSheet> sheets = list.stream().filter(l -> (l.getStartDate().isBefore(localDate) || l.getStartDate().isEqual(localDate)) && (l.getEndDate().isAfter(localDate) || l.getEndDate().isEqual(localDate))).collect(Collectors.toList());
+//                            double sum = sheets.stream().mapToDouble(LeaveSheet::getTimeHours).sum();
+//                            if(sum>=8){
+//                                workTime= workTime-8;
+//                            }else {
+//                                workTime= workTime-sum;
+//                            }
+                        }
+                    }
+                    UserFvTime userFvTime=new UserFvTime();
+                    userFvTime.setWorkDate(localDate);
+                    userFvTime.setStartTime(df2.format(min));
+                    userFvTime.setEndTime(df2.format(max));
+                    userFvTime.setUserId(first.get().getId());
+                    userFvTime.setCompanyId(companyId);
+                    userFvTime.setWorkHours(workTime.floatValue());
+                    UserFvTime one = userFvTimeService.getOne(new LambdaQueryWrapper<UserFvTime>().eq(UserFvTime::getCompanyId, companyId).eq(UserFvTime::getUserId, first.get().getId()).eq(UserFvTime::getWorkDate, localDate));
+                    if(one!=null){
+                        userFvTime.setId(one.getId());
+                    }
+                    userFvTimeList.add(userFvTime);
+                }
+            }
+        }
+        if(userFvTimeList.size()>0){
+            if(!userFvTimeService.saveOrUpdateBatch(userFvTimeList)){
+                msg.setError("同步验证失败");
+            }
+        }
+        return msg;
+    }
+
+    public static double round( double num, double multipleOf) {
+        if (num%multipleOf == 0){
+            return num;
+        }
+        return Math.floor(num / multipleOf) * multipleOf;
+    }
 }

+ 1 - 254
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/task/TimingTask.java

@@ -2268,260 +2268,7 @@ public class TimingTask {
             startDate=LocalDate.now().minusDays(3).format(df);
             endDate=LocalDate.now().plusDays(1).format(df);
         }
-
-
-        List<User> userList = userMapper.selectList(new LambdaQueryWrapper<User>().eq(User::getCompanyId, 5978));
-        List<UserWithBeisen> userWithBeisenList = userWithBeisenService.list(new LambdaQueryWrapper<UserWithBeisen>().eq(UserWithBeisen::getCompanyId, 5978));
-        BeisenConfig beisenConfig = beisenConfigMapper.selectById(5978);
-        //获取特殊节假日设置
-        List<HolidaySetting> holidaySettings = holidaySettingService.list(new LambdaQueryWrapper<HolidaySetting>().eq(HolidaySetting::getCompanyId, 5978));
-        if(beisenConfig==null){
-            return;
-        }
-        //todo 获取到指定日期的加班数据
-        List<LocalDate> workDaysListInRange = WorkDayCalculateUtils.getWorkDaysListInRange(startDate, endDate, 1);
-        JSONArray allOverTimeList=new JSONArray();
-        JSONArray attendanceStatistics=new JSONArray();
-        JSONArray allVacationList=new JSONArray();
-        List<UserFvTime> userFvTimeList=new ArrayList<>();
-        List<LeaveSheet> leaveSheetList=new ArrayList<>();
-        for (LocalDate localDate : workDaysListInRange) {
-            JSONArray overTimeList = BeiSenUtils.getOverTimeList(df.format(localDate), beisenConfig.getAppKey(), beisenConfig.getAppSecret(), 1, 100);
-            //todo 获取到指定日期的考勤数据
-            JSONArray attendanceStatisticList = BeiSenUtils.getAttendanceStatistics(df.format(localDate), df.format(localDate), beisenConfig.getAppKey(), beisenConfig.getAppSecret(), 1, 100);
-            JSONArray vacationList = BeiSenUtils.getVacationList(df.format(localDate), beisenConfig.getAppKey(), beisenConfig.getAppSecret(),1,100);
-            allOverTimeList.addAll(overTimeList);
-            attendanceStatistics.addAll(attendanceStatisticList);
-            allVacationList.addAll(vacationList);
-        }
-        for (LocalDate localDate : workDaysListInRange) {
-            Stream<JSONObject> swipingCardsStream = attendanceStatistics.stream().map(item -> (JSONObject) item);
-            //todo: 获取当天的考勤数据
-            List<JSONObject> swipingCardDateList = swipingCardsStream.filter(i -> LocalDateTime.parse(i.getString("SwipingCardDate"),df1).toLocalDate().equals(localDate)).collect(Collectors.toList());
-            for (JSONObject item : swipingCardDateList) {
-                //获取当前数据下的人员工号对应到工时管家
-                String cardNumber = item.getString("CardNumber");
-                Optional<User> first = userList.stream().filter(f -> f.getJobNumber().equals(cardNumber)).findFirst();
-                //todo: 获取考勤打卡时间集合
-                JSONArray times = item.getJSONArray("Times");
-                Stream<JSONObject> timeStream = times.stream().map(time -> (JSONObject) time);
-                Stream<JSONObject> timeStream1 = times.stream().map(time -> (JSONObject) time);
-                //获取最早上班打卡时间
-                List<LocalTime> minLocalTimeList = timeStream.filter(t -> t.getIntValue("Type") == 1).map(i -> LocalDateTime.parse(i.getString("ActualTime"),df1).toLocalTime()).collect(Collectors.toList());
-                Optional<LocalTime> minOp = minLocalTimeList.stream().min(LocalTime::compareTo);
-                //获取最早上班打卡时间
-                List<LocalTime> maxLocalTimeList = timeStream1.filter(t -> t.getIntValue("Type") == 9).map(i -> LocalDateTime.parse(i.getString("ActualTime"),df1).toLocalTime()).collect(Collectors.toList());
-                Optional<LocalTime> maxOp = maxLocalTimeList.stream().max(LocalTime::compareTo);
-                //获取最晚下班时间
-                if(first.isPresent()){
-                    boolean workDay = WorkDayCalculateUtils.isWorkDay(localDate);
-                    //todo:针对景昱 工作日默认以8小时工作制度加上加班时长 非工作日以加班时长为准
-                    Double workTime;
-                    LocalTime min = minOp.get();
-                    LocalTime max = maxOp.get();
-                    Duration between = Duration.between(min,max);
-                    if(between.toHours()<=0){
-                        continue;
-                    }else {
-                        if(workDay){
-                            //去掉休息时长
-                            workTime=8.0;
-                        }else {
-                            //去掉休息时长
-                            workTime=0.0;
-                        }
-                    }
-                    Stream<JSONObject> overTimeStream = allOverTimeList.stream().map(elment -> (JSONObject) elment);
-                    Stream<JSONObject> vacationStream = allVacationList.stream().map(elment -> (JSONObject) elment);
-                    Optional<UserWithBeisen> beisen = userWithBeisenList.stream().filter(u -> u.getJobNumber() != null && u.getJobNumber().equals(first.get().getJobNumber())).findFirst();
-                    if(beisen.isPresent()){
-                        //todo:之前的逻辑
-//                        List<JSONObject> overTimeList = overTimeStream.filter(a -> a.getString("StaffId").equals(beisen.get().getUserId())
-//                                && (a.getIntValue("ApproveStatus") == 2||a.getIntValue("ApproveStatus") == 1)
-//                                &&LocalDateTime.parse(a.getString("StartDate"),df1).toLocalDate().isEqual(localDate)).collect(Collectors.toList());
-                        List<JSONObject> overTimeList = overTimeStream.filter(a -> a.getString("StaffId").equals(beisen.get().getUserId())
-                                && (a.getIntValue("ApproveStatus") == 2||a.getIntValue("ApproveStatus") == 1)).collect(Collectors.toList());
-                        //加班数据可能存在结束日期是当前日期的情况的情况
-                        BigDecimal overTimeBigDecimal= new BigDecimal(0);
-                        //计算加班时长 工作日打卡超过19:00:00算加班那 非工作日全天算加班
-                        if(workDay){
-                            //工作日打卡超过19:00:00算加班那 非工作日全天算加班
-                            if(max.isAfter(LocalTime.parse("19:00:00", df4))){
-                                overTimeBigDecimal = new BigDecimal(Duration.between(LocalTime.parse("18:00:00", df4),max).toMinutes());
-                            }
-                        }else {
-                            //非工作日全天 去掉休息时长 都算加班
-                            overTimeBigDecimal=new BigDecimal(Duration.between(min, max).toMinutes()) ;
-                            long rest1 = DateTimeUtil.calculateOverlap(min, max, LocalTime.parse("12:00:00", df4), LocalTime.parse("13:00:00", df4));
-                            long rest2 = DateTimeUtil.calculateOverlap(min, max, LocalTime.parse("17:30:00", df4), LocalTime.parse("18:00:00", df4));
-                            overTimeBigDecimal=overTimeBigDecimal.subtract(new BigDecimal(rest1)).subtract(new BigDecimal(rest2));
-                        }
-                        for (JSONObject o : overTimeList) {
-                            //存在开始日期为当前日期的数据以及结束日期为当天日期的数据 分开计算
-                            if(LocalDateTime.parse(o.getString("StartDate"),df1).toLocalDate().isEqual(localDate)){
-                                //存在开始日期为当天的数据
-                                if(LocalDateTime.parse(o.getString("StartDate"),df1).toLocalDate().isEqual(LocalDateTime.parse(o.getString("StopDate"),df1).toLocalDate())){
-                                    //开始日期和结束日期是相同的情况 说明是加班区间只存在于当天的情况
-                                    //对比打卡体现的加班时长和加班单时长取小
-                                    BigDecimal divide = overTimeBigDecimal.divide(new BigDecimal(60), 1, RoundingMode.HALF_DOWN);
-                                    if(divide.doubleValue()>o.getDouble("OverTimeDuration")){
-                                        //打卡获取到的加班时长大于加班单时长 需要在打卡体现的时长-打卡体现的加班时长+加班单时长
-                                        workTime=workTime+o.getDouble("OverTimeDuration");
-                                    }else{
-                                        workTime=workTime+round(divide.doubleValue(),0.5);
-                                    }
-                                }else {
-                                    //开始日期和结束日期是不相同的情况 说明是加班区间存在加班到第二天的情况
-                                    LocalDateTime start = LocalDateTime.parse(o.getString("StartDate"), df1);
-                                    LocalDateTime stop = start.toLocalDate().atTime(LocalTime.MAX);
-                                    Duration duration = Duration.between(start, stop);
-                                    BigDecimal decimal = new BigDecimal(duration.toMinutes());
-                                    decimal=decimal.divide(new BigDecimal(60),1,RoundingMode.HALF_DOWN);
-                                    double l = decimal.doubleValue();
-                                    //对比打卡体现的加班时长和加班单时长取小
-                                    BigDecimal divide = overTimeBigDecimal.divide(new BigDecimal(60), 1, RoundingMode.HALF_DOWN);
-                                    if(divide.doubleValue()>l){
-                                        //打卡获取到的加班时长大于加班单时长 需要在打卡体现的时长-打卡体现的加班时长+加班单时长
-                                        workTime=workTime+l;
-                                    }else {
-                                        workTime=workTime+round(divide.doubleValue(),0.5);
-                                    }
-                                }
-                            }else if(LocalDateTime.parse(o.getString("StopDate"),df1).toLocalDate().isEqual(localDate)){
-                                //存在结束日期为当天的数据
-                                if(LocalDateTime.parse(o.getString("StartDate"),df1).toLocalDate().isEqual(LocalDateTime.parse(o.getString("StopDate"),df1).toLocalDate())){
-                                    //开始日期和结束日期是相同的情况 说明是加班区间只存在于当天的情况
-                                    //判断打卡时间是不是大于19:00 通过打卡计算加班时长 与加班单作比较 取小
-                                    BigDecimal divide = overTimeBigDecimal.divide(new BigDecimal(60), 1, RoundingMode.HALF_DOWN);
-                                    if(divide.doubleValue()>o.getDouble("OverTimeDuration")){
-                                        //打卡获取到的加班时长大于加班单时长 需要在打卡体现的时长-打卡体现的加班时长+加班单时长
-                                        workTime=workTime+o.getDouble("OverTimeDuration");
-                                    }else {
-                                        workTime=workTime+round(divide.doubleValue(),0.5);
-                                    }
-                                }else {
-                                    //开始日期和结束日期是不相同的情况 说明是加班区间存在加班到第二天的情况
-                                    LocalDateTime stop = LocalDateTime.parse(o.getString("StopDate"), df1);
-                                    LocalDateTime start = stop.toLocalDate().atTime(LocalTime.MIN);
-                                    Duration duration = Duration.between(start, stop);
-                                    BigDecimal decimal = new BigDecimal(duration.toMinutes());
-                                    decimal=decimal.divide(new BigDecimal(60),1,RoundingMode.HALF_DOWN);
-                                    double l = decimal.doubleValue();
-                                    //对比打卡体现的加班时长和加班单时长取小
-                                    BigDecimal divide = overTimeBigDecimal.divide(new BigDecimal(60), 1, RoundingMode.HALF_DOWN);
-                                    if(divide.doubleValue()>l){
-                                        //打卡获取到的加班时长大于加班单时长 需要在打卡体现的时长-打卡体现的加班时长+加班单时长
-                                        workTime=workTime+l;
-                                    }else {
-                                        workTime=workTime+round(divide.doubleValue(),0.5);
-                                    }
-                                }
-                            }
-                        }
-                        List<JSONObject> vacationList = vacationStream.filter(a ->{
-                            LocalDate vacationStartDate = LocalDateTime.parse(a.getString("VacationStartDateTime"), df3).toLocalDate();
-                            LocalDate vacationStopDate = LocalDateTime.parse(a.getString("VacationStopDateTime"), df3).toLocalDate();
-                            boolean b=false;
-                            if((localDate.isAfter(vacationStartDate)||localDate.isEqual(vacationStartDate))
-                                    &&(localDate.isBefore(vacationStopDate)||localDate.isEqual(vacationStopDate))){
-                                b=true;
-                            }
-                            if(a.getString("StaffId").equals(beisen.get().getUserId())
-                                    && b
-                                    &&a.getString("DocumentType").equals("请假")
-                                    &&  (a.getString("ApproveStatus").equals("通过") || a.getString("ApproveStatus").equals("审批中"))){
-                                return true;
-                            }
-                            return false;
-                        }).collect(Collectors.toList());
-                        if(vacationList.size()>0){
-                            double vacationDuration = vacationList.stream().mapToDouble(i -> i.getDouble("VacationDuration")).sum();
-                            BigDecimal decimal = new BigDecimal(vacationDuration);
-                            decimal=decimal.divide(new BigDecimal(60),1,RoundingMode.HALF_DOWN);
-//                            //可能存在休假多天 只减去一天
-                            if(decimal.doubleValue()>=8){
-                                workTime= workTime-8;
-                            }else {
-                                workTime= workTime-decimal.doubleValue();
-                            }
-                        }
-                    }
-                    UserFvTime userFvTime=new UserFvTime();
-                    userFvTime.setWorkDate(localDate);
-                    userFvTime.setStartTime(df2.format(min));
-                    userFvTime.setEndTime(df2.format(max));
-                    userFvTime.setUserId(first.get().getId());
-                    userFvTime.setCompanyId(5978);
-                    userFvTime.setWorkHours(workTime.floatValue());
-                    UserFvTime one = userFvTimeService.getOne(new LambdaQueryWrapper<UserFvTime>().eq(UserFvTime::getCompanyId, 5978).eq(UserFvTime::getUserId, first.get().getId()).eq(UserFvTime::getWorkDate, localDate));
-                    if(one!=null){
-                        userFvTime.setId(one.getId());
-                    }
-                    userFvTimeList.add(userFvTime);
-                }
-            }
-        }
-        if(userFvTimeList.size()>0){
-            userFvTimeService.saveOrUpdateBatch(userFvTimeList);
-        }
-        //同步休假数据到工时管家
-        for (int i = 0; i < allVacationList.size(); i++) {
-            JSONObject jsonObject = allVacationList.getJSONObject(i);
-            Optional<UserWithBeisen> beisen = userWithBeisenList.stream().filter(b -> b.getUserId().equals(jsonObject.getString("StaffId"))).findFirst();
-            if(beisen.isPresent()){
-                Optional<User> first = userList.stream().filter(u -> u.getJobNumber().equals(beisen.get().getJobNumber())).findFirst();
-                if(first.isPresent()){
-                    LeaveSheet leaveSheet=new LeaveSheet();
-                    leaveSheet.setCompanyId(beisenConfig.getCompanyId());
-                    leaveSheet.setStatus(0);
-                    leaveSheet.setOwnerId(first.get().getId());
-                    leaveSheet.setOwnerName(first.get().getName());
-                    leaveSheet.setStartDate(LocalDateTime.parse(String.valueOf(jsonObject.get("VacationStartDateTime")),df3).toLocalDate());
-                    leaveSheet.setEndDate(LocalDateTime.parse(String.valueOf(jsonObject.get("VacationStopDateTime")),df3).toLocalDate());
-                    leaveSheet.setTimeType(1);
-                    leaveSheet.setTimeDays(jsonObject.getFloatValue("DayValueOfDuration"));
-                    leaveSheet.setTimeHours(jsonObject.getFloatValue("VacationDuration")/60);
-                    Integer leaveType;
-                    switch (jsonObject.getString("VacationType")){
-                        case "事假":leaveType=0;
-                            break;
-                        case "病假":leaveType=1;
-                            break;
-                        case "年假":leaveType=2;
-                            break;
-                        case "产假":leaveType=3;
-                            break;
-                        case "婚假":leaveType=4;
-                            break;
-                        case "丧假":leaveType=5;
-                            break;
-                        case "调休":leaveType=6;
-                            break;
-                        case "陪产假":leaveType=7;
-                            break;
-                        default:leaveType=8;
-                    }
-                    leaveSheet.setLeaveType(leaveType);
-                    leaveSheet.setRemark(jsonObject.getString("Reason"));
-                    leaveSheet.setStatus(jsonObject.getString("ApproveStatus").equals("通过")?0:jsonObject.getString("ApproveStatus").equals("审批中")?1:2);
-                    leaveSheet.setProcinstId(jsonObject.getString("VacationId"));
-                    LeaveSheet one = leaveSheetService.getOne(new LambdaQueryWrapper<LeaveSheet>().eq(LeaveSheet::getOwnerId, first.get().getId()).eq(LeaveSheet::getStartDate, leaveSheet.getStartDate()).eq(LeaveSheet::getProcinstId,leaveSheet.getProcinstId()).eq(LeaveSheet::getEndDate, leaveSheet.getEndDate()));
-                    if(one==null){
-                        leaveSheetList.add(leaveSheet);
-                    }
-                }
-            }
-        }
-        if(leaveSheetList.size()>0){
-            leaveSheetService.saveOrUpdateBatch(leaveSheetList);
-        }
-    }
-
-    public static double round( double num, double multipleOf) {
-        if (num%multipleOf == 0){
-            return num;
-        }
-        return Math.floor(num / multipleOf) * multipleOf;
+        userWithBeisenService.syncAttendanceFromBeisen(startDate,endDate,5978);
     }
 
 

+ 46 - 1
fhKeeper/formulahousekeeper/management-platform/src/main/resources/mapper/ProjectMapper.xml

@@ -1915,7 +1915,11 @@
         LEFT JOIN department d ON d.department_id=u.department_id
         LEFT JOIN (
         SELECT SUM(working_time) AS realHour,SUM(cost) AS realCost,(SUM(working_time)-SUM(overtime_hours)) AS normalHour,SUM(overtime_hours) AS overHour,group_id,dept_id
-        FROM report  WHERE state=1 <if test="startDate!=null and startDate!='' and endDate!=null and endDate!=''"> AND create_date BETWEEN #{startDate} AND #{endDate} </if>AND project_id IS NOT NULL AND company_id=#{companyId} GROUP BY group_id,dept_id) r ON r.group_id=tg.`id` and r.dept_id=u.department_id
+        FROM report  WHERE state=1
+        <if test="startDate!=null and startDate!='' and endDate!=null and endDate!=''">
+         AND create_date BETWEEN #{startDate} AND #{endDate}
+        </if>
+        AND project_id IS NOT NULL AND company_id=#{companyId} GROUP BY group_id,dept_id) r ON r.group_id=tg.`id` and r.dept_id=u.department_id
         WHERE u.company_id=#{companyId}
         AND tg.name IN ('生产部电气','生产部车间','工程部现场安装施工','工程部配合调试','研发部工艺设计','研发部结构设计','研发部BIM设计','研发部电气设计','研发部工艺调试验收','研发部电气调试验收')
         <if test="userId!=null and userId!=''">
@@ -1924,6 +1928,47 @@
         GROUP BY p.id,tg.id,d.department_id ORDER BY p.id,d.department_id
     </select>
 
+    <select id="groupExpendProcessListForChart" resultType="java.util.Map">
+        SELECT groupName,SUM(realHour) AS realHour,SUM(realCost) AS realCost,SUM(normalHour) AS normalHour,SUM(overHour) AS overHour,SUM(planHour) AS planHour,SUM(afterSetPlanHour) AS afterSetPlanHour
+         FROM   (SELECT p.project_name AS projectName,p.id AS projectId,tg.id AS groupId,d.department_name,d.department_id AS deptId,d.corpwx_deptid AS corpwxDeptId,tg.name AS groupName,
+        IFNULL(r.realHour,0) AS realHour,IFNULL(r.realCost,0) AS realCost,IFNULL(r.normalHour,0) AS normalHour,IFNULL(r.overHour,0) AS overHour,
+        IFNULL(tg.man_day*8,0) AS planHour,IFNULL((SELECT SUM(change_man_day*8) FROM `group_budget_review` WHERE group_id=tg.`id` AND `status`=1),0) AS afterSetPlanHour
+        FROM task_executor te
+        LEFT JOIN task t ON t.id=te.task_id
+        LEFT JOIN `user` u ON te.executor_id=u.id
+        LEFT JOIN task_group tg ON tg.id=t.group_id
+        LEFT JOIN project p ON p.id=tg.project_id
+        LEFT JOIN department d ON d.department_id=u.department_id
+        LEFT JOIN (
+        SELECT SUM(working_time) AS realHour,SUM(cost) AS realCost,(SUM(working_time)-SUM(overtime_hours)) AS normalHour,SUM(overtime_hours) AS overHour,group_id,dept_id
+        FROM report  WHERE state=1
+        <if test="startDate!=null and startDate!='' and endDate!=null and endDate!=''">
+            AND create_date BETWEEN #{startDate} AND #{endDate}
+        </if>
+        AND project_id IS NOT NULL AND company_id=#{companyId} GROUP BY group_id,dept_id) r ON r.group_id=tg.`id`
+        WHERE u.company_id=#{companyId}
+        <if test="listThird!=null and listThird.size()>0">
+            AND tg.project_id in
+            <foreach collection="listThird" separator="," open="(" close=")" item="item">
+                #{item}
+            </foreach>
+        </if>
+        AND tg.name IN ('生产部电气','生产部车间','工程部现场安装施工','工程部配合调试','研发部工艺设计','研发部结构设计','研发部BIM设计','研发部电气设计','研发部工艺调试验收','研发部电气调试验收')
+        <if test="userId!=null and userId!=''">
+            and t.executor_id=#{userId}
+        </if>
+        GROUP BY tg.id ORDER BY p.id,d.department_id) AS t
+        <where>
+            <if test="listFour!=null and listFour.size()>0">
+                t.groupName in
+                <foreach collection="listFour" close=")" open="(" separator="," item="item">
+                    #{item}
+                </foreach>
+            </if>
+        </where>
+         GROUP BY t.groupName
+    </select>
+
     <select id="projectExpendProcessList" resultType="java.util.Map">
         select p.id AS projectId,p.project_name as projectName,DATE_FORMAT(p.`plan_start_date`,'%Y-%m-%d') AS planStartDate,DATE_FORMAT(p.`plan_end_date`,'%Y-%m-%d') AS planEndDate,pc.name as categoryName,p.project_code as projectCode,IFNULL(SUM(te.plan_hours),0) as planHour,
         IFNULL((select SUM(working_time) from report where project_id=p.id and create_date BETWEEN #{startDate} AND #{endDate} and state=1),0) as realHour, IFNULL((select SUM(cost) from report where project_id=p.id and create_date BETWEEN #{startDate} AND #{endDate} and state=1),0) as realCost,