| | |
| | | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
| | | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; |
| | | import com.google.common.util.concurrent.AtomicDouble; |
| | | import com.ruoyi.common.core.domain.entity.SysDictData; |
| | | import com.ruoyi.common.core.domain.entity.User; |
| | | import com.ruoyi.common.enums.*; |
| | | import com.ruoyi.common.utils.api.icc.IccApiUtil; |
| | | import com.ruoyi.common.utils.api.icc.model.GetResultPageRequest; |
| | | import com.ruoyi.common.utils.api.icc.model.GetResultPageResponse; |
| | | |
| | | import com.ruoyi.performance.dto.PerformanceShiftMapDto; |
| | | import com.ruoyi.performance.dto.StaffAttendanceDTO; |
| | | import com.ruoyi.performance.excel.StaffAttendanceAnnotationTextExcelData; |
| | | import com.ruoyi.performance.excel.StaffAttendanceExcelData; |
| | | import com.ruoyi.performance.excel.handler.attendance.CommentWriteHandler; |
| | | import com.ruoyi.performance.mapper.StaffAttendanceTrackingRecordMapper; |
| | | import com.ruoyi.performance.pojo.StaffAttendanceTrackingRecord; |
| | | import com.ruoyi.performance.service.StaffAttendanceTrackingRecordService; |
| | | import com.ruoyi.performance.dto.PerformanceShiftMapDto; |
| | | import com.ruoyi.performance.mapper.PerformanceShiftMapper; |
| | | import com.ruoyi.performance.mapper.ShiftTimeMapper; |
| | | import com.ruoyi.performance.mapper.StaffAttendanceTrackingRecordMapper; |
| | | import com.ruoyi.performance.pojo.ShiftTime; |
| | | import com.ruoyi.performance.pojo.StaffAttendanceTrackingRecord; |
| | | import com.ruoyi.performance.service.StaffAttendanceTrackingRecordService; |
| | | import com.ruoyi.performance.utils.HourDiffCalculator; |
| | | import com.ruoyi.performance.utils.TimeDiffCalculator; |
| | | import com.ruoyi.performance.vo.StaffAttendanceVO; |
| | | import com.ruoyi.system.mapper.UserMapper; |
| | | import com.ruoyi.system.service.ISysDictTypeService; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.apache.commons.lang3.ObjectUtils; |
| | | import org.apache.commons.lang3.StringUtils; |
| | |
| | | import java.math.RoundingMode; |
| | | import java.net.URLEncoder; |
| | | import java.nio.charset.StandardCharsets; |
| | | import java.time.LocalDate; |
| | | import java.time.LocalDateTime; |
| | | import java.time.LocalTime; |
| | | import java.time.ZoneId; |
| | | import java.time.*; |
| | | import java.time.format.DateTimeFormatter; |
| | | import java.util.*; |
| | | import java.util.concurrent.atomic.AtomicInteger; |
| | |
| | | |
| | | @Autowired |
| | | private IccApiUtil iccApiUtil; |
| | | |
| | | @Autowired |
| | | private ISysDictTypeService sysDictTypeService; |
| | | |
| | | @Autowired |
| | | private PerformanceShiftMapper performanceShiftMapper; |
| | |
| | | private static final String maternityLeaveKeyword = "产";//产假班次关键字 |
| | | |
| | | /** |
| | | * 同步的门禁设备列表 |
| | | * channel_name device_code |
| | | * 10.100.22.2_门禁通道_1 1001538 |
| | | * 10.100.22.3_门禁通道_1 1001539 |
| | | * 10.100.22.4_门禁通道_1 1001540 |
| | | * 10.100.22.5_门禁通道_1 1001541 |
| | | * 10.100.22.12_门禁通道_1 1001626 |
| | | * 10.100.22.13_门禁通道_1 1001627 |
| | | * 10.100.22.14_门禁通道_1 1001628 |
| | | * 10.100.22.15_门禁通道_1 1001629 |
| | | */ |
| | | private final static List<String> syncDeviceCode = Arrays.asList("1001538", "1001539", "1001540", "1001541", |
| | | "1001626", "1001627", "1001628", "1001629"); |
| | | |
| | | /** |
| | | * 上班时间判定边界小时数 |
| | | */ |
| | | private final static long WORK_TIME_BOUNDARY = 2L; |
| | |
| | | if (ObjectUtil.isAllEmpty(startDate, endDate)) { |
| | | throw new RuntimeException("同步日期不能为空"); |
| | | } |
| | | |
| | | //查询门禁设备字典列表 |
| | | List<SysDictData> performanceIccDevice = sysDictTypeService.selectDictDataByType("performance_icc_device"); |
| | | Set<String> syncDeviceCode = performanceIccDevice.stream().map(SysDictData::getDictValue).collect(Collectors.toSet()); |
| | | // 查询已同步的记录 |
| | | List<Long> trackingRecordIccIdList = baseMapper.selectIccIdList(); |
| | | try { |
| | |
| | | return this.saveOrUpdateBatch(records); |
| | | } |
| | | |
| | | /** |
| | | * 根据导出日期格式化导出时间范围 |
| | | * @param staffAttendanceDTO |
| | | */ |
| | | private static void formatExportDateRange(StaffAttendanceDTO staffAttendanceDTO){ |
| | | if(StringUtils.isNoneBlank(staffAttendanceDTO.getReportDate())){ |
| | | LocalTime startTime = LocalTime.of(0,0,0); |
| | | LocalTime endTime = LocalTime.of(23,59,59); |
| | | YearMonth yearMonth; |
| | | if(StringUtils.equals(staffAttendanceDTO.getAttendanceReportType(),CalendarType.MONTH.name())){ |
| | | yearMonth = YearMonth.parse(staffAttendanceDTO.getReportDate(),DateTimeFormatter.ofPattern("yyyy-MM")); |
| | | LocalDateTime startDateTime = LocalDateTime.of(yearMonth.minusMonths(1L).atDay(26),startTime); |
| | | LocalDateTime endDateTime = LocalDateTime.of(yearMonth.atDay(25),endTime); |
| | | staffAttendanceDTO.setStartDate(startDateTime); |
| | | staffAttendanceDTO.setEndDate(endDateTime); |
| | | }else if(StringUtils.equals(staffAttendanceDTO.getAttendanceReportType(),CalendarType.YEAR.name())){ |
| | | Year year = Year.parse(staffAttendanceDTO.getReportDate(),DateTimeFormatter.ofPattern("yyyy")); |
| | | yearMonth = year.atMonth(1); |
| | | LocalDateTime startDateTime = LocalDateTime.of(yearMonth.minusMonths(1L).atDay(26),startTime); |
| | | LocalDateTime endDateTime = LocalDateTime.of(yearMonth.withMonth(12).atDay(25),endTime); |
| | | staffAttendanceDTO.setStartDate(startDateTime); |
| | | staffAttendanceDTO.setEndDate(endDateTime); |
| | | } |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | public void exportStaffAttendanceRecords(HttpServletResponse response, StaffAttendanceDTO staffAttendanceDTO) { |
| | | response.reset(); |
| | | try{ |
| | | formatExportDateRange(staffAttendanceDTO); |
| | | //查询人员架构 |
| | | List<User> userList = userMapper.selectUserListByPerformance(false); |
| | | List<Integer> userIdList = userList.stream().map(User::getId).collect(Collectors.toList()); |
| | |
| | | //批注信息坐标信息 |
| | | List<StaffAttendanceAnnotationTextExcelData> annotationTextList = new ArrayList<>(); |
| | | // 查询班次 |
| | | |
| | | List<PerformanceShiftMapDto> performanceShifts = performanceShiftMapper.selectListByWorkTime( |
| | | staffAttendanceDTO.getStartDate(), staffAttendanceDTO.getEndDate(), staffAttendanceDTO.getKeyword()); |
| | | //获取考勤数据 |
| | |
| | | AtomicInteger maternityLeaveCount = new AtomicInteger(0);//产假天数 |
| | | AtomicInteger attendanceDayCount = new AtomicInteger(0);//出勤天数 |
| | | AtomicDouble attendanceWorkHourCount = new AtomicDouble(0D);//出勤总时间 |
| | | for (int j = 0; j < shiftMapDtos.size(); j++) { |
| | | PerformanceShiftMapDto shiftMapDto = shiftMapDtos.get(j); |
| | | //统计各假期和公差的天数 |
| | | if(StringUtils.contains(shiftMapDto.getShiftName(),holidayLeaveKeyword)){ |
| | | holidayCount.getAndIncrement(); |
| | | }else if(StringUtils.contains(shiftMapDto.getShiftName(),personalLeaveKeyword)){ |
| | | personalLeaveCount.getAndIncrement(); |
| | | }else if(StringUtils.contains(shiftMapDto.getShiftName(),annualLeaveKeyword)){ |
| | | annualLeaveCount.getAndIncrement(); |
| | | }else if(StringUtils.contains(shiftMapDto.getShiftName(),officialTripKeyword)){ |
| | | officialTripCount.getAndIncrement(); |
| | | }else if(StringUtils.contains(shiftMapDto.getShiftName(),marriageLeaveKeyword)){ |
| | | marriageLeaveCount.getAndIncrement(); |
| | | }else if(StringUtils.contains(shiftMapDto.getShiftName(),bereavementLeaveKeyword)){ |
| | | bereavementLeaveCount.getAndIncrement(); |
| | | }else if(StringUtils.contains(shiftMapDto.getShiftName(),sickLeaveKeyword)){ |
| | | sickLeaveCount.getAndIncrement(); |
| | | }else if(StringUtils.contains(shiftMapDto.getShiftName(),maternityLeaveKeyword)){ |
| | | maternityLeaveCount.getAndIncrement(); |
| | | } |
| | | if(StringUtils.isAllBlank(shiftMapDto.getStartTime(),shiftMapDto.getEndTime())){ |
| | | shiftList.add(shiftMapDto.getShiftName()); |
| | | }else{ |
| | | //过滤当前人员的班次信息 |
| | | StaffAttendanceVO vo = attendanceRecords.stream().filter(f->StringUtils.isNotBlank(f.getPersonCode())).filter(f -> StringUtils.equals(f.getPersonCode(), shiftMapDto.getPersonCode()) && f.getSwingDate().isEqual(shiftMapDto.getWorkTime())).findFirst().orElse(null); |
| | | if(ObjectUtils.isEmpty(vo)){ |
| | | shiftList.add(""); |
| | | for (int j = 0; j < attendanceDateList.size(); j++) { |
| | | LocalDate localDate = attendanceDateList.get(j); |
| | | PerformanceShiftMapDto shiftMapDto = shiftMapDtos.stream().filter(f -> f.getWorkTime().toLocalDate().equals(localDate)).findFirst().orElse(null); |
| | | if(Objects.nonNull(shiftMapDto)){ |
| | | //统计各假期和公差的天数 |
| | | if(StringUtils.contains(shiftMapDto.getShiftName(),holidayLeaveKeyword)){ |
| | | holidayCount.getAndIncrement(); |
| | | }else if(StringUtils.contains(shiftMapDto.getShiftName(),personalLeaveKeyword)){ |
| | | personalLeaveCount.getAndIncrement(); |
| | | }else if(StringUtils.contains(shiftMapDto.getShiftName(),annualLeaveKeyword)){ |
| | | annualLeaveCount.getAndIncrement(); |
| | | }else if(StringUtils.contains(shiftMapDto.getShiftName(),officialTripKeyword)){ |
| | | officialTripCount.getAndIncrement(); |
| | | }else if(StringUtils.contains(shiftMapDto.getShiftName(),marriageLeaveKeyword)){ |
| | | marriageLeaveCount.getAndIncrement(); |
| | | }else if(StringUtils.contains(shiftMapDto.getShiftName(),bereavementLeaveKeyword)){ |
| | | bereavementLeaveCount.getAndIncrement(); |
| | | }else if(StringUtils.contains(shiftMapDto.getShiftName(),sickLeaveKeyword)){ |
| | | sickLeaveCount.getAndIncrement(); |
| | | }else if(StringUtils.contains(shiftMapDto.getShiftName(),maternityLeaveKeyword)){ |
| | | maternityLeaveCount.getAndIncrement(); |
| | | } |
| | | if(StringUtils.isAllBlank(shiftMapDto.getStartTime(),shiftMapDto.getEndTime())){ |
| | | shiftList.add(shiftMapDto.getShiftName()); |
| | | }else{ |
| | | String actualWorkHours = Objects.toString(vo.getActualWorkHours(), ""); |
| | | Double diffHour = ObjectUtils.defaultIfNull(vo.getDiffHour(), 0D); |
| | | if (StringUtils.isBlank(actualWorkHours)) { |
| | | //过滤当前人员的班次信息 |
| | | StaffAttendanceVO vo = attendanceRecords.stream().filter(f->StringUtils.isNotBlank(f.getPersonCode())).filter(f -> StringUtils.equals(f.getPersonCode(), shiftMapDto.getPersonCode()) && f.getSwingDate().isEqual(shiftMapDto.getWorkTime())).findFirst().orElse(null); |
| | | if(ObjectUtils.isEmpty(vo)){ |
| | | shiftList.add(""); |
| | | } else { |
| | | shiftList.add(Double.compare(diffHour, 0D) < 0 ? "-" + actualWorkHours : actualWorkHours); |
| | | attendanceDayCount.getAndIncrement(); |
| | | attendanceWorkHourCount.getAndAdd(Double.parseDouble(actualWorkHours)); |
| | | }else{ |
| | | String actualWorkHours = Objects.toString(vo.getActualWorkHours(), ""); |
| | | Double diffHour = ObjectUtils.defaultIfNull(vo.getDiffHour(), 0D); |
| | | if (StringUtils.isBlank(actualWorkHours)) { |
| | | shiftList.add(""); |
| | | } else { |
| | | shiftList.add(Double.compare(diffHour, 0D) < 0 ? "-" + actualWorkHours : actualWorkHours); |
| | | attendanceDayCount.getAndIncrement(); |
| | | attendanceWorkHourCount.getAndAdd(Double.parseDouble(actualWorkHours)); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | //月度统计才插入批注数据 |
| | | if(StringUtils.isNoneBlank(staffAttendanceDTO.getAttendanceReportType()) && StringUtils.equals(staffAttendanceDTO.getAttendanceReportType(), CalendarType.MONTH.name())){ |
| | | if(StringUtils.isNotBlank(shiftMapDto.getAnnotationText())){ |
| | | annotationTextList.add(new StaffAttendanceAnnotationTextExcelData(i,j,shiftMapDto.getAnnotationText())); |
| | | //月度统计才插入批注数据 |
| | | if(StringUtils.isNoneBlank(staffAttendanceDTO.getAttendanceReportType()) && StringUtils.equals(staffAttendanceDTO.getAttendanceReportType(), CalendarType.MONTH.name())){ |
| | | if(StringUtils.isNotBlank(shiftMapDto.getAnnotationText())){ |
| | | annotationTextList.add(new StaffAttendanceAnnotationTextExcelData(i,j,shiftMapDto.getAnnotationText())); |
| | | } |
| | | } |
| | | }else{ |
| | | shiftList.add(""); |
| | | } |
| | | } |
| | | if(StringUtils.isNoneBlank(staffAttendanceDTO.getAttendanceReportType()) && StringUtils.equals(staffAttendanceDTO.getAttendanceReportType(), CalendarType.MONTH.name())){ |
| | |
| | | public static String restorePersonCode(Object number) { |
| | | // 1. 空值校验 |
| | | if (number == null) { |
| | | throw new IllegalArgumentException("传入数字不能为空"); |
| | | return ""; |
| | | } |
| | | |
| | | String original = number.toString(); |
| | | try { |
| | | // 2. 统一转换为字符串并去除首尾空格 |
| | | String numStr = number.toString().trim(); |
| | | String numStr = original.trim(); |
| | | |
| | | // 3. 校验是否为纯数字(排除负数、非数字字符) |
| | | if (!numStr.matches("\\d+")) { |
| | | throw new IllegalArgumentException("传入的不是有效正整数:" + numStr); |
| | | } |
| | | String digitStr; |
| | | if (numStr.matches("\\d+")) { |
| | | digitStr = numStr; |
| | | } else if (numStr.matches("(?i)^ZT\\d+$")) { |
| | | digitStr = numStr.substring(2); |
| | | } else if (numStr.matches("(?i)^ZT-\\d+$")) { |
| | | digitStr = numStr.substring(3); |
| | | } else { |
| | | return original; |
| | | } |
| | | |
| | | // 4. 补前置0到指定长度(6位),超出则保留原数字 |
| | | String paddedNum = String.format("%0" + DIGIT_LENGTH + "d", Long.parseLong(numStr)); |
| | | String paddedNum = StringUtils.leftPad(digitStr, DIGIT_LENGTH, '0'); |
| | | |
| | | // 5. 拼接前缀返回 |
| | | return PREFIX + paddedNum; |
| | | return PREFIX + paddedNum; |
| | | } catch (Exception e) { |
| | | return original; |
| | | } |
| | | } |
| | | |
| | | } |