529 lines
16 KiB
Vue
529 lines
16 KiB
Vue
<template>
|
||
<view>
|
||
<uni-collapse>
|
||
<uni-forms ref="form" :modelValue="formData" :rules="rules" label-align="right">
|
||
<uni-collapse-item title="直接入库单" :open="true">
|
||
<uni-forms-item label="工单" :labelWidth='80' name="workOrderCode">
|
||
<uni-easyinput suffixIcon="scan" @iconClick="scanWorkOrderCode" @change="handleChangeWorkOrderCode"
|
||
v-model="workOrderCode" type="text" />
|
||
</uni-forms-item>
|
||
<uni-forms-item label="产品入库任务单" :labelWidth='80' name="productInTaskCode">
|
||
<uni-easyinput @change="fetchTaskInfo" v-model="formData.productInTaskCode" />
|
||
</uni-forms-item>
|
||
<uni-forms-item label="上架员" :labelWidth='80' name="shelfPutBy">
|
||
<uni-easyinput suffixIcon="scan" @iconClick="scanPutBy" v-model="formData.shelfPutBy" type="text" />
|
||
<uni-data-picker popup-title="选择上架员" :localdata="dataTree" v-model="pickerData" @change="onchange"
|
||
@nodeclick="onnodeclick" @popupopened="onpopupopened" @popupclosed="onpopupclosed" placeholder="选择上架员"
|
||
class="putByPicker" :preload="true">
|
||
</uni-data-picker>
|
||
</uni-forms-item>
|
||
<uni-forms-item label="入库方式" :labelWidth='80'>
|
||
<uni-data-checkbox v-model="value" :localdata="pdcInTypeOptions" class="pdcInType" />
|
||
</uni-forms-item>
|
||
<span v-if="value=='扫物料标签' && formData.wmsProductInDetailList.length == 0" class="scanMatLabel">
|
||
<button size="mini" type="primary" class="scanMatLabelBtn" @click="show=!show">
|
||
添加物料标签
|
||
</button>
|
||
</span>
|
||
<u-modal :show="show" title="扫描物料标签编码" showCancelButton closeOnClickOverlay @cancel="cancelMaterialLabel"
|
||
@close="cancelMaterialLabel" :showConfirmButton="false">
|
||
<uni-easyinput suffixIcon="scan" @iconClick="scanBarMaterialLabel" v-model="materialLabel" type="text"
|
||
@confirm="confirmMaterialLabel" maxlength="-1" focus="true" />
|
||
</u-modal>
|
||
</uni-collapse-item>
|
||
<uni-collapse-item title="直接入库单明细" :open="true">
|
||
<uni-swipe-action>
|
||
<uni-swipe-action-item :rightOptions="rightOptions" :key="index"
|
||
v-for="(item, index) in formData.wmsProductInDetailList" @click="(data) => clickDetail(index,data)"
|
||
@change="swipChange">
|
||
<uni-badge :text="index+1" type="primary"></uni-badge>
|
||
<uni-forms-item label="物料编码" :labelWidth='90' :name="'wmsProductInDetailList.'+ index +'.materialCode'">
|
||
<uni-easyinput type="text" disabled v-model="item.materialCode"></uni-easyinput>
|
||
</uni-forms-item>
|
||
<uni-forms-item label="物料名称" :labelWidth='90' :name="'wmsProductInDetailList.'+ index +'.materialName'">
|
||
<uni-easyinput type="text" disabled v-model="item.materialName"></uni-easyinput>
|
||
</uni-forms-item>
|
||
<uni-forms-item label="物料批号" :labelWidth='90' name="'wmsProductInDetailList.'+ index +'.materialBatchNo'">
|
||
<uni-easyinput type="text" v-model="item.materialBatchNo" />
|
||
</uni-forms-item>
|
||
<uni-forms-item label="物料箱号" :labelWidth='90' name="'wmsProductInDetailList.'+ index +'.materialLotNo'">
|
||
<uni-easyinput disabled type="text" v-model="item.materialLotNo" />
|
||
</uni-forms-item>
|
||
<uni-forms-item label="类型" :labelWidth='90' name="'wmsProductInDetailList.'+ index +'.type'">
|
||
<uni-tag v-if="item.type == 1" text="合格" type="success"></uni-tag>
|
||
<uni-tag v-else-if="item.type == 2" text="不良" type="warning"></uni-tag>
|
||
<uni-tag v-else-if="item.type == 3" text="报废" type="error"></uni-tag>
|
||
</uni-forms-item>
|
||
<uni-forms-item label="推荐库位" :label-width="90" ref="myInput">
|
||
<uni-easyinput type="text" class="uni-mt-5" v-model="item.recommendLocation" disabled>
|
||
<template #right>
|
||
<uni-icons custom-prefix="iconfont" type="icon-fuzhi" size="40"
|
||
@click="clickCopy(index)"></uni-icons>
|
||
</template>
|
||
</uni-easyinput>
|
||
</uni-forms-item>
|
||
<uni-forms-item label="库位条码" :labelWidth='90'
|
||
name="'wmsProductInDetailList.'+ index +'.storageLocationBarcode'">
|
||
<uni-easyinput suffixIcon="scan" @iconClick="scanBarstorageLocationBarcode(index)" type="text"
|
||
v-model="item.storageLocationBarcode" />
|
||
</uni-forms-item>
|
||
<uni-forms-item label="上架数量" :labelWidth='90' name="'wmsProductInDetailList.'+ index +'number'">
|
||
<uni-easyinput disabled type="text" v-model="item.number" v-if="value == '扫物料标签'" />
|
||
<u-number-box inputWidth="120" button-size="36" v-model="item.number" :min="0" :max="item.notInNumber" v-else></u-number-box>
|
||
</uni-forms-item>
|
||
</uni-swipe-action-item>
|
||
</uni-swipe-action>
|
||
</uni-collapse-item>
|
||
</uni-forms>
|
||
</uni-collapse>
|
||
<view class="opt">
|
||
<button @click="clickCopy">一键复制</button>
|
||
<button type="primary" @click="submit">提交</button>
|
||
</view>
|
||
</view>
|
||
</template>
|
||
|
||
<script>
|
||
import {
|
||
addIn,
|
||
listTask,
|
||
getTask,
|
||
getReveive,
|
||
getDetails,
|
||
listReceiveDetail,
|
||
getDetail,
|
||
directProductInByTaskDetail,
|
||
getConnectLoc
|
||
} from "@/api/wms/pdcIn.js";
|
||
import { listDepartment } from "@/api/basic/department";
|
||
import { listEmployee } from "@/api/mes/jobIn.js";
|
||
import { listWarehouse } from "@/api/wms/warehouse";
|
||
import { listStock } from "@/api/wms/stock.js";
|
||
import { getConfigKey } from "@/api/system/config.js"
|
||
import { getMaterial_code } from "@/api/wms/purchase.js";
|
||
import { listLocation } from '@/api/basic/location';
|
||
|
||
export default {
|
||
mounted() {
|
||
// 获取部门列表
|
||
listDepartment().then((res) => {
|
||
this.dptList = res.rows
|
||
})
|
||
// 获取员工列表
|
||
listEmployee().then((res) => {
|
||
this.empList = res.rows
|
||
})
|
||
// 获取参数: 库位显示级数
|
||
getConfigKey('wms.location.size').then(res => {
|
||
this.locationSize = res.msg
|
||
})
|
||
},
|
||
data() {
|
||
return {
|
||
locationSize: null,
|
||
value: '正常',
|
||
show: false,
|
||
materialLabel: null,
|
||
workOrderCode: '',
|
||
legalLocation: true,
|
||
dptList: [],
|
||
empList: [],
|
||
item: '',
|
||
dataTree: [],
|
||
pickerData: '',
|
||
formData: {
|
||
billType: '2',
|
||
status: '3',
|
||
productInTaskCode: '',
|
||
shelfPutBy: null,
|
||
wmsProductInDetailList: [],
|
||
},
|
||
//类型
|
||
pdcInTypeOptions: [
|
||
{ text: '正常', value: '正常' },
|
||
{ text: '扫物料标签', value: '扫物料标签' },
|
||
],
|
||
typeOptions: [{
|
||
value: 1,
|
||
label: "合格",
|
||
},
|
||
{
|
||
value: 2,
|
||
label: "不良",
|
||
},
|
||
{
|
||
value: 3,
|
||
label: "报废",
|
||
},
|
||
],
|
||
rightOptions: [{
|
||
text: '删除',
|
||
style: {
|
||
backgroundColor: '#ff2a17'
|
||
}
|
||
}, ],
|
||
rules: {
|
||
productInTaskCode: {
|
||
rules: [{
|
||
required: true,
|
||
errorMessage: '请输入产品入库任务单!'
|
||
}]
|
||
},
|
||
shelfPutBy: {
|
||
rules: [{
|
||
required: false,
|
||
errorMessage: '请输入上架员编码!'
|
||
}]
|
||
}
|
||
}
|
||
}
|
||
},
|
||
methods: {
|
||
// 工单改变
|
||
handleChangeWorkOrderCode() {
|
||
// 重置任务单编码
|
||
this.formData.productInTaskCode = '';
|
||
// 重置明细
|
||
this.formData.wmsProductInDetailList = [];
|
||
},
|
||
// 扫描工单号
|
||
scanWorkOrderCode() {
|
||
const _this = this;
|
||
uni.scanCode({
|
||
scanType: ['barCode', 'qrCode'],
|
||
success: function(res) {
|
||
_this.workOrderCode = res.result;
|
||
_this.handleChangeWorkOrderCode();
|
||
}
|
||
});
|
||
},
|
||
onnodeclick(e) {
|
||
this.item = e
|
||
this.onchange(this.item)
|
||
},
|
||
onpopupopened(e) {
|
||
this.dataTree = []
|
||
this.empList.filter(item => item.deptId).forEach(item => {
|
||
item.departmentTitle = this.dptList.find(item2 => item2.id == item.deptId).departmentTitle
|
||
// 检查dataTree中是否已存在相同部门
|
||
let existingDept = this.dataTree.find(dept => dept.value === item.deptId);
|
||
if (existingDept) {
|
||
// 如果已存在相同部门,则将员工信息push进该部门的children数组
|
||
existingDept.children.push({
|
||
text: item.name,
|
||
value: item.empCode
|
||
});
|
||
} else {
|
||
// 如果不存在相同部门,则创建一个新部门对象,包括children数组,并将员工信息push进去
|
||
let newDept = {
|
||
text: item.departmentTitle,
|
||
value: item.deptId,
|
||
children: [{
|
||
text: item.name,
|
||
value: item.empCode
|
||
}]
|
||
};
|
||
this.dataTree.push(newDept);
|
||
}
|
||
})
|
||
},
|
||
onchange(e) {
|
||
this.formData.shelfPutBy = null
|
||
this.$set(this.formData, 'shelfPutBy', e.value.split('/')[0])
|
||
},
|
||
cancelMaterialLabel() {
|
||
this.materialLabel = null;
|
||
this.show = false;
|
||
},
|
||
confirmMaterialLabel(data) {
|
||
data = JSON.parse(data)
|
||
if (data) {
|
||
this.id = data.id
|
||
getDetail(data.id).then(res => {
|
||
if (res.data) {
|
||
this.formData.productInTaskCode = res.data.productInTaskCode;
|
||
let obj = {
|
||
materialCode: res.data.materialCode,
|
||
materialName: res.data.materialName,
|
||
materialBatchNo: res.data.materialBatchNo,
|
||
materialLotNo: res.data.materialLotNo,
|
||
type: res.data.type,
|
||
storageLocationBarcode: res.data.storageLocationBarcode,
|
||
number: res.data.number
|
||
}
|
||
this.formData.wmsProductInDetailList.push(obj)
|
||
this.materialLabel = null;
|
||
this.show = false;
|
||
} else {
|
||
this.$modal.msg("未查询到该条物料明细!")
|
||
}
|
||
})
|
||
}
|
||
},
|
||
scanBarMaterialLabel() {
|
||
const _this = this;
|
||
uni.scanCode({
|
||
scanType: ['barCode', 'qrCode'],
|
||
success: function(res) {
|
||
_this.materialLabel = res.result;
|
||
// console.log(materialLabel)
|
||
_this.confirmMaterialLabel(_this.materialLabel);
|
||
}
|
||
});
|
||
},
|
||
// 验证库位合法性
|
||
async validateLocation(item) {
|
||
const code = item.storageLocationBarcode
|
||
if (!code) return false
|
||
if (['2', '4'].includes(this.locationSize)) return true
|
||
|
||
let fullLocation = null
|
||
|
||
if (this.locationSize == '0') {
|
||
fullLocation = code
|
||
} else if (this.locationSize == '5') {
|
||
// 用两级库位查完整库位
|
||
const res = await listLocation({
|
||
storageShelvesCode: code.split('-')[0],
|
||
storageLocationCode: code.split('-').slice(1).join('-')
|
||
})
|
||
fullLocation = res.rows[0]?.storageLocationBarcode || null
|
||
}
|
||
|
||
const data = await getConnectLoc({ connectLoc: fullLocation })
|
||
if (data.data) {
|
||
item.whCode = fullLocation.split('-')[0] || null
|
||
item.areaCode = fullLocation.split('-')[1] || null
|
||
item.shelvesCode = fullLocation.split('-')[2] || null
|
||
item.storageLocationCode = fullLocation.split('-').slice(3).join('-') || null
|
||
} else {
|
||
this.$modal.msg("库位条码校验错误,请重新输入!")
|
||
}
|
||
return data.data
|
||
},
|
||
// 扫描库位编码
|
||
scanBarstorageLocationBarcode(i) {
|
||
const _this = this;
|
||
uni.scanCode({
|
||
scanType: ['barCode', 'qrCode'],
|
||
success: function(res) {
|
||
_this.$set(_this.formData.wmsProductInDetailList[i], "storageLocationBarcode", res.result);
|
||
}
|
||
});
|
||
},
|
||
// 依次获取推荐库位
|
||
async fetchLocation(taskDetail) {
|
||
const promises = taskDetail.map(async (item) => {
|
||
if (!item.materialCode) {
|
||
return {
|
||
...item,
|
||
recommend: null,
|
||
recommendLocation: null
|
||
}
|
||
}
|
||
const res = await getMaterial_code(item.materialCode);
|
||
// 提供默认值以防 res 为 null 或 undefined
|
||
const { data } = res || {};
|
||
const recommend = data || null;
|
||
const recommendLocation = data ? this.getRecommend(data) : null;
|
||
|
||
return { ...item, recommend, recommendLocation };
|
||
});
|
||
|
||
// 等待所有异步操作完成
|
||
const updatedList = await Promise.all(promises);
|
||
return updatedList;
|
||
},
|
||
async fetchTaskInfo() {
|
||
// 清空明细单列表
|
||
this.formData.wmsProductInDetailList = [];
|
||
if (!this.formData.productInTaskCode) return;
|
||
|
||
let taskId = null;
|
||
let taskDetail = [];
|
||
|
||
// 获取任务单 id
|
||
await listTask({
|
||
productInTaskCode: this.formData.productInTaskCode
|
||
}).then(res => {
|
||
taskId = res.rows[0].id
|
||
}).catch(err => {
|
||
console.error(`获取入库任务单号为${this.formData.productInTaskCode}的任务单 id 失败,详情:${err}`);
|
||
})
|
||
|
||
// 根据任务单 id 获取任务单明细
|
||
await getTask(taskId).then(res => {
|
||
taskDetail = res.data.wmsProductInTaskDetailList.filter(item => item.notInNumber);
|
||
}).catch(err => {
|
||
console.error(`获取入库任务单 id 为${taskId}的任务单明细失败,详情:${err}`);
|
||
})
|
||
if (taskDetail.length === 0) return
|
||
|
||
// 获取推荐库位
|
||
this.formData.wmsProductInDetailList = await this.fetchLocation(taskDetail)
|
||
console.log("明细单列表: ", this.formData.wmsProductInDetailList)
|
||
},
|
||
// 上架员
|
||
scanPutBy() {
|
||
const _this = this;
|
||
uni.scanCode({
|
||
scanType: ['qrCode', 'barCode'],
|
||
success: function(res) {
|
||
_this.formData.shelfPutBy = res.result;
|
||
}
|
||
});
|
||
},
|
||
// 拆解推荐库位
|
||
getRecommend(recommend) {
|
||
const { whCode, areaCode, shelvesCode, storageLocationCode } = recommend
|
||
if (!(whCode || areaCode || shelvesCode || storageLocationCode)) return null
|
||
|
||
switch (this.locationSize) {
|
||
case '0':
|
||
return [whCode, areaCode, shelvesCode, storageLocationCode].join('-')
|
||
case '2':
|
||
return areaCode
|
||
case '4':
|
||
return storageLocationCode
|
||
case '5':
|
||
return [shelvesCode, storageLocationCode].join('-')
|
||
}
|
||
},
|
||
// 校验明细单各项库位是否为空
|
||
checkLocation() {
|
||
this.formData.wmsProductInDetailList.forEach(item => {
|
||
if (!item.storageLocationBarcode) {
|
||
this.$modal.msg("库位条码不允许为空")
|
||
return false
|
||
}
|
||
})
|
||
return true
|
||
},
|
||
// 提交
|
||
async submit() {
|
||
const _this = this;
|
||
if (!this.checkLocation()) return
|
||
_this.$modal.loading('校验库位中')
|
||
await _this.formData.wmsProductInDetailList.forEach(async item => {
|
||
// 避免明细传递失败,删除明细 id
|
||
delete item.id;
|
||
if (!item.storageLocationBarcode) {
|
||
this.$modal.msg("库位条码不允许为空");
|
||
return;
|
||
}
|
||
const res = await _this.validateLocation(item)
|
||
if (!res) {
|
||
item.storageLocationBarcode = null
|
||
this.$modal.msg("库位条码校验错误,请重新输入!")
|
||
return
|
||
}
|
||
})
|
||
_this.$modal.closeLoading()
|
||
this.$refs.form.validate().then(res => {
|
||
uni.showModal({
|
||
title: '提示',
|
||
content: '您确定完成直接入库吗?',
|
||
success: function(res) {
|
||
if (res.confirm) {
|
||
if (_this.value == '扫物料标签') {
|
||
let obj = {
|
||
id: _this.id,
|
||
whCode: _this.formData.wmsProductInDetailList[0].whCode,
|
||
areaCode: _this.formData.wmsProductInDetailList[0]
|
||
.areaCode,
|
||
shelvesCode: _this.formData.wmsProductInDetailList[0]
|
||
.shelvesCode,
|
||
storageLocationCode: _this.formData.wmsProductInDetailList[
|
||
0].storageLocationCode
|
||
}
|
||
_this.$modal.loading('提交中')
|
||
directProductInByTaskDetail(obj).then(async res => {
|
||
_this.$modal.closeLoading();
|
||
_this.$modal.msgSuccess("入库成功!");
|
||
_this.$tab.switchTab('/pages/work/index');
|
||
});
|
||
} else {
|
||
if (_this.formData.productInTaskCode) {
|
||
_this.$modal.loading('提交中')
|
||
addIn(_this.formData).then(async res => {
|
||
_this.$modal.closeLoading();
|
||
_this.$modal.msgSuccess("入库成功!");
|
||
_this.$tab.switchTab('/pages/work/index');
|
||
});
|
||
}
|
||
}
|
||
} else if (res.cancel) {
|
||
console.log('用户点击取消');
|
||
}
|
||
}
|
||
});
|
||
});
|
||
},
|
||
// 复制库位
|
||
clickCopy(index) {
|
||
// 创建新数组避免引用问题
|
||
const newList = this.formData.wmsProductInDetailList.map(item => ({ ...item }));
|
||
|
||
if (typeof index === 'number') {
|
||
// 复制单个项
|
||
newList[index] = {
|
||
...newList[index],
|
||
storageLocationBarcode: newList[index].recommendLocation,
|
||
whCode: newList[index].recommend.whCode,
|
||
areaCode: newList[index].recommend.areaCode,
|
||
shelvesCode: newList[index].recommend.shelvesCode,
|
||
storageLocationCode: newList[index].recommend.storageLocationCode
|
||
};
|
||
} else {
|
||
// 复制所有项
|
||
newList.forEach(item => {
|
||
item.storageLocationBarcode = item.recommendLocation;
|
||
item.whCode = item.recommend.whCode;
|
||
item.areaCode = item.recommend.areaCode;
|
||
item.shelvesCode = item.recommend.shelvesCode;
|
||
item.storageLocationCode = item.recommend.storageLocationCode;
|
||
});
|
||
}
|
||
|
||
// 创建新对象确保响应式更新
|
||
this.formData = {
|
||
...this.formData,
|
||
wmsProductInDetailList: newList
|
||
};
|
||
}
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style lang="scss" scoped>
|
||
.putByPicker {
|
||
margin-top: 5px;
|
||
}
|
||
|
||
.pdcInType {
|
||
margin-top: 6px;
|
||
}
|
||
|
||
.scanMatLabel {
|
||
display: flex;
|
||
}
|
||
|
||
.scanMatLabel .scanMatLabelBtn {
|
||
justify-content: center;
|
||
font-size: 1.1rem;
|
||
}
|
||
|
||
.opt {
|
||
// position: fixed;
|
||
// bottom: 0;
|
||
width: 100%;
|
||
padding: 2vw 0;
|
||
display: flex;
|
||
justify-content: space-evenly;
|
||
}
|
||
|
||
.opt button {
|
||
flex: 1;
|
||
margin: 0 5px;
|
||
}
|
||
</style> |