| | |
| | | <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 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-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>--> |
| | | <!-- <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="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="240" |
| | | 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 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" |
| | | /> |
| | | <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"; |
| | | 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 { proxy } = getCurrentInstance() |
| | | // 响应式数据 |
| | | const tableLoading = ref(false) |
| | | const trendChart = ref(null) |
| | | const comparisonChart = ref(null) |
| | | const searchForm = reactive({ |
| | | reportType: "daily", |
| | | singleDate: "", |
| | | dateRange: [], |
| | | monthRange: [], |
| | | }); |
| | | |
| | | 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 = { |
| | | const reportData = ref({ |
| | | summary: null, |
| | | chartData: null, |
| | | tableData: [] |
| | | } |
| | | } |
| | | tableData: [], |
| | | }); |
| | | |
| | | // 查询数据 |
| | | const handleQuery = async () => { |
| | | if (!validateSearchForm()) { |
| | | return |
| | | } |
| | | |
| | | tableLoading.value = true |
| | | try { |
| | | const baseParams = getQueryParams() |
| | | 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 = { |
| | | ...baseParams, |
| | | current: page.current, |
| | | size: page.size, |
| | | } |
| | | let response |
| | | reportType: searchForm.reportType, |
| | | reportDate: "", |
| | | startMonth: "", |
| | | endMonth: "", |
| | | startDate: "", |
| | | endDate: "", |
| | | }; |
| | | |
| | | if (searchForm.reportType === 'inout') { |
| | | response = await getStockInventoryInAndOutReportList(params) |
| | | if (searchForm.reportType === "daily") { |
| | | params.reportDate = searchForm.singleDate; |
| | | } else if (searchForm.reportType === "monthly") { |
| | | params.startMonth = searchForm.monthRange[0]; |
| | | params.endMonth = searchForm.monthRange[1]; |
| | | } else { |
| | | response = await getStockInventoryReportList(params) |
| | | params.startDate = searchForm.dateRange[0]; |
| | | params.endDate = searchForm.dateRange[1]; |
| | | } |
| | | 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() |
| | | // }) |
| | | |
| | | |
| | | 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; |
| | | } |
| | | } catch (error) { |
| | | ElMessage.error('查询失败:' + error.message) |
| | | } finally { |
| | | tableLoading.value = false |
| | | } |
| | | } |
| | | |
| | | // 查询按钮:重置到第一页并查询 |
| | | const onSearch = () => { |
| | | page.current = 1 |
| | | handleQuery() |
| | | } |
| | | 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) |
| | | |
| | | // 分页变化 |
| | | 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 |
| | | // ElMessage.success('导出成功') |
| | | } catch (error) { |
| | | ElMessage.error("导出失败:" + error.message); |
| | | } |
| | | } 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 initCharts = () => { |
| | | if (!reportData.value.chartData) return; |
| | | |
| | | // 重置搜索 |
| | | const handleReset = () => { |
| | | searchForm.reportType = 'daily' |
| | | searchForm.singleDate = '' |
| | | searchForm.dateRange = [] |
| | | searchForm.monthRange = [] |
| | | reportData.value = { |
| | | summary: null, |
| | | chartData: null, |
| | | tableData: [] |
| | | } |
| | | } |
| | | initTrendChart(); |
| | | initComparisonChart(); |
| | | }; |
| | | |
| | | // 导出报表 |
| | | 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 initTrendChart = () => { |
| | | if (!trendChart.value) return; |
| | | |
| | | // 初始化图表 |
| | | 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' |
| | | } |
| | | const chart = echarts.init(trendChart.value); |
| | | const option = { |
| | | title: { |
| | | text: "库存变化趋势", |
| | | left: "center", |
| | | }, |
| | | { |
| | | name: '出库', |
| | | type: 'bar', |
| | | data: reportData.value.chartData.outValues || [], |
| | | itemStyle: { |
| | | color: '#F56C6C' |
| | | } |
| | | } |
| | | ] |
| | | } |
| | | chart.setOption(option) |
| | | } |
| | | 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); |
| | | }; |
| | | |
| | | // 组件挂载时设置默认时间 |
| | | 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] |
| | | ] |
| | | // 初始化对比图 |
| | | const initComparisonChart = () => { |
| | | if (!comparisonChart.value) return; |
| | | |
| | | fetchStockRecordTypeOptions() |
| | | // 初始化加载一次数据 |
| | | handleQuery() |
| | | }) |
| | | 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; |
| | | } |
| | | .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_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_left { |
| | | display: flex; |
| | | align-items: center; |
| | | } |
| | | |
| | | .search_title { |
| | | font-weight: 500; |
| | | color: #333; |
| | | margin-right: 8px; |
| | | } |
| | | .search_title { |
| | | font-weight: 500; |
| | | color: #333; |
| | | margin-right: 8px; |
| | | } |
| | | |
| | | .ml10 { |
| | | margin-left: 10px; |
| | | } |
| | | .ml10 { |
| | | margin-left: 10px; |
| | | } |
| | | |
| | | .stats_cards { |
| | | margin-bottom: 20px; |
| | | } |
| | | .stats_cards { |
| | | margin-bottom: 20px; |
| | | } |
| | | |
| | | .stats_card { |
| | | border-radius: 8px; |
| | | box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); |
| | | } |
| | | .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_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 { |
| | | 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.in { |
| | | background: linear-gradient(135deg, #67c23a, #85ce61); |
| | | } |
| | | |
| | | .stats_icon.out { |
| | | background: linear-gradient(135deg, #F56C6C, #F78989); |
| | | } |
| | | .stats_icon.out { |
| | | background: linear-gradient(135deg, #f56c6c, #f78989); |
| | | } |
| | | |
| | | .stats_icon.stock { |
| | | background: linear-gradient(135deg, #409EFF, #66B1FF); |
| | | } |
| | | .stats_icon.stock { |
| | | background: linear-gradient(135deg, #409eff, #66b1ff); |
| | | } |
| | | |
| | | .stats_icon.turnover { |
| | | background: linear-gradient(135deg, #E6A23C, #EEBE77); |
| | | } |
| | | .stats_icon.turnover { |
| | | background: linear-gradient(135deg, #e6a23c, #eebe77); |
| | | } |
| | | |
| | | .stats_info { |
| | | flex: 1; |
| | | } |
| | | .stats_info { |
| | | flex: 1; |
| | | } |
| | | |
| | | .stats_value { |
| | | font-size: 24px; |
| | | font-weight: bold; |
| | | color: #333; |
| | | line-height: 1; |
| | | margin-bottom: 5px; |
| | | } |
| | | .stats_value { |
| | | font-size: 24px; |
| | | font-weight: bold; |
| | | color: #333; |
| | | line-height: 1; |
| | | margin-bottom: 5px; |
| | | } |
| | | |
| | | .stats_label { |
| | | font-size: 14px; |
| | | color: #666; |
| | | } |
| | | .stats_label { |
| | | font-size: 14px; |
| | | color: #666; |
| | | } |
| | | |
| | | .chart_section { |
| | | margin-bottom: 20px; |
| | | } |
| | | .chart_section { |
| | | margin-bottom: 20px; |
| | | } |
| | | |
| | | .table_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-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__header-wrapper th) { |
| | | background-color: #f0f1f5 !important; |
| | | color: #333333; |
| | | font-weight: 600; |
| | | } |
| | | |
| | | :deep(.el-table .el-table__body-wrapper td) { |
| | | padding: 8px 0; |
| | | } |
| | | :deep(.el-table .el-table__body-wrapper td) { |
| | | padding: 8px 0; |
| | | } |
| | | </style> |