<template>
|
<div class="app-container">
|
<!-- 搜索表单 -->
|
<div class="search_form">
|
<div class="search_left">
|
<span class="search_title">报表类型:</span>
|
<el-select v-model="searchForm.reportType"
|
style="width: 150px;"
|
placeholder="请选择"
|
@change="handleReportTypeChange">
|
<el-option label="日报"
|
value="daily" />
|
<el-option label="月报"
|
value="monthly" />
|
<el-option label="进出存报表"
|
value="inout" />
|
</el-select>
|
<span class="search_title ml10">时间范围:</span>
|
<el-date-picker v-if="searchForm.reportType === 'daily'"
|
v-model="searchForm.singleDate"
|
type="date"
|
placeholder="请选择日期"
|
format="YYYY-MM-DD"
|
value-format="YYYY-MM-DD"
|
style="width: 200px;" />
|
<el-date-picker v-else-if="searchForm.reportType === 'monthly'"
|
v-model="searchForm.monthRange"
|
type="monthrange"
|
range-separator="至"
|
start-placeholder="开始月份"
|
end-placeholder="结束月份"
|
format="YYYY-MM-DD"
|
value-format="YYYY-MM-DD"
|
style="width: 240px;" />
|
<el-date-picker v-else
|
v-model="searchForm.dateRange"
|
type="daterange"
|
range-separator="至"
|
start-placeholder="开始日期"
|
end-placeholder="结束日期"
|
format="YYYY-MM-DD"
|
value-format="YYYY-MM-DD"
|
style="width: 240px;" />
|
<el-button type="primary"
|
@click="onSearch"
|
style="margin-left: 10px">
|
查询
|
</el-button>
|
<el-button @click="handleReset">重置</el-button>
|
</div>
|
<div class="search_right">
|
<!-- <el-button type="success" @click="handleExport" icon="Download">-->
|
<!-- 导出报表-->
|
<!-- </el-button>-->
|
</div>
|
</div>
|
<!-- <!– 统计卡片 –>-->
|
<!-- <div class="stats_cards" v-if="reportData.summary">-->
|
<!-- <el-row :gutter="20">-->
|
<!-- <el-col :span="6">-->
|
<!-- <el-card class="stats_card">-->
|
<!-- <div class="stats_content">-->
|
<!-- <div class="stats_icon in">-->
|
<!-- <el-icon><TrendCharts /></el-icon>-->
|
<!-- </div>-->
|
<!-- <div class="stats_info">-->
|
<!-- <div class="stats_value">{{ reportData.summary.totalIn || 0 }}</div>-->
|
<!-- <div class="stats_label">总入库量</div>-->
|
<!-- </div>-->
|
<!-- </div>-->
|
<!-- </el-card>-->
|
<!-- </el-col>-->
|
<!-- <el-col :span="6">-->
|
<!-- <el-card class="stats_card">-->
|
<!-- <div class="stats_content">-->
|
<!-- <div class="stats_icon out">-->
|
<!-- <el-icon><TrendCharts /></el-icon>-->
|
<!-- </div>-->
|
<!-- <div class="stats_info">-->
|
<!-- <div class="stats_value">{{ reportData.summary.totalOut || 0 }}</div>-->
|
<!-- <div class="stats_label">总出库量</div>-->
|
<!-- </div>-->
|
<!-- </div>-->
|
<!-- </el-card>-->
|
<!-- </el-col>-->
|
<!-- <el-col :span="6">-->
|
<!-- <el-card class="stats_card">-->
|
<!-- <div class="stats_content">-->
|
<!-- <div class="stats_icon stock">-->
|
<!-- <el-icon><Box /></el-icon>-->
|
<!-- </div>-->
|
<!-- <div class="stats_info">-->
|
<!-- <div class="stats_value">{{ reportData.summary.currentStock || 0 }}</div>-->
|
<!-- <div class="stats_label">当前库存</div>-->
|
<!-- </div>-->
|
<!-- </div>-->
|
<!-- </el-card>-->
|
<!-- </el-col>-->
|
<!-- <el-col :span="6">-->
|
<!-- <el-card class="stats_card">-->
|
<!-- <div class="stats_content">-->
|
<!-- <div class="stats_icon turnover">-->
|
<!-- <el-icon><Refresh /></el-icon>-->
|
<!-- </div>-->
|
<!-- <div class="stats_info">-->
|
<!-- <div class="stats_value">{{ reportData.summary.turnoverRate || 0 }}%</div>-->
|
<!-- <div class="stats_label">周转率</div>-->
|
<!-- </div>-->
|
<!-- </div>-->
|
<!-- </el-card>-->
|
<!-- </el-col>-->
|
<!-- </el-row>-->
|
<!-- </div>-->
|
<!-- <!– 图表区域 –>-->
|
<!-- <div class="chart_section" v-if="reportData.chartData">-->
|
<!-- <el-row :gutter="20">-->
|
<!-- <el-col :span="12">-->
|
<!-- <el-card>-->
|
<!-- <template #header>-->
|
<!-- <span>库存趋势图</span>-->
|
<!-- </template>-->
|
<!-- <div ref="trendChart" style="height: 300px;"></div>-->
|
<!-- </el-card>-->
|
<!-- </el-col>-->
|
<!-- <el-col :span="12">-->
|
<!-- <el-card>-->
|
<!-- <template #header>-->
|
<!-- <span>进出库对比</span>-->
|
<!-- </template>-->
|
<!-- <div ref="comparisonChart" style="height: 300px;"></div>-->
|
<!-- </el-card>-->
|
<!-- </el-col>-->
|
<!-- </el-row>-->
|
<!-- </div>-->
|
<!-- 详细数据表格 -->
|
<div class="table_section">
|
<el-card>
|
<template #header>
|
<span>{{ getTableTitle() }}</span>
|
</template>
|
<el-table v-loading="tableLoading"
|
:data="reportData.tableData"
|
border
|
height="400"
|
style="width: 100%"
|
:header-cell-style="{ background: '#F0F1F5', color: '#333333' }">
|
<el-table-column align="center"
|
label="序号"
|
type="index"
|
width="60" />
|
<el-table-column label="入库时间"
|
prop="createTime"
|
width="200"
|
show-overflow-tooltip
|
v-if="searchForm.reportType !== 'inout'" />
|
<el-table-column label="入库批次"
|
prop="inboundBatches"
|
width="180"
|
show-overflow-tooltip
|
v-if="searchForm.reportType !== 'inout'" />
|
<el-table-column label="批号"
|
prop="batchNo"
|
width="180"
|
show-overflow-tooltip
|
v-if="searchForm.reportType !== 'inout'" />
|
<el-table-column label="产品大类"
|
prop="productName"
|
show-overflow-tooltip />
|
<el-table-column label="规格型号"
|
prop="model"
|
show-overflow-tooltip />
|
<el-table-column label="单位"
|
prop="unit"
|
show-overflow-tooltip />
|
<el-table-column label="入库数量"
|
prop="totalStockIn"
|
align="center"
|
v-if="searchForm.reportType === 'inout'" />
|
<el-table-column label="入库数量"
|
prop="stockInNum"
|
align="center"
|
v-else />
|
<el-table-column label="出库数量"
|
prop="totalStockOut"
|
width="100"
|
align="center"
|
v-if="searchForm.reportType === 'inout'" />
|
<el-table-column label="现在库存"
|
prop="currentStock"
|
align="center" />
|
<el-table-column label="来源"
|
prop="recordType"
|
v-if="searchForm.reportType !== 'inout'"
|
show-overflow-tooltip>
|
<template #default="scope">
|
{{ getRecordType(scope.row.recordType) }}
|
</template>
|
</el-table-column>
|
<el-table-column label="入库人"
|
prop="createBy"
|
width="80"
|
v-if="searchForm.reportType !== 'inout'"
|
show-overflow-tooltip />
|
</el-table>
|
<pagination :total="total"
|
layout="total, sizes, prev, pager, next, jumper"
|
:page="page.current"
|
:limit="page.size"
|
@pagination="paginationChange" />
|
</el-card>
|
</div>
|
</div>
|
</template>
|
|
<script setup>
|
import { ref, reactive, onMounted, nextTick, getCurrentInstance } from "vue";
|
import { ElMessage } from "element-plus";
|
import * as echarts from "echarts";
|
import pagination from "@/components/PIMTable/Pagination.vue";
|
import {
|
getStockInventoryInAndOutReportList,
|
getStockInventoryReportList,
|
} from "@/api/inventoryManagement/stockInventory.js";
|
import {
|
findAllQualifiedStockInRecordTypeOptions,
|
// findAllUnQualifiedStockInRecordTypeOptions,
|
} from "@/api/basicData/enum.js";
|
|
const { proxy } = getCurrentInstance();
|
// 响应式数据
|
const tableLoading = ref(false);
|
const trendChart = ref(null);
|
const comparisonChart = ref(null);
|
|
const searchForm = reactive({
|
reportType: "daily",
|
singleDate: "",
|
dateRange: [],
|
monthRange: [],
|
});
|
|
const reportData = ref({
|
summary: null,
|
chartData: null,
|
tableData: [],
|
});
|
|
const page = reactive({
|
current: 1,
|
size: 10,
|
});
|
|
const total = ref(0);
|
|
const stockRecordTypeOptions = ref([]);
|
|
const getRecordType = recordType => {
|
return (
|
stockRecordTypeOptions.value.find(item => item.value === recordType)
|
?.label || ""
|
);
|
};
|
|
// 获取来源类型选项
|
const fetchStockRecordTypeOptions = () => {
|
findAllQualifiedStockInRecordTypeOptions().then(res => {
|
stockRecordTypeOptions.value = res.data;
|
// findAllUnQualifiedStockInRecordTypeOptions().then(res => {
|
// stockRecordTypeOptions.value = [
|
// ...stockRecordTypeOptions.value,
|
// ...res.data,
|
// ];
|
// });
|
});
|
};
|
|
// 获取表格标题
|
const getTableTitle = () => {
|
const typeMap = {
|
daily: "日报详细数据",
|
monthly: "月报详细数据",
|
inout: "进出存报表详细数据",
|
};
|
return typeMap[searchForm.reportType] || "报表详细数据";
|
};
|
|
// 报表类型改变
|
const handleReportTypeChange = () => {
|
page.current = 1;
|
reportData.value = {
|
summary: null,
|
chartData: null,
|
tableData: [],
|
};
|
};
|
|
// 查询数据
|
const handleQuery = async () => {
|
if (!validateSearchForm()) {
|
return;
|
}
|
|
tableLoading.value = true;
|
try {
|
const baseParams = getQueryParams();
|
const params = {
|
...baseParams,
|
current: page.current,
|
size: page.size,
|
};
|
let response;
|
|
if (searchForm.reportType === "inout") {
|
response = await getStockInventoryInAndOutReportList(params);
|
} else {
|
response = await getStockInventoryReportList(params);
|
}
|
if (response.code === 200) {
|
reportData.value.tableData = response.data.records || [];
|
total.value = response.data.total || 0;
|
// reportData.value.summary = response.data.summary
|
// reportData.value.chartData = response.data.chartData
|
// nextTick(() => {
|
// initCharts()
|
// })
|
}
|
} catch (error) {
|
ElMessage.error("查询失败:" + error.message);
|
} finally {
|
tableLoading.value = false;
|
}
|
};
|
|
// 查询按钮:重置到第一页并查询
|
const onSearch = () => {
|
page.current = 1;
|
handleQuery();
|
};
|
|
// 分页变化
|
const paginationChange = obj => {
|
page.current = obj.page;
|
page.size = obj.limit;
|
handleQuery();
|
};
|
// // 生成假数据
|
// const generateMockData = () => {
|
// // 生成统计卡片假数据
|
// const summary = {
|
// totalIn: 1000,
|
// totalOut: 600,
|
// currentStock: 400,
|
// turnoverRate: 30
|
// }
|
|
// // 生成图表假数据
|
// const trendDates = ['2025-09-15', '2025-09-16', '2025-09-17', '2025-09-18', '2025-09-19']
|
// const trendValues = [300, 350, 400, 380, 420]
|
// const comparisonDates = ['2025-09-15', '2025-09-16', '2025-09-17']
|
// const inValues = [100, 150, 200]
|
// const outValues = [80, 120, 100]
|
|
// const chartData = {
|
// trendDates,
|
// trendValues,
|
// comparisonDates,
|
// inValues,
|
// outValues
|
// }
|
|
// reportData.value = {
|
// summary,
|
// chartData,
|
// tableData: []
|
// }
|
// }
|
// 验证搜索表单
|
const validateSearchForm = () => {
|
if (searchForm.reportType === "daily") {
|
if (!searchForm.singleDate) {
|
ElMessage.warning("请选择日期");
|
return false;
|
}
|
} else if (searchForm.reportType === "inout") {
|
if (!searchForm.dateRange || searchForm.dateRange.length !== 2) {
|
ElMessage.warning("请选择日期范围");
|
return false;
|
}
|
} else if (searchForm.reportType === "monthly") {
|
if (!searchForm.monthRange || searchForm.monthRange.length !== 2) {
|
ElMessage.warning("请选择月份范围");
|
return false;
|
}
|
}
|
return true;
|
};
|
|
// 获取查询参数
|
const getQueryParams = () => {
|
const params = {
|
reportType: searchForm.reportType,
|
reportDate: "",
|
startMonth: "",
|
endMonth: "",
|
startDate: "",
|
endDate: "",
|
};
|
|
if (searchForm.reportType === "daily") {
|
params.reportDate = searchForm.singleDate;
|
} else if (searchForm.reportType === "monthly") {
|
params.startMonth = searchForm.monthRange[0];
|
params.endMonth = searchForm.monthRange[1];
|
} else {
|
params.startDate = searchForm.dateRange[0];
|
params.endDate = searchForm.dateRange[1];
|
}
|
|
return params;
|
};
|
|
// 重置搜索
|
const handleReset = () => {
|
searchForm.reportType = "daily";
|
searchForm.singleDate = "";
|
searchForm.dateRange = [];
|
searchForm.monthRange = [];
|
reportData.value = {
|
summary: null,
|
chartData: null,
|
tableData: [],
|
};
|
};
|
|
// 导出报表
|
const handleExport = async () => {
|
if (!validateSearchForm()) {
|
return;
|
}
|
|
try {
|
const params = getQueryParams();
|
// const response = await exportStockReport(params)
|
proxy.download("/stockin/exportCopy", params, "库存报表.xlsx");
|
// 创建下载链接
|
// const blob = new Blob([response], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' })
|
// const url = window.URL.createObjectURL(blob)
|
// const link = document.createElement('a')
|
// link.href = url
|
// link.download = `${getTableTitle()}_${new Date().getTime()}.xlsx`
|
// document.body.appendChild(link)
|
// link.click()
|
// document.body.removeChild(link)
|
// window.URL.revokeObjectURL(url)
|
|
// ElMessage.success('导出成功')
|
} catch (error) {
|
ElMessage.error("导出失败:" + error.message);
|
}
|
};
|
|
// 初始化图表
|
const initCharts = () => {
|
if (!reportData.value.chartData) return;
|
|
initTrendChart();
|
initComparisonChart();
|
};
|
|
// 初始化趋势图
|
const initTrendChart = () => {
|
if (!trendChart.value) return;
|
|
const chart = echarts.init(trendChart.value);
|
const option = {
|
title: {
|
text: "库存变化趋势",
|
left: "center",
|
},
|
tooltip: {
|
trigger: "axis",
|
},
|
legend: {
|
data: ["库存量"],
|
top: 30,
|
},
|
xAxis: {
|
type: "category",
|
data: reportData.value.chartData.trendDates || [],
|
},
|
yAxis: {
|
type: "value",
|
},
|
series: [
|
{
|
name: "库存量",
|
type: "line",
|
data: reportData.value.chartData.trendValues || [],
|
smooth: true,
|
itemStyle: {
|
color: "#409EFF",
|
},
|
},
|
],
|
};
|
chart.setOption(option);
|
};
|
|
// 初始化对比图
|
const initComparisonChart = () => {
|
if (!comparisonChart.value) return;
|
|
const chart = echarts.init(comparisonChart.value);
|
const option = {
|
title: {
|
text: "进出库对比",
|
left: "center",
|
},
|
tooltip: {
|
trigger: "axis",
|
},
|
legend: {
|
data: ["入库", "出库"],
|
top: 30,
|
},
|
xAxis: {
|
type: "category",
|
data: reportData.value.chartData.comparisonDates || [],
|
},
|
yAxis: {
|
type: "value",
|
},
|
series: [
|
{
|
name: "入库",
|
type: "bar",
|
data: reportData.value.chartData.inValues || [],
|
itemStyle: {
|
color: "#67C23A",
|
},
|
},
|
{
|
name: "出库",
|
type: "bar",
|
data: reportData.value.chartData.outValues || [],
|
itemStyle: {
|
color: "#F56C6C",
|
},
|
},
|
],
|
};
|
chart.setOption(option);
|
};
|
|
// 组件挂载时设置默认时间
|
onMounted(() => {
|
const today = new Date();
|
searchForm.singleDate = today.toISOString().split("T")[0];
|
|
const yesterday = new Date(today.getTime() - 24 * 60 * 60 * 1000);
|
searchForm.dateRange = [
|
yesterday.toISOString().split("T")[0],
|
today.toISOString().split("T")[0],
|
];
|
|
fetchStockRecordTypeOptions();
|
// 初始化加载一次数据
|
handleQuery();
|
});
|
</script>
|
|
<style scoped>
|
.app-container {
|
padding: 20px;
|
}
|
|
.search_form {
|
display: flex;
|
justify-content: space-between;
|
align-items: center;
|
margin-bottom: 20px;
|
padding: 20px;
|
background: #fff;
|
border-radius: 4px;
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
}
|
|
.search_left {
|
display: flex;
|
align-items: center;
|
}
|
|
.search_title {
|
font-weight: 500;
|
color: #333;
|
margin-right: 8px;
|
}
|
|
.ml10 {
|
margin-left: 10px;
|
}
|
|
.stats_cards {
|
margin-bottom: 20px;
|
}
|
|
.stats_card {
|
border-radius: 8px;
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
}
|
|
.stats_content {
|
display: flex;
|
align-items: center;
|
padding: 10px 0;
|
}
|
|
.stats_icon {
|
width: 50px;
|
height: 50px;
|
border-radius: 50%;
|
display: flex;
|
align-items: center;
|
justify-content: center;
|
margin-right: 15px;
|
font-size: 24px;
|
color: #fff;
|
}
|
|
.stats_icon.in {
|
background: linear-gradient(135deg, #67c23a, #85ce61);
|
}
|
|
.stats_icon.out {
|
background: linear-gradient(135deg, #f56c6c, #f78989);
|
}
|
|
.stats_icon.stock {
|
background: linear-gradient(135deg, #409eff, #66b1ff);
|
}
|
|
.stats_icon.turnover {
|
background: linear-gradient(135deg, #e6a23c, #eebe77);
|
}
|
|
.stats_info {
|
flex: 1;
|
}
|
|
.stats_value {
|
font-size: 24px;
|
font-weight: bold;
|
color: #333;
|
line-height: 1;
|
margin-bottom: 5px;
|
}
|
|
.stats_label {
|
font-size: 14px;
|
color: #666;
|
}
|
|
.chart_section {
|
margin-bottom: 20px;
|
}
|
|
.table_section {
|
margin-bottom: 20px;
|
}
|
|
:deep(.el-card__header) {
|
background: #f8f9fa;
|
border-bottom: 1px solid #e9ecef;
|
font-weight: 500;
|
}
|
|
:deep(.el-table .el-table__header-wrapper th) {
|
background-color: #f0f1f5 !important;
|
color: #333333;
|
font-weight: 600;
|
}
|
|
:deep(.el-table .el-table__body-wrapper td) {
|
padding: 8px 0;
|
}
|
</style>
|