fix(图表): 仪表盘在动态字段中除数值、数值小数字段以外其他字段类型汇总方式为计数

This commit is contained in:
jianneng-fit2cloud
2026-06-30 17:42:26 +08:00
parent dbc64e6205
commit 2512863527
4 changed files with 57 additions and 33 deletions

View File

@@ -6,6 +6,7 @@ import io.dataease.chart.utils.ChartDataBuild;
import io.dataease.engine.sql.SQLProvider;
import io.dataease.engine.trans.Quota2SQLObj;
import io.dataease.engine.utils.Utils;
import io.dataease.exception.DEException;
import io.dataease.extensions.datasource.dto.DatasetTableFieldDTO;
import io.dataease.extensions.datasource.dto.DatasourceRequest;
import io.dataease.extensions.datasource.dto.DatasourceSchemaDTO;
@@ -13,6 +14,7 @@ import io.dataease.extensions.datasource.model.SQLMeta;
import io.dataease.extensions.datasource.provider.Provider;
import io.dataease.extensions.view.dto.*;
import io.dataease.extensions.view.util.FieldUtil;
import io.dataease.i18n.Translator;
import io.dataease.utils.BeanUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
@@ -20,6 +22,7 @@ import org.apache.commons.lang3.StringUtils;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
public class NumericalChartHandler extends DefaultChartHandler {
@Override
@@ -73,15 +76,18 @@ public class NumericalChartHandler extends DefaultChartHandler {
String summary = (String) maxField.get("summary");
DatasetTableFieldDTO datasetTableField = datasetTableFieldManage.selectById(id);
if (ObjectUtils.isNotEmpty(datasetTableField)) {
if (datasetTableField.getDeType() == 0 || datasetTableField.getDeType() == 1 || datasetTableField.getDeType() == 5) {
if (!StringUtils.containsIgnoreCase(summary, "count")) {
resetDynamicField(target, type, field);
return null;
}
boolean isText = datasetTableField.getDeType() == 0 || datasetTableField.getDeType() == 1 || datasetTableField.getDeType() == 5;
if (isText && !StringUtils.containsIgnoreCase(summary, "count")) {
DEException.throwException(Translator.get("i18n_gauge_field_change"));
}
ChartViewFieldDTO dto = new ChartViewFieldDTO();
BeanUtils.copyBean(dto, datasetTableField);
if (StringUtils.isEmpty(dto.getSummary())) {
// 文本类型的计算字段时,判断originName是否包含表达式,如果包含,这里取消汇总,后续sql中会有默认表达式count,否则将会套一层count导致报错
if (isText) {
String textSummary = (dto.getExtField() == 2 && StringUtils.isNotEmpty(dto.getOriginName()) &&
Pattern.compile("^(.*?)\\(\\[").matcher(dto.getOriginName()).find()) ? "" : "count";
dto.setSummary(textSummary);
} else if (StringUtils.isEmpty(dto.getSummary())) {
dto.setSummary(summary);
}
return dto;

View File

@@ -46,6 +46,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.*;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
/**
@@ -469,15 +470,20 @@ public class ChartDataManage {
String summary = (String) maxField.get("summary");
DatasetTableFieldDTO datasetTableField = datasetTableFieldManage.selectById(id);
if (ObjectUtils.isNotEmpty(datasetTableField)) {
if (datasetTableField.getDeType() == 0 || datasetTableField.getDeType() == 1 || datasetTableField.getDeType() == 5) {
if (!StringUtils.containsIgnoreCase(summary, "count")) {
resetDynamicField(sizeObj, type, field);
return null;
}
boolean isText = datasetTableField.getDeType() == 0 || datasetTableField.getDeType() == 1 || datasetTableField.getDeType() == 5;
if (isText && !StringUtils.containsIgnoreCase(summary, "count")) {
DEException.throwException(Translator.get("i18n_gauge_field_change"));
}
ChartViewFieldDTO dto = new ChartViewFieldDTO();
BeanUtils.copyBean(dto, datasetTableField);
dto.setSummary(summary);
// 文本类型的计算字段避免后续 SQL 再套一层 count
if (isText) {
String textSummary = (dto.getExtField() == 2 && StringUtils.isNotEmpty(dto.getOriginName()) &&
Pattern.compile("^(.*?)\\(\\[").matcher(dto.getOriginName()).find()) ? "" : "count";
dto.setSummary(textSummary);
} else {
dto.setSummary(summary);
}
return dto;
} else {
resetDynamicField(sizeObj, type, field);

View File

@@ -73,9 +73,8 @@ const changeThreshold = () => {
emit('onThresholdChange', state.thresholdForm)
}
const changeSplitThreshold = (threshold: string) => {
// check input
if (threshold) {
const regex = /^(\d+)(,\d+)*$/
const regex = /^\d+(\.\d+)?(,\d+(\.\d+)?)*$/
if (!regex.test(threshold)) {
ElMessage.error(t('chart.gauge_threshold_format_error'))
return

View File

@@ -155,7 +155,7 @@ const sanitizeDynamicFieldConfig = (typeKey, fieldKey, valueKey) => {
if (!quotaField?.id) {
return resetDynamicFieldConfig(typeKey, fieldKey, valueKey)
}
return false
return normalizeDynamicFieldSummary(currentField)
}
const syncInvalidDynamicField = () => {
let changed = false
@@ -179,6 +179,9 @@ const changeQuotaField = (type: string, resetSummary?: boolean) => {
if (isDynamic && resetSummary) {
state.miscForm.gaugeMaxField.summary = quotaField.summary
}
if (isDynamic) {
normalizeDynamicFieldSummary(state.miscForm.gaugeMaxField)
}
if (!isDynamic) {
state.miscForm.gaugeMax = cloneDeep(gaugeLiquidYaxisDefaultValue.gaugeMax)
state.miscForm.gaugeMaxField.id = ''
@@ -192,6 +195,9 @@ const changeQuotaField = (type: string, resetSummary?: boolean) => {
if (isDynamic && resetSummary) {
state.miscForm.gaugeMinField.summary = quotaField.summary
}
if (isDynamic) {
normalizeDynamicFieldSummary(state.miscForm.gaugeMinField)
}
if (!isDynamic) {
state.miscForm.gaugeMin = state.miscForm.gaugeMin || 0
state.miscForm.gaugeMinField.id = ''
@@ -206,6 +212,9 @@ const changeQuotaField = (type: string, resetSummary?: boolean) => {
if (isDynamic && resetSummary) {
state.miscForm.liquidMaxField.summary = quotaField.summary
}
if (isDynamic) {
normalizeDynamicFieldSummary(state.miscForm.liquidMaxField)
}
if (!isDynamic) {
state.miscForm.liquidMax = cloneDeep(gaugeLiquidYaxisDefaultValue.liquidMax)
state.miscForm.liquidMaxField.id = ''
@@ -248,6 +257,7 @@ const initAxis = yAxisId => {
state.miscForm.liquidMaxField.id = getDynamicField()?.id || state.quotaData[0]?.id
const quotaField = getQuotaField(state.miscForm.liquidMaxField.id)
state.miscForm.liquidMaxField.summary = quotaField.summary
normalizeDynamicFieldSummary(state.miscForm.liquidMaxField)
}
if (isGauge.value) {
// max
@@ -255,6 +265,7 @@ const initAxis = yAxisId => {
state.miscForm.gaugeMaxField.id = getDynamicField()?.id || state.quotaData[0]?.id
const quotaField = getQuotaField(state.miscForm.gaugeMaxField.id)
state.miscForm.gaugeMaxField.summary = quotaField.summary
normalizeDynamicFieldSummary(state.miscForm.gaugeMaxField)
// min
state.miscForm.gaugeMinType = 'fix'
state.miscForm.gaugeMin = 0
@@ -300,18 +311,20 @@ const validMaxFieldAgg = computed(() => {
const isAggField = field => {
return quotaData.value.find(ele => ele.id === field.id)?.agg
}
// 校验计算字段和聚合函数
const validLiquidMaxFieldCalcAndAgg = computed(() => {
return isCalcFieldAndAgg(state.miscForm.liquidMaxField)
})
const validMinFieldCalcAndAgg = computed(() => {
return isCalcFieldAndAgg(state.miscForm.gaugeMinField)
})
const validMaxFieldCalcAndAgg = computed(() => {
return isCalcFieldAndAgg(state.miscForm.gaugeMaxField)
})
const isCalcFieldAndAgg = field => {
return quotaData.value.find(ele => ele.id === field.id && ele.extField === 2 && ele.agg)
// 非数值或计算字段作为动态值时,后端只按计数聚合
const isDisabledSummaryField = field => {
const quotaField = quotaData.value.find(ele => ele.id === field.id)
return quotaField
? quotaField.extField === 2 || !NUMBER_DE_TYPE.includes(quotaField.deType)
: false
}
const normalizeDynamicFieldSummary = field => {
if (isDisabledSummaryField(field) && field.summary !== 'count') {
field.summary = 'count'
return true
}
return false
}
// 校验数值类型
@@ -424,7 +437,7 @@ onMounted(() => {
:gutter="8"
v-if="showProperty('gaugeMinField') && state.miscForm.gaugeMinType === 'dynamic'"
>
<el-col :span="validMinFieldCalcAndAgg ? 24 : 12">
<el-col :span="isDisabledSummaryField(state.miscForm.gaugeMinField) ? 24 : 12">
<el-form-item class="form-item" :class="'form-item-' + themes">
<el-select
:effect="themes"
@@ -454,7 +467,7 @@ onMounted(() => {
</el-select>
</el-form-item>
</el-col>
<el-col :span="12" v-if="!validMinFieldCalcAndAgg">
<el-col :span="12" v-if="!isDisabledSummaryField(state.miscForm.gaugeMinField)">
<el-form-item class="form-item" :class="'form-item-' + themes">
<el-select
:effect="themes"
@@ -526,7 +539,7 @@ onMounted(() => {
:gutter="8"
v-if="showProperty('gaugeMaxField') && state.miscForm.gaugeMaxType === 'dynamic'"
>
<el-col :span="validMaxFieldCalcAndAgg ? 24 : 12">
<el-col :span="isDisabledSummaryField(state.miscForm.gaugeMaxField) ? 24 : 12">
<el-form-item class="form-item" :class="'form-item-' + themes">
<el-select
:effect="themes"
@@ -556,7 +569,7 @@ onMounted(() => {
</el-select>
</el-form-item>
</el-col>
<el-col :span="12" v-if="!validMaxFieldCalcAndAgg">
<el-col :span="12" v-if="!isDisabledSummaryField(state.miscForm.gaugeMaxField)">
<el-form-item class="form-item" :class="'form-item-' + themes">
<el-select
:effect="themes"
@@ -679,7 +692,7 @@ onMounted(() => {
:gutter="8"
v-if="showProperty('liquidMaxField') && state.miscForm.liquidMaxType === 'dynamic'"
>
<el-col :span="validLiquidMaxFieldCalcAndAgg ? 24 : 12">
<el-col :span="isDisabledSummaryField(state.miscForm.liquidMaxField) ? 24 : 12">
<el-form-item class="form-item" :class="'form-item-' + themes">
<el-select
:effect="themes"
@@ -709,7 +722,7 @@ onMounted(() => {
</el-select>
</el-form-item>
</el-col>
<el-col :span="12" v-if="!validLiquidMaxFieldCalcAndAgg">
<el-col :span="12" v-if="!isDisabledSummaryField(state.miscForm.liquidMaxField)">
<el-form-item class="form-item" :class="'form-item-' + themes">
<el-select
:effect="themes"