Files
GEAR-OA/gear-ui3/src/views/wms/stock/index.vue
2025-09-22 14:13:48 +08:00

411 lines
14 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="app-container stock-layout">
<!-- 左侧树结构 -->
<div class="stock-tree-col">
<el-card shadow="never" class="stock-tree-card">
<div slot="header" class="stock-tree-title">仓库结构</div>
<WarehouseTree @node-click="handleTreeSelect" />
</el-card>
</div>
<!-- 右侧内容 -->
<div class="stock-main-col">
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
<!-- 移除仓库筛选项 -->
<!-- <MaterialSelect :itemType.sync="queryParams.itemType" :itemId.sync="queryParams.itemId" @change="getList" /> -->
<el-form-item label="单位" prop="unit">
<el-input v-model="queryParams.unit" placeholder="请输入单位" clearable @keyup.enter.native="handleQuery" />
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
<el-button type="warning" plain icon="Download" size="mini" @click="handleExport">导出</el-button>
<!-- 合并批次<el-switch v-model="queryParams.mergeBatch" :active-value="1" :inactive-value="0" @change="handleQuery" /> -->
</el-form-item>
</el-form>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
<el-table v-loading="loading" :data="stockList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="仓库" align="center" prop="warehouseName" />
<el-table-column label="物品类型" align="center" prop="itemType">
<template #default="scope">
<dict-tag :options="stock_item_type" :value="scope.row.itemType" />
</template>
</el-table-column>
<el-table-column label="物品" align="center" prop="itemName">
<template #default="scope">
<ProductInfo v-if="scope.row.itemType == 'product' || scope.row.itemType == 'semi'" :productId="scope.row.itemId">
<template #default="{ product }">
{{ product.productName }}({{ product.productCode }})
</template>
</ProductInfo>
<!-- <RawMaterialInfo v-else-if="scope.row.itemType === 'raw_material'" :materialId="scope.row.itemId">
<template #default="{ material }">
{{ material.rawMaterialName }}({{ material.rawMaterialCode }})
</template>
</RawMaterialInfo> -->
</template>
</el-table-column>
<el-table-column label="BOM">
<template #default="scope">
<BomInfoMini :itemType="scope.row.itemType" :itemId="scope.row.itemId" />
</template>
</el-table-column>
<el-table-column label="库存数量" align="center" prop="quantity" />
<!-- <el-table-column label="在途数量" align="center" prop="onTheWay" /> -->
<el-table-column label="单位" align="center" prop="unit" />
<el-table-column label="批次号" align="center" prop="batchNo" />
<el-table-column label="备注" align="center" prop="remark" />
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template #default="scope">
<el-button type="text" size="small" @click="handleTrace(scope.row)">物料追溯</el-button>
</template>
</el-table-column>
</el-table>
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize"
@pagination="getList" />
<!-- 添加或修改库存对话框保持不变 -->
<el-dialog :title="title" v-model="open" width="500px" append-to-body>
<el-form ref="form" :model="form" :rules="rules" label-width="80px">
<el-form-item label="仓库/库区/库位ID" prop="warehouseId">
<warehouse-select v-model="form.warehouseId" placeholder="请选择仓库/库区/库位" style="width: 100%;" clearable />
</el-form-item>
<el-form-item label="物品类型" prop="itemType">
<el-select v-model="form.itemType" placeholder="请选择物品类型">
<el-option v-for="dict in stock_item_type" :key="dict.value" :label="dict.label"
:value="dict.value"></el-option>
</el-select>
</el-form-item>
<el-form-item label="物品" prop="itemId">
<!-- <raw-material-select v-if="form.itemType === 'rawMaterial'" v-model="form.itemId" placeholder="请选择原材料"
style="width: 100%;" clearable /> -->
<product-select v-if="form.itemType === 'product'" v-model="form.itemId" placeholder="请选择产品"
style="width: 100%;" clearable />
<el-input v-else v-model="form.itemId" placeholder="请先选择物品类型" :disabled="true" style="width: 100%;" />
</el-form-item>
<el-form-item label="库存数量" prop="quantity">
<el-input v-model="form.quantity" placeholder="请输入库存数量" />
</el-form-item>
<el-form-item label="单位" prop="unit">
<el-input v-model="form.unit" placeholder="请输入单位" />
</el-form-item>
<el-form-item label="批次号" prop="batchNo">
<el-input v-model="form.batchNo" placeholder="请输入批次号" />
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" placeholder="请输入备注" />
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button :loading="buttonLoading" type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</el-dialog>
<el-dialog v-model="stockBoxVisible" title="暂存单据" width="800px" append-to-body>
<stock-io :data="stockBoxData" @generateBill="handleGenerateBill" />
</el-dialog>
<el-dialog v-model="stockTraceVisible" title="物料追溯" width="800px" append-to-body>
<el-table :data="stockTraceList" style="width: 100%">
<el-table-column label="单据类型" align="center" prop="ioType">
<template #default="scope">
<dict-tag :options="stock_io_type" :value="scope.row.ioType" />
</template>
</el-table-column>
<el-table-column label="单据ID" align="center" prop="stockIoId" />
<el-table-column label="单据编号" align="center" prop="stockIoCode" />
<!-- <el-table-column label="创建时间" align="center" prop="createTime" /> -->
<el-table-column label="变更数量" align="center" prop="quantity" />
<el-table-column label="备注" align="center" prop="remark" />
</el-table>
</el-dialog>
</div>
</div>
</template>
<script>
import { listStock, delStock, addStock, updateStock, getStockTrace } from "@/api/wms/stock";
import { addStockIoWithDetail } from "@/api/wms/stockIo";
import ProductSelect from "@/components/ProductSelect";
import WarehouseSelect from "@/components/WarehouseSelect";
import StockBox from './box';
import ProductInfo from "@/components/Renderer/ProductInfo";
import BomInfoMini from "@/components/Renderer/BomInfoMini";
import StockIo from './panels/stockIo.vue';
import WarehouseTree from "@/components/WarehouseTree/index.vue";
export default {
name: "Stock",
setup() {
const { proxy } = getCurrentInstance();
const { stock_item_type, stock_io_type } = proxy.useDict('stock_item_type', 'stock_io_type');
return {
stock_item_type,
stock_io_type,
};
},
components: {
WarehouseSelect,
ProductSelect,
StockBox,
ProductInfo,
BomInfoMini,
StockIo,
WarehouseTree,
},
data() {
return {
// 库存分析对话框显示状态
stockBoxVisible: false,
// 按钮loading
buttonLoading: false,
// 遮罩层
loading: true,
// 选中数组
ids: [],
// 非单个禁用
single: true,
// 非多个禁用
multiple: true,
// 显示搜索条件
showSearch: true,
// 总条数
total: 0,
// 库存:原材料/产品与库区/库位的存放关系表格数据
stockList: [],
// 弹出层标题
title: "",
// 是否显示弹出层
open: false,
// 查询参数
queryParams: {
pageNum: 1,
pageSize: 20,
warehouseId: undefined,
itemType: undefined,
itemId: undefined,
quantity: undefined,
unit: undefined,
batchNo: undefined,
mergeBatch: false,
},
// 表单参数
form: {},
// 表单校验
rules: {
warehouseId: [
{ required: true, message: "仓库/库区/库位ID不能为空", trigger: "blur" }
],
itemType: [
{ required: true, message: "物品类型不能为空", trigger: "change" }
],
itemId: [
{ required: true, message: "物品ID不能为空", trigger: "blur" }
],
quantity: [
{ required: true, message: "库存数量不能为空", trigger: "blur" }
],
unit: [
{ required: true, message: "单位不能为空", trigger: "blur" }
],
batchNo: [
{ required: true, message: "批次号不能为空", trigger: "blur" }
],
},
// 暂存用于创建出库单或移库单的数据
stockBoxData: [],
stockBoxVisible: false,
// 选中的数据
selectedRows: [],
stockTraceList: [],
stockTraceVisible: false,
};
},
created() {
this.getList();
},
methods: {
/** 查询库存:原材料/产品与库区/库位的存放关系列表 */
getList() {
this.loading = true;
listStock(this.queryParams).then(response => {
this.stockList = response.rows;
this.total = response.total;
this.loading = false;
});
},
// 树节点点击
handleTreeSelect(node) {
this.queryParams.warehouseId = node.warehouseId;
this.queryParams.pageNum = 1;
this.getList();
},
// 取消按钮
cancel() {
this.open = false;
this.reset();
},
// 表单重置
reset() {
this.form = {
stockId: undefined,
warehouseId: undefined,
itemType: undefined,
itemId: undefined,
quantity: undefined,
unit: undefined,
batchNo: undefined,
remark: undefined,
delFlag: undefined,
createTime: undefined,
createBy: undefined,
updateTime: undefined,
updateBy: undefined
};
this.resetForm("form");
},
/** 搜索按钮操作 */
handleQuery() {
this.queryParams.pageNum = 1;
this.getList();
},
/** 重置按钮操作 */
resetQuery() {
this.resetForm("queryForm");
this.handleQuery();
},
// 多选框选中数据
handleSelectionChange(selection) {
this.selectedRows = selection;
this.ids = selection.map(item => item.stockId)
this.single = selection.length !== 1
this.multiple = !selection.length
},
/** 提交按钮 */
submitForm() {
this.$refs["form"].validate(valid => {
if (valid) {
this.buttonLoading = true;
if (this.form.stockId != null) {
updateStock(this.form).then(response => {
this.$modal.msgSuccess("修改成功");
this.open = false;
this.getList();
}).finally(() => {
this.buttonLoading = false;
});
} else {
addStock(this.form).then(response => {
this.$modal.msgSuccess("新增成功");
this.open = false;
this.getList();
}).finally(() => {
this.buttonLoading = false;
});
}
}
});
},
/** 删除按钮操作 */
handleDelete(row) {
const stockIds = row.stockId || this.ids;
this.$modal.confirm('是否确认删除库存:原材料/产品与库区/库位的存放关系编号为"' + stockIds + '"的数据项?').then(() => {
this.loading = true;
return delStock(stockIds);
}).then(() => {
this.loading = false;
this.getList();
this.$modal.msgSuccess("删除成功");
}).catch(() => {
}).finally(() => {
this.loading = false;
});
},
/** 导出按钮操作 */
handleExport() {
this.download('wms/stock/export', {
...this.queryParams
}, `stock_${new Date().getTime()}.xlsx`)
},
handleStockBox() {
// 添加到暂存单据中,并且去重,去重依据为stockId是否相同
const list = [...this.selectedRows, ...this.stockBoxData];
console.log(list);
const uniqueStockBoxData = list.filter((item, index, self) =>
index === self.findIndex(t => t.stockId === item.stockId)
);
this.stockBoxData = uniqueStockBoxData;
this.$modal.msgSuccess("暂存成功,请点击“暂存单据”按钮生成单据");
},
handleGenerateBill(data) {
addStockIoWithDetail(data).then(response => {
this.$modal.msgSuccess("生成单据成功");
});
},
handleViewStockBox() {
// 查看暂存单据
console.log(this.stockBoxData);
this.stockBoxVisible = true;
},
handleTrace(row) {
// 查询对应批次号的的出库和入库单据明细并展示
getStockTrace(row.batchNo).then(response => {
this.stockTraceList = response.data;
this.stockTraceVisible = true;
});
}
}
};
</script>
<style scoped>
.stock-layout {
height: 100%;
display: flex;
flex-direction: row;
}
.stock-tree-col {
width: 260px;
max-width: 300px;
background: #fff;
border-right: 1px solid #f0f0f0;
height: 100%;
padding-right: 0;
box-sizing: border-box;
display: flex;
flex-direction: column;
}
.stock-tree-card {
height: 100%;
border: none;
box-shadow: none;
}
.stock-tree-title {
font-weight: bold;
font-size: 16px;
padding: 8px 0;
}
.stock-tree {
min-height: 500px;
max-height: 80vh;
overflow-y: auto;
}
.stock-main-col {
flex: 1;
padding-left: 24px;
min-width: 0;
display: flex;
flex-direction: column;
}
</style>