<template>
|
<div class="inventory-statistics">
|
<!-- 筛选表单 -->
|
<div class="filter-form">
|
<el-form :model="filterForm" inline>
|
<!-- <el-form-item label="时间范围">-->
|
<!-- <el-date-picker-->
|
<!-- v-model="filterForm.dateRange"-->
|
<!-- type="daterange"-->
|
<!-- range-separator="至"-->
|
<!-- start-placeholder="开始日期"-->
|
<!-- end-placeholder="结束日期"-->
|
<!-- />-->
|
<!-- </el-form-item>-->
|
<!-- <el-form-item label="供应商名称">-->
|
<!-- <el-input v-model="filterForm.supplierName" style="width: 240px" placeholder="请输入" clearable prefix-icon="Search" />-->
|
<!-- </el-form-item>-->
|
<!-- <el-form-item label="产品名称">-->
|
<!-- <el-input v-model="filterForm.productCategory" style="width: 240px" placeholder="请输入" clearable prefix-icon="Search" />-->
|
<!-- </el-form-item>-->
|
<el-form-item>
|
<el-button type="primary" @click="handleSearch">查询</el-button>
|
<!-- <el-button @click="handleReset">重置</el-button>-->
|
<!-- <el-button type="success" @click="handleExport">导出</el-button>-->
|
</el-form-item>
|
</el-form>
|
</div>
|
|
<!-- 统计汇总卡片 -->
|
<div class="summary-cards">
|
<el-row :gutter="20">
|
<el-col :span="6">
|
<el-card class="summary-card">
|
<div class="summary-item">
|
<p class="summary-title">总库存数量</p>
|
<p class="summary-value">{{ summaryData.totalInventoryCount }}</p>
|
</div>
|
</el-card>
|
</el-col>
|
<el-col :span="6">
|
<el-card class="summary-card">
|
<div class="summary-item">
|
<p class="summary-title">总库存金额</p>
|
<p class="summary-value">¥{{ summaryData.totalInventoryValue }}</p>
|
</div>
|
</el-card>
|
</el-col>
|
<el-col :span="6">
|
<el-card class="summary-card">
|
<div class="summary-item">
|
<p class="summary-title">库存变动数量</p>
|
<p class="summary-value">{{ summaryData.inventoryChangeCount }}</p>
|
</div>
|
</el-card>
|
</el-col>
|
<el-col :span="6">
|
<el-card class="summary-card">
|
<div class="summary-item">
|
<p class="summary-title">库存变动金额</p>
|
<p class="summary-value">¥{{ summaryData.inventoryChangeValue }}</p>
|
</div>
|
</el-card>
|
</el-col>
|
</el-row>
|
</div>
|
|
<!-- 图表区域 -->
|
<div class="chart-section">
|
<el-row :gutter="20">
|
<el-col :span="12">
|
<el-card class="chart-card">
|
<template #header>
|
<div class="card-header">
|
<span>库存分类占比</span>
|
</div>
|
</template>
|
<div id="category-pie-chart" style="height: 400px;"></div>
|
</el-card>
|
</el-col>
|
<el-col :span="12">
|
<el-card class="chart-card">
|
<template #header>
|
<div class="card-header">
|
<span>库存金额趋势</span>
|
</div>
|
</template>
|
<div id="amount-trend-chart" style="height: 400px;"></div>
|
</el-card>
|
</el-col>
|
</el-row>
|
</div>
|
|
<!-- 数据表格 -->
|
<div class="table_list">
|
<el-table
|
:data="tableData"
|
v-loading="loading"
|
border
|
style="width: 100%"
|
:header-cell-style="{ background: '#f5f7fa', color: '#606266' }"
|
>
|
<el-table-column align="center" type="selection" width="55" />
|
<el-table-column align="center" label="序号" type="index" width="60" />
|
<el-table-column label="供应商名称" prop="supplierName" width="240" show-overflow-tooltip />
|
<el-table-column label="产品" prop="productCategory" min-width="100" show-overflow-tooltip />
|
<el-table-column label="规格型号" prop="specificationModel" min-width="200" show-overflow-tooltip />
|
<el-table-column label="单位" prop="unit" width="70" show-overflow-tooltip />
|
<el-table-column label="入库数量" prop="inboundNum" width="90" show-overflow-tooltip />
|
<el-table-column label="库存数量" prop="inboundNum0" width="90" show-overflow-tooltip />
|
<el-table-column label="含税单价" prop="taxInclusiveUnitPrice" width="100" show-overflow-tooltip />
|
<el-table-column label="含税总价" prop="taxInclusiveTotalPrice" width="100" show-overflow-tooltip />
|
<el-table-column label="税率(%)" prop="taxRate" width="80" show-overflow-tooltip />
|
<el-table-column label="不含税总价" prop="taxExclusiveTotalPrice" width="100" show-overflow-tooltip />
|
<el-table-column label="入库人" prop="createBy" width="100" show-overflow-tooltip />
|
</el-table>
|
<pagination v-show="total > 0" :total="total" layout="total, sizes, prev, pager, next, jumper" :page="page.current" :limit="page.size" @pagination="paginationChange" />
|
</div>
|
</div>
|
</template>
|
|
<script setup>
|
import { ref, reactive, onMounted, nextTick } from 'vue'
|
import * as echarts from 'echarts'
|
import {getStockInChartData, getStockInPage} from "@/api/inventoryManagement/stockIn.js";
|
|
// 状态变量
|
const loading = ref(false)
|
const total = ref(0)
|
const tableData = ref([])
|
const summaryData = ref({})
|
const page = reactive({
|
current: 1,
|
size: 100,
|
})
|
|
// 图表实例
|
const categoryPieChart = ref(null)
|
const amountTrendChart = ref(null)
|
|
// 筛选表单
|
const filterForm = reactive({
|
dateRange: [],
|
supplierName: '',
|
productCategory: ''
|
})
|
|
const paginationChange = (obj) => {
|
page.current = obj.page;
|
page.size = obj.limit;
|
loadData()
|
}
|
|
// 初始化数据
|
onMounted(() => {
|
loadSummaryData()
|
loadData()
|
})
|
|
// 加载统计汇总数据
|
const loadSummaryData = () => {
|
getStockInChartData().then(res => {
|
summaryData.value = res.data
|
})
|
}
|
|
// 加载库存数据
|
const loadData = () => {
|
loading.value = true
|
getStockInPage({ ...filterForm, ...page }).then(res => {
|
loading.value = false
|
tableData.value = res.data.records
|
total.value = res.data.total
|
console.log('res', res.data.records)
|
|
// 数据加载完成后渲染图表
|
nextTick(() => {
|
renderCategoryPieChart()
|
renderAmountTrendChart()
|
})
|
}).catch(() => {
|
loading.value = false
|
})
|
}
|
|
// 渲染分类占比饼图
|
const renderCategoryPieChart = () => {
|
if (!categoryPieChart.value) {
|
categoryPieChart.value = echarts.init(document.getElementById('category-pie-chart'))
|
}
|
// 根据 tableData 按 productCategory 分类并计算 inboundNum0 数量总和
|
const categoryMap = tableData.value.reduce((acc, cur) => {
|
acc[cur.productCategory] = (acc[cur.productCategory] || 0) + cur.inboundNum0
|
return acc
|
}, {})
|
|
// 将分类结果转换为 ECharts 饼图所需的数据格式
|
const categoryData = Object.entries(categoryMap).map(([name, value]) => ({
|
name: name,
|
value: value
|
}))
|
const option = {
|
title: {
|
text: '库存分类占比',
|
left: 'center'
|
},
|
tooltip: {
|
trigger: 'item',
|
formatter: '{a} <br/>{b}: {c} ({d}%)'
|
},
|
legend: {
|
orient: 'vertical',
|
left: 'left'
|
},
|
series: [
|
{
|
name: '库存分类',
|
type: 'pie',
|
radius: ['40%', '70%'],
|
avoidLabelOverlap: false,
|
itemStyle: {
|
borderRadius: 10,
|
borderColor: '#fff',
|
borderWidth: 2
|
},
|
label: {
|
show: true,
|
formatter: '{b}: {d}%'
|
},
|
emphasis: {
|
label: {
|
show: true,
|
fontSize: '16',
|
fontWeight: 'bold'
|
}
|
},
|
data: categoryData
|
}
|
]
|
}
|
|
categoryPieChart.value.setOption(option)
|
}
|
// 渲染金额趋势折线图
|
const renderAmountTrendChart = () => {
|
if (!amountTrendChart.value) {
|
amountTrendChart.value = echarts.init(document.getElementById('amount-trend-chart'))
|
}
|
// 按月份分组并计算taxInclusiveTotalPrice总和
|
const monthlyAmounts = tableData.value.reduce((acc, cur) => {
|
const date = new Date(cur.createTime);
|
const month = date.getMonth() + 1;
|
|
// 确保month在1-12范围内
|
if (month >= 1 && month <= 12) {
|
acc[month] = (acc[month] || 0) + cur.taxInclusiveTotalPrice;
|
}
|
return acc;
|
}, {});
|
|
// 生成12个月的数据,缺失月份用0代替
|
const amounts = [];
|
for (let i = 1; i <= 12; i++) {
|
amounts.push(monthlyAmounts[i] || 0);
|
}
|
const dates = ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月']
|
|
const option = {
|
title: {
|
text: '库存金额趋势',
|
left: 'center'
|
},
|
tooltip: {
|
trigger: 'axis',
|
formatter: '{b}: ¥{c}'
|
},
|
xAxis: {
|
type: 'category',
|
data: dates
|
},
|
yAxis: {
|
type: 'value',
|
axisLabel: {
|
formatter: '¥{value}'
|
}
|
},
|
series: [
|
{
|
name: '库存金额',
|
type: 'line',
|
data: amounts,
|
smooth: true,
|
areaStyle: {}
|
}
|
]
|
}
|
|
amountTrendChart.value.setOption(option)
|
}
|
|
// 查询操作
|
const handleSearch = () => {
|
loadData()
|
}
|
|
// 重置操作
|
const handleReset = () => {
|
filterForm.dateRange = []
|
filterForm.supplierName = ''
|
filterForm.productCategory = ''
|
loadData()
|
}
|
|
// 导出操作
|
const handleExport = () => {
|
console.log('导出数据')
|
}
|
|
// 窗口大小改变时,重新调整图表大小
|
window.addEventListener('resize', () => {
|
if (categoryPieChart.value) categoryPieChart.value.resize()
|
if (amountTrendChart.value) amountTrendChart.value.resize()
|
})
|
</script>
|
|
<style scoped>
|
.inventory-statistics {
|
padding: 20px;
|
}
|
|
.filter-form {
|
margin-bottom: 20px;
|
}
|
|
.summary-cards {
|
margin-bottom: 20px;
|
}
|
|
.summary-card {
|
text-align: center;
|
height: 100px;
|
display: flex;
|
align-items: center;
|
justify-content: center;
|
}
|
|
.summary-item {
|
width: 100%;
|
}
|
|
.summary-title {
|
font-size: 14px;
|
color: #606266;
|
margin-bottom: 5px;
|
}
|
|
.summary-value {
|
font-size: 24px;
|
font-weight: bold;
|
color: #303133;
|
}
|
|
.summary-value.warning {
|
color: #e6a23c;
|
}
|
|
.summary-value.danger {
|
color: #f56c6c;
|
}
|
|
.chart-section {
|
margin-bottom: 20px;
|
}
|
|
.chart-card {
|
height: 460px;
|
}
|
|
.card-header {
|
font-weight: bold;
|
}
|
|
.table_list {
|
margin-top: 20px;
|
}
|
|
.pagination {
|
text-align: right;
|
margin-top: 20px;
|
}
|
</style>
|