forked from github/dataease
feat(图表): 拆分双轴图左右轴数据
This commit is contained in:
parent
dfca84679d
commit
98161b4c8d
@ -82,7 +82,6 @@ public class ChartDataManage {
|
||||
chartExtRequest = new ChartExtRequest();
|
||||
}
|
||||
|
||||
ChartViewDTO chartViewDTO = new ChartViewDTO();
|
||||
if (ObjectUtils.isEmpty(view)) {
|
||||
DEException.throwException(ResultCode.DATA_IS_WRONG.code(), Translator.get("i18n_chart_delete"));
|
||||
}
|
||||
@ -108,6 +107,54 @@ public class ChartDataManage {
|
||||
|
||||
// get all fields
|
||||
List<ChartViewFieldDTO> allFields = getAllChartFields(view);
|
||||
ChartViewDTO chartViewDTO = null;
|
||||
|
||||
if (StringUtils.equalsIgnoreCase(view.getType(), "chart-mix")) {
|
||||
//左轴右轴需要分别调用一次查询
|
||||
String viewJson = (String) JsonUtil.toJSONString(view);
|
||||
Map<String, Object> data = new HashMap<>();
|
||||
//针对左轴,删除yAxisExt
|
||||
ChartViewDTO view1 = JsonUtil.parseObject(viewJson, ChartViewDTO.class);
|
||||
view1.setYAxisExt(new ArrayList<>());
|
||||
if (view1.getSenior() != null) {
|
||||
ChartSeniorAssistCfgDTO assistLineCfg1 = JsonUtil.parseObject((String) JsonUtil.toJSONString(view1.getSenior().get("assistLineCfg")), ChartSeniorAssistCfgDTO.class);
|
||||
if (assistLineCfg1 != null && assistLineCfg1.isEnable()) {
|
||||
List<ChartSeniorAssistDTO> assistLines = assistLineCfg1.getAssistLine();
|
||||
//去除右轴辅助线
|
||||
assistLineCfg1.setAssistLine(assistLines.stream().filter(d -> StringUtils.equalsIgnoreCase(d.getYAxisType(), "left")).collect(Collectors.toList()));
|
||||
view1.getSenior().put("assistLineCfg", assistLineCfg1);
|
||||
}
|
||||
}
|
||||
ChartViewDTO left = calcData(view1, chartExtRequest, allFields, viewFields);
|
||||
data.put("left", left.getData());
|
||||
//针对右轴,删除yAxis
|
||||
ChartViewDTO view2 = JsonUtil.parseObject(viewJson, ChartViewDTO.class);
|
||||
view2.setYAxis(new ArrayList<>());
|
||||
if (view2.getSenior() != null) {
|
||||
ChartSeniorAssistCfgDTO assistLineCfg2 = JsonUtil.parseObject((String) JsonUtil.toJSONString(view2.getSenior().get("assistLineCfg")), ChartSeniorAssistCfgDTO.class);
|
||||
if (assistLineCfg2 != null && assistLineCfg2.isEnable()) {
|
||||
List<ChartSeniorAssistDTO> assistLines = assistLineCfg2.getAssistLine();
|
||||
//去除左轴辅助线
|
||||
assistLineCfg2.setAssistLine(assistLines.stream().filter(d -> StringUtils.equalsIgnoreCase(d.getYAxisType(), "right")).collect(Collectors.toList()));
|
||||
view2.getSenior().put("assistLineCfg", assistLineCfg2);
|
||||
}
|
||||
}
|
||||
ChartViewDTO right = calcData(view2, chartExtRequest, allFields, viewFields);
|
||||
data.put("right", right.getData());
|
||||
|
||||
//重新组装
|
||||
chartViewDTO = BeanUtils.copyBean(new ChartViewDTO(), left);
|
||||
chartViewDTO.setYAxisExt(view.getYAxisExt());
|
||||
chartViewDTO.setData(data);
|
||||
chartViewDTO.setSenior(view.getSenior());
|
||||
} else {
|
||||
chartViewDTO = calcData(view, chartExtRequest, allFields, viewFields);
|
||||
}
|
||||
|
||||
return chartViewDTO;
|
||||
}
|
||||
|
||||
public ChartViewDTO calcData(ChartViewDTO view, ChartExtRequest chartExtRequest, List<ChartViewFieldDTO> allFields, List<ChartViewFieldDTO> viewFields) throws Exception {
|
||||
|
||||
List<ChartViewFieldDTO> xAxisBase = new ArrayList<>(view.getXAxis());
|
||||
List<ChartViewFieldDTO> xAxis = new ArrayList<>(view.getXAxis());
|
||||
@ -557,7 +604,7 @@ public class ChartDataManage {
|
||||
} else if (StringUtils.containsIgnoreCase(view.getType(), "quadrant")) {
|
||||
Dimension2SQLObj.dimension2sqlObj(sqlMeta, xAxis, transFields(allFields), crossDs, dsMap);
|
||||
yAxis.addAll(extBubble);
|
||||
if(ObjectUtils.isNotEmpty(view.getExtTooltip())){
|
||||
if (ObjectUtils.isNotEmpty(view.getExtTooltip())) {
|
||||
yAxis.addAll(new ArrayList<>(view.getExtTooltip()));
|
||||
}
|
||||
Quota2SQLObj.quota2sqlObj(sqlMeta, yAxis, transFields(allFields), crossDs, dsMap);
|
||||
@ -803,7 +850,7 @@ public class ChartDataManage {
|
||||
} else {
|
||||
mapTableNormal = ChartDataBuild.transTableNormal(xAxis, yAxis, view, data, extStack, desensitizationList);
|
||||
}
|
||||
chartViewDTO = uniteViewResult(datasourceRequest.getQuery(), mapChart, mapTableNormal, view, isDrill, drillFilters, dynamicAssistFields, assistData);
|
||||
ChartViewDTO chartViewDTO = uniteViewResult(datasourceRequest.getQuery(), mapChart, mapTableNormal, view, isDrill, drillFilters, dynamicAssistFields, assistData);
|
||||
chartViewDTO.setTotalPage(totalPage);
|
||||
chartViewDTO.setTotalItems(totalItems);
|
||||
return chartViewDTO;
|
||||
|
@ -4,6 +4,7 @@ import io.dataease.api.chart.ChartDataApi;
|
||||
import io.dataease.api.chart.dto.ChartViewDTO;
|
||||
import io.dataease.api.chart.dto.ViewDetailField;
|
||||
import io.dataease.api.chart.request.ChartExcelRequest;
|
||||
import io.dataease.api.chart.request.ChartExcelRequestInner;
|
||||
import io.dataease.chart.manage.ChartDataManage;
|
||||
import io.dataease.constant.AuthConstant;
|
||||
import io.dataease.constant.CommonConstants;
|
||||
@ -32,7 +33,6 @@ import java.io.OutputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @Author Junjun
|
||||
@ -90,14 +90,8 @@ public class ChartDataServer implements ChartDataApi {
|
||||
OutputStream outputStream = response.getOutputStream();
|
||||
try {
|
||||
findExcelData(request);
|
||||
List<Object[]> details = request.getDetails();
|
||||
Integer[] excelTypes = request.getExcelTypes();
|
||||
details.add(0, request.getHeader());
|
||||
|
||||
Workbook wb = new SXSSFWorkbook();
|
||||
//明细sheet
|
||||
Sheet detailsSheet = wb.createSheet("数据");
|
||||
|
||||
|
||||
//给单元格设置样式
|
||||
CellStyle cellStyle = wb.createCellStyle();
|
||||
@ -113,109 +107,35 @@ public class ChartDataServer implements ChartDataApi {
|
||||
//设置单元格填充样式(使用纯色背景颜色填充)
|
||||
cellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
|
||||
|
||||
|
||||
Boolean mergeHead = false;
|
||||
ViewDetailField[] detailFields = request.getDetailFields();
|
||||
if (ArrayUtils.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]);
|
||||
if (CollectionUtils.isEmpty(request.getMultiInfo())) {
|
||||
List<Object[]> details = request.getDetails();
|
||||
Integer[] excelTypes = request.getExcelTypes();
|
||||
details.add(0, request.getHeader());
|
||||
ViewDetailField[] detailFields = request.getDetailFields();
|
||||
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<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);
|
||||
}
|
||||
//明细sheet
|
||||
Sheet detailsSheet = wb.createSheet("数据");
|
||||
|
||||
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);
|
||||
}
|
||||
setExcelData(detailsSheet, cellStyle, header, details, detailFields, excelTypes);
|
||||
} else {
|
||||
//多个sheet
|
||||
for (int i = 0; i < request.getMultiInfo().size(); i++) {
|
||||
ChartExcelRequestInner requestInner = request.getMultiInfo().get(i);
|
||||
|
||||
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;
|
||||
}
|
||||
List<Object[]> details = requestInner.getDetails();
|
||||
Integer[] excelTypes = requestInner.getExcelTypes();
|
||||
details.add(0, requestInner.getHeader());
|
||||
ViewDetailField[] detailFields = requestInner.getDetailFields();
|
||||
Object[] header = requestInner.getHeader();
|
||||
|
||||
Cell cell = row.createCell(j);
|
||||
if (i == 0) {// 头部
|
||||
cell.setCellValue(cellValObj.toString());
|
||||
cell.setCellStyle(cellStyle);
|
||||
//设置列的宽度
|
||||
detailsSheet.setColumnWidth(j, 255 * 20);
|
||||
} else if (cellValObj != null) {
|
||||
try {
|
||||
// with DataType
|
||||
if ((excelTypes[j].equals(DeTypeConstants.DE_INT) || excelTypes[j].equals(DeTypeConstants.DE_FLOAT)) && StringUtils.isNotEmpty(cellValObj.toString())) {
|
||||
cell.setCellValue(Double.valueOf(cellValObj.toString()));
|
||||
} else {
|
||||
cell.setCellValue(cellValObj.toString());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LogUtil.warn("export excel data transform error");
|
||||
}
|
||||
}
|
||||
//明细sheet
|
||||
Sheet detailsSheet = wb.createSheet("数据 " + (i + 1));
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
setExcelData(detailsSheet, cellStyle, header, details, detailFields, excelTypes);
|
||||
}
|
||||
}
|
||||
|
||||
response.setContentType("application/vnd.ms-excel");
|
||||
//文件名称
|
||||
response.setHeader("Content-disposition", "attachment;filename=" + request.getViewName() + ".xlsx");
|
||||
@ -227,6 +147,111 @@ public class ChartDataServer implements ChartDataApi {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static void setExcelData(Sheet detailsSheet, CellStyle cellStyle, Object[] header, List<Object[]> details, ViewDetailField[] detailFields, Integer[] excelTypes) {
|
||||
boolean mergeHead = false;
|
||||
if (ArrayUtils.isNotEmpty(detailFields)) {
|
||||
cellStyle.setBorderTop(BorderStyle.THIN);
|
||||
cellStyle.setBorderRight(BorderStyle.THIN);
|
||||
cellStyle.setBorderBottom(BorderStyle.THIN);
|
||||
cellStyle.setBorderLeft(BorderStyle.THIN);
|
||||
String[] detailField = Arrays.stream(detailFields).map(ViewDetailField::getName).toList().toArray(new String[detailFields.length]);
|
||||
|
||||
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<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);
|
||||
if (i == 0) {// 头部
|
||||
cell.setCellValue(cellValObj.toString());
|
||||
cell.setCellStyle(cellStyle);
|
||||
//设置列的宽度
|
||||
detailsSheet.setColumnWidth(j, 255 * 20);
|
||||
} else if (cellValObj != null) {
|
||||
try {
|
||||
// with DataType
|
||||
if ((excelTypes[j].equals(DeTypeConstants.DE_INT) || excelTypes[j].equals(DeTypeConstants.DE_FLOAT)) && StringUtils.isNotEmpty(cellValObj.toString())) {
|
||||
cell.setCellValue(Double.valueOf(cellValObj.toString()));
|
||||
} else {
|
||||
cell.setCellValue(cellValObj.toString());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LogUtil.warn("export excel data transform error");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getFieldData(ChartViewDTO view, Long fieldId, String fieldType) throws Exception {
|
||||
return chartDataManage.getFieldData(view, fieldId, fieldType);
|
||||
|
@ -4,11 +4,11 @@ package io.dataease.exportCenter.manage;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import io.dataease.api.chart.dto.ViewDetailField;
|
||||
import io.dataease.api.chart.request.ChartExcelRequest;
|
||||
import io.dataease.api.chart.request.ChartExcelRequestInner;
|
||||
import io.dataease.api.exportCenter.vo.ExportTaskDTO;
|
||||
import io.dataease.auth.bo.TokenUserBO;
|
||||
import io.dataease.chart.dao.auto.mapper.CoreChartViewMapper;
|
||||
import io.dataease.chart.server.ChartDataServer;
|
||||
import io.dataease.engine.constant.DeTypeConstants;
|
||||
import io.dataease.exception.DEException;
|
||||
import io.dataease.exportCenter.dao.auto.entity.CoreExportTask;
|
||||
import io.dataease.exportCenter.dao.auto.mapper.CoreExportTaskMapper;
|
||||
@ -21,10 +21,8 @@ import jakarta.annotation.PostConstruct;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.poi.ss.usermodel.*;
|
||||
import org.apache.poi.ss.util.CellRangeAddress;
|
||||
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
@ -38,7 +36,6 @@ import java.util.*;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Component
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@ -52,7 +49,7 @@ public class ExportCenterManage {
|
||||
@Autowired
|
||||
private WsService wsService;
|
||||
@Resource
|
||||
private SysParameterManage sysParameterManage;
|
||||
private SysParameterManage sysParameterManage;
|
||||
|
||||
@Value("${export.dataset.limit:100000}")
|
||||
private int limit;
|
||||
@ -251,12 +248,9 @@ public class ExportCenterManage {
|
||||
exportTask.setExportStatus("IN_PROGRESS");
|
||||
exportTaskMapper.updateById(exportTask);
|
||||
chartDataServer.findExcelData(request);
|
||||
List<Object[]> details = request.getDetails();
|
||||
Integer[] excelTypes = request.getExcelTypes();
|
||||
details.add(0, request.getHeader());
|
||||
|
||||
Workbook wb = new SXSSFWorkbook();
|
||||
//明细sheet
|
||||
Sheet detailsSheet = wb.createSheet("数据");
|
||||
|
||||
//给单元格设置样式
|
||||
CellStyle cellStyle = wb.createCellStyle();
|
||||
Font font = wb.createFont();
|
||||
@ -271,110 +265,36 @@ public class ExportCenterManage {
|
||||
//设置单元格填充样式(使用纯色背景颜色填充)
|
||||
cellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
|
||||
|
||||
|
||||
Boolean mergeHead = false;
|
||||
ViewDetailField[] detailFields = request.getDetailFields();
|
||||
if (ArrayUtils.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]);
|
||||
if (CollectionUtils.isEmpty(request.getMultiInfo())) {
|
||||
List<Object[]> details = request.getDetails();
|
||||
Integer[] excelTypes = request.getExcelTypes();
|
||||
details.add(0, request.getHeader());
|
||||
ViewDetailField[] detailFields = request.getDetailFields();
|
||||
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<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);
|
||||
}
|
||||
//明细sheet
|
||||
Sheet detailsSheet = wb.createSheet("数据");
|
||||
|
||||
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);
|
||||
}
|
||||
ChartDataServer.setExcelData(detailsSheet, cellStyle, header, details, detailFields, excelTypes);
|
||||
} else {
|
||||
//多个sheet
|
||||
for (int i = 0; i < request.getMultiInfo().size(); i++) {
|
||||
ChartExcelRequestInner requestInner = request.getMultiInfo().get(i);
|
||||
|
||||
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;
|
||||
}
|
||||
List<Object[]> details = requestInner.getDetails();
|
||||
Integer[] excelTypes = requestInner.getExcelTypes();
|
||||
details.add(0, requestInner.getHeader());
|
||||
ViewDetailField[] detailFields = requestInner.getDetailFields();
|
||||
Object[] header = requestInner.getHeader();
|
||||
|
||||
Cell cell = row.createCell(j);
|
||||
if (i == 0) {// 头部
|
||||
cell.setCellValue(cellValObj.toString());
|
||||
cell.setCellStyle(cellStyle);
|
||||
//设置列的宽度
|
||||
detailsSheet.setColumnWidth(j, 255 * 20);
|
||||
} else if (cellValObj != null) {
|
||||
try {
|
||||
// with DataType
|
||||
if ((excelTypes[j].equals(DeTypeConstants.DE_INT) || excelTypes[j].equals(DeTypeConstants.DE_FLOAT)) && StringUtils.isNotEmpty(cellValObj.toString())) {
|
||||
cell.setCellValue(Double.valueOf(cellValObj.toString()));
|
||||
} else {
|
||||
cell.setCellValue(cellValObj.toString());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LogUtil.warn("export excel data transform error");
|
||||
}
|
||||
}
|
||||
//明细sheet
|
||||
Sheet detailsSheet = wb.createSheet("数据 " + (i + 1));
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
ChartDataServer.setExcelData(detailsSheet, cellStyle, header, details, detailFields, excelTypes);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
try (FileOutputStream outputStream = new FileOutputStream(dataPath + "/" + request.getViewName() + ".xlsx")) {
|
||||
wb.write(outputStream);
|
||||
outputStream.flush();
|
||||
|
@ -59,11 +59,29 @@
|
||||
show-position="viewDialog"
|
||||
/>
|
||||
<chart-component-s2
|
||||
v-if="optType === 'details'"
|
||||
v-if="optType === 'details' && sourceViewType !== 'chart-mix'"
|
||||
:view="viewInfo"
|
||||
show-position="viewDialog"
|
||||
ref="chartComponentDetails"
|
||||
/>
|
||||
<template v-else-if="optType === 'details' && sourceViewType === 'chart-mix'">
|
||||
<el-tabs class="tab-header" v-model="activeName" @tab-change="handleClick">
|
||||
<el-tab-pane :label="t('chart.drag_block_value_axis_left')" name="left"></el-tab-pane>
|
||||
<el-tab-pane :label="t('chart.drag_block_value_axis_right')" name="right"></el-tab-pane>
|
||||
</el-tabs>
|
||||
<chart-component-s2
|
||||
v-if="activeName === 'left'"
|
||||
:view="viewInfo"
|
||||
show-position="viewDialog"
|
||||
ref="chartComponentDetails"
|
||||
/>
|
||||
<chart-component-s2
|
||||
v-else-if="activeName === 'right'"
|
||||
:view="viewInfo"
|
||||
show-position="viewDialog"
|
||||
ref="chartComponentDetails2"
|
||||
/>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</el-dialog>
|
||||
@ -93,9 +111,11 @@ const viewContainer = ref(null)
|
||||
const { t } = useI18n()
|
||||
const optType = ref(null)
|
||||
const chartComponentDetails = ref(null)
|
||||
const chartComponentDetails2 = ref(null)
|
||||
const { dvInfo } = storeToRefs(dvMainStore)
|
||||
const exportLoading = ref(false)
|
||||
const sourceViewType = ref()
|
||||
const activeName = ref('left')
|
||||
const DETAIL_TABLE_ATTR: DeepPartial<ChartObj> = {
|
||||
render: 'antv',
|
||||
type: 'table-info',
|
||||
@ -184,7 +204,23 @@ const dialogInit = (canvasStyle, view, item, opt) => {
|
||||
const dataDetailsOpt = () => {
|
||||
nextTick(() => {
|
||||
const viewDataInfo = dvMainStore.getViewDataDetails(viewInfo.value.id)
|
||||
chartComponentDetails.value.renderChartFromDialog(viewInfo.value, viewDataInfo)
|
||||
if (sourceViewType.value === 'chart-mix') {
|
||||
chartComponentDetails.value?.renderChartFromDialog(viewInfo.value, viewDataInfo.left)
|
||||
chartComponentDetails2.value?.renderChartFromDialog(viewInfo.value, viewDataInfo.right)
|
||||
} else {
|
||||
chartComponentDetails.value.renderChartFromDialog(viewInfo.value, viewDataInfo)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const handleClick = tab => {
|
||||
nextTick(() => {
|
||||
const viewDataInfo = dvMainStore.getViewDataDetails(viewInfo.value.id)
|
||||
if (tab === 'left') {
|
||||
chartComponentDetails.value?.renderChartFromDialog(viewInfo.value, viewDataInfo.left)
|
||||
} else if (tab === 'right') {
|
||||
chartComponentDetails2.value?.renderChartFromDialog(viewInfo.value, viewDataInfo.right)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@ -319,4 +355,42 @@ defineExpose({
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
.tab-header {
|
||||
--ed-tabs-header-height: 34px;
|
||||
--custom-tab-color: #646a73;
|
||||
|
||||
:deep(.ed-tabs__nav-wrap::after) {
|
||||
background-color: unset;
|
||||
}
|
||||
|
||||
&.dark {
|
||||
--custom-tab-color: #a6a6a6;
|
||||
}
|
||||
|
||||
:deep(.ed-tabs__item) {
|
||||
font-weight: 400;
|
||||
font-size: 12px;
|
||||
padding: 0 8px !important;
|
||||
margin-right: 12px;
|
||||
color: var(--custom-tab-color);
|
||||
}
|
||||
:deep(.is-active) {
|
||||
font-weight: 500;
|
||||
color: var(--ed-color-primary, #3370ff);
|
||||
}
|
||||
|
||||
:deep(.ed-tabs__nav-scroll) {
|
||||
padding-left: 0 !important;
|
||||
}
|
||||
|
||||
:deep(.ed-tabs__header) {
|
||||
margin: 0 !important;
|
||||
}
|
||||
|
||||
:deep(.ed-tabs__content) {
|
||||
height: calc(100% - 35px);
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
15
core/core-frontend/src/models/chart/chart.d.ts
vendored
15
core/core-frontend/src/models/chart/chart.d.ts
vendored
@ -17,6 +17,21 @@ declare interface Chart {
|
||||
dynamicAssistLines?: AssistLine[]
|
||||
fields: ChartViewField[]
|
||||
tableRow: []
|
||||
//chart-mix
|
||||
left: {
|
||||
data: any[]
|
||||
series?: any[]
|
||||
dynamicAssistLines?: AssistLine[]
|
||||
fields: ChartViewField[]
|
||||
tableRow: []
|
||||
}
|
||||
right: {
|
||||
data: any[]
|
||||
series?: any[]
|
||||
dynamicAssistLines?: AssistLine[]
|
||||
fields: ChartViewField[]
|
||||
tableRow: []
|
||||
}
|
||||
}
|
||||
xAxis?: Axis[]
|
||||
xAxisExt?: Axis[]
|
||||
|
@ -12,7 +12,7 @@ import {
|
||||
setGradientColor
|
||||
} from '../../common/common_antv'
|
||||
import { flow, hexColorToRGBA, parseJson } from '@/views/chart/components/js/util'
|
||||
import { cloneDeep, isEmpty, defaultTo, map, filter } from 'lodash-es'
|
||||
import { cloneDeep, isEmpty, defaultTo, map, filter, union } from 'lodash-es'
|
||||
import { valueFormatter } from '@/views/chart/components/js/formatter'
|
||||
import {
|
||||
CHART_MIX_AXIS_TYPE,
|
||||
@ -55,21 +55,23 @@ export class ColumnLineMix extends G2PlotChartView<DualAxesOptions, DualAxes> {
|
||||
}
|
||||
drawChart(drawOptions: G2PlotDrawOptions<DualAxes>): DualAxes {
|
||||
const { chart, action, container } = drawOptions
|
||||
if (!chart.data.data?.length) {
|
||||
if (!chart.data.left.data?.length && !chart.data.right.data?.length) {
|
||||
return
|
||||
}
|
||||
const data = cloneDeep(chart.data.data)
|
||||
const left = cloneDeep(chart.data?.left?.data)
|
||||
const right = cloneDeep(chart.data?.right?.data)
|
||||
|
||||
const data1Type = data[0]?.type === 'bar' ? 'column' : data[0]?.type
|
||||
const data2Type = data[1]?.type === 'bar' ? 'column' : data[1]?.type
|
||||
const data1Type = (left[0]?.type === 'bar' ? 'column' : left[0]?.type) ?? 'column'
|
||||
const data2Type = (right[0]?.type === 'bar' ? 'column' : right[0]?.type) ?? 'column'
|
||||
|
||||
const data1 = defaultTo(data[0]?.data, [])
|
||||
const data2 = map(defaultTo(data[1]?.data, []), d => {
|
||||
const data1 = defaultTo(left[0]?.data, [])
|
||||
const data2 = map(defaultTo(right[0]?.data, []), d => {
|
||||
return {
|
||||
...d,
|
||||
valueExt: d.value
|
||||
}
|
||||
})
|
||||
|
||||
// custom color
|
||||
const customAttr = parseJson(chart.customAttr)
|
||||
let color = customAttr.basicStyle.colors
|
||||
@ -368,14 +370,16 @@ export class ColumnLineMix extends G2PlotChartView<DualAxesOptions, DualAxes> {
|
||||
protected configLegend(chart: Chart, options: DualAxesOptions): DualAxesOptions {
|
||||
const o = super.configLegend(chart, options)
|
||||
if (o.legend) {
|
||||
const data = chart.data.data
|
||||
const left = cloneDeep(chart.data?.left?.data)
|
||||
const right = cloneDeep(chart.data?.right?.data)
|
||||
|
||||
o.legend.itemName = {
|
||||
formatter: (text: string, item: any, index: number) => {
|
||||
let name = undefined
|
||||
if (index === 0 && text === 'value') {
|
||||
name = data[0]?.name
|
||||
name = left[0]?.name
|
||||
} else if (index === 1 && text === 'valueExt') {
|
||||
name = data[1]?.name
|
||||
name = right[0]?.name
|
||||
}
|
||||
if (name === undefined) {
|
||||
return text
|
||||
@ -389,6 +393,10 @@ export class ColumnLineMix extends G2PlotChartView<DualAxesOptions, DualAxes> {
|
||||
}
|
||||
|
||||
protected configAnalyse(chart: Chart, options: DualAxesOptions): DualAxesOptions {
|
||||
chart.data.dynamicAssistLines = union(
|
||||
defaultTo(chart.data?.left?.dynamicAssistLines, []),
|
||||
defaultTo(chart.data?.right?.dynamicAssistLines, [])
|
||||
)
|
||||
const list = getAnalyse(chart)
|
||||
const annotations = {
|
||||
value: filter(list, l => l.yAxisType === 'left'),
|
||||
|
@ -11,6 +11,7 @@ import { innerExportDetails } from '@/api/chart'
|
||||
import { ElMessage } from 'element-plus-secondary'
|
||||
import { useI18n } from '@/hooks/web/useI18n'
|
||||
import { useLinkStoreWithOut } from '@/store/modules/link'
|
||||
|
||||
const { t } = useI18n()
|
||||
// 同时支持将hex和rgb,转换成rgba
|
||||
export function hexColorToRGBA(hex, alpha) {
|
||||
@ -420,17 +421,16 @@ export const getGeoJsonFile = async (areaId: string): Promise<FeatureCollection>
|
||||
return toRaw(geoJson)
|
||||
}
|
||||
|
||||
export const exportExcelDownload = (chart, callBack?) => {
|
||||
const fields = JSON.parse(JSON.stringify(chart.data.fields))
|
||||
const tableRow = JSON.parse(JSON.stringify(chart.data.tableRow))
|
||||
const getExcelDownloadRequest = data => {
|
||||
const fields = JSON.parse(JSON.stringify(data.fields))
|
||||
const tableRow = JSON.parse(JSON.stringify(data.tableRow))
|
||||
const excelHeader = fields.map(item => item.chartShowName ?? item.name)
|
||||
const excelTypes = fields.map(item => item.deType)
|
||||
const excelHeaderKeys = fields.map(item => item.dataeaseName)
|
||||
let excelData = tableRow.map(item => excelHeaderKeys.map(i => item[i]))
|
||||
const excelName = chart.title
|
||||
let detailFields = []
|
||||
if (chart.data.detailFields?.length) {
|
||||
detailFields = chart.data.detailFields.map(item => {
|
||||
if (data.detailFields?.length) {
|
||||
detailFields = data.detailFields.map(item => {
|
||||
return {
|
||||
name: item.name,
|
||||
deType: item.deType,
|
||||
@ -450,21 +450,41 @@ export const exportExcelDownload = (chart, callBack?) => {
|
||||
})
|
||||
})
|
||||
}
|
||||
const request = {
|
||||
proxy: null,
|
||||
viewId: chart.id,
|
||||
viewName: excelName,
|
||||
return {
|
||||
header: excelHeader,
|
||||
details: excelData,
|
||||
excelTypes: excelTypes,
|
||||
excelHeaderKeys: excelHeaderKeys,
|
||||
viewInfo: chart,
|
||||
detailFields
|
||||
detailFields: detailFields
|
||||
}
|
||||
}
|
||||
|
||||
export const exportExcelDownload = (chart, callBack?) => {
|
||||
const excelName = chart.title
|
||||
let request: any = {
|
||||
proxy: null,
|
||||
viewId: chart.id,
|
||||
viewInfo: chart,
|
||||
viewName: excelName
|
||||
}
|
||||
if (chart.type === 'chart-mix') {
|
||||
const req1 = getExcelDownloadRequest(chart.data.left)
|
||||
const req2 = getExcelDownloadRequest(chart.data.right)
|
||||
request = {
|
||||
...request,
|
||||
multiInfo: [req1, req2]
|
||||
}
|
||||
} else {
|
||||
const req = getExcelDownloadRequest(chart.data)
|
||||
request = {
|
||||
...request,
|
||||
...req
|
||||
}
|
||||
}
|
||||
|
||||
const linkStore = useLinkStoreWithOut()
|
||||
|
||||
const method = innerExportDetails
|
||||
method(request)
|
||||
innerExportDetails(request)
|
||||
.then(res => {
|
||||
if (linkStore.getLinkToken) {
|
||||
const blob = new Blob([res.data], { type: 'application/vnd.ms-excel' })
|
||||
|
@ -1,31 +1,25 @@
|
||||
package io.dataease.api.chart.request;
|
||||
|
||||
import io.dataease.api.chart.dto.ChartViewDTO;
|
||||
import io.dataease.api.chart.dto.ViewDetailField;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @Author wangjiahao
|
||||
*/
|
||||
@Data
|
||||
public class ChartExcelRequest {
|
||||
public class ChartExcelRequest extends ChartExcelRequestInner {
|
||||
@Serial
|
||||
private static final long serialVersionUID = 3829386417457449431L;
|
||||
|
||||
private String viewId;
|
||||
|
||||
private String viewName;
|
||||
|
||||
private String[] header;
|
||||
|
||||
private Integer[] excelTypes;
|
||||
|
||||
private List<Object[]> details;
|
||||
|
||||
private ViewDetailField[] detailFields;
|
||||
|
||||
private ChartViewDTO viewInfo;
|
||||
|
||||
private List<String> excelHeaderKeys;
|
||||
private List<ChartExcelRequestInner> multiInfo;
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,26 @@
|
||||
package io.dataease.api.chart.request;
|
||||
|
||||
import io.dataease.api.chart.dto.ViewDetailField;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
@Data
|
||||
public class ChartExcelRequestInner implements Serializable {
|
||||
@Serial
|
||||
private static final long serialVersionUID = -8655439241248268940L;
|
||||
|
||||
private String[] header;
|
||||
|
||||
private Integer[] excelTypes;
|
||||
|
||||
private List<Object[]> details;
|
||||
|
||||
private ViewDetailField[] detailFields;
|
||||
|
||||
private List<String> excelHeaderKeys;
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user