若依后台数据大屏实战:用ECharts嵌套饼图展示‘计划 vs 实际’业务数据
·
若依后台数据大屏实战:用ECharts嵌套饼图展示‘计划 vs 实际’业务数据
在企业管理系统中,数据可视化是提升决策效率的关键。当我们需要直观展示"计划与实际"的业务对比时,嵌套饼图(Nested Pie Chart)往往能带来意想不到的效果——内环展示日维度数据,外环呈现月维度统计,形成天然的层级关系。本文将基于若依分离版框架,从后端SQL查询到前端ECharts配置,完整实现一个可复用的数据对比大屏模块。
1. 业务数据准备与后端接口设计
任何数据可视化的前提都是准确的数据源。在若依框架中,我们通常通过MyBatis操作数据库。假设我们需要统计某物流系统的日发货计划与实际完成量对比,首先需要构建合理的SQL查询:
-- 获取当月每日计划与实际数据
SELECT
DATE_FORMAT(shipment_date, '%Y-%m-%d') AS day,
SUM(plan_quantity) AS daily_plan,
SUM(actual_quantity) AS daily_actual
FROM sm_shipment_daily
WHERE DATE_FORMAT(shipment_date,'%Y-%m') = #{month}
GROUP BY day
ORDER BY day;
在Controller层,我们需要设计符合RESTful规范的API接口。考虑到数据大屏可能需要同时展示多组数据,建议采用如下结构返回:
@GetMapping("/api/shipment/compare/{month}")
public R<ShipmentCompareVO> getShipmentCompare(
@PathVariable String month) {
// 1. 查询日维度数据
List<DailyShipment> dailyData = shipmentService.selectDailyCompare(month);
// 2. 计算月维度汇总
MonthlyShipment monthlyData = shipmentService.calculateMonthlyTotal(month);
// 3. 封装VO对象
ShipmentCompareVO vo = new ShipmentCompareVO();
vo.setDailyData(dailyData);
vo.setMonthlyData(monthlyData);
return R.ok(vo);
}
返回的JSON数据结构示例:
{
"code": 200,
"msg": "操作成功",
"data": {
"dailyData": [
{"day": "2024-08-01", "plan": 1200, "actual": 980},
...
],
"monthlyData": {
"month": "2024-08",
"totalPlan": 30000,
"totalActual": 27500
}
}
}
2. 前端数据预处理与ECharts组件集成
在若依分离版的前端Vue项目中,我们需要先确保正确引入了ECharts。对于Vue 2.x项目,推荐使用vue-echarts的5.x版本:
npm install echarts@4.9.0 vue-echarts@5.0.0-beta.0 @vue/composition-api --save
在main.js中进行全局注册:
import ECharts from 'vue-echarts'
import 'echarts'
Vue.component('v-chart', ECharts)
数据获取与预处理是可视化效果的关键。在Vue组件中,我们需要:
- 通过axios获取后端数据
- 将原始数据转换为ECharts需要的格式
- 处理可能的空值或异常情况
export default {
data() {
return {
currentMonth: '2024-08',
chartOption: null
}
},
methods: {
async fetchData() {
try {
const res = await getShipmentCompare(this.currentMonth)
this.prepareChartOption(res.data)
} catch (error) {
console.error('数据获取失败:', error)
}
},
prepareChartOption(apiData) {
// 计算月完成率
const monthlyCompletion = (
apiData.monthlyData.totalActual /
apiData.monthlyData.totalPlan * 100
).toFixed(1)
// 计算日平均完成率
const dailyAvg = apiData.dailyData.reduce((sum, item) => {
return sum + (item.actual / item.plan)
}, 0) / apiData.dailyData.length * 100
this.chartOption = {
// 将在下一节详细配置
}
}
},
mounted() {
this.fetchData()
}
}
3. 嵌套饼图的高级配置解析
嵌套饼图的核心在于series数组中配置多个饼图系列,并通过radius属性控制它们的半径范围。以下是完整的option配置及其业务含义:
{
tooltip: {
trigger: 'item',
formatter: params => {
const { name, value, percent } = params
const unit = params.seriesIndex === 0 ? '件/日' : '件/月'
return `${name}<br/>${value}${unit} (${percent}%)`
}
},
legend: {
data: ['日计划', '日实际', '月计划', '月实际'],
bottom: 10
},
series: [
// 内环 - 日维度数据
{
name: '日维度',
type: 'pie',
radius: ['0%', '40%'],
label: {
position: 'inner',
formatter: '{b}\n{c}件'
},
labelLine: { show: false },
data: [
{
value: apiData.dailyData.reduce((sum, d) => sum + d.plan, 0),
name: '日计划',
itemStyle: { color: '#5470C6' }
},
{
value: apiData.dailyData.reduce((sum, d) => sum + d.actual, 0),
name: '日实际',
itemStyle: { color: '#91CC75' }
}
]
},
// 外环 - 月维度数据
{
name: '月维度',
type: 'pie',
radius: ['55%', '70%'],
label: {
formatter: '{b}: {c} ({d}%)',
textStyle: { fontSize: 14 }
},
data: [
{
value: apiData.monthlyData.totalPlan,
name: '月计划',
itemStyle: { color: '#EE6666' }
},
{
value: apiData.monthlyData.totalActual,
name: '月实际',
itemStyle: { color: '#FAC858' }
}
]
}
]
}
关键配置说明:
-
radius控制饼图半径 :
- 内环设置为
['0%', '40%']表示从中心到40%的位置 - 外环设置为
['55%', '70%']形成环状效果
- 内环设置为
-
label标签定制 :
- 内环使用
position: 'inner'将标签显示在内部 - 外环标签显示更详细的信息
- 内环使用
-
颜色方案 :
- 使用互补色区分计划和实际数据
- 日维度使用蓝色系,月维度使用红色系
4. 交互增强与性能优化
基础图表实现后,我们需要考虑实际业务场景中的交互需求:
动态数据刷新
// 在组件中添加定时刷新
setInterval(() => {
this.fetchData()
}, 300000) // 每5分钟刷新一次
响应式调整
window.addEventListener('resize', () => {
if (this.$refs.chart) {
this.$refs.chart.resize()
}
})
大数据量优化
当数据量较大时,可以启用ECharts的数据采样和动画优化:
{
animation: true,
animationThreshold: 2000,
progressive: 200,
progressiveThreshold: 3000
}
点击钻取交互
通过ECharts的点击事件实现下钻功能:
this.$refs.chart.on('click', params => {
if (params.seriesName === '月维度') {
this.currentMonth = params.name === '月计划' ?
this.currentMonth :
moment(this.currentMonth).subtract(1, 'month').format('YYYY-MM')
this.fetchData()
}
})
5. 业务场景扩展与实践建议
嵌套饼图不仅适用于计划与实际对比,还可应用于:
- 多层级占比分析 :如销售渠道分布(线上/线下)下的具体品类占比
- 目标进度监控 :年度目标与季度完成情况对比
- 资源分配评估 :预算分配与实际支出对比
实际项目中需要注意:
- 数据准确性 :确保后端计算逻辑与业务定义一致
- 颜色语义 :使用行业通用颜色编码(如红色常表示预警)
- 移动端适配 :在小屏幕上可能需要简化图表元素
// 移动端简化配置示例
const isMobile = window.innerWidth < 768
if (isMobile) {
this.chartOption.legend.orient = 'vertical'
this.chartOption.legend.right = 10
this.chartOption.series[0].radius = ['0%', '30%']
this.chartOption.series[1].radius = ['40%', '60%']
}
更多推荐



所有评论(0)