diff --git a/src/main/java/cn/lihongjie/coal/acAppointment/dto/AcAppointmentDto.java b/src/main/java/cn/lihongjie/coal/acAppointment/dto/AcAppointmentDto.java index bf1c40ed..ad511221 100644 --- a/src/main/java/cn/lihongjie/coal/acAppointment/dto/AcAppointmentDto.java +++ b/src/main/java/cn/lihongjie/coal/acAppointment/dto/AcAppointmentDto.java @@ -3,12 +3,17 @@ package cn.lihongjie.coal.acAppointment.dto; import cn.lihongjie.coal.acDevice.dto.AcDeviceDto; import cn.lihongjie.coal.base.dto.OrgCommonDto; +import io.hypersistence.utils.hibernate.type.array.ListArrayType; + import jakarta.persistence.ManyToOne; import lombok.Data; import org.hibernate.annotations.Comment; import org.hibernate.annotations.Formula; +import org.hibernate.annotations.Type; + +import java.util.List; @Data public class AcAppointmentDto extends OrgCommonDto { @@ -35,6 +40,9 @@ public class AcAppointmentDto extends OrgCommonDto { @Comment("事由") private String reason; + @Formula("(select array_agg(d.id) from t_ac_device_data d where d.plate_no = plate_no and d.pass_time between start_time and end_time)") + @Type(ListArrayType.class) + private List acDeviceDataIds; @Comment("下发时间") @@ -79,4 +87,16 @@ public class AcAppointmentDto extends OrgCommonDto { private String archiveStatus; private String archiveStatusName; + + @Comment("预约状态") + private String appointmentStatus; + + @Formula( + "(select i.name\n" + + "from t_dictionary d,\n" + + " t_dictionary_item i\n" + + "where d.id = i.dictionary_id\n" + + " and d.code = 'appointment.status'\n" + + " and i.code = appointment_status)") + private String appointmentStatusName; } diff --git a/src/main/java/cn/lihongjie/coal/acAppointment/dto/BatchCreateAcAppointmentDto.java b/src/main/java/cn/lihongjie/coal/acAppointment/dto/BatchCreateAcAppointmentDto.java index 478ec89b..da820446 100644 --- a/src/main/java/cn/lihongjie/coal/acAppointment/dto/BatchCreateAcAppointmentDto.java +++ b/src/main/java/cn/lihongjie/coal/acAppointment/dto/BatchCreateAcAppointmentDto.java @@ -11,6 +11,8 @@ import java.util.List; @Data public class BatchCreateAcAppointmentDto extends OrgCommonDto { + private String device; + @Comment("预约开始时间") private java.time.LocalDateTime startTime; diff --git a/src/main/java/cn/lihongjie/coal/acAppointment/entity/AcAppointmentEntity.java b/src/main/java/cn/lihongjie/coal/acAppointment/entity/AcAppointmentEntity.java index 60bbc081..ed298e82 100644 --- a/src/main/java/cn/lihongjie/coal/acAppointment/entity/AcAppointmentEntity.java +++ b/src/main/java/cn/lihongjie/coal/acAppointment/entity/AcAppointmentEntity.java @@ -3,6 +3,8 @@ package cn.lihongjie.coal.acAppointment.entity; import cn.lihongjie.coal.acDevice.entity.AcDeviceEntity; import cn.lihongjie.coal.base.entity.OrgCommonEntity; +import io.hypersistence.utils.hibernate.type.array.ListArrayType; + import jakarta.persistence.Entity; import jakarta.persistence.ManyToOne; @@ -11,6 +13,9 @@ import lombok.Data; import org.hibernate.annotations.ColumnDefault; import org.hibernate.annotations.Comment; import org.hibernate.annotations.Formula; +import org.hibernate.annotations.Type; + +import java.util.List; @Data @Entity @@ -59,7 +64,9 @@ public class AcAppointmentEntity extends OrgCommonEntity { - + @Formula("(select array_agg(d.id) from t_ac_device_data d where d.plate_no = plate_no and d.pass_time between start_time and end_time)") + @Type(ListArrayType.class) + private List acDeviceDataIds; diff --git a/src/main/java/cn/lihongjie/coal/acAppointment/service/AcAppointmentService.java b/src/main/java/cn/lihongjie/coal/acAppointment/service/AcAppointmentService.java index 00651a5d..eaf846a9 100644 --- a/src/main/java/cn/lihongjie/coal/acAppointment/service/AcAppointmentService.java +++ b/src/main/java/cn/lihongjie/coal/acAppointment/service/AcAppointmentService.java @@ -15,8 +15,6 @@ import cn.lihongjie.coal.dbFunctions.DbFunctionService; import cn.lihongjie.coal.exception.BizException; import cn.lihongjie.coal.rabbitmq.RabbitMQService; -import com.google.common.base.Splitter; - import jakarta.persistence.criteria.CriteriaBuilder; import jakarta.persistence.criteria.CriteriaQuery; import jakarta.persistence.criteria.Predicate; @@ -34,6 +32,7 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.time.LocalDateTime; +import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -54,7 +53,8 @@ public class AcAppointmentService AcAppointmentEntity entity = mapper.toEntity(request); entity.setAppointmentStatus("0"); - + entity.setSendStatus("0"); + entity.setDeleteStatus("0"); this.repository.save(entity); rabbitMQService.sendToSysExchange("acAppointment.create", entity.getId(), new HashMap()); @@ -66,9 +66,11 @@ public class AcAppointmentService for (String no : request.getLines()) { - List parts = Splitter.on(",").trimResults().omitEmptyStrings().splitToList(no); + List parts = Arrays.stream(no.split("[,,]")).toList(); CreateAcAppointmentDto dto = new CreateAcAppointmentDto(); + dto.setDevice(request.getDevice()); + dto.setStartTime(request.getStartTime()); dto.setEndTime(request.getEndTime()); dto.setPlateNo(parts.get(0)); @@ -138,7 +140,7 @@ public class AcAppointmentService AcAppointmentEntity::getArchiveStatus, x -> "0", (e, actual, expected) -> { - throw new BizException("数据 " + "已归档,无法删除"); + throw new BizException("数据 " + "已归档,无法操作"); }); List all = this.repository.findAllById(request.getIds()); diff --git a/src/main/java/cn/lihongjie/coal/common/Base64File.java b/src/main/java/cn/lihongjie/coal/common/Base64File.java new file mode 100644 index 00000000..275d0ad8 --- /dev/null +++ b/src/main/java/cn/lihongjie/coal/common/Base64File.java @@ -0,0 +1,35 @@ +package cn.lihongjie.coal.common; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.SneakyThrows; + +import org.apache.commons.io.IOUtils; + +import java.io.InputStream; +import java.util.*; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class Base64File { + + private String fileName; + + private String base64; + + public void setData(byte[] data) { + this.base64 = Base64.getEncoder().encodeToString(data); + } + + public void setData(String data) { + this.base64 = Base64.getEncoder().encodeToString(data.getBytes()); + } + + @SneakyThrows + public void setData(InputStream is) { + + setData(IOUtils.toByteArray(is)); + } +} diff --git a/src/main/java/cn/lihongjie/coal/common/ExcelUtils.java b/src/main/java/cn/lihongjie/coal/common/ExcelUtils.java index 6d266581..00be7cf2 100644 --- a/src/main/java/cn/lihongjie/coal/common/ExcelUtils.java +++ b/src/main/java/cn/lihongjie/coal/common/ExcelUtils.java @@ -10,12 +10,13 @@ import lombok.experimental.UtilityClass; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; -import org.apache.poi.ss.formula.functions.T; +import org.apache.poi.ss.SpreadsheetVersion; import org.apache.poi.ss.usermodel.*; import org.apache.poi.ss.util.CellRangeAddressList; import org.apache.poi.ss.util.CellReference; import org.apache.poi.xssf.usermodel.*; +import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.net.URLEncoder; @@ -23,12 +24,16 @@ import java.nio.charset.StandardCharsets; import java.time.LocalDate; import java.time.LocalDateTime; import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicReference; import java.util.function.Function; import java.util.function.Supplier; @UtilityClass public class ExcelUtils { + public static Map> wbCtxManager = new ConcurrentHashMap<>(); + public static String getCode(Object value) { if (value == null) { return null; @@ -44,8 +49,7 @@ public class ExcelUtils { } public static LocalDate getLocalDate(Object value) { - - + if (value == null) { return null; } @@ -53,7 +57,10 @@ public class ExcelUtils { return (LocalDate) value; } if (value instanceof Date) { - return ((Date) value).toInstant().atZone(TimeZone.getDefault().toZoneId()).toLocalDate(); + return ((Date) value) + .toInstant() + .atZone(TimeZone.getDefault().toZoneId()) + .toLocalDate(); } if (value instanceof LocalDateTime) { return ((LocalDateTime) value).toLocalDate(); @@ -65,7 +72,6 @@ public class ExcelUtils { return LocalDate.parse((String) value); } return null; - } public static List readFirstSheetToObjectList( @@ -115,9 +121,8 @@ public class ExcelUtils { } case NUMERIC: { - if (DateUtil.isCellDateFormatted(cell)) { - value = cell.getDateCellValue(); + value = cell.getDateCellValue(); } else { value = cell.getNumericCellValue(); @@ -175,7 +180,8 @@ public class ExcelUtils { String wbName, List headers, HeaderCellCustomizer headerCellCustomizer, - HttpServletResponse response) { + HttpServletResponse response, + SheetCustomizer sheetCustomizer) { genSingleSheetToHttp( wbName, null, @@ -183,7 +189,42 @@ public class ExcelUtils { headerCellCustomizer, Collections.emptyList(), null, - response); + response, + sheetCustomizer); + } + + public static void genSingleSheetToBase64( + String wbName, + List headers, + HeaderCellCustomizer headerCellCustomizer, + AtomicReference ref, + SheetCustomizer sheetCustomizer) { + genSingleSheetToBase64( + wbName, + null, + headers, + headerCellCustomizer, + Collections.emptyList(), + null, + ref, + sheetCustomizer); + } + + public static void genSingleSheetToBase64File( + String wbName, + List headers, + HeaderCellCustomizer headerCellCustomizer, + Base64File ref, + SheetCustomizer sheetCustomizer) { + genSingleSheetToBase64File( + wbName, + null, + headers, + headerCellCustomizer, + Collections.emptyList(), + null, + ref, + sheetCustomizer); } public static void genSingleSheetToHttp( @@ -193,7 +234,8 @@ public class ExcelUtils { HeaderCellCustomizer headerCellCustomizer, Iterable data, Function2 valueGetter, - HttpServletResponse response) { + HttpServletResponse response, + SheetCustomizer sheetCustomizer) { genSingleSheet( wbName, sheetName, @@ -201,7 +243,48 @@ public class ExcelUtils { headerCellCustomizer, data, valueGetter, - WorkbookConsumer.httpResponseConsumer(response)); + WorkbookConsumer.httpResponseConsumer(response), + sheetCustomizer); + } + + public static void genSingleSheetToBase64( + String wbName, + String sheetName, + List headers, + HeaderCellCustomizer headerCellCustomizer, + Iterable data, + Function2 valueGetter, + AtomicReference ref, + SheetCustomizer sheetCustomizer) { + genSingleSheet( + wbName, + sheetName, + headers, + headerCellCustomizer, + data, + valueGetter, + WorkbookConsumer.base64Consumer(ref), + sheetCustomizer); + } + + public static void genSingleSheetToBase64File( + String wbName, + String sheetName, + List headers, + HeaderCellCustomizer headerCellCustomizer, + Iterable data, + Function2 valueGetter, + Base64File ref, + SheetCustomizer sheetCustomizer) { + genSingleSheet( + wbName, + sheetName, + headers, + headerCellCustomizer, + data, + valueGetter, + WorkbookConsumer.base64FileConsumer(ref), + sheetCustomizer); } public static void genSingleSheet( @@ -211,7 +294,8 @@ public class ExcelUtils { HeaderCellCustomizer headerCellCustomizer, Iterable data, Function2 valueGetter, - WorkbookConsumer workbookConsumer) { + WorkbookConsumer workbookConsumer, + SheetCustomizer sheetCustomizer) { genSingleSheet( wbName, sheetName, @@ -220,7 +304,8 @@ public class ExcelUtils { data, valueGetter, null, - workbookConsumer); + workbookConsumer, + sheetCustomizer); } public static void genSingleSheet( @@ -231,82 +316,394 @@ public class ExcelUtils { Iterable data, Function2 valueGetter, DataCellCustomizer dataCellCustomizer, + WorkbookConsumer workbookConsumer, + SheetCustomizer sheetCustomizer) { + genSingleSheet( + wbName, + sheetName, + headers, + headerCellCustomizer, + data, + valueGetter, + sheetCustomizer, + dataCellCustomizer, + workbookConsumer); + } + + public static void genSingleSheet( + String wbName, + String sheetName, + List headers, + HeaderCellCustomizer headerCellCustomizer, + Iterable data, + Function2 valueGetter, + SheetCustomizer sheetCustomizer, + DataCellCustomizer dataCellCustomizer, WorkbookConsumer workbookConsumer) { + try { + Workbook workbook = new XSSFWorkbook(); + try { - try (Workbook workbook = new XSSFWorkbook()) { + HashMap wbCtx = new HashMap<>(); + wbCtxManager.put(workbook.hashCode() + "", wbCtx); + Sheet sheet = + StringUtils.isEmpty(sheetName) + ? workbook.createSheet() + : workbook.createSheet(sheetName); - Sheet sheet = - StringUtils.isEmpty(sheetName) - ? workbook.createSheet() - : workbook.createSheet(sheetName); - - Row headerRow = sheet.createRow(0); - for (int i = 0, headersSize = headers.size(); i < headersSize; i++) { - String header = headers.get(i); - - Cell cell = headerRow.createCell(i); - cell.setCellValue(header); - if (headerCellCustomizer != null) { - - headerCellCustomizer.customize(header, cell); - } - } - - int rowNum = 1; - - for (Object d : data) { - Row row = sheet.createRow(rowNum++); + Row headerRow = sheet.createRow(0); for (int i = 0, headersSize = headers.size(); i < headersSize; i++) { String header = headers.get(i); - Cell cell = row.createCell(i); - Object value = valueGetter == null ? null : valueGetter.apply(header, d); - if (value == null) { + Cell cell = headerRow.createCell(i); + cell.setCellValue(header); + if (headerCellCustomizer != null) { - cell.setBlank(); - } else if (value instanceof CharSequence) { - cell.setCellValue(value.toString()); - } else if (value instanceof Number) { - cell.setCellValue(((Number) value).doubleValue()); - } else if (value instanceof Date) { - cell.setCellValue((Date) value); - } else if (value instanceof Boolean) { - cell.setCellValue((Boolean) value); - } else if (value instanceof LocalDateTime) { - - cell.setCellValue((LocalDateTime) value); - } else if (value instanceof LocalDate) { - - cell.setCellValue((LocalDate) value); - } else if (value instanceof Calendar) { - cell.setCellValue((Calendar) value); - } else { - - if (value instanceof Iterable) { - List list = new ArrayList<>(); - for (Object o : (Iterable) value) { - list.add(o.toString()); - } - cell.setCellValue(String.join(",", list)); - } else { - cell.setCellValue(value.toString()); - } + headerCellCustomizer.customize(header, cell); } - if (dataCellCustomizer != null) { + String cellValue = cell.getStringCellValue(); - dataCellCustomizer.customize(header, d, value, cell); + wbCtx.put( + "max_column_length_" + i, + StringUtils.defaultIfBlank(cellValue, "").length()); + } + + int rowNum = 1; + + for (Object d : data) { + Row row = sheet.createRow(rowNum++); + for (int i = 0, headersSize = headers.size(); i < headersSize; i++) { + String header = headers.get(i); + Cell cell = row.createCell(i); + Object value = valueGetter == null ? null : valueGetter.apply(header, d); + int newLength = 0; + String maxColumnLengthKey = "max_column_length_" + i; + + if (value == null) { + + cell.setBlank(); + + } else if (value instanceof CharSequence) { + cell.setCellValue(value.toString()); + newLength = value.toString().length(); + } else if (value instanceof Number) { + cell.setCellValue(((Number) value).doubleValue()); + newLength = value.toString().length(); + } else if (value instanceof Date) { + cell.setCellValue((Date) value); + + } else if (value instanceof Boolean) { + cell.setCellValue((Boolean) value); + newLength = 2; + } else if (value instanceof LocalDateTime) { + + cell.setCellValue((LocalDateTime) value); + newLength = 12; + } else if (value instanceof LocalDate) { + + cell.setCellValue((LocalDate) value); + + newLength = 6; + } else if (value instanceof Calendar) { + cell.setCellValue((Calendar) value); + newLength = 12; + } else { + + if (value instanceof Iterable) { + List list = new ArrayList<>(); + for (Object o : (Iterable) value) { + list.add(o.toString()); + } + cell.setCellValue(String.join(",", list)); + + newLength = cell.getStringCellValue().length(); + } else { + cell.setCellValue(value.toString()); + newLength = value.toString().length(); + } + } + + if (dataCellCustomizer != null) { + + dataCellCustomizer.customize(header, d, value, cell); + } + int oldLen = Integer.parseInt(wbCtx.get(maxColumnLengthKey).toString()); + + wbCtx.put(maxColumnLengthKey, Math.max(oldLen, newLength)); } } + + if (sheetCustomizer != null) { + sheetCustomizer.customize(sheet); + } + + workbookConsumer.accept(wbName, workbook); + + } finally { + workbook.close(); + wbCtxManager.remove(workbook.hashCode() + ""); } - - workbookConsumer.accept(wbName, workbook); - } catch (IOException e) { throw new RuntimeException(e); } } + public interface ValidationInfo { + + record ListValidationInfo(List list) implements ValidationInfo {} + + record AnyValidationInfo() implements ValidationInfo {} + + record IntValidationInfo(int opt, String formula1, String formula2) + implements ValidationInfo {} + + record DecimalValidationInfo(int opt, String formula1, String formula2) + implements ValidationInfo {} + + record DateValidationInfo(int opt, String formula1, String formula2) + implements ValidationInfo { + + public DateValidationInfo(int opt, LocalDate d1, LocalDate d2) { + + this( + opt, + d1 == null ? null : "DATEVALUE(\"" + d1 + "\")", + d2 == null ? null : "DATEVALUE(\"" + d2 + "\")"); + } + + + public DateValidationInfo() { + this(DataValidationConstraint.OperatorType.BETWEEN, LocalDate.of(1900, 1, 1), + LocalDate.of(2100, 1, 1)); + } + } + + record TimeValidationInfo(int opt, String formula1, String formula2) + implements ValidationInfo {} + } + + public interface SheetCustomizer { + + static SheetCustomizer centerFirstRowCustomizer() { + return new SheetCustomizer() { + @Override + public void customize(Sheet sheet) { + CellStyle style = sheet.getWorkbook().createCellStyle(); + style.setAlignment(HorizontalAlignment.CENTER); + style.setVerticalAlignment(VerticalAlignment.CENTER); + Row firstRow = sheet.getRow(0); + for (Cell cell : firstRow) { + cell.setCellStyle(style); + } + } + }; + } + + static SheetCustomizer autoSizeColumnCustomizer() { + return new SheetCustomizer() { + @Override + public void customize(Sheet sheet) { + + Row firstRow = sheet.getRow(0); + for (int i = 0; i < firstRow.getLastCellNum(); i++) { + try { + + int maxLen = + Integer.parseInt( + wbCtxManager + .get(sheet.getWorkbook().hashCode() + "") + .get("max_column_length_" + i) + .toString()); + sheet.setColumnWidth(i, maxLen * 256 * 4); + } catch (Exception e) { + sheet.autoSizeColumn(i); + } + } + } + }; + } + + static SheetCustomizer headerBasedConstrainCustomizer( + Function headerMap) { + + return new SheetCustomizer() { + @Override + public void customize(Sheet sheet) { + + XSSFDataValidationHelper helper = + new XSSFDataValidationHelper((XSSFSheet) sheet); + + Row headerRow = sheet.getRow(0); + + for (Cell headerCell : headerRow) { + + CellRangeAddressList addressList = + new CellRangeAddressList( + headerCell.getRowIndex() + 1, + SpreadsheetVersion.EXCEL97.getLastRowIndex(), + headerCell.getColumnIndex(), + headerCell.getColumnIndex()); + String headerName = headerCell.getStringCellValue(); + + ValidationInfo validationInfo = headerMap.apply(headerName); + + if (validationInfo instanceof ValidationInfo.ListValidationInfo) { + List list = + ((ValidationInfo.ListValidationInfo) validationInfo).list(); + + Map wbCtx = + wbCtxManager.get(sheet.getWorkbook().hashCode() + ""); + Object o = wbCtx.get("hiddenSheet"); + + Sheet hiddenSheet = null; + + if (o == null) { + hiddenSheet = sheet.getWorkbook().createSheet("hidden"); + sheet.getWorkbook() + .setSheetHidden( + hiddenSheet + .getWorkbook() + .getSheetIndex(hiddenSheet), + true); + wbCtx.put("hiddenSheet", hiddenSheet); + } else { + hiddenSheet = (Sheet) o; + } + + Row row = hiddenSheet.createRow(hiddenSheet.getLastRowNum() + 1); + row.createCell(0).setCellValue(headerName + "选项"); + for (int i = 0; i < list.size(); i++) { + + row.createCell(i + 1).setCellValue(list.get(i)); + } + + Name wbName = hiddenSheet.getWorkbook().createName(); + int rowIndex = row.getRowNum(); + wbName.setNameName("validate_" + rowIndex); + CellReference rangeStart = new CellReference(rowIndex, 1, true, true); + + CellReference rangeEnd = + new CellReference(rowIndex, list.size(), true, true); + + wbName.setRefersToFormula( + hiddenSheet.getSheetName() + + "!" + + rangeStart.formatAsString(false) + + ":" + + rangeEnd.formatAsString(false)); + + XSSFDataValidationConstraint dvConstraint = + (XSSFDataValidationConstraint) + helper.createFormulaListConstraint( + wbName.getNameName()); + + XSSFDataValidation validation = + (XSSFDataValidation) + helper.createValidation(dvConstraint, addressList); + validation.setSuppressDropDownArrow(true); + validation.setShowErrorBox(true); + sheet.addValidationData(validation); + + } else if (validationInfo instanceof ValidationInfo.AnyValidationInfo) { + + } else if (validationInfo instanceof ValidationInfo.IntValidationInfo) { + + DataValidationConstraint integerConstraint = + helper.createIntegerConstraint( + ((ValidationInfo.IntValidationInfo) validationInfo) + .opt(), + ((ValidationInfo.IntValidationInfo) validationInfo) + .formula1(), + ((ValidationInfo.IntValidationInfo) validationInfo) + .formula2()); + + XSSFDataValidation validation = + (XSSFDataValidation) + helper.createValidation(integerConstraint, addressList); + validation.setSuppressDropDownArrow(true); + validation.setShowErrorBox(true); + + sheet.addValidationData(validation); + + } else if (validationInfo instanceof ValidationInfo.DecimalValidationInfo) { + + DataValidationConstraint decimalConstraint = + helper.createDecimalConstraint( + ((ValidationInfo.DecimalValidationInfo) validationInfo) + .opt(), + ((ValidationInfo.DecimalValidationInfo) validationInfo) + .formula1(), + ((ValidationInfo.DecimalValidationInfo) validationInfo) + .formula2()); + + XSSFDataValidation validation = + (XSSFDataValidation) + helper.createValidation(decimalConstraint, addressList); + validation.setSuppressDropDownArrow(true); + validation.setShowErrorBox(true); + + sheet.addValidationData(validation); + + } else if (validationInfo instanceof ValidationInfo.DateValidationInfo) { + + DataValidationConstraint dateConstraint = + helper.createDateConstraint( + ((ValidationInfo.DateValidationInfo) validationInfo) + .opt(), + ((ValidationInfo.DateValidationInfo) validationInfo) + .formula1(), + ((ValidationInfo.DateValidationInfo) validationInfo) + .formula2(), + null); + + XSSFDataValidation validation = + (XSSFDataValidation) + helper.createValidation(dateConstraint, addressList); + validation.setSuppressDropDownArrow(true); + validation.setShowErrorBox(true); + + sheet.addValidationData(validation); + + } else if (validationInfo instanceof ValidationInfo.TimeValidationInfo) { + + DataValidationConstraint timeConstraint = + helper.createTimeConstraint( + ((ValidationInfo.TimeValidationInfo) validationInfo) + .opt(), + ((ValidationInfo.TimeValidationInfo) validationInfo) + .formula1(), + ((ValidationInfo.TimeValidationInfo) validationInfo) + .formula2()); + + XSSFDataValidation validation = + (XSSFDataValidation) + helper.createValidation(timeConstraint, addressList); + validation.setSuppressDropDownArrow(true); + validation.setShowErrorBox(true); + + sheet.addValidationData(validation); + } else { + throw new RuntimeException("unknown validation info"); + } + } + } + }; + } + + default SheetCustomizer andThen(SheetCustomizer other) { + return new SheetCustomizer() { + @Override + public void customize(Sheet sheet) { + SheetCustomizer.this.customize(sheet); + other.customize(sheet); + } + }; + } + + void customize(Sheet sheet); + } + @FunctionalInterface public interface CellValueHandler { void handle(Cell headerCell, Cell dataCell, Object rowObject, Object value); @@ -320,12 +717,47 @@ public class ExcelUtils { @FunctionalInterface public interface WorkbookConsumer { + static WorkbookConsumer base64Consumer(AtomicReference strRef) { + return (name, workbook) -> { + try (ByteArrayOutputStream bs = new ByteArrayOutputStream()) { + workbook.write(bs); + strRef.set(Base64.getEncoder().encodeToString(bs.toByteArray())); + } catch (IOException e) { + throw new RuntimeException(e); + } + }; + } + + static WorkbookConsumer base64FileConsumer(Base64File file) { + return (name, workbook) -> { + try (ByteArrayOutputStream bs = new ByteArrayOutputStream()) { + workbook.write(bs); + file.setFileName(name); + file.setData(bs.toByteArray()); + } catch (IOException e) { + throw new RuntimeException(e); + } + }; + } + + static WorkbookConsumer byteArrayConsumer(ByteArrayOutputStream bs) { + return (name, workbook) -> { + try { + workbook.write(bs); + } catch (IOException e) { + throw new RuntimeException(e); + } + }; + } + static WorkbookConsumer httpResponseConsumer(HttpServletResponse response) { return (name, workbook) -> { try { response.setHeader( "Content-Disposition", - "attachment; filename=" + URLEncoder.encode(name, StandardCharsets.UTF_8) + ".xlsx"); + "attachment; filename=" + + URLEncoder.encode(name, StandardCharsets.UTF_8) + + ".xlsx"); workbook.write(response.getOutputStream()); } catch (IOException e) { throw new RuntimeException(e); @@ -371,20 +803,28 @@ public class ExcelUtils { } Row row = hiddenSheet.createRow(rowIndex); - + row.createCell(0).setCellValue(name + "选项"); for (int i = 0; i < list.size(); i++) { - row.createCell(i).setCellValue(list.get(i)); + row.createCell(i + 1).setCellValue(list.get(i)); } Name wbName = hiddenSheet.getWorkbook().createName(); wbName.setNameName("validate_" + (rowIndex)); - CellReference cellReference = - new CellReference( - hiddenSheet.getSheetName(), rowIndex, list.size(), true, true); - wbName.setRefersToFormula(cellReference.formatAsString()); + CellReference rangeStart = new CellReference(rowIndex, 1, true, true); + + CellReference rangeEnd = new CellReference(rowIndex, list.size(), true, true); + + wbName.setRefersToFormula( + hiddenSheet.getSheetName() + + "!" + + rangeStart.formatAsString(false) + + ":" + + rangeEnd.formatAsString(false)); + XSSFDataValidationHelper dvHelper = new XSSFDataValidationHelper((XSSFSheet) cell.getSheet()); + XSSFDataValidationConstraint dvConstraint = (XSSFDataValidationConstraint) dvHelper.createFormulaListConstraint(wbName.getNameName()); diff --git a/src/main/java/cn/lihongjie/coal/employee/controller/EmployeeController.java b/src/main/java/cn/lihongjie/coal/employee/controller/EmployeeController.java index 09650099..f5a78436 100644 --- a/src/main/java/cn/lihongjie/coal/employee/controller/EmployeeController.java +++ b/src/main/java/cn/lihongjie/coal/employee/controller/EmployeeController.java @@ -4,14 +4,13 @@ import cn.lihongjie.coal.annotation.OrgScope; import cn.lihongjie.coal.annotation.SysLog; import cn.lihongjie.coal.base.dto.CommonQuery; import cn.lihongjie.coal.base.dto.IdRequest; +import cn.lihongjie.coal.common.Base64File; import cn.lihongjie.coal.employee.dto.CreateEmployeeDto; import cn.lihongjie.coal.employee.dto.EmployeeDto; import cn.lihongjie.coal.employee.dto.ImportEmpFromExcelRequest; import cn.lihongjie.coal.employee.dto.UpdateEmployeeDto; import cn.lihongjie.coal.employee.service.EmployeeService; -import jakarta.servlet.http.HttpServletResponse; - import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; @@ -57,9 +56,8 @@ public class EmployeeController { @PostMapping("/importTemplate") - public void importTemplate(HttpServletResponse response) { - this.service.generateImportTemplate(response); - + public Base64File importTemplate() { + return (this.service.generateImportTemplate()); } diff --git a/src/main/java/cn/lihongjie/coal/employee/service/EmployeeService.java b/src/main/java/cn/lihongjie/coal/employee/service/EmployeeService.java index 31704f3a..45ce1c40 100644 --- a/src/main/java/cn/lihongjie/coal/employee/service/EmployeeService.java +++ b/src/main/java/cn/lihongjie/coal/employee/service/EmployeeService.java @@ -3,6 +3,7 @@ package cn.lihongjie.coal.employee.service; import cn.lihongjie.coal.base.dto.CommonQuery; import cn.lihongjie.coal.base.dto.IdRequest; import cn.lihongjie.coal.base.service.BaseService; +import cn.lihongjie.coal.common.Base64File; import cn.lihongjie.coal.common.ExcelUtils; import cn.lihongjie.coal.department.dto.CreateDepartmentDto; import cn.lihongjie.coal.department.dto.DepartmentDto; @@ -25,7 +26,6 @@ import io.vavr.Function1; import jakarta.persistence.EntityManager; import jakarta.persistence.PersistenceContext; -import jakarta.servlet.http.HttpServletResponse; import lombok.Cleanup; import lombok.SneakyThrows; @@ -41,7 +41,6 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.io.InputStream; -import java.util.ArrayList; import java.util.List; @Service @@ -124,21 +123,35 @@ public class EmployeeService extends BaseService - switch (name) { - case "性别" -> dictionaryService.getExcelValidation("sex"); - case "民族" -> dictionaryService.getExcelValidation("nation"); - case "婚姻状况" -> dictionaryService.getExcelValidation("marriage"); - case "学历" -> dictionaryService.getExcelValidation("education"); - default -> new ArrayList<>(); - }), - response); + null, + base64File, + ExcelUtils.SheetCustomizer.headerBasedConstrainCustomizer( + name -> { + return switch (name) { + case "入职时间" -> + new ExcelUtils.ValidationInfo.DateValidationInfo(); + case "性别" -> + new ExcelUtils.ValidationInfo.ListValidationInfo( + dictionaryService.getExcelValidation("sex")); + case "民族" -> + new ExcelUtils.ValidationInfo.ListValidationInfo( + dictionaryService.getExcelValidation("nation")); + case "婚姻状况" -> + new ExcelUtils.ValidationInfo.ListValidationInfo( + dictionaryService.getExcelValidation("marriage")); + case "学历" -> + new ExcelUtils.ValidationInfo.ListValidationInfo( + dictionaryService.getExcelValidation("education")); + default -> new ExcelUtils.ValidationInfo.AnyValidationInfo(); + }; + }).andThen(ExcelUtils.SheetCustomizer.autoSizeColumnCustomizer()).andThen(ExcelUtils.SheetCustomizer.centerFirstRowCustomizer())); + return base64File; } @SneakyThrows @@ -149,8 +162,7 @@ public class EmployeeService extends BaseService getDepartmentId = Function1.of( (String name) -> { - DepartmentDto department = - departmentService.findByName(name); + DepartmentDto department = departmentService.findByName(name); if (department == null) { CreateDepartmentDto dto = new CreateDepartmentDto(); @@ -207,6 +219,8 @@ public class EmployeeService extends BaseService x.setEmpStatus("1")); + this.repository.saveAll(list); } }