|
|
|
|
<template>
|
|
|
|
|
<el-dialog
|
|
|
|
|
:title="rowItem.isBatch ? '批量出库' : '出库'"
|
|
|
|
|
append-to-body
|
|
|
|
|
:modelValue="openShow"
|
|
|
|
|
width="90%"
|
|
|
|
|
@close="closeDialog"
|
|
|
|
|
fullscreen
|
|
|
|
|
>
|
|
|
|
|
<div style="height: 50px">
|
|
|
|
|
<el-input
|
|
|
|
|
v-model="formInline.orderId"
|
|
|
|
|
placeholder="扫描出库单号条形码"
|
|
|
|
|
@keyup.enter.native="changeCode"
|
|
|
|
|
style="width: 200px; float: left"
|
|
|
|
|
></el-input>
|
|
|
|
|
<el-button type="danger" @click="delFn" style="float: right">删除</el-button>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<avue-crud
|
|
|
|
|
:option="option"
|
|
|
|
|
:table-loading="loading"
|
|
|
|
|
:data="data"
|
|
|
|
|
v-model="form"
|
|
|
|
|
v-model:page="page"
|
|
|
|
|
ref="crud"
|
|
|
|
|
@search-change="searchChange"
|
|
|
|
|
@search-reset="searchReset"
|
|
|
|
|
:before-open="beforeOpen"
|
|
|
|
|
@selection-change="selectionChange"
|
|
|
|
|
@current-change="currentChange"
|
|
|
|
|
@size-change="sizeChange"
|
|
|
|
|
@refresh-change="refreshChange"
|
|
|
|
|
@on-load="onLoad"
|
|
|
|
|
@row-save="rowSave"
|
|
|
|
|
@cell-click="cellClick"
|
|
|
|
|
>
|
|
|
|
|
<template #goodsCode="scope">
|
|
|
|
|
<el-select v-model="scope.row.goodsCode" @change="val => changeGoods(val, scope.index)">
|
|
|
|
|
<el-option
|
|
|
|
|
v-for="item in goodsList"
|
|
|
|
|
:key="item.id"
|
|
|
|
|
:label="item.goodsCode"
|
|
|
|
|
:value="item.goodsCode"
|
|
|
|
|
></el-option>
|
|
|
|
|
</el-select>
|
|
|
|
|
</template>
|
|
|
|
|
<template #shId="scope">
|
|
|
|
|
<el-select v-model="scope.row.shId" @change="val => changeWare(val, scope.index)">
|
|
|
|
|
<el-option
|
|
|
|
|
v-for="item in scope.row.shList"
|
|
|
|
|
:key="item.id"
|
|
|
|
|
:label="item.shName"
|
|
|
|
|
:value="item.id"
|
|
|
|
|
></el-option>
|
|
|
|
|
</el-select>
|
|
|
|
|
</template>
|
|
|
|
|
<template #slId="scope">
|
|
|
|
|
<el-select v-model="scope.row.slId" @change="val => changeLocation(val, scope.index)">
|
|
|
|
|
<el-option
|
|
|
|
|
v-for="item in scope.row.slList"
|
|
|
|
|
:key="item.id"
|
|
|
|
|
:label="item.location"
|
|
|
|
|
:value="item.slId"
|
|
|
|
|
></el-option>
|
|
|
|
|
</el-select>
|
|
|
|
|
</template>
|
|
|
|
|
<template #piNo="scope">
|
|
|
|
|
<el-select v-model="scope.row.piNo" @change="val => changePiNo(val, scope.index)">
|
|
|
|
|
<el-option
|
|
|
|
|
v-for="item in scope.row.piNoList"
|
|
|
|
|
:key="item.id"
|
|
|
|
|
:label="item.piNo"
|
|
|
|
|
:value="item.piNo"
|
|
|
|
|
></el-option>
|
|
|
|
|
</el-select>
|
|
|
|
|
</template>
|
|
|
|
|
<template #outQty="scope">
|
|
|
|
|
<el-input-number
|
|
|
|
|
v-model="scope.row.outQty"
|
|
|
|
|
:min="1"
|
|
|
|
|
:max="scope.row.stockQty"
|
|
|
|
|
style="width: 90%"
|
|
|
|
|
controls-position="right"
|
|
|
|
|
></el-input-number>
|
|
|
|
|
</template>
|
|
|
|
|
</avue-crud>
|
|
|
|
|
|
|
|
|
|
<template #footer>
|
|
|
|
|
<span class="dialog-footer">
|
|
|
|
|
<el-button @click="closeDialog">取 消</el-button>
|
|
|
|
|
<el-button type="primary" @click="submit">确 定</el-button>
|
|
|
|
|
</span>
|
|
|
|
|
</template>
|
|
|
|
|
</el-dialog>
|
|
|
|
|
</template>
|
|
|
|
|
<script>
|
|
|
|
|
import {
|
|
|
|
|
getGoodsList,
|
|
|
|
|
getWarehouseList,
|
|
|
|
|
getLocationData,
|
|
|
|
|
scanIssue,
|
|
|
|
|
batchIssue,
|
|
|
|
|
} from '@/api/storeManagement/glassCakeOutbound';
|
|
|
|
|
export default {
|
|
|
|
|
props: {
|
|
|
|
|
showDialog: {
|
|
|
|
|
type: Boolean,
|
|
|
|
|
default: false,
|
|
|
|
|
},
|
|
|
|
|
rowItem: {
|
|
|
|
|
type: Object,
|
|
|
|
|
default: () => ({}),
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
data() {
|
|
|
|
|
return {
|
|
|
|
|
openShow: false,
|
|
|
|
|
formInline: {
|
|
|
|
|
orderId: '',
|
|
|
|
|
number2: '',
|
|
|
|
|
},
|
|
|
|
|
goodsList: [],
|
|
|
|
|
option: {
|
|
|
|
|
columnSort: true,
|
|
|
|
|
tip: false,
|
|
|
|
|
align: 'center',
|
|
|
|
|
calcHeight: 32,
|
|
|
|
|
simplePage: false,
|
|
|
|
|
page: false,
|
|
|
|
|
searchShow: true,
|
|
|
|
|
searchMenuSpan: 6,
|
|
|
|
|
searchIcon: true,
|
|
|
|
|
searchIndex: 3,
|
|
|
|
|
tree: false,
|
|
|
|
|
border: true,
|
|
|
|
|
index: false,
|
|
|
|
|
selection: true,
|
|
|
|
|
viewBtn: false,
|
|
|
|
|
delBtn: false,
|
|
|
|
|
editBtn: true,
|
|
|
|
|
cellEdit: true,
|
|
|
|
|
menu: true,
|
|
|
|
|
|
|
|
|
|
editBtnText: '修改',
|
|
|
|
|
editBtnIcon: ' ',
|
|
|
|
|
delBtnIcon: ' ',
|
|
|
|
|
addBtn: false,
|
|
|
|
|
labelWidth: 140,
|
|
|
|
|
searchLabelWidth: 120,
|
|
|
|
|
menu: false,
|
|
|
|
|
menuWidth: 200,
|
|
|
|
|
dialogWidth: 1200,
|
|
|
|
|
dialogClickModal: false,
|
|
|
|
|
searchEnter: true,
|
|
|
|
|
excelBtn: true,
|
|
|
|
|
gridBtn: false,
|
|
|
|
|
searchShowBtn: false,
|
|
|
|
|
showOverflowTooltip: true,
|
|
|
|
|
header: false,
|
|
|
|
|
searchLabelPosition: 'left',
|
|
|
|
|
searchLabelPosition: 'left',
|
|
|
|
|
searchGutter: 24,
|
|
|
|
|
searchSpan: 6,
|
|
|
|
|
menuAlign: 'left',
|
|
|
|
|
gridBtn: false,
|
|
|
|
|
searchMenuPosition: 'right',
|
|
|
|
|
addBtnIcon: ' ',
|
|
|
|
|
viewBtnIcon: ' ',
|
|
|
|
|
delBtnIcon: ' ',
|
|
|
|
|
editBtnIcon: ' ',
|
|
|
|
|
|
|
|
|
|
column: [
|
|
|
|
|
{
|
|
|
|
|
label: '生产单号',
|
|
|
|
|
prop: 'yoCode',
|
|
|
|
|
width: 150,
|
|
|
|
|
search: false,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
label: '零件号',
|
|
|
|
|
prop: 'partCode',
|
|
|
|
|
width: 150,
|
|
|
|
|
search: false,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
label: '零件名称',
|
|
|
|
|
prop: 'partName',
|
|
|
|
|
width: 150,
|
|
|
|
|
search: false,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
label: '流程卡号',
|
|
|
|
|
prop: 'cardNo',
|
|
|
|
|
width: 150,
|
|
|
|
|
search: false,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
label: '生产数量',
|
|
|
|
|
prop: 'quantity',
|
|
|
|
|
search: false,
|
|
|
|
|
width: 120,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
label: '物料号',
|
|
|
|
|
prop: 'goodsCode',
|
|
|
|
|
search: false,
|
|
|
|
|
width: 200,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
label: '物料名称',
|
|
|
|
|
width: 150,
|
|
|
|
|
prop: 'goodsName',
|
|
|
|
|
search: false,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
label: '库房',
|
|
|
|
|
prop: 'shId',
|
|
|
|
|
width: 150,
|
|
|
|
|
search: false,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
label: '库位',
|
|
|
|
|
prop: 'slId',
|
|
|
|
|
width: 150,
|
|
|
|
|
search: false,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
label: '批次号',
|
|
|
|
|
prop: 'piNo',
|
|
|
|
|
width: 150,
|
|
|
|
|
search: false,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
label: '是否印字',
|
|
|
|
|
prop: 'printMark',
|
|
|
|
|
width: 120,
|
|
|
|
|
search: false,
|
|
|
|
|
type: 'select',
|
|
|
|
|
dicData: [
|
|
|
|
|
{ label: '是', value: true },
|
|
|
|
|
{ label: '否', value: false },
|
|
|
|
|
],
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
label: '粉重',
|
|
|
|
|
prop: 'powderWeight',
|
|
|
|
|
width: 120,
|
|
|
|
|
search: false,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
label: '材料号',
|
|
|
|
|
prop: 'materialNo',
|
|
|
|
|
search: false,
|
|
|
|
|
width: 120,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
label: '成型厚度',
|
|
|
|
|
prop: 'thickness',
|
|
|
|
|
width: 120,
|
|
|
|
|
search: false,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
label: '炉批号',
|
|
|
|
|
prop: 'stovePiNo',
|
|
|
|
|
search: false,
|
|
|
|
|
width: 120,
|
|
|
|
|
},
|
|
|
|
|
// {
|
|
|
|
|
// label:"已出库数量",
|
|
|
|
|
// prop: "outQuantity",
|
|
|
|
|
// width:150,
|
|
|
|
|
// },
|
|
|
|
|
{
|
|
|
|
|
label: '库存数量',
|
|
|
|
|
prop: 'stockQty',
|
|
|
|
|
width: 120,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
label: '出库数量',
|
|
|
|
|
prop: 'outQty',
|
|
|
|
|
width: 150,
|
|
|
|
|
},
|
|
|
|
|
],
|
|
|
|
|
},
|
|
|
|
|
data: [],
|
|
|
|
|
selectionList: [],
|
|
|
|
|
};
|
|
|
|
|
},
|
|
|
|
|
mounted() {
|
|
|
|
|
this.openShow = this.showDialog;
|
|
|
|
|
this.getGoods();
|
|
|
|
|
this.onLoad();
|
|
|
|
|
},
|
|
|
|
|
watch: {
|
|
|
|
|
showDialog(newVal) {
|
|
|
|
|
this.openShow = newVal;
|
|
|
|
|
if (newVal) {
|
|
|
|
|
this.onLoad();
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
rowItem: {
|
|
|
|
|
handler() {
|
|
|
|
|
if (this.openShow) {
|
|
|
|
|
this.onLoad();
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
deep: true,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
methods: {
|
|
|
|
|
getGoods() {
|
|
|
|
|
getGoodsList().then(res => {
|
|
|
|
|
this.goodsList = res.data.data.records;
|
|
|
|
|
});
|
|
|
|
|
},
|
|
|
|
|
selectionChange(list) {
|
|
|
|
|
this.selectionList = list;
|
|
|
|
|
},
|
|
|
|
|
uniqueByKeys(arr, keys) {
|
|
|
|
|
const seen = new Set();
|
|
|
|
|
return arr.filter(item => {
|
|
|
|
|
// 生成唯一键,例如 "1-A123" 或 "1||A123"(避免字段值包含分隔符冲突)
|
|
|
|
|
const keyValue = keys.map(k => item[k]).join('||');
|
|
|
|
|
if (seen.has(keyValue)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
seen.add(keyValue);
|
|
|
|
|
return true;
|
|
|
|
|
});
|
|
|
|
|
},
|
|
|
|
|
changeCode() {
|
|
|
|
|
scanIssue({
|
|
|
|
|
cardNo: this.formInline.orderId,
|
|
|
|
|
}).then(res => {
|
|
|
|
|
console.log('res------------', res);
|
|
|
|
|
let data_ = res.data.data;
|
|
|
|
|
// data_[0].outQty =data_.requireQty
|
|
|
|
|
data_.forEach(item => {
|
|
|
|
|
item.outQty = item.requireQty;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
let data = [...res.data.data, ...this.data];
|
|
|
|
|
this.data = this.uniqueByKeys(data, ['id', 'cardNo']);
|
|
|
|
|
if (this.data.length > 0) {
|
|
|
|
|
this.data.map(item => {
|
|
|
|
|
getWarehouseList({
|
|
|
|
|
goodsCode: item.goodsCode,
|
|
|
|
|
}).then(res => {
|
|
|
|
|
item.shList = res.data.data;
|
|
|
|
|
});
|
|
|
|
|
getLocationData({
|
|
|
|
|
goodsId: item.goodsId,
|
|
|
|
|
shId: item.shId,
|
|
|
|
|
}).then(res => {
|
|
|
|
|
let data = this.uniqueById(res.data.data.records);
|
|
|
|
|
item.slList = data;
|
|
|
|
|
});
|
|
|
|
|
getLocationData({
|
|
|
|
|
goodsId: item.goodsId,
|
|
|
|
|
shId: item.shId,
|
|
|
|
|
slId: item.slId,
|
|
|
|
|
}).then(res => {
|
|
|
|
|
item.piNoList = res.data.data.records;
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
changeGoods(val, index) {
|
|
|
|
|
let tmp = this.goodsList.find(item => item.goodsCode == val);
|
|
|
|
|
console.log('tmp------------', tmp);
|
|
|
|
|
console.log('index------------', index);
|
|
|
|
|
this.data[index].goodsName = tmp.goodsName;
|
|
|
|
|
this.data[index].goodsId = tmp.id;
|
|
|
|
|
this.data[index].shId = '';
|
|
|
|
|
this.data[index].slId = '';
|
|
|
|
|
this.data[index].stockQty = '';
|
|
|
|
|
this.data[index].outQty = '';
|
|
|
|
|
|
|
|
|
|
getWarehouseList({
|
|
|
|
|
goodsCode: val,
|
|
|
|
|
}).then(res => {
|
|
|
|
|
this.data[index].shList = res.data.data;
|
|
|
|
|
});
|
|
|
|
|
},
|
|
|
|
|
uniqueById(arr) {
|
|
|
|
|
const seen = new Map();
|
|
|
|
|
for (const item of arr) {
|
|
|
|
|
if (!seen.has(item.slId)) {
|
|
|
|
|
seen.set(item.slId, item);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return Array.from(seen.values());
|
|
|
|
|
},
|
|
|
|
|
changeWare(val, index) {
|
|
|
|
|
this.data[index].stockQty = '';
|
|
|
|
|
this.data[index].slId = '';
|
|
|
|
|
getLocationData({
|
|
|
|
|
goodsId: this.data[index].goodsId,
|
|
|
|
|
shId: val,
|
|
|
|
|
}).then(res => {
|
|
|
|
|
let data = this.uniqueById(res.data.data.records);
|
|
|
|
|
this.data[index].slList = data;
|
|
|
|
|
});
|
|
|
|
|
},
|
|
|
|
|
changeLocation(val, index) {
|
|
|
|
|
console.log('val', val);
|
|
|
|
|
this.data[index].piNo = '';
|
|
|
|
|
this.data[index].stockQty = '';
|
|
|
|
|
getLocationData({
|
|
|
|
|
goodsId: this.data[index].goodsId,
|
|
|
|
|
shId: this.data[index].shId,
|
|
|
|
|
slId: val,
|
|
|
|
|
}).then(res => {
|
|
|
|
|
this.data[index].piNoList = res.data.data.records;
|
|
|
|
|
});
|
|
|
|
|
},
|
|
|
|
|
changePiNo(val, index) {
|
|
|
|
|
console.log('val', val);
|
|
|
|
|
console.log('index', index);
|
|
|
|
|
let tmp = this.data[index].piNoList.find(item => item.piNo == val);
|
|
|
|
|
console.log('tmp=======', tmp);
|
|
|
|
|
this.data[index].stockQty = tmp.usableQuantity;
|
|
|
|
|
this.data[index].rlsId = tmp.id;
|
|
|
|
|
},
|
|
|
|
|
closeDialog(val) {
|
|
|
|
|
this.openShow = false;
|
|
|
|
|
this.$emit('closeDialog', val);
|
|
|
|
|
},
|
|
|
|
|
submit() {
|
|
|
|
|
// 1. 校验逻辑:遍历数据,检查出库数量是否超标
|
|
|
|
|
const invalidRow = this.data.filter(row => {
|
|
|
|
|
// 获取需求数量,默认为0防止undefined
|
|
|
|
|
const requireQty = row.requireQty || 0;
|
|
|
|
|
// 获取当前出库数量,默认为0
|
|
|
|
|
const outQty = row.outQty || 0;
|
|
|
|
|
|
|
|
|
|
// 计算允许的最大出库数量 (需求 + 需求的20%)
|
|
|
|
|
const maxAllowedQty = requireQty + requireQty * 0.2;
|
|
|
|
|
|
|
|
|
|
// 如果出库数量大于允许的最大值,则视为无效行
|
|
|
|
|
return outQty > maxAllowedQty;
|
|
|
|
|
});
|
|
|
|
|
console.log(898989898,invalidRow)
|
|
|
|
|
|
|
|
|
|
// 2. 如果存在超标数据,提示用户并终止提交
|
|
|
|
|
if (invalidRow) {
|
|
|
|
|
// 重新计算该行的最大允许数量用于提示
|
|
|
|
|
const requireQty = invalidRow[0].requireQty;
|
|
|
|
|
const maxAllowedQty = requireQty + (requireQty * 0.2);
|
|
|
|
|
|
|
|
|
|
// 提取标识符用于提示
|
|
|
|
|
const identifier = invalidRow[0].cardNo;
|
|
|
|
|
|
|
|
|
|
this.$message.error(
|
|
|
|
|
`流程卡/零件 [${identifier}] 的出库数量超过允许最大值 (${maxAllowedQty.toFixed(0)}),请调整后重试!`
|
|
|
|
|
);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
// 校验通过:准备提交数据(过滤无用字段)
|
|
|
|
|
const submitData = this.data.map(row => {
|
|
|
|
|
const { _select, shList, slList, piNoList, ...validData } = row; // 剔除选择状态字段
|
|
|
|
|
return validData;
|
|
|
|
|
});
|
|
|
|
|
console.log('submitData', submitData);
|
|
|
|
|
|
|
|
|
|
batchIssue(submitData).then(res => {
|
|
|
|
|
if (res.data.code === 200) {
|
|
|
|
|
this.$message.success('出库成功');
|
|
|
|
|
this.closeDialog(true);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
// this.$message.success('提交成功')
|
|
|
|
|
// this.openShow = false
|
|
|
|
|
},
|
|
|
|
|
delFn() {
|
|
|
|
|
if (this.selectionList.length == 0) {
|
|
|
|
|
this.$message.error('请至少选择一条数据');
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this.$confirm('确定将选择数据删除?', {
|
|
|
|
|
confirmButtonText: '确定',
|
|
|
|
|
cancelButtonText: '取消',
|
|
|
|
|
type: 'warning',
|
|
|
|
|
}).then(() => {
|
|
|
|
|
// 1. 提取 arr2 中所有 id,放入 Set(提高查找效率)
|
|
|
|
|
const arr2Ids = new Set(this.selectionList.map(item => item.id));
|
|
|
|
|
|
|
|
|
|
// 2. 过滤 arr1:只保留 id 不在 arr2Ids 中的项
|
|
|
|
|
const result = this.data.filter(item => !arr2Ids.has(item.id));
|
|
|
|
|
this.data = result;
|
|
|
|
|
// return removeApiScope(this.scopeIds);
|
|
|
|
|
});
|
|
|
|
|
},
|
|
|
|
|
cellClick(row, column, cell, event) {
|
|
|
|
|
if (column.property === 'actualPartCode' || column.property === 'goodsKuwei') {
|
|
|
|
|
this.$refs.crud.rowCellEdit(row, column);
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
onLoad() {
|
|
|
|
|
if (JSON.stringify(this.rowItem) !== '{}') {
|
|
|
|
|
this.data = [{ ...this.rowItem }];
|
|
|
|
|
getWarehouseList({
|
|
|
|
|
goodsCode: this.rowItem.goodsCode,
|
|
|
|
|
}).then(res => {
|
|
|
|
|
this.data[0].shList = res.data.data;
|
|
|
|
|
});
|
|
|
|
|
getLocationData({
|
|
|
|
|
goodsId: this.data[0].goodsId,
|
|
|
|
|
shId: this.data[0].shId,
|
|
|
|
|
}).then(res => {
|
|
|
|
|
let data = this.uniqueById(res.data.data.records);
|
|
|
|
|
this.data[0].slList = data;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
</script>
|
|
|
|
|
<style lang="scss" scoped></style>
|