|
@@ -60,6 +60,7 @@ import java.util.concurrent.Executor;
|
|
|
import java.util.concurrent.ExecutorService;
|
|
|
import java.util.concurrent.Executors;
|
|
|
import java.util.concurrent.atomic.AtomicReference;
|
|
|
+import java.util.function.Function;
|
|
|
import java.util.stream.Collectors;
|
|
|
|
|
|
/**
|
|
@@ -10955,6 +10956,321 @@ public class ReportServiceImpl extends ServiceImpl<ReportMapper, Report> impleme
|
|
|
return msg;
|
|
|
}
|
|
|
|
|
|
+ @Override
|
|
|
+ public HttpRespMsg getReportRateOfTaskNew(Integer projectId, String userIds, Integer companyId, Integer type) {
|
|
|
+ HttpRespMsg msg = new HttpRespMsg();
|
|
|
+ DecimalFormat dft = new DecimalFormat("0%");
|
|
|
+ List<String> collect=new ArrayList<>();
|
|
|
+ if (userIds!=null&&!userIds.isEmpty()){
|
|
|
+ String[] strings = userIds.split(",");
|
|
|
+ collect = Arrays.stream(strings).collect(Collectors.toList());
|
|
|
+ }
|
|
|
+ List<ReportRateTaskVO> reportRateTaskVOList= reportMapper.getReportRateOfTask(projectId, collect, type,companyId);
|
|
|
+
|
|
|
+
|
|
|
+ List<Department> departmentList = departmentMapper.selectList(new QueryWrapper<Department>().eq("company_id", companyId));
|
|
|
+ List<User> userList = userMapper.selectList(new QueryWrapper<User>().eq("company_id", companyId));
|
|
|
+
|
|
|
+ List<Integer> taskIds = reportRateTaskVOList.stream().distinct().map(r -> r.getTaskId()).collect(Collectors.toList());
|
|
|
+ System.out.println(taskIds.toString());
|
|
|
+ taskIds.add(-1);
|
|
|
+ List<Map<String,Object>> reportList=reportMapper.getUserReportTimelinessRateWithTask(companyId,taskIds);
|
|
|
+ Map<Object, List<Map<String, Object>>> listMap = reportList.stream().filter(item->!StringUtils.isEmpty(item.get("userName"))).collect(Collectors.groupingBy(rp -> rp.get("userName")));
|
|
|
+ //获取到公司设置的特殊节假日设置
|
|
|
+ List<HolidaySetting> holidaySettingList = holidaySettingService.list(new LambdaQueryWrapper<HolidaySetting>().eq(HolidaySetting::getCompanyId, companyId).isNotNull(HolidaySetting::getHolidayDate));
|
|
|
+ List<HolidaySetting> allUsersSetting = holidaySettingList.stream().filter(h -> h.getRangeType() == 0).collect(Collectors.toList());
|
|
|
+ List<HolidaySetting> targetUserOrDeptSetting = holidaySettingList.stream().filter(h -> h.getRangeType() == 1).collect(Collectors.toList());
|
|
|
+ TimeType timeType = timeTypeMapper.selectById(companyId);
|
|
|
+ Integer timeliness = timeType.getTimeliness();
|
|
|
+
|
|
|
+ for (ReportRateTaskVO rateTaskVO : reportRateTaskVOList) {
|
|
|
+ Optional<User> first = userList.stream().filter(u -> u.getId().equals(rateTaskVO.getUserId())).findFirst();
|
|
|
+ if (first.isPresent()){
|
|
|
+ User user = first.get();
|
|
|
+ rateTaskVO.setJobNumber(user.getJobNumber());
|
|
|
+ Optional<Department> firstDept = departmentList.stream().filter(d->d.getDepartmentId().equals(user.getDepartmentId())).findFirst();
|
|
|
+ if(firstDept.isPresent()){
|
|
|
+ Department dept= firstDept.get();
|
|
|
+ rateTaskVO.setDepartmentName(dept.getDepartmentName());
|
|
|
+ }
|
|
|
+
|
|
|
+ List<Map<String, Object>> mapList = listMap.get(user.getName());
|
|
|
+ LocalDate startDate = rateTaskVO.getStartDate();
|
|
|
+ LocalDate endDate = rateTaskVO.getEndDate();
|
|
|
+ AtomicReference<List<LocalDate>> listAtomicReference = new AtomicReference<>(getDays(startDate, endDate));
|
|
|
+ long days = listAtomicReference.get().size();
|
|
|
+ for (LocalDate localDateTime : listAtomicReference.get()) {
|
|
|
+ if(mapList!=null){
|
|
|
+ //在非工作日下 填报了的情况下 及时填报了就算作及时率计算的基数
|
|
|
+ if(localDateTime!=null&& !WorkDayCalculateUtils.isWorkDay(localDateTime)&&!mapList.stream().anyMatch(ml->{
|
|
|
+ Integer taskId=ml.get("taskId")!=null?Integer.parseInt(ml.get("taskId").toString()):null;
|
|
|
+ if (taskId == null || !taskId.equals(rateTaskVO.getTaskId())) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ Date date = (Date) ml.get("createDate");
|
|
|
+ LocalDate createDate = date != null ? date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate() : null;
|
|
|
+ return createDate.isEqual(localDateTime);
|
|
|
+ })){
|
|
|
+ days-=1;
|
|
|
+ }
|
|
|
+ }else {
|
|
|
+ if(localDateTime!=null&&!WorkDayCalculateUtils.isWorkDay(localDateTime)){
|
|
|
+ days-=1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //获取请假数据
|
|
|
+ List<LeaveSheet> leaveSheetList = leaveSheetMapper.selectList(new LambdaQueryWrapper<LeaveSheet>()
|
|
|
+ .eq(LeaveSheet::getCompanyId, companyId).le(endDate!=null,LeaveSheet::getStartDate,endDate)
|
|
|
+ .ge(startDate!=null,LeaveSheet::getEndDate,startDate));
|
|
|
+ List<LeaveSheet> leaveSheets = leaveSheetList.stream().filter(ls -> ls.getOwnerId().equals(user.getId())
|
|
|
+ &&(endDate!=null &&startDate!=null)
|
|
|
+ &&((ls.getStartDate().isBefore(ChronoLocalDate.from(endDate))||ls.getStartDate().isEqual(ChronoLocalDate.from(endDate))))
|
|
|
+ &&((ls.getEndDate().isAfter(ChronoLocalDate.from(startDate))||ls.getEndDate().isEqual(ChronoLocalDate.from(startDate)))))
|
|
|
+ .collect(Collectors.toList());
|
|
|
+ long daysWithLeave =days;
|
|
|
+ if(leaveSheets.size()>0){
|
|
|
+ for (LeaveSheet leaveSheet : leaveSheets) {
|
|
|
+ AtomicReference<List<LocalDateTime>> leaveDateList = new AtomicReference<>(getDays(leaveSheet.getStartDate().atTime(LocalTime.MIN), leaveSheet.getEndDate().atTime(LocalTime.MIN)));
|
|
|
+ AtomicReference<List<LocalDateTime>> list = new AtomicReference<>(getDays(leaveSheet.getStartDate().atTime(LocalTime.MIN), leaveSheet.getEndDate().atTime(LocalTime.MIN)));
|
|
|
+ if(allUsersSetting.size()>0){
|
|
|
+ List<LocalDateTime> holidayDateList = allUsersSetting.stream().map(h->h.getHolidayDate().atTime(LocalTime.MIN)).collect(Collectors.toList());
|
|
|
+ leaveDateList.set(leaveDateList.get().stream().filter(d -> !holidayDateList.contains(d)).collect(Collectors.toList()));
|
|
|
+ list.set(list.get().stream().filter(d -> !holidayDateList.contains(d)).collect(Collectors.toList()));
|
|
|
+ }
|
|
|
+ if(targetUserOrDeptSetting.size()>0){
|
|
|
+ targetUserOrDeptSetting.forEach(t->{
|
|
|
+ LocalDateTime holidayDate = t.getHolidayDate().atTime(LocalTime.MIN);
|
|
|
+ if(!StringUtils.isEmpty(t.getTargetUsers())&&!t.getTargetUsers().equals("")){
|
|
|
+ String[] userSplit = t.getTargetUsers().split(",");
|
|
|
+ List<String> userAsList = Arrays.asList(userSplit);
|
|
|
+ if(userAsList.contains(user.getId())){
|
|
|
+ leaveDateList.set(leaveDateList.get().stream().filter(d -> !d.isEqual(holidayDate)).collect(Collectors.toList()));
|
|
|
+ list.set(list.get().stream().filter(d -> !d.isEqual(holidayDate)).collect(Collectors.toList()));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if(!StringUtils.isEmpty(t.getTargetDepts())&&!t.getTargetDepts().equals("")){
|
|
|
+ String[] deptSplit = t.getTargetDepts().split(",");
|
|
|
+ List<String> deptAsList = Arrays.asList(deptSplit);
|
|
|
+ for (String deptId : deptAsList) {
|
|
|
+ List<Integer> subDeptIds = getBranchDepartment(Integer.valueOf(deptId), departmentList);
|
|
|
+ if(deptId.equals(user.getDepartmentId())||subDeptIds.contains(user.getDepartmentId())){
|
|
|
+ leaveDateList.set(leaveDateList.get().stream().filter(d -> !d.isEqual(holidayDate)).collect(Collectors.toList()));
|
|
|
+ list.set(list.get().stream().filter(d -> !d.isEqual(holidayDate)).collect(Collectors.toList()));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+ if(list.get().size()>1){
|
|
|
+ days-= list.get().size();
|
|
|
+ }else {
|
|
|
+ days-=1;
|
|
|
+ }
|
|
|
+ for (LocalDateTime localDateTime : leaveDateList.get()) {
|
|
|
+ //todo: 请假区间当中有非工作日在之前被当作 不需填报 所以要加上 保证基数正确
|
|
|
+ if(localDateTime!=null&&!WorkDayCalculateUtils.isWorkDay(localDateTime.toLocalDate())){
|
|
|
+ days+=1;
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ if((startDate!=null&&endDate!=null)&&localDateTime.isBefore(startDate.atStartOfDay())||localDateTime.isAfter(endDate.atStartOfDay().plusDays(1))){
|
|
|
+ days++;
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ if(mapList!=null&&mapList.stream().anyMatch(ml->{
|
|
|
+ Integer taskId=ml.get("taskId")!=null?Integer.parseInt(ml.get("taskId").toString()):null;
|
|
|
+ if (taskId == null || !taskId.equals(rateTaskVO.getTaskId())) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ Date date = (Date) ml.get("createDate");
|
|
|
+ LocalDate createDate = date != null ? date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate() : null;
|
|
|
+ return createDate.isEqual(localDateTime.toLocalDate());
|
|
|
+ })){
|
|
|
+ days++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ int num=0;
|
|
|
+ if(mapList!=null){
|
|
|
+ for (Map<String, Object> map : mapList) {
|
|
|
+ if (map.get("createDate")!=null && map.get("createTime")!=null) {
|
|
|
+ Map<String, Object> objectMap = new HashMap<>();
|
|
|
+ Date date = (Date) map.get("createDate");
|
|
|
+ SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
|
|
|
+ //去掉sql返回的毫秒值
|
|
|
+ java.sql.Date createTime = (java.sql.Date) map.get("createTime");
|
|
|
+ LocalDate createDate = date != null ? date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate() : null;
|
|
|
+ // 针对美莱德 去除2024-02-09
|
|
|
+ if (user.getCompanyId() == 876) {
|
|
|
+ if (createDate.isEqual(LocalDate.parse("2024-02-09"))) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ LocalDate createTimeDate = createTime.toLocalDate();
|
|
|
+ //根据设置
|
|
|
+ switch (timeliness) {
|
|
|
+ case 1:
|
|
|
+ createDate = createDate.plusDays(1);
|
|
|
+ while (createDate!=null&&!WorkDayCalculateUtils.isWorkDay(createDate)) {
|
|
|
+ createDate = createDate.plusDays(1);
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case 2:
|
|
|
+ Integer a = 0;
|
|
|
+ while (a != 2) {
|
|
|
+ createDate = createDate.plusDays(1);
|
|
|
+ if (createDate!=null&&WorkDayCalculateUtils.isWorkDay(createDate)) {
|
|
|
+ a++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ if (createTimeDate.isBefore(createDate) || createTimeDate.isEqual(createDate)) {
|
|
|
+ num++;
|
|
|
+ objectMap.put(simpleDateFormat.format(date), MessageUtils.message("entry.timely") + "/" + MessageUtils.message("entry.SubTime") + createTimeDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
|
|
|
+ } else {
|
|
|
+ objectMap.put(simpleDateFormat.format(date), MessageUtils.message("entry.NoTimely") + "/" + MessageUtils.message("entry.SubTime") + createTimeDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+ //处理漏填的情况,漏填的也算不及时
|
|
|
+ boolean hasMissReport = false;
|
|
|
+ for (LocalDate localDateTime : listAtomicReference.get()) {
|
|
|
+ if(localDateTime!=null&&!WorkDayCalculateUtils.isWorkDay(localDateTime)){
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ hasMissReport = true;
|
|
|
+ }
|
|
|
+ BigDecimal bigDecimal=new BigDecimal(num);
|
|
|
+ BigDecimal bigDecimalWithLeave=new BigDecimal(num+(daysWithLeave-days));
|
|
|
+ BigDecimal divide;
|
|
|
+ BigDecimal divideWithLeave;
|
|
|
+ if(days!=0){
|
|
|
+ divide = bigDecimal.divide(BigDecimal.valueOf(days), 2, BigDecimal.ROUND_HALF_UP);
|
|
|
+ }else if(days==0){
|
|
|
+ divide=new BigDecimal(1);
|
|
|
+ //查看当天有请假直接算100%
|
|
|
+ }else if (days==0&&num!=0&&leaveSheetList.size()>0){
|
|
|
+ divide=new BigDecimal(1);
|
|
|
+ }else{
|
|
|
+ divide=new BigDecimal(0);
|
|
|
+ }
|
|
|
+ if(divide.compareTo(new BigDecimal(1))==1){
|
|
|
+ divide=new BigDecimal(1);
|
|
|
+ log.error("填报及时率数据异常:==="+user.getName());
|
|
|
+ }
|
|
|
+ if(daysWithLeave!=0){
|
|
|
+ divideWithLeave = bigDecimalWithLeave.divide(BigDecimal.valueOf(daysWithLeave), 2, BigDecimal.ROUND_HALF_UP);
|
|
|
+ }else if(daysWithLeave==0){
|
|
|
+ divideWithLeave=new BigDecimal(1);
|
|
|
+ //查看当天有请假直接算100%
|
|
|
+ }else if (daysWithLeave==0&&num!=0&&leaveSheetList.size()>0){
|
|
|
+ divideWithLeave=new BigDecimal(1);
|
|
|
+ }else{
|
|
|
+ divideWithLeave=new BigDecimal(0);
|
|
|
+ }
|
|
|
+ if(divideWithLeave.compareTo(new BigDecimal(1))==1){
|
|
|
+ divideWithLeave=new BigDecimal(1);
|
|
|
+ log.error("填报及时率数据异常:==="+user.getName());
|
|
|
+ }
|
|
|
+ String number = dft.format(divide);
|
|
|
+ String numberWithLeave = dft.format(divideWithLeave);
|
|
|
+ rateTaskVO.setTimelinessRate(String.valueOf(number));
|
|
|
+ rateTaskVO.setTimelinessRateWithLeave(String.valueOf(numberWithLeave));
|
|
|
+ }else {
|
|
|
+ BigDecimal bigDecimal=new BigDecimal(num);
|
|
|
+ BigDecimal bigDecimalWithLeave=new BigDecimal(num+(daysWithLeave-days));
|
|
|
+ BigDecimal divide;
|
|
|
+ BigDecimal divideWithLeave;
|
|
|
+ if(days!=0){
|
|
|
+ System.out.println("及时日=="+num+","+days);
|
|
|
+ divide = bigDecimal.divide(BigDecimal.valueOf(days), 2, BigDecimal.ROUND_HALF_UP);
|
|
|
+ }else if(days==0){
|
|
|
+ divide=new BigDecimal(1);
|
|
|
+ //查看当天有请假直接算100%
|
|
|
+ }else if (days==0&&num!=0&&leaveSheetList.size()>0){
|
|
|
+ divide=new BigDecimal(1);
|
|
|
+ }else if(leaveSheets.size()>0){
|
|
|
+ divide=new BigDecimal(1);
|
|
|
+ }else{
|
|
|
+ divide=new BigDecimal(0);
|
|
|
+ }
|
|
|
+ if(divide.compareTo(new BigDecimal(1))==1){
|
|
|
+ divide=new BigDecimal(1);
|
|
|
+ log.error("填报及时率数据异常:==="+user.getName());
|
|
|
+ }
|
|
|
+ if(daysWithLeave!=0){
|
|
|
+ divideWithLeave = bigDecimalWithLeave.divide(BigDecimal.valueOf(daysWithLeave), 2, BigDecimal.ROUND_HALF_UP);
|
|
|
+ }else if(daysWithLeave==0){
|
|
|
+ divideWithLeave=new BigDecimal(1);
|
|
|
+ //查看当天有请假直接算100%
|
|
|
+ }else if (daysWithLeave==0&&num!=0&&leaveSheetList.size()>0){
|
|
|
+ divideWithLeave=new BigDecimal(1);
|
|
|
+ }else if(leaveSheets.size()>0){
|
|
|
+ divideWithLeave=new BigDecimal(1);
|
|
|
+ }else{
|
|
|
+ divideWithLeave=new BigDecimal(0);
|
|
|
+ }
|
|
|
+ if(divideWithLeave.compareTo(new BigDecimal(1))==1){
|
|
|
+ divideWithLeave=new BigDecimal(1);
|
|
|
+ log.error("填报及时率数据异常:==="+user.getName());
|
|
|
+ }
|
|
|
+ String number = dft.format(divide);
|
|
|
+ String numberWithLeave = dft.format(divideWithLeave);
|
|
|
+ rateTaskVO.setTimelinessRate(String.valueOf(number));
|
|
|
+ rateTaskVO.setTimelinessRateWithLeave(String.valueOf(numberWithLeave));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (type==1) {
|
|
|
+ // 3. 主处理逻辑
|
|
|
+ Map<String, List<ReportRateTaskVO>> groupedByTaskId = reportRateTaskVOList.stream()
|
|
|
+ .filter(task -> task.getUserId() != null)
|
|
|
+ .collect(Collectors.groupingBy(ReportRateTaskVO::getUserId));
|
|
|
+
|
|
|
+ groupedByTaskId.forEach((userId, list) -> {
|
|
|
+ String avgPercentage = calculateAverage(list, ReportRateTaskVO::getTimelinessRate);
|
|
|
+ String avgLeavePercentage = calculateAverage(list, ReportRateTaskVO::getTimelinessRateWithLeave);
|
|
|
+
|
|
|
+ // 直接更新当前分组中的对象,避免二次遍历
|
|
|
+ list.forEach(task -> {
|
|
|
+ task.setAveragePercentage(avgPercentage);
|
|
|
+ task.setAverageLeavePercentage(avgLeavePercentage);
|
|
|
+ });
|
|
|
+ });
|
|
|
+ msg.setData(reportRateTaskVOList);
|
|
|
+ }else {
|
|
|
+ msg.setData(reportRateTaskVOList);
|
|
|
+ }
|
|
|
+ return msg;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 2. 定义计算平均值方法
|
|
|
+ private String calculateAverage(List<ReportRateTaskVO> list, Function<ReportRateTaskVO, String> rateExtractor) {
|
|
|
+ double average = list.stream()
|
|
|
+ .map(rateExtractor)
|
|
|
+ .filter(rate -> rate != null && !rate.isEmpty())
|
|
|
+ .map(this::convertPercentage)
|
|
|
+ .filter(Objects::nonNull)
|
|
|
+ .mapToDouble(Double::doubleValue)
|
|
|
+ .average()
|
|
|
+ .orElse(0.0);
|
|
|
+ DecimalFormat dft = new DecimalFormat("0%");
|
|
|
+ return dft.format(average);
|
|
|
+ }
|
|
|
+ // 1. 先定义百分比转换方法
|
|
|
+ private Double convertPercentage(String percentageStr) {
|
|
|
+ if (percentageStr == null || percentageStr.isEmpty()) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ String rateStr = percentageStr.replace("%", "");
|
|
|
+ return Double.parseDouble(rateStr) / 100.0;
|
|
|
+ }
|
|
|
+
|
|
|
@Override
|
|
|
public HttpRespMsg getReportRateOfTask(Integer projectId, String userIds, Integer companyId, Integer type) {
|
|
|
HttpRespMsg msg = new HttpRespMsg();
|