diff --git a/src/main/java/com/zhgd/xmgl/modules/worker/controller/WorkerAttendanceController.java b/src/main/java/com/zhgd/xmgl/modules/worker/controller/WorkerAttendanceController.java index 1f0b51e9d..7db125f77 100644 --- a/src/main/java/com/zhgd/xmgl/modules/worker/controller/WorkerAttendanceController.java +++ b/src/main/java/com/zhgd/xmgl/modules/worker/controller/WorkerAttendanceController.java @@ -1,5 +1,7 @@ package com.zhgd.xmgl.modules.worker.controller; +import cn.afterturn.easypoi.excel.ExcelExportUtil; +import cn.afterturn.easypoi.excel.entity.TemplateExportParams; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.convert.Convert; import cn.hutool.core.date.DateUtil; @@ -8,6 +10,7 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.zhgd.annotation.OperLog; +import com.zhgd.file.FileUtil; import com.zhgd.jeecg.common.api.vo.Result; import com.zhgd.jeecg.common.execption.OpenAlertException; import com.zhgd.jeecg.common.mybatis.EntityMap; @@ -15,9 +18,9 @@ import com.zhgd.xmgl.constant.Cts; import com.zhgd.xmgl.entity.vo.AttendanceOfEachCompanyVo; import com.zhgd.xmgl.entity.vo.NumberTimeTableVo; import com.zhgd.xmgl.modules.basicdata.service.INoticeService; -import com.zhgd.xmgl.modules.realnamestatistics.entity.vo.WorkerAttendanceVo; import com.zhgd.xmgl.modules.quality.entity.QualityRegionToUfaceDev; import com.zhgd.xmgl.modules.quality.service.IQualityRegionToUfaceDevService; +import com.zhgd.xmgl.modules.realnamestatistics.entity.vo.WorkerAttendanceVo; import com.zhgd.xmgl.modules.worker.entity.MockWorkerAttendanceConfig; import com.zhgd.xmgl.modules.worker.entity.UfaceDev; import com.zhgd.xmgl.modules.worker.entity.WorkerAttendance; @@ -28,7 +31,9 @@ import com.zhgd.xmgl.modules.worker.entity.vo.PresentDayByMonthVo; import com.zhgd.xmgl.modules.worker.entity.vo.SafetyPerformanceAnalysisVo; import com.zhgd.xmgl.modules.worker.service.*; import com.zhgd.xmgl.security.util.SecurityUtils; +import com.zhgd.xmgl.util.EasyPoiUtil; import com.zhgd.xmgl.util.ExcelUtils; +import com.zhgd.xmgl.util.Fileutils; import com.zhgd.xmgl.util.MapBuilder; import io.swagger.annotations.Api; import io.swagger.annotations.ApiImplicitParam; @@ -36,6 +41,7 @@ import io.swagger.annotations.ApiImplicitParams; import io.swagger.annotations.ApiOperation; import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections.MapUtils; +import org.apache.poi.ss.usermodel.Workbook; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Lazy; @@ -44,6 +50,7 @@ import springfox.documentation.annotations.ApiIgnore; import javax.annotation.Resource; import javax.servlet.http.HttpServletResponse; +import java.io.IOException; import java.util.*; import java.util.concurrent.ThreadLocalRandom; import java.util.function.Function; @@ -541,4 +548,90 @@ public class WorkerAttendanceController { public Result> getPresentDayByMonth(@ApiIgnore @RequestBody Map paramMap) { return Result.success(workerAttendanceService.getPresentDayByMonth(paramMap)); } + + @ApiOperation(value = "人员考勤导出excel记录", notes = "人员考勤导出excel记录", httpMethod = "POST") + @ApiImplicitParams({ + @ApiImplicitParam(name = "projectSn", value = "项目sn", paramType = "body", required = true, dataType = "String"), + }) + @PostMapping(value = "/exportXls") + public void exportXls(HttpServletResponse response, @RequestBody HashMap param) { + String templateUrl = null; + try { + Map map = new HashMap<>(); + List records = workerAttendanceService.selectWorkerAttendancePage(param).getRecords(); + List> listMap = new ArrayList<>(); + for (int i = 0; i < records.size(); i++) { + Map objectMap = new HashMap<>(); + WorkerAttendanceVo vo = records.get(i); + objectMap.put("no", i + 1); + objectMap.put("workerName", vo.getWorkerName()); + objectMap.put("personSn", vo.getPersonSn()); + objectMap.put("passType", Objects.equals(vo.getPassType(), 1) ? "进" : "出"); + objectMap.put("createTime", vo.getCreateTime()); + objectMap.put("projectSn", vo.getProjectSn()); + objectMap.put("cardType", getType(vo.getCardType())); + objectMap.put("imageUrl", EasyPoiUtil.getImageEntityByXls(vo.getImageUrl())); + objectMap.put("attendanceType", vo.getAttendanceType()); + objectMap.put("passagewayName", vo.getPassagewayName()); + objectMap.put("attendanceStatus", vo.getAttendanceStatus()); + objectMap.put("temperature", vo.getTemperature()); + objectMap.put("devSn", vo.getDevSn()); + objectMap.put("isStatistics", vo.getIsStatistics()); + objectMap.put("carNumber", vo.getCarNumber()); + objectMap.put("address", vo.getAddress()); + objectMap.put("idCard", vo.getIdCard()); + objectMap.put("regionName", vo.getRegionName()); + objectMap.put("teamName", vo.getTeamName()); + objectMap.put("departmentTeamId", vo.getDepartmentTeamId()); + objectMap.put("workerClassify", vo.getWorkerClassify()); + objectMap.put("codeState", vo.getCodeState()); + objectMap.put("isMock", vo.getIsMock()); + objectMap.put("fieldAcquisitionUrl", vo.getFieldAcquisitionUrl()); + objectMap.put("departmentTeamName", vo.getDepartmentTeamName()); + objectMap.put("mockTime", vo.getMockTime()); + objectMap.put("enterpriseName", vo.getEnterpriseName()); + listMap.add(objectMap); + } + map.put("listMap", listMap); + templateUrl = Fileutils.getExportTemplateFile("excel/人员考勤记录导出.xlsx").getAbsolutePath(); + TemplateExportParams params = new TemplateExportParams(templateUrl); + Workbook workbook = ExcelExportUtil.exportExcel(params, map); + //设置下拉 + ExcelUtils.downLoadExcel("风险点清单导出模板.xlsx", response, workbook); + } catch (IOException e) { + log.error("", e); + throw new OpenAlertException("系统错误"); + } finally { + if (templateUrl != null) { + FileUtil.deleteFile(templateUrl); + } + } + } + + public static String getType(Integer number) { + if (number == null) { + return ""; + } + switch (number) { + case 1: + return "IC卡"; + case 2: + return "人脸识别"; + case 3: + return "指纹识别"; + case 4: + return "补卡操作"; + case 5: + return "二维码"; + case 6: + return "蓝牙"; + case 7: + return "手机打卡"; + case 8: + return "车辆通行"; + default: + return "未知类型"; + } + } + } diff --git a/src/main/java/com/zhgd/xmgl/modules/worker/controller/WorkerDailyAttendanceStatisticsV2Controller.java b/src/main/java/com/zhgd/xmgl/modules/worker/controller/WorkerDailyAttendanceStatisticsV2Controller.java index 348b4a2a5..9d62597ec 100644 --- a/src/main/java/com/zhgd/xmgl/modules/worker/controller/WorkerDailyAttendanceStatisticsV2Controller.java +++ b/src/main/java/com/zhgd/xmgl/modules/worker/controller/WorkerDailyAttendanceStatisticsV2Controller.java @@ -46,6 +46,7 @@ import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections.MapUtils; import org.apache.poi.ss.usermodel.Workbook; import org.apache.poi.ss.util.CellRangeAddress; +import org.apache.poi.xssf.usermodel.XSSFWorkbook; import org.jetbrains.annotations.Nullable; import org.simpleframework.xml.core.Validate; import org.springframework.beans.factory.annotation.Autowired; @@ -747,7 +748,7 @@ public class WorkerDailyAttendanceStatisticsV2Controller { sheetMap.put("listMap", listMap); root.put(j++, sheetMap); } - templateUrl = Fileutils.getExportTemplateFile("excel/" + tempSheetName).getAbsolutePath(); + templateUrl = Fileutils.getExportTemplateFile("excel/workerDailyAttendanceStatisticsV2/" + tempSheetName).getAbsolutePath(); String outputTemplateFilePath = PathUtil.getBasePath() + "/temp/" + IdUtil.randomUUID() + ".xlsx"; EasyPoiUtil.cloneSheetMultipleTimes(templateUrl, outputTemplateFilePath, "1", dateTimes.size() - 1); TemplateExportParams params = new TemplateExportParams(outputTemplateFilePath, true); @@ -843,6 +844,7 @@ public class WorkerDailyAttendanceStatisticsV2Controller { public void exportWorkerDailyAttendancesStaticsByMonthXls(HttpServletResponse response, @RequestBody HashMap param) { String templateUrl = null; try { + ArrayList delColIndexes = new ArrayList<>(); String projectSn = MapUtils.getString(param, "projectSn"); Project project = projectService.getOne(new LambdaQueryWrapper() .eq(Project::getProjectSn, projectSn)); @@ -872,9 +874,9 @@ public class WorkerDailyAttendanceStatisticsV2Controller { .stream().filter(w -> Objects.nonNull(w.getPersonSn())).collect(Collectors.groupingBy(WorkerAttendance::getPersonSn, Collectors.groupingBy(o -> DateUtil.formatDate(DateUtil.parseDate(o.getCreateTime())), Collectors.toList()))); - BigDecimal totalAttendanceDay = BigDecimal.ZERO; BigDecimal totalHour = BigDecimal.ZERO; for (Map.Entry> entry : deptNameMap.entrySet()) { + BigDecimal totalAttendanceDay = BigDecimal.ZERO; Map sheetMap = new HashMap<>(); List> listMap = new ArrayList<>(); List vos = entry.getValue(); @@ -882,7 +884,7 @@ public class WorkerDailyAttendanceStatisticsV2Controller { for (StatisticsListVo vo : vos) { Map map = new HashMap<>(); map.put("no", ++index); - map.put("personType", vo.getPersonType()); + map.put("personType", Objects.equals(vo.getPersonType(), 1) ? "施工人员" : "管理人员"); map.put("enterpriseName", vo.getEnterpriseName()); map.put("workerName", vo.getWorkerName()); map.put("deptName", vo.getDeptName()); @@ -896,7 +898,6 @@ public class WorkerDailyAttendanceStatisticsV2Controller { for (int z = 0; z < dateTimes.size(); z++) { DateTime dateTime = dateTimes.get(z); sheetMap.put("date" + (z + 1), DateUtil.format(dateTime, "M/d")); - sheetMap.put("delete" + (z + 1), false); String value; if (Objects.equals(downloadType, 1) || Objects.equals(downloadType, 2)) { value = getExcelAmPmAttendanceByDate(personSn2Date2AttendancesMap, vo, dateTime, downloadType); @@ -909,9 +910,6 @@ public class WorkerDailyAttendanceStatisticsV2Controller { } map.put("attendanceByDate" + (z + 1), value); } - for (int i = dateTimes.size(); i < 31; i++) { - sheetMap.put("delete" + (i + 1), true); - } map.put("totalHour", vo.getTotalHour()); map.put("totalAttendanceDay", vo.getTotalAttendanceDay()); totalAttendanceDay = NumberUtil.add(vo.getTotalAttendanceDay(), totalAttendanceDay); @@ -928,7 +926,13 @@ public class WorkerDailyAttendanceStatisticsV2Controller { root.put(sheetIndex++, sheetMap); sheetNames.add(entry.getKey()); } + for (int i = 11 + dateTimes.size(); i < 11 + 31; i++) { + delColIndexes.add(i); + } templateUrl = Fileutils.getExportTemplateFile("excel/workerDailyAttendanceStatisticsV2/" + tempSheetName).getAbsolutePath(); + if (CollUtil.isNotEmpty(delColIndexes)) { + ExcelUtils.removeColumns(templateUrl, 0, delColIndexes); + } String outputTemplateFilePath = PathUtil.getBasePath() + "/temp/" + IdUtil.randomUUID() + ".xlsx"; EasyPoiUtil.cloneSheetMultipleTimes(templateUrl, outputTemplateFilePath, "1", sheetNames.size() - 1); TemplateExportParams params = new TemplateExportParams(outputTemplateFilePath, true); @@ -947,8 +951,8 @@ public class WorkerDailyAttendanceStatisticsV2Controller { Integer totalGlNum = 0; Integer totalSgNum = 0; Map deptKeyMap = new HashMap<>(); + int index = 0; for (Map.Entry> entry : date2Map.entrySet()) { - int index = 0; Map map = new HashMap<>(); map.put("no", ++index); map.put("date", entry.getKey()); @@ -963,8 +967,7 @@ public class WorkerDailyAttendanceStatisticsV2Controller { String sgKey = "sg" + bo.getDeptName(); e.put("glNum", "t." + glKey); e.put("sgNum", "t." + sgKey); - e.put("glTotalNum", glKey); - e.put("sgTotalNum", sgKey); + e.put("totalNumKey", bo.getDeptName()); colList.add(e); if (Objects.equals(bo.getPersonType(), 1)) { sgNum = bo.getWorkerNum() + sgNum; @@ -985,7 +988,10 @@ public class WorkerDailyAttendanceStatisticsV2Controller { totalGlNum += glNum; totalSgNum += sgNum; } - sheetMap1.putAll(deptKeyMap); + for (Map map : colList) { + map.put("glTotalNum", deptKeyMap.get("gl" + MapUtils.getString(map, "totalNumKey"))); + map.put("sgTotalNum", deptKeyMap.get("sg" + MapUtils.getString(map, "totalNumKey"))); + } sheetMap1.put("listMap", listMap1); sheetMap1.put("totalGlNum", totalGlNum); sheetMap1.put("totalSgNum", totalSgNum); @@ -999,16 +1005,17 @@ public class WorkerDailyAttendanceStatisticsV2Controller { sheetMap1.put("colList", colList); root.put(0, sheetMap1); sheetNames.add(enterpriseName + "出勤人数"); - + param.put("startTime", startDate); + param.put("endTime", endDate); //导出sheet2上海振南考勤报表 List voList = this.doCountDailyAttendanceByDateRange(param).getRecords(); Map sheetMap2 = new HashMap<>(); - int index = 0; + index = 0; List> listMap2 = new ArrayList<>(); for (StatisticsListVo vo : voList) { Map map = new HashMap<>(); map.put("no", ++index); - map.put("personType", vo.getPersonType()); + map.put("personType", Objects.equals(vo.getPersonType(), 1) ? "施工人员" : "管理人员"); map.put("enterpriseName", vo.getEnterpriseName()); map.put("workerName", vo.getWorkerName()); map.put("deptName", vo.getDeptName()); @@ -1024,14 +1031,10 @@ public class WorkerDailyAttendanceStatisticsV2Controller { for (int z = 0; z < dateTimes.size(); z++) { DateTime dateTime = dateTimes.get(z); sheetMap2.put("date" + (z + 1), DateUtil.format(dateTime, "M/d")); - sheetMap2.put("delete" + (z + 1), false); //每日工时 String value = Optional.ofNullable(vo.getDailyHourMap().get(DateUtil.formatDate(dateTime))).map(decimal -> decimal.toString()).orElse(""); map.put("attendanceByDate" + (z + 1), value); } - for (int i = dateTimes.size(); i < 31; i++) { - sheetMap2.put("delete" + (i + 1), true); - } listMap2.add(map); } sheetMap2.put("listMap", listMap2); @@ -1043,11 +1046,22 @@ public class WorkerDailyAttendanceStatisticsV2Controller { sheetNames.add(enterpriseName + "考勤报表"); templateUrl = Fileutils.getExportTemplateFile("excel/workerDailyAttendanceStatisticsV2/" + tempSheetName).getAbsolutePath(); TemplateExportParams params = new TemplateExportParams(templateUrl, true); + params.setColForEach(true); params.setSheetName(sheetNames.toArray(new String[]{})); Workbook workbook = ExcelExportUtil.exportExcel(root, params); + for (int i = 9 + dateTimes.size(); i < 9 + 31; i++) { + delColIndexes.add(i); + } + if (CollUtil.isNotEmpty(delColIndexes)) { + ExcelUtils.removeColumns(((XSSFWorkbook) workbook), 1, delColIndexes); + } + ExcelUtils.mergeRows(workbook, 0, 0, 0, 0, 4 + colList.size() * 2); ExcelUtils.downLoadExcel(tempSheetName, response, workbook); } else if (Objects.equals(groupByType, 4)) { //按人员 + param.put("startTime", startDate); + param.put("endTime", endDate); + param.put("pageSize", -1); tempSheetName = "单个人员考勤出入明细报表.xlsx"; List voList = this.doCountDailyAttendanceByDateRange(param).getRecords(); Map>> personSn2Date2AttendancesMap = workerAttendanceService.list(new LambdaQueryWrapper() @@ -1074,6 +1088,7 @@ public class WorkerDailyAttendanceStatisticsV2Controller { listMap.add(map); } root.put(sheetIndex++, sheetMap); + sheetMap.put("listMap", listMap); sheetMap.put("projectName", project.getProjectName()); sheetMap.put("personType", vo.getPersonType() == 1 ? "班组" : "部门"); sheetMap.put("enterpriseName", vo.getEnterpriseName()); @@ -1113,7 +1128,7 @@ public class WorkerDailyAttendanceStatisticsV2Controller { for (StatisticsListVo vo : vos) { Map map = new HashMap<>(); map.put("no", ++index); - map.put("personType", vo.getPersonType()); + map.put("personType", Objects.equals(vo.getPersonType(), 1) ? "施工人员" : "管理人员"); map.put("enterpriseName", vo.getEnterpriseName()); map.put("workerName", vo.getWorkerName()); map.put("deptName", vo.getDeptName()); @@ -1127,7 +1142,6 @@ public class WorkerDailyAttendanceStatisticsV2Controller { for (int z = 0; z < dateTimes.size(); z++) { DateTime dateTime = dateTimes.get(z); sheetMap.put("date" + (z + 1), DateUtil.format(dateTime, "M/d")); - sheetMap.put("delete" + (z + 1), false); String value; if (Objects.equals(downloadType, 1) || Objects.equals(downloadType, 2)) { value = getExcelAmPmAttendanceByDate(personSn2Date2AttendancesMap, vo, dateTime, downloadType); @@ -1140,15 +1154,16 @@ public class WorkerDailyAttendanceStatisticsV2Controller { } map.put("attendanceByDate" + (z + 1), value); } - for (int i = dateTimes.size(); i < 31; i++) { - sheetMap.put("delete" + (i + 1), true); - } + map.put("totalHour", vo.getTotalHour()); map.put("totalAttendanceDay", vo.getTotalAttendanceDay()); totalAttendanceDay = NumberUtil.add(vo.getTotalAttendanceDay(), totalAttendanceDay); totalHour = NumberUtil.add(vo.getTotalHour(), totalHour); listMap.add(map); } + for (int i = 11 + dateTimes.size(); i < 11 + 31; i++) { + delColIndexes.add(i); + } sheetMap.put("listMap", listMap); sheetMap.put("totalAttendanceDay", totalAttendanceDay); sheetMap.put("totalWorkerNum", vos.size()); @@ -1162,7 +1177,9 @@ public class WorkerDailyAttendanceStatisticsV2Controller { TemplateExportParams params = new TemplateExportParams(templateUrl, true); params.setSheetName(sheetNames.toArray(new String[]{})); Workbook workbook = ExcelExportUtil.exportExcel(root, params); - + if (CollUtil.isNotEmpty(delColIndexes)) { + ExcelUtils.removeColumns(((XSSFWorkbook) workbook), 0, delColIndexes); + } ExcelUtils.downLoadExcel(tempSheetName, response, workbook); } } catch (IOException e) { diff --git a/src/main/java/com/zhgd/xmgl/modules/worker/entity/vo/StatisticsListVo.java b/src/main/java/com/zhgd/xmgl/modules/worker/entity/vo/StatisticsListVo.java index 6dddc698f..e25e6e18a 100644 --- a/src/main/java/com/zhgd/xmgl/modules/worker/entity/vo/StatisticsListVo.java +++ b/src/main/java/com/zhgd/xmgl/modules/worker/entity/vo/StatisticsListVo.java @@ -79,11 +79,6 @@ public class StatisticsListVo { */ @ApiModelProperty(value = "人员sn") private java.lang.String personSn; - /** - * 劳务人员Id - */ - @ApiModelProperty(value = "劳务人员Id") - private java.lang.Long workerId; /** * 工种名称 */ diff --git a/src/main/java/com/zhgd/xmgl/modules/xz/security/service/impl/XzSecurityDangerFieldConfigServiceImpl.java b/src/main/java/com/zhgd/xmgl/modules/xz/security/service/impl/XzSecurityDangerFieldConfigServiceImpl.java index a8f793f19..1fccf1aa5 100644 --- a/src/main/java/com/zhgd/xmgl/modules/xz/security/service/impl/XzSecurityDangerFieldConfigServiceImpl.java +++ b/src/main/java/com/zhgd/xmgl/modules/xz/security/service/impl/XzSecurityDangerFieldConfigServiceImpl.java @@ -1,26 +1,24 @@ package com.zhgd.xmgl.modules.xz.security.service.impl; -import com.zhgd.jeecg.common.execption.OpenAlertException; -import com.zhgd.xmgl.modules.xz.security.entity.XzSecurityDangerFieldConfig; -import com.zhgd.xmgl.modules.xz.security.entity.vo.XzSecurityDangerFieldConfigVo; -import com.zhgd.xmgl.modules.xz.security.entity.dto.XzSecurityDangerFieldConfigDto; -import com.zhgd.xmgl.modules.xz.security.mapper.XzSecurityDangerFieldConfigMapper; -import com.zhgd.xmgl.modules.xz.security.service.IXzSecurityDangerFieldConfigService; -import org.springframework.stereotype.Service; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; -import com.zhgd.jeecg.common.system.query.QueryGenerator; -import com.zhgd.xmgl.util.PageUtil; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.zhgd.jeecg.common.execption.OpenAlertException; +import com.zhgd.jeecg.common.system.query.QueryGenerator; +import com.zhgd.xmgl.modules.xz.security.entity.XzSecurityDangerFieldConfig; +import com.zhgd.xmgl.modules.xz.security.entity.dto.XzSecurityDangerFieldConfigDto; +import com.zhgd.xmgl.modules.xz.security.entity.vo.XzSecurityDangerFieldConfigVo; +import com.zhgd.xmgl.modules.xz.security.mapper.XzSecurityDangerFieldConfigMapper; +import com.zhgd.xmgl.modules.xz.security.service.IXzSecurityDangerFieldConfigService; +import com.zhgd.xmgl.util.PageUtil; +import com.zhgd.xmgl.util.RefUtil; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; import java.util.HashMap; import java.util.List; -import com.zhgd.xmgl.util.RefUtil; -import org.springframework.transaction.annotation.Transactional; -import org.springframework.beans.factory.annotation.Autowired; - /** * @Description: 安全隐患检查字段设置配置 * @author: pds @@ -90,4 +88,5 @@ public class XzSecurityDangerFieldConfigServiceImpl extends ServiceImpl syncList = new ArrayList<>(); @@ -382,6 +378,8 @@ public class XzHikvisionSyncServiceImpl extends ServiceImpl deleteColumnIndexes) throws IOException { + // 对列索引进行降序排序,以便从右到左删除,避免索引变化问题 + deleteColumnIndexes.sort(Collections.reverseOrder()); + + Sheet sheet = workbook.getSheetAt(sheetIndex); + for (int colIndex : deleteColumnIndexes) { + removeColumn(sheet, colIndex); + } + } + + public static void removeColumns(String excelPath, int sheetIndex, List columnIndexes) throws IOException { + // 对列索引进行降序排序,以便从右到左删除,避免索引变化问题 + columnIndexes.sort(Collections.reverseOrder()); + + try (FileInputStream fis = new FileInputStream(excelPath); + Workbook workbook = WorkbookFactory.create(fis)) { + + Sheet sheet = workbook.getSheetAt(sheetIndex); + + for (int colIndex : columnIndexes) { + removeColumn(sheet, colIndex); + } + + try (FileOutputStream fos = new FileOutputStream(excelPath)) { + workbook.write(fos); + } + } + } + + private static void removeColumn(Sheet sheet, int colIndex) { + // 处理行数据 + for (int rowIndex = 0; rowIndex <= sheet.getLastRowNum(); rowIndex++) { + Row row = sheet.getRow(rowIndex); + if (row != null) { + removeCell(row, colIndex); + + // 将右侧单元格左移 + shiftCellsLeft(row, colIndex); + } + } + + // 处理合并区域 + processMergedRegions(sheet, colIndex); + + // 处理列宽 + shiftColumnWidths(sheet, colIndex); + } + + private static void removeCell(Row row, int colIndex) { + Cell cell = row.getCell(colIndex); + if (cell != null) { + row.removeCell(cell); + } + } + + private static void shiftCellsLeft(Row row, int colIndex) { + for (int i = colIndex + 1; i <= row.getLastCellNum(); i++) { + Cell oldCell = row.getCell(i); + if (oldCell != null) { + Cell newCell = row.createCell(i - 1, oldCell.getCellType()); + copyCellContent(oldCell, newCell); + copyCellStyle(oldCell, newCell); + row.removeCell(oldCell); + } + } + } + + private static void copyCellContent(Cell oldCell, Cell newCell) { + switch (oldCell.getCellType()) { + case STRING: + newCell.setCellValue(oldCell.getStringCellValue()); + break; + case NUMERIC: + newCell.setCellValue(oldCell.getNumericCellValue()); + break; + case BOOLEAN: + newCell.setCellValue(oldCell.getBooleanCellValue()); + break; + case FORMULA: + newCell.setCellFormula(oldCell.getCellFormula()); + break; + case BLANK: + newCell.setCellValue(""); // 将单元格值设置为空字符串 + newCell.setCellType(CellType.BLANK); + break; + case ERROR: + newCell.setCellErrorValue(oldCell.getErrorCellValue()); + break; + default: + break; + } + } + + private static void copyCellStyle(Cell oldCell, Cell newCell) { + Workbook workbook = newCell.getSheet().getWorkbook(); + CellStyle newStyle = workbook.createCellStyle(); + newStyle.cloneStyleFrom(oldCell.getCellStyle()); + newCell.setCellStyle(newStyle); + } + + private static void processMergedRegions(Sheet sheet, int colIndex) { + for (int i = sheet.getNumMergedRegions() - 1; i >= 0; i--) { + CellRangeAddress region = sheet.getMergedRegion(i); + + if (colIndex >= region.getFirstColumn() && colIndex <= region.getLastColumn()) { + // 如果删除的列在合并区域内 + if (region.getFirstColumn() == region.getLastColumn()) { + // 如果合并区域只有一列,直接删除 + sheet.removeMergedRegion(i); + } else { + // 缩小合并区域 + region.setLastColumn(region.getLastColumn() - 1); + sheet.removeMergedRegion(i); + sheet.addMergedRegion(region); + } + } else if (colIndex < region.getFirstColumn()) { + // 如果删除的列在合并区域左侧,将合并区域左移 + region.setFirstColumn(region.getFirstColumn() - 1); + region.setLastColumn(region.getLastColumn() - 1); + sheet.removeMergedRegion(i); + sheet.addMergedRegion(region); + } + // 如果删除的列在合并区域右侧,不需要处理 + } + } + + private static void shiftColumnWidths(Sheet sheet, int colIndex) { + int maxColumn = 255; // Excel的最大列数 + for (int i = colIndex; i < maxColumn; i++) { + int width = sheet.getColumnWidth(i + 1); + sheet.setColumnWidth(i, width); + } + // 清空最后一列 + sheet.setColumnWidth(maxColumn, sheet.getDefaultColumnWidth()); + } + + // 示例用法 + public static void main(String[] args) { + try { + // 假设要删除第1列和第3列(0-based索引) + long l = System.currentTimeMillis(); + List columnsToRemove = new ArrayList<>(); + for (int i = 13; i < 41 + 1; i++) { + columnsToRemove.add(i); + } + removeColumns("C:\\Users\\Administrator\\Desktop\\1.xlsx", 0, columnsToRemove); + System.out.println("列删除成功!" + (System.currentTimeMillis() - l)); + } catch (IOException e) { + e.printStackTrace(); + } + } + + + /** + * 合并Excel中的行 + * + * @param filePath Excel文件路径 + * @param sheetIndex 工作表索引(0-based) + * @param startRow 开始行索引(0-based) + * @param endRow 结束行索引(0-based) + * @throws IOException 文件操作异常 + */ + public static void mergeRows(String filePath, int sheetIndex, int startRow, int endRow) throws IOException { + if (startRow > endRow) { + throw new IllegalArgumentException("开始行索引不能大于结束行索引"); + } + + try (FileInputStream fis = new FileInputStream(filePath); + Workbook workbook = WorkbookFactory.create(fis)) { + + Sheet sheet = workbook.getSheetAt(sheetIndex); + + // 获取工作表的列数 + int lastColumn = getLastColumn(sheet, startRow, endRow); + + // 逐列合并行 + for (int colIndex = 0; colIndex <= lastColumn; colIndex++) { + mergeCellsInColumn(sheet, colIndex, startRow, endRow); + } + + // 保存修改后的文件 + try (FileOutputStream fos = new FileOutputStream(filePath)) { + workbook.write(fos); + } + } + } + + /** + * 获取工作表中指定行范围内的最大列数 + */ + private static int getLastColumn(Sheet sheet, int startRow, int endRow) { + int maxColumn = -1; + for (int rowIndex = startRow; rowIndex <= endRow; rowIndex++) { + Row row = sheet.getRow(rowIndex); + if (row != null) { + int lastCellNum = row.getLastCellNum(); + if (lastCellNum > maxColumn) { + maxColumn = lastCellNum; + } + } + } + return maxColumn == -1 ? 0 : maxColumn - 1; + } + + /** + * 合并指定列中的行单元格 + */ + private static void mergeCellsInColumn(Sheet sheet, int colIndex, int startRow, int endRow) { + // 检查是否需要合并(检查单元格内容是否相同) + if (shouldMergeCells(sheet, colIndex, startRow, endRow)) { + // 创建合并区域 + CellRangeAddress mergeRegion = new CellRangeAddress( + startRow, // 起始行 + endRow, // 结束行 + colIndex, // 起始列 + colIndex // 结束列 + ); + + // 添加合并区域到工作表 + sheet.addMergedRegion(mergeRegion); + + // 设置合并后单元格的样式和内容 + setMergedCellContentAndStyle(sheet, colIndex, startRow, endRow); + } + } + + /** + * 检查指定列中的单元格内容是否相同(决定是否需要合并) + */ + private static boolean shouldMergeCells(Sheet sheet, int colIndex, int startRow, int endRow) { + if (startRow == endRow) { + return false; // 只有一行,不需要合并 + } + + Object firstValue = null; + for (int rowIndex = startRow; rowIndex <= endRow; rowIndex++) { + Row row = sheet.getRow(rowIndex); + if (row == null) { + return false; // 有空行,不合并 + } + + Cell cell = row.getCell(colIndex); + Object currentValue = getCellValue(cell); + + if (firstValue == null) { + firstValue = currentValue; + } else if (!isEqual(firstValue, currentValue)) { + return false; // 值不相同,不合并 + } + } + + return firstValue != null; // 所有值相同且不为空,可以合并 + } + + /** + * 获取单元格的值 + */ + private static Object getCellValue(Cell cell) { + if (cell == null) { + return null; + } + + switch (cell.getCellType()) { + case STRING: + return cell.getStringCellValue(); + case NUMERIC: + return cell.getNumericCellValue(); + case BOOLEAN: + return cell.getBooleanCellValue(); + case FORMULA: + return cell.getCellFormula(); + case BLANK: + return ""; + case ERROR: + return cell.getErrorCellValue(); + default: + return null; + } + } + + /** + * 比较两个值是否相等 + */ + private static boolean isEqual(Object value1, Object value2) { + if (value1 == null && value2 == null) { + return true; + } + if (value1 == null || value2 == null) { + return false; + } + return value1.equals(value2); + } + + /** + * 设置合并后单元格的内容和样式 + */ + private static void setMergedCellContentAndStyle(Sheet sheet, int colIndex, int startRow, int endRow) { + Row firstRow = sheet.getRow(startRow); + if (firstRow == null) { + firstRow = sheet.createRow(startRow); + } + + Cell firstCell = firstRow.getCell(colIndex); + if (firstCell == null) { + firstCell = firstRow.createCell(colIndex); + } + + // 设置合并区域的样式(使用第一个单元格的样式) + CellStyle style = firstCell.getCellStyle(); + + // 为合并区域内的所有单元格设置相同的样式 + for (int rowIndex = startRow; rowIndex <= endRow; rowIndex++) { + Row row = sheet.getRow(rowIndex); + if (row == null) { + row = sheet.createRow(rowIndex); + } + + Cell cell = row.getCell(colIndex); + if (cell == null) { + cell = row.createCell(colIndex); + } + + cell.setCellStyle(style); + } + } + + /** + * 重载方法:合并指定区域 + */ + public static void mergeRows(Workbook workbook, int sheetIndex, int startRow, int endRow, int startCol, int endCol) throws IOException { + Sheet sheet = workbook.getSheetAt(sheetIndex); + // 创建合并区域 + CellRangeAddress mergeRegion = new CellRangeAddress( + startRow, endRow, startCol, endCol + ); + // 添加合并区域 + sheet.addMergedRegion(mergeRegion); + + // 设置合并区域样式 + setMergedRegionStyle(sheet, mergeRegion); + } + + /** + * 设置合并区域的样式 + */ + private static void setMergedRegionStyle(Sheet sheet, CellRangeAddress region) { + Row firstRow = sheet.getRow(region.getFirstRow()); + if (firstRow == null) { + firstRow = sheet.createRow(region.getFirstRow()); + } + + Cell firstCell = firstRow.getCell(region.getFirstColumn()); + if (firstCell == null) { + firstCell = firstRow.createCell(region.getFirstColumn()); + } + + CellStyle style = firstCell.getCellStyle(); + + // 为合并区域内的所有单元格设置相同样式 + for (int row = region.getFirstRow(); row <= region.getLastRow(); row++) { + Row currentRow = sheet.getRow(row); + if (currentRow == null) { + currentRow = sheet.createRow(row); + } + + for (int col = region.getFirstColumn(); col <= region.getLastColumn(); col++) { + Cell cell = currentRow.getCell(col); + if (cell == null) { + cell = currentRow.createCell(col); + } + cell.setCellStyle(style); + } + } + } + +// // 示例用法 +// public static void main(String[] args) { +// try { +// // 示例1:合并第2行到第5行的所有列(0-based索引) +// mergeRows("C:\\Users\\Administrator\\Desktop\\heng.xlsx", 0, 0, 7); +// +// // 示例2:合并第3行到第6行的第2列(0-based索引) +//// mergeRows("example.xlsx", 0, 2, 5, 1, 1); +// +// System.out.println("行合并成功!"); +// } catch (IOException e) { +// e.printStackTrace(); +// } +//} + } diff --git a/src/main/java/com/zhgd/xmgl/util/Fileutils.java b/src/main/java/com/zhgd/xmgl/util/Fileutils.java index 62cc99a6e..227771827 100644 --- a/src/main/java/com/zhgd/xmgl/util/Fileutils.java +++ b/src/main/java/com/zhgd/xmgl/util/Fileutils.java @@ -7,15 +7,13 @@ import org.apache.poi.util.IOUtils; import org.springframework.core.io.ClassPathResource; import java.io.File; +import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.time.LocalDateTime; import java.time.ZoneId; import java.time.format.DateTimeFormatter; -import java.util.ArrayList; -import java.util.Comparator; -import java.util.Date; -import java.util.List; +import java.util.*; import java.util.stream.Collectors; @Slf4j @@ -69,30 +67,64 @@ public class Fileutils { } /** - * 获取导出的模板 + * 获取导出模板文件,每次生成新的随机目录 * - * @param classPath - * @return - * @throws IOException + * @param classPath 类路径下的文件路径 + * @return 临时文件对象 + * @throws IOException 文件操作异常 */ public static File getExportTemplateFile(String classPath) throws IOException { InputStream fis = null; File out = null; try { fis = new ClassPathResource(classPath).getInputStream(); - out = new File(new File(System.getProperty("user.dir").replace("file:/", "/").replace("\\", "/"), "tmp"), StringUtils.substringAfter(classPath, "/")); + + // 生成随机目录名 + String randomDirName = UUID.randomUUID().toString(); + + // 构建输出路径:基础临时目录/随机目录/文件名 + String fileName = StringUtils.substringAfterLast(classPath, "/"); + if (StringUtils.isBlank(fileName)) { + fileName = "template.xlsx"; // 默认文件名 + } + + // 创建临时目录结构 + File baseTempDir = new File(System.getProperty("java.io.tmpdir"), "export_templates"); + File randomTempDir = new File(baseTempDir, randomDirName); + + out = new File(randomTempDir, fileName); + + // 确保目录存在 if (!out.getParentFile().exists()) { out.getParentFile().mkdirs(); } - IOUtils.copy(fis, out); + + // 复制文件 + IOUtils.copy(fis, new FileOutputStream(out)); + } finally { if (fis != null) { - fis.close(); + try { + fis.close(); + } catch (IOException e) { + // 忽略关闭异常 + } } } return out; } + public static List searchData(final List fileArray, String startTime, String endTime) { + DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + //开始时间 + LocalDateTime stadt = LocalDateTime.parse(startTime, df); + //截止时间 + LocalDateTime enddt = LocalDateTime.parse(endTime, df); + + return fileArray.stream().filter(s -> new Date(s.lastModified()).toLocaleString() != null && new Date(s.lastModified()).toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime().isAfter(stadt) && new Date(s.lastModified()).toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime().isBefore(enddt)).collect(Collectors.toList()); + + } + //根据文件修改时间进行比较的内部类 static class CompratorByLastModified implements Comparator { @Override @@ -108,15 +140,4 @@ public class Fileutils { } } - public static List searchData(final List fileArray, String startTime, String endTime) { - DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); - //开始时间 - LocalDateTime stadt = LocalDateTime.parse(startTime, df); - //截止时间 - LocalDateTime enddt = LocalDateTime.parse(endTime, df); - - return fileArray.stream().filter(s -> new Date(s.lastModified()).toLocaleString() != null && new Date(s.lastModified()).toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime().isAfter(stadt) && new Date(s.lastModified()).toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime().isBefore(enddt)).collect(Collectors.toList()); - - } - } diff --git a/src/main/resources/excel/workerDailyAttendanceStatisticsV2/考勤日报-出勤导出模版(上午下午).xlsx b/src/main/resources/excel/workerDailyAttendanceStatisticsV2/考勤日报-出勤导出模版(上午下午).xlsx new file mode 100644 index 000000000..7f7f59470 Binary files /dev/null and b/src/main/resources/excel/workerDailyAttendanceStatisticsV2/考勤日报-出勤导出模版(上午下午).xlsx differ diff --git a/src/main/resources/excel/考勤日报-出勤导出模版(进场出场).xlsx b/src/main/resources/excel/workerDailyAttendanceStatisticsV2/考勤日报-出勤导出模版(进场出场).xlsx similarity index 81% rename from src/main/resources/excel/考勤日报-出勤导出模版(进场出场).xlsx rename to src/main/resources/excel/workerDailyAttendanceStatisticsV2/考勤日报-出勤导出模版(进场出场).xlsx index dca067ec2..21e9aa642 100644 Binary files a/src/main/resources/excel/考勤日报-出勤导出模版(进场出场).xlsx and b/src/main/resources/excel/workerDailyAttendanceStatisticsV2/考勤日报-出勤导出模版(进场出场).xlsx differ diff --git a/src/main/resources/excel/workerDailyAttendanceStatisticsV2/考勤月报-按单位-出勤人数与考勤报表.xlsx b/src/main/resources/excel/workerDailyAttendanceStatisticsV2/考勤月报-按单位-出勤人数与考勤报表.xlsx index 17ba25843..b680b62a9 100644 Binary files a/src/main/resources/excel/workerDailyAttendanceStatisticsV2/考勤月报-按单位-出勤人数与考勤报表.xlsx and b/src/main/resources/excel/workerDailyAttendanceStatisticsV2/考勤月报-按单位-出勤人数与考勤报表.xlsx differ diff --git a/src/main/resources/excel/workerDailyAttendanceStatisticsV2/考勤月报-按班组.xlsx b/src/main/resources/excel/workerDailyAttendanceStatisticsV2/考勤月报-按班组.xlsx index 0cc9171c3..d53dc13a4 100644 Binary files a/src/main/resources/excel/workerDailyAttendanceStatisticsV2/考勤月报-按班组.xlsx and b/src/main/resources/excel/workerDailyAttendanceStatisticsV2/考勤月报-按班组.xlsx differ diff --git a/src/main/resources/excel/workerDailyAttendanceStatisticsV2/考勤月报-按项目.xlsx b/src/main/resources/excel/workerDailyAttendanceStatisticsV2/考勤月报-按项目.xlsx index 2b9262dfb..0151dc52c 100644 Binary files a/src/main/resources/excel/workerDailyAttendanceStatisticsV2/考勤月报-按项目.xlsx and b/src/main/resources/excel/workerDailyAttendanceStatisticsV2/考勤月报-按项目.xlsx differ diff --git a/src/main/resources/excel/人员考勤记录导出.xlsx b/src/main/resources/excel/人员考勤记录导出.xlsx new file mode 100644 index 000000000..d0fef0f9a Binary files /dev/null and b/src/main/resources/excel/人员考勤记录导出.xlsx differ diff --git a/src/main/resources/excel/考勤日报-出勤导出模版(上午下午).xlsx b/src/main/resources/excel/考勤日报-出勤导出模版(上午下午).xlsx deleted file mode 100644 index a1c392ea3..000000000 Binary files a/src/main/resources/excel/考勤日报-出勤导出模版(上午下午).xlsx and /dev/null differ