后台传输过来的json数据:

需求描述: 两个展示各渠道支付环境(支付渠道可能有多重)的柱状图,如下:
柱状图1:

柱状图2:

柱状图样式代码:
<div id="channelPayMoneyCharts" style="width: 100%;height:400px;" />
<div id="channelPayTimeCharts" style="width: 100%;height:400px;" />
js:
<script>
export default {
name: 'channelPie',
props: ['channelData'],
data () {
return {
// 动态赋值给柱状图
channelPayMoneyOptionData : [],
channelPayMoneyOptionLegend : [],
channelPayTimeOptionData : [],
channelPayTimeOptionLegend : [],
channelPayMoneyOption: {
// 提示框组件,用于配置鼠标滑过或点击图表时的显示框
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow',
},
},
// 标题
title: {
text: '各渠道支付次数汇总分析[单位:元]',
},
// 左侧显示图例(按钮)
legend: {
type: 'scroll',
orient: 'horizontal',
bottom: 10,
// data: this.channelPayMoneyOptionLegend,
data: []
},
toolbox: {
show: true,
orient: 'vertical',
left: 'right',
top: 'center',
feature: {
mark: { show: true, },
dataView: { show: true, readOnly: false, },
magicType: { show: true, type: ['line', 'bar', 'stack', 'tiled'], },
restore: { show: true, },
saveAsImage: { show: true, },
},
},
xAxis: [
{
type: 'category',
axisTick: { show: false, },
data: [],
}
],
// y轴
yAxis: [
{
type: 'value',
}
],
series: []
},
channelPayTimeOption: {
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow',
},
},
title: {
text: '各渠道支付次数汇总分析',
},
legend: {
type: 'scroll',
orient: 'horizontal',
bottom: 10,
data: [],
},
toolbox: {
show: true,
orient: 'vertical',
left: 'right',
top: 'center',
feature: {
mark: { show: true, },
dataView: { show: true, readOnly: false, },
magicType: { show: true, type: ['line', 'bar', 'stack', 'tiled'], },
restore: { show: true, },
saveAsImage: { show: true, },
},
},
xAxis: [
{
type: 'category',
axisTick: { show: false, },
data: [],
}
],
yAxis: [
{
type: 'value',
minInterval: 1,
axisLabel: {
formatter: '{value} 笔',
},
}
],
series: []
},
}
},
watch: {
channelData: {
handler (newValue, oldValue) {
this.setChannelCharts(newValue)
},
immediate: true,
},
},
mounted () {
this.showChannelPayMoneyCharts()
this.showChannelPayTimeCharts()
},
methods: {
// 初始化series的data数组的对象元素
dataItem() {
return {
// 每个柱的名字
name: '',
type: '',
data: []
}
},
showChannelPayMoneyCharts () {
const channelPayMoneyCharts = this.$echarts.init(document.getElementById('channelPayMoneyCharts'))
channelPayMoneyCharts.setOption(this.channelPayMoneyOption,true)
},
showChannelPayTimeCharts () {
const channelPayTimeCharts = this.$echarts.init(document.getElementById('channelPayTimeCharts'))
channelPayTimeCharts.setOption(this.channelPayTimeOption,true)
},
setChannelCharts (data) {
// 每次赋值之前,先将数据置空一次
this.channelPayMoneyOptionData = []
this.channelPayMoneyOptionLegend = []
this.channelPayTimeOptionData = []
this.channelPayTimeOptionLegend = []
if (data.channelTotals.length > 0 && data.channelDays.length > 0) {
// region 柱状图数据获取
// x轴的值
const x = []
for (let i = 0; i < data.channelDays.length; i++) {
x.push(data.channelDays[i].day.substring(data.channelDays[i].day.length - 2, data.channelDays[i].day.length))
}
for (let i = 0; i < data.channelTotals.length; i++) {
// 初始化5个对象,并给name赋值,有n个渠道,这里就初始化n*5个对象
//截取name来判断支付渠道的类型
const channelPayMoneyOptionDataItem1 = this.dataItem()
channelPayMoneyOptionDataItem1.name = data.channelTotals[i].chName + "支付金额"
channelPayMoneyOptionDataItem1.type = 'line'
this.channelPayMoneyOptionData.push(channelPayMoneyOptionDataItem1)
const channelPayMoneyOptionDataItem2 = this.dataItem()
channelPayMoneyOptionDataItem2.type = 'line'
channelPayMoneyOptionDataItem2.name = data.channelTotals[i].chName + "退款金额"
this.channelPayMoneyOptionData.push(channelPayMoneyOptionDataItem2)
const channelPayMoneyOptionDataItem3 = this.dataItem()
channelPayMoneyOptionDataItem3.type = 'bar'
channelPayMoneyOptionDataItem3.name = data.channelTotals[i].chName + "实收金额"
this.channelPayMoneyOptionData.push(channelPayMoneyOptionDataItem3)
const channelPayTimeOptionDataItem1 = this.dataItem()
channelPayTimeOptionDataItem1.name = data.channelTotals[i].chName + "支付笔数"
channelPayTimeOptionDataItem1.type = 'bar'
this.channelPayTimeOptionData.push(channelPayTimeOptionDataItem1)
const channelPayTimeOptionDataItem2 = this.dataItem()
channelPayTimeOptionDataItem2.name = data.channelTotals[i].chName + "退款笔数"
channelPayTimeOptionDataItem2.type = 'line'
this.channelPayTimeOptionData.push(channelPayTimeOptionDataItem2)
// 给legend数组的名字赋值
this.channelPayMoneyOptionLegend.push(data.channelTotals[i].chName + "支付金额")
this.channelPayMoneyOptionLegend.push(data.channelTotals[i].chName + "退款金额")
this.channelPayMoneyOptionLegend.push(data.channelTotals[i].chName + "实收金额")
this.channelPayTimeOptionLegend.push(data.channelTotals[i].chName + "支付笔数")
this.channelPayTimeOptionLegend.push(data.channelTotals[i].chName + "退款笔数")
}
// 给柱状图标题赋值
this.channelPayTimeOption.title.text = `${data.channelDays[0].day.substr(0, 4)}年${data.channelDays[0].day.substr(5, 2)}月每天各支付渠道支付次数汇总统计`
this.channelPayMoneyOption.title.text = `${data.channelDays[0].day.substr(0, 4)}年${data.channelDays[0].day.substr(5, 2)}月每天各支付渠道支付金额汇总统计[单位:元]`
for (let i = 0; i < data.channelDays.length; i++) {
// 一天的数据
for (let j = 0; j < data.channelDays[i].channelDayDetails.length; j++) {
for (let k = 0; k < this.channelPayMoneyOptionData.length; k++) {
if (data.channelDays[i].channelDayDetails[j].chName === this.channelPayMoneyOptionData[k].name.substring(0,this.channelPayMoneyOptionData[k].name.length-4)) {
this.channelPayMoneyOptionData[k].data.push(data.channelDays[i].channelDayDetails[j].totalMoney)
this.channelPayMoneyOptionData[k + 1].data.push(data.channelDays[i].channelDayDetails[j].refundMoney)
this.channelPayMoneyOptionData[k + 2].data.push(data.channelDays[i].channelDayDetails[j].realPay)
k += 2
}
}
for (let l = 0; l < this.channelPayTimeOptionData.length; l++) {
if (data.channelDays[i].channelDayDetails[j].chName === this.channelPayTimeOptionData[l].name.substring(0,this.channelPayTimeOptionData[l].name.length-4)) {
this.channelPayTimeOptionData[l].data.push(data.channelDays[i].channelDayDetails[j].payTime)
this.channelPayTimeOptionData[l + 1].data.push(data.channelDays[i].channelDayDetails[j].refundTimes)
l++
}
}
}
}
this.channelPayTimeOption.xAxis[0].data = x
this.channelPayMoneyOption.xAxis[0].data = x
this.channelPayMoneyOption.legend.data = this.channelPayMoneyOptionLegend
this.channelPayMoneyOption.series = this.channelPayMoneyOptionData
this.channelPayTimeOption.legend.data = this.channelPayTimeOptionLegend
this.channelPayTimeOption.series = this.channelPayTimeOptionData
// endregion
//region 数据渲染
this.showChannelPayMoneyCharts()
this.showChannelPayTimeCharts()
// endregion
} else {
// 清空数据
if (this.channelPayTimeOption.series.length > 0) {
for (let i = 0; i < this.channelPayTimeOption.series.length; i++) {
this.channelPayTimeOption.series[i].data = []
}
this.channelPayTimeOption.xAxis[0].data = []
}
if (this.channelPayMoneyOption.series.length > 0) {
for (let i = 0; i < this.channelPayMoneyOption.series.length; i++) {
this.channelPayMoneyOption.series[i].data = []
}
this.channelPayMoneyOption.xAxis[0].data = []
}
this.showChannelPayCharts()
this.showChannelTimesCharts()
this.showChannelPayMoneyCharts()
this.showChannelPayTimeCharts()
}
console.log(this.channelPayMoneyOption)
console.log(this.channelPayTimeOption)
},
},
}
</script>
给legend的data赋值的时候,直接声明一个数组(存放字符串),然后将后台数据装进数组,然后再把数组的值传给legend.data就可以了
给series赋值的时候,直接声明一个数组(存放对象),需要声明一个构造器来实例化对象,然后存进数组中,构造器的内容参考官方文档后,其属性有:name、type、data

dataItem() {
return {
// 每个柱的名字
name: '',
type: '',
data: []
}
},
当一天的柱状图有 n 条,那么legend的data就需要装 n 个字符串,series就需要装 n 个对象
这是一个前后端分离的项目,先说一下后台优化的思路,即如何数据置零:
先遍历总体数据的所有支付渠道
然后给每天的数据中都添加进所有支付渠道,即使那天渠道数据为空
这一步很简单,先实例化pojo赋初值,然后判断数据库数据是否为空
- 如果为空,那么久直接把pojo对象传进去(这时候,pojo所有值都是初始值,主要用来占位,保证数据与x轴日期一一对应)
- 如果不为空,那就将数据库数据赋值给pojo对象
优化之后,后台传过来的每日数据如下:

接着是对上面的前端js代码的优化思路:
legend 和 series 直接指向空数组,然后在赋值方法中声明对应的数组对象,最后给 legend和series赋值
legend: {
type: 'scroll',
orient: 'horizontal',
bottom: 10,
data: [],
},
series: [],
...
// Series==>需要显示的每一项数据名字、类型、以及数据
const channelPayMoneySeries = []
const channelPayTimeSeries = []
// legend==>需要显示的标签(数据标签)
const channelPayMoneyLegend = []
const channelPayTimeLegend = []
...
// 给option赋值
this.channelPayTimeOption.xAxis[0].data = x
this.channelPayMoneyOption.xAxis[0].data = x
this.channelPayMoneyOption.legend.data = channelPayMoneyLegend
this.channelPayMoneyOption.series = channelPayMoneySeriesNew
this.channelPayTimeOption.legend.data = channelPayTimeLegend
this.channelPayTimeOption.series = channelPayTimeSeriesNew
因为后台数据已经优化,所以前端赋值代码也要改变,给legend和series的name和type的赋值只需要遍历 channelDays[0].channelDayDetails 就可
因为js弱类型语言的特性,所以可以直接给series的data中的对象添加chId属性进去,进行类型判断,就不需要进行字符串截取判断了,这样更方便
data.channelDays[0].channelDayDetails.forEach((channelDayDetail) => {
const channelPayMoneyItem = this.dataItem()
channelPayMoneyItem.name = channelDayDetail.chName + '支付金额'
channelPayMoneyItem.chId = channelDayDetail.chId
channelPayMoneyItem.type = 'line'
现在给series赋值,其逻辑如下:
data.channelDays.forEach((channelDay) => {
channelDay.channelDayDetails.forEach((channelDayDetail) => {
channelPayMoneySeries.forEach((channelPayMoneySerie) => {
if (channelDayDetail.chId == channelPayMoneySerie.chId) {
// 删除没有统计数据的渠道
const channelPayMoneySeriesNew = channelPayMoneySeries.filter((channelPayMoneySerie) => {
let dataSum = 0
channelPayMoneySerie.data.forEach((dataItem) => {
dataSum += dataItem
})
return dataSum > 0
})
const channelPayTimeSeriesNew = channelPayTimeSeries.filter((channelPayTimeSerie) => {
let dataSum = 0
channelPayTimeSerie.data.forEach((dataItem) => {
dataSum += dataItem
})
return dataSum > 0
})