From 2694bc0bca7664e8a8dc9d3cc6c2131055952035 Mon Sep 17 00:00:00 2001 From: fit2cloud-chenyw Date: Fri, 23 Dec 2022 15:10:17 +0800 Subject: [PATCH] =?UTF-8?q?perf(=E5=9C=B0=E5=9B=BE):=20=E5=AF=BC=E5=87=BAe?= =?UTF-8?q?xcel=E5=90=88=E5=B9=B6=E5=8D=95=E5=85=83=E6=A0=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../panel/PanelViewDetailsRequest.java | 4 +- .../request/panel/ViewDetailField.java | 15 +++ .../service/panel/PanelGroupService.java | 96 +++++++++++++++++-- .../canvas/customComponent/UserViewDialog.vue | 29 +++++- 4 files changed, 131 insertions(+), 13 deletions(-) create mode 100644 backend/src/main/java/io/dataease/controller/request/panel/ViewDetailField.java diff --git a/backend/src/main/java/io/dataease/controller/request/panel/PanelViewDetailsRequest.java b/backend/src/main/java/io/dataease/controller/request/panel/PanelViewDetailsRequest.java index 2523167f11..dc2293f938 100644 --- a/backend/src/main/java/io/dataease/controller/request/panel/PanelViewDetailsRequest.java +++ b/backend/src/main/java/io/dataease/controller/request/panel/PanelViewDetailsRequest.java @@ -20,7 +20,7 @@ public class PanelViewDetailsRequest { private Integer[] excelTypes; - private List details; + private List details; private String snapshot; @@ -28,6 +28,6 @@ public class PanelViewDetailsRequest { private int snapshotHeight; - + private ViewDetailField[] detailFields; } diff --git a/backend/src/main/java/io/dataease/controller/request/panel/ViewDetailField.java b/backend/src/main/java/io/dataease/controller/request/panel/ViewDetailField.java new file mode 100644 index 0000000000..e3293f3bb0 --- /dev/null +++ b/backend/src/main/java/io/dataease/controller/request/panel/ViewDetailField.java @@ -0,0 +1,15 @@ +package io.dataease.controller.request.panel; + +import lombok.Data; + +import java.io.Serializable; + +@Data +public class ViewDetailField implements Serializable { + + private String name; + + private String dataeaseName; + + private Integer deType; +} diff --git a/backend/src/main/java/io/dataease/service/panel/PanelGroupService.java b/backend/src/main/java/io/dataease/service/panel/PanelGroupService.java index 64f48249e3..61a92a9220 100644 --- a/backend/src/main/java/io/dataease/service/panel/PanelGroupService.java +++ b/backend/src/main/java/io/dataease/service/panel/PanelGroupService.java @@ -1,5 +1,6 @@ package io.dataease.service.panel; +import cn.hutool.core.util.ArrayUtil; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import com.google.gson.Gson; @@ -42,6 +43,7 @@ import org.apache.commons.lang3.StringUtils; import org.apache.poi.hssf.usermodel.HSSFClientAnchor; import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.ss.usermodel.*; +import org.apache.poi.ss.util.CellRangeAddress; import org.apache.poi.xssf.usermodel.XSSFWorkbook; import org.pentaho.di.core.util.UUIDUtil; import org.slf4j.Logger; @@ -642,13 +644,15 @@ public class PanelGroupService { OutputStream outputStream = response.getOutputStream(); try { String snapshot = request.getSnapshot(); - List details = request.getDetails(); + List details = request.getDetails(); Integer[] excelTypes = request.getExcelTypes(); details.add(0, request.getHeader()); + Workbook wb = new XSSFWorkbook(); //明细sheet Sheet detailsSheet = wb.createSheet("数据"); + //给单元格设置样式 CellStyle cellStyle = wb.createCellStyle(); Font font = wb.createFont(); @@ -663,30 +667,104 @@ public class PanelGroupService { //设置单元格填充样式(使用纯色背景颜色填充) cellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND); - if (CollectionUtils.isNotEmpty(details)) { - for (int i = 0; i < details.size(); i++) { - Row row = detailsSheet.createRow(i); - String[] rowData = details.get(i); + + Boolean mergeHead = false; + ViewDetailField[] detailFields = request.getDetailFields(); + if (ArrayUtil.isNotEmpty(detailFields)) { + cellStyle.setBorderTop(BorderStyle.THIN); + cellStyle.setBorderRight(BorderStyle.THIN); + cellStyle.setBorderBottom(BorderStyle.THIN); + cellStyle.setBorderLeft(BorderStyle.THIN); + String[] detailField = Arrays.stream(detailFields).map(field -> field.getName()).collect(Collectors.toList()).toArray(new String[detailFields.length]); + Object[] header = request.getHeader(); + Row row = detailsSheet.createRow(0); + int headLen = header.length; + int detailFieldLen = detailField.length; + for (int i = 0; i < headLen; i++) { + Cell cell = row.createCell(i); + cell.setCellValue(header[i].toString()); + if (i < headLen - 1) { + CellRangeAddress cellRangeAddress = new CellRangeAddress(0, 1, i, i); + detailsSheet.addMergedRegion(cellRangeAddress); + } else { + for (int j = i + 1; j < detailFieldLen + i; j++) { + row.createCell(j).setCellStyle(cellStyle); + } + CellRangeAddress cellRangeAddress = new CellRangeAddress(0, 0, i, i + detailFieldLen - 1); + detailsSheet.addMergedRegion(cellRangeAddress); + } + cell.setCellStyle(cellStyle); + detailsSheet.setColumnWidth(i, 255 * 20); + } + + Row detailRow = detailsSheet.createRow(1); + for (int i = 0; i < headLen - 1; i++) { + Cell cell = detailRow.createCell(i); + cell.setCellStyle(cellStyle); + } + for (int i = 0; i < detailFieldLen; i++) { + int colIndex = headLen - 1 + i; + Cell cell = detailRow.createCell(colIndex); + cell.setCellValue(detailField[i]); + cell.setCellStyle(cellStyle); + detailsSheet.setColumnWidth(colIndex, 255 * 20); + } + details.add(1, detailField); + mergeHead = true; + } + if (CollectionUtils.isNotEmpty(details) && (!mergeHead || details.size() > 2)) { + int realDetailRowIndex = 2; + for (int i = (mergeHead ? 2 : 0); i < details.size(); i++) { + Row row = detailsSheet.createRow(realDetailRowIndex > 2 ? realDetailRowIndex : i); + Object[] rowData = details.get(i); if (rowData != null) { for (int j = 0; j < rowData.length; j++) { + Object cellValObj = rowData[j]; + if (mergeHead && j == rowData.length - 1 && (cellValObj.getClass().isArray() || cellValObj instanceof ArrayList)) { + Object[] detailRowArray = ((List) cellValObj).toArray(new Object[((List) cellValObj).size()]); + int detailRowArrayLen = detailRowArray.length; + int temlJ = j; + while (detailRowArrayLen > 1 && temlJ-- > 0) { + CellRangeAddress cellRangeAddress = new CellRangeAddress(realDetailRowIndex, realDetailRowIndex + detailRowArrayLen - 1, temlJ, temlJ); + detailsSheet.addMergedRegion(cellRangeAddress); + } + + for (int k = 0; k < detailRowArrayLen; k++) { + List detailRows = (List) detailRowArray[k]; + Row curRow = row; + if (k > 0) { + curRow = detailsSheet.createRow(realDetailRowIndex + k); + } + + for (int l = 0; l < detailRows.size(); l++) { + Object col = detailRows.get(l); + Cell cell = curRow.createCell(j + l); + cell.setCellValue(col.toString()); + } + } + realDetailRowIndex += detailRowArrayLen; + break; + } + Cell cell = row.createCell(j); if (i == 0) {// 头部 - cell.setCellValue(rowData[j]); + cell.setCellValue(cellValObj.toString()); cell.setCellStyle(cellStyle); //设置列的宽度 detailsSheet.setColumnWidth(j, 255 * 20); } else { // with DataType - if ((excelTypes[j] == DeTypeConstants.DE_INT || excelTypes[j] == DeTypeConstants.DE_FLOAT) && StringUtils.isNotEmpty(rowData[j])) { + if ((excelTypes[j] == DeTypeConstants.DE_INT || excelTypes[j] == DeTypeConstants.DE_FLOAT) && StringUtils.isNotEmpty(cellValObj.toString())) { try { - cell.setCellValue(Double.valueOf(rowData[j])); + cell.setCellValue(Double.valueOf(cellValObj.toString())); } catch (Exception e) { LogUtil.warn("export excel data transform error"); } } else { - cell.setCellValue(rowData[j]); + cell.setCellValue(cellValObj.toString()); } } + } } } diff --git a/frontend/src/components/canvas/customComponent/UserViewDialog.vue b/frontend/src/components/canvas/customComponent/UserViewDialog.vue index 58740b44e8..a61588c35e 100644 --- a/frontend/src/components/canvas/customComponent/UserViewDialog.vue +++ b/frontend/src/components/canvas/customComponent/UserViewDialog.vue @@ -250,8 +250,32 @@ export default { const excelHeader = JSON.parse(JSON.stringify(this.chart.data.fields)).map(item => item.name) const excelTypes = JSON.parse(JSON.stringify(this.chart.data.fields)).map(item => item.deType) const excelHeaderKeys = JSON.parse(JSON.stringify(this.chart.data.fields)).map(item => item.dataeaseName) - const excelData = JSON.parse(JSON.stringify(this.chart.data.tableRow)).map(item => excelHeaderKeys.map(i => item[i])) + let excelData = JSON.parse(JSON.stringify(this.chart.data.tableRow)).map(item => excelHeaderKeys.map(i => item[i])) const excelName = this.chart.name + let detailFields = [] + if (this.chart.data.detailFields?.length) { + detailFields = this.chart.data.detailFields.map(item => { + const temp = { + name: item.name, + deType: item.deType, + dataeaseName: item.dataeaseName + } + return temp + }) + excelData = JSON.parse(JSON.stringify(this.chart.data.tableRow)).map(item => { + const temp = excelHeaderKeys.map(i => { + if (i === 'detail' && !item[i] && Array.isArray(item['details'])) { + const arr = item['details'] + if (arr?.length) { + return arr.map(ele => detailFields.map(field => ele[field.dataeaseName])) + } + return null + } + return item[i] + }) + return temp + }) + } const request = { viewId: this.chart.id, viewName: excelName, @@ -260,7 +284,8 @@ export default { excelTypes: excelTypes, snapshot: snapshot, snapshotWidth: width, - snapshotHeight: height + snapshotHeight: height, + detailFields } let method = innerExportDetails const token = this.$store.getters.token || getToken()