187 lines
5.6 KiB
Vue
187 lines
5.6 KiB
Vue
<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
|
||
};
|
||
},
|
||
props: {
|
||
refName: {
|
||
type: String,
|
||
default: 'verticalBarChart',
|
||
},
|
||
detailData: {
|
||
type: Object,
|
||
default: () => ({
|
||
completeRate: 0,
|
||
diff: 0,
|
||
real: 0,
|
||
target: 0,
|
||
thb: 0,
|
||
flag: 0
|
||
}),
|
||
}
|
||
},
|
||
mounted() {
|
||
this.$nextTick(() => this.updateChart());
|
||
},
|
||
watch: {
|
||
detailData: {
|
||
handler() {
|
||
this.updateChart();
|
||
},
|
||
deep: true,
|
||
immediate: true
|
||
}
|
||
},
|
||
methods: {
|
||
updateChart() {
|
||
const chartDom = this.$refs[this.refName];
|
||
if (!chartDom) {
|
||
console.error('图表容器未找到!');
|
||
return;
|
||
}
|
||
|
||
// 修复:优化实例销毁逻辑,避免重复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表示替换所有配置,避免缓存
|
||
|
||
// 优化:防抖resize,避免频繁触发
|
||
const resizeHandler = () => {
|
||
this.myChart && this.myChart.resize();
|
||
};
|
||
window.removeEventListener('resize', resizeHandler); // 先移除再添加,避免重复绑定
|
||
window.addEventListener('resize', resizeHandler);
|
||
|
||
this.$once('hook:destroyed', () => {
|
||
window.removeEventListener('resize', resizeHandler);
|
||
this.myChart && this.myChart.dispose();
|
||
this.myChart = null;
|
||
});
|
||
}
|
||
},
|
||
};
|
||
</script>
|