| 方法 | 路径 | 说明 |
|---|---|---|
| GET | /home/salesPurchaseStorageProductCount | 销售-采购-储存统计(新增日期筛选) |
| GET | /home/productCategoryDistribution | 产品大类分布(修复数据) |
请求参数(新增):
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| startDate | String | 否 | 开始日期(yyyy-MM-dd) |
| endDate | String | 否 | 结束日期(yyyy-MM-dd) |
不传日期参数时默认统计当前月 vs 上月。
响应格式变化:
- 第一个指标名称从 "销售产品数" 改为 "销售订单数"
- 数值统计口径从"销售产品记录数"改为"销售订单数(sales_ledger 表记录数)"
{
"code": 200,
"data": [
{ "name": "销售订单数", "value": "156", "rate": "12.50" },
{ "name": "采购产品数", "value": "89", "rate": "-5.30" },
{ "name": "储存产品数", "value": "234", "rate": "8.20" }
]
}
修复了小类 value/rate 数据为 0 的问题,现在返回实际的采购数据。
响应格式:json { "code": 200, "data": { "items": [ { "name": "原材料", "value": "45", "rate": "40.50", "children": [ { "name": "钢材", "value": "20", "rate": "44.44", "children": [] }, { "name": "塑料", "value": "15", "rate": "33.33", "children": [] }, { "name": "电子元件", "value": "10", "rate": "22.22", "children": [] } ] } ] } }
<div class="stat-card">
<div class="stat-label">销售订单数</div>
<div class="stat-value">{{ salesOrderCount.value }}</div>
<div class="stat-rate" :class="{ up: salesOrderCount.rate > 0, down: salesOrderCount.rate < 0 }">
环比 {{ salesOrderCount.rate }}%
</div>
</div>
在页面左上角新增日期范围下拉筛选。
<el-date-picker
v-model="dateRange"
type="daterange"
range-separator="至"
start-placeholder="开始日期"
end-placeholder="结束日期"
value-format="yyyy-MM-dd"
@change="handleDateChange"
style="margin-right: 16px;" />
data() {
return {
dateRange: [],
salesOrderCount: { value: 0, rate: 0 },
purchaseProductCount: { value: 0, rate: 0 },
storageProductCount: { value: 0, rate: 0 },
productCategoryData: [],
}
}
async loadSalesPurchaseStorageCount() {
const params = {};
if (this.dateRange && this.dateRange.length === 2) {
params.startDate = this.dateRange[0];
params.endDate = this.dateRange[1];
}
const res = await this.$http.get('/home/salesPurchaseStorageProductCount', { params });
const data = res.data || [];
this.salesOrderCount = this.extractStatData(data[0]);
this.purchaseProductCount = this.extractStatData(data[1]);
this.storageProductCount = this.extractStatData(data[2]);
},
extractStatData(item) {
return item ? {
value: parseInt(item.value) || 0,
rate: parseFloat(item.rate) || 0,
} : { value: 0, rate: 0 };
},
handleDateChange(val) {
this.loadSalesPurchaseStorageCount();
},
async loadProductCategoryDistribution() {
const res = await this.$http.get('/home/productCategoryDistribution');
this.productCategoryData = res.data.items || [];
this.renderCategoryChart();
},
renderCategoryChart() {
const chart = this.$echarts.init(this.$refs.categoryChart);
const seriesData = [];
const legendData = [];
this.productCategoryData.forEach(major => {
legendData.push(major.name);
seriesData.push({
name: major.name,
value: parseInt(major.value) || 0,
children: (major.children || []).map(child => ({
name: child.name,
value: parseInt(child.value) || 0,
}))
});
});
chart.setOption({
tooltip: { trigger: 'item' },
legend: { data: legendData, orient: 'vertical', right: 10, top: 20 },
series: [{
type: 'sunburst',
data: seriesData,
radius: [0, '90%'],
label: { rotate: 'radial' }
}]
});
},