Files
yudao-dev/src/views/home/components/psiLineBar.vue
‘937886381’ 1ea62af1d6 修改
2025-11-12 16:56:14 +08:00

268 lines
8.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 ref="cockpitEffChip" id="coreLineChart" style="width: 100%; height: 400px;"></div>
</template>
<script>
import * as echarts from 'echarts';
export default {
components: {},
data() {
return {
myChart: null,
resizeHandler: null
};
},
props: ["saleAndProductData"],
watch: {
// 监听数据变化,动态更新图表
saleAndProductData: {
handler() {
this.updateChart();
},
deep: true,
immediate: true
}
},
mounted() {
this.$nextTick(() => {
this.initChart();
});
},
beforeDestroy() {
// 清理资源
this.myChart && this.myChart.dispose();
window.removeEventListener('resize', this.resizeHandler);
},
methods: {
// 初始化图表实例
initChart() {
const chartDom = this.$refs.cockpitEffChip;
if (!chartDom) {
console.error('图表容器未找到!');
return;
}
this.myChart = echarts.init(chartDom);
this.resizeHandler = () => this.myChart?.resize();
window.addEventListener('resize', this.resizeHandler);
},
// 解析数据提取地名和对应数值统一去掉“基地XX”后缀
parseData() {
// const { saleValues = [], productValues = [], productAndSaleRates = [] } = this.saleAndProductData || {};
const xData = []; // 统一X轴地名
const saleData = []; // 销量数据
const productData = []; // 产量数据
const rateData = []; // 产销率数据(转为百分比)
// 第一步:提取所有地名(以销量数据为准,其他数据按地名匹配)
if (Array.isArray(this.saleAndProductData) && this.saleAndProductData.length) {
this.saleAndProductData.forEach(item => {
// const key = Object.keys(item)[0];
const place = item.name.replace('分公司', ''); // 提取地名(如“宜兴基地销量”→“宜兴”)
xData.push(place);
saleData.push(item.saleValue); // 销量值(保留两位小数)
productData.push(item.productValue);
rateData.push(item.saleAndProductProportion *100 ); // 转为百分比后保留两位小数
});
}
// // 第二步匹配产量数据按X轴地名顺序
// if (Array.isArray(productValues) && productValues.length) {
// xData.forEach(place => {
// const targetItem = productValues.find(item => {
// const key = Object.keys(item)[0];
// return key.includes(place); // 匹配包含该地名的产量键
// });
// productData.push(targetItem ? (Number(targetItem[Object.keys(targetItem)[0]]).toFixed(2) * 1) : 0);
// });
// }
// // 第三步:匹配产销率数据(转为百分比,保留两位小数)
// if (Array.isArray(productAndSaleRates) && productAndSaleRates.length) {
// xData.forEach(place => {
// const targetItem = productAndSaleRates.find(item => {
// const key = Object.keys(item)[0];
// return key.includes(place); // 匹配包含该地名的产销率键
// });
// const rate = targetItem ? (Number(targetItem[Object.keys(targetItem)[0]]).toFixed(4) * 100) : 0;
// rateData.push(rate.toFixed(2) * 1); // 转为百分比后保留两位小数
// });
// }
return { xData, saleData, productData, rateData };
},
// 动态更新图表
updateChart() {
if (!this.myChart) return;
// 解析数据
const { xData, saleData, productData, rateData } = this.parseData();
const option = {
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'cross',
label: {
backgroundColor: '#6a7985'
}
},
formatter: (params) => {
let html = `${params[0].axisValue}<br/>`;
params.forEach(item => {
const unit = item.seriesName === '产销率' ? '%' : '万㎡';
html += `${item.marker} ${item.seriesName}: ${item.value ? item.value :0}${unit}<br/>`;
});
return html;
}
},
grid: {
top: 30,
bottom: 30,
right: 70,
left: 40,
},
xAxis: [
{
type: 'category',
boundaryGap: true,
axisTick: { show: false },
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]
},
data: xData // 动态X轴统一地名
}
],
yAxis: [
{
type: 'value',
name: '万㎡',
nameTextStyle: {
color: 'rgba(0, 0, 0, 0.45)',
fontSize: 12,
align: 'right'
},
min: 0,
max: (value) => value.max > 0 ? Math.ceil(value.max * 1.1) : 10,
scale: false,
axisTick: { show: false },
axisLabel: {
color: 'rgba(0, 0, 0, 0.45)',
fontSize: 12,
formatter: '{value}'
},
splitLine: { lineStyle: { color: 'rgba(0, 0, 0, 0.15)' } },
axisLine: { lineStyle: { color: 'rgba(0, 0, 0, 0.15)' } },
splitNumber: 4
},
{
type: 'value',
nameTextStyle: {
color: 'rgba(0, 0, 0, 0.45)',
fontSize: 12,
align: 'left'
},
min: 0,
max: 100,
axisTick: { show: false },
axisLabel: {
color: 'rgba(0, 0, 0, 0.45)',
fontSize: 12,
formatter: '{value}%'
},
splitLine: { show: false },
axisLine: { lineStyle: { color: 'rgba(0, 0, 0, 0.15)' } },
splitNumber: 4
}
],
series: [
// 1. 产销率折线图右侧Y轴
{
name: '产销率',
type: 'line',
yAxisIndex: 1,
lineStyle: {
color: 'rgba(40, 138, 255, .5)',
width: 2
},
itemStyle: {
color: 'rgba(40, 138, 255, 1)',
borderColor: 'rgba(40, 138, 255, 1)',
borderWidth: 2,
radius: 4
},
areaStyle: {
opacity: 0.2,
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: 'rgba(40, 138, 255, .9)' },
{ offset: 1, color: 'rgba(255, 132, 0, 0)' }
])
},
data: rateData, // 动态产销率数据
symbol: 'circle',
symbolSize: 6
},
// 2. 销量柱状图左侧Y轴
{
name: '销量',
type: 'bar',
yAxisIndex: 0,
barWidth: 24,
itemStyle: {
color: {
type: 'linear',
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [
{ offset: 0, color: 'rgba(130, 204, 255, 1)' },
{ offset: 1, color: 'rgba(75, 157, 255, 1)' }
]
},
borderRadius: [4, 4, 0, 0],
borderWidth: 0
},
data: saleData // 动态销量数据
},
// 3. 产量柱状图左侧Y轴
{
name: '产量',
type: 'bar',
yAxisIndex: 0,
barWidth: 24,
itemStyle: {
color: {
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)' }
]
},
borderRadius: [4, 4, 0, 0],
borderWidth: 0
},
data: productData // 动态产量数据
}
]
};
this.myChart.setOption(option);
}
},
};
</script>