From 98161b4c8d24d725717353dc47c56d896ac21213 Mon Sep 17 00:00:00 2001 From: ulleo Date: Thu, 6 Jun 2024 16:38:20 +0800 Subject: [PATCH] =?UTF-8?q?feat(=E5=9B=BE=E8=A1=A8):=20=E6=8B=86=E5=88=86?= =?UTF-8?q?=E5=8F=8C=E8=BD=B4=E5=9B=BE=E5=B7=A6=E5=8F=B3=E8=BD=B4=E6=95=B0?= =?UTF-8?q?=E6=8D=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../chart/manage/ChartDataManage.java | 53 +++- .../chart/server/ChartDataServer.java | 229 ++++++++++-------- .../manage/ExportCenterManage.java | 130 ++-------- .../visualization/UserViewEnlarge.vue | 78 +++++- .../core-frontend/src/models/chart/chart.d.ts | 15 ++ .../js/panel/charts/others/chart-mix.ts | 28 ++- .../src/views/chart/components/js/util.ts | 48 ++-- .../api/chart/request/ChartExcelRequest.java | 16 +- .../chart/request/ChartExcelRequestInner.java | 26 ++ 9 files changed, 376 insertions(+), 247 deletions(-) create mode 100644 sdk/api/api-base/src/main/java/io/dataease/api/chart/request/ChartExcelRequestInner.java diff --git a/core/core-backend/src/main/java/io/dataease/chart/manage/ChartDataManage.java b/core/core-backend/src/main/java/io/dataease/chart/manage/ChartDataManage.java index 974e2a1b0b..57b8f7d93f 100644 --- a/core/core-backend/src/main/java/io/dataease/chart/manage/ChartDataManage.java +++ b/core/core-backend/src/main/java/io/dataease/chart/manage/ChartDataManage.java @@ -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 allFields = getAllChartFields(view); + ChartViewDTO chartViewDTO = null; + + if (StringUtils.equalsIgnoreCase(view.getType(), "chart-mix")) { + //左轴右轴需要分别调用一次查询 + String viewJson = (String) JsonUtil.toJSONString(view); + Map 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 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 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 allFields, List viewFields) throws Exception { List xAxisBase = new ArrayList<>(view.getXAxis()); List 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; diff --git a/core/core-backend/src/main/java/io/dataease/chart/server/ChartDataServer.java b/core/core-backend/src/main/java/io/dataease/chart/server/ChartDataServer.java index 4e99e031e6..bd9e295de4 100644 --- a/core/core-backend/src/main/java/io/dataease/chart/server/ChartDataServer.java +++ b/core/core-backend/src/main/java/io/dataease/chart/server/ChartDataServer.java @@ -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 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 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) 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 detailRows = (List) 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 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 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) 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(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 getFieldData(ChartViewDTO view, Long fieldId, String fieldType) throws Exception { return chartDataManage.getFieldData(view, fieldId, fieldType); diff --git a/core/core-backend/src/main/java/io/dataease/exportCenter/manage/ExportCenterManage.java b/core/core-backend/src/main/java/io/dataease/exportCenter/manage/ExportCenterManage.java index 26a8587f20..b49d49084d 100644 --- a/core/core-backend/src/main/java/io/dataease/exportCenter/manage/ExportCenterManage.java +++ b/core/core-backend/src/main/java/io/dataease/exportCenter/manage/ExportCenterManage.java @@ -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 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 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) 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 detailRows = (List) 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 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(); diff --git a/core/core-frontend/src/components/visualization/UserViewEnlarge.vue b/core/core-frontend/src/components/visualization/UserViewEnlarge.vue index 3578f29692..899f639fa7 100644 --- a/core/core-frontend/src/components/visualization/UserViewEnlarge.vue +++ b/core/core-frontend/src/components/visualization/UserViewEnlarge.vue @@ -59,11 +59,29 @@ show-position="viewDialog" /> + @@ -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 = { 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; + } +} diff --git a/core/core-frontend/src/models/chart/chart.d.ts b/core/core-frontend/src/models/chart/chart.d.ts index 9de6ebdd0e..b3ac02b7b1 100644 --- a/core/core-frontend/src/models/chart/chart.d.ts +++ b/core/core-frontend/src/models/chart/chart.d.ts @@ -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[] diff --git a/core/core-frontend/src/views/chart/components/js/panel/charts/others/chart-mix.ts b/core/core-frontend/src/views/chart/components/js/panel/charts/others/chart-mix.ts index 18c5a45910..7d4525efa4 100644 --- a/core/core-frontend/src/views/chart/components/js/panel/charts/others/chart-mix.ts +++ b/core/core-frontend/src/views/chart/components/js/panel/charts/others/chart-mix.ts @@ -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 { } drawChart(drawOptions: G2PlotDrawOptions): 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 { 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 { } 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'), diff --git a/core/core-frontend/src/views/chart/components/js/util.ts b/core/core-frontend/src/views/chart/components/js/util.ts index 9c64b79e1a..cbd0c170a6 100644 --- a/core/core-frontend/src/views/chart/components/js/util.ts +++ b/core/core-frontend/src/views/chart/components/js/util.ts @@ -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 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' }) diff --git a/sdk/api/api-base/src/main/java/io/dataease/api/chart/request/ChartExcelRequest.java b/sdk/api/api-base/src/main/java/io/dataease/api/chart/request/ChartExcelRequest.java index 71bf0f47f3..dcdc8fd207 100644 --- a/sdk/api/api-base/src/main/java/io/dataease/api/chart/request/ChartExcelRequest.java +++ b/sdk/api/api-base/src/main/java/io/dataease/api/chart/request/ChartExcelRequest.java @@ -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 details; - - private ViewDetailField[] detailFields; - private ChartViewDTO viewInfo; - private List excelHeaderKeys; + private List multiInfo; } diff --git a/sdk/api/api-base/src/main/java/io/dataease/api/chart/request/ChartExcelRequestInner.java b/sdk/api/api-base/src/main/java/io/dataease/api/chart/request/ChartExcelRequestInner.java new file mode 100644 index 0000000000..374f4e9dc0 --- /dev/null +++ b/sdk/api/api-base/src/main/java/io/dataease/api/chart/request/ChartExcelRequestInner.java @@ -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 details; + + private ViewDetailField[] detailFields; + + private List excelHeaderKeys; + +}