296 lines
9.1 KiB
Vue
296 lines
9.1 KiB
Vue
<template>
|
||
<!-- 动态绑定 ref:使用 props 中的 chartRef,而非硬编码 -->
|
||
<div :ref="chartRef" id="coreLineChart" style="height: 100%; width: 100%;"></div>
|
||
</template>
|
||
|
||
<script>
|
||
import * as echarts from 'echarts';
|
||
|
||
export default {
|
||
name: 'Container',
|
||
props: {
|
||
// 1. 重命名 props:ref → chartRef,避免关键字冲突,同时定义类型和默认值
|
||
chartRef: {
|
||
type: String,
|
||
required: true, // 强制父组件传值,避免获取不到 DOM
|
||
// validator: (value) => {
|
||
// // 验证:ref 名不能为空,确保有效
|
||
// return value.trim() !== '';
|
||
// }
|
||
},
|
||
pieData: {
|
||
type: Object,
|
||
default: () => { } // 默认空数组,避免报错
|
||
},
|
||
},
|
||
data() {
|
||
return {
|
||
myChart: null,
|
||
resizeHandler: null
|
||
};
|
||
},
|
||
computed: {},
|
||
watch: {
|
||
// 监听 pieData 变化,只要数据变了,就更新图表
|
||
pieData: {
|
||
handler() {
|
||
this.initData(); // 直接调用更新,无需判断 myChart 是否存在
|
||
},
|
||
deep: true,
|
||
immediate: true // 初始化时立即执行
|
||
},
|
||
},
|
||
mounted() {
|
||
this.$nextTick(() => {
|
||
this.initChart(); // 只负责初始化图表实例
|
||
});
|
||
// 注册窗口resize事件,使用稳定的引用以便后续移除
|
||
this.resizeHandler = () => {
|
||
if (this.myChart) {
|
||
this.myChart.resize();
|
||
}
|
||
};
|
||
window.addEventListener('resize', this.resizeHandler);
|
||
},
|
||
methods: {
|
||
initData() {
|
||
console.log(this.pieData,'this.pieData.value');
|
||
|
||
const chartDom = this.$refs[this.chartRef];
|
||
if (!chartDom) {
|
||
console.error(`图表容器未找到!请确认父组件传递的 chartRef 为 "${this.chartRef}"`);
|
||
return;
|
||
}
|
||
const myChart = echarts.init(chartDom);
|
||
|
||
// 自定义颜色数组(与系列一一对应)
|
||
const customColors = [
|
||
'rgba(113, 100, 255, 1)',
|
||
'rgba(40, 138, 255, 1)',
|
||
'rgba(118, 218, 190, 1)',
|
||
'rgba(255, 206, 106, 1)',
|
||
];
|
||
|
||
const option = {
|
||
// 标题配置(主标题+副标题)
|
||
title: [
|
||
{
|
||
text: '月度',
|
||
left: 'center',
|
||
top: '35%',
|
||
textStyle: {
|
||
fontSize: 24,
|
||
letterSpacing: 5,
|
||
color: 'rgba(0, 0, 0, 0.85)',
|
||
fontFamily: 'PingFangSC, PingFang SC'
|
||
}
|
||
},
|
||
{
|
||
text: '单位:万m²',
|
||
left: 'center',
|
||
top: '50%',
|
||
textStyle: {
|
||
fontSize: 16,
|
||
color: 'rgba(0, 0, 0, 0.55)',
|
||
fontFamily: 'PingFangSC, PingFang SC'
|
||
}
|
||
}
|
||
],
|
||
series: [
|
||
{
|
||
name: '销量',
|
||
type: 'pie',
|
||
radius: ['60%', '80%'],
|
||
center: ['50%', '50%'],
|
||
avoidLabelOverlap: false,
|
||
label: {
|
||
show: true,
|
||
position: 'outside',
|
||
distance: 10,
|
||
formatter: '{c}万m²\n{b}',
|
||
textStyle: {
|
||
fontSize: 14,
|
||
color: 'rgba(0, 0, 0, 0.7)',
|
||
fontFamily: 'PingFangSC, PingFang SC',
|
||
lineHeight: 1.5
|
||
}
|
||
},
|
||
labelLine: {
|
||
show: true,
|
||
length: 0,
|
||
length2: 10,
|
||
lineStyle: {
|
||
color: (params) => customColors[params.dataIndex]
|
||
}
|
||
},
|
||
itemStyle: {
|
||
color: (params) => customColors[params.dataIndex]
|
||
},
|
||
data: [
|
||
{
|
||
value: this.pieData?.value || 0, name: '单镀面板',
|
||
label: {
|
||
normal: {
|
||
align: 'left',
|
||
distanceToLabelLine: 2,
|
||
formatter: (params) => [
|
||
`{b|${params.value.toLocaleString()}}`,
|
||
`{hr|■}{c|${params.name}}`
|
||
].join('\n'),
|
||
rich: {
|
||
hr: {
|
||
color: 'rgba(39, 96, 255, 1)',
|
||
fontSize: 20,
|
||
padding: [26, 8, 0, 0]
|
||
},
|
||
b: {
|
||
color: 'rgba(0, 0, 0, 0.75)',
|
||
fontSize: 18,
|
||
padding: [0, 0, 0, 0]
|
||
},
|
||
c: {
|
||
color: 'rgba(64, 64, 64, 1)',
|
||
fontSize: 14,
|
||
padding: [30, 0, 0, -5]
|
||
}
|
||
}
|
||
}
|
||
},
|
||
labelLine: {
|
||
lineStyle: { color: 'rgba(39, 96, 255, 1)' },
|
||
length: 10,
|
||
length2: 20,
|
||
},
|
||
itemStyle: { color: 'rgba(39, 96, 255, 1)' }
|
||
},
|
||
{
|
||
value: 735, name: '双镀销量',
|
||
label: {
|
||
normal: {
|
||
align: 'left',
|
||
distanceToLabelLine: 2,
|
||
formatter: (params) => [
|
||
`{b|${params.value.toLocaleString()}}`,
|
||
`{hr|■}{c|${params.name}}`
|
||
].join('\n'),
|
||
rich: {
|
||
hr: {
|
||
color: 'rgba(40, 138, 255, 1)',
|
||
fontSize: 20,
|
||
padding: [6, 8, 0, 10]
|
||
},
|
||
b: {
|
||
color: 'rgba(0, 0, 0, 0.75)',
|
||
fontSize: 18,
|
||
padding: [-30, 0, 0, 30]
|
||
},
|
||
c: {
|
||
color: 'rgba(64, 64, 64, 1)',
|
||
fontSize: 14,
|
||
padding: [10, 0, 0, -5]
|
||
}
|
||
}
|
||
}
|
||
},
|
||
labelLine: {
|
||
length: 0,
|
||
length2: 10,
|
||
lineStyle: { color: 'rgba(40, 138, 255, 1)' },
|
||
},
|
||
itemStyle: { color: 'rgba(40, 138, 255, 1)' }
|
||
},
|
||
{
|
||
value: 580, name: '丝印打孔',
|
||
label: {
|
||
normal: {
|
||
align: 'left',
|
||
distanceToLabelLine: 2,
|
||
formatter: (params) => [
|
||
`{b|${params.value.toLocaleString()}}`,
|
||
`{hr|■}{c|${params.name}}`
|
||
].join('\n'),
|
||
rich: {
|
||
hr: {
|
||
color: 'rgba(118, 218, 190, 1)',
|
||
fontSize: 20,
|
||
padding: [36, 5, 0, 0]
|
||
},
|
||
b: {
|
||
color: 'rgba(0, 0, 0, 0.75)',
|
||
fontSize: 18,
|
||
padding: [0, 10, 0, 0]
|
||
},
|
||
c: {
|
||
color: 'rgba(64, 64, 64, 1)',
|
||
fontSize: 14,
|
||
padding: [40, -5, 0, 0]
|
||
}
|
||
}
|
||
}
|
||
},
|
||
labelLine: {
|
||
lineStyle: { color: 'rgba(118, 218, 190, 1)' },
|
||
length: 0,
|
||
length2: 10,
|
||
},
|
||
itemStyle: { color: 'rgba(118, 218, 190, 1)' }
|
||
},
|
||
{
|
||
value: 484, name: '无印打孔',
|
||
label: {
|
||
normal: {
|
||
align: 'left',
|
||
distanceToLabelLine: 2,
|
||
formatter: (params) => [
|
||
`{b|${params.value.toLocaleString()}}`,
|
||
`{hr|■}{c|${params.name}}`
|
||
].join('\n'),
|
||
rich: {
|
||
hr: {
|
||
color: 'rgba(255, 206, 106, 1)',
|
||
fontSize: 20,
|
||
padding: [36, 5, 0, 0]
|
||
},
|
||
b: {
|
||
color: 'rgba(0, 0, 0, 0.75)',
|
||
fontSize: 18,
|
||
padding: [0, 20, 0, 0]
|
||
},
|
||
c: {
|
||
color: 'rgba(64, 64, 64, 1)',
|
||
fontSize: 14,
|
||
padding: [40, 15, 0, 0]
|
||
}
|
||
}
|
||
}
|
||
},
|
||
labelLine: {
|
||
lineStyle: { color: 'rgba(255, 206, 106, 1)' },
|
||
length: 10,
|
||
length2: 10,
|
||
},
|
||
itemStyle: { color: 'rgba(255, 206, 106, 1)' }
|
||
}
|
||
]
|
||
}
|
||
]
|
||
};
|
||
|
||
option && this.myChart.setOption(option);
|
||
}
|
||
},
|
||
beforeDestroy() {
|
||
// 移除窗口resize事件监听器
|
||
if (this.resizeHandler) {
|
||
window.removeEventListener('resize', this.resizeHandler);
|
||
this.resizeHandler = null;
|
||
}
|
||
// 销毁图表实例
|
||
if (this.myChart) {
|
||
this.myChart.dispose();
|
||
this.myChart = null;
|
||
}
|
||
}
|
||
};
|
||
</script>
|