<template>
|
<div class="scan-container">
|
<el-card class="scan-card">
|
<div slot="header" class="clearfix">
|
<span>波次打包校验扫描</span>
|
</div>
|
<el-form ref="form" :model="formData" label-width="120px" class="scan-form">
|
<el-form-item label="波次号">
|
<el-input ref="orderPrintCode" v-model="formData.orderPrintCode" autofocus class="input-300" @keyup.native.enter.stop="getData"></el-input>
|
<span class="sub-item">
|
<span class="sub-label">开启装箱:</span>
|
<el-switch v-model="formData.isOpenCase" @change="onIsOpenCase"></el-switch>
|
</span>
|
</el-form-item>
|
<el-form-item v-if="formData.isOpenCase" label="箱号">
|
<el-input v-model="formData.caseNumber" class="input-300" @keyup.native.enter.stop="onKeyupCaseNumber"></el-input>
|
<el-radio-group v-model="formData.caseMode" @change="onCaseMode">
|
<el-radio :label="1">一品一箱</el-radio>
|
<el-radio :label="2">多品一箱</el-radio>
|
</el-radio-group>
|
</el-form-item>
|
<el-form-item label="物料条码">
|
<el-input ref="productModel" v-model="formData.productModel" class="input-300" @keyup.native.enter.stop="checkPackingBarcode"></el-input>
|
<span v-if="!(formData.isOpenCase && formData.caseMode === 1)" class="sub-item">
|
<span class="sub-label">扫描数量:</span>
|
<el-input-number v-model="formData.scanQty" :min="0" controls-position="right" class="input-120" @change="setScanQty"></el-input-number>
|
</span>
|
</el-form-item>
|
<el-form-item label="称重">
|
<el-input v-model="formData.weight" autofocus class="input-300"></el-input>
|
</el-form-item>
|
<el-form-item v-if="formData.isOpenCase" label="选择打印机">
|
<el-select v-model="formData.printerName" placeholder="请选择打印机" class="w-300" @change="changePrint">
|
<el-option v-for="(item, index) in printList" :key="index" :label="item" :value="item"></el-option>
|
</el-select>
|
</el-form-item>
|
<el-form-item>
|
<el-button v-if="formData.isOpenCase" @click="changeBox">换箱</el-button>
|
<el-button type="primary" @click="onSubmit">复核提交</el-button>
|
<el-button @click="onReset">重置</el-button>
|
<el-checkbox v-if="formData.isOpenCase" v-model="formData.isOuter_Packinglist" @change="outerPacking">打印装箱清单</el-checkbox>
|
</el-form-item>
|
</el-form>
|
</el-card>
|
<el-card class="scan-card body-no-padding">
|
<div slot="header" class="clearfix">
|
<span class="padding-top-10">扫描结果</span>
|
<el-button type="text" class="floatRight" @click="setting.visible = true">字段设置</el-button>
|
</div>
|
<el-table ref="scan-table" :data="tableData" :row-class-name="rowClass" stripe style="width: 100%" class="scan-table" @row-click="setCurrent">
|
<template v-for="(item, index) in setting.fields">
|
<template v-if="
|
['unFinishedQuantity', 'finishedQuantity'].indexOf(item.prop) >= 0
|
">
|
<el-table-column v-if="item.visible" :key="index" :prop="item.prop" :label="item.label" :width="item.width">
|
<template slot-scope="scope">
|
<template v-if="!formData.isValidateProductCode">
|
<el-input-number v-model="scope.row[item.prop]" :min="0" :max="scope.row['Quantity']" size="mini" class="w-100pc" controls-position="right" @change="rowChangeQty(item.prop, scope.row)"></el-input-number>
|
</template>
|
<template v-else>
|
{{ scope.row[item.prop] }}
|
</template>
|
</template>
|
</el-table-column>
|
</template>
|
<template v-else-if="'positionName,scanWeight'.indexOf(item.prop) >= 0">
|
<el-table-column v-if="item.visible" :key="index" :prop="item.prop" :label="item.label" :width="item.width">
|
<template slot-scope="scope">
|
<template>
|
<el-input v-model="scope.row[item.prop]" size="mini" class="w-100pc"></el-input>
|
</template>
|
</template>
|
</el-table-column>
|
</template>
|
<template v-else-if="'produceDate,limitDate'.indexOf(item.prop) >= 0">
|
<el-table-column v-if="item.visible" :key="index" :prop="item.prop" :label="item.label" :width="item.width">
|
<template slot-scope="scope">
|
<template>
|
<el-date-picker v-model="scope.row[item.prop]" size="mini" type="date" placeholder="选择日期" class="w-110" value-format="yyyy-MM-dd">
|
</el-date-picker>
|
</template>
|
</template>
|
</el-table-column>
|
</template>
|
<template v-else-if="'caseNumber'.indexOf(item.prop) >= 0">
|
<el-table-column v-if="item.visible && formData.isOpenCase" :key="index" :prop="item.prop" :label="item.label" :width="item.width">
|
</el-table-column>
|
</template>
|
<template v-else>
|
<el-table-column v-if="item.visible" :key="index" :prop="item.prop" :label="item.label" :width="item.width">
|
</el-table-column>
|
</template>
|
</template>
|
</el-table>
|
</el-card>
|
|
<scan-setting-dialog ref="setting-dialog" :visible.sync="setting.visible" :fields="setting.fields" :name="setting.name">
|
</scan-setting-dialog>
|
<!-- 显示打印装箱清单模板 -->
|
<div id="mount-print"></div>
|
|
<!--声音文件-->
|
<audio ref="sound_error" controls="controls" style="display:none;">
|
<source src="@/assets/sounds/error2.mp3" type="audio/mpeg" />
|
</audio>
|
<audio ref="sound_correct" controls="controls" style="display:none;">
|
<source src="@/assets/sounds/feixin.mp3" type="audio/mpeg" />
|
</audio>
|
<audio ref="sound_scan" controls="controls" style="display:none;">
|
<source src="@/assets/sounds/saomiao.wav" type="audio/mpeg" />
|
</audio>
|
</div>
|
</template>
|
|
<script>
|
import { getLodop } from "@/utils/LodopFuncs";
|
import Vue from "vue";
|
import PrintCase from "@/views/sys/print/base-fenjianji";
|
import YrtScanMixins from "@/components/common/yrtScanMixins.vue";
|
import ScanSettingDialog from "@/components/common/components/scanSettingDialog.vue";
|
var moment = require("moment");
|
|
export default {
|
name: "outbound-scan-out-scan-batch",
|
components: {
|
PrintCase,
|
ScanSettingDialog
|
},
|
mixins: [YrtScanMixins],
|
data() {
|
return {
|
// 配置参数
|
config: {
|
// 自动生成上架单
|
in_generateShelve: true,
|
// 是否启用装箱操作
|
in_caseNumber: false,
|
// 支持一品多码
|
sku_productToMultiBarcode: true,
|
caseMode: 0,
|
// 称重阈值
|
outer_weightWhreshold: 0
|
},
|
formData: {
|
orderPrintCode: "",
|
weight: null,
|
productModel: null, // 物料条码
|
allotPositionName: null, // 配货位
|
scanQty: 0, // 扫描数量
|
caseNumber: null, // 箱号
|
isOpenCase: false, // 开启装箱
|
// 装箱方式:0:常规扫描,1:一品一箱,2:多品一箱
|
caseMode: 0,
|
// 打印面单
|
isOuter_PrintBill: false,
|
// 打印装箱清单
|
isOuter_Packinglist: false,
|
wrapperBarcode: ""
|
},
|
// 订单信息
|
orderInfo: null,
|
// 明细数据
|
tableData: [],
|
// 当前正在扫描的数据
|
currentRow: {},
|
// 已经找到的数据
|
existRows: [],
|
// 装箱方式:0:常规扫描,1:一品一箱,2:多品一箱
|
caseMode: 0,
|
// 一次扫描的数量
|
scanCount: 1,
|
// 装箱新增行
|
caseNewRows: [],
|
// 打印机设备列表
|
printList: [],
|
// 扫描列设置对话框参数
|
setting: {
|
visible: false,
|
name: "outbound-scan-out-scan-batch",
|
fields: [
|
{
|
prop: "orderCode",
|
label: "订单号",
|
visible: true,
|
width: 140,
|
order: 1
|
},
|
{
|
prop: "productModel",
|
label: "条形码",
|
visible: true,
|
width: 140,
|
order: 2
|
},
|
{
|
prop: "quantityOrder",
|
label: "物料数量",
|
visible: true,
|
width: 90,
|
order: 3
|
},
|
{
|
prop: "quantityOuter",
|
label: "已出库数量",
|
visible: true,
|
width: 100,
|
order: 4
|
},
|
{
|
prop: "finishedQuantity",
|
label: "已扫描数量",
|
visible: true,
|
width: 120,
|
order: 5
|
},
|
{
|
prop: "unFinishedQuantity",
|
label: "未扫描数量",
|
visible: true,
|
width: 130,
|
order: 6
|
},
|
{
|
prop: "salePrice",
|
label: "单价",
|
visible: true,
|
width: 100,
|
order: 7
|
},
|
|
{
|
prop: "caseNumber",
|
label: "箱号",
|
visible: true,
|
width: 90,
|
order: 8
|
},
|
{
|
prop: "productSpec",
|
label: "物料规格",
|
visible: true,
|
width: 130,
|
order: 9
|
},
|
{
|
prop: "productCode",
|
label: "物料编号",
|
visible: true,
|
width: 130,
|
order: 10
|
},
|
{
|
prop: "weight",
|
label: "单位毛重",
|
visible: false,
|
width: 90,
|
order: 11
|
},
|
{
|
prop: "scanWeight",
|
label: "已扫重量",
|
visible: false,
|
width: 80,
|
order: 12
|
},
|
{
|
prop: "productName",
|
label: "物料名称",
|
visible: true,
|
width: null,
|
order: 13
|
}
|
]
|
}
|
};
|
},
|
// 监听数据
|
watch: {
|
// 当前行扫描数据改变后,将扫描数量也改变
|
currentRow: {
|
handler: function(rowData) {
|
this.formData.scanQty = rowData.finishedQuantity;
|
},
|
deep: true
|
}
|
},
|
activated() {
|
// 开启装箱
|
const isOpenCase = localStorage["out_isOpenCase"];
|
if (isOpenCase) {
|
this.formData.isOpenCase = isOpenCase === "true";
|
const caseMode = localStorage["out_caseMode"] || "0";
|
this.formData.caseMode = parseInt(caseMode);
|
}
|
// 勾选打印装箱
|
const isOuter_Packinglist = localStorage["isOuter_Packinglist"];
|
if (isOuter_Packinglist) {
|
this.formData.isOuter_Packinglist = isOuter_Packinglist === "true";
|
}
|
},
|
mounted() {
|
this.$refs["orderPrintCode"].focus();
|
// 获得打印模板
|
this.getPrintTemplate();
|
// 获取打印机
|
this.getPrintList();
|
// 字段设置
|
const setting = localStorage[this.setting.name + "-setting"];
|
if (setting) {
|
this.setting.fields = JSON.parse(setting);
|
}
|
},
|
methods: {
|
// 是否开启装箱
|
onIsOpenCase() {
|
localStorage["out_isOpenCase"] = this.formData.isOpenCase;
|
if (this.formData.isOpenCase) {
|
const caseMode = localStorage["out_caseMode"] || "0";
|
this.formData.caseMode = parseInt(caseMode);
|
} else {
|
this.formData.caseMode = 0;
|
}
|
},
|
// 切换装箱模式
|
onCaseMode() {
|
localStorage["out_caseMode"] = this.formData.caseMode;
|
},
|
// 箱号回车
|
onKeyupCaseNumber() {
|
this.focus("productModel");
|
},
|
// 获得打印机列表
|
getPrintList() {
|
window.setTimeout(() => {
|
const LODOP = getLodop();
|
var iPrinterCount = LODOP.GET_PRINTER_COUNT();
|
for (var i = 0; i < iPrinterCount; i++) {
|
this.printList.push(LODOP.GET_PRINTER_NAME(i));
|
}
|
// 设置默认打印机
|
const printerName = localStorage["printerName"];
|
if (printerName) {
|
this.formData.printerName = printerName;
|
}
|
}, 1000);
|
},
|
// 获取运单信息和打印机名称
|
getPrintTemplate() {
|
var url = "/api/sys/printTemplate/getPrintTemplate";
|
var params = {
|
openNodeApi: true,
|
menu_Id: 200013 // 打印模板MenuID
|
};
|
this.common.ajax(
|
url,
|
params,
|
res => {
|
this.common.showMsg(res);
|
if (res.result) {
|
this.printCaseVueData = res.data;
|
}
|
},
|
true
|
);
|
},
|
// 打印装箱单
|
printCase() {
|
// 获取装箱数据
|
const caseDataList = this.tableData.filter(item => {
|
item.RowTotal = item.finishedQuantity * item.salePrice;
|
return item.caseNumber === this.formData.caseNumber;
|
});
|
if (!caseDataList.length) {
|
this.$message.error("没有可打印的数据");
|
return;
|
}
|
// 箱号
|
this.orderInfo.caseNumber = this.formData.caseNumber;
|
this.orderInfo.shippingName = this.currentRow.shippingName;
|
this.orderInfo.orderCode = this.currentRow.orderCode;
|
this.orderInfo.shippingAddress = this.currentRow.shippingAddress;
|
this.orderInfo.mobile = this.currentRow.mobile;
|
this.orderInfo.createDate = moment(this.orderInfo.createDate).format("YYYY-MM-DD HH:mm:ss");
|
const billDataInfo = {
|
mainInfo: this.orderInfo,
|
detailList: {
|
total: caseDataList.length,
|
rows: caseDataList
|
}
|
};
|
var Profile = Vue.extend(PrintCase);
|
var m = new Profile({
|
propsData: {
|
vueData: this.printCaseVueData,
|
billDataInfo: billDataInfo,
|
printInfo: {
|
printerName: this.formData.printerName
|
},
|
billCodeField: "orderPrintCode"
|
}
|
}).$mount();
|
var mountPrint = document.getElementById("mount-print");
|
var firstChild = mountPrint.firstChild;
|
mountPrint.insertBefore(m.$el, firstChild);
|
m.lodopPrint();
|
window.setTimeout(() => {
|
document.getElementById(this.orderInfo.orderCode).remove();
|
}, 2 * 60 * 1000);
|
},
|
// 打印机改变
|
changePrint() {
|
localStorage["printerName"] = this.formData.printerName;
|
},
|
// 获得明细数据
|
getData() {
|
var orderPrintCode = this.formData.orderPrintCode;
|
if (!orderPrintCode) {
|
this.$message.error("波次号不能为空");
|
return;
|
}
|
const url = "/api/outbound/outScanBatch/getData";
|
const parment = {
|
openNodeApi: true,
|
orderPrintCode: orderPrintCode
|
};
|
const callback = res => {
|
this.common.showMsg(res);
|
if (res.result) {
|
// 构建数据
|
this.currentRow = {};
|
this.tableData = res.data.map(row => {
|
this.$set(row, "finishedQuantity", 0);
|
this.$set(row, "sortIndex", 0);
|
this.$set(row, "unFinishedQuantity", row.quantityOrder - row.quantityOuter);
|
return row;
|
});
|
this.formData.caseNumber = res.dynamic;
|
this.orderInfo = res.data2;
|
// 条码框获得焦点
|
this.$refs["productModel"].focus();
|
this.$refs["productModel"].select();
|
}
|
};
|
this.common.ajax(url, parment, callback, true);
|
},
|
// 判断扫描包装条码
|
checkPackingBarcode() {
|
var code = this.formData.productModel;
|
if (!code) {
|
this.focus("productModel");
|
this.$message.error("物料条码不能为空!");
|
return;
|
}
|
if (this.formData.isOpenCase && this.formData.caseMode <= 0) {
|
this.focus("productModel");
|
this.$message.error("请选择装箱方式!");
|
return;
|
}
|
|
// 装箱操作
|
if (this.formData.isOpenCase) {
|
if (this.formData.caseMode === 1) {
|
// 一品一箱
|
this.addRow_1();
|
} else if (this.formData.caseMode === 2) {
|
// 多品一箱
|
this.addRow_2();
|
}
|
} else {
|
// 常规扫描
|
this.checkPackingProductModel(this.tableData);
|
}
|
this.focus("productModel");
|
},
|
// 单击选择行数据
|
setCurrent(row, event, column) {
|
if (row.productModel === this.formData.productModel) {
|
this.currentRow = [];
|
this.currentRow = row;
|
this.existRows = [];
|
this.existRows.push(this.currentRow);
|
}
|
},
|
// 提交数据
|
onSubmit() {
|
var orderPrintCode = this.formData.orderPrintCode;
|
var weight = this.formData.weight;
|
if (!this.formData.orderPrintCode) {
|
this.$message.error("请扫描波次单号!");
|
this.$refs.orderPrintCode.focus();
|
this.$refs.sound_error.play(); // 播放声音
|
return;
|
}
|
var dataList = [];
|
|
this.tableData.forEach(rowData => {
|
if (rowData.finishedQuantity <= 0) return;
|
dataList.push({
|
caseNumber: rowData.caseNumber,
|
order_Id: rowData.order_Id,
|
orderCode: rowData.orderCode,
|
orderList_Id: rowData.orderList_Id,
|
scanCount: rowData.finishedQuantity,
|
weight: rowData.weight,
|
totalWeight: rowData.scanWeight
|
});
|
});
|
if (!dataList.length) {
|
this.$message.error("只是需要扫描一条记录");
|
return;
|
}
|
|
// 明细理论求和值
|
let theoryweight = 0;
|
// 明细实际求和值
|
let scanWeight = 0;
|
// 得到设置的阈值
|
const Outer_weightWhreshold = this.config.outer_weightWhreshold;
|
// 对明细已扫描数量求和算出理论值
|
dataList.forEach(item => {
|
theoryweight += item.scanCount * item.weight;
|
});
|
// 直接扫描重量
|
dataList.forEach(item => {
|
scanWeight += Math.Round(item.totalWeight, 2);
|
});
|
const absWeight = Math.abs(theoryweight - scanWeight);
|
if (absWeight > Outer_weightWhreshold) {
|
this.$message.error("物料实际重量与物料理论重量差值超过设定阈值" + Outer_weightWhreshold + ",不允许出库");
|
return;
|
}
|
|
const url = "/api/outbound/outScanBatch/partialSaveScan";
|
const parment = {
|
openNodeApi: true,
|
orderPrintCode: orderPrintCode,
|
dataList: dataList,
|
weight: weight,
|
wrapperBarcode: "",
|
newExpressCode: ""
|
};
|
this.common.ajax(
|
url,
|
parment,
|
res => {
|
this.common.showMsg(res);
|
if (res.result) {
|
this.onReset();
|
}
|
},
|
true
|
);
|
},
|
// 重置
|
onReset() {
|
this.formData.orderPrintCode = null;
|
this.formData.caseNumber = null;
|
this.formData.positionName = null;
|
this.formData.productModel = null;
|
this.formData.scanQty = null;
|
this.tableData = [];
|
this.$refs.orderPrintCode.focus();
|
},
|
// 勾选装箱清单
|
outerPacking() {
|
localStorage["isOuter_Packinglist"] = this.formData.isOuter_Packinglist;
|
},
|
// 换箱
|
changeBox() {
|
var batchNo = this.formData.orderPrintCode;
|
if (batchNo === null) {
|
this.$message({
|
message: "请先扫描出库单号!",
|
type: "warning"
|
});
|
return;
|
}
|
if (!this.currentRow) {
|
this.$message({
|
message: "请先扫描物料信息!",
|
type: "warning"
|
});
|
return;
|
}
|
if (this.formData.isOuter_Packinglist) {
|
// 打印装箱单
|
this.printCase();
|
// 重新生成箱号
|
this.generateCaseNumber();
|
} else {
|
this.$message({
|
message: "请勾选打印装箱清单!",
|
type: "warning"
|
});
|
return;
|
}
|
},
|
// 生成箱号
|
generateCaseNumber() {
|
var batchNo = this.formData.orderPrintCode;
|
var max = 1;
|
var num = this.formData.caseNumber;
|
if (num.indexOf("-") >= 0) {
|
var nums = num.split("-");
|
num = nums[nums.length - 1];
|
} else {
|
num = num.substr(num.length - 4);
|
}
|
num = parseInt(num);
|
++num;
|
if (num > max) max = num;
|
max = "00000" + max;
|
max = max.substr(max.length - 2);
|
var caseNumber = batchNo + "-" + max;
|
this.formData.caseNumber = caseNumber;
|
},
|
// 一品一箱
|
addRow_1() {
|
const rowData = this.tableData.find(item => {
|
return item.productModel === this.formData.productModel && item.unFinishedQuantity > 0;
|
});
|
if (!rowData) {
|
this.$message.error("没有可扫描的物料条码");
|
this.playError();
|
return;
|
}
|
|
// 箱号存在
|
var existCaseRow = this.tableData.find(item => {
|
return item.caseNumber === this.formData.caseNumber && item.unFinishedQuantity > 0;
|
});
|
this.existRows = [rowData];
|
|
if (!existCaseRow) {
|
var newRow = JSON.parse(JSON.stringify(rowData));
|
rowData.unFinishedQuantity = 0;
|
|
newRow.finishedQuantity = 1;
|
newRow.unFinishedQuantity -= 1;
|
newRow.caseNumber = this.formData.caseNumber;
|
this.tableData.splice(0, 0, newRow);
|
this.currentRow = newRow;
|
this.currentRow.scanWeight = Math.Round(this.currentRow.weight * this.currentRow.finishedQuantity, 2);
|
}
|
this.generateCaseNumber();
|
this.play();
|
},
|
// 多品一箱
|
addRow_2() {
|
const rowData = this.tableData.find(item => {
|
const exist = this.checkProductModelExist(this.formData.productModel, item);
|
return exist && item.unFinishedQuantity > 0;
|
});
|
if (!rowData) {
|
this.$message.error("没有可扫描的物料条码");
|
this.playError();
|
return;
|
}
|
|
this.currentRow = rowData;
|
this.existRows = [rowData];
|
const qty = this.getScanQty();
|
if (rowData.unFinishedQuantity < qty) {
|
this.$message.error("没有足够的数量!");
|
return;
|
}
|
|
if (rowData.caseNumber === this.formData.caseNumber) {
|
rowData.unFinishedQuantity -= qty;
|
rowData.finishedQuantity += qty;
|
} else {
|
if (!rowData.caseNumber) {
|
rowData.unFinishedQuantity -= qty;
|
rowData.finishedQuantity += qty;
|
rowData.caseNumber = this.formData.caseNumber;
|
} else {
|
var newRow = JSON.parse(JSON.stringify(rowData));
|
rowData.unFinishedQuantity = 0;
|
|
newRow.finishedQuantity = qty;
|
newRow.unFinishedQuantity -= qty;
|
newRow.caseNumber = this.formData.caseNumber;
|
this.tableData.splice(0, 0, newRow);
|
this.currentRow = newRow;
|
this.existRows = [newRow];
|
}
|
}
|
this.currentRow.scanWeight = Math.Round(this.currentRow.weight * this.currentRow.finishedQuantity, 2);
|
this.play();
|
|
this.currentRow.sortIndex = 1;
|
// 置顶排序
|
this.tableData.sort(function(a, b) {
|
return b.sortIndex - a.sortIndex;
|
});
|
|
this.tableData.forEach(element => {
|
element.sortIndex = 0;
|
});
|
}
|
}
|
};
|
</script>
|
|
<style lang="scss" scoped>
|
@import "../../../styles/scan.scss";
|
.scan-card {
|
position: relative;
|
.allot-position {
|
position: absolute;
|
top: 65px;
|
left: 700px;
|
.title {
|
padding: 10px;
|
}
|
.value {
|
color: red;
|
font-size: 50px;
|
}
|
}
|
}
|
</style>
|