From bcabbf905df685ed9201e244a4cc6d019cecdf91 Mon Sep 17 00:00:00 2001 From: junjie Date: Thu, 9 Dec 2021 18:32:30 +0800 Subject: [PATCH] =?UTF-8?q?feat(=E8=A7=86=E5=9B=BE):=20=E5=90=8C=E6=AF=94?= =?UTF-8?q?=E7=8E=AF=E6=AF=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dto/chart/ChartFieldCompareCustomDTO.java | 21 +++ .../dto/chart/ChartFieldCompareDTO.java | 15 ++ .../dataease/dto/chart/ChartViewFieldDTO.java | 2 + .../service/chart/ChartConstants.java | 13 ++ .../service/chart/ChartViewService.java | 144 ++++++++++++++++++ .../components/drag-item/ChartDragItem.vue | 10 +- .../components/drag-item/DimensionItem.vue | 23 ++- .../chart/components/drag-item/QuotaItem.vue | 2 +- 8 files changed, 222 insertions(+), 8 deletions(-) create mode 100644 backend/src/main/java/io/dataease/dto/chart/ChartFieldCompareCustomDTO.java create mode 100644 backend/src/main/java/io/dataease/dto/chart/ChartFieldCompareDTO.java create mode 100644 backend/src/main/java/io/dataease/service/chart/ChartConstants.java diff --git a/backend/src/main/java/io/dataease/dto/chart/ChartFieldCompareCustomDTO.java b/backend/src/main/java/io/dataease/dto/chart/ChartFieldCompareCustomDTO.java new file mode 100644 index 0000000000..8ae4a5be60 --- /dev/null +++ b/backend/src/main/java/io/dataease/dto/chart/ChartFieldCompareCustomDTO.java @@ -0,0 +1,21 @@ +package io.dataease.dto.chart; + +import lombok.Data; + +import java.util.List; + +/** + * @Author gin + * @Date 2021/12/9 2:48 下午 + */ +@Data +public class ChartFieldCompareCustomDTO { + private String field; + private String calcType; + private String timeType; + private String currentTime; + private String compareTime; + private List currentTimeRange; + private List compareTimeRange; + +} diff --git a/backend/src/main/java/io/dataease/dto/chart/ChartFieldCompareDTO.java b/backend/src/main/java/io/dataease/dto/chart/ChartFieldCompareDTO.java new file mode 100644 index 0000000000..800a37f0cb --- /dev/null +++ b/backend/src/main/java/io/dataease/dto/chart/ChartFieldCompareDTO.java @@ -0,0 +1,15 @@ +package io.dataease.dto.chart; + +import lombok.Data; + +/** + * @Author gin + * @Date 2021/12/9 2:48 下午 + */ +@Data +public class ChartFieldCompareDTO { + private String type; + private String resultData; + private String field; + private ChartFieldCompareCustomDTO custom; +} diff --git a/backend/src/main/java/io/dataease/dto/chart/ChartViewFieldDTO.java b/backend/src/main/java/io/dataease/dto/chart/ChartViewFieldDTO.java index 221ff0d218..3d5b13665d 100644 --- a/backend/src/main/java/io/dataease/dto/chart/ChartViewFieldDTO.java +++ b/backend/src/main/java/io/dataease/dto/chart/ChartViewFieldDTO.java @@ -46,4 +46,6 @@ public class ChartViewFieldDTO implements Serializable { private Integer extField; private String chartType; + + private ChartFieldCompareDTO compareCalc; } diff --git a/backend/src/main/java/io/dataease/service/chart/ChartConstants.java b/backend/src/main/java/io/dataease/service/chart/ChartConstants.java new file mode 100644 index 0000000000..9b1736018c --- /dev/null +++ b/backend/src/main/java/io/dataease/service/chart/ChartConstants.java @@ -0,0 +1,13 @@ +package io.dataease.service.chart; + +/** + * @Author gin + * @Date 2021/12/9 3:58 下午 + */ +public class ChartConstants { + public static final String YEAR_MOM = "year_mom"; + public static final String MONTH_MOM = "month_mom"; + public static final String YEAR_YOY = "year_yoy"; + public static final String DAY_MOM = "day_mom"; + public static final String MONTH_YOY = "month_yoy"; +} diff --git a/backend/src/main/java/io/dataease/service/chart/ChartViewService.java b/backend/src/main/java/io/dataease/service/chart/ChartViewService.java index d90a240ebb..b9a8d478c6 100644 --- a/backend/src/main/java/io/dataease/service/chart/ChartViewService.java +++ b/backend/src/main/java/io/dataease/service/chart/ChartViewService.java @@ -36,6 +36,7 @@ import org.springframework.stereotype.Service; import javax.annotation.Resource; import java.math.BigDecimal; import java.math.RoundingMode; +import java.text.SimpleDateFormat; import java.util.*; import java.util.concurrent.locks.ReentrantLock; import java.util.stream.Collectors; @@ -433,6 +434,87 @@ public class ChartViewService { } } + // 同比/环比计算,通过对比类型和数据设置,计算出对应指标的结果,然后替换结果data数组中的对应元素 + // 如果因维度变化(如时间字段缺失,时间字段的展示格式变化)导致无法计算结果的,则结果data数组中的对应元素全置为null + // 根据不同图表类型,获得需要替换的指标index array + for (int i = 0; i < yAxis.size(); i++) { + ChartViewFieldDTO chartViewFieldDTO = yAxis.get(i); + ChartFieldCompareDTO compareCalc = chartViewFieldDTO.getCompareCalc(); + if (ObjectUtils.isEmpty(compareCalc)) { + continue; + } + if (StringUtils.isNotEmpty(compareCalc.getType()) + && !StringUtils.equalsIgnoreCase(compareCalc.getType(), "none")) { + String compareFieldId = compareCalc.getField();// 选中字段 + String resultData = compareCalc.getResultData();// 数据设置 + // 获取选中字段以及下标 + List checkedField = new ArrayList<>(xAxis); + if (StringUtils.containsIgnoreCase(view.getType(), "stack")) { + checkedField.addAll(extStack); + } + int timeIndex = 0;// 时间字段下标 + ChartViewFieldDTO timeField = null; + for (int j = 0; j < checkedField.size(); j++) { + if (StringUtils.equalsIgnoreCase(checkedField.get(j).getId(), compareFieldId)) { + timeIndex = j; + timeField = checkedField.get(j); + } + } + // 计算指标对应的下标 + int dataIndex = 0;// 数据字段下标 + if (StringUtils.containsIgnoreCase(view.getType(), "stack")) { + dataIndex = xAxis.size() + extStack.size() + i; + } else { + dataIndex = xAxis.size() + i; + } + // 无选中字段,或者选中字段已经不在维度list中,或者选中字段日期格式不符合对比类型的,直接将对应数据置为null + if (ObjectUtils.isEmpty(timeField) || !checkCalcType(timeField.getDateStyle(), compareCalc.getType())) { + // set null + for (String[] item : data) { + item[dataIndex] = null; + } + } else { + // 计算 同比/环比 + // 1,处理当期数据;2,根据type计算上一期数据;3,根据resultData计算结果 + Map currentMap = new LinkedHashMap<>(); + for (String[] item : data) { + currentMap.put(item[timeIndex], item[dataIndex]); + } + + Iterator> iterator = currentMap.entrySet().iterator(); + int index = 0; + while (iterator.hasNext()) { + Map.Entry next = iterator.next(); + String cTime = next.getKey(); + String cValue = next.getValue(); + + String lastTime = calcLastTime(cTime, compareCalc.getType(), timeField.getDateStyle()); + String lastValue = currentMap.get(lastTime); + if (StringUtils.isEmpty(cValue) || StringUtils.isEmpty(lastValue)) { + data.get(index)[dataIndex] = null; + } else { + if (StringUtils.equalsIgnoreCase(resultData, "sub")) { + data.get(index)[dataIndex] = new BigDecimal(cValue).subtract(new BigDecimal(lastValue)).toString(); + } else if (StringUtils.equalsIgnoreCase(resultData, "percent")) { + if (StringUtils.isEmpty(lastValue)) { + data.get(index)[dataIndex] = null; + } else { + data.get(index)[dataIndex] = new BigDecimal(cValue) + .divide(new BigDecimal(lastValue), 2, RoundingMode.HALF_UP) + .subtract(new BigDecimal(1)) + .setScale(2, RoundingMode.HALF_UP) + .toString(); + } + } + } + index++; + } + + } + } + } + + // 构建结果 Map map = new TreeMap<>(); // 图表组件可再扩展 Map mapChart = new HashMap<>(); @@ -491,6 +573,68 @@ public class ChartViewService { return dto; } + private boolean checkCalcType(String dateStyle, String calcType) { + switch (dateStyle) { + case "y": + return StringUtils.equalsIgnoreCase(calcType, "year_mom"); + case "y_M": + return StringUtils.equalsIgnoreCase(calcType, "month_mom") + || StringUtils.equalsIgnoreCase(calcType, "year_yoy"); + case "y_M_d": + return StringUtils.equalsIgnoreCase(calcType, "day_mom") + || StringUtils.equalsIgnoreCase(calcType, "month_yoy") + || StringUtils.equalsIgnoreCase(calcType, "year_yoy"); + } + return false; + } + + private String calcLastTime(String cTime, String type, String dateStyle) throws Exception { + String lastTime = null; + Calendar calendar = Calendar.getInstance(); + if (StringUtils.equalsIgnoreCase(type, ChartConstants.YEAR_MOM)) { + SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy"); + Date date = simpleDateFormat.parse(cTime); + calendar.setTime(date); + calendar.add(Calendar.YEAR, -1); + lastTime = simpleDateFormat.format(calendar.getTime()); + } else if (StringUtils.equalsIgnoreCase(type, ChartConstants.MONTH_MOM)) { + SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM"); + Date date = simpleDateFormat.parse(cTime); + calendar.setTime(date); + calendar.add(Calendar.MONTH, -1); + lastTime = simpleDateFormat.format(calendar.getTime()); + } else if (StringUtils.equalsIgnoreCase(type, ChartConstants.YEAR_YOY)) { + SimpleDateFormat simpleDateFormat = null; + if (StringUtils.equalsIgnoreCase(dateStyle, "y_M")) { + simpleDateFormat = new SimpleDateFormat("yyyy-MM"); + } else if (StringUtils.equalsIgnoreCase(dateStyle, "y_M_d")) { + simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd"); + } + Date date = simpleDateFormat.parse(cTime); + calendar.setTime(date); + calendar.add(Calendar.YEAR, -1); + lastTime = simpleDateFormat.format(calendar.getTime()); + } else if (StringUtils.equalsIgnoreCase(type, ChartConstants.DAY_MOM)) { + SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd"); + Date date = simpleDateFormat.parse(cTime); + calendar.setTime(date); + calendar.add(Calendar.DAY_OF_MONTH, -1); + lastTime = simpleDateFormat.format(calendar.getTime()); + } else if (StringUtils.equalsIgnoreCase(type, ChartConstants.MONTH_YOY)) { + SimpleDateFormat simpleDateFormat = null; + if (StringUtils.equalsIgnoreCase(dateStyle, "y_M")) { + simpleDateFormat = new SimpleDateFormat("yyyy-MM"); + } else if (StringUtils.equalsIgnoreCase(dateStyle, "y_M_d")) { + simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd"); + } + Date date = simpleDateFormat.parse(cTime); + calendar.setTime(date); + calendar.add(Calendar.MONTH, -1); + lastTime = simpleDateFormat.format(calendar.getTime()); + } + return lastTime; + } + private boolean checkDrillExist(List xAxis, List extStack, ChartViewFieldDTO dto, ChartViewWithBLOBs view) { if (CollectionUtils.isNotEmpty(xAxis)) { for (ChartViewFieldDTO x : xAxis) { diff --git a/frontend/src/views/chart/components/drag-item/ChartDragItem.vue b/frontend/src/views/chart/components/drag-item/ChartDragItem.vue index 400fadab32..8fded96dda 100644 --- a/frontend/src/views/chart/components/drag-item/ChartDragItem.vue +++ b/frontend/src/views/chart/components/drag-item/ChartDragItem.vue @@ -11,6 +11,9 @@ {{ item.name }} {{ $t('chart.'+item.summary) }} + + {{ $t('chart.' + item.dateStyle) }} + @@ -25,6 +28,9 @@ {{ item.name }} {{ $t('chart.'+item.summary) }} + + {{ $t('chart.' + item.dateStyle) }} + @@ -239,7 +245,7 @@ export default { .item-span-style{ display: inline-block; - width: 80px; + width: 70px; white-space: nowrap; text-overflow: ellipsis; overflow: hidden; @@ -254,6 +260,6 @@ export default { margin-left: 4px; color: #878d9f; position: absolute; - right: 30px; + right: 25px; } diff --git a/frontend/src/views/chart/components/drag-item/DimensionItem.vue b/frontend/src/views/chart/components/drag-item/DimensionItem.vue index 073edc2b01..5b71a0f813 100644 --- a/frontend/src/views/chart/components/drag-item/DimensionItem.vue +++ b/frontend/src/views/chart/components/drag-item/DimensionItem.vue @@ -10,6 +10,9 @@ {{ item.name }} + + {{ $t('chart.' + item.dateStyle) }} + @@ -23,6 +26,9 @@ {{ item.name }} + + {{ $t('chart.' + item.dateStyle) }} + @@ -32,7 +38,7 @@ {{ $t('chart.sort') }} - ({{ $t('chart.'+item.sort) }}) + ({{ $t('chart.'+item.sort) }}) @@ -53,7 +59,7 @@ {{ $t('chart.dateStyle') }} - ({{ $t('chart.'+item.dateStyle) }}) + ({{ $t('chart.'+item.dateStyle) }}) @@ -73,7 +79,7 @@ {{ $t('chart.datePattern') }} - ({{ $t('chart.'+item.datePattern) }}) + ({{ $t('chart.'+item.datePattern) }}) @@ -215,7 +221,9 @@ export default { .summary-span{ margin-left: 4px; - color: #878d9f;; + color: #878d9f; + position: absolute; + right: 25px; } .inner-dropdown-menu{ @@ -227,9 +235,14 @@ export default { .item-span-style{ display: inline-block; - width: 80px; + width: 70px; white-space: nowrap; text-overflow: ellipsis; overflow: hidden; } + + .summary-span-item{ + margin-left: 4px; + color: #878d9f; + } diff --git a/frontend/src/views/chart/components/drag-item/QuotaItem.vue b/frontend/src/views/chart/components/drag-item/QuotaItem.vue index 565412392a..38855fcece 100644 --- a/frontend/src/views/chart/components/drag-item/QuotaItem.vue +++ b/frontend/src/views/chart/components/drag-item/QuotaItem.vue @@ -195,7 +195,7 @@ export default { const t2 = extStack.filter(ele => { return ele.deType === 1 }) - if ((t1.length > 0 || t2.length > 0) && this.chart.type !== 'text' && this.chart.type !== 'gauge' && this.chart.type !== 'liquid') { + if ((t1.length + t2.length === 1) && this.chart.type !== 'text' && this.chart.type !== 'gauge' && this.chart.type !== 'liquid') { this.disableEditCompare = false } else { this.disableEditCompare = true