| | |
| | | <template> |
| | | <div class="picking-confirm"> |
| | | <div class="OutboundPicking-container"> |
| | | <div class="page-header"> |
| | | <el-page-header @back="goBack"> |
| | | <template #content> |
| | | <span class="title">åºåºæ£é确认 - {{ orderInfo.orderNo }}</span> |
| | | <span class="title">åºåºæ£é确认 - {{ this.$route.query.orderNo }}</span> |
| | | </template> |
| | | </el-page-header> |
| | | </div> |
| | | <!-- æ«ç åºå --> |
| | | <div class="scanner-area"> |
| | | <el-card> |
| | | <div class="scanner-form"> |
| | | <el-input |
| | | ref="palletInput" |
| | | v-model="scanData.palletCode" |
| | | placeholder="æ«ææçç " |
| | | @change="onPalletScan" |
| | | @keyup.enter.native="onPalletScan"> |
| | | </el-input> |
| | | <el-input |
| | | ref="barcodeInput" |
| | | v-model="scanData.barcode" |
| | | placeholder="æ«æç©ææ¡ç " |
| | | @change="onBarcodeScan" |
| | | @keyup.enter.native="onBarcodeScan"> |
| | | </el-input> |
| | | <el-button type="success" @click="confirmPicking">确认æ£é</el-button> |
| | | <!-- <el-button type="warning" @click="openSplitDialog">æå
</el-button> |
| | | <el-button type="info" @click="openRevertSplitDialog">æ¤éæå
</el-button> --> |
| | | <el-button type="info" @click="handleEmptyPallet">å空箱</el-button> |
| | | <el-button type="primary" @click="openBatchReturnDialog">ååº</el-button> |
| | | <!-- <el-button type="danger" @click="handleDirectOutbound">ç´æ¥åºåº</el-button> --> |
| | | |
| | | <el-row :gutter="20" class="main-content"> |
| | | <el-col :span="8"> |
| | | <div class="scan-section"> |
| | | <el-card header="æ«ç åºå"> |
| | | <el-form label-width="100px" size="small"> |
| | | <el-form-item label="æçæ¡ç "> |
| | | <el-input |
| | | v-model="scanForm.palletCode" |
| | | placeholder="æ«ææè¾å
¥æçæ¡ç " |
| | | @keyup.enter="handlePalletScan" |
| | | clearable |
| | | > |
| | | <template #append> |
| | | <el-button @click="handlePalletScan">确认</el-button> |
| | | </template> |
| | | </el-input> |
| | | </el-form-item> |
| | | |
| | | <el-form-item label="ç©ææ¡ç "> |
| | | <el-input |
| | | v-model="scanForm.barcode" |
| | | placeholder="æ«ææè¾å
¥ç©ææ¡ç " |
| | | @keyup.enter="handleBarcodeScan" |
| | | :disabled="!currentPallet" |
| | | clearable |
| | | > |
| | | <template #append> |
| | | <el-button @click="handleBarcodeScan" :disabled="!currentPallet">确认</el-button> |
| | | </template> |
| | | </el-input> |
| | | </el-form-item> |
| | | |
| | | <el-form-item label="æ£éæ°é"> |
| | | <el-input-number |
| | | v-model="scanForm.quantity" |
| | | :min="1" |
| | | :max="maxPickQuantity" |
| | | :disabled="!currentLockInfo" |
| | | /> |
| | | </el-form-item> |
| | | </el-form> |
| | | |
| | | <div class="current-info" v-if="currentPallet"> |
| | | <p>å½åæç: {{ currentPallet.palletCode }}</p> |
| | | <p>è´§ä½: {{ currentPallet.locationCode }}</p> |
| | | <p>ç¶æ: {{ currentPallet.statusText }}</p> |
| | | </div> |
| | | </el-card> |
| | | |
| | | <div class="action-buttons"> |
| | | <el-button |
| | | type="warning" |
| | | @click="handleBackToStock" |
| | | :disabled="!currentPallet" |
| | | style="margin-bottom: 10px;" |
| | | > |
| | | ååº |
| | | </el-button> |
| | | <el-button |
| | | type="success" |
| | | @click="handleDirectOutbound" |
| | | :disabled="!currentPallet" |
| | | style="margin-bottom: 10px;" |
| | | > |
| | | ç´æ¥åºåº |
| | | </el-button> |
| | | <el-button |
| | | type="primary" |
| | | @click="handleOpenSplit" |
| | | :disabled="!currentLockInfo" |
| | | > |
| | | æå
|
| | | </el-button> |
| | | </div> |
| | | </div> |
| | | </el-col> |
| | | </el-card> |
| | | </div> |
| | | |
| | | <el-col :span="16"> |
| | | <el-card header="æ£éç»æ"> |
| | | <div class="summary-info"> |
| | | <el-alert |
| | | :title="`æªæ£è´§: ${unpickedCount} æ¡, ${unpickedQuantity} 个`" |
| | | type="warning" |
| | | :closable="false" |
| | | /> |
| | | </div> |
| | | <!-- æ±æ»ä¿¡æ¯ --> |
| | | <div class="summary-area"> |
| | | <el-card> |
| | | <div class="summary-info"> |
| | | <el-tag type="warning">æªæ£éæ¡æ°: {{summary.unpickedCount}}</el-tag> |
| | | <el-tag type="danger">æªæ£éæ°é: {{summary.unpickedQuantity}}</el-tag> |
| | | <!-- <el-tag type="success">å·²æ£éæ¡æ°: {{summary.pickedCount}}</el-tag> --> |
| | | <el-tag type="info">æçç¶æ: {{palletStatus}}</el-tag> |
| | | </div> |
| | | </el-card> |
| | | </div> |
| | | |
| | | <vol-table |
| | | :data="pickedList" |
| | | :columns="pickedColumns" |
| | | :pagination="false" |
| | | :height="400" |
| | | > |
| | | <template #action="{ row }"> |
| | | <el-button type="text" @click="handleCancelPick(row)">æ¤é</el-button> |
| | | </template> |
| | | </vol-table> |
| | | </el-card> |
| | | </el-col> |
| | | </el-row> |
| | | <!-- æ°æ®å表 --> |
| | | <div class="content-area"> |
| | | <el-row :gutter="20"> |
| | | <el-col :span="12"> |
| | | <el-card header="æªæ£éå表"> |
| | | <el-table :data="unpickedList" border height="440"> |
| | | <el-table-column prop="materielCode" label="ç©æç¼ç " width="120"></el-table-column> |
| | | |
| | | <el-table-column prop="assignQuantity" label="åé
æ°é" width="100"></el-table-column> |
| | | <el-table-column prop="remainQuantity" label="å©ä½æ°é" width="100"></el-table-column> |
| | | <el-table-column prop="locationCode" label="è´§ä½" width="100"></el-table-column> |
| | | <el-table-column prop="currentBarcode" label="æ¡ç "></el-table-column> |
| | | <!-- <el-table-column label="æä½" width="100"> |
| | | <template slot-scope="scope"> |
| | | <el-button |
| | | size="mini" |
| | | type="primary" |
| | | @click="handleSingleReturn(scope.row)"> |
| | | ååº |
| | | </el-button> |
| | | </template> |
| | | </el-table-column> --> |
| | | </el-table> |
| | | </el-card> |
| | | </el-col> |
| | | |
| | | <el-col :span="12"> |
| | | <el-card header="å·²æ£éå表"> |
| | | <div class="table-actions"> |
| | | <el-button |
| | | size="mini" |
| | | type="danger" |
| | | :disabled="selectedPickedRows.length === 0" |
| | | @click="batchCancelSelected"> |
| | | åæ¶æ£é |
| | | </el-button> |
| | | <span class="selection-count">已鿩 {{selectedPickedRows.length}} 项</span> |
| | | </div> |
| | | <el-table :data="pickedList" border height="400" style="width: 100%" @selection-change="handlePickedSelectionChange"> |
| | | <el-table-column type="selection" width="55"></el-table-column> |
| | | <el-table-column prop="materielCode" label="ç©æç¼ç " width="120"></el-table-column> |
| | | |
| | | <el-table-column prop="pickedQty" label="å·²æ£æ°é" width="100"></el-table-column> |
| | | <el-table-column prop="locationCode" label="è´§ä½" width="100"></el-table-column> |
| | | <el-table-column prop="currentBarcode" label="æ¡ç "></el-table-column> |
| | | |
| | | |
| | | </el-table> |
| | | </el-card> |
| | | </el-col> |
| | | </el-row> |
| | | </div> |
| | | |
| | | <!-- æå
å¼¹çª --> |
| | | <vol-box |
| | | v-model="splitVisible" |
| | | title="æå
æä½" |
| | | :width="600" |
| | | :height="500" |
| | | > |
| | | <SplitPackageModal |
| | | v-if="splitVisible" |
| | | :lockInfo="currentLockInfo" |
| | | @success="handleSplitSuccess" |
| | | @close="splitVisible = false" |
| | | /> |
| | | </vol-box> |
| | | <!-- æå
å¼¹çª --> |
| | | <div v-if="showCustomSplitDialog" class="custom-dialog-overlay"> |
| | | <div class="custom-dialog-wrapper"> |
| | | <div class="custom-dialog"> |
| | | <div class="custom-dialog-header"> |
| | | <h3>æå
æä½</h3> |
| | | <!-- <el-button |
| | | type="text" |
| | | icon="el-icon-close" |
| | | @click="closeCustomSplitDialog" |
| | | class="close-button"> |
| | | </el-button> --> |
| | | <el-button |
| | | type="text" |
| | | @click="closeCustomSplitDialog" |
| | | class="close-button"> |
| | | X |
| | | </el-button> |
| | | |
| | | </div> |
| | | <div class="custom-dialog-body"> |
| | | <el-form :model="splitForm" :rules="splitFormRules" ref="splitFormRef" label-width="100px"> |
| | | <el-form-item label="订åç¼å·"> |
| | | <el-input v-model="splitForm.orderNo" disabled></el-input> |
| | | </el-form-item> |
| | | <el-form-item label="æçç¼å·"> |
| | | <el-input v-model="splitForm.palletCode" disabled></el-input> |
| | | </el-form-item> |
| | | <el-form-item label="åæ¡ç " prop="originalBarcode"> |
| | | <el-input |
| | | v-model="splitForm.originalBarcode" |
| | | placeholder="æ«æåæ¡ç " |
| | | @keyup.enter.native="onSplitBarcodeScan" |
| | | @change="onSplitBarcodeScan" |
| | | clearable> |
| | | </el-input> |
| | | </el-form-item> |
| | | <el-form-item label="ç©æç¼ç "> |
| | | <el-input v-model="splitForm.materielCode" disabled></el-input> |
| | | </el-form-item> |
| | | <el-form-item label="å©ä½æ°é"> |
| | | <el-input v-model="splitForm.maxQuantity" disabled></el-input> |
| | | </el-form-item> |
| | | <el-form-item label="æå
æ°é" prop="splitQuantity"> |
| | | <el-input-number |
| | | v-model="splitForm.splitQuantity" |
| | | :min="1" |
| | | :max="splitForm.maxQuantity" |
| | | :precision="2" |
| | | :step="1" |
| | | style="width: 100%"> |
| | | </el-input-number> |
| | | </el-form-item> |
| | | </el-form> |
| | | </div> |
| | | <div class="custom-dialog-footer"> |
| | | <el-button @click="closeCustomSplitDialog">åæ¶</el-button> |
| | | <el-button type="primary" @click="handleSplitPackage" :loading="splitLoading">确认æå
</el-button> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | |
| | | |
| | | <!-- æ¤éæå
å¼¹çª --> |
| | | <div v-if="showRevertSplitDialog" class="custom-dialog-overlay"> |
| | | <div class="custom-dialog-wrapper"> |
| | | <div class="custom-dialog"> |
| | | <div class="custom-dialog-header"> |
| | | <h3>æ¤éæå
</h3> |
| | | <el-button |
| | | type="text" |
| | | @click="closeRevertSplitDialog" |
| | | class="close-button"> |
| | | Ã |
| | | </el-button> |
| | | </div> |
| | | <div class="custom-dialog-body"> |
| | | <el-form |
| | | :model="revertSplitForm" |
| | | :rules="revertSplitFormRules" |
| | | ref="revertSplitFormRef" |
| | | label-width="100px"> |
| | | <el-form-item label="åæ¡ç " prop="originalBarcode"> |
| | | <el-input |
| | | v-model="revertSplitForm.originalBarcode" |
| | | placeholder="æ«æåæ¡ç " |
| | | @keyup.enter.native="onRevertSplitBarcodeScan" |
| | | @change="onRevertSplitBarcodeScan" |
| | | clearable> |
| | | </el-input> |
| | | </el-form-item> |
| | | </el-form> |
| | | </div> |
| | | <div class="custom-dialog-footer"> |
| | | <el-button @click="closeRevertSplitDialog">åæ¶</el-button> |
| | | <el-button type="primary" @click="handleRevertSplit" :loading="revertSplitLoading">确认æ¤é</el-button> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | |
| | | <!-- æ¹éååºå¼¹çª --> |
| | | <div v-if="showBatchReturnDialog" class="custom-dialog-overlay"> |
| | | <div class="custom-dialog-wrapper"> |
| | | <div class="custom-dialog"> |
| | | <div class="custom-dialog-header"> |
| | | <h3>ååº</h3> |
| | | <el-button |
| | | type="text" |
| | | @click="closeBatchReturnDialog" |
| | | class="close-button"> |
| | | Ã |
| | | </el-button> |
| | | </div> |
| | | <div class="custom-dialog-body"> |
| | | <el-form |
| | | :model="batchReturnForm" |
| | | :rules="batchReturnFormRules" |
| | | ref="batchReturnFormRef" |
| | | label-width="100px"> |
| | | <el-form-item label="订åç¼å·"> |
| | | <el-input v-model="batchReturnForm.orderNo" disabled></el-input> |
| | | </el-form-item> |
| | | <el-form-item label="æçç¼å·" prop="palletCode"> |
| | | <el-input |
| | | v-model="batchReturnForm.palletCode" |
| | | placeholder="æ«ææçç " |
| | | @keyup.enter.native="onBatchReturnPalletScan" |
| | | @change="onBatchReturnPalletScan" |
| | | clearable> |
| | | </el-input> |
| | | </el-form-item> |
| | | <el-form-item label="æªæ£éæ°é"> |
| | | <el-input v-model="batchReturnForm.unpickedCount" disabled></el-input> |
| | | </el-form-item> |
| | | <el-form-item label="æªæ£éæ¡æ°"> |
| | | <el-input v-model="batchReturnForm.unpickedQuantity" disabled></el-input> |
| | | </el-form-item> |
| | | </el-form> |
| | | </div> |
| | | <div class="custom-dialog-footer"> |
| | | <el-button @click="closeBatchReturnDialog">åæ¶</el-button> |
| | | <el-button type="primary" @click="handleBatchReturnConfirm" :loading="batchReturnLoading">确认ååº</el-button> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | |
| | | <!-- å走空箱--> |
| | | <div v-if="showEmptyPalletDialog" class="custom-dialog-overlay"> |
| | | <div class="custom-dialog-wrapper"> |
| | | <div class="custom-dialog"> |
| | | <div class="custom-dialog-header"> |
| | | <h3>å走空箱</h3> |
| | | <el-button |
| | | type="text" |
| | | @click="closeEmptyPalletDialog" |
| | | class="close-button"> |
| | | Ã |
| | | </el-button> |
| | | </div> |
| | | <div class="custom-dialog-body"> |
| | | <el-form |
| | | :model="emptypalletOutForm" |
| | | :rules="emptypalletOutFormRules" |
| | | ref="emptypalletOutFormRef" |
| | | label-width="100px"> |
| | | <el-form-item label="订åç¼å·"> |
| | | <el-input v-model="emptypalletOutForm.orderNo" disabled></el-input> |
| | | </el-form-item> |
| | | <el-form-item label="æçç¼å·" prop="palletCode"> |
| | | <el-input |
| | | v-model="emptypalletOutForm.palletCode" |
| | | placeholder="æ«ææçç " |
| | | @keyup.enter.native="onEmptyPalletScan" |
| | | @change="onEmptyPalletScan" |
| | | clearable> |
| | | </el-input> |
| | | </el-form-item> |
| | | </el-form> |
| | | </div> |
| | | <div class="custom-dialog-footer"> |
| | | <el-button @click="closeEmptyPalletDialog">åæ¶</el-button> |
| | | <el-button type="primary" @click="handleEmptyPalletConfirm" :loading="emptypalletOutLoading">确认å走空箱</el-button> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | |
| | | <!-- ç´æ¥åºåºå¼¹çª --> |
| | | <div v-if="showDirectOutDialog" class="custom-dialog-overlay"> |
| | | <div class="custom-dialog-wrapper"> |
| | | <div class="custom-dialog"> |
| | | <div class="custom-dialog-header"> |
| | | <h3>ç´æ¥åºåº</h3> |
| | | <el-button |
| | | type="text" |
| | | @click="closeDirectOutDialog" |
| | | class="close-button"> |
| | | Ã |
| | | </el-button> |
| | | </div> |
| | | <div class="custom-dialog-body"> |
| | | <el-form |
| | | :model="directOutForm" |
| | | :rules="directOutFormRules" |
| | | ref="directOutFormRef" |
| | | label-width="100px"> |
| | | <el-form-item label="订åç¼å·"> |
| | | <el-input v-model="directOutForm.orderNo" disabled></el-input> |
| | | </el-form-item> |
| | | <el-form-item label="æçç¼å·" prop="palletCode"> |
| | | <el-input |
| | | v-model="directOutForm.palletCode" |
| | | placeholder="æ«ææçç " |
| | | @keyup.enter.native="onDirectOutPalletScan" |
| | | @change="onDirectOutPalletScan" |
| | | clearable> |
| | | </el-input> |
| | | </el-form-item> |
| | | </el-form> |
| | | </div> |
| | | <div class="custom-dialog-footer"> |
| | | <el-button @click="closeDirectOutDialog">åæ¶</el-button> |
| | | <el-button type="primary" @click="handleDirectOutConfirm" :loading="directOutLoading">确认åºåº</el-button> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | |
| | | <print-view ref="childs" @parentcall="parentcall"></print-view> |
| | | </template> |
| | | |
| | | <script> |
| | | import SplitPackageModal from './SplitPackageModal.vue' |
| | | import http from '@/api/http.js' |
| | | import { ref, defineComponent } from "vue"; |
| | | import { ElMessage } from 'element-plus' |
| | | import { useRoute } from 'vue-router' |
| | | import printView from "@/extension/outbound/extend/printView.vue" |
| | | |
| | | export default { |
| | | components: { SplitPackageModal }, |
| | | export default defineComponent({ |
| | | name: 'PickingConfirm', |
| | | components: {printView}, |
| | | props: { |
| | | orderNo: { |
| | | type: String, |
| | | required: true |
| | | } |
| | | }, |
| | | emits: ['confirm', 'close'], |
| | | data() { |
| | | // å®ä¹æå
表åéªè¯è§å |
| | | const validateOriginalBarcode = (rule, value, callback) => { |
| | | if (!value || value.trim() === '') { |
| | | callback(new Error('请è¾å
¥åæ¡ç ')); |
| | | } else { |
| | | callback(); |
| | | } |
| | | }; |
| | | |
| | | const validateSplitQuantity = (rule, value, callback) => { |
| | | if (value === null || value === undefined || value === '') { |
| | | callback(new Error('请è¾å
¥æå
æ°é')); |
| | | } else if (value <= 0) { |
| | | callback(new Error('æå
æ°éå¿
须大äº0')); |
| | | } else if (this.splitForm.maxQuantity && value > this.splitForm.maxQuantity) { |
| | | callback(new Error('æå
æ°éä¸è½å¤§äºå©ä½æ°é')); |
| | | } else { |
| | | callback(); |
| | | } |
| | | }; |
| | | |
| | | // å®ä¹æ¤éæå
表åéªè¯è§å |
| | | const validateRevertOriginalBarcode = (rule, value, callback) => { |
| | | if (!value || value.trim() === '') { |
| | | callback(new Error('请è¾å
¥åæ¡ç ')); |
| | | } else { |
| | | callback(); |
| | | } |
| | | }; |
| | | // å®ä¹æ¹éååºè¡¨åéªè¯è§å |
| | | const validateBatchReturnPalletCode = (rule, value, callback) => { |
| | | if (!value || value.trim() === '') { |
| | | callback(new Error('请è¾å
¥æçç ')); |
| | | } else { |
| | | callback(); |
| | | } |
| | | }; |
| | | // å®ä¹ç´æ¥åºåºè¡¨åéªè¯è§å |
| | | const validateDirectOutPalletCode = (rule, value, callback) => { |
| | | if (!value || value.trim() === '') { |
| | | callback(new Error('请è¾å
¥æçç ')); |
| | | } else { |
| | | callback(); |
| | | } |
| | | }; |
| | | return { |
| | | orderInfo: {}, |
| | | scanForm: { |
| | | scanData: { |
| | | orderNo: '', |
| | | palletCode: '', |
| | | barcode: '' |
| | | }, |
| | | unpickedList: [], |
| | | pickedList: [], |
| | | selectedUnpickedRows: [], // æªæ£éå表éä¸çè¡ |
| | | selectedPickedRows: [], // å·²æ£éå表éä¸çè¡ |
| | | summary: { |
| | | unpickedCount: 0, |
| | | unpickedQuantity: 0, |
| | | pickedCount: 0 |
| | | }, |
| | | palletStatus: 'æªç¥', |
| | | showSplitDialog: false, |
| | | showRevertSplitDialog: false, |
| | | showCustomSplitDialog: false, // èªå®ä¹æå
å¼¹çªæ¾ç¤ºç¶æ |
| | | showBatchReturnDialog: false, // æ¹éååºå¼¹çªæ¾ç¤ºç¶æ |
| | | showReturnDialog: false, |
| | | splitLoading: false, |
| | | revertSplitLoading: false, |
| | | batchReturnLoading: false, // æ¹éååºå è½½ç¶æ |
| | | splitForm: { |
| | | orderNo: '', |
| | | palletCode: '', |
| | | originalBarcode: '', |
| | | materielCode: '', |
| | | splitQuantity: 0, |
| | | maxQuantity: 0 |
| | | }, |
| | | // æå
表åéªè¯è§å |
| | | splitFormRules: { |
| | | originalBarcode: [ |
| | | { required: true, validator: validateOriginalBarcode, trigger: 'blur' } |
| | | ], |
| | | splitQuantity: [ |
| | | { required: true, validator: validateSplitQuantity, trigger: 'blur' } |
| | | ] |
| | | }, |
| | | revertSplitForm: { |
| | | originalBarcode: '' |
| | | }, |
| | | // æ¤éæå
表åéªè¯è§å |
| | | revertSplitFormRules: { |
| | | originalBarcode: [ |
| | | { required: true, validator: validateRevertOriginalBarcode, trigger: 'blur' } |
| | | ] |
| | | }, |
| | | // æ¹éååºè¡¨å |
| | | batchReturnForm: { |
| | | orderNo: '', |
| | | palletCode: '', |
| | | unpickedCount: 0, |
| | | unpickedQuantity: 0 |
| | | }, |
| | | // æ¹éååºè¡¨åéªè¯è§å |
| | | batchReturnFormRules: { |
| | | palletCode: [ |
| | | { required: true, validator: validateBatchReturnPalletCode, trigger: 'blur' } |
| | | ] |
| | | }, |
| | | showDirectOutDialog: false, // ç´æ¥åºåºå¼¹çªæ¾ç¤ºç¶æ |
| | | directOutLoading: false, // ç´æ¥åºåºå è½½ç¶æ |
| | | directOutForm: { |
| | | orderNo: '', |
| | | palletCode: '' |
| | | }, |
| | | directOutFormRules: { |
| | | palletCode: [ |
| | | { required: true, validator: validateDirectOutPalletCode, trigger: 'blur' } |
| | | ] |
| | | }, |
| | | |
| | | showEmptyPalletDialog: false, // åèµ°ç©ºç®±å¼¹çªæ¾ç¤ºç¶æ |
| | | emptypalletOutLoading: false, // å走空箱å è½½ç¶æ |
| | | emptypalletOutForm: { |
| | | orderNo: '', |
| | | palletCode: '' |
| | | }, |
| | | emptypalletOutFormRules: { |
| | | palletCode: [ |
| | | { required: true, validator: validateDirectOutPalletCode, trigger: 'blur' } |
| | | ] |
| | | }, |
| | | |
| | | |
| | | returnForm: { |
| | | orderNo: '', |
| | | palletCode: '', |
| | | barcode: '', |
| | | quantity: 1 |
| | | materielCode: '', |
| | | returnQuantity: 0 |
| | | }, |
| | | currentPallet: null, |
| | | currentLockInfo: null, |
| | | pickedList: [], |
| | | pickedColumns: [ |
| | | { field: 'barcode', title: 'ç©ææ¡ç ', width: 150 }, |
| | | { field: 'materielCode', title: 'ç©æç¼ç ', width: 120 }, |
| | | { field: 'materielName', title: 'ç©æåç§°', width: 150 }, |
| | | { field: 'pickQuantity', title: 'æ£éæ°é', width: 100 }, |
| | | { field: 'palletCode', title: 'æçç¼å·', width: 120 }, |
| | | { field: 'pickTime', title: 'æ£éæ¶é´', width: 160 }, |
| | | { field: 'operator', title: 'æä½äºº', width: 100 }, |
| | | { field: 'action', title: 'æä½', width: 80, slot: true } |
| | | ], |
| | | splitVisible: false, |
| | | maxPickQuantity: 0 |
| | | } |
| | | }, |
| | | computed: { |
| | | unpickedCount() { |
| | | return this.orderInfo.unpickedCount || 0 |
| | | }, |
| | | unpickedQuantity() { |
| | | return this.orderInfo.unpickedQuantity || 0 |
| | | } |
| | | }, |
| | | methods: { |
| | | goBack() { |
| | | this.$router.back() |
| | | }, |
| | | |
| | | async loadOrderInfo() { |
| | | const orderId = this.$route.query.orderId |
| | | if (!orderId) return |
| | | |
| | | try { |
| | | const result = await this.http.post(`api/OutboundOrder/GetById?id=${orderId}`) |
| | | if (result.status) { |
| | | this.orderInfo = result.data |
| | | } |
| | | } catch (error) { |
| | | this.$message.error('å è½½åºåºåä¿¡æ¯å¤±è´¥') |
| | | } |
| | | }, |
| | | |
| | | async handlePalletScan() { |
| | | if (!this.scanForm.palletCode) { |
| | | this.$message.warning('请è¾å
¥æçæ¡ç ') |
| | | return |
| | | } |
| | | |
| | | try { |
| | | const result = await this.http.get( |
| | | `api/OutboundPicking/GetPalletOutboundStatus?palletCode=${this.scanForm.palletCode}` |
| | | ) |
| | | if (result.status) { |
| | | this.currentPallet = result.data |
| | | this.loadPalletLockInfo() |
| | | this.$message.success(`æç ${this.scanForm.palletCode} è¯å«æå`) |
| | | } else { |
| | | this.$message.error(result.message) |
| | | } |
| | | } catch (error) { |
| | | this.$message.error('æçè¯å«å¤±è´¥') |
| | | } |
| | | }, |
| | | |
| | | async loadPalletLockInfo() { |
| | | if (!this.currentPallet) return |
| | | |
| | | try { |
| | | const result = await this.http.get( |
| | | `api/OutboundPicking/GetPalletLockInfos?palletCode=${this.currentPallet.palletCode}` |
| | | ) |
| | | if (result.status && result.data.length > 0) { |
| | | this.currentLockInfo = result.data[0] |
| | | this.maxPickQuantity = this.currentLockInfo.assignQuantity - this.currentLockInfo.pickedQty |
| | | } |
| | | } catch (error) { |
| | | console.error('å è½½éå®ä¿¡æ¯å¤±è´¥:', error) |
| | | } |
| | | }, |
| | | |
| | | async handleBarcodeScan() { |
| | | // å®ç°æ«ç 确认é»è¾ |
| | | if (!this.scanForm.barcode) { |
| | | this.$message.warning('请è¾å
¥ç©ææ¡ç ') |
| | | return |
| | | } |
| | | |
| | | try { |
| | | const request = { |
| | | barcode: this.scanForm.barcode, |
| | | quantity: this.scanForm.quantity, |
| | | palletCode: this.currentPallet.palletCode, |
| | | orderId: this.orderInfo.id |
| | | } |
| | | |
| | | const result = await this.http.post('api/OutboundPicking/ConfirmPicking', request) |
| | | if (result.status) { |
| | | this.$message.success('æ£é确认æå') |
| | | this.scanForm.barcode = '' |
| | | this.scanForm.quantity = 1 |
| | | this.loadPickedHistory() |
| | | this.loadOrderInfo() |
| | | } else { |
| | | this.$message.error(result.message) |
| | | } |
| | | } catch (error) { |
| | | this.$message.error('æ£é确认失败') |
| | | } |
| | | }, |
| | | |
| | | async handleBackToStock() { |
| | | if (!this.currentPallet) return |
| | | |
| | | try { |
| | | await this.$confirm(`ç¡®å®å°æç ${this.currentPallet.palletCode} ååºåï¼`, 'æç¤º', { |
| | | type: 'warning' |
| | | }) |
| | | |
| | | const result = await this.http.post('api/BackToStock/GenerateBackToStockTask', { |
| | | palletCode: this.currentPallet.palletCode, |
| | | currentLocation: 'æ£éä½' |
| | | }) |
| | | |
| | | if (result.status) { |
| | | this.$message.success('ååºä»»å¡å·²çæ') |
| | | this.resetCurrentPallet() |
| | | } |
| | | } catch (error) { |
| | | // ç¨æ·åæ¶ |
| | | } |
| | | }, |
| | | |
| | | async handleDirectOutbound() { |
| | | if (!this.currentPallet) return |
| | | |
| | | try { |
| | | await this.$confirm(`ç¡®å®å°æç ${this.currentPallet.palletCode} ç´æ¥åºåºåï¼`, 'æç¤º', { |
| | | type: 'warning' |
| | | }) |
| | | |
| | | const result = await this.http.post('api/OutboundPicking/DirectOutbound', { |
| | | palletCode: this.currentPallet.palletCode |
| | | }) |
| | | |
| | | if (result.status) { |
| | | this.$message.success('ç´æ¥åºåºæå') |
| | | this.resetCurrentPallet() |
| | | this.loadOrderInfo() |
| | | } |
| | | } catch (error) { |
| | | // ç¨æ·åæ¶ |
| | | } |
| | | }, |
| | | |
| | | handleOpenSplit() { |
| | | if (!this.currentLockInfo) { |
| | | this.$message.warning('请å
éæ©éå®ä¿¡æ¯') |
| | | return |
| | | } |
| | | this.splitVisible = true |
| | | }, |
| | | |
| | | handleSplitSuccess() { |
| | | this.$message.success('æå
æå') |
| | | this.loadPalletLockInfo() |
| | | }, |
| | | |
| | | resetCurrentPallet() { |
| | | this.currentPallet = null |
| | | this.currentLockInfo = null |
| | | this.scanForm.palletCode = '' |
| | | }, |
| | | |
| | | async loadPickedHistory() { |
| | | const orderId = this.$route.query.orderId |
| | | if (!orderId) return |
| | | |
| | | try { |
| | | const result = await this.http.get(`api/OutboundPicking/GetPickingHistory?orderId=${orderId}`) |
| | | if (result.status) { |
| | | this.pickedList = result.data |
| | | } |
| | | } catch (error) { |
| | | console.error('å è½½æ£éåå²å¤±è´¥:', error) |
| | | } |
| | | }, |
| | | |
| | | async handleCancelPick(row) { |
| | | try { |
| | | await this.$confirm('ç¡®å®æ¤éè¿æ¡æ£éè®°å½åï¼', 'æç¤º', { type: 'warning' }) |
| | | |
| | | const result = await this.http.post('api/OutboundPicking/CancelPicking', { |
| | | pickingHistoryId: row.id |
| | | }) |
| | | |
| | | if (result.status) { |
| | | this.$message.success('æ¤éæå') |
| | | this.loadPickedHistory() |
| | | this.loadOrderInfo() |
| | | } |
| | | } catch (error) { |
| | | // ç¨æ·åæ¶ |
| | | } |
| | | isProcessing: false // 鲿¢éå¤æäº¤ |
| | | } |
| | | }, |
| | | mounted() { |
| | | this.loadOrderInfo() |
| | | this.loadPickedHistory() |
| | | // ä»è·¯ç±åæ°è·å订åç¼å· |
| | | if (this.$route.query.orderNo) { |
| | | this.scanData.orderNo = this.$route.query.orderNo; |
| | | this.splitForm.orderNo = this.$route.query.orderNo; |
| | | this.returnForm.orderNo = this.$route.query.orderNo; |
| | | } |
| | | // 页é¢å è½½åèªå¨èç¦å°æçç è¾å
¥æ¡ |
| | | this.$nextTick(() => { |
| | | this.$refs.palletInput.focus(); |
| | | }); |
| | | |
| | | }, |
| | | methods: { |
| | | goBack(){ |
| | | this.$router.back() |
| | | }, |
| | | |
| | | openSplitDialog() { |
| | | console.log('æå¼èªå®ä¹æå
å¼¹çª'); |
| | | if (!this.scanData.palletCode) { |
| | | this.$message.warning('请å
æ«ææçç '); |
| | | return; |
| | | } |
| | | this.showCustomSplitDialog = true; |
| | | |
| | | // é置表å |
| | | this.resetSplitForm(); |
| | | |
| | | // 设置订ååæçä¿¡æ¯ |
| | | this.splitForm.orderNo = this.scanData.orderNo; |
| | | this.splitForm.palletCode = this.scanData.palletCode; |
| | | |
| | | // æ¸
é¤è¡¨åéªè¯ |
| | | this.$nextTick(() => { |
| | | if (this.$refs.splitFormRef) { |
| | | this.$refs.splitFormRef.clearValidate(); |
| | | } |
| | | }); |
| | | }, |
| | | |
| | | // å
³éèªå®ä¹æå
å¼¹çª |
| | | closeCustomSplitDialog() { |
| | | this.showCustomSplitDialog = false; |
| | | this.resetSplitForm(); |
| | | // æ¸
é¤è¡¨åéªè¯ |
| | | if (this.$refs.splitFormRef) { |
| | | this.$refs.splitFormRef.clearValidate(); |
| | | } |
| | | }, |
| | | |
| | | // æå¼æ¤éæå
å¼¹çª |
| | | openRevertSplitDialog() { |
| | | console.log('æå¼æ¤éæå
å¼¹çª'); |
| | | this.showRevertSplitDialog = true; |
| | | |
| | | // é置表å |
| | | this.resetRevertSplitForm(); |
| | | |
| | | // æ¸
é¤è¡¨åéªè¯ |
| | | this.$nextTick(() => { |
| | | if (this.$refs.revertSplitFormRef) { |
| | | this.$refs.revertSplitFormRef.clearValidate(); |
| | | } |
| | | }); |
| | | }, |
| | | |
| | | // å
³éæ¤éæå
å¼¹çª |
| | | closeRevertSplitDialog() { |
| | | this.showRevertSplitDialog = false; |
| | | this.resetRevertSplitForm(); |
| | | |
| | | // æ¸
é¤è¡¨åéªè¯ |
| | | if (this.$refs.revertSplitFormRef) { |
| | | this.$refs.revertSplitFormRef.clearValidate(); |
| | | } |
| | | }, |
| | | // æå¼æ¹éååºå¼¹çª |
| | | openBatchReturnDialog() { |
| | | console.log('æå¼æ¹éååºå¼¹çª'); |
| | | this.showBatchReturnDialog = true; |
| | | |
| | | // é置表å |
| | | this.resetBatchReturnForm(); |
| | | |
| | | // 设置订åä¿¡æ¯ |
| | | this.batchReturnForm.orderNo = this.scanData.orderNo; |
| | | |
| | | // æ´æ°æªæ£éä¿¡æ¯ |
| | | this.batchReturnForm.unpickedCount = this.summary.unpickedCount || 0; |
| | | this.batchReturnForm.unpickedQuantity = this.summary.unpickedQuantity || 0; |
| | | |
| | | // æ¸
é¤è¡¨åéªè¯ |
| | | this.$nextTick(() => { |
| | | if (this.$refs.batchReturnFormRef) { |
| | | this.$refs.batchReturnFormRef.clearValidate(); |
| | | } |
| | | }); |
| | | }, |
| | | |
| | | // å
³éæ¹éååºå¼¹çª |
| | | closeBatchReturnDialog() { |
| | | this.showBatchReturnDialog = false; |
| | | this.resetBatchReturnForm(); |
| | | |
| | | // æ¸
é¤è¡¨åéªè¯ |
| | | if (this.$refs.batchReturnFormRef) { |
| | | this.$refs.batchReturnFormRef.clearValidate(); |
| | | } |
| | | }, |
| | | |
| | | // ååºæçç æ«ç |
| | | onBatchReturnPalletScan() { |
| | | if (!this.batchReturnForm.palletCode) return; |
| | | |
| | | this.batchReturnForm.palletCode = this.batchReturnForm.palletCode.replace(/\n/g, '').trim(); |
| | | |
| | | // æ¸
é¤éªè¯ç¶æ |
| | | if (this.$refs.batchReturnFormRef) { |
| | | this.$refs.batchReturnFormRef.clearValidate(['palletCode']); |
| | | } |
| | | }, |
| | | |
| | | // ååºç¡®è®¤ |
| | | async handleBatchReturnConfirm() { |
| | | // 表åéªè¯ |
| | | if (this.$refs.batchReturnFormRef) { |
| | | this.$refs.batchReturnFormRef.validate((valid) => { |
| | | if (valid) { |
| | | this.submitBatchReturn(); |
| | | } else { |
| | | this.$message.warning('è¯·æ«ææçç '); |
| | | return false; |
| | | } |
| | | }); |
| | | } else { |
| | | // å¦ææ²¡æè¡¨åå¼ç¨ï¼ä½¿ç¨åæçéªè¯ |
| | | if (!this.batchReturnForm.palletCode) { |
| | | this.$message.warning('è¯·æ«ææçç '); |
| | | return; |
| | | } |
| | | |
| | | this.submitBatchReturn(); |
| | | } |
| | | }, |
| | | |
| | | // æäº¤ååºè¯·æ± |
| | | async submitBatchReturn() { |
| | | this.batchReturnLoading = true; |
| | | |
| | | try { |
| | | const res = await this.http.post('/api/OutboundPicking/return-to-stock', { |
| | | orderNo: this.batchReturnForm.orderNo, |
| | | palletCode: this.batchReturnForm.palletCode |
| | | }); |
| | | |
| | | if (res.status) { |
| | | this.$message.success(res.message); |
| | | this.showBatchReturnDialog = false; |
| | | this.loadData(); |
| | | } else { |
| | | this.$message.error(res.message || 'ååºå¤±è´¥'); |
| | | } |
| | | } catch (error) { |
| | | this.$message.error('ååºå¤±è´¥'); |
| | | } finally { |
| | | this.batchReturnLoading = false; |
| | | } |
| | | }, |
| | | // æå¼ç´æ¥åºåºå¼¹çª |
| | | openDirectOutDialog() { |
| | | console.log('æå¼ç´æ¥åºåºå¼¹çª'); |
| | | this.showDirectOutDialog = true; |
| | | |
| | | // é置表å |
| | | this.resetDirectOutForm(); |
| | | |
| | | // 设置订åä¿¡æ¯ |
| | | this.directOutForm.orderNo = this.scanData.orderNo; |
| | | |
| | | // æ¸
é¤è¡¨åéªè¯ |
| | | this.$nextTick(() => { |
| | | if (this.$refs.directOutFormRef) { |
| | | this.$refs.directOutFormRef.clearValidate(); |
| | | } |
| | | }); |
| | | }, |
| | | |
| | | // å
³éç´æ¥åºåºå¼¹çª |
| | | closeDirectOutDialog() { |
| | | this.showDirectOutDialog = false; |
| | | this.resetDirectOutForm(); |
| | | |
| | | // æ¸
é¤è¡¨åéªè¯ |
| | | if (this.$refs.directOutFormRef) { |
| | | this.$refs.directOutFormRef.clearValidate(); |
| | | } |
| | | }, |
| | | |
| | | // ç´æ¥åºåºæçç æ«ç |
| | | onDirectOutPalletScan() { |
| | | if (!this.directOutForm.palletCode) return; |
| | | |
| | | this.directOutForm.palletCode = this.directOutForm.palletCode.replace(/\n/g, '').trim(); |
| | | |
| | | // æ¸
é¤éªè¯ç¶æ |
| | | if (this.$refs.directOutFormRef) { |
| | | this.$refs.directOutFormRef.clearValidate(['palletCode']); |
| | | } |
| | | }, |
| | | |
| | | // ç´æ¥åºåºç¡®è®¤ |
| | | async handleDirectOutConfirm() { |
| | | // 表åéªè¯ |
| | | if (this.$refs.directOutFormRef) { |
| | | this.$refs.directOutFormRef.validate((valid) => { |
| | | if (valid) { |
| | | this.submitDirectOut(); |
| | | } else { |
| | | this.$message.warning('è¯·æ«ææçç '); |
| | | return false; |
| | | } |
| | | }); |
| | | } else { |
| | | // å¦ææ²¡æè¡¨åå¼ç¨ï¼ä½¿ç¨åæçéªè¯ |
| | | if (!this.directOutForm.palletCode) { |
| | | this.$message.warning('è¯·æ«ææçç '); |
| | | return; |
| | | } |
| | | |
| | | this.submitDirectOut(); |
| | | } |
| | | }, |
| | | |
| | | // æäº¤ç´æ¥åºåºè¯·æ± |
| | | async submitDirectOut() { |
| | | this.directOutLoading = true; |
| | | |
| | | try { |
| | | const res = await this.http.post('/api/OutboundPicking/direct-outbound', { |
| | | orderNo: this.directOutForm.orderNo, |
| | | palletCode: this.directOutForm.palletCode |
| | | }); |
| | | debugger; |
| | | if (res.status) { |
| | | this.$message.success('ç´æ¥åºåºæå'); |
| | | this.showDirectOutDialog = false; |
| | | this.loadData(); |
| | | } else { |
| | | this.$message.error(res.message || 'ç´æ¥åºåºå¤±è´¥'); |
| | | } |
| | | } catch (error) { |
| | | this.$message.error('ç´æ¥åºåºå¤±è´¥'); |
| | | } finally { |
| | | this.directOutLoading = false; |
| | | } |
| | | }, |
| | | |
| | | // éç½®ç´æ¥åºåºè¡¨å |
| | | resetDirectOutForm() { |
| | | this.directOutForm.palletCode = ''; |
| | | }, |
| | | |
| | | // ä¿®æ¹åæçç´æ¥åºåºæé®ç¹å»äºä»¶ |
| | | handleDirectOutbound() { |
| | | this.openDirectOutDialog(); |
| | | }, |
| | | |
| | | // æå¼åèµ°ç©ºç®±å¼¹çª |
| | | openEmptyPalletDialog() { |
| | | console.log('æå¼å走空箱弹çª'); |
| | | this.showEmptyPalletDialog = true; |
| | | |
| | | // é置表å |
| | | this.resetEmptyPalletForm(); |
| | | |
| | | // 设置订åä¿¡æ¯ |
| | | this.emptypalletOutForm.orderNo = this.scanData.orderNo; |
| | | |
| | | // æ¸
é¤è¡¨åéªè¯ |
| | | this.$nextTick(() => { |
| | | if (this.$refs.emptyPalletFormRef) { |
| | | this.$refs.emptyPalletFormRef.clearValidate(); |
| | | } |
| | | }); |
| | | }, |
| | | |
| | | // å
³éåèµ°ç©ºç®±å¼¹çª |
| | | closeEmptyPalletDialog() { |
| | | this.showEmptyPalletDialog = false; |
| | | this.resetEmptyPalletForm(); |
| | | |
| | | // æ¸
é¤è¡¨åéªè¯ |
| | | if (this.$refs.emptyPalletFormRef) { |
| | | this.$refs.emptyPalletFormRef.clearValidate(); |
| | | } |
| | | }, |
| | | |
| | | // å走空箱æçç æ«ç |
| | | onEmptyPalletScan() { |
| | | if (!this.emptypalletOutForm.palletCode) return; |
| | | |
| | | this.emptypalletOutForm.palletCode = this.emptypalletOutForm.palletCode.replace(/\n/g, '').trim(); |
| | | |
| | | // æ¸
é¤éªè¯ç¶æ |
| | | if (this.$refs.emptyPalletFormRef) { |
| | | this.$refs.emptyPalletFormRef.clearValidate(['palletCode']); |
| | | } |
| | | }, |
| | | |
| | | // å走空箱确认 |
| | | async handleEmptyPalletConfirm() { |
| | | // 表åéªè¯ |
| | | if (this.$refs.emptyPalletFormRef) { |
| | | this.$refs.emptyPalletFormRef.validate((valid) => { |
| | | if (valid) { |
| | | this.submitEmptyPallet(); |
| | | } else { |
| | | this.$message.warning('è¯·æ«ææçç '); |
| | | return false; |
| | | } |
| | | }); |
| | | } else { |
| | | // å¦ææ²¡æè¡¨åå¼ç¨ï¼ä½¿ç¨åæçéªè¯ |
| | | if (!this.emptypalletOutForm.palletCode) { |
| | | this.$message.warning('è¯·æ«ææçç '); |
| | | return; |
| | | } |
| | | |
| | | this.submitEmptyPallet(); |
| | | } |
| | | }, |
| | | |
| | | // æäº¤åèµ°ç©ºç®±è¯·æ± |
| | | async submitEmptyPallet() { |
| | | this.emptypalletOutLoading = true; |
| | | |
| | | try { |
| | | const res = await this.http.post('/api/OutboundPicking/remove-empty-pallet', { |
| | | orderNo: this.emptypalletOutForm.orderNo, |
| | | palletCode: this.emptypalletOutForm.palletCode |
| | | }); |
| | | debugger; |
| | | if (res.status) { |
| | | this.$message.success('å走空箱æå'); |
| | | this.showEmptyPalletDialog = false; |
| | | this.loadData(); |
| | | } else { |
| | | this.$message.error(res.message || 'å走空箱失败'); |
| | | } |
| | | } catch (error) { |
| | | this.$message.error('å走空箱失败'); |
| | | } finally { |
| | | this.emptypalletOutLoading = false; |
| | | } |
| | | }, |
| | | |
| | | // éç½®å走空箱表å |
| | | resetEmptyPalletForm() { |
| | | this.emptypalletOutForm.palletCode = ''; |
| | | }, |
| | | |
| | | // ä¿®æ¹åæçå走空箱æé®ç¹å»äºä»¶ |
| | | handleEmptyPallet() { |
| | | this.openEmptyPalletDialog(); |
| | | }, |
| | | |
| | | |
| | | |
| | | |
| | | async loadData() { |
| | | if (!this.scanData.orderNo || !this.scanData.palletCode) { |
| | | return; |
| | | } |
| | | |
| | | try { |
| | | // å è½½æªæ£éå表 |
| | | const unpickedRes = await this.http.post('/api/OutboundPicking/unpicked-list', this.scanData); |
| | | this.unpickedList = unpickedRes.data || []; |
| | | |
| | | // å 载已æ£éå表 |
| | | const pickedRes = await this.http.post('/api/OutboundPicking/picked-list', this.scanData); |
| | | this.pickedList = pickedRes.data || []; |
| | | |
| | | // å è½½æ±æ»ä¿¡æ¯ |
| | | const summaryRes = await this.http.post('/api/OutboundPicking/picking-summary',this.scanData); |
| | | this.summary = summaryRes.data || {}; |
| | | |
| | | // æ´æ°æçç¶æ |
| | | this.updatePalletStatus(); |
| | | |
| | | } catch (error) { |
| | | this.$message.error('å è½½æ°æ®å¤±è´¥'); |
| | | } |
| | | }, |
| | | |
| | | updatePalletStatus() { |
| | | if (this.unpickedList.length === 0 && this.pickedList.length > 0) { |
| | | this.palletStatus = 'å·²å
¨é¨æ£é'; |
| | | } else if (this.unpickedList.length > 0 && this.pickedList.length === 0) { |
| | | this.palletStatus = 'å¾
æ£é'; |
| | | } else if (this.unpickedList.length > 0 && this.pickedList.length > 0) { |
| | | this.palletStatus = 'é¨åæ£é'; |
| | | } else { |
| | | this.palletStatus = 'æ æ°æ®'; |
| | | } |
| | | }, |
| | | // å·²æ£éåè¡¨éæ©åå |
| | | handlePickedSelectionChange(selection) { |
| | | this.selectedPickedRows = selection; |
| | | }, |
| | | // æ¹éåæ¶éä¸çå·²æ£é项 |
| | | async batchCancelSelected() { |
| | | if (this.selectedPickedRows.length === 0) { |
| | | this.$message.warning('请å
éæ©è¦åæ¶ç项'); |
| | | return; |
| | | } |
| | | |
| | | this.$confirm(`ç¡®å®è¦åæ¶éä¸ç ${this.selectedPickedRows.length} 项åï¼`, 'æç¤º', { |
| | | confirmButtonText: 'ç¡®å®', |
| | | cancelButtonText: 'åæ¶', |
| | | type: 'warning' |
| | | }).then(async () => { |
| | | try { |
| | | let successCount = 0; |
| | | let errorCount = 0; |
| | | |
| | | for (const row of this.selectedPickedRows) { |
| | | try { |
| | | const res = await this.http.post('/api/OutboundPicking/CancelPicking', { |
| | | orderNo: this.scanData.orderNo, |
| | | palletCode: this.scanData.palletCode, |
| | | barcode: row.currentBarcode |
| | | }); |
| | | |
| | | if (res.status) { |
| | | successCount++; |
| | | this.$message.success(`æååæ¶`); |
| | | } else { |
| | | errorCount++; |
| | | this.$message.warning(`åæ¶æ£é失败: ${row.currentBarcode} - ${res.message}`); |
| | | } |
| | | } catch (error) { |
| | | errorCount++; |
| | | this.$message.warning(`åæ¶æ£é失败: ${row.currentBarcode} - ${error.message}` ); |
| | | } |
| | | } |
| | | |
| | | this.loadData(); |
| | | this.selectedPickedRows = []; |
| | | } catch (error) { |
| | | this.$message.error('æ¹éåæ¶æä½å¤±è´¥'); |
| | | } |
| | | }).catch(() => { |
| | | this.$message.info('已忶æ¹éæä½'); |
| | | }); |
| | | }, |
| | | // æçç æ«ç |
| | | onPalletScan() { |
| | | // å»é¤å车符åååç©ºæ ¼ |
| | | this.scanData.palletCode = this.scanData.palletCode.replace(/\n/g, '').trim(); |
| | | if (!this.scanData.palletCode) return; |
| | | |
| | | this.splitForm.palletCode = this.scanData.palletCode; |
| | | this.returnForm.palletCode = this.scanData.palletCode; |
| | | |
| | | // å è½½æ°æ® |
| | | this.loadData(); |
| | | |
| | | // èªå¨è·³è½¬å°ç©ææ¡ç è¾å
¥æ¡ |
| | | this.$nextTick(() => { |
| | | this.$refs.barcodeInput.focus(); |
| | | }); |
| | | }, |
| | | |
| | | onBarcodeScan() { |
| | | // å»é¤å车符åååç©ºæ ¼ |
| | | this.scanData.barcode = this.scanData.barcode.replace(/\n/g, '').trim(); |
| | | if (!this.scanData.barcode) return; |
| | | |
| | | // èªå¨ç¡®è®¤æ£é |
| | | this.confirmPicking(); |
| | | }, |
| | | |
| | | async confirmPicking() { |
| | | if (this.isProcessing) return; |
| | | |
| | | if (!this.scanData.orderNo || !this.scanData.palletCode || !this.scanData.barcode) { |
| | | this.$message.warning('请å
æ«ææçç åç©ææ¡ç '); |
| | | this.focusBarcodeInput(); |
| | | return; |
| | | } |
| | | |
| | | this.isProcessing = true; |
| | | |
| | | try { |
| | | const res = await this.http.post('/api/OutboundPicking/confirm-picking', this.scanData); |
| | | if (res.status) { |
| | | this.$message.success('æ£é确认æå'); |
| | | this.scanData.barcode = ''; // æ¸
ç©ºç©ææ¡ç |
| | | this.loadData(); |
| | | console.log(res.data.splitResults) |
| | | if(res.data && res.data.splitResults.length>0){ |
| | | // è°ç¨åç»ä»¶æå°æ¹æ³ |
| | | this.$refs.childs.open(res.data.splitResults); |
| | | //this.$refs.childs.printSplitLabel(res.data.splitResults); |
| | | } |
| | | // æååç»§ç»èç¦å°ç©ææ¡ç è¾å
¥æ¡ï¼åå¤ä¸ä¸ä¸ªæ«ç |
| | | this.$nextTick(() => { |
| | | this.$refs.barcodeInput.focus(); |
| | | }); |
| | | } else { |
| | | // æ¾ç¤ºå端è¿åçéè¯¯ä¿¡æ¯ |
| | | this.$message.error(res.message || 'æ£é确认失败'); |
| | | // 失败æ¶èç¦å¹¶éä¸ç©ææ¡ç è¾å
¥æ¡å
容 |
| | | this.focusBarcodeInput(true); |
| | | } |
| | | } catch (error) { |
| | | this.$message.error('æ£é确认失败: ' + (error.message || 'ç½ç»é误')); |
| | | // 失败æ¶èç¦å¹¶éä¸ç©ææ¡ç è¾å
¥æ¡å
容 |
| | | this.focusBarcodeInput(true); |
| | | } finally { |
| | | this.isProcessing = false; |
| | | } |
| | | }, |
| | | |
| | | // èç¦å°ç©ææ¡ç è¾å
¥æ¡ |
| | | focusBarcodeInput(selectText = false) { |
| | | this.$nextTick(() => { |
| | | const input = this.$refs.barcodeInput; |
| | | if (input && input.$el && input.$el.querySelector('input')) { |
| | | const inputEl = input.$el.querySelector('input'); |
| | | inputEl.focus(); |
| | | if (selectText) { |
| | | inputEl.select(); |
| | | } |
| | | } |
| | | }); |
| | | }, |
| | | |
| | | async cancelPicking(row) { |
| | | try { |
| | | const res = await this.http.post('/api/OutboundPicking/CancelPicking', { |
| | | orderNo: this.scanData.orderNo, |
| | | palletCode: this.scanData.palletCode, |
| | | barcode: row.Barcode |
| | | }); |
| | | |
| | | if (res.status) { |
| | | this.$message.success('åæ¶æ£éæå'); |
| | | this.loadData(); |
| | | } else { |
| | | this.$message.error(res.message || 'åæ¶æ£é失败'); |
| | | } |
| | | } catch (error) { |
| | | this.$message.error('åæ¶æ£é失败'); |
| | | } |
| | | }, |
| | | |
| | | /* // ååºæä½ - ååºæ´ä¸ªæçæªæ£éçè´§ç© |
| | | async handleBatchReturn() { |
| | | if (!this.scanData.orderNo || !this.scanData.palletCode) { |
| | | this.$message.warning('请å
æ«ææçç '); |
| | | return; |
| | | } |
| | | |
| | | if (this.unpickedList.length === 0) { |
| | | this.$message.warning('该æç没æå¯ååºçè´§ç©'); |
| | | return; |
| | | } |
| | | |
| | | this.$confirm(`ç¡®å®è¦ååºæ´ä¸ªæççæªæ£éè´§ç©åï¼å
± ${this.unpickedList.length} æ¡è®°å½`, 'æç¤º', { |
| | | confirmButtonText: 'ç¡®å®', |
| | | cancelButtonText: 'åæ¶', |
| | | type: 'warning' |
| | | }).then(async () => { |
| | | try { |
| | | const res = await this.http.post('/api/OutboundPicking/batch-return-to-stock', { |
| | | orderNo: this.scanData.orderNo, |
| | | palletCode: this.scanData.palletCode |
| | | }); |
| | | |
| | | if (res.success) { |
| | | this.$message.success('æ¹éååºæå'); |
| | | this.loadData(); |
| | | } else { |
| | | this.$message.error(res.message || 'æ¹éååºå¤±è´¥'); |
| | | } |
| | | } catch (error) { |
| | | this.$message.error('æ¹éååºå¤±è´¥'); |
| | | } |
| | | }).catch(() => { |
| | | this.$message.info('已忶æ¹éååº'); |
| | | }); |
| | | }, */ |
| | | |
| | | /* // ç´æ¥åºåºæä½ |
| | | async handleDirectOutbound() { |
| | | if (!this.scanData.orderNo || !this.scanData.palletCode) { |
| | | this.$message.warning('请å
æ«ææçç '); |
| | | return; |
| | | } |
| | | |
| | | this.$confirm('ç¡®å®è¦ç´æ¥åºåºæ´ä¸ªæçåï¼', 'æç¤º', { |
| | | confirmButtonText: 'ç¡®å®', |
| | | cancelButtonText: 'åæ¶', |
| | | type: 'warning' |
| | | }).then(async () => { |
| | | try { |
| | | const res = await this.http.post('/api/OutboundPicking/direct-outbound', { |
| | | orderNo: this.scanData.orderNo, |
| | | palletCode: this.scanData.palletCode |
| | | }); |
| | | |
| | | if (res.success) { |
| | | this.$message.success('ç´æ¥åºåºæå'); |
| | | this.loadData(); |
| | | } else { |
| | | this.$message.error(res.message || 'ç´æ¥åºåºå¤±è´¥'); |
| | | } |
| | | } catch (error) { |
| | | this.$message.error('ç´æ¥åºåºå¤±è´¥'); |
| | | } |
| | | }).catch(() => { |
| | | this.$message.info('å·²åæ¶ç´æ¥åºåº'); |
| | | }); |
| | | }, */ |
| | | // 确认ååºï¼éè¿å¼¹çªï¼ |
| | | async handleReturnConfirm() { |
| | | if (!this.returnForm.barcode) { |
| | | this.$message.warning('è¯·æ«æååºæ¡ç '); |
| | | return; |
| | | } |
| | | |
| | | try { |
| | | const res = await this.http.post('/api/OutboundPicking/return-to-stock', { |
| | | orderNo: this.returnForm.orderNo, |
| | | palletCode: this.returnForm.palletCode, |
| | | barcode: this.returnForm.barcode |
| | | }); |
| | | |
| | | if (res.status) { |
| | | this.$message.success('ååºæå'); |
| | | this.showReturnDialog = false; |
| | | this.resetReturnForm(); |
| | | this.loadData(); |
| | | } else { |
| | | this.$message.error(res.message || 'ååºå¤±è´¥'); |
| | | } |
| | | } catch (error) { |
| | | this.$message.error('ååºå¤±è´¥'); |
| | | } |
| | | }, |
| | | |
| | | // æå
æ«ç |
| | | async onSplitBarcodeScan() { |
| | | if (!this.splitForm.originalBarcode) return; |
| | | |
| | | // å»é¤å车符åååç©ºæ ¼ |
| | | this.splitForm.originalBarcode = this.splitForm.originalBarcode.replace(/\n/g, '').trim(); |
| | | |
| | | try { |
| | | const res = await this.http.post('/api/OutboundPicking/split-package-info', { |
| | | |
| | | orderNo: this.splitForm.orderNo, |
| | | palletCode: this.splitForm.palletCode, |
| | | barcode: this.splitForm.originalBarcode |
| | | |
| | | }); |
| | | |
| | | if (res.status) { |
| | | this.splitForm.materielCode = res.data.materielCode; |
| | | this.splitForm.maxQuantity = res.data.remainQuantity; |
| | | this.splitForm.splitQuantity = Math.min(1, this.splitForm.maxQuantity); |
| | | // æ¸
é¤éªè¯ç¶æ |
| | | if (this.$refs.splitFormRef) { |
| | | this.$refs.splitFormRef.clearValidate(['originalBarcode']); |
| | | } |
| | | } else { |
| | | this.$message.error(res.message || 'è·åæå
ä¿¡æ¯å¤±è´¥'); |
| | | // éªè¯å¤±è´¥ï¼è®¾ç½®éè¯¯ç¶æ |
| | | if (this.$refs.splitFormRef) { |
| | | this.$refs.splitFormRef.validateField('originalBarcode'); |
| | | } |
| | | } |
| | | } catch (error) { |
| | | this.$message.error('è·åæå
ä¿¡æ¯å¤±è´¥'); |
| | | // éªè¯å¤±è´¥ï¼è®¾ç½®éè¯¯ç¶æ |
| | | if (this.$refs.splitFormRef) { |
| | | this.$refs.splitFormRef.validateField('originalBarcode'); |
| | | } |
| | | } |
| | | }, |
| | | |
| | | async handleSplitPackage() { |
| | | // 表åéªè¯ |
| | | if (this.$refs.splitFormRef) { |
| | | this.$refs.splitFormRef.validate((valid) => { |
| | | if (valid) { |
| | | this.submitSplitPackage(); |
| | | } else { |
| | | this.$message.warning('请填å宿´çæå
ä¿¡æ¯'); |
| | | return false; |
| | | } |
| | | }); |
| | | } else { |
| | | // å¦ææ²¡æè¡¨åå¼ç¨ï¼ä½¿ç¨åæçéªè¯ |
| | | if (!this.splitForm.originalBarcode || this.splitForm.splitQuantity <= 0) { |
| | | this.$message.warning('请填å宿´çæå
ä¿¡æ¯'); |
| | | return; |
| | | } |
| | | |
| | | if (this.splitForm.splitQuantity > this.splitForm.maxQuantity) { |
| | | this.$message.warning('æå
æ°éä¸è½å¤§äºå©ä½æ°é'); |
| | | return; |
| | | } |
| | | |
| | | this.submitSplitPackage(); |
| | | } |
| | | |
| | | |
| | | }, |
| | | // æäº¤æå
è¯·æ± |
| | | async submitSplitPackage() { |
| | | this.splitLoading = true; |
| | | try { |
| | | const res = await this.http.post('/api/OutboundPicking/split-package', this.splitForm); |
| | | if (res.status) { |
| | | this.$message.success('æå
æå'); |
| | | this.showSplitDialog = false; |
| | | this.splitLoading = false; |
| | | this.resetSplitForm(); |
| | | this.loadData(); |
| | | } else { |
| | | this.splitLoading = false; |
| | | this.$message.error(res.message || 'æå
失败'); |
| | | } |
| | | } catch (error) { |
| | | this.splitLoading = false; |
| | | this.$message.error('æå
失败'); |
| | | } |
| | | }, |
| | | // æ¤éæå
æ«ç |
| | | onRevertSplitBarcodeScan() { |
| | | if (!this.revertSplitForm.originalBarcode) return; |
| | | |
| | | this.revertSplitForm.originalBarcode = this.revertSplitForm.originalBarcode.replace(/\n/g, '').trim(); |
| | | |
| | | // æ¸
é¤éªè¯ç¶æ |
| | | if (this.$refs.revertSplitFormRef) { |
| | | this.$refs.revertSplitFormRef.clearValidate(['originalBarcode']); |
| | | } |
| | | }, |
| | | async handleRevertSplit() { |
| | | // 表åéªè¯ |
| | | if (this.$refs.revertSplitFormRef) { |
| | | this.$refs.revertSplitFormRef.validate((valid) => { |
| | | if (valid) { |
| | | this.submitRevertSplit(); |
| | | } else { |
| | | this.$message.warning('请è¾å
¥åæ¡ç '); |
| | | return false; |
| | | } |
| | | }); |
| | | } else { |
| | | // å¦ææ²¡æè¡¨åå¼ç¨ï¼ä½¿ç¨åæçéªè¯ |
| | | if (!this.revertSplitForm.originalBarcode) { |
| | | this.$message.warning('请è¾å
¥åæ¡ç '); |
| | | return; |
| | | } |
| | | |
| | | this.submitRevertSplit(); |
| | | } |
| | | }, |
| | | // æäº¤æ¤éæå
è¯·æ± |
| | | async submitRevertSplit() { |
| | | this.revertSplitLoading = true; |
| | | |
| | | try { |
| | | const res = await this.http.post('/api/OutboundPicking/revert-split-package', { |
| | | originalBarcode: this.revertSplitForm.originalBarcode |
| | | }); |
| | | |
| | | if (res.status) { |
| | | this.$message.success('æ¤éæå
æå'); |
| | | this.showRevertSplitDialog = false; |
| | | this.revertSplitLoading = false; |
| | | this.revertSplitForm.originalBarcode = ''; |
| | | this.loadData(); |
| | | } else { |
| | | this.revertSplitLoading = false; |
| | | this.$message.error(res.message || 'æ¤éæå
失败'); |
| | | } |
| | | } catch (error) { |
| | | this.revertSplitLoading = false; |
| | | this.$message.error('æ¤éæå
失败'); |
| | | } |
| | | }, |
| | | resetSplitForm() { |
| | | this.splitForm.originalBarcode = ''; |
| | | this.splitForm.materielCode = ''; |
| | | this.splitForm.splitQuantity = 0; |
| | | this.splitForm.maxQuantity = 0; |
| | | }, |
| | | // éç½®æ¹éååºè¡¨å |
| | | resetBatchReturnForm() { |
| | | this.batchReturnForm.palletCode = ''; |
| | | this.batchReturnForm.unpickedCount = 0; |
| | | this.batchReturnForm.unpickedQuantity = 0; |
| | | }, |
| | | resetReturnForm() { |
| | | this.returnForm.barcode = ''; |
| | | this.returnForm.materielCode = ''; |
| | | this.returnForm.returnQuantity = 0; |
| | | } |
| | | } |
| | | }) |
| | | </script> |
| | | |
| | | <style scoped> |
| | | .picking-container { |
| | | padding: 20px; |
| | | position: relative; /* 为弹çªå®ä½æä¾ä¸ä¸æ */ |
| | | } |
| | | .scanner-form { |
| | | display: flex; |
| | | gap: 10px; |
| | | align-items: center; |
| | | flex-wrap: wrap; |
| | | } |
| | | .scanner-form .el-input { |
| | | width: 200px; |
| | | } |
| | | .summary-info { |
| | | display: flex; |
| | | gap: 20px; |
| | | flex-wrap: wrap; |
| | | } |
| | | |
| | | /* è¡¨æ ¼æä½åºåæ ·å¼ */ |
| | | .table-actions { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | margin-bottom: 10px; |
| | | padding: 0 10px; |
| | | } |
| | | |
| | | .selection-count { |
| | | font-size: 12px; |
| | | color: #909399; |
| | | } |
| | | |
| | | /* è¡¨æ ¼æ ·å¼è°æ´ */ |
| | | .content-area .el-table { |
| | | margin-top: 0; |
| | | } |
| | | |
| | | /* ç¡®ä¿è¡¨æ ¼é«åº¦éåº */ |
| | | .content-area .el-card__body { |
| | | padding: 15px; |
| | | } |
| | | |
| | | |
| | | /* èªå®ä¹å¼¹çªæ ·å¼ */ |
| | | .custom-dialog-overlay { |
| | | position: fixed; |
| | | top: 0; |
| | | left: 0; |
| | | right: 0; |
| | | bottom: 0; |
| | | background-color: rgba(0, 0, 0, 0.5); |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | z-index: 9999; |
| | | } |
| | | |
| | | .custom-dialog-wrapper { |
| | | position: relative; |
| | | z-index: 10000; |
| | | } |
| | | |
| | | .custom-dialog { |
| | | background: white; |
| | | border-radius: 4px; |
| | | width: 500px; |
| | | max-width: 90vw; |
| | | max-height: 90vh; |
| | | box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1); |
| | | overflow: auto; |
| | | } |
| | | |
| | | .custom-dialog-header { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | padding: 20px 20px 10px; |
| | | border-bottom: 1px solid #ebeef5; |
| | | } |
| | | |
| | | .custom-dialog-header h3 { |
| | | margin: 0; |
| | | color: #303133; |
| | | } |
| | | |
| | | /* å
³éæé®æ ·å¼ */ |
| | | .close-button { |
| | | font-size: 18px; |
| | | color: #909399; |
| | | padding: 0; |
| | | width: 24px; |
| | | height: 24px; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | } |
| | | |
| | | .close-button:hover { |
| | | color: #409EFF; |
| | | background-color: transparent; |
| | | } |
| | | |
| | | .custom-dialog-body { |
| | | padding: 20px; |
| | | } |
| | | |
| | | .custom-dialog-footer { |
| | | padding: 10px 20px 20px; |
| | | text-align: right; |
| | | border-top: 1px solid #ebeef5; |
| | | } |
| | | |
| | | .custom-dialog-footer .el-button { |
| | | margin-left: 10px; |
| | | } |
| | | |
| | | /* ç¡®ä¿å¼¹çªå¨ç§»å¨è®¾å¤ä¸ä¹è½æ£å¸¸æ¾ç¤º */ |
| | | @media (max-width: 768px) { |
| | | .custom-dialog { |
| | | width: 95vw; |
| | | margin: 10px; |
| | | } |
| | | } |
| | | </script> |
| | | </style> |