| | |
| | | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| | | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; |
| | | import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; |
| | | import cn.iocoder.yudao.module.hrm.controller.admin.attendance.vo.HrmAttendanceRecordImportExcelVO; |
| | | import cn.iocoder.yudao.module.hrm.controller.admin.attendance.vo.HrmAttendanceRecordImportReqVO; |
| | | import cn.iocoder.yudao.module.hrm.controller.admin.attendance.vo.HrmAttendanceRecordPageReqVO; |
| | | import cn.iocoder.yudao.module.hrm.controller.admin.attendance.vo.HrmAttendanceRecordRespVO; |
| | | import cn.iocoder.yudao.module.hrm.dal.dataobject.attendance.HrmAttendanceRecordDO; |
| | |
| | | HrmEmployeeDO employee = employeeMap.get(respVO.getUserId()); |
| | | if (employee != null) { |
| | | respVO.setUserName(employee.getName()); |
| | | respVO.setPhone(employee.getPhone()); |
| | | } |
| | | // 部门名称 |
| | | DeptRespDTO dept = deptMap.get(respVO.getDeptId()); |
| | |
| | | HrmEmployeeDO employee = employeeService.getEmployee(attendanceRecord.getUserId()); |
| | | if (employee != null) { |
| | | respVO.setUserName(employee.getName()); |
| | | respVO.setPhone(employee.getPhone()); |
| | | } |
| | | } |
| | | if (attendanceRecord.getDeptId() != null) { |
| | |
| | | return success(respVO); |
| | | } |
| | | |
| | | @GetMapping("/get-import-template") |
| | | @Operation(summary = "下载考勤记录导入模板") |
| | | @PreAuthorize("@ss.hasPermission('hrm:attendance-record:import')") |
| | | public void importTemplate(HttpServletResponse response) throws IOException { |
| | | List<HrmAttendanceRecordImportExcelVO> list = Collections.singletonList( |
| | | HrmAttendanceRecordImportExcelVO.builder() |
| | | .userName("张三") |
| | | .phone("13800138000") |
| | | .date(java.time.LocalDate.of(2026, 1, 15)) |
| | | .clockInTime(java.time.LocalDateTime.of(2026, 1, 15, 8, 30)) |
| | | .clockOutTime(java.time.LocalDateTime.of(2026, 1, 15, 17, 30)) |
| | | .clockInType(1) |
| | | .clockOutType(1) |
| | | .location("办公区") |
| | | .remark("示例数据") |
| | | .build() |
| | | ); |
| | | ExcelUtils.write(response, "考勤导入模板.xls", "考勤记录", HrmAttendanceRecordImportExcelVO.class, list); |
| | | } |
| | | |
| | | @PostMapping("/import") |
| | | @Operation(summary = "导入考勤记录") |
| | | @PreAuthorize("@ss.hasPermission('hrm:attendance-record:import')") |
| | | public CommonResult<String> importExcel(@Valid HrmAttendanceRecordImportReqVO importReqVO) throws IOException { |
| | | List<HrmAttendanceRecordImportExcelVO> list = ExcelUtils.read(importReqVO.getFile(), HrmAttendanceRecordImportExcelVO.class); |
| | | if (CollUtil.isEmpty(list)) { |
| | | return success("没有可导入的数据"); |
| | | } |
| | | int successCount = 0; |
| | | Set<String> missingNames = new LinkedHashSet<>(); |
| | | Set<String> duplicateNames = new LinkedHashSet<>(); |
| | | Set<String> invalidRows = new LinkedHashSet<>(); |
| | | for (HrmAttendanceRecordImportExcelVO item : list) { |
| | | if (item.getDate() == null) { |
| | | invalidRows.add((item.getUserName() == null || item.getUserName().isBlank()) ? "未填姓名的行" : "考勤日期为空(" + item.getUserName().trim() + ")"); |
| | | continue; |
| | | } |
| | | if (item.getUserName() == null || item.getUserName().isBlank()) { |
| | | invalidRows.add("考勤日期为 " + item.getDate() + " 但未填员工姓名"); |
| | | continue; |
| | | } |
| | | List<HrmEmployeeDO> employees = employeeService.getEmployeeListByName(item.getUserName().trim()); |
| | | if (employees.isEmpty()) { |
| | | missingNames.add(item.getUserName().trim()); |
| | | continue; |
| | | } |
| | | HrmEmployeeDO employee = employees.get(0); |
| | | // 存在多个同名员工时,用手机号区分 |
| | | if (employees.size() > 1) { |
| | | String phone = item.getPhone() != null ? item.getPhone().trim() : null; |
| | | List<HrmEmployeeDO> matchedByPhone = new ArrayList<>(); |
| | | if (phone != null && !phone.isEmpty()) { |
| | | for (HrmEmployeeDO emp : employees) { |
| | | if (phone.equals(emp.getPhone())) { |
| | | matchedByPhone.add(emp); |
| | | } |
| | | } |
| | | } |
| | | if (matchedByPhone.size() == 1) { |
| | | employee = matchedByPhone.get(0); |
| | | } else { |
| | | duplicateNames.add(item.getUserName().trim()); |
| | | continue; |
| | | } |
| | | } |
| | | HrmAttendanceRecordDO record = attendanceRecordService.getAttendanceRecordByUserIdAndDate(employee.getId(), item.getDate()); |
| | | if (record == null) { |
| | | record = HrmAttendanceRecordDO.builder() |
| | | .userId(employee.getId()).deptId(employee.getDeptId()).date(item.getDate()) |
| | | .clockInTime(item.getClockInTime()).clockOutTime(item.getClockOutTime()) |
| | | .clockInType(item.getClockInType()).clockOutType(item.getClockOutType()) |
| | | .location(item.getLocation()).remark(item.getRemark()) |
| | | .dataSource(2).build(); |
| | | attendanceRecordService.createImportedRecord(record); |
| | | } else if (Boolean.TRUE.equals(importReqVO.getUpdateSupport())) { |
| | | record.setClockInTime(item.getClockInTime()); |
| | | record.setClockOutTime(item.getClockOutTime()); |
| | | record.setClockInType(item.getClockInType()); |
| | | record.setClockOutType(item.getClockOutType()); |
| | | record.setLocation(item.getLocation()); |
| | | record.setRemark(item.getRemark()); |
| | | attendanceRecordService.updateImportedRecord(record); |
| | | } |
| | | successCount++; |
| | | } |
| | | StringBuilder msg = new StringBuilder("成功导入 " + successCount + " 条"); |
| | | if (!missingNames.isEmpty()) { |
| | | msg.append(";以下员工不存在,未能导入:").append(String.join("、", missingNames)); |
| | | } |
| | | if (!duplicateNames.isEmpty()) { |
| | | msg.append(";以下员工存在多名同名员工,需补充手机号区分,未能导入:").append(String.join("、", duplicateNames)); |
| | | } |
| | | if (!invalidRows.isEmpty()) { |
| | | msg.append(";以下记录数据不完整,未能导入:").append(String.join("、", invalidRows)); |
| | | } |
| | | return success(msg.toString()); |
| | | } |
| | | |
| | | @GetMapping("/export-excel") |
| | | @Operation(summary = "导出考勤记录 Excel") |
| | | @PreAuthorize("@ss.hasPermission('hrm:attendance:export')") |