feat(RealTimeInventory): 添加销售数据展示并与库存历史趋势对比

- 新增销售数据获取API接口调用
- 在图表中同时展示库存历史趋势和销售数据
- 优化图表配置以支持多系列数据显示
- 添加销售数据相关状态管理
master
huangjinysf 2 months ago
parent f6550cd819
commit 04d29f5aae

@ -155,8 +155,11 @@ const wmsTableRef = ref(null)
// //
const inventoryChartRef = ref(null) const inventoryChartRef = ref(null)
const historyChartLoading = ref(false) const historyChartLoading = ref(false)
const salesChartLoading = ref(false)
const historyData = ref([]) const historyData = ref([])
const salesData = ref([])
const hasHistoryData = ref(false) const hasHistoryData = ref(false)
const hasSalesData = ref(false)
const selectedTimeRange = ref('近1月') const selectedTimeRange = ref('近1月')
const chartUnit = ref('box') const chartUnit = ref('box')
let inventoryChart = null let inventoryChart = null
@ -401,6 +404,65 @@ const handleCellDblClick = (row, column, cell, event) => {
fetchInventoryHistoryData(model, row.specification, wire_disc); fetchInventoryHistoryData(model, row.specification, wire_disc);
}; };
//
const fetchSalesData = (model, specification) => {
salesChartLoading.value = true;
const dateRange = getDateRangeByTimeRange(selectedTimeRange.value);
// API URL
const params = new URLSearchParams({
model: model || '',
specification: specification || '',
start_date: dateRange.start_date,
end_date: dateRange.end_date
});
let apiUrl = `${API_CONFIG.BASE_URL}/api/sale/records?${params.toString()}`;
console.log('销售数据API调用参数:', {
model,
specification,
dateRange,
apiUrl
});
fetch(apiUrl)
.then(response => response.json())
.then(data => {
console.log('销售数据API原始返回数据:', data);
if (data.code === 200 && data.data) {
let records = data.data;
console.log('销售原始数据:', records);
console.log('销售记录数量:', records.length);
//
if (records.length > 0) {
console.log('销售第一条记录结构:', records[0]);
console.log('销售第一条记录的所有键:', Object.keys(records[0]));
}
salesData.value = records;
hasSalesData.value = salesData.value.length > 0;
console.log('设置后的salesData:', salesData.value);
console.log('hasSalesData:', hasSalesData.value);
} else {
console.error('销售数据API返回数据格式错误:', data);
salesData.value = [];
hasSalesData.value = false;
}
})
.catch(error => {
console.error('销量数据API调用失败:', error);
salesData.value = [];
hasSalesData.value = false;
})
.finally(() => {
salesChartLoading.value = false;
});
};
// //
const fetchInventoryHistoryData = (model, specification, wireDisc) => { const fetchInventoryHistoryData = (model, specification, wireDisc) => {
historyChartLoading.value = true; historyChartLoading.value = true;
@ -418,7 +480,7 @@ const fetchInventoryHistoryData = (model, specification, wireDisc) => {
let apiUrl = `${API_CONFIG.BASE_URL}/api/plan/wms/history?${params.toString()}`; let apiUrl = `${API_CONFIG.BASE_URL}/api/plan/wms/history?${params.toString()}`;
console.log('API调用参数:', { console.log('库存历史API调用参数:', {
model, model,
specification, specification,
wireDisc, wireDisc,
@ -426,21 +488,48 @@ const fetchInventoryHistoryData = (model, specification, wireDisc) => {
apiUrl apiUrl
}); });
fetch(apiUrl) //
Promise.all([
fetchInventoryHistoryAPI(apiUrl),
fetchSalesData(model, specification)
]).then(() => {
nextTick(() => {
setTimeout(() => {
console.log('开始初始化图表');
initInventoryChart();
}, 100);
});
}).catch(error => {
console.error('数据获取失败:', error);
historyData.value = [];
hasHistoryData.value = false;
salesData.value = [];
hasSalesData.value = false;
}).finally(() => {
historyChartLoading.value = false;
});
};
// API
const fetchInventoryHistoryAPI = (apiUrl) => {
return fetch(apiUrl)
.then(response => response.json()) .then(response => response.json())
.then(data => { .then(data => {
console.log('API原始返回数据:', data); console.log('库存历史API原始返回数据:', data);
if (data.code === 200 && data.data && data.data.records) { if (data.code === 200 && data.data && data.data.records) {
let records = data.data.records; let records = data.data.records;
console.log('原始records数据:', records); console.log('库存历史原始records数据:', records);
console.log('records数量:', records.length); console.log('库存历史records数量:', records.length);
// //
if (records.length > 0) { if (records.length > 0) {
console.log('第一条记录结构:', records[0]); console.log('库存历史第一条记录结构:', records[0]);
console.log('第一条记录的所有键:', Object.keys(records[0])); console.log('库存历史第一条记录的所有键:', Object.keys(records[0]));
} }
//
const dateRange = getDateRangeByTimeRange(selectedTimeRange.value);
// 使 // 使
if (isMoreThanOneWeek(dateRange.start_date, dateRange.end_date)) { if (isMoreThanOneWeek(dateRange.start_date, dateRange.end_date)) {
records = downsampleHistoryToKeyTimes(records); records = downsampleHistoryToKeyTimes(records);
@ -452,17 +541,8 @@ const fetchInventoryHistoryData = (model, specification, wireDisc) => {
console.log('设置后的historyData:', historyData.value); console.log('设置后的historyData:', historyData.value);
console.log('hasHistoryData:', hasHistoryData.value); console.log('hasHistoryData:', hasHistoryData.value);
nextTick(() => {
setTimeout(() => {
console.log('开始初始化图表');
initInventoryChart();
}, 100);
});
} else { } else {
console.error('API返回数据格式错误:', data); console.error('库存历史API返回数据格式错误:', data);
console.error('data.code:', data.code);
console.error('data.data:', data.data);
historyData.value = []; historyData.value = [];
hasHistoryData.value = false; hasHistoryData.value = false;
} }
@ -471,9 +551,6 @@ const fetchInventoryHistoryData = (model, specification, wireDisc) => {
console.error('库存历史数据API调用失败:', error); console.error('库存历史数据API调用失败:', error);
historyData.value = []; historyData.value = [];
hasHistoryData.value = false; hasHistoryData.value = false;
})
.finally(() => {
historyChartLoading.value = false;
}); });
}; };
@ -571,46 +648,50 @@ const initInventoryChart = () => {
// //
const option = { const option = {
title: { title: {
text: '库存历史趋势', text: '库存历史趋势与销售对比',
left: 'center', left: 'center',
textStyle: { textStyle: {
fontSize: 16, fontSize: 16,
fontWeight: 'bold' fontWeight: 'bold'
} }
}, },
tooltip: { tooltip: {
trigger: 'axis', trigger: 'axis',
axisPointer: { axisPointer: {
type: 'cross', type: 'cross',
label: { label: {
backgroundColor: '#6a7985' backgroundColor: '#6a7985'
} }
}, },
formatter: function(params) { formatter: function(params) {
let result = `<div style="margin-bottom: 5px;"><strong>${echarts.format.formatTime('yyyy-MM-dd hh:mm', params[0].value[0])}</strong></div>`; let result = `<div style="margin-bottom: 5px;"><strong>${echarts.format.formatTime('yyyy-MM-dd hh:mm', params[0].value[0])}</strong></div>`;
params.forEach(param => { params.forEach(param => {
const seriesName = param.seriesName; const seriesName = param.seriesName;
const value = param.value[1]; const value = param.value[1];
const unit = chartUnit.value === 'box' ? '箱' : 'kg'; const unit = chartUnit.value === 'box' ? '箱' : 'kg';
result += `<div style="margin: 3px 0;"> result += `<div style="margin: 3px 0;">
<span style="display:inline-block;margin-right:5px;border-radius:10px;width:10px;height:10px;background-color:${param.color};"></span> <span style="display:inline-block;margin-right:5px;border-radius:10px;width:10px;height:10px;background-color:${param.color};"></span>
${seriesName}: ${value}${unit} ${seriesName}: ${value}${unit}
</div>`; </div>`;
}); });
return result; return result;
} }
}, },
legend: { legend: {
data: ['库存'], data: chartData.map(s => s.name),
top: 30 right: 10,
}, top: 30,
textStyle: {
fontSize: 12
}
},
grid: { grid: {
left: '3%', left: '3%',
right: '4%', right: '15%',
bottom: '3%', bottom: '3%',
containLabel: true containLabel: true
}, },
@ -660,29 +741,32 @@ const prepareInventoryChartData = () => {
console.log('prepareInventoryChartData 被调用'); console.log('prepareInventoryChartData 被调用');
console.log('hasHistoryData.value:', hasHistoryData.value); console.log('hasHistoryData.value:', hasHistoryData.value);
console.log('historyData.value.length:', historyData.value ? historyData.value.length : 0); console.log('historyData.value.length:', historyData.value ? historyData.value.length : 0);
console.log('hasSalesData.value:', hasSalesData.value);
console.log('salesData.value.length:', salesData.value ? salesData.value.length : 0);
const series = []; const series = [];
//
if (hasHistoryData.value && historyData.value.length > 0) { if (hasHistoryData.value && historyData.value.length > 0) {
console.log('开始处理历史数据'); console.log('开始处理库存历史数据');
console.log('第一条历史数据示例:', historyData.value[0]); console.log('第一条库存历史数据示例:', historyData.value[0]);
const historySeriesData = historyData.value.map((item, index) => { const historySeriesData = historyData.value.map((item, index) => {
console.log(`处理${index}条数据:`, item); console.log(`处理库存历史${index}条数据:`, item);
// //
const timeField = item.create_time || item.createTime || item.time || item.timestamp; const timeField = item.create_time || item.createTime || item.time || item.timestamp;
const boxCountField = item.box_count || item.boxCount || item.box || item.count || item.total_number; const boxCountField = item.box_count || item.boxCount || item.box || item.count || item.total_number;
const weightField = item.total_weight || item.totalWeight || item.weight || item.total_net_weight || item.totalGrossWeight; const weightField = item.total_weight || item.totalWeight || item.weight || item.total_net_weight || item.totalGrossWeight;
// console.log(':', { console.log('库存字段映射检查:', {
// timeField, timeField,
// boxCountField, boxCountField,
// weightField weightField
// }); });
if (!timeField) { if (!timeField) {
// console.warn(`${index}`); console.warn(`库存历史第${index}条数据缺少时间字段`);
return null; return null;
} }
@ -695,18 +779,18 @@ const prepareInventoryChartData = () => {
value = weightField || 0; value = weightField || 0;
} }
console.log(`时间戳: ${time}, 值: ${value}`); console.log(`库存时间戳: ${time}, 值: ${value}`);
if (isNaN(time) || time <= 0) { if (isNaN(time) || time <= 0) {
console.warn(`${index}条数据时间格式无效:`, timeField); console.warn(`库存历史${index}条数据时间格式无效:`, timeField);
return null; return null;
} }
return [time, value]; return [time, value];
}).filter(item => item !== null); // }).filter(item => item !== null); //
// console.log(':', historySeriesData); console.log('库存历史转换后的图表数据:', historySeriesData);
// console.log(':', historySeriesData.length); console.log('库存历史有效数据点数量:', historySeriesData.length);
if (historySeriesData.length > 0) { if (historySeriesData.length > 0) {
series.push({ series.push({
@ -728,12 +812,77 @@ const prepareInventoryChartData = () => {
]) ])
} }
}); });
console.log('成功创建图表序列'); console.log('成功创建库存图表序列');
} else {
console.warn('没有有效的库存图表数据');
}
} else {
console.warn('没有库存历史数据或库存历史数据为空');
}
//
if (hasSalesData.value && salesData.value.length > 0) {
console.log('开始处理销售数据');
console.log('第一条销售数据示例:', salesData.value[0]);
const salesSeriesData = salesData.value.map((item, index) => {
console.log(`处理销售第${index}条数据:`, item);
//
const timeField = item.date || item.create_time || item.createTime || item.time || item.timestamp;
const boxCountField = item.box_count || item.boxCount || item.box || item.count;
const weightField = item.weight || item.total_weight || item.totalWeight;
console.log('销售字段映射检查:', {
timeField,
boxCountField,
weightField
});
if (!timeField) {
console.warn(`销售第${index}条数据缺少时间字段`);
return null;
}
const time = new Date(timeField).getTime();
let value;
if (chartUnit.value === 'box') {
value = boxCountField || 0;
} else {
value = weightField || 0;
}
console.log(`销售时间戳: ${time}, 值: ${value}`);
if (isNaN(time) || time <= 0) {
console.warn(`销售第${index}条数据时间格式无效:`, timeField);
return null;
}
return [time, value];
}).filter(item => item !== null); //
console.log('销售转换后的图表数据:', salesSeriesData);
console.log('销售有效数据点数量:', salesSeriesData.length);
if (salesSeriesData.length > 0) {
series.push({
name: '销售',
type: 'bar',
data: salesSeriesData,
barWidth: 8,
itemStyle: {
color: '#F56C6C',
borderRadius: [2, 2, 0, 0]
}
});
console.log('成功创建销售图表序列');
} else { } else {
console.warn('没有有效的图表数据'); console.warn('没有有效的销售图表数据');
} }
} else { } else {
console.warn('没有历史数据或历史数据为空'); console.warn('没有销售数据或销售数据为空');
} }
console.log('最终返回的series:', series); console.log('最终返回的series:', series);

Loading…
Cancel
Save