Browse Source

Merge remote-tracking branch 'origin/master'

Guo1B0 9 months ago
parent
commit
6c0432f371
21 changed files with 764 additions and 575 deletions
  1. 11 1
      fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/service/impl/TaskServiceImpl.java
  2. 2 1
      fhKeeper/formulahousekeeper/management-crm/src/main/resources/mapper/TaskMapper.xml
  3. 1 1
      fhKeeper/formulahousekeeper/management-platform-import/src/main/java/com/management/platform/service/impl/ReportServiceImpl.java
  4. 2 2
      fhKeeper/formulahousekeeper/management-platform-import/src/main/resources/application.yml
  5. 6 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/ProjectController.java
  6. 32 287
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/UserWithBeisenController.java
  7. 14 1
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/TimeType.java
  8. 2 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/mapper/ProjectMapper.java
  9. 2 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/ProjectService.java
  10. 2 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/UserWithBeisenService.java
  11. 61 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/ProjectServiceImpl.java
  12. 54 15
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/ReportServiceImpl.java
  13. 314 1
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/UserWithBeisenServiceImpl.java
  14. 1 254
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/task/TimingTask.java
  15. 1 1
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/util/MessageUtils.java
  16. 46 1
      fhKeeper/formulahousekeeper/management-platform/src/main/resources/mapper/ProjectMapper.xml
  17. 3 1
      fhKeeper/formulahousekeeper/management-platform/src/main/resources/mapper/TimeTypeMapper.xml
  18. 1 1
      fhKeeper/formulahousekeeper/timesheet/index.html
  19. 59 0
      fhKeeper/formulahousekeeper/timesheet/src/components/echartsEchar.vue
  20. 87 0
      fhKeeper/formulahousekeeper/timesheet/src/views/corpreport/echartsData.js
  21. 63 8
      fhKeeper/formulahousekeeper/timesheet/src/views/corpreport/list.vue

+ 11 - 1
fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/service/impl/TaskServiceImpl.java

@@ -280,6 +280,15 @@ public class TaskServiceImpl extends ServiceImpl<TaskMapper, Task> implements Ta
         Task task = taskMapper.selectById(taskDto.getId());
         updateTaskRepeatConfigure(task);//将任务中之前的关于重复日期相关的置空
         taskMapper.updateRepeatConfig(task);
+        //根据任务的开始时间与当下时间判断任务的状态
+        if (taskDto.getStartDate()!=null&&taskDto.getStartDate().isAfter(LocalDateTime.now())){
+            task.setStatus(0);
+        }else if (taskDto.getEndDate()!=null&&taskDto.getEndDate().isBefore(LocalDateTime.now())){
+            task.setStatus(3);
+        } else if (taskDto.getStartDate()!=null&&taskDto.getStartDate().isBefore(LocalDateTime.now())&&taskDto.getEndDate()!=null&&taskDto.getEndDate().isAfter(LocalDateTime.now()))
+        {
+            task.setStatus(1);
+        }
         BeanUtils.copyProperties(taskDto,task);
         taskMapper.updateById(task);
 
@@ -1187,7 +1196,8 @@ public class TaskServiceImpl extends ServiceImpl<TaskMapper, Task> implements Ta
 
     public void updateTaskRepeatConfigure(Task task){
         task.setRepeatType(null).setRepeatEndNever(null).setRepeatEndCount(null)
-                .setRepeatEndDate(null).setRepeatDesignDay(null).setRepeatDesignSameday(null);
+                .setRepeatEndDate(null).setRepeatDesignDay(null).setRepeatDesignSameday(null)
+                .setCustomId(null).setBusinessOpportunityId(null).setOrderId(null).setClueId(null).setContactsId(null);
     }
 
 

+ 2 - 1
fhKeeper/formulahousekeeper/management-crm/src/main/resources/mapper/TaskMapper.xml

@@ -271,7 +271,8 @@
         update task
         <set>
             repeat_type=#{repeatType},repeat_end_never=#{repeatEndNever},repeat_end_count=#{repeatEndCount},
-            repeat_end_date=#{repeatEndDate},repeat_design_day=#{repeatDesignDay},repeat_design_sameday=#{repeatDesignSameday}
+            repeat_end_date=#{repeatEndDate},repeat_design_day=#{repeatDesignDay},repeat_design_sameday=#{repeatDesignSameday},
+            custom_id=#{customId},business_opportunity_id=#{businessOpportunityId},order_id=#{orderId},clue_id=#{clueId},contacts_id=#{contactsId}
         </set>
         where id=#{id}
     </update>

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

@@ -3987,7 +3987,7 @@ public class ReportServiceImpl extends ServiceImpl<ReportMapper, Report> impleme
                     }
                     Optional<SubProject> subProject = allSubProjectList.stream().filter(al -> al.getName().equals(row.getCell(4).getStringCellValue())&&al.getProjectId().equals(project.get().getId())).findFirst();
                     if(!subProject.isPresent()){
-                        msg.setError("子项目["+subProject.get().getName()+"]不属于项目["+project.get().getProjectName()+"]");
+                        msg.setError("子项目["+row.getCell(4).getStringCellValue()+"]不属于项目["+project.get().getProjectName()+"]");
                         return msg;
                     }
                     subP=subProject.get();

+ 2 - 2
fhKeeper/formulahousekeeper/management-platform-import/src/main/resources/application.yml

@@ -15,9 +15,9 @@ spring:
       location: C:/upload/
   datasource:
     driver-class-name: com.mysql.cj.jdbc.Driver
-    url: jdbc:mysql://47.101.180.183:3306/man_import?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8&rewriteBatchedStatements=true&useSSL=false
+    url: jdbc:mysql://47.101.180.183:17089/man_import?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8&rewriteBatchedStatements=true&useSSL=false
     username: root
-    password: HuoshiDB@2022
+    password: P011430@Huoshi*
     hikari:
       maximum-pool-size: 60
       minimum-idle: 10

+ 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());

+ 14 - 1
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/TimeType.java

@@ -17,7 +17,7 @@ import lombok.experimental.Accessors;
  * </p>
  *
  * @author Seyason
- * @since 2024-06-22
+ * @since 2024-07-24
  */
 @Data
 @EqualsAndHashCode(callSuper = false)
@@ -598,6 +598,19 @@ public class TimeType extends Model<TimeType> {
     @TableField(exist = false)
     private Integer saasSyncContact;
 
+    /**
+     * 日报第二审核人;在reportAuditType5时有效
+     */
+    @TableField("second_auditor")
+    private String secondAuditor;
+
+    /**
+     * 日报第三审核人;在reportAuditType5时有效
+     */
+    @TableField("third_auditor")
+    private String thirdAuditor;
+
+
     @Override
     protected Serializable pkVal() {
         return this.companyId;

+ 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;
+    }
 }

+ 54 - 15
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/ReportServiceImpl.java

@@ -2137,6 +2137,9 @@ public class ReportServiceImpl extends ServiceImpl<ReportMapper, Report> impleme
                 boolean hasAuditAllPri = sysFunctionService.hasPriviledge(user.getRoleId(), "审核全员日报");
                 List<Report> reportList = reportMapper.selectList(new QueryWrapper<Report>().select("id, state, group_audit_state, creator_id, create_date, project_id,audit_dept_managerid,department_audit_state, project_auditor_id, is_dept_audit").in("id", ids));
                 Integer onlyAuditOnce = userMapper.selectById(reportList.get(0).getCreatorId()).getOnlyAuditOnce();
+                //5情况下,可能设置了第二和第三审核人
+                String secondAuditor = timeType.getSecondAuditor();
+                String thirdAuditor = timeType.getThirdAuditor();
                 for (Report r : reportList) {
                     //直属领导审核或者部门负责人审核
                     Report newReport = new Report();
@@ -2144,9 +2147,25 @@ public class ReportServiceImpl extends ServiceImpl<ReportMapper, Report> impleme
                     if (timeType.getReportAuditType() == 5) {
                         if(hasAuditAllPri || ((r.getIsDeptAudit() == 0 &&  user.getId().equals(r.getProjectAuditorId()))
                                 || (r.getIsDeptAudit() == 1 && user.getId().equals(r.getAuditDeptManagerid())))){
-                            newReport.setState(1);
-                            newReport.setDepartmentAuditState(1);
-                            newReport.setProjectAuditState(1);
+                            if (thirdAuditor != null && secondAuditor != null) {
+                                if (user.getId().equals(thirdAuditor)) {
+                                    //当前为第三审核人在审核,直接通过
+                                    newReport.setState(1);
+                                    newReport.setDepartmentAuditState(1);
+                                    newReport.setProjectAuditState(1);
+                                } else if (user.getId().equals(secondAuditor)) {
+                                    newReport.setIsDeptAudit(0);
+                                    newReport.setProjectAuditorId(thirdAuditor);
+                                } else {
+                                    //第一层审核,转给第二审核人
+                                    newReport.setIsDeptAudit(0);
+                                    newReport.setProjectAuditorId(secondAuditor);
+                                }
+                            } else {
+                                newReport.setState(1);
+                                newReport.setDepartmentAuditState(1);
+                                newReport.setProjectAuditState(1);
+                            }
                             newReport.setProjectAuditTime(LocalDateTime.now());
                         }else {
                             httpRespMsg.setError("您无权审核该日报");
@@ -2734,12 +2753,7 @@ public class ReportServiceImpl extends ServiceImpl<ReportMapper, Report> impleme
             Integer roleId = user.getRoleId();
             boolean canAuditAllReport = sysFunctionService.hasPriviledge(roleId, "审核全员日报");
             boolean isDirectAudit = false;
-            String reporterSuperiorId = userMapper.selectById(oneReport.getCreatorId()).getSuperiorId();
-            if(reporterSuperiorId!=null && reporterSuperiorId.equals(user.getId().toString())){
-                isDirectAudit = true;
-            }
-
-            if(!(isDirectAudit  || (reporterSuperiorId == null && user.getId().equals(oneReport.getAuditDeptManagerid())) || canAuditAllReport)){
+            if (!(canAuditAllReport || user.getId().equals(oneReport.getProjectAuditorId()) || user.getId().equals(oneReport.getAuditDeptManagerid()))) {
                 httpRespMsg.setError("您无权操作权限");
                 return httpRespMsg;
             }
@@ -3436,6 +3450,8 @@ public class ReportServiceImpl extends ServiceImpl<ReportMapper, Report> impleme
                 //人员所属部门负责人审核或者直属领导审核
                 boolean hasAuditAllPri = sysFunctionService.hasPriviledge(user.getRoleId(), "审核全员日报");
                 List<Report> reportList = reportMapper.selectList(new QueryWrapper<Report>().select("id, state, group_audit_state, creator_id, create_date, project_id,audit_dept_managerid,department_audit_state, project_auditor_id, is_dept_audit").in("id", ids));
+                String secondAuditor = timeType.getSecondAuditor();
+                String thirdAuditor = timeType.getThirdAuditor();
                 allReports = reportList;
                 for (Report r : reportList) {
                     //直属领导审核或者部门负责人审核
@@ -3444,13 +3460,36 @@ public class ReportServiceImpl extends ServiceImpl<ReportMapper, Report> impleme
                     if (timeType.getReportAuditType() == 5) {
                         if(hasAuditAllPri || ((r.getIsDeptAudit() == 0 &&  user.getId().equals(r.getProjectAuditorId()))
                                 || (r.getIsDeptAudit() == 1 && user.getId().equals(r.getAuditDeptManagerid())))){
-                            r.setState(1);
-                            r.setDepartmentAuditState(1);
-                            r.setProjectAuditState(1);
+                            if (thirdAuditor != null && secondAuditor != null) {
+                                if (user.getId().equals(thirdAuditor)) {
+                                    //当前为第三审核人在审核,直接通过
+                                    r.setState(1);
+                                    r.setDepartmentAuditState(1);
+                                    r.setProjectAuditState(1);
+                                    newReport.setState(1);
+                                    newReport.setDepartmentAuditState(1);
+                                    newReport.setProjectAuditState(1);
+                                } else if (user.getId().equals(secondAuditor)) {
+                                    r.setIsDeptAudit(0);
+                                    r.setProjectAuditorId(thirdAuditor);
+                                    newReport.setIsDeptAudit(0);
+                                    newReport.setProjectAuditorId(thirdAuditor);
+                                } else {
+                                    //第一层审核,转给第二审核人
+                                    r.setIsDeptAudit(0);
+                                    r.setProjectAuditorId(secondAuditor);
+                                    newReport.setIsDeptAudit(0);
+                                    newReport.setProjectAuditorId(secondAuditor);
+                                }
+                            } else {
+                                r.setState(1);
+                                r.setDepartmentAuditState(1);
+                                r.setProjectAuditState(1);
+                                newReport.setState(1);
+                                newReport.setDepartmentAuditState(1);
+                                newReport.setProjectAuditState(1);
+                            }
                             r.setProjectAuditTime(LocalDateTime.now());
-                            newReport.setState(1);
-                            newReport.setDepartmentAuditState(1);
-                            newReport.setProjectAuditState(1);
                             newReport.setProjectAuditTime(LocalDateTime.now());
                         } else {
                             httpRespMsg.setError("您无权审核该日报");

+ 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);
     }
 
 

+ 1 - 1
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/util/MessageUtils.java

@@ -21,7 +21,7 @@ public class MessageUtils {
     public static String message(String code, Object... args) {
         MessageSource messageSource = SpringUtils.getBean(MessageSource.class);
         Locale locale = LocaleContextHolder.getLocale();
-//        System.out.println("本地为:" +locale.getDisplayName()+", code="+code);
+        System.out.println("本地为:" +locale.getDisplayName()+", code="+code);
         return messageSource.getMessage(code, args, locale);
     }
 

+ 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,

File diff suppressed because it is too large
+ 3 - 1
fhKeeper/formulahousekeeper/management-platform/src/main/resources/mapper/TimeTypeMapper.xml


+ 1 - 1
fhKeeper/formulahousekeeper/timesheet/index.html

@@ -2,7 +2,7 @@
 <html>
   <head>
     <meta charset="utf-8" />
-    <meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">
+    <!-- <meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests"> -->
     <!-- 尝试清除打包缓存 -->
     <!-- <meta http-equiv="pragram" content="no-cache">
         <meta http-equiv="cache-control" content="no-cache, no-store, must-revalidate">

+ 59 - 0
fhKeeper/formulahousekeeper/timesheet/src/components/echartsEchar.vue

@@ -0,0 +1,59 @@
+<template>
+  <div :id="uuid" :style="style"></div>
+</template>
+
+<script>
+import * as echarts from "echarts";
+export default {
+  props: {
+    height: {
+      type: String,
+      default: "100%",
+    },
+    width: {
+      type: String,
+      default: "100%",
+    },
+    options: {
+      type: Object,
+      default: null,
+    },
+  },
+  components: {},
+  data() {
+    return {
+      uuid: null,
+      myChart: null,
+    };
+  },
+  computed: {
+    style() {
+      return {
+        height: this.height,
+        width: this.width,
+      };
+    },
+  },
+  watch: {
+    options() {
+      if (this.myChart) {
+        this.myChart.setOption(this.options);
+      }
+    },
+  },
+  created() {
+    this.uuid = this.idGen();
+  },
+  mounted() {
+    this.myChart = echarts.init(document.getElementById(this.uuid));
+    this.myChart.setOption(this.options);
+  },
+  methods: {
+    idGen() {
+      return new Date().getTime();
+    },
+  },
+};
+</script>
+
+<style scoped lang="scss"></style>

+ 87 - 0
fhKeeper/formulahousekeeper/timesheet/src/views/corpreport/echartsData.js

@@ -0,0 +1,87 @@
+export function getGroupConsumption(nameList = [], actualPlan = [], actualSupplement = [], summary = [], realHourList = []) {
+  let num1 = actualPlan.reduce((accumulator, currentValue) => accumulator + currentValue, 0)
+  let num2 = actualSupplement.reduce((accumulator, currentValue) => accumulator + currentValue, 0)
+  let num3 = realHourList.reduce((accumulator, currentValue) => accumulator + currentValue, 0)
+  return {
+    title: {
+      text: `求和项:合计工时:${num3}(h) 实际工时: ${num1}(h)  实际增补: ${num2}(h)`,
+      top: 20
+    },
+    tooltip: {},
+    toolbox: {},
+    grid: {
+      top: 80,
+      left: 80,
+      right: 80,
+      bottom: 120,
+    },
+    legend: {
+      data: ["实际计划", "实际增补", "汇总"],
+      top: 20,
+      right: 100
+    },
+    xAxis: [
+      {
+        data: nameList,
+        axisPointer: {
+          type: "shadow",
+        },
+        axisLabel: {
+          rotate: 45,
+        },
+      },
+    ],
+    yAxis: [
+      {
+        type: "value",
+        axisLabel: {
+          formatter: "{value} (h)",
+        },
+      },
+      {
+        type: "value",
+        axisLabel: {
+          formatter: "{value} (h)",
+        },
+      },
+    ],
+    series: [
+      {
+        name: "实际计划",
+        type: "bar",
+        stack: "one",
+        barWidth: 40,
+        itemStyle: {
+          normal: {
+            color: "#5B9BD5",
+          },
+        },
+        data: actualPlan,
+      },
+      {
+        name: "实际增补",
+        type: "bar",
+        stack: "one",
+        barWidth: 40,
+        itemStyle: {
+          normal: {
+            color: "#ED7D31",
+          },
+        },
+        data: actualSupplement,
+      },
+      {
+        name: "汇总",
+        type: "line",
+        yAxisIndex: 1,
+        lineStyle: {
+          normal: {
+            width: 3,
+            color: "#5B9BD5",
+          },
+        },
+        data: summary,
+      },
+    ],
+  }
+}

+ 63 - 8
fhKeeper/formulahousekeeper/timesheet/src/views/corpreport/list.vue

@@ -119,7 +119,7 @@
         </template>
 
         <template v-if="ins == 24">
-          <el-radio-group v-model="tabPosition">
+          <el-radio-group v-model="tabPosition" size="small" @input="getGroupConsumptionData">
             <el-radio-button label="0">表格</el-radio-button>
             <el-radio-button label="1">柱状图</el-radio-button>
           </el-radio-group>
@@ -139,6 +139,10 @@
           </el-option>
         </el-select>
 
+        <el-select v-if="ins == 24 && tabPosition == 1" v-model="groupConsumptionName" placeholder="'请选择任务分组'" clearable filterable size="small" @change="getList(true)" multiple collapse-tags style="margin-left:10px; width: 250px">
+          <el-option v-for="(item, index) in groupConsumptionList" :key="item.id" :label="item" :value="item"> </el-option>
+        </el-select>
+
         <!-- 任务分组 -->
         <el-select v-if="ins == 1 && user.companyId == '3092'" v-model="projectGroupId" :placeholder="$t('defaultText.pleaseSelectaTaskGroup')" clearable filterable size="small" @change="getList(true)" style="margin-left:10px">
           <el-option v-for="(item) in projectTaskgroupList" :key="item.id" :label="item.name" :value="item.id"></el-option>
@@ -1168,7 +1172,7 @@
             </el-table>
 
             <!-- 分组耗用进度表 -->
-            <el-table  v-if="ins == 24 && this.tabPosition==0" :key="24" border :data="isbeCustomReport.consumptionSchedule" highlight-current-row v-loading="listLoading" :height="(+tableHeight - 0) - 1" style="width: 100%;" :span-method="objectSpanMethod">
+            <el-table  v-if="ins == 24 && tabPosition==0" :key="24" border :data="isbeCustomReport.consumptionSchedule" highlight-current-row v-loading="listLoading" :height="(+tableHeight - 0) - 1" style="width: 100%;" :span-method="objectSpanMethod">
               <el-table-column align="center" prop="projectName" :label="$t('headerTop.projectName')" min-width="200"></el-table-column>
               <el-table-column align="center" prop="department_name" :label="$t('fuZeBuMen')" min-width="150">
                 <template slot-scope="scope">
@@ -1195,6 +1199,11 @@
               <el-table-column align="center" prop="process" :label="$t('gongShiHaoYongShuai')" width="150"></el-table-column>
             </el-table>
 
+            <!-- 分组耗用进度图表 -->
+            <div v-if="ins == 24 && tabPosition!=0" class="useASchedule" :style="`height:${tableHeight + 50}px`" v-loading="groupConsumptionLoading">
+              <EchartsEchar :options="groupConsumptionOption"></EchartsEchar>
+            </div>
+
             <!-- 项目耗用进度表 -->
             <el-table  v-if="ins == 25" :key="25" border :data="isbeCustomReport.consumptionScheduleTwo" highlight-current-row v-loading="listLoading" :height="(+tableHeight) - 1" style="width: 100%;" >
               <el-table-column align="center" prop="projectName" :label="$t('headerTop.projectName')" min-width="220"></el-table-column>
@@ -1321,7 +1330,7 @@
               <el-table-column align="center" prop="onTimePercent" :label="$t('anShiWanChengShuai')" min-width="150"></el-table-column>
             </el-table>
         <!--工具条-->
-        <el-col :span="24" class="toolbar" v-if="ins != 6 && ins != 20 && ins != 21 && this.tabPosition==0">
+        <el-col :span="24" class="toolbar" v-if="ins != 6 && ins != 20 && ins != 21 && tabPosition==0">
           <el-pagination
                 v-if="ins == 12"
                 @size-change="groupSizeChange"
@@ -1637,12 +1646,15 @@
 import selectCat from "@/components/select.vue"
 // 引入自定义级联组件
 import vueCascader from "@/components/cascader.vue"
+import EchartsEchar from "@/components/echartsEchar.vue"
+import { getGroupConsumption } from "./echartsData"
 
 export default {
   name: "expense",
   components: {
     selectCat,
-    vueCascader
+    vueCascader,
+    EchartsEchar
   },
   props: {},
   data() {
@@ -1868,7 +1880,14 @@ export default {
       writeOffOperationVisable: false,
       writeOffOperationTransitionData: {},
       writeOffStatus: '',
-      tabPosition:"0"
+      tabPosition:"0",
+
+      // 分组耗用进度图表
+      groupConsumptionOption: {},
+      groupConsumptionLoading: false,
+      groupConsumptionList: ['工程部现场安装施工', '工程部配合调试', '生产部电气', '生产部车间', '研发部BIM设计', '研发部工艺设计', '研发部工艺调试验收', '研发部电气设计', '研发部电气调试验收', '研发部结构设计'],
+      groupConsumptionName: [],
+      groupConsumptionTimer: null
     };
   },
   computed: {},
@@ -2326,7 +2345,11 @@ export default {
                   this.getProjectSchedule()
                 }
                 if(this.ins == 24) {
-                  this.getConsumptionSchedule()
+                  if(this.tabPosition == 1) {
+                    this.getGroupConsumptionData()
+                  } else {
+                    this.getConsumptionSchedule()
+                  }
                 }
                 if(this.ins == 25) {
                   this.getConsumptionScheduleTwo()
@@ -3696,7 +3719,11 @@ export default {
         this.getProjectSchedule()
       }
       if(this.ins == 24) {
-        this.getConsumptionSchedule()
+        if(this.tabPosition == 1) {
+          this.getGroupConsumptionData()
+        } else {
+          this.getConsumptionSchedule()
+        }
       }
       if(this.ins == 25) {
         this.page=1
@@ -4259,6 +4286,32 @@ export default {
         this.writeOffOperationVisable = false
       }
       this.getList(6)
+    },
+
+    getGroupConsumptionData() {
+      if(this.groupConsumptionTimer) {
+        clearTimeout(this.groupConsumptionTimer)
+      }
+      this.groupConsumptionTimer = setTimeout(async () => {
+        if(this.tabPosition == 0) {
+          this.proJuctId = ''
+          return
+        }
+        this.groupConsumptionLoading = true
+        let { data } = await this.postData('/project/groupExpendProcessListForChart', {
+          startDate: this.rangeDatas[0],
+          endDate: this.rangeDatas[1],
+          projectIds: this.proJuctId,
+          groupNames: this.groupConsumptionName.join(',')
+        })
+        this.groupConsumptionLoading = false
+        let nameList = data.map(item => (item.groupName || ''))
+        let realHourList = data.map(item => (item.realHour || 0))
+        let actualPlan = data.map(item => (item.planHour || 0))
+        let actualSupplement = data.map(item => (item.afterSetPlanHour || 0))
+        let summary = data.map(item => (item.planHour || 0) + (item.afterSetPlanHour || 0))
+        this.groupConsumptionOption = getGroupConsumption(nameList, actualPlan, actualSupplement, summary, realHourList)
+      }, 500)
     }
   },
 };
@@ -4488,5 +4541,7 @@ export default {
 .warntext{
   color:red;
 }
-
+.useASchedule {
+  width: 100%;
+}
 </style>