Files
yudao-dev/src/views/home/totalProfitComponents/verticalBarChart.vue

198 lines
6.2 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div style="width: 100%; height: 210px;position: relative;">
<div style='font-size: 16px;position: absolute;left: 20px;top:10px'>
万元
</div>
<div style='font-size: 16px;position: absolute;right: 20px;top:10px'>
<span>完成率:<span style='color: #0B58FF;'>{{detailData.completeRate}}%</span></span>
<span style='display: inline-block;margin-left: 10px;'>差值:<span :style="{color:detailData.flag>0?'#30B590':'#FF9423'}" >{{detailData.diff}}</span></span>
</div>
<div :ref="refName" id="coreLineChart" style="width: 100%; height: 210px;"></div>
</div>
</template>
<script>
import * as echarts from 'echarts';
export default {
components: {},
data() {
return {
myChart: null,
resizeHandler: null, // 窗口resize事件处理器
isMounted: false // 图表挂载标志,避免过早执行
};
},
props: {
refName: {
type: String,
default: 'verticalBarChart',
},
detailData: {
type: Object,
default: () => ({
completeRate: 0,
diff: 0,
real: 0,
target: 0,
thb: 0,
flag: 0
}),
}
},
mounted() {
this.isMounted = true;
this.$nextTick(() => this.updateChart());
// 注册窗口resize事件使用稳定的引用以便后续移除
this.resizeHandler = () => {
if (this.myChart) {
this.myChart.resize();
}
};
window.addEventListener('resize', this.resizeHandler);
},
watch: {
detailData: {
handler() {
if (!this.isMounted) return;
this.updateChart();
},
deep: true
// 移除 immediate: true由 mounted 中的 updateChart() 处理初始化
}
},
methods: {
updateChart() {
const chartDom = this.$refs[this.refName];
if (!chartDom) {
if (process.env.NODE_ENV === 'development') console.warn('图表容器未找到!');
return;
}
console.log('this.detailData', this.detailData);
// 修复优化实例销毁逻辑避免重复dispose
if (this.myChart) {
this.myChart.clear(); // 先清空,再重新渲染
} else {
this.myChart = echarts.init(chartDom);
}
// 解构数据,避免重复取值
const { diff, completeRate, real, target, flag } = this.detailData;
// 确保数值为数字类型
const realValue = Number(real) || 0;
const targetValue = Number(target) || 0;
const diffValue = Number(diff) || 0;
const rateValue = Number(completeRate) || 0;
const flagValue = Number(flag) || 0;
const option = {
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'cross',
label: { backgroundColor: '#6a7985' }
}
},
grid: {
top: 40,
bottom: 15,
right: 80,
left: 10,
containLabel: true,
show: false
},
xAxis: {
type: 'value',
axisTick: { show: false },
min: 0,
splitNumber: 4,
axisLine: { show: true, lineStyle: { color: 'rgba(0, 0, 0, 0.15)' } },
axisLabel: { color: 'rgba(0, 0, 0, 0.45)', fontSize: 12, interval: 0, padding: [5, 0, 0, 0] }
},
yAxis: {
type: 'category',
axisLabel: { color: 'rgba(0, 0, 0, 0.75)', fontSize: 12, interval: 0, padding: [5, 0, 0, 0] },
axisLine: { show: true, lineStyle: { color: '#E5E6EB', width: 1, type: 'solid' } },
axisTick: { show: false },
data: ['实际', '预算']
},
series: [
{
type: 'bar',
barWidth: 24,
// 修复:拆分数据项,确保每个柱子的样式独立生效
data: [
// 实际值柱子核心绑定flag颜色
{
value: realValue,
label: {
show: true,
position: 'right',
fontSize: 14
},
// 修复flag颜色判断独立绑定到实际值柱子
itemStyle: {
color: flagValue === 1
? {
type: 'linear',
x: 0, y: 0, x2: 0, y2: 1,
colorStops: [
{ offset: 0, color: 'rgba(174, 239, 224, 1)' },
{ offset: 1, color: 'rgba(118, 218, 190, 1)' }
]
}
: {
type: 'linear',
x: 0, y: 0, x2: 0, y2: 1,
colorStops: [
{ offset: 0, color: 'rgba(253, 209, 129, 1)' },
{ offset: 1, color: 'rgba(249, 164, 74, 1)' }
]
},
borderRadius: [4, 4, 0, 0]
}
},
// 预算值柱子(固定蓝色渐变)
{
value: targetValue,
label: {
show: true,
position: 'right',
fontSize: 14
},
itemStyle: {
color: {
type: 'linear',
x: 1, y: 0, x2: 0, y2: 1,
colorStops: [
{ offset: 0, color: '#82CCFF' },
{ offset: 1, color: '#4B9DFF' }
]
},
borderRadius: [4, 4, 0, 0],
borderWidth: 0
}
}
]
}
]
};
this.myChart.setOption(option, true); // 新增true表示替换所有配置避免缓存
}
},
beforeDestroy() {
// 移除窗口resize事件监听器
if (this.resizeHandler) {
window.removeEventListener('resize', this.resizeHandler);
this.resizeHandler = null;
}
// 销毁图表,避免内存泄漏
if (this.myChart) {
this.myChart.dispose();
this.myChart = null;
}
}
};
</script>