Files
klp-oa/klp-ui/src/views/wms/stock/panels/bar.vue
2025-08-11 18:34:45 +08:00

215 lines
5.5 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="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>