Merge pull request #4175 from dataease/pr@dev@perf_mark_map_export_excel

perf(地图): 导出excel合并单元格
This commit is contained in:
fit2cloud-chenyw 2022-12-23 15:11:59 +08:00 committed by GitHub
commit 65559d155e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 131 additions and 13 deletions

View File

@ -20,7 +20,7 @@ public class PanelViewDetailsRequest {
private Integer[] excelTypes; private Integer[] excelTypes;
private List<String[]> details; private List<Object[]> details;
private String snapshot; private String snapshot;
@ -28,6 +28,6 @@ public class PanelViewDetailsRequest {
private int snapshotHeight; private int snapshotHeight;
private ViewDetailField[] detailFields;
} }

View File

@ -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;
}

View File

@ -1,5 +1,6 @@
package io.dataease.service.panel; package io.dataease.service.panel;
import cn.hutool.core.util.ArrayUtil;
import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
import com.google.gson.Gson; 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.HSSFClientAnchor;
import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.*; import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.usermodel.XSSFWorkbook; import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.pentaho.di.core.util.UUIDUtil; import org.pentaho.di.core.util.UUIDUtil;
import org.slf4j.Logger; import org.slf4j.Logger;
@ -642,13 +644,15 @@ public class PanelGroupService {
OutputStream outputStream = response.getOutputStream(); OutputStream outputStream = response.getOutputStream();
try { try {
String snapshot = request.getSnapshot(); String snapshot = request.getSnapshot();
List<String[]> details = request.getDetails(); List<Object[]> details = request.getDetails();
Integer[] excelTypes = request.getExcelTypes(); Integer[] excelTypes = request.getExcelTypes();
details.add(0, request.getHeader()); details.add(0, request.getHeader());
Workbook wb = new XSSFWorkbook(); Workbook wb = new XSSFWorkbook();
//明细sheet //明细sheet
Sheet detailsSheet = wb.createSheet("数据"); Sheet detailsSheet = wb.createSheet("数据");
//给单元格设置样式 //给单元格设置样式
CellStyle cellStyle = wb.createCellStyle(); CellStyle cellStyle = wb.createCellStyle();
Font font = wb.createFont(); Font font = wb.createFont();
@ -663,30 +667,104 @@ public class PanelGroupService {
//设置单元格填充样式(使用纯色背景颜色填充) //设置单元格填充样式(使用纯色背景颜色填充)
cellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND); cellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
if (CollectionUtils.isNotEmpty(details)) {
for (int i = 0; i < details.size(); i++) { Boolean mergeHead = false;
Row row = detailsSheet.createRow(i); ViewDetailField[] detailFields = request.getDetailFields();
String[] rowData = details.get(i); 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) { if (rowData != null) {
for (int j = 0; j < rowData.length; j++) { 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<Object>) 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<Object> detailRows = (List<Object>) 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); Cell cell = row.createCell(j);
if (i == 0) {// 头部 if (i == 0) {// 头部
cell.setCellValue(rowData[j]); cell.setCellValue(cellValObj.toString());
cell.setCellStyle(cellStyle); cell.setCellStyle(cellStyle);
//设置列的宽度 //设置列的宽度
detailsSheet.setColumnWidth(j, 255 * 20); detailsSheet.setColumnWidth(j, 255 * 20);
} else { } else {
// with DataType // 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 { try {
cell.setCellValue(Double.valueOf(rowData[j])); cell.setCellValue(Double.valueOf(cellValObj.toString()));
} catch (Exception e) { } catch (Exception e) {
LogUtil.warn("export excel data transform error"); LogUtil.warn("export excel data transform error");
} }
} else { } else {
cell.setCellValue(rowData[j]); cell.setCellValue(cellValObj.toString());
} }
} }
} }
} }
} }

View File

@ -250,8 +250,32 @@ export default {
const excelHeader = JSON.parse(JSON.stringify(this.chart.data.fields)).map(item => item.name) 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 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 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 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 = { const request = {
viewId: this.chart.id, viewId: this.chart.id,
viewName: excelName, viewName: excelName,
@ -260,7 +284,8 @@ export default {
excelTypes: excelTypes, excelTypes: excelTypes,
snapshot: snapshot, snapshot: snapshot,
snapshotWidth: width, snapshotWidth: width,
snapshotHeight: height snapshotHeight: height,
detailFields
} }
let method = innerExportDetails let method = innerExportDetails
const token = this.$store.getters.token || getToken() const token = this.$store.getters.token || getToken()