2026-01-14 11:02:39 +08:00
|
|
|
|
<template>
|
|
|
|
|
|
<!-- Echarts图表容器,必须设置宽高,绑定ref用于获取DOM -->
|
|
|
|
|
|
<div class="line-chart-container" ref="chartRef"></div>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
<script>
|
|
|
|
|
|
// Vue2 推荐这种引入方式,适配绝大多数echarts版本
|
|
|
|
|
|
import * as echarts from 'echarts'
|
|
|
|
|
|
|
|
|
|
|
|
export default {
|
|
|
|
|
|
name: 'LineChart',
|
|
|
|
|
|
props: {
|
|
|
|
|
|
data: {
|
|
|
|
|
|
type: Array,
|
|
|
|
|
|
default: () => []
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
data() {
|
|
|
|
|
|
return {
|
|
|
|
|
|
// 存储echarts实例对象,防止重复渲染
|
|
|
|
|
|
chartInstance: null
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
mounted() {
|
|
|
|
|
|
// 组件挂载完成初始化图表
|
|
|
|
|
|
this.initEcharts()
|
|
|
|
|
|
// 监听浏览器窗口大小变化,图表自适应
|
|
|
|
|
|
window.addEventListener('resize', this.resizeChart)
|
|
|
|
|
|
},
|
|
|
|
|
|
beforeDestroy() {
|
|
|
|
|
|
// Vue2 销毁生命周期【重点】,不是beforeUnmount
|
|
|
|
|
|
// 销毁实例+解绑监听,防止内存泄漏
|
|
|
|
|
|
window.removeEventListener('resize', this.resizeChart)
|
|
|
|
|
|
if (this.chartInstance) {
|
|
|
|
|
|
this.chartInstance.dispose()
|
|
|
|
|
|
this.chartInstance = null
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
watch: {
|
|
|
|
|
|
// 深度监听父组件传入的data数据,数据更新时重新渲染图表【核心】
|
|
|
|
|
|
data: {
|
|
|
|
|
|
deep: true,
|
|
|
|
|
|
immediate: true,
|
|
|
|
|
|
handler() {
|
|
|
|
|
|
// 数据变化时,先判断实例是否存在,存在则重新渲染
|
|
|
|
|
|
this.chartInstance && this.initEcharts()
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
methods: {
|
|
|
|
|
|
// 初始化echarts图表核心方法
|
|
|
|
|
|
initEcharts() {
|
|
|
|
|
|
const chartDom = this.$refs.chartRef
|
|
|
|
|
|
// 防止重复初始化,先销毁再创建
|
|
|
|
|
|
if (this.chartInstance) {
|
|
|
|
|
|
this.chartInstance.dispose()
|
|
|
|
|
|
}
|
|
|
|
|
|
// 初始化图表实例
|
|
|
|
|
|
this.chartInstance = echarts.init(chartDom)
|
|
|
|
|
|
|
2026-01-14 14:40:19 +08:00
|
|
|
|
// 1. 浅拷贝原数组 + 按planDate日期升序排序,生成新数组,不修改原this.data
|
|
|
|
|
|
const sortedData = [...this.data].sort((a, b) => new Date(a.planDate) - new Date(b.planDate))
|
|
|
|
|
|
|
|
|
|
|
|
// 2. 从排序后的新数组中,提取图表所需数据
|
|
|
|
|
|
const xAxisData = sortedData.map(item => item.productName)
|
|
|
|
|
|
const coilCountData = sortedData.map(item => item.coilCount)
|
|
|
|
|
|
// 总重量字符串转数字,保证图表渲染正常
|
|
|
|
|
|
const totalWeightData = sortedData.map(item => Number(item.totalWeight))
|
2026-01-14 11:02:39 +08:00
|
|
|
|
|
|
|
|
|
|
// echarts核心配置项 - 双Y轴折线图
|
|
|
|
|
|
const option = {
|
|
|
|
|
|
// 图表内边距,防止内容溢出
|
|
|
|
|
|
grid: { left: '3%', right: '10%', bottom: '3%', containLabel: true },
|
|
|
|
|
|
// 鼠标悬浮提示框,展示精准数据
|
|
|
|
|
|
tooltip: {
|
|
|
|
|
|
trigger: 'axis',
|
|
|
|
|
|
formatter: '{b}<br/>{a}: {c}',
|
|
|
|
|
|
axisPointer: { type: 'cross' }
|
|
|
|
|
|
},
|
|
|
|
|
|
// 图例,可点击切换显隐对应折线
|
|
|
|
|
|
legend: {
|
|
|
|
|
|
data: ['总卷数', '总重量(吨)'],
|
|
|
|
|
|
top: 10
|
|
|
|
|
|
},
|
|
|
|
|
|
// X轴 - 类目轴,展示收货计划名称
|
|
|
|
|
|
xAxis: [
|
|
|
|
|
|
{
|
|
|
|
|
|
type: 'category',
|
|
|
|
|
|
data: xAxisData,
|
|
|
|
|
|
axisLabel: {
|
2026-01-14 14:40:19 +08:00
|
|
|
|
// interval: 0, // 强制显示所有X轴标签,不隐藏
|
2026-01-14 11:02:39 +08:00
|
|
|
|
fontSize: 12
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
],
|
|
|
|
|
|
// 双Y轴核心配置
|
|
|
|
|
|
yAxis: [
|
|
|
|
|
|
{
|
|
|
|
|
|
// 左侧Y轴 - 对应【总卷数】
|
|
|
|
|
|
type: 'value',
|
|
|
|
|
|
name: '总卷数',
|
|
|
|
|
|
nameTextStyle: { color: '#2db7f5' },
|
|
|
|
|
|
axisLine: { lineStyle: { color: '#2db7f5' } }
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
// 右侧Y轴 - 对应【总重量】
|
|
|
|
|
|
type: 'value',
|
|
|
|
|
|
name: '总重量(吨)',
|
|
|
|
|
|
nameTextStyle: { color: '#ff6600' },
|
|
|
|
|
|
axisLine: { lineStyle: { color: '#ff6600' } },
|
|
|
|
|
|
splitLine: { show: false } // 关闭右侧网格线,避免页面杂乱
|
|
|
|
|
|
}
|
|
|
|
|
|
],
|
|
|
|
|
|
// 折线图系列数据
|
|
|
|
|
|
series: [
|
|
|
|
|
|
{
|
|
|
|
|
|
name: '总卷数',
|
|
|
|
|
|
type: 'line',
|
|
|
|
|
|
yAxisIndex: 0, // 指定绑定左侧Y轴
|
|
|
|
|
|
data: coilCountData,
|
|
|
|
|
|
smooth: true, // 平滑折线,更美观
|
|
|
|
|
|
symbol: 'circle', // 拐点为圆点
|
|
|
|
|
|
symbolSize: 6,
|
|
|
|
|
|
lineStyle: { width: 2, color: '#2db7f5' },
|
|
|
|
|
|
itemStyle: { color: '#2db7f5' }
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
name: '总重量(吨)',
|
|
|
|
|
|
type: 'line',
|
|
|
|
|
|
yAxisIndex: 1, // 指定绑定右侧Y轴
|
|
|
|
|
|
data: totalWeightData,
|
|
|
|
|
|
smooth: true,
|
|
|
|
|
|
symbol: 'circle',
|
|
|
|
|
|
symbolSize: 6,
|
|
|
|
|
|
lineStyle: { width: 2, color: '#ff6600' },
|
|
|
|
|
|
itemStyle: { color: '#ff6600' }
|
2026-01-14 14:40:19 +08:00
|
|
|
|
},
|
2026-01-14 11:02:39 +08:00
|
|
|
|
]
|
|
|
|
|
|
}
|
|
|
|
|
|
// 设置配置项并渲染图表
|
|
|
|
|
|
this.chartInstance.setOption(option)
|
|
|
|
|
|
},
|
|
|
|
|
|
// 图表自适应窗口大小
|
|
|
|
|
|
resizeChart() {
|
|
|
|
|
|
this.chartInstance && this.chartInstance.resize()
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
|
|
<style scoped>
|
|
|
|
|
|
/* 图表容器必须设置宽高,否则无法渲染,可根据需求修改尺寸 */
|
|
|
|
|
|
.line-chart-container {
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
height: 400px;
|
|
|
|
|
|
}
|
|
|
|
|
|
</style>
|