Merge pull request #10242 from ulleo/dev-v2

feat(图表): 新增分组柱线组合图&堆叠柱线组合图
This commit is contained in:
ulleo 2024-06-13 14:16:45 +08:00 committed by GitHub
commit 9b60b15a30
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
15 changed files with 213 additions and 26 deletions

View File

@ -114,12 +114,26 @@ public class ChartDataManage {
List<ChartViewFieldDTO> allFields = getAllChartFields(view);
ChartViewDTO chartViewDTO = null;
if (StringUtils.equalsIgnoreCase(view.getType(), "chart-mix")) {
if (StringUtils.containsIgnoreCase(view.getType(), "chart-mix")) {
// 需要排除掉除类别轴以外所有的排序
view.getXAxisExt().forEach(dto -> dto.setSort("none"));
view.getExtBubble().forEach(dto -> dto.setSort("none"));
view.getExtStack().forEach(dto -> dto.setSort("none"));
view.getYAxis().forEach(dto -> dto.setSort("none"));
view.getYAxisExt().forEach(dto -> dto.setSort("none"));
//左轴右轴需要分别调用一次查询
String viewJson = (String) JsonUtil.toJSONString(view);
Map<String, Object> data = new HashMap<>();
//针对左轴删除yAxisExt
ChartViewDTO view1 = JsonUtil.parseObject(viewJson, ChartViewDTO.class);
if (!StringUtils.equalsIgnoreCase(view.getType(), "chart-mix-group")) {
view1.setXAxisExt(new ArrayList<>());
}
if (!StringUtils.equalsIgnoreCase(view.getType(), "chart-mix-stack")) {
view1.setExtStack(new ArrayList<>());
}
view1.setExtBubble(new ArrayList<>());
view1.setYAxisExt(new ArrayList<>());
if (view1.getSenior() != null) {
ChartSeniorAssistCfgDTO assistLineCfg1 = JsonUtil.parseObject((String) JsonUtil.toJSONString(view1.getSenior().get("assistLineCfg")), ChartSeniorAssistCfgDTO.class);
@ -145,13 +159,17 @@ public class ChartDataManage {
}
}
view2.setXAxisExt(view2.getExtBubble());
view2.setExtStack(new ArrayList<>());
view2.setExtBubble(new ArrayList<>());
ChartViewDTO right = calcData(view2, chartExtRequest, allFields, viewFields);
data.put("right", right.getData());
//重新组装
chartViewDTO = BeanUtils.copyBean(new ChartViewDTO(), left);
chartViewDTO.setXAxisExt(view.getXAxisExt());
chartViewDTO.setExtStack(view.getExtStack());
chartViewDTO.setYAxisExt(view.getYAxisExt());
chartViewDTO.setExtBubble(view.getExtBubble());
chartViewDTO.setData(data);
chartViewDTO.setSenior(view.getSenior());
} else {
@ -171,12 +189,12 @@ public class ChartDataManage {
|| ("antv".equalsIgnoreCase(view.getRender()) && "line".equalsIgnoreCase(view.getType()))
|| StringUtils.equalsIgnoreCase(view.getType(), "flow-map")
|| StringUtils.equalsIgnoreCase(view.getType(), "sankey")
|| StringUtils.equalsIgnoreCase(view.getType(), "chart-mix")
|| StringUtils.containsIgnoreCase(view.getType(), "chart-mix")
) {
xAxis.addAll(xAxisExt);
}
List<ChartViewFieldDTO> yAxis = new ArrayList<>(view.getYAxis());
if (StringUtils.equalsIgnoreCase(view.getType(), "chart-mix")
if (StringUtils.containsIgnoreCase(view.getType(), "chart-mix")
|| StringUtils.equalsIgnoreCase(view.getType(), "bidirectional-bar")
|| StringUtils.equalsIgnoreCase(view.getType(), "quadrant")
|| StringUtils.containsIgnoreCase(view.getType(), "progress-bar")) {
@ -836,8 +854,15 @@ public class ChartDataManage {
} else if (StringUtils.containsIgnoreCase(view.getType(), "bidirectional-bar")
|| StringUtils.containsIgnoreCase(view.getType(), "progress-bar")) {
mapChart = ChartDataBuild.transMixChartDataAntV(xAxisBase, xAxis, new ArrayList<>(), yAxis, view, data, isDrill);
} else if (StringUtils.containsIgnoreCase(view.getType(), "chart-mix")) {
} else if (StringUtils.containsIgnoreCase(view.getType(), "chart-mix") && !StringUtils.containsIgnoreCase(view.getType(), "stack")) {
mapChart = ChartDataBuild.transMixChartDataAntV(xAxisBase, xAxis, xAxisExt, yAxis, view, data, isDrill);
} else if (StringUtils.containsIgnoreCase(view.getType(), "chart-mix") && StringUtils.containsIgnoreCase(view.getType(), "stack")) {
if (CollectionUtils.isNotEmpty(extStack)) {
mapChart = ChartDataBuild.transMixChartStackDataAntV(xAxisBase, xAxis, extStack, yAxis, view, data, isDrill);
} else {
//右轴还是走原逻辑
mapChart = ChartDataBuild.transMixChartDataAntV(xAxisBase, xAxis, xAxisExt, yAxis, view, data, isDrill);
}
} else if (StringUtils.containsIgnoreCase(view.getType(), "label")) {
mapChart = ChartDataBuild.transLabelChartData(xAxis, yAxis, view, data, isDrill);
} else if (StringUtils.containsIgnoreCase(view.getType(), "quadrant")) {
@ -1321,7 +1346,7 @@ public class ChartDataManage {
xAxis.addAll(xAxisExt);
}
List<ChartViewFieldDTO> yAxis = new ArrayList<>(view.getYAxis());
if (StringUtils.equalsIgnoreCase(view.getType(), "chart-mix")) {
if (StringUtils.containsIgnoreCase(view.getType(), "chart-mix")) {
List<ChartViewFieldDTO> yAxisExt = new ArrayList<>(view.getYAxisExt());
yAxis.addAll(yAxisExt);
}

View File

@ -5,6 +5,7 @@ import io.dataease.i18n.Lang;
import io.dataease.i18n.Translator;
import io.dataease.utils.IDUtils;
import io.dataease.utils.JsonUtil;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.ObjectUtils;
@ -172,7 +173,7 @@ public class ChartDataBuild {
axisChartDataDTO.setCategory(StringUtils.defaultIfBlank(yAxis.get(j).getChartShowName(), yAxis.get(j).getName()));
buildDynamicValue(view, axisChartDataDTO, row, size, extSize);
Map<String, Object> object = JsonUtil.parse((String) JsonUtil.toJSONString(axisChartDataDTO) , HashMap.class);
Map<String, Object> object = JsonUtil.parse((String) JsonUtil.toJSONString(axisChartDataDTO), HashMap.class);
object.put("x", new BigDecimal(row[0]));
object.put("y", new BigDecimal(row[1]));
@ -515,7 +516,7 @@ public class ChartDataBuild {
}
// antV组合图形
public static Map<String, Object> transMixChartDataAntV(List<ChartViewFieldDTO> xAxisBase, List<ChartViewFieldDTO> xAxis,List<ChartViewFieldDTO> xAxisExt, List<ChartViewFieldDTO> yAxis, ChartViewDTO view, List<String[]> data, boolean isDrill) {
public static Map<String, Object> transMixChartDataAntV(List<ChartViewFieldDTO> xAxisBase, List<ChartViewFieldDTO> xAxis, List<ChartViewFieldDTO> xAxisExt, List<ChartViewFieldDTO> yAxis, ChartViewDTO view, List<String[]> data, boolean isDrill) {
Map<String, Object> map = new HashMap<>();
List<Series> series = new ArrayList<>();
@ -583,7 +584,7 @@ public class ChartDataBuild {
}
axisChartDataDTO.setCategory(
StringUtils.defaultIfBlank(b.toString(),
StringUtils.defaultIfBlank(yAxis.get(j).getChartShowName(), yAxis.get(j).getName())));
StringUtils.defaultIfBlank(yAxis.get(j).getChartShowName(), yAxis.get(j).getName())));
buildDynamicValue(view, axisChartDataDTO, d, size, extSize);
series.get(j).getData().add(axisChartDataDTO);
}
@ -593,6 +594,90 @@ public class ChartDataBuild {
return map;
}
public static Map<String, Object> transMixChartStackDataAntV(List<ChartViewFieldDTO> xAxisBase, List<ChartViewFieldDTO> xAxis, List<ChartViewFieldDTO> extStack, List<ChartViewFieldDTO> yAxis, ChartViewDTO view, List<String[]> data, boolean isDrill) {
if (CollectionUtils.isEmpty(extStack)) {
return transMixChartDataAntV(xAxisBase, xAxis, new ArrayList<>(), yAxis, view, data, isDrill);
}
Map<String, Object> map = new HashMap<>();
List<Series> series = new ArrayList<>();
for (ChartViewFieldDTO y : yAxis) {
Series series1 = new Series();
series1.setName(y.getName());
series1.setType(y.getChartType());
series1.setData(new ArrayList<>());
series.add(series1);
}
for (int i1 = 0; i1 < data.size(); i1++) {
String[] row = data.get(i1);
StringBuilder a = new StringBuilder();
if (isDrill) {
a.append(row[xAxis.size() - 1]);
} else {
for (int i = 0; i < xAxis.size(); i++) {
if (i == xAxis.size() - 1) {
a.append(row[i]);
} else {
a.append(row[i]).append("\n");
}
}
}
// yAxis最后的数据对应extLabel和extTooltip将他们从yAxis中去掉同时转换成动态值
int size = xAxis.size() + extStack.size() + yAxis.size();
int extSize = view.getExtLabel().size() + view.getExtTooltip().size();
int i = xAxis.size();
AxisChartDataAntVDTO axisChartDataDTO = new AxisChartDataAntVDTO();
axisChartDataDTO.setField(a.toString());
axisChartDataDTO.setName(a.toString());
axisChartDataDTO.setCategory(row[xAxis.size()]);
List<ChartDimensionDTO> dimensionList = new ArrayList<>();
List<ChartQuotaDTO> quotaList = new ArrayList<>();
for (int k = 0; k < xAxis.size(); k++) {
ChartDimensionDTO chartDimensionDTO = new ChartDimensionDTO();
chartDimensionDTO.setId(xAxis.get(k).getId());
chartDimensionDTO.setValue(row[k]);
dimensionList.add(chartDimensionDTO);
}
ChartDimensionDTO chartDimensionDTO = new ChartDimensionDTO();
chartDimensionDTO.setId(extStack.get(0).getId());
chartDimensionDTO.setValue(row[xAxis.size()]);
dimensionList.add(chartDimensionDTO);
axisChartDataDTO.setDimensionList(dimensionList);
int j = i - xAxis.size();
int valueIndex = xAxis.size() + extStack.size();
if (ObjectUtils.isNotEmpty(yAxis)) {
ChartQuotaDTO chartQuotaDTO = new ChartQuotaDTO();
chartQuotaDTO.setId(yAxis.get(j).getId());
quotaList.add(chartQuotaDTO);
axisChartDataDTO.setQuotaList(quotaList);
try {
axisChartDataDTO.setValue(StringUtils.isEmpty(row[valueIndex]) ? null : new BigDecimal(row[valueIndex]));
} catch (Exception e) {
axisChartDataDTO.setValue(new BigDecimal(0));
}
buildDynamicValue(view, axisChartDataDTO, row, size, extSize);
} else {
axisChartDataDTO.setQuotaList(quotaList);
axisChartDataDTO.setValue(new BigDecimal(0));
}
series.get(j).getData().add(axisChartDataDTO);
}
map.put("data", series);
return map;
}
// 基础图形
public static Map<String, Object> transChartData(List<ChartViewFieldDTO> xAxis, List<ChartViewFieldDTO> yAxis, ChartViewDTO view, List<String[]> data, boolean isDrill) {
Map<String, Object> map = new HashMap<>();

View File

@ -64,12 +64,12 @@
show-position="viewDialog"
/>
<chart-component-s2
v-if="optType === 'details' && sourceViewType !== 'chart-mix'"
v-if="optType === 'details' && !sourceViewType.includes('chart-mix')"
:view="viewInfo"
show-position="viewDialog"
ref="chartComponentDetails"
/>
<template v-else-if="optType === 'details' && sourceViewType === 'chart-mix'">
<template v-else-if="optType === 'details' && sourceViewType.includes('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>
@ -214,7 +214,7 @@ const dialogInit = (canvasStyle, view, item, opt) => {
const dataDetailsOpt = () => {
nextTick(() => {
const viewDataInfo = dvMainStore.getViewDataDetails(viewInfo.value.id)
if (sourceViewType.value === 'chart-mix') {
if (sourceViewType.value.includes('chart-mix')) {
chartComponentDetails.value?.renderChartFromDialog(viewInfo.value, viewDataInfo.left)
chartComponentDetails2.value?.renderChartFromDialog(viewInfo.value, viewDataInfo.right)
} else {

View File

@ -883,6 +883,8 @@ export default {
last_layer: '当前已经是最后一级',
radar_size: '大小',
chart_mix: '柱线组合图',
chart_mix_group_column: '分组柱线组合图',
chart_mix_stack_column: '堆叠柱线组合图',
axis_value: '轴值',
axis_value_min: '最小值',
axis_value_max: '最大值',

View File

@ -226,7 +226,13 @@ onMounted(() => {
class="drop-style"
:class="themes === 'dark' ? 'dark-dimension-quota' : ''"
>
<el-dropdown-item @click.prevent>
<el-dropdown-item
@click.prevent
v-if="
!chart.type.includes('chart-mix') ||
(chart.type.includes('chart-mix') && type === 'dimension')
"
>
<el-dropdown
:effect="themes"
popper-class="data-dropdown_popper_mr9"
@ -305,7 +311,14 @@ onMounted(() => {
</el-dropdown>
</el-dropdown-item>
<el-dropdown-item @click.prevent v-if="item.deType === 1" divided>
<el-dropdown-item
@click.prevent
v-if="item.deType === 1"
:divided="
!chart.type.includes('chart-mix') ||
(chart.type.includes('chart-mix') && type === 'dimension')
"
>
<el-dropdown
:effect="themes"
placement="right-start"
@ -495,7 +508,14 @@ onMounted(() => {
</template>
</el-dropdown>
</el-dropdown-item>
<el-dropdown-item class="menu-item-padding" divided :command="beforeClickItem('rename')">
<el-dropdown-item
class="menu-item-padding"
:divided="
!chart.type.includes('chart-mix') ||
(chart.type.includes('chart-mix') && type === 'dimension')
"
:command="beforeClickItem('rename')"
>
<el-icon>
<icon name="icon_edit_outlined"></icon>
</el-icon>

View File

@ -665,7 +665,10 @@ onMounted(() => {
<el-dropdown-item
@click.prevent
v-if="
props.type !== 'extLabel' && props.type !== 'extTooltip' && props.type !== 'extBubble'
props.type !== 'extLabel' &&
props.type !== 'extTooltip' &&
props.type !== 'extBubble' &&
!chart.type.includes('chart-mix')
"
:divided="chart.type !== 'table-info'"
>
@ -739,6 +742,7 @@ onMounted(() => {
"
:icon="Filter"
:command="beforeClickItem('filter')"
:divided="chart.type.includes('chart-mix')"
>
<span>{{ t('chart.filter') }}...</span>
</el-dropdown-item>

View File

@ -21,7 +21,7 @@ const props = defineProps({
(props.view.type.includes('bar') ||
props.view.type.includes('line') ||
props.view.type.includes('scatter') ||
props.view.type === 'chart-mix' ||
props.view.type.includes('chart-mix') ||
props.view.type === 'waterfall' ||
props.view.type === 'area' ||
props.view.type === 'area-stack')

View File

@ -45,7 +45,7 @@ const props = defineProps({
<span v-else-if="props.view.type && props.view.type.includes('tree')">{{
t('chart.drag_block_treemap_size')
}}</span>
<span v-else-if="props.view.type && props.view.type === 'chart-mix'">{{
<span v-else-if="props.view.type && props.view.type.includes('chart-mix')">{{
t('chart.drag_block_value_axis_main')
}}</span>
<span v-else-if="props.view.type && props.view.type === 'liquid'">{{

View File

@ -41,7 +41,7 @@ const quotaExtFields = computed<Array<any>>(() => {
})
const useQuotaExt = computed<boolean>(() => {
return props.chart.type === 'chart-mix'
return props.chart.type.includes('chart-mix')
})
const state = reactive({

View File

@ -124,7 +124,7 @@ const onChangeXAxisForm = (val, prop) => {
}
const onChangeYAxisForm = (val, prop) => {
if (prop === 'show' && chart.value.type === 'chart-mix') {
if (prop === 'show' && chart.value.type.includes('chart-mix')) {
chart.value.customStyle.yAxisExt.show = val.show
onChangeYAxisExtForm(chart.value.customStyle.yAxisExt, 'show')
}

View File

@ -634,7 +634,7 @@ const addAxis = (e, axis: AxisType) => {
emitter.emit('removeAxis', { axisType: 'yAxis', axis, editType: 'remove' })
}
}
if (view.value.type === 'chart-mix') {
if (view.value.type.includes('chart-mix')) {
if (axis === 'yAxis') {
if (view.value.yAxisExt.length > 0) {
const chartType = view.value.yAxisExt[0].chartType
@ -1052,7 +1052,6 @@ const saveRename = ref => {
ref.validate(valid => {
if (valid) {
const { renameType, index, chartShowName } = state.itemForm
console.log(renameType)
let axisType, axis
switch (renameType) {
case 'quota':

View File

@ -1374,6 +1374,20 @@ export const CHART_TYPE_CONFIGS = [
value: 'chart-mix',
title: t('chart.chart_mix'),
icon: 'chart-mix'
},
{
render: 'antv',
category: 'dual_axes',
value: 'chart-mix-group',
title: t('chart.chart_mix_group_column'),
icon: 'chart-mix'
},
{
render: 'antv',
category: 'dual_axes',
value: 'chart-mix-stack',
title: t('chart.chart_mix_stack_column'),
icon: 'chart-mix'
}
]
},

View File

@ -72,6 +72,9 @@ export class ColumnLineMix extends G2PlotChartView<DualAxesOptions, DualAxes> {
const data1Type = 'column'
const data2Type = 'line'
const isGroup = this.name === 'chart-mix-group' && chart.xAxisExt?.length > 0
const isStack = this.name === 'chart-mix-stack' && chart.extStack?.length > 0
const seriesField = isGroup ? 'category' : isStack ? 'category' : undefined
const seriesField2 = chart.extBubble?.length > 0 ? 'category' : undefined
const data1 = defaultTo(left[0]?.data, [])
@ -104,7 +107,11 @@ export class ColumnLineMix extends G2PlotChartView<DualAxesOptions, DualAxes> {
geometryOptions: [
{
geometry: data1Type,
color: color[0]
color: isGroup || isStack ? color : color[0],
isGroup: isGroup,
isStack: isStack,
seriesField: seriesField
},
{
geometry: data2Type,
@ -398,11 +405,12 @@ export class ColumnLineMix extends G2PlotChartView<DualAxesOptions, DualAxes> {
o.legend.itemName = {
formatter: (text: string, item: any, index: number) => {
let name = undefined
if (index === 0 && text === 'value') {
if (item.viewId === 'left-axes-view' && text === 'value') {
name = left[0]?.name
} else if (index === 1 && text === 'valueExt') {
} else if (item.viewId === 'right-axes-view' && text === 'valueExt') {
name = right[0]?.name
}
item.id = item.id + '__' + index //防止重复的图例出现问题但是左右轴如果有相同的怎么办
if (name === undefined) {
return text
} else {
@ -447,3 +455,32 @@ export class ColumnLineMix extends G2PlotChartView<DualAxesOptions, DualAxes> {
super(name, DEFAULT_DATA)
}
}
export class GroupColumnLineMix extends ColumnLineMix {
axis: AxisType[] = [...this['axis'], 'xAxisExt']
axisConfig = {
...this['axisConfig'],
yAxis: {
name: `${t('chart.drag_block_value_axis_left')} / ${t('chart.column_quota')}`,
limit: 1,
type: 'q'
}
}
constructor(name = 'chart-mix-group') {
super(name)
}
}
export class StackColumnLineMix extends ColumnLineMix {
axis: AxisType[] = [...this['axis'], 'extStack']
axisConfig = {
...this['axisConfig'],
yAxis: {
name: `${t('chart.drag_block_value_axis_left')} / ${t('chart.column_quota')}`,
limit: 1,
type: 'q'
}
}
constructor(name = 'chart-mix-stack') {
super(name)
}
}

View File

@ -676,7 +676,8 @@ export function getAnalyse(chart: Chart) {
return (
dynamicLineFields?.includes(item.fieldId) &&
(!!_.find(quotaFields, d => d.id === item.fieldId) ||
(!!_.find(quotaExtFields, d => d.id === item.fieldId) && chart.type === 'chart-mix'))
(!!_.find(quotaExtFields, d => d.id === item.fieldId) &&
chart.type.includes('chart-mix')))
)
})
const lines = fixedLines.concat(dynamicLines)

View File

@ -467,7 +467,7 @@ export const exportExcelDownload = (chart, callBack?) => {
viewInfo: chart,
viewName: excelName
}
if (chart.type === 'chart-mix') {
if (chart.type.includes('chart-mix')) {
const req1 = getExcelDownloadRequest(chart.data.left)
const req2 = getExcelDownloadRequest(chart.data.right)
request = {