部门模块功能开发

This commit is contained in:
lizhenhua 2026-01-12 17:52:09 +08:00
parent 5c2b4c1bc3
commit 1b98e2da99
2 changed files with 1622 additions and 0 deletions

View File

@ -0,0 +1,822 @@
<template>
<div class="app-container">
<!-- 查询表单部分保持不变 -->
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="90px">
<!-- 库存日期 -->
<el-form-item label="库存日期">
<el-date-picker
v-model="dateRange"
type="daterange"
align="right"
unlink-panels
range-separator="至"
start-placeholder="开始日期"
end-placeholder="结束日期"
format="yyyy-MM-dd"
value-format="yyyy-MM-dd"
style="width: 240px"
:picker-options="pickerOptions">
</el-date-picker>
</el-form-item>
<!-- 货品类别 - 级联多选 -->
<el-form-item label="货品类别">
<el-cascader
v-model="selectedCategories"
:options="goodsCategoryOptions"
:show-all-levels="false"
:props="categoryProps"
clearable
filterable
multiple
collapse-tags
placeholder="请选择货品类别"
style="width: 200px;"
@change="handleCategoryChange">
</el-cascader>
</el-form-item>
<!-- 所属区域 -->
<el-form-item label="所属区域">
<el-cascader
v-model="selectedOrg"
:options="orgOptions"
:show-all-levels="false"
clearable
filterable
placeholder="请选择所属区域"
:props="{
checkStrictly: true,
expandTrigger: 'hover',
value: 'orgId',
label: 'orgName',
children: 'children'
}"
style="width: 200px;"
@change="handleAreaChange">
</el-cascader>
</el-form-item>
<!-- 货品仓库 -->
<el-form-item label="货品仓库" prop="warehouseId">
<el-select
v-model="queryParams.warehouseIdList"
multiple
placeholder="请选择货品仓库"
clearable
style="width: 200px"
@change="handleWarehouseChange">
<el-option
v-for="item in wareHouseOptions"
:key="item.warehouseId"
:label="item.warehouseName"
:value="item.warehouseId">
</el-option>
</el-select>
</el-form-item>
<!-- 货品名称 -->
<el-form-item label="货品名称" prop="goodsName">
<el-input
v-model="queryParams.materialName"
placeholder="请输入货品名称"
maxlength="100"
clearable
style="width: 200px"/>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<!-- 操作按钮栏 -->
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button
type="warning"
plain
icon="el-icon-download"
size="mini"
@click="handleExport"
>导出</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="info"
plain
icon="el-icon-printer"
size="mini"
@click="handlePrint"
>打印</el-button>
</el-col>
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
<!-- 数据表格 - 只修改字段名称以匹配后端实体 -->
<el-table
v-loading="loading"
:data="tableListData"
border
show-summary
:summary-method="getSummaries">
<el-table-column label="序号" align="center" width="60" type="index">
<template slot-scope="scope">
<span>{{(queryParams.pageNum - 1) * queryParams.pageSize + scope.$index + 1}}</span>
</template>
</el-table-column>
<!-- 货品编码 -->
<el-table-column label="货品编码" align="center" prop="materialCode" width="120" :show-overflow-tooltip="true"/>
<!-- 货品名称 -->
<el-table-column label="货品名称" align="center" prop="materialName" width="150" :show-overflow-tooltip="true"/>
<!-- 货品类别 -->
<el-table-column label="货品类别" align="center" prop="categoryName" width="120" :show-overflow-tooltip="true"/>
<!-- 计量单位 -->
<el-table-column label="计量单位" align="center" prop="unitName" width="100"/>
<!-- 货品规格 -->
<el-table-column label="货品规格" align="center" prop="size" width="120" :show-overflow-tooltip="true"/>
<!-- 所属区域 -->
<el-table-column label="所属区域" align="center" prop="areaName" width="120" :show-overflow-tooltip="true"/>
<!-- 所属仓库 -->
<el-table-column label="所属仓库" align="center" prop="warehouseName" width="120" :show-overflow-tooltip="true"/>
<!-- 入库数量 -->
<el-table-column label="入库数量" align="center" prop="intoTotalNum" width="100">
<template slot-scope="scope">
<span>{{ formatNumber(scope.row.intoTotalNum) }}</span>
</template>
</el-table-column>
<!-- 入库金额() -->
<el-table-column label="入库金额(元)" align="center" prop="intoTotalAmount" width="120">
<template slot-scope="scope">
<span>{{ formatMoney((scope.row.intoTotalAmount || 0) / 100) }}</span>
</template>
</el-table-column>
<!-- 入库总数量 -->
<el-table-column label="入库总数量" align="center" prop="intoTotalNum" width="120">
<template slot-scope="scope">
<span>{{ formatNumber(scope.row.intoTotalNum) }}</span>
</template>
</el-table-column>
<!-- 入库总金额() -->
<el-table-column label="入库总金额(元)" align="center" prop="intoTotalAmount" width="130">
<template slot-scope="scope">
<span>{{ formatMoney((scope.row.intoTotalAmount || 0) / 100) }}</span>
</template>
</el-table-column>
<!-- 出库数量 -->
<el-table-column label="出库数量" align="center" prop="outTotalNum" width="100">
<template slot-scope="scope">
<span>{{ formatNumber(scope.row.outTotalNum) }}</span>
</template>
</el-table-column>
<!-- 出库金额() -->
<el-table-column label="出库金额(元)" align="center" prop="outTotalAmount" width="120">
<template slot-scope="scope">
<span>{{ formatMoney((scope.row.outTotalAmount || 0) / 100) }}</span>
</template>
</el-table-column>
<!-- 出库总数量 -->
<el-table-column label="出库总数量" align="center" prop="outTotalNum" width="120">
<template slot-scope="scope">
<span>{{ formatNumber(scope.row.outTotalNum) }}</span>
</template>
</el-table-column>
<!-- 出库总金额() -->
<el-table-column label="出库总金额(元)" align="center" prop="outTotalAmount" width="130">
<template slot-scope="scope">
<span>{{ formatMoney((scope.row.outTotalAmount || 0) / 100) }}</span>
</template>
</el-table-column>
</el-table>
<!-- 分页组件 -->
<pagination
v-show="total>0"
:total="total"
:page.sync="queryParams.pageNum"
:limit.sync="queryParams.pageSize"
@pagination="getList"
/>
</div>
</template>
<script>
// API
import {getTreeArea} from "@/api/canteen/canteenRecord";
// API
import {
listInventoryIntoDetail,
exportInventoryIntoDetail,
getWarehouseList,
getGoodsCategoryDict
} from "@/api/report/inventoryhz";
export default {
name: "InventoryIntoDetail",
dicts: [],
data() {
return {
//
summaryData: null,
//
orgOptions: [],
selectedOrg: [], //
//
goodsCategoryOptions: [], //
selectedCategories: [], //
categoryProps: {
expandTrigger: 'hover',
value: 'id',
label: 'dictLabel',
children: 'children',
emitPath: true,
multiple: true
},
//
wareHouseOptions: [],
//
loading: true,
//
showSearch: true,
//
total: 0,
//
tableListData: [],
//
queryParams: {
pageNum: 1,
pageSize: 10,
recordId: null, //
categoryIdList: [], // ID
warehouseIdList: [], // ID
goodsName: null, //
areaIdList: [], // ID
startDate: null, //
endDate: null //
},
//
dateRange: this.defaultDateRange(),
//
pickerOptions: {
shortcuts: [{
text: '最近一周',
onClick: (picker) => {
const end = new Date();
const start = new Date();
start.setTime(start.getTime() - 3600 * 1000 * 24 * 6);
picker.$emit('pick', [this.formatDate(start), this.formatDate(end)]);
}
}, {
text: '最近一个月',
onClick: (picker) => {
const end = new Date();
const start = new Date();
start.setTime(start.getTime() - 3600 * 1000 * 24 * 30);
picker.$emit('pick', [this.formatDate(start), this.formatDate(end)]);
}
}, {
text: '最近三个月',
onClick: (picker) => {
const end = new Date();
const start = new Date();
start.setTime(start.getTime() - 3600 * 1000 * 24 * 91);
picker.$emit('pick', [this.formatDate(start), this.formatDate(end)]);
}
}]
}
};
},
created() {
//
this.getTree(); //
this.getWareHouseData(); //
this.getGoodsCategoryData(); //
this.getList(); //
},
methods: {
/**
* 自定义合计计算方法
*/
getSummaries(param) {
const { columns, data } = param;
const sums = [];
columns.forEach((column, index) => {
if (index === 0) {
// ""
sums[index] = '合计';
return;
}
//
const columnProp = column.property;
if (this.summaryData) {
switch(columnProp) {
case 'intoTotalNum':
sums[index] = this.formatNumber(this.summaryData.intoTotalNum || 0);
break;
case 'intoTotalAmount':
sums[index] = this.formatMoney((this.summaryData.intoTotalAmount || 0) / 100);
break;
case 'outTotalNum':
sums[index] = this.formatNumber(this.summaryData.outTotalNum || 0);
break;
case 'outTotalAmount':
sums[index] = this.formatMoney((this.summaryData.outTotalAmount || 0) / 100);
break;
default:
//
sums[index] = '';
break;
}
} else {
sums[index] = '';
}
});
return sums;
},
//
getGoodsCategoryData() {
getGoodsCategoryDict().then((response) => {
const data = response.data || response || [];
console.log('获取到的货品类别数据:', data);
//
if (data.length > 0 && !data[0].children) {
// 使
this.goodsCategoryOptions = this.buildCategoryTree(data);
} else {
// 使
this.goodsCategoryOptions = data;
}
console.log('转换后的货品类别树:', this.goodsCategoryOptions);
}).catch(error => {
console.error('获取货品类别失败:', error);
this.goodsCategoryOptions = [];
});
},
buildCategoryTree(list) {
//
const tree = [];
// 1.
const materialRoot = {
id: 25595457052610560,
dictLabel: "原料",
parentId: -1,
children: []
};
// 2.
const goodsRoot = {
id: 65595542415085568,
dictLabel: "商品",
parentId: -1,
children: []
};
// parent_id
const map = {};
list.forEach(item => {
if (!map[item.id]) {
map[item.id] = { ...item, children: [] };
}
});
//
list.forEach(item => {
if (item.parentId === 25595457052610560) {
const child = { ...item, children: [] };
materialRoot.children.push(child);
map[item.id] = child;
} else if (item.parentId === 65595542415085568) {
const child = { ...item, children: [] };
goodsRoot.children.push(child);
map[item.id] = child;
} else if (item.parentId !== -1 && map[item.parentId]) {
const child = { ...item, children: [] };
if (!map[item.parentId].children) {
map[item.parentId].children = [];
}
map[item.parentId].children.push(child);
map[item.id] = child;
}
});
tree.push(materialRoot, goodsRoot);
return tree;
},
handleCategoryChange(values) {
if (!values || values.length === 0) {
this.queryParams.categoryIdList = [];
return;
}
let allCategoryIds = [];
values.forEach(path => {
const selectedId = path[path.length - 1];
const node = this.findCategoryNodeById(selectedId, this.goodsCategoryOptions);
if (node) {
allCategoryIds.push(...this.getAllChildCategoryIds(node));
}
});
this.queryParams.categoryIdList = Array.from(new Set(allCategoryIds));
console.log("最终传给后台的 categoryIdList =", this.queryParams.categoryIdList);
},
findCategoryNodeById(id, options) {
for (const node of options) {
if (node.id === id) {
return node;
}
if (node.children && node.children.length > 0) {
const found = this.findCategoryNodeById(id, node.children);
if (found) return found;
}
}
return null;
},
getAllChildCategoryIds(node) {
if (!node) return [];
let ids = [node.id];
if (node.children && node.children.length > 0) {
node.children.forEach(child => {
ids = ids.concat(this.getAllChildCategoryIds(child));
});
}
return ids;
},
getSelectedOrgIds() {
if (!this.selectedOrg || this.selectedOrg.length === 0) return [];
const lastValue = this.selectedOrg[this.selectedOrg.length - 1];
//
let stack = [...this.orgOptions];
let node = null;
for (let val of this.selectedOrg) {
node = stack.find(item => item.orgId === val);
if (!node) break;
stack = node.children || [];
}
if (node) {
return this.getAllChildIds(node, this.orgOptions);
}
return [lastValue];
},
getAllChildIds(node, options) {
let ids = [node.orgId]; //
if (node.children && node.children.length > 0) {
node.children.forEach(child => {
ids = ids.concat(this.getAllChildIds(child, options)); //
});
}
return ids;
},
getTree() {
getTreeArea().then(res => {
this.orgOptions = res || [];
});
},
handleAreaChange() {
//
this.queryParams.warehouseIdList = [];
this.getWareHouseData();
},
handleWarehouseChange() {
//
},
getWareHouseData() {
const areaIdList = this.getSelectedOrgIds();
console.log("选中的 orgId 列表:", areaIdList, Array.isArray(areaIdList));
if (!areaIdList || !areaIdList.length) {
this.wareHouseOptions = [];
return;
}
getWarehouseList({
areaIdList: areaIdList.join(',')
}).then(res => {
this.wareHouseOptions = res.data || [];
});
},
handleQuery() {
this.queryParams.pageNum = 1;
this.getList();
},
resetQuery() {
this.dateRange = this.defaultDateRange();
this.selectedOrg = [];
this.selectedCategories = [];
this.summaryData = null;
this.queryParams = {
pageNum: 1,
pageSize: 10,
recordId: null,
categoryIdList: [],
warehouseIdList: [],
goodsName: null,
areaIdList: [],
startDate: null,
endDate: null
};
this.resetForm("queryForm");
this.getWareHouseData();
this.handleQuery();
},
getList() {
this.loading = true;
// ID
this.queryParams.areaIdList = this.getSelectedOrgIds();
//
if (this.dateRange && this.dateRange.length === 2) {
this.queryParams.startDate = this.dateRange[0];
this.queryParams.endDate = this.dateRange[1];
} else {
this.queryParams.startDate = null;
this.queryParams.endDate = null;
}
// API
listInventoryIntoDetail(this.queryParams).then(response => {
const data = response.data || response;
this.tableListData = data.rows || [];
this.total = Number(data.total) || 0;
this.summaryData = data.summary || null;
console.log('合计数据:', this.summaryData);
this.loading = false;
}).catch(() => {
this.loading = false;
});
},
handleExport() {
//
let startDate = '';
let endDate = '';
if (this.dateRange && this.dateRange.length === 2) {
const start = this.dateRange[0];
const end = this.dateRange[1];
startDate = start + ' 00:00:00';
endDate = end + ' 23:59:59';
}
//
let param = {
pageNum: this.queryParams.pageNum,
pageSize: this.queryParams.pageSize,
recordId: this.queryParams.recordId,
categoryIdList: this.queryParams.categoryIdList,
warehouseIdList: this.queryParams.warehouseIdList,
materialName: this.queryParams.materialName,
areaIdList: this.getSelectedOrgIds(),
startDate: startDate,
endDate: endDate
};
// 使download
this.$modal.confirm('是否确认导出货品汇总明细数据项?').then(() => {
this.loading = true;
// 使download
this.download(
'/smart-canteen/drp/inventoryIntohz/goods/summary/export',
param,
`货品库存明细_${new Date().getTime()}.xlsx`
).then(() => {
this.loading = false;
this.$modal.msgSuccess("导出成功");
}).catch(error => {
this.loading = false;
console.error('导出失败:', error);
this.$modal.msgError("导出失败");
});
}).catch(() => {
//
});
},
handlePrint() {
const printData = {
title: '库存入库明细表',
columns: [
{ prop: 'materialCode', label: '货品编码', width: 120 },
{ prop: 'materialName', label: '货品名称', width: 150 },
{ prop: 'categoryName', label: '货品类别', width: 120 },
{ prop: 'unitName', label: '计量单位', width: 100 },
{ prop: 'size', label: '货品规格', width: 120 },
{ prop: 'areaName', label: '所属区域', width: 120 },
{ prop: 'warehouseName', label: '所属仓库', width: 120 },
{ prop: 'intoTotalNum', label: '入库数量', width: 100 },
{ prop: 'intoTotalAmount', label: '入库金额(元)', width: 120 },
{ prop: 'intoTotalNum', label: '入库总数量', width: 120 },
{ prop: 'intoTotalAmount', label: '入库总金额(元)', width: 130 },
{ prop: 'outTotalNum', label: '出库数量', width: 100 },
{ prop: 'outTotalAmount', label: '出库金额(元)', width: 120 },
{ prop: 'outTotalNum', label: '出库总数量', width: 120 },
{ prop: 'outTotalAmount', label: '出库总金额(元)', width: 130 }
],
data: this.tableListData,
queryParams: this.queryParams
};
const printWindow = window.open('', '_blank');
const printContent = this.generatePrintHTML(printData);
printWindow.document.write(printContent);
printWindow.document.close();
printWindow.focus();
setTimeout(() => {
printWindow.print();
printWindow.close();
}, 500);
},
generatePrintHTML(printData) {
let html = `
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>${printData.title}</title>
<style>
body { font-family: "Microsoft YaHei", Arial, sans-serif; margin: 20px; }
h2 { text-align: center; margin-bottom: 20px; }
table { width: 100%; border-collapse: collapse; font-size: 12px; }
th, td { border: 1px solid #000; padding: 8px; text-align: center; }
th { background-color: #f0f0f0; font-weight: bold; }
.print-info { margin-bottom: 20px; font-size: 12px; }
@media print {
@page { size: landscape; margin: 10mm; }
}
</style>
</head>
<body>
<h2>${printData.title}</h2>
<div class="print-info">
<p>打印时间${new Date().toLocaleString()}</p>
<p> ${printData.data.length} 条记录</p>
</div>
<table>
<thead>
<tr>
`;
printData.columns.forEach(col => {
html += `<th>${col.label}</th>`;
});
html += `
</tr>
</thead>
<tbody>
`;
printData.data.forEach(row => {
html += '<tr>';
printData.columns.forEach(col => {
let value = row[col.prop] || '-';
if (col.prop === 'intoTotalAmount' || col.prop === 'outTotalAmount') {
value = this.formatMoney((value || 0) / 100);
} else if (col.prop === 'intoTotalNum' || col.prop === 'outTotalNum') {
value = this.formatNumber(value);
}
html += `<td>${value}</td>`;
});
html += '</tr>';
});
html += `
</tbody>
</table>
</body>
</html>
`;
return html;
},
defaultDateRange() {
const end = new Date();
const start = new Date();
start.setTime(start.getTime() - 30 * 24 * 60 * 60 * 1000);
return [this.formatDate(start), this.formatDate(end)];
},
formatDate(date) {
if (!date) return '';
const d = new Date(date);
const year = d.getFullYear();
const month = String(d.getMonth() + 1).padStart(2, '0');
const day = String(d.getDate()).padStart(2, '0');
return `${year}-${month}-${day}`;
},
formatDateTime(date) {
if (!date) return '';
const d = new Date(date);
const year = d.getFullYear();
const month = String(d.getMonth() + 1).padStart(2, '0');
const day = String(d.getDate()).padStart(2, '0');
const hours = String(d.getHours()).padStart(2, '0');
const minutes = String(d.getMinutes()).padStart(2, '0');
return `${year}-${month}-${day} ${hours}:${minutes}`;
},
formatMoney(value) {
if (value === null || value === undefined || value === '') return '0.00';
return Number(value).toFixed(2);
},
formatNumber(value) {
if (value === null || value === undefined || value === '') return '0';
return Number(value);
}
}
};
</script>
<style scoped>
.app-container {
padding: 20px;
}
/* 合计行样式增强 */
::v-deep .el-table__footer-wrapper tbody td {
background-color: #f5f7fa;
font-weight: bold;
color: #303133;
}
::v-deep .el-table__footer-wrapper tbody td:first-child {
font-weight: bold;
color: #409EFF;
}
/* 表格样式 */
::v-deep .el-table__fixed-right td.blue-record-col .cell {
color: #1677ff !important;
font-weight: 600;
}
/* 调整表单样式 */
::v-deep .el-form-item {
margin-bottom: 18px;
}
/* 调整按钮样式 */
::v-deep .el-button {
margin-left: 0;
}
::v-deep .el-form-item__content {
line-height: 32px;
}
/* 调整表格样式 */
::v-deep .el-table {
margin-top: 20px;
}
::v-deep .el-table th {
background-color: #f5f7fa;
color: #303133;
}
::v-deep .el-pagination {
margin-top: 15px;
}
</style>

View File

@ -0,0 +1,800 @@
<template>
<div class="app-container">
<!-- 查询表单部分保持不变 -->
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="90px">
<!-- 库存日期 -->
<el-form-item label="库存日期">
<el-date-picker
v-model="dateRange"
type="daterange"
align="right"
unlink-panels
range-separator="至"
start-placeholder="开始日期"
end-placeholder="结束日期"
format="yyyy-MM-dd"
value-format="yyyy-MM-dd"
style="width: 240px"
:picker-options="pickerOptions">
</el-date-picker>
</el-form-item>
<!-- 货品类别 - 级联多选 -->
<el-form-item label="货品类别">
<el-cascader
v-model="selectedCategories"
:options="goodsCategoryOptions"
:show-all-levels="false"
:props="categoryProps"
clearable
filterable
multiple
collapse-tags
placeholder="请选择货品类别"
style="width: 200px;"
@change="handleCategoryChange">
</el-cascader>
</el-form-item>
<!-- 所属区域 -->
<el-form-item label="所属区域">
<el-cascader
v-model="selectedOrg"
:options="orgOptions"
:show-all-levels="false"
clearable
filterable
placeholder="请选择所属区域"
:props="{
checkStrictly: true,
expandTrigger: 'hover',
value: 'orgId',
label: 'orgName',
children: 'children'
}"
style="width: 200px;"
@change="handleAreaChange">
</el-cascader>
</el-form-item>
<!-- 货品仓库 -->
<el-form-item label="货品仓库" prop="warehouseId">
<el-select
v-model="queryParams.warehouseIdList"
multiple
placeholder="请选择货品仓库"
clearable
style="width: 200px"
@change="handleWarehouseChange">
<el-option
v-for="item in wareHouseOptions"
:key="item.warehouseId"
:label="item.warehouseName"
:value="item.warehouseId">
</el-option>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<!-- 操作按钮栏 -->
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button
type="warning"
plain
icon="el-icon-download"
size="mini"
@click="handleExport"
>导出</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="info"
plain
icon="el-icon-printer"
size="mini"
@click="handlePrint"
>打印</el-button>
</el-col>
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
<!-- 数据表格 - 只修改字段名称以匹配后端实体 -->
<el-table
v-loading="loading"
:data="tableListData"
border
show-summary
:summary-method="getSummaries">
<el-table-column label="序号" align="center" width="60" type="index">
<template slot-scope="scope">
<span>{{(queryParams.pageNum - 1) * queryParams.pageSize + scope.$index + 1}}</span>
</template>
</el-table-column>
<!-- 货品类别 -->
<el-table-column label="货品类别" align="center" prop="categoryName" width="120" :show-overflow-tooltip="true"/>
<!-- 所属区域 -->
<el-table-column label="所属区域" align="center" prop="areaName" :show-overflow-tooltip="true"/>
<!-- 所属仓库 -->
<el-table-column label="所属仓库" align="center" prop="warehouseName" :show-overflow-tooltip="true"/>
<!-- 入库数量 -->
<el-table-column label="入库数量" align="center" prop="intoTotalNum" width="100">
<template slot-scope="scope">
<span>{{ formatNumber(scope.row.intoTotalNum) }}</span>
</template>
</el-table-column>
<!-- 入库金额() -->
<el-table-column label="入库金额(元)" align="center" prop="intoTotalAmount" width="120">
<template slot-scope="scope">
<span>{{ formatMoney((scope.row.intoTotalAmount || 0) / 100) }}</span>
</template>
</el-table-column>
<!-- 入库总数量 -->
<el-table-column label="入库总数量" align="center" prop="intoTotalNum" width="120">
<template slot-scope="scope">
<span>{{ formatNumber(scope.row.intoTotalNum) }}</span>
</template>
</el-table-column>
<!-- 入库总金额() -->
<el-table-column label="入库总金额(元)" align="center" prop="intoTotalAmount" width="130">
<template slot-scope="scope">
<span>{{ formatMoney((scope.row.intoTotalAmount || 0) / 100) }}</span>
</template>
</el-table-column>
<!-- 出库数量 -->
<el-table-column label="出库数量" align="center" prop="outTotalNum" width="100">
<template slot-scope="scope">
<span>{{ formatNumber(scope.row.outTotalNum) }}</span>
</template>
</el-table-column>
<!-- 出库金额() -->
<el-table-column label="出库金额(元)" align="center" prop="outTotalAmount" width="120">
<template slot-scope="scope">
<span>{{ formatMoney((scope.row.outTotalAmount || 0) / 100) }}</span>
</template>
</el-table-column>
<!-- 出库总数量 -->
<el-table-column label="出库总数量" align="center" prop="outTotalNum" width="120">
<template slot-scope="scope">
<span>{{ formatNumber(scope.row.outTotalNum) }}</span>
</template>
</el-table-column>
<!-- 出库总金额() -->
<el-table-column label="出库总金额(元)" align="center" prop="outTotalAmount" width="130">
<template slot-scope="scope">
<span>{{ formatMoney((scope.row.outTotalAmount || 0) / 100) }}</span>
</template>
</el-table-column>
</el-table>
<!-- 分页组件 -->
<pagination
v-show="total>0"
:total="total"
:page.sync="queryParams.pageNum"
:limit.sync="queryParams.pageSize"
@pagination="getList"
/>
</div>
</template>
<script>
// API
import {getTreeArea} from "@/api/canteen/canteenRecord";
// API
import {
listInventoryIntoDetail,
exportInventoryIntoDetail,
getWarehouseList,
getGoodsCategoryDict
} from "@/api/report/inventoryhz";
export default {
name: "InventoryIntoDetail",
dicts: [],
data() {
return {
//
summaryData: null,
//
orgOptions: [],
selectedOrg: [], //
//
goodsCategoryOptions: [], //
selectedCategories: [], //
categoryProps: {
expandTrigger: 'hover',
value: 'id',
label: 'dictLabel',
children: 'children',
emitPath: true,
multiple: true
},
//
wareHouseOptions: [],
//
loading: true,
//
showSearch: true,
//
total: 0,
//
tableListData: [],
//
queryParams: {
pageNum: 1,
pageSize: 10,
recordId: null, //
categoryIdList: [], // ID
warehouseIdList: [], // ID
goodsName: null, //
areaIdList: [], // ID
startDate: null, //
endDate: null //
},
//
dateRange: this.defaultDateRange(),
//
pickerOptions: {
shortcuts: [{
text: '最近一周',
onClick: (picker) => {
const end = new Date();
const start = new Date();
start.setTime(start.getTime() - 3600 * 1000 * 24 * 6);
picker.$emit('pick', [this.formatDate(start), this.formatDate(end)]);
}
}, {
text: '最近一个月',
onClick: (picker) => {
const end = new Date();
const start = new Date();
start.setTime(start.getTime() - 3600 * 1000 * 24 * 30);
picker.$emit('pick', [this.formatDate(start), this.formatDate(end)]);
}
}, {
text: '最近三个月',
onClick: (picker) => {
const end = new Date();
const start = new Date();
start.setTime(start.getTime() - 3600 * 1000 * 24 * 91);
picker.$emit('pick', [this.formatDate(start), this.formatDate(end)]);
}
}]
}
};
},
created() {
//
this.getTree(); //
this.getWareHouseData(); //
this.getGoodsCategoryData(); //
this.getList(); //
},
methods: {
/**
* 自定义合计计算方法
*/
getSummaries(param) {
const { columns, data } = param;
const sums = [];
columns.forEach((column, index) => {
if (index === 0) {
// ""
sums[index] = '合计';
return;
}
//
const columnProp = column.property;
if (this.summaryData) {
switch(columnProp) {
case 'intoTotalNum':
sums[index] = this.formatNumber(this.summaryData.intoTotalNum || 0);
break;
case 'intoTotalAmount':
sums[index] = this.formatMoney((this.summaryData.intoTotalAmount || 0) / 100);
break;
case 'outTotalNum':
sums[index] = this.formatNumber(this.summaryData.outTotalNum || 0);
break;
case 'outTotalAmount':
sums[index] = this.formatMoney((this.summaryData.outTotalAmount || 0) / 100);
break;
default:
//
sums[index] = '';
break;
}
} else {
sums[index] = '';
}
});
return sums;
},
//
getGoodsCategoryData() {
getGoodsCategoryDict().then((response) => {
const data = response.data || response || [];
console.log('获取到的货品类别数据:', data);
//
if (data.length > 0 && !data[0].children) {
// 使
this.goodsCategoryOptions = this.buildCategoryTree(data);
} else {
// 使
this.goodsCategoryOptions = data;
}
console.log('转换后的货品类别树:', this.goodsCategoryOptions);
}).catch(error => {
console.error('获取货品类别失败:', error);
this.goodsCategoryOptions = [];
});
},
buildCategoryTree(list) {
//
const tree = [];
// 1.
const materialRoot = {
id: 25595457052610560,
dictLabel: "原料",
parentId: -1,
children: []
};
// 2.
const goodsRoot = {
id: 65595542415085568,
dictLabel: "商品",
parentId: -1,
children: []
};
// parent_id
const map = {};
list.forEach(item => {
if (!map[item.id]) {
map[item.id] = { ...item, children: [] };
}
});
//
list.forEach(item => {
if (item.parentId === 25595457052610560) {
const child = { ...item, children: [] };
materialRoot.children.push(child);
map[item.id] = child;
} else if (item.parentId === 65595542415085568) {
const child = { ...item, children: [] };
goodsRoot.children.push(child);
map[item.id] = child;
} else if (item.parentId !== -1 && map[item.parentId]) {
const child = { ...item, children: [] };
if (!map[item.parentId].children) {
map[item.parentId].children = [];
}
map[item.parentId].children.push(child);
map[item.id] = child;
}
});
tree.push(materialRoot, goodsRoot);
return tree;
},
handleCategoryChange(values) {
if (!values || values.length === 0) {
this.queryParams.categoryIdList = [];
return;
}
let allCategoryIds = [];
values.forEach(path => {
const selectedId = path[path.length - 1];
const node = this.findCategoryNodeById(selectedId, this.goodsCategoryOptions);
if (node) {
allCategoryIds.push(...this.getAllChildCategoryIds(node));
}
});
this.queryParams.categoryIdList = Array.from(new Set(allCategoryIds));
console.log("最终传给后台的 categoryIdList =", this.queryParams.categoryIdList);
},
findCategoryNodeById(id, options) {
for (const node of options) {
if (node.id === id) {
return node;
}
if (node.children && node.children.length > 0) {
const found = this.findCategoryNodeById(id, node.children);
if (found) return found;
}
}
return null;
},
getAllChildCategoryIds(node) {
if (!node) return [];
let ids = [node.id];
if (node.children && node.children.length > 0) {
node.children.forEach(child => {
ids = ids.concat(this.getAllChildCategoryIds(child));
});
}
return ids;
},
getSelectedOrgIds() {
if (!this.selectedOrg || this.selectedOrg.length === 0) return [];
const lastValue = this.selectedOrg[this.selectedOrg.length - 1];
//
let stack = [...this.orgOptions];
let node = null;
for (let val of this.selectedOrg) {
node = stack.find(item => item.orgId === val);
if (!node) break;
stack = node.children || [];
}
if (node) {
return this.getAllChildIds(node, this.orgOptions);
}
return [lastValue];
},
getAllChildIds(node, options) {
let ids = [node.orgId]; //
if (node.children && node.children.length > 0) {
node.children.forEach(child => {
ids = ids.concat(this.getAllChildIds(child, options)); //
});
}
return ids;
},
getTree() {
getTreeArea().then(res => {
this.orgOptions = res || [];
});
},
handleAreaChange() {
//
this.queryParams.warehouseIdList = [];
this.getWareHouseData();
},
handleWarehouseChange() {
//
},
getWareHouseData() {
const areaIdList = this.getSelectedOrgIds();
console.log("选中的 orgId 列表:", areaIdList, Array.isArray(areaIdList));
if (!areaIdList || !areaIdList.length) {
this.wareHouseOptions = [];
return;
}
getWarehouseList({
areaIdList: areaIdList.join(',')
}).then(res => {
this.wareHouseOptions = res.data || [];
});
},
handleQuery() {
this.queryParams.pageNum = 1;
this.getList();
},
resetQuery() {
this.dateRange = this.defaultDateRange();
this.selectedOrg = [];
this.selectedCategories = [];
this.summaryData = null;
this.queryParams = {
pageNum: 1,
pageSize: 10,
recordId: null,
categoryIdList: [],
warehouseIdList: [],
goodsName: null,
areaIdList: [],
startDate: null,
endDate: null
};
this.resetForm("queryForm");
this.getWareHouseData();
this.handleQuery();
},
getList() {
this.loading = true;
// ID
this.queryParams.areaIdList = this.getSelectedOrgIds();
//
if (this.dateRange && this.dateRange.length === 2) {
this.queryParams.startDate = this.dateRange[0];
this.queryParams.endDate = this.dateRange[1];
} else {
this.queryParams.startDate = null;
this.queryParams.endDate = null;
}
// API
listInventoryIntoDetail(this.queryParams).then(response => {
const data = response.data || response;
this.tableListData = data.rows || [];
this.total = Number(data.total) || 0;
this.summaryData = data.summary || null;
console.log('合计数据:', this.summaryData);
this.loading = false;
}).catch(() => {
this.loading = false;
});
},
handleExport() {
//
let startDate = '';
let endDate = '';
if (this.dateRange && this.dateRange.length === 2) {
const start = this.dateRange[0];
const end = this.dateRange[1];
startDate = start + ' 00:00:00';
endDate = end + ' 23:59:59';
}
//
let param = {
pageNum: this.queryParams.pageNum,
pageSize: this.queryParams.pageSize,
recordId: this.queryParams.recordId,
categoryIdList: this.queryParams.categoryIdList,
warehouseIdList: this.queryParams.warehouseIdList,
materialName: this.queryParams.materialName,
areaIdList: this.getSelectedOrgIds(),
startDate: startDate,
endDate: endDate
};
// 使download
this.$modal.confirm('是否确认导出货品汇总明细数据项?').then(() => {
this.loading = true;
// 使download
this.download(
'/smart-canteen/drp/inventoryIntohz/goods/summary/export',
param,
`货品库存明细_${new Date().getTime()}.xlsx`
).then(() => {
this.loading = false;
this.$modal.msgSuccess("导出成功");
}).catch(error => {
this.loading = false;
console.error('导出失败:', error);
this.$modal.msgError("导出失败");
});
}).catch(() => {
//
});
},
handlePrint() {
const printData = {
title: '库存入库明细表',
columns: [
{ prop: 'categoryName', label: '货品类别', width: 120 },
{ prop: 'areaName', label: '所属区域', width: 120 },
{ prop: 'warehouseName', label: '所属仓库', width: 120 },
{ prop: 'intoTotalNum', label: '入库数量', width: 100 },
{ prop: 'intoTotalAmount', label: '入库金额(元)', width: 120 },
{ prop: 'intoTotalNum', label: '入库总数量', width: 120 },
{ prop: 'intoTotalAmount', label: '入库总金额(元)', width: 130 },
{ prop: 'outTotalNum', label: '出库数量', width: 100 },
{ prop: 'outTotalAmount', label: '出库金额(元)', width: 120 },
{ prop: 'outTotalNum', label: '出库总数量', width: 120 },
{ prop: 'outTotalAmount', label: '出库总金额(元)', width: 130 }
],
data: this.tableListData,
queryParams: this.queryParams
};
const printWindow = window.open('', '_blank');
const printContent = this.generatePrintHTML(printData);
printWindow.document.write(printContent);
printWindow.document.close();
printWindow.focus();
setTimeout(() => {
printWindow.print();
printWindow.close();
}, 500);
},
generatePrintHTML(printData) {
let html = `
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>${printData.title}</title>
<style>
body { font-family: "Microsoft YaHei", Arial, sans-serif; margin: 20px; }
h2 { text-align: center; margin-bottom: 20px; }
table { width: 100%; border-collapse: collapse; font-size: 12px; }
th, td { border: 1px solid #000; padding: 8px; text-align: center; }
th { background-color: #f0f0f0; font-weight: bold; }
.print-info { margin-bottom: 20px; font-size: 12px; }
@media print {
@page { size: landscape; margin: 10mm; }
}
</style>
</head>
<body>
<h2>${printData.title}</h2>
<div class="print-info">
<p>打印时间${new Date().toLocaleString()}</p>
<p> ${printData.data.length} 条记录</p>
</div>
<table>
<thead>
<tr>
`;
printData.columns.forEach(col => {
html += `<th>${col.label}</th>`;
});
html += `
</tr>
</thead>
<tbody>
`;
printData.data.forEach(row => {
html += '<tr>';
printData.columns.forEach(col => {
let value = row[col.prop] || '-';
if (col.prop === 'intoTotalAmount' || col.prop === 'outTotalAmount') {
value = this.formatMoney((value || 0) / 100);
} else if (col.prop === 'intoTotalNum' || col.prop === 'outTotalNum') {
value = this.formatNumber(value);
}
html += `<td>${value}</td>`;
});
html += '</tr>';
});
html += `
</tbody>
</table>
</body>
</html>
`;
return html;
},
defaultDateRange() {
const end = new Date();
const start = new Date();
start.setTime(start.getTime() - 30 * 24 * 60 * 60 * 1000);
return [this.formatDate(start), this.formatDate(end)];
},
formatDate(date) {
if (!date) return '';
const d = new Date(date);
const year = d.getFullYear();
const month = String(d.getMonth() + 1).padStart(2, '0');
const day = String(d.getDate()).padStart(2, '0');
return `${year}-${month}-${day}`;
},
formatDateTime(date) {
if (!date) return '';
const d = new Date(date);
const year = d.getFullYear();
const month = String(d.getMonth() + 1).padStart(2, '0');
const day = String(d.getDate()).padStart(2, '0');
const hours = String(d.getHours()).padStart(2, '0');
const minutes = String(d.getMinutes()).padStart(2, '0');
return `${year}-${month}-${day} ${hours}:${minutes}`;
},
formatMoney(value) {
if (value === null || value === undefined || value === '') return '0.00';
return Number(value).toFixed(2);
},
formatNumber(value) {
if (value === null || value === undefined || value === '') return '0';
return Number(value);
}
}
};
</script>
<style scoped>
.app-container {
padding: 20px;
}
/* 合计行样式增强 */
::v-deep .el-table__footer-wrapper tbody td {
background-color: #f5f7fa;
font-weight: bold;
color: #303133;
}
::v-deep .el-table__footer-wrapper tbody td:first-child {
font-weight: bold;
color: #409EFF;
}
/* 表格样式 */
::v-deep .el-table__fixed-right td.blue-record-col .cell {
color: #1677ff !important;
font-weight: 600;
}
/* 调整表单样式 */
::v-deep .el-form-item {
margin-bottom: 18px;
}
/* 调整按钮样式 */
::v-deep .el-button {
margin-left: 0;
}
::v-deep .el-form-item__content {
line-height: 32px;
}
/* 调整表格样式 */
::v-deep .el-table {
margin-top: 20px;
}
::v-deep .el-table th {
background-color: #f5f7fa;
color: #303133;
}
::v-deep .el-pagination {
margin-top: 15px;
}
</style>