215 lines
5.5 KiB
Vue
215 lines
5.5 KiB
Vue
<template>
|
||
<div ref="chartContainer" style="height: 100%;"></div>
|
||
</template>
|
||
|
||
<script>
|
||
import * as echarts from 'echarts';
|
||
|
||
export default {
|
||
name: "MaterialBar",
|
||
props: {
|
||
// 图表高度
|
||
height: {
|
||
type: String,
|
||
default: '300px'
|
||
},
|
||
// 库存数据
|
||
stockData: {
|
||
type: Array,
|
||
default: () => []
|
||
},
|
||
// 选中的仓库ID
|
||
selectedWarehouseId: {
|
||
type: [String, Number],
|
||
default: null
|
||
},
|
||
// 仓库树数据
|
||
warehouseTreeData: {
|
||
type: Array,
|
||
default: () => []
|
||
}
|
||
},
|
||
data() {
|
||
return {
|
||
chart: null
|
||
};
|
||
},
|
||
watch: {
|
||
stockData: {
|
||
handler: 'updateChart',
|
||
deep: true
|
||
},
|
||
selectedWarehouseId: {
|
||
handler: 'updateChart',
|
||
immediate: true
|
||
}
|
||
},
|
||
mounted() {
|
||
this.initChart();
|
||
this.updateChart();
|
||
},
|
||
methods: {
|
||
initChart() {
|
||
if (this.chart) {
|
||
this.chart.dispose();
|
||
}
|
||
this.chart = echarts.init(this.$refs.chartContainer);
|
||
window.addEventListener('resize', this.handleResize);
|
||
},
|
||
handleResize() {
|
||
this.chart && this.chart.resize();
|
||
},
|
||
// 获取所有子仓库ID(包括自身)
|
||
getAllWarehouseIds(warehouseId) {
|
||
const ids = new Set();
|
||
|
||
const findChildren = (treeData, targetId) => {
|
||
for (const node of treeData) {
|
||
if (String(node.warehouseId) === String(targetId)) {
|
||
// 找到目标节点,收集它和它的所有子节点的ID
|
||
const collectIds = (node) => {
|
||
ids.add(String(node.warehouseId));
|
||
if (node.children) {
|
||
node.children.forEach(child => collectIds(child));
|
||
}
|
||
};
|
||
collectIds(node);
|
||
return true;
|
||
}
|
||
if (node.children && findChildren(node.children, targetId)) {
|
||
return true;
|
||
}
|
||
}
|
||
return false;
|
||
};
|
||
|
||
if (warehouseId) {
|
||
findChildren(this.warehouseTreeData, warehouseId);
|
||
}
|
||
|
||
return ids;
|
||
},
|
||
|
||
// 处理数据,获取前10的物料
|
||
processData() {
|
||
let filteredData;
|
||
|
||
if (this.selectedWarehouseId) {
|
||
// 获取选中仓库及其所有子仓库的ID
|
||
const warehouseIds = this.getAllWarehouseIds(this.selectedWarehouseId);
|
||
// 过滤属于这些仓库的数据
|
||
filteredData = this.stockData.filter(item => warehouseIds.has(String(item.warehouseId)));
|
||
} else {
|
||
filteredData = this.stockData;
|
||
}
|
||
|
||
// 按物料分组并汇总数量
|
||
const materialMap = new Map();
|
||
filteredData.forEach(item => {
|
||
const key = item.itemName;
|
||
const quantity = Number(item.quantity) || 0;
|
||
const currentQuantity = materialMap.get(key) || 0;
|
||
materialMap.set(key, currentQuantity + quantity);
|
||
});
|
||
|
||
// 转换为数组并排序
|
||
const sortedData = Array.from(materialMap.entries())
|
||
.map(([name, value]) => ({ name, value }))
|
||
.sort((a, b) => b.value - a.value)
|
||
.slice(0, 10); // 只取前10名
|
||
|
||
return sortedData;
|
||
},
|
||
updateChart() {
|
||
if (!this.chart) return;
|
||
|
||
const data = this.processData();
|
||
const names = data.map(item => item.name);
|
||
const values = data.map(item => item.value);
|
||
|
||
// 计算最大值,用于设置图表的最大刻度
|
||
const maxValue = Math.max(...values);
|
||
const interval = Math.ceil(maxValue / 5); // 将刻度分为5份
|
||
|
||
const option = {
|
||
tooltip: {
|
||
trigger: 'axis',
|
||
axisPointer: {
|
||
type: 'shadow'
|
||
},
|
||
formatter: (params) => {
|
||
const data = params[0];
|
||
return `${data.name}<br/>数量: ${data.value}`;
|
||
}
|
||
},
|
||
grid: {
|
||
left: '3%',
|
||
right: '4%',
|
||
bottom: '3%',
|
||
containLabel: true
|
||
},
|
||
xAxis: {
|
||
type: 'value',
|
||
boundaryGap: [0, 0.01],
|
||
max: Math.ceil(maxValue / interval) * interval,
|
||
interval: interval
|
||
},
|
||
yAxis: {
|
||
type: 'category',
|
||
data: names,
|
||
axisTick: {
|
||
alignWithLabel: true
|
||
},
|
||
axisLabel: {
|
||
formatter: (value) => {
|
||
// 如果名称太长,截断并添加省略号
|
||
if (value.length > 10) {
|
||
return value.substring(0, 10) + '...';
|
||
}
|
||
return value;
|
||
}
|
||
}
|
||
},
|
||
series: [
|
||
{
|
||
name: '数量',
|
||
type: 'bar',
|
||
data: values,
|
||
itemStyle: {
|
||
color: new echarts.graphic.LinearGradient(0, 0, 1, 0, [
|
||
{ offset: 0, color: '#83bff6' },
|
||
{ offset: 0.5, color: '#188df0' },
|
||
{ offset: 1, color: '#188df0' }
|
||
])
|
||
},
|
||
emphasis: {
|
||
itemStyle: {
|
||
color: new echarts.graphic.LinearGradient(0, 0, 1, 0, [
|
||
{ offset: 0, color: '#2378f7' },
|
||
{ offset: 0.7, color: '#2378f7' },
|
||
{ offset: 1, color: '#83bff6' }
|
||
])
|
||
}
|
||
},
|
||
label: {
|
||
show: true,
|
||
position: 'right',
|
||
formatter: '{c}'
|
||
}
|
||
}
|
||
]
|
||
};
|
||
|
||
this.chart.setOption(option, true);
|
||
}
|
||
},
|
||
beforeDestroy() {
|
||
window.removeEventListener('resize', this.handleResize);
|
||
if (this.chart) {
|
||
this.chart.dispose();
|
||
this.chart = null;
|
||
}
|
||
}
|
||
};
|
||
</script>
|