343 lines
9.4 KiB
Vue
343 lines
9.4 KiB
Vue
|
|
<template>
|
|||
|
|
<view class="container">
|
|||
|
|
<uni-easyinput class="scanInput" placeholder="请扫描销售单号" v-model="saleCode"
|
|||
|
|
@confirm="fetchDetail" @blur="isFocusSaleCode = false" :focus="isFocusSaleCode" clearable />
|
|||
|
|
<t-sale-info :saleInfo="saleInfo" />
|
|||
|
|
<uni-easyinput class="scanInput" placeholder="请扫描工业条码" v-if="!isFinish" :key="inputKey"
|
|||
|
|
v-model="pieceBarcode" @confirm="submitPiece" @blur="isFocusPieceBarcode = false" :focus="isFocusPieceBarcode" clearable />
|
|||
|
|
<uni-table border stripe emptyText="暂无更多数据" class="pieceInfo">
|
|||
|
|
<uni-tr>
|
|||
|
|
<uni-th align="center" width="30">物料名称</uni-th>
|
|||
|
|
<uni-th align="center" width="30">规格</uni-th>
|
|||
|
|
<uni-th align="center" width="20">发货数</uni-th>
|
|||
|
|
<uni-th align="center" width="20">校验数</uni-th>
|
|||
|
|
</uni-tr>
|
|||
|
|
<uni-tr v-for="(item, index) in saleInfo.wmsSaleOutTaskDetailList" :key="index">
|
|||
|
|
<uni-td align="center">{{ item.materialName }}</uni-td>
|
|||
|
|
<uni-td align="center">{{ item.specification }}</uni-td>
|
|||
|
|
<uni-td align="center">{{ item.number }}</uni-td>
|
|||
|
|
<uni-td align="center">{{ item.validationNumber }}</uni-td>
|
|||
|
|
</uni-tr>
|
|||
|
|
</uni-table>
|
|||
|
|
<view class="actions">
|
|||
|
|
<u-button class="reload-btn" icon="reload" @click="fetchDetail"></u-button>
|
|||
|
|
<uni-badge size="small" :text="errorLogs.length" absolute="rightTop" type="error">
|
|||
|
|
<u-button class="logs-btn" @click="showErrorLogs">异常记录</u-button>
|
|||
|
|
</uni-badge>
|
|||
|
|
<u-button class="submit-btn" type="primary" @click="submit" :disabled="!isFinish">提交</u-button>
|
|||
|
|
</view>
|
|||
|
|
<uni-popup ref="popup" type="bottom" border-radius="10px 10px 0 0" background-color="#fff">
|
|||
|
|
<scroll-view scroll-y class="err-logs-container" v-if="errorLogs.length">
|
|||
|
|
<uni-section :title="'共有' + errorLogs.length + '条错误记录'" type="line" />
|
|||
|
|
<uni-card v-for="(err, index) in errorLogs" :key="err.pieceBarcode">
|
|||
|
|
<template #title>
|
|||
|
|
<view class="err-logs-card__title">
|
|||
|
|
<text style="flex: 1">{{ err.pieceBarcode }}</text>
|
|||
|
|
<u-button size="mini" text="X" style="flex: 0" @click="removeErrPiece(err.pieceBarcode)"></u-button>
|
|||
|
|
</view>
|
|||
|
|
</template>
|
|||
|
|
{{ err.msg }}
|
|||
|
|
<template #actions>
|
|||
|
|
<view class="actions-container" @click="reSubmitPiece(err.pieceBarcode)">
|
|||
|
|
<text>重新提交</text>
|
|||
|
|
</view>
|
|||
|
|
</template>
|
|||
|
|
</uni-card>
|
|||
|
|
</scroll-view>
|
|||
|
|
<u-empty mode="list" v-else />
|
|||
|
|
</uni-popup>
|
|||
|
|
<u-modal :show="showModal" :title="title" :content="content" @confirm="handleConfirm" />
|
|||
|
|
</view>
|
|||
|
|
</template>
|
|||
|
|
|
|||
|
|
<script>
|
|||
|
|
import { addOut } from '@/api/wms/sale.js';
|
|||
|
|
import {
|
|||
|
|
listTask,
|
|||
|
|
getTask,
|
|||
|
|
fetchTask
|
|||
|
|
} from '@/api/wms/sale.js';
|
|||
|
|
import { autioError, autioSuccess } from '@/utils/audio';
|
|||
|
|
import { addWmsPieceOutRecord } from '@/api/mes/wmsPieceOutRecord.js';
|
|||
|
|
import { nextTick } from "vue";
|
|||
|
|
|
|||
|
|
export default {
|
|||
|
|
data() {
|
|||
|
|
return {
|
|||
|
|
inputKey: 0,
|
|||
|
|
isFinish: false,
|
|||
|
|
isFocusSaleCode: true,
|
|||
|
|
isFocusPieceBarcode: false,
|
|||
|
|
// 销售单号
|
|||
|
|
saleCode: null,
|
|||
|
|
// 销售单 id
|
|||
|
|
saleId: null,
|
|||
|
|
// 工业条码
|
|||
|
|
pieceBarcode: '',
|
|||
|
|
// 扫描销售单号获取的数据
|
|||
|
|
saleInfo: {
|
|||
|
|
// 销售单号
|
|||
|
|
saleOutTaskCode: '',
|
|||
|
|
// 扫描数量
|
|||
|
|
scanNumber: '',
|
|||
|
|
// 订单总数
|
|||
|
|
allNumber: '',
|
|||
|
|
// 动态字段
|
|||
|
|
dynamicField1: {
|
|||
|
|
// 下级客户
|
|||
|
|
nextLevelCus: ''
|
|||
|
|
},
|
|||
|
|
//获取的物料详情
|
|||
|
|
wmsSaleOutTaskDetailList: []
|
|||
|
|
},
|
|||
|
|
showModal: false,
|
|||
|
|
modalType: '',
|
|||
|
|
title: '',
|
|||
|
|
content: '',
|
|||
|
|
errorLogs: []
|
|||
|
|
};
|
|||
|
|
},
|
|||
|
|
methods: {
|
|||
|
|
focusSaleCode() {
|
|||
|
|
this.$nextTick(() => {
|
|||
|
|
this.isFocusSaleCode = true;
|
|||
|
|
});
|
|||
|
|
},
|
|||
|
|
focusPieceBarcode() {
|
|||
|
|
this.inputKey++;
|
|||
|
|
this.$nextTick(() => {
|
|||
|
|
this.isFocusPieceBarcode = true;
|
|||
|
|
});
|
|||
|
|
},
|
|||
|
|
showErrorLogs() {
|
|||
|
|
this.$refs.popup.open('bottom');
|
|||
|
|
},
|
|||
|
|
showConfirm(title, content, type) {
|
|||
|
|
this.title = title;
|
|||
|
|
this.content = content;
|
|||
|
|
this.modalType = type;
|
|||
|
|
this.showModal = true;
|
|||
|
|
},
|
|||
|
|
handleConfirm() {
|
|||
|
|
autioError();
|
|||
|
|
const type = this.modalType;
|
|||
|
|
this.showModal = false;
|
|||
|
|
this.title = this.content = this.modalType = '';
|
|||
|
|
|
|||
|
|
if (type === 'saleCode') this.focusSaleCode();
|
|||
|
|
else if (type === 'pieceBarCode') this.focusPieceBarcode();
|
|||
|
|
},
|
|||
|
|
// 校验工业条码规范性
|
|||
|
|
validatePieceBarcode() {
|
|||
|
|
//判断工业条码里面是否有逗号,逗号后面大于九位
|
|||
|
|
if (!this.pieceBarcode) return false;
|
|||
|
|
const [prefix, suffix] = this.pieceBarcode.replace(',', ',').split(',');
|
|||
|
|
return !!(prefix && suffix?.length >= 9);
|
|||
|
|
},
|
|||
|
|
// 提交工业条码
|
|||
|
|
submitPiece() {
|
|||
|
|
if (!this.pieceBarcode) return;
|
|||
|
|
if (!this.saleCode) return this.showConfirm('错误', '请先输入销售单号', 'saleCode');
|
|||
|
|
if (!this.validatePieceBarcode()) return this.showConfirm('错误', '请输入正确的工业条码', 'pieceBarCode');
|
|||
|
|
|
|||
|
|
const pieceBarcode = this.pieceBarcode;
|
|||
|
|
|
|||
|
|
autioSuccess();
|
|||
|
|
this.$modal.msgSuccess('提交成功');
|
|||
|
|
addWmsPieceOutRecord({
|
|||
|
|
// 销售订单号
|
|||
|
|
saleOrderCode: this.saleCode,
|
|||
|
|
// 工业条码
|
|||
|
|
pieceBarcode,
|
|||
|
|
// 客户编码
|
|||
|
|
customerCode: this.saleInfo.customerCode,
|
|||
|
|
delStatus: '0'
|
|||
|
|
}).catch(err => {
|
|||
|
|
this.addError(pieceBarcode, err.msg);
|
|||
|
|
});
|
|||
|
|
this.isFocusPieceBarcode = false;
|
|||
|
|
this.pieceBarcode = '';
|
|||
|
|
this.focusPieceBarcode();
|
|||
|
|
},
|
|||
|
|
async reSubmitPiece(pieceBarcode) {
|
|||
|
|
this.$modal.loading('重新提交中');
|
|||
|
|
await addWmsPieceOutRecord({
|
|||
|
|
// 销售订单号
|
|||
|
|
saleOrderCode: this.saleCode,
|
|||
|
|
// 工业条码
|
|||
|
|
pieceBarcode,
|
|||
|
|
// 客户编码
|
|||
|
|
customerCode: this.saleInfo.customerCode,
|
|||
|
|
delStatus: '0'
|
|||
|
|
}).then(() => {
|
|||
|
|
this.$modal.msgSuccess('提交成功');
|
|||
|
|
this.removeErrPiece(pieceBarcode);
|
|||
|
|
}).catch(err => {
|
|||
|
|
autioError();
|
|||
|
|
this.addError(pieceBarcode, err.msg);
|
|||
|
|
this.showConfirm('重新提交失败', err.msg, 'pieceBarCode');
|
|||
|
|
});
|
|||
|
|
this.$modal.closeLoading();
|
|||
|
|
},
|
|||
|
|
addError(pieceBarcode, msg) {
|
|||
|
|
const idx = this.errorLogs.findIndex(i => i.pieceBarcode === pieceBarcode);
|
|||
|
|
if (idx !== -1) {
|
|||
|
|
// 已存在 → 更新
|
|||
|
|
this.errorLogs[idx].msg = msg;
|
|||
|
|
// 为确保视图立即刷新(Vue2 对数组项更新可能不追踪)
|
|||
|
|
this.errorLogs.splice(idx, 1, this.errorLogs[idx]);
|
|||
|
|
} else {
|
|||
|
|
// 不存在 → 添加新记录
|
|||
|
|
this.errorLogs.push({ pieceBarcode, msg });
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
removeErrPiece(pieceBarcode) {
|
|||
|
|
this.errorLogs = this.errorLogs.filter(i => i.pieceBarcode !== pieceBarcode);
|
|||
|
|
},
|
|||
|
|
// 通过销售单号获取任务单明细
|
|||
|
|
async fetchDetail() {
|
|||
|
|
//当输入值明显不合法时不执行后续操作
|
|||
|
|
if (!this.saleCode) return;
|
|||
|
|
|
|||
|
|
if (this.saleCode.length < 9) {
|
|||
|
|
this.showConfirm('错误', `销售单号 ${this.saleCode} 错误,请扫描正确的销售单号`, 'saleCode');
|
|||
|
|
this.saleCode = '';
|
|||
|
|
return autioError();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
this.$modal.loading('获取明细中...');
|
|||
|
|
try {
|
|||
|
|
// 从任务单信息中获取任务单 id
|
|||
|
|
const res = await listTask({ saleOutTaskCode: this.saleCode });
|
|||
|
|
this.saleId = res.rows[0]?.id || null;
|
|||
|
|
if (!this.saleId) {
|
|||
|
|
this.$modal.closeLoading();
|
|||
|
|
this.showConfirm('获取明细失败', `请检查销售单号 ${this.saleCode}`, 'saleCode');
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 用任务单 id 获取明细详情
|
|||
|
|
const res_task = await getTask(this.saleId);
|
|||
|
|
const data = res_task.data;
|
|||
|
|
|
|||
|
|
data.dynamicField1 = data.dynamicField1
|
|||
|
|
? JSON.parse(data.dynamicField1)
|
|||
|
|
: { nextLevelCus: null };
|
|||
|
|
delete data.id;
|
|||
|
|
|
|||
|
|
this.saleInfo = data;
|
|||
|
|
this.isFinish = !!(data.scanNumber && data.allNumber && data.scanNumber >= data.allNumber);
|
|||
|
|
this.focusPieceBarcode();
|
|||
|
|
} catch (err) {
|
|||
|
|
autioError();
|
|||
|
|
this.showConfirm('获取明细失败', err.message || err, 'saleCode');
|
|||
|
|
}
|
|||
|
|
this.$modal.closeLoading();
|
|||
|
|
},
|
|||
|
|
// 提交
|
|||
|
|
async submit() {
|
|||
|
|
try {
|
|||
|
|
this.$modal.loading('提交中...');
|
|||
|
|
const { data } = await fetchTask(this.saleId);
|
|||
|
|
const detail = {
|
|||
|
|
...data,
|
|||
|
|
wmsSaleOutTaskDetailList: data.wmsSaleOutTaskDetailList.map(i => {
|
|||
|
|
const { id, ...rest } = i;
|
|||
|
|
return rest;
|
|||
|
|
}),
|
|||
|
|
dynamicField1: JSON.stringify(this.saleInfo.dynamicField1),
|
|||
|
|
wmsSaleOutDetailList: data.wmsSaleOutTaskDetailList,
|
|||
|
|
billType: 2
|
|||
|
|
};
|
|||
|
|
delete detail.id;
|
|||
|
|
await addOut(detail);
|
|||
|
|
autioSuccess();
|
|||
|
|
this.$modal.msgSuccess('出库成功');
|
|||
|
|
} catch (err) {
|
|||
|
|
autioError();
|
|||
|
|
this.$modal.alert(err.msg || err.message || err);
|
|||
|
|
} finally {
|
|||
|
|
this.$modal.closeLoading();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
</script>
|
|||
|
|
|
|||
|
|
<style scoped lang="scss">
|
|||
|
|
.container {
|
|||
|
|
background-color: #ffffff;
|
|||
|
|
// #ifdef H5
|
|||
|
|
height: calc(100vh - 44px);
|
|||
|
|
// #endif
|
|||
|
|
// #ifdef APP-PLUS
|
|||
|
|
height: 100vh;
|
|||
|
|
// #endif
|
|||
|
|
padding: 10px;
|
|||
|
|
display: flex;
|
|||
|
|
flex-direction: column;
|
|||
|
|
overflow: hidden;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.scanInput,
|
|||
|
|
.saleInfo,
|
|||
|
|
.pieceInfo, {
|
|||
|
|
flex: 0 0 auto;
|
|||
|
|
margin: 0.5vh 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.pieceInfo {
|
|||
|
|
flex: 1;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.uni-table-th,
|
|||
|
|
.uni-table-td {
|
|||
|
|
padding: 4px;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.uni-table-th {
|
|||
|
|
position: sticky;
|
|||
|
|
top: 0;
|
|||
|
|
z-index: 2;
|
|||
|
|
background-color: #ffffff;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
::v-deep .u-popup {
|
|||
|
|
flex: unset;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.actions {
|
|||
|
|
width: 100%;
|
|||
|
|
display: flex;
|
|||
|
|
gap: 10px;
|
|||
|
|
.reload-btn {
|
|||
|
|
width: 46px;
|
|||
|
|
}
|
|||
|
|
.submit-btn {
|
|||
|
|
flex: 1;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
::v-deep .uni-badge {
|
|||
|
|
z-index: 99;
|
|||
|
|
}
|
|||
|
|
::v-deep .err-logs-container {
|
|||
|
|
.uni-scroll-view {
|
|||
|
|
max-height: 40vh;
|
|||
|
|
}
|
|||
|
|
.err-logs-card__title {
|
|||
|
|
display: flex;
|
|||
|
|
align-items: center;
|
|||
|
|
padding: 10px 5px;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
.uni-popup__wrapper {
|
|||
|
|
z-index: 999 !important;
|
|||
|
|
}
|
|||
|
|
.actions-container {
|
|||
|
|
display: flex;
|
|||
|
|
align-items: center;
|
|||
|
|
justify-content: center;
|
|||
|
|
padding: 12px 0;
|
|||
|
|
border-top: 1px #EBEEF5 solid;
|
|||
|
|
}
|
|||
|
|
</style>
|