diff --git a/backend/src/main/java/io/dataease/service/chart/util/ChartDataBuild.java b/backend/src/main/java/io/dataease/service/chart/util/ChartDataBuild.java
index d2351a8a3e..7af383f8bd 100644
--- a/backend/src/main/java/io/dataease/service/chart/util/ChartDataBuild.java
+++ b/backend/src/main/java/io/dataease/service/chart/util/ChartDataBuild.java
@@ -158,12 +158,17 @@ public class ChartDataBuild {
} catch (Exception e) {
axisChartDataDTO.setValue(new BigDecimal(0));
}
- if ("line".equals(view.getType()) && CollectionUtils.isEmpty(xAxisExt)) {
- axisChartDataDTO.setCategory(yAxis.get(j).getName());
- } else {
- axisChartDataDTO.setCategory(b.toString());
- }
+ axisChartDataDTO.setCategory(b.toString());
dataList.add(axisChartDataDTO);
+
+ if ("line".equals(view.getType())) {
+ if (CollectionUtils.isEmpty(xAxisExt)){
+ axisChartDataDTO.setCategory(yAxis.get(j).getName());
+ } else {
+ // 多指标只取第一个
+ break;
+ }
+ }
}
}
map.put("data", dataList);
diff --git a/frontend/src/lang/en.js b/frontend/src/lang/en.js
index 75277831cc..4cc96873e4 100644
--- a/frontend/src/lang/en.js
+++ b/frontend/src/lang/en.js
@@ -1446,7 +1446,11 @@ export default {
total_sort_none: 'None',
total_sort_asc: 'ASC',
total_sort_desc: 'DESC',
- total_sort_field: 'Sort Field'
+ total_sort_field: 'Sort Field',
+ empty_data_strategy: 'Empty Data Strategy',
+ break_line: 'Disconnection',
+ set_zero: 'Set Zero',
+ ignore_data: 'Ignore Data'
},
dataset: {
spend_time: 'Spend',
diff --git a/frontend/src/lang/tw.js b/frontend/src/lang/tw.js
index 34cb3bb7f6..1f265b98d2 100644
--- a/frontend/src/lang/tw.js
+++ b/frontend/src/lang/tw.js
@@ -1446,7 +1446,11 @@ export default {
total_sort_none: '無',
total_sort_asc: '升序',
total_sort_desc: '降序',
- total_sort_field: '排序字段'
+ total_sort_field: '排序字段',
+ empty_data_strategy: '空值處理',
+ break_line: '線條斷開',
+ set_zero: '置為0,線條不斷開',
+ ignore_data: '跳過空值,不展示'
},
dataset: {
spend_time: '耗時',
diff --git a/frontend/src/lang/zh.js b/frontend/src/lang/zh.js
index a29a2b0b17..f9c00523d5 100644
--- a/frontend/src/lang/zh.js
+++ b/frontend/src/lang/zh.js
@@ -1445,7 +1445,11 @@ export default {
total_sort_none: '无',
total_sort_asc: '升序',
total_sort_desc: '降序',
- total_sort_field: '排序字段'
+ total_sort_field: '排序字段',
+ empty_data_strategy: '空值处理',
+ break_line: '线条断开',
+ set_zero: '置为0,线条不断开',
+ ignore_data: '跳过空值,不展示'
},
dataset: {
spend_time: '耗时',
diff --git a/frontend/src/views/chart/chart/chart.js b/frontend/src/views/chart/chart/chart.js
index a1083cc57a..5f78851539 100644
--- a/frontend/src/views/chart/chart/chart.js
+++ b/frontend/src/views/chart/chart/chart.js
@@ -438,7 +438,8 @@ export const DEFAULT_FUNCTION_CFG = {
sliderRange: [0, 10],
sliderBg: '#FFFFFF',
sliderFillBg: '#BCD6F1',
- sliderTextClolor: '#999999'
+ sliderTextClolor: '#999999',
+ emptyDataStrategy: 'breakLine'
}
export const DEFAULT_THRESHOLD = {
gaugeThreshold: '',
diff --git a/frontend/src/views/chart/chart/line/line_antv.js b/frontend/src/views/chart/chart/line/line_antv.js
index 52cd766dfe..4616c7e695 100644
--- a/frontend/src/views/chart/chart/line/line_antv.js
+++ b/frontend/src/views/chart/chart/line/line_antv.js
@@ -10,7 +10,8 @@ import {
getSlider,
getAnalyse
} from '@/views/chart/chart/common/common_antv'
-import { antVCustomColor } from '@/views/chart/chart/util'
+import { antVCustomColor, handleEmptyDataStrategy } from '@/views/chart/chart/util'
+import _ from 'lodash'
export function baseLineOptionAntV(plot, container, chart, action) {
// theme
@@ -23,7 +24,7 @@ export function baseLineOptionAntV(plot, container, chart, action) {
const xAxis = getXAxis(chart)
const yAxis = getYAxis(chart)
// data
- const data = chart.data.data
+ const data = _.cloneDeep(chart.data.data)
// config
const slider = getSlider(chart)
const analyse = getAnalyse(chart)
@@ -87,7 +88,8 @@ export function baseLineOptionAntV(plot, container, chart, action) {
}
// custom color
options.color = antVCustomColor(chart)
-
+ const emptyDataStrategy = chart.senior ? JSON.parse(chart.senior)?.functionCfg.emptyDataStrategy : 'breakLine'
+ handleEmptyDataStrategy(emptyDataStrategy, chart, data, options)
// 开始渲染
if (plot) {
plot.destroy()
diff --git a/frontend/src/views/chart/chart/util.js b/frontend/src/views/chart/chart/util.js
index c14f28c8d7..ca04a3124f 100644
--- a/frontend/src/views/chart/chart/util.js
+++ b/frontend/src/views/chart/chart/util.js
@@ -3310,3 +3310,120 @@ export function getRemark(chart) {
}
export const quotaViews = ['label', 'richTextView', 'text', 'gauge', 'liquid']
+
+export function handleEmptyDataStrategy(strategy, chart, data, options) {
+ if (!data?.length) {
+ return
+ }
+ if (strategy === 'ignoreData') {
+ handleIgnoreData(chart, data)
+ return
+ }
+ const yaxis = JSON.parse(chart.yaxis)
+ const extAxis = JSON.parse(chart.xaxisExt)
+ const multiDimension = yaxis?.length >= 2 || extAxis?.length > 0
+ switch (strategy) {
+ case 'breakLine': {
+ if (multiDimension) {
+ // 多维度线条断开
+ handleBreakLineMultiDimension(chart, data, options)
+ } else {
+ // 单维度线条断开
+ options.connectNulls = false
+ }
+ break
+ }
+ case 'setZero': {
+ if (multiDimension > 0) {
+ // 多维度置0
+ handleSetZeroMultiDimension(chart, data, options)
+ } else {
+ // 单维度置0
+ handleSetZeroSingleDimension(chart, data, options)
+ }
+ break
+ }
+ default:
+ break
+ }
+}
+
+function handleBreakLineMultiDimension(chart, data, options) {
+ options.connectNulls = false
+ const dimensionInfoMap = new Map()
+ const subDimensionSet = new Set()
+ for (let i = 0; i < data.length; i++) {
+ const item = data[i]
+ const dimensionInfo = dimensionInfoMap.get(item.field)
+ if (dimensionInfo) {
+ dimensionInfo.set.add(item.category)
+ } else {
+ dimensionInfoMap.set(item.field, { set: new Set([item.category]), index: i })
+ }
+ subDimensionSet.add(item.category)
+ }
+ // Map 是按照插入顺序排序的,所以插入索引往后推
+ let insertCount = 0
+ dimensionInfoMap.forEach((dimensionInfo, field) => {
+ if (dimensionInfo.set.size < subDimensionSet.size) {
+ const toBeFillDimension = [...subDimensionSet].filter(item => !dimensionInfo.set.has(item))
+ toBeFillDimension.forEach(dimension => {
+ data.splice(dimensionInfo.index + insertCount, 0, {
+ field,
+ value: null,
+ category: dimension
+ })
+ })
+ insertCount += toBeFillDimension.size
+ }
+ })
+}
+
+function handleSetZeroMultiDimension(chart, data) {
+ const dimensionInfoMap = new Map()
+ const subDimensionSet = new Set()
+ for (let i = 0; i < data.length; i++) {
+ const item = data[i]
+ if (item.value === null) {
+ item.value = 0
+ }
+ const dimensionInfo = dimensionInfoMap.get(item.field)
+ if (dimensionInfo) {
+ dimensionInfo.set.add(item.category)
+ } else {
+ dimensionInfoMap.set(item.field, { set: new Set([item.category]), index: i })
+ }
+ subDimensionSet.add(item.category)
+ }
+ let insertCount = 0
+ dimensionInfoMap.forEach((dimensionInfo, field) => {
+ if (dimensionInfo.set.size < subDimensionSet.size) {
+ const toBeFillDimension = [...subDimensionSet].filter(item => !dimensionInfo.set.has(item))
+ toBeFillDimension.forEach(dimension => {
+ data.splice(dimensionInfo.index + insertCount, 0, {
+ field,
+ value: 0,
+ category: dimension
+ })
+ })
+ insertCount += toBeFillDimension.size
+ }
+ })
+}
+
+function handleSetZeroSingleDimension(chart, data) {
+ data.forEach(item => {
+ if (item.value === null) {
+ item.value = 0
+ }
+ })
+}
+
+function handleIgnoreData(chart, data) {
+ for (let i = data.length - 1; i >= 0; i--) {
+ const item = data[i]
+ if (item.value === null) {
+ data.splice(i, 1)
+ }
+ }
+}
diff --git a/frontend/src/views/chart/components/senior/FunctionCfg.vue b/frontend/src/views/chart/components/senior/FunctionCfg.vue
index 4c76c7159a..4fe2252ca1 100644
--- a/frontend/src/views/chart/components/senior/FunctionCfg.vue
+++ b/frontend/src/views/chart/components/senior/FunctionCfg.vue
@@ -67,6 +67,20 @@
@change="changeFunctionCfg"
/>
+
+
+ {{ $t('chart.break_line') }}
+ {{ $t('chart.set_zero') }}
+ {{ $t('chart.ignore_data') }}
+
+
@@ -110,7 +124,7 @@ export default {
senior = JSON.parse(chart.senior)
}
if (senior.functionCfg) {
- this.functionForm = senior.functionCfg
+ this.functionForm = { ...DEFAULT_FUNCTION_CFG, ...senior.functionCfg }
} else {
this.functionForm = JSON.parse(JSON.stringify(DEFAULT_FUNCTION_CFG))
}
@@ -123,7 +137,7 @@ export default {
}
-
diff --git a/frontend/src/views/chart/view/ChartEdit.vue b/frontend/src/views/chart/view/ChartEdit.vue
index ae3f8df8fe..bd78ac4b01 100644
--- a/frontend/src/views/chart/view/ChartEdit.vue
+++ b/frontend/src/views/chart/view/ChartEdit.vue
@@ -2086,7 +2086,7 @@ export default {
ele.filter = []
}
})
- if (view.type === 'table-pivot' || view.type === 'bar-group') {
+ if (view.type === 'table-pivot' || view.type === 'bar-group' || (view.render === 'antv' && view.type === 'line')) {
view.xaxisExt.forEach(function(ele) {
if (!ele.dateStyle || ele.dateStyle === '') {
ele.dateStyle = 'y_M_d'