ÏîÄ¿´úÂë/WIDESEA_WMSClient/src/extension/basic/extend/printView.vue
@@ -59,13 +59,97 @@ print() { let printContent = document.getElementById("printContent"); let palletcode=document.getElementById("palletcode"); var printWindow = window.open("", ""); printWindow.document.write(printContent.innerHTML); printWindow.document.write(palletcode.innerHTML); var printWindow = window.open("", "", "width=400,height=400"); // åå»ºå®æ´çHTMLç»æä»¥é¿å 空ç½é¡µ printWindow.document.write(` <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>æå°</title> <style> @page { size: auto; margin: 0; } body { margin: 0; padding: 10px; font-family: Arial, sans-serif; background: white; } .print-container { width: 100%; height: 100vh; display: flex; flex-direction: column; justify-content: center; align-items: center; page-break-after: avoid; } .qrcode-container { display: flex; justify-content: center; align-items: center; margin-bottom: 20px; } .pallet-code { display: flex; justify-content: center; align-items: center; font-size: 18px; font-weight: bold; } canvas { display: block !important; margin: auto !important; } @media print { body { margin: 0; padding: 5mm; } .print-container { width: 100%; height: 100vh; page-break-after: avoid; page-break-inside: avoid; } } </style> </head> <body> <div class="print-container"> <div class="qrcode-container"> ${printContent.innerHTML} </div> <div class="pallet-code"> ${palletcode.innerHTML} </div> </div> <script> window.onload = function() { setTimeout(function() { window.print(); window.close(); }, 500); }; <\/script> </body> </html> `); printWindow.document.close(); printWindow.focus(); printWindow.print(); printWindow.close(); this.http .post("api/palletCodeInfo/PrintStatusUp?printCode="+this.palletCode, null, "æ°æ®å¤çä¸") .then((x) => { ÏîÄ¿´úÂë/WIDESEA_WMSClient/src/extension/outbound/extend/printView.vue
@@ -192,6 +192,7 @@ return } printWindow.document.write(` <!DOCTYPE html> <html> @@ -236,26 +237,39 @@ padding: 0 !important; } body { html { height: auto !important; width: 80mm !important; height: 60mm !important; margin: 0 !important; padding: 0 !important; background: white !important; } body { height: auto !important; width: 80mm !important; margin: 0 !important; padding: 0 !important; background: white !important; overflow: visible !important; min-height: 0 !important; max-height: none !important; } .print-page { width: 80mm !important; height: 60mm !important; page-break-after: always !important; margin: 0 !important; padding: 1mm !important; display: block !important; background: white !important; page-break-inside: avoid !important; position: relative !important; page-break-after: always !important; } .print-page:last-child { page-break-after: avoid !important; page-break-after: auto !important; } .material-card { ÏîÄ¿´úÂë/WIDESEA_WMSClient/src/extension/outbound/outboundOrder.js
@@ -340,12 +340,15 @@ if (!selectedRows || selectedRows.length === 0) { return _this.$Message.warning('请å éæ©éè¦å¤ççåæ®'); } const requestParams = { orderNos: selectedRows.map(row => row.orderNo), inout: 2 }; if (selectedRows.length > 1) { return _this.$Message.warning('è¯·éæ©ä¸æ¡æ°æ®'); } // const requestParams = { // orderNos: selectedRows.map(row => row.orderNo), // inout: 2 // }; _this.http .post("api/InboundOrder/BatchOrderFeedbackToMes", requestParams, "æ°æ®å¤çä¸...") .post(`api/MesFeedback/OutboundFeedback?orderNo=${selectedRows[0].orderNo}`, {}, "æ°æ®å¤çä¸...") .then((x) => { if (x.status) { _this.$Message.success('åæ¹åºåºåè°å®æ'); ÏîÄ¿´úÂë/WIDESEA_WMSClient/src/views/outbound/out copyPicking.vue
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,805 @@ <template> <div class="picking-container"> <!-- é¡¶é¨è®¢åä¿¡æ¯ --> <el-card class="order-info-card" shadow="never"> <div class="order-header"> <div class="order-title"> <i class="el-icon-document"></i> <span class="order-label">订åå·ï¼</span> <span class="order-value">{{ orderNo }}</span> </div> <div class="order-status" v-if="orderInfo"> <el-tag :type="getStatusType(orderInfo.status)" size="medium"> {{ orderInfo.statusName || 'è¿è¡ä¸' }} </el-tag> </div> </div> </el-card> <!-- æ«ç æä½åºå --> <el-card class="scan-section-card" shadow="never"> <div class="scan-section"> <el-alert title="è¯·ä½¿ç¨æ«ç æªæ«æï¼æ¯æå车èªå¨ç¡®è®¤" type="info" :closable="false" show-icon class="scan-alert"> <template #default> <span>1. è¯·å æ«ææçç â 2. åæ«æç©ææ¡ç </span> </template> </el-alert> <el-form :model="scanForm" :rules="scanRules" ref="scanFormRef" class="scan-form"> <el-row :gutter="20"> <el-col :span="8"> <el-form-item label="æçç " prop="palletCode"> <el-input ref="palletInput" v-model="scanForm.palletCode" placeholder="è¯·æ«ææçç " size="large" clearable @keyup.enter="handlePalletScan"> <template #prefix> <i class="el-icon-box"></i> </template> </el-input> </el-form-item> </el-col> <el-col :span="8"> <el-form-item label="ç©ææ¡ç " prop="materialBarcode"> <el-input ref="materialInput" v-model="scanForm.materialBarcode" placeholder="è¯·æ«æç©ææ¡ç " size="large" clearable :disabled="unpickedData.length <= 0" @keyup.enter="handleMaterialScan"> <template #prefix> <i class="el-icon-s-grid"></i> </template> </el-input> </el-form-item> </el-col> <el-col :span="8"> <el-form-item class="button-form-item"> <div class="action-buttons"> <el-button type="primary" size="large" @click="handleConfirmPick" :loading="confirmLoading" :disabled="!canConfirm"> <i class="el-icon-check"></i> 确认æ£é </el-button> <el-button type="warning" size="large" @click="handleEmptyBox" :disabled="!scanForm.palletCode"> <i class="el-icon-delete"></i> å空箱 </el-button> <el-button type="success" size="large" @click="handleReturnToWarehouse" :disabled="!scanForm.palletCode"> <i class="el-icon-refresh-left"></i> ååº </el-button> </div> </el-form-item> </el-col> </el-row> </el-form> </div> </el-card> <!-- æ°æ®å表åºå --> <div class="tables-section"> <el-row :gutter="20"> <!-- æªæ£éå表 --> <el-col :span="12"> <el-card class="table-card" shadow="never"> <template #header> <div class="card-header"> <span class="card-title"> <i class="el-icon-time"></i> æªæ£éå表 </span> <el-badge :value="unpickedCount" class="badge-item" type="warning"> <el-button size="small" @click="refreshUnpickedTable" icon="el-icon-refresh"> å·æ° </el-button> </el-badge> </div> </template> <el-table ref="unpickedTable" :data="unpickedData" height="400" stripe highlight-current-row> <el-table-column type="index" label="åºå·" width="60" align="center" /> <el-table-column prop="materielCode" label="ç©æç¼ç " width="120" show-overflow-tooltip /> <el-table-column prop="materielName" label="ç©æåç§°" width="80" show-overflow-tooltip /> <el-table-column prop="batchNo" label="æ¹æ¬¡å·" width="100" /> <el-table-column prop="assignQuantity" label="忣æ°é" width="80" align="right"> <template #default="scope"> <el-text type="danger">{{ scope.row.assignQuantity }}</el-text> </template> </el-table-column> <el-table-column prop="sortedQuantity" label="已忣æ°é" width="120" align="right"> <template #default="scope"> <el-text type="danger">{{ scope.row.sortedQuantity }}</el-text> </template> </el-table-column> <el-table-column prop="unit" label="åä½" width="60" /> <el-table-column prop="locationCode" label="åºä½" /> <!-- <el-table-column label="æä½" width="80" align="center"> <template #default="scope"> <el-button type="text" size="small" @click="quickPick(scope.row)" :disabled="!scanForm.palletCode"> æ£é </el-button> </template> </el-table-column> --> </el-table> <div class="table-footer"> <el-descriptions :column="2" size="small"> <el-descriptions-item label="æ»æ¡æ°"> <el-text type="info">{{ unpickedTotal }}</el-text> </el-descriptions-item> <el-descriptions-item label="æ»æ°é"> <el-text type="warning">{{ unpickedQuantity }}</el-text> </el-descriptions-item> </el-descriptions> </div> </el-card> </el-col> <!-- å·²æ£éå表 --> <el-col :span="12"> <el-card class="table-card" shadow="never"> <template #header> <div class="card-header"> <span class="card-title"> <i class="el-icon-circle-check"></i> å·²æ£éå表 </span> <el-badge :value="pickedCount" class="badge-item" type="success"> <el-button size="small" @click="refreshPickedTable" icon="el-icon-refresh"> å·æ° </el-button> </el-badge> </div> </template> <el-table ref="pickedTable" :data="pickedData" height="400" stripe> <el-table-column type="index" label="åºå·" width="60" align="center" /> <el-table-column prop="materielCode" label="ç©æç¼ç " width="120" /> <el-table-column prop="materielName" label="ç©æåç§°" show-overflow-tooltip /> <el-table-column prop="batchNo" label="æ¹æ¬¡å·" width="100" /> <el-table-column prop="changeQuantity" label="æ£éæ°é" width="80" align="right"> <template #default="scope"> <el-text type="success">{{ 0 - scope.row.changeQuantity }}</el-text> </template> </el-table-column> <el-table-column prop="changeQuantity" label="ååºåé" width="80" align="right"> <template #default="scope"> <el-text type="success">{{ scope.row.beforeQuantity }}</el-text> </template> </el-table-column> <el-table-column prop="changeQuantity" label="æ£éååºåé" width="80" align="right"> <template #default="scope"> <el-text type="success">{{ scope.row.afterQuantity }}</el-text> </template> </el-table-column> <el-table-column prop="unit" label="åä½" width="60" /> <el-table-column prop="palletCode" label="æçç " width="100" /> <el-table-column prop="createDate" label="æ£éæ¶é´" width="160" /> <el-table-column prop="originalBarcode" label="åç©æç " width="160" /> <el-table-column prop="newBarcode" label="æ°ç©æç " width="160" /> <!-- <el-table-column label="æä½" width="80" align="center"> <template #default="scope"> <el-button type="text" size="small" @click="undoPick(scope.row)"> æ¤é </el-button> </template> </el-table-column> --> </el-table> <div class="table-footer"> <el-descriptions :column="2" size="small"> <el-descriptions-item label="æ»æ¡æ°"> <el-text type="info">{{ pickedTotal }}</el-text> </el-descriptions-item> <el-descriptions-item label="æ»æ°é"> <el-text type="success">{{ pickedQuantity }}</el-text> </el-descriptions-item> </el-descriptions> </div> </el-card> </el-col> </el-row> </div> <print-view ref="printView" @parentcall="parentcall"></print-view> <!-- ç¡®è®¤å¯¹è¯æ¡ --> <el-dialog v-model="confirmDialogVisible" title="æä½ç¡®è®¤" width="400px" :before-close="handleDialogClose"> <div class="confirm-content"> <p>{{ confirmMessage }}</p> </div> <template #footer> <span class="dialog-footer"> <el-button @click="confirmDialogVisible = false">åæ¶</el-button> <el-button type="primary" @click="executeConfirm" :loading="executeLoading"> ç¡®å® </el-button> </span> </template> </el-dialog> </div> </template> <script> import printView from "@/extension/outbound/extend/printView.vue" export default { components: { printView }, name: 'OutPicking', data() { return { orderNo: '', orderInfo: null, scanForm: { palletCode: '', materialBarcode: '' }, scanRules: { palletCode: [ { required: true, message: 'è¯·æ«ææçç ', trigger: 'blur' } ], materialBarcode: [ { required: true, message: 'è¯·æ«æç©ææ¡ç ', trigger: 'blur' } ] }, unpickedData: [], pickedData: [], unpickedCount: 0, unpickedTotal: 0, unpickedQuantity: 0, pickedCount: 0, pickedTotal: 0, pickedQuantity: 0, confirmLoading: false, confirmDialogVisible: false, confirmMessage: '', currentAction: null, executeLoading: false } }, computed: { canConfirm() { return this.scanForm.palletCode && this.scanForm.materialBarcode } }, mounted() { this.initPage() }, methods: { initPage() { // ä»è·¯ç±åæ°è·å订åå· this.orderNo = this.$route.query.orderNo || '' if (!this.orderNo) { this.$message.error('订åå·ä¸è½ä¸ºç©º') this.$router.back() return } // èªå¨èç¦å°æçç è¾å ¥æ¡ this.$nextTick(() => { if (this.$refs.palletInput) { this.$refs.palletInput.focus() } }) }, loadPalletData() { if (!this.scanForm.palletCode) { this.unpickedData = [] return } try { this.loadUnpickedData(); this.loadPickedData(); } catch (error) { console.error('å è½½æçæ°æ®å¤±è´¥:', error) this.unpickedData = [] } }, loadUnpickedData() { try { this.http.post(`/api/Outbound/QueryPickingTasks?orderNo=${this.orderNo}&palletCode=${this.scanForm.palletCode}`, {}).then(response => { if (response.status) { if (response.data.length > 0) { this.unpickedData = response.data this.calculateUnpickedStats() // èªå¨èç¦å°ç©ææ¡ç è¾å ¥æ¡ this.$nextTick(() => { if (this.$refs.materialInput) { this.$refs.materialInput.focus() } }) } else { this.$message.warning('该æçæ æªæ£éä»»å¡') this.unpickedData = [] } } else { this.$message.error(response.message || 'è·åæçæ°æ®å¤±è´¥') this.unpickedData = [] } } ) } catch (error) { console.error('å è½½æªæ£éæ°æ®å¤±è´¥:', error) } }, loadPickedData() { try { this.http.post(`/api/Outbound/QueryPickedList?orderNo=${this.orderNo}&palletCode=${this.scanForm.palletCode}`, {}).then(response => { if (response.status) { if (response.data.length > 0) { this.pickedData = response.data this.calculatePickedStats() } else { this.pickedData = [] } } else { this.$message.error(response.message || 'è·åæçæ°æ®å¤±è´¥') this.pickedData = [] } } ) } catch (error) { console.error('å 载已æ£éæ°æ®å¤±è´¥:', error) } }, // è®¡ç®æªæ£é calculateUnpickedStats() { // æªæ£éæ¡ç®æ°é this.unpickedCount = this.unpickedData.length // è®¡ç®æªæ£éçæ»æ°éï¼åæ£æ°é - 已忣æ°éï¼ this.unpickedQuantity = this.unpickedData.reduce((sum, item) => { const assignQty = item.assignQuantity || 0 const sortedQty = item.sortedQuantity || 0 const remainingQty = Math.max(0, assignQty - sortedQty) return sum + remainingQty }, 0) // æ»æ¡ç®æ°ï¼ä¸æ¡ç®æ°éç¸åï¼è¿éä¿çåéä¸è´æ§ï¼ this.unpickedTotal = this.unpickedCount }, // 计ç®å·²æ£é calculatePickedStats() { // å·²æ£éæ¡ç®æ°é this.pickedCount = this.pickedData.length // 计ç®å·²æ£éçæ»æ°é this.pickedQuantity = 0 - this.pickedData.reduce((sum, item) => { return (sum + item.changeQuantity) }, 0) // æ»æ¡ç®æ°ï¼ä¸æ¡ç®æ°éç¸åï¼ this.pickedTotal = this.pickedCount }, handlePalletScan() { if (this.scanForm.palletCode) { // this.$message.success(`æçç : ${this.scanForm.palletCode}`) this.loadPalletData() } }, handleMaterialScan() { if (!this.scanForm.palletCode) { this.$message.warning('è¯·å æ«ææçç ') this.$refs.palletInput.focus() return } if (!this.scanForm.materialBarcode) { this.$message.warning('è¯·æ«æç©ææ¡ç ') return } // èªå¨æ§è¡ç¡®è®¤æ£é this.handleConfirmPick() }, handleConfirmPick() { if (!this.scanForm.palletCode || !this.scanForm.materialBarcode) { this.$message.warning('è¯·å æ«ææçç åç©ææ¡ç ') return } this.confirmLoading = true try { this.http.post('/api/Outbound/CompleteOutboundWithBarcode', { orderNo: this.orderNo, palletCode: this.scanForm.palletCode, barcode: this.scanForm.materialBarcode, operator: this.getUserName() }).then(response => { if (response.status) { if (response.data.scannedDetail.isUnpacked && response.data.scannedDetail.materialCodes.length > 0) { this.$refs.printView.open(response.data.scannedDetail.materialCodes); } this.$message.success('æ£é确认æå') this.resetMaterialBarcode() // this.loadUnpickedData() // this.loadPickedData() this.loadPalletData() } else { this.$message.error(response.message || 'æ£é确认失败') } }) } catch (error) { console.error('æ£é确认失败:', error) this.$message.error('æ£é确认失败') } finally { this.confirmLoading = false } }, handleEmptyBox() { if (!this.scanForm.palletCode) { this.$message.warning('è¯·å æ«ææçç ') return } this.confirmMessage = `ç¡®å®è¦å空æç ${this.scanForm.palletCode} åï¼` this.currentAction = 'emptyBox' this.confirmDialogVisible = true }, handleReturnToWarehouse() { if (!this.scanForm.palletCode) { this.$message.warning('è¯·å æ«ææçç ') return } this.confirmMessage = `ç¡®å®è¦å°æç ${this.scanForm.palletCode} ååºåï¼` this.currentAction = 'returnToWarehouse' this.confirmDialogVisible = true }, executeConfirm() { this.executeLoading = true try { let apiUrl = '' let params = { orderNo: this.orderNo, palletCode: this.scanForm.palletCode } if (this.currentAction === 'emptyBox') { apiUrl = '/api/Outbound/EmptyBox' } else if (this.currentAction === 'returnToWarehouse') { apiUrl = '/api/Outbound/ReturnToWarehouse' } this.http.post(apiUrl, params).then(response => { if (response.status) { this.$message.success('æä½æå') this.confirmDialogVisible = false this.resetForm() // this.loadUnpickedData() // this.loadPickedData() } else { this.$message.error(response.message || 'æä½å¤±è´¥') } }) } catch (error) { console.error('æä½å¤±è´¥:', error) this.$message.error('æä½å¤±è´¥') } finally { this.executeLoading = false } }, handleDialogClose() { if (!this.executeLoading) { this.confirmDialogVisible = false } }, quickPick(row) { this.scanForm.materialBarcode = row.materielCode this.handleConfirmPick() }, undoPick(row) { try { this.$confirm('ç¡®å®è¦æ¤éè¿æ¡æ£éè®°å½åï¼', 'æç¤º', { type: 'warning' }) const response = this.http.post('/api/Outbound/UndoPicking', { id: row.id }).then(response => { if (response.status) { this.$message.success('æ¤éæå') this.loadUnpickedData() this.loadPickedData() } else { this.$message.error(response.message || 'æ¤é失败') } }) } catch (error) { if (error !== 'cancel') { console.error('æ¤é失败:', error) this.$message.error('æ¤é失败') } } }, // handleUnpickedRowClick(row) { // // ç¹å»æªæ£éè¡æ¶èªå¨å¡«å ç©ææ¡ç // this.scanForm.materialBarcode = row.materielCode // }, refreshUnpickedTable() { if (this.scanForm.palletCode) { this.loadPalletData() } }, refreshPickedTable() { this.loadPickedData() }, resetMaterialBarcode() { this.scanForm.materialBarcode = '' this.$nextTick(() => { if (this.$refs.materialInput) { this.$refs.materialInput.focus() } }) }, resetForm() { this.scanForm.palletCode = '' this.scanForm.materialBarcode = '' this.unpickedData = [] this.$nextTick(() => { if (this.$refs.palletInput) { this.$refs.palletInput.focus() } }) }, getUserName() { // å°è¯ä» Vuex store è·åç¨æ·å if (this.$store && this.$store.state && this.$store.state.userInfo) { return this.$store.state.userInfo.userName || this.$store.state.userInfo.username || 'æªç»å½ç¨æ·' } // å°è¯ä» localStorage è·å try { const userInfo = localStorage.getItem('user') if (userInfo) { const user = JSON.parse(userInfo) return user.userName || user.username || 'æªç»å½ç¨æ·' } } catch (error) { console.error('è·åç¨æ·ä¿¡æ¯å¤±è´¥:', error) } return 'æªç»å½ç¨æ·' }, getStatusType(status) { const statusMap = { 0: 'info', // å¾ å¤ç 10: 'warning', // è¿è¡ä¸ 20: 'primary', // æ£éä¸ 30: 'success', // 已宿 40: 'danger' // å¼å¸¸ } return statusMap[status] || 'info' } } } </script> <style scoped> .picking-container { padding: 20px; background-color: #f5f5f5; min-height: 100vh; } /* 订åä¿¡æ¯å¡ç */ .order-info-card { margin-bottom: 20px; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; } .order-header { display: flex; justify-content: space-between; align-items: center; } .order-title { display: flex; align-items: center; font-size: 18px; font-weight: bold; } .order-title i { margin-right: 10px; font-size: 24px; } .order-label { margin-left: 10px; opacity: 0.9; } .order-value { font-size: 20px; font-weight: bold; letter-spacing: 1px; } /* æ«ç åºå */ .scan-section-card { margin-bottom: 20px; } .scan-section { padding: 10px 0; } .scan-alert { margin-bottom: 20px; } .scan-form { margin-top: 20px; } .button-form-item { margin-bottom: 0; } .button-form-item .el-form-item__content { line-height: normal; } .action-buttons { display: flex; gap: 8px; width: 100%; height: 40px; } .action-buttons .el-button { flex: 1; height: 40px; font-weight: bold; border-radius: 6px; margin: 0; } /* è¡¨æ ¼åºå */ .tables-section { margin-top: 20px; } .table-card { height: 600px; display: flex; flex-direction: column; } .card-header { display: flex; justify-content: space-between; align-items: center; } .card-title { display: flex; align-items: center; font-weight: bold; font-size: 16px; } .card-title i { margin-right: 8px; color: #409EFF; } .badge-item { margin-left: 10px; } .table-footer { margin-top: 10px; padding-top: 10px; border-top: 1px solid #ebeef5; } /* è¡¨æ ¼è¡æ ·å¼ */ .el-table tbody tr:hover>td { background-color: #f0f9ff !important; } .el-table tbody tr.current-row>td { background-color: #e1f3ff !important; } /* å¯¹è¯æ¡æ ·å¼ */ .confirm-content { padding: 20px 0; text-align: center; } .confirm-content p { font-size: 16px; color: #606266; } .dialog-footer { text-align: center; } /* ååºå¼è®¾è®¡ */ @media (max-width: 1200px) { .action-buttons .el-button { font-size: 14px; } } /* Element UI ç»ä»¶æ ·å¼è¦ç */ ::v-deep .el-card__header { padding: 18px 20px; border-bottom: 1px solid #ebeef5; } ::v-deep .el-input__inner { border-radius: 6px; } ::v-deep .el-button--primary { background: linear-gradient(135deg, #409EFF 0%, #3a8ee6 100%); border: none; } ::v-deep .el-button--warning { background: linear-gradient(135deg, #E6A23C 0%, #d9971a 100%); border: none; } ::v-deep .el-button--success { background: linear-gradient(135deg, #67C23A 0%, #5daf34 100%); border: none; } /* 徿 æ ·å¼ */ .el-icon-document, .el-icon-box, .el-icon-s-grid, .el-icon-check, .el-icon-delete, .el-icon-refresh-left, .el-icon-time, .el-icon-circle-check { font-size: 18px; } /* æè¿°åè¡¨æ ·å¼ */ ::v-deep .el-descriptions__label { font-weight: bold; color: #909399; } ::v-deep .el-descriptions__content { color: #606266; } </style> ÏîÄ¿´úÂë/WIDESEA_WMSClient/src/views/outbound/outPicking.vue
@@ -21,7 +21,13 @@ <div class="scan-section"> <el-alert title="è¯·ä½¿ç¨æ«ç æªæ«æï¼æ¯æå车èªå¨ç¡®è®¤" type="info" :closable="false" show-icon class="scan-alert"> <template #default> <span>1. è¯·å æ«ææçç â 2. åæ«æç©ææ¡ç </span> <div> <div>1. è¯·å æ«ææçç â 2. åæ«æç©ææ ç¾ç </div> <div style="margin-top: 8px; font-size: 13px; color: #666;"> <i class="el-icon-info" style="color: #409EFF;"></i> æ¯ææ«æçç æ´ç®±åºåºï¼æ«ææçç åå¯ç´æ¥è¿è¡æ´ç®±ç©ææ£éï¼æ éåæ«æç©ææ ç¾ç ã </div> </div> </template> </el-alert> @@ -71,6 +77,41 @@ </el-col> </el-row> </el-form> <!-- 忣ç»è®¡ä¿¡æ¯ --> <div class="picking-stats" v-if="scanForm.palletCode && unpickedData.length > 0"> <el-divider content-position="left"> <span style="color: #409EFF; font-size: 14px;"> <i class="el-icon-data-analysis"></i> æç忣ç»è®¡ </span> </el-divider> <div class="stats-container"> <div class="stat-item"> <el-tag type="primary" size="medium" effect="dark"> <i class="el-icon-s-order"></i> åæ£æ»æ°ï¼<b>{{ calculateTotalAssignQuantity() }}</b> </el-tag> </div> <div class="stat-item"> <el-tag type="success" size="medium" effect="dark"> <i class="el-icon-circle-check"></i> 已忣ï¼<b>{{ calculateTotalSortedQuantity() }}</b> </el-tag> </div> <div class="stat-item"> <el-tag type="warning" size="medium" effect="dark"> <i class="el-icon-time"></i> æªåæ£ï¼<b>{{ calculateTotalUnsortedQuantity() }}</b> </el-tag> </div> <div class="stat-item"> <el-tag type="success" size="medium" effect="dark"> <i class="el-icon-box"></i> æ¯å¦æ´åºï¼{{ hasWholeOut() ? 'æ¯' : 'å¦' }} </el-tag> </div> </div> </div> </div> </el-card> @@ -198,6 +239,53 @@ </el-card> </el-col> </el-row> <!-- æçç©æåºåä¿¡æ¯ --> <!-- <div class="pallet-inventory" v-if="scanForm.palletCode && unpickedData.length > 0"> <el-divider content-position="left"> <span style="color: #67C23A; font-size: 14px;"> <i class="el-icon-goods"></i> æçç©æåºåä¿¡æ¯ </span> </el-divider> <div class="inventory-container"> <el-table :data="unpickedData" size="small" :show-header="true" :border="true" stripe highlight-current-row max-height="200" class="inventory-table"> <el-table-column type="index" label="åºå·" width="50" align="center" /> <el-table-column prop="materielCode" label="ç©æç¼ç " width="100" show-overflow-tooltip /> <el-table-column prop="materielName" label="ç©æåç§°" width="120" show-overflow-tooltip /> <el-table-column prop="batchNo" label="æ¹æ¬¡å·" width="90" /> <el-table-column label="å½ååºå" width="80" align="right"> <template #default="scope"> <el-text type="primary" tag="b">{{ scope.row.currentStock || 0 }}</el-text> </template> </el-table-column> <el-table-column label="忣æ°é" width="80" align="right"> <template #default="scope"> <el-text type="warning">{{ scope.row.assignQuantity }}</el-text> </template> </el-table-column> <el-table-column label="已忣" width="70" align="right"> <template #default="scope"> <el-text type="success">{{ scope.row.sortedQuantity || 0 }}</el-text> </template> </el-table-column> <el-table-column label="å©ä½åºå" width="80" align="right"> <template #default="scope"> <el-text type="info">{{ calculateRemainingStock(scope.row) }}</el-text> </template> </el-table-column> <el-table-column prop="unit" label="åä½" width="100" align="center" /> <el-table-column prop="locationCode" label="åºä½" width="150" /> <el-table-column label="ç¶æ" width="80" align="center"> <template #default="scope"> <el-tag :type="getStockStatusType(scope.row)" size="mini"> {{ getStockStatusText(scope.row) }} </el-tag> </template> </el-table-column> </el-table> </div> </div> --> </div> <print-view ref="printView" @parentcall="parentcall"></print-view> @@ -253,7 +341,8 @@ confirmDialogVisible: false, confirmMessage: '', currentAction: null, executeLoading: false executeLoading: false, matMixed: true } }, computed: { @@ -300,8 +389,9 @@ try { this.http.post(`/api/Outbound/QueryPickingTasks?orderNo=${this.orderNo}&palletCode=${this.scanForm.palletCode}`, {}).then(response => { if (response.status) { if (response.data.length > 0) { this.unpickedData = response.data if (response.data.outStockLockInfos.length > 0) { this.unpickedData = response.data.outStockLockInfos; this.matMixed = response.data.isMatMixed; this.calculateUnpickedStats() // èªå¨èç¦å°ç©ææ¡ç è¾å ¥æ¡ @@ -589,6 +679,71 @@ return 'æªç»å½ç¨æ·' }, // 计ç®åæ£æ»æ° calculateTotalAssignQuantity() { return this.unpickedData.reduce((sum, item) => { return sum + (item.assignQuantity || 0) }, 0) }, // 计ç®å·²åæ£æ»æ° calculateTotalSortedQuantity() { return this.unpickedData.reduce((sum, item) => { return sum + (item.sortedQuantity || 0) }, 0) }, // è®¡ç®æªåæ£æ»æ° calculateTotalUnsortedQuantity() { return this.unpickedData.reduce((sum, item) => { const assignQty = item.assignQuantity || 0 const sortedQty = item.sortedQuantity || 0 return sum + Math.max(0, assignQty - sortedQty) }, 0) }, // æ£æ¥æ¯å¦å 嫿´åº hasWholeOut() { return this.unpickedData.some(item => item.assignQuantity === item.originalQuantity) && this.matMixed; }, // 计ç®å©ä½åºå calculateRemainingStock(row) { const currentStock = row.currentStock || 0 const assignQty = row.assignQuantity || 0 return Math.max(0, currentStock - assignQty) }, // è·ååºåç¶æç±»å getStockStatusType(row) { const currentStock = row.currentStock || 0 const assignQty = row.assignQuantity || 0 const sortedQty = row.sortedQuantity || 0 if (sortedQty >= assignQty) { return 'success' // 已宿 } else if (currentStock < assignQty) { return 'danger' // åºåä¸è¶³ } else { return 'warning' // è¿è¡ä¸ } }, // è·ååºåç¶æææ¬ getStockStatusText(row) { const currentStock = row.currentStock || 0 const assignQty = row.assignQuantity || 0 const sortedQty = row.sortedQuantity || 0 if (sortedQty >= assignQty) { return '已宿' } else if (currentStock < assignQty) { return 'åºåä¸è¶³' } else { return '忣ä¸' } }, getStatusType(status) { const statusMap = { 0: 'info', // å¾ å¤ç @@ -802,4 +957,118 @@ ::v-deep .el-descriptions__content { color: #606266; } /* è¡¨æ ¼å¢å¼ºæ ·å¼ */ ::v-deep .el-table th { background-color: #fafafa; font-weight: 600; color: #303133; } ::v-deep .el-table .el-text { font-weight: 500; } /* æ ç¾æ ·å¼å¢å¼º */ ::v-deep .el-tag--small { font-weight: 500; } /* æç¤ºä¿¡æ¯æ ·å¼å¢å¼º */ .scan-alert ::v-deep .el-alert__content { width: 100%; } .scan-alert ::v-deep .el-alert__description { margin-top: 8px; } /* 忣ç»è®¡ä¿¡æ¯æ ·å¼ */ .picking-stats { margin-top: 20px; padding: 0 10px; } .stats-container { display: flex; flex-wrap: wrap; gap: 12px; align-items: center; } .stat-item { display: inline-flex; align-items: center; } .stat-item .el-tag { display: flex; align-items: center; padding: 6px 12px; font-size: 13px; border-radius: 20px; } .stat-item .el-tag i { margin-right: 6px; font-size: 14px; } .stat-item b { margin-left: 4px; font-size: 14px; } /* åå²çº¿æ ·å¼ */ ::v-deep .el-divider__text { background-color: #f5f5f5; padding: 0 20px; } /* æçåºåä¿¡æ¯æ ·å¼ */ .pallet-inventory { margin-top: 20px; padding: 0 10px; } .inventory-container { margin-top: 10px; } .inventory-table { width: 100%; } .inventory-table ::v-deep .el-table__header { background-color: #f0f9ff; } .inventory-table ::v-deep .el-table__header th { background-color: #e1f3ff; color: #1f2937; font-weight: 600; font-size: 12px; padding: 8px 0; } .inventory-table ::v-deep .el-table__body td { padding: 6px 0; font-size: 12px; } .inventory-table ::v-deep .el-table__row { cursor: pointer; } .inventory-table ::v-deep .el-table__row:hover { background-color: #f0f9ff; } /* åºåè¡¨æ ¼ä¸çæ ç¾æ ·å¼ */ .inventory-table ::v-deep .el-tag--mini { font-size: 11px; padding: 1px 6px; height: 18px; line-height: 16px; } </style> ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/.vs/WIDESEA_WMSServer/CopilotIndices/17.14.1204.46620/CodeChunks.dbBinary files differ
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/.vs/WIDESEA_WMSServer/CopilotIndices/17.14.1204.46620/SemanticSymbols.dbBinary files differ
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_BasicService/BasicService.cs
@@ -109,7 +109,7 @@ throw new Exception($"转æ¢ååä½ä¸è½ä¸ºç©º"); } decimal ratio = 0; decimal ratio = 1; if (fromUnit.Trim().ToLower() == toUnit.Trim().ToLower()) { ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_BasicService/MESOperation/FeedbackMesService.cs
@@ -14,6 +14,7 @@ using WIDESEA_DTO.ReturnMES; using WIDESEA_IBasicService; using WIDESEA_Model.Models; using static HslCommunication.Profinet.Knx.KnxCode; namespace WIDESEA_BasicService.MESOperation { @@ -23,27 +24,189 @@ private readonly HttpClientHelper _httpClientHelper; private readonly IRepository<Dt_OutboundOrder> _outboundOrderRepository; private readonly IBasicService _basicService; private readonly IRepository<Dt_AllocateOrder> _allocateRepository; public FeedbackMesService(IRepository<Dt_MesReturnRecord> BaseDal, IUnitOfWorkManage unitOfWorkManage, HttpClientHelper httpClientHelper, IRepository<Dt_OutboundOrder> outboundOrderRepository, IBasicService basicService) : base(BaseDal) public FeedbackMesService(IRepository<Dt_MesReturnRecord> BaseDal, IUnitOfWorkManage unitOfWorkManage, HttpClientHelper httpClientHelper, IRepository<Dt_OutboundOrder> outboundOrderRepository, IBasicService basicService, IRepository<Dt_AllocateOrder> allocateRepository) : base(BaseDal) { _unitOfWorkManage = unitOfWorkManage; _httpClientHelper = httpClientHelper; _outboundOrderRepository = outboundOrderRepository; _basicService = basicService; _allocateRepository = allocateRepository; } public void MaterialOutboundFeedback(string orderNo) public WebResponseContent OutboundFeedback(string orderNo) { try { Dt_OutboundOrder outboundOrder = _outboundOrderRepository.Db.Queryable<Dt_OutboundOrder>().Where(x => x.OrderNo == orderNo).Includes(x => x.Details).First(); if (outboundOrder == null) { // todo è®°å½æ¥å¿ï¼æªæ¾å°å¯¹åºçåºåºå return; return WebResponseContent.Instance.Error($"æªæ¾å°å¯¹åºçåºåºåä¿¡æ¯"); } HttpResponseResult<MesResponseDTO> httpResponseResult = new HttpResponseResult<MesResponseDTO>(); string reqCode = Guid.NewGuid().ToString(); string reqTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); string requestData = string.Empty; List<string> lineNos = new List<string>(); if (outboundOrder.OrderType == 0) { MaterialOutboundReturnDTO? returnDTO = BuildOutboundFeedbackData(outboundOrder); if (returnDTO == null) { return WebResponseContent.Instance.Error($"æå»ºåè°å¯¹è±¡å¤±è´¥"); } string apiUrl = ""; returnDTO.ReqCode = reqCode; returnDTO.ReqTime = reqTime; requestData = returnDTO.Serialize(); lineNos = returnDTO.Details.Select(x => x.LineNo).ToList(); httpResponseResult = _httpClientHelper.Post<MesResponseDTO>(apiUrl, requestData); httpResponseResult.ApiUrl = apiUrl; } else { Dt_AllocateOrder allocateOrder = _allocateRepository.QueryFirst(x => x.OrderNo == outboundOrder.OrderNo); if (allocateOrder == null) { return WebResponseContent.Instance.Error($"æªæ¾å°å¯¹åºçè°æ¨å"); } AllocationReturnDTO? returnDTO = BuildAllocationFeedbackData(outboundOrder, allocateOrder.FromWarehouse, allocateOrder.ToWarehouse); if (returnDTO == null) { return WebResponseContent.Instance.Error($"æå»ºåè°å¯¹è±¡å¤±è´¥"); } string apiUrl = ""; returnDTO.ReqCode = reqCode; returnDTO.ReqTime = reqTime; requestData = returnDTO.Serialize(); lineNos = returnDTO.Details.Select(x => x.LineNo).ToList(); httpResponseResult = _httpClientHelper.Post<MesResponseDTO>(apiUrl, requestData); httpResponseResult.ApiUrl = apiUrl; } bool isSuccess = httpResponseResult.IsSuccess && httpResponseResult.Data != null && httpResponseResult.Data.Code == "200"; string message = "æå"; if (!isSuccess) { if (!httpResponseResult.IsSuccess) { message = $"MESæ¥å£è¿åé误ï¼HTTP代ç ï¼{httpResponseResult.StatusCode}ï¼ä¿¡æ¯ï¼{httpResponseResult.ErrorMessage}"; } else if (httpResponseResult.Data.Code != "200") { message = $"è°ç¨MESæ¥å£å¤±è´¥ï¼ä»£ç ï¼{httpResponseResult.Data.Code}ï¼ä¿¡æ¯ï¼{httpResponseResult.Data.Message}"; } } Dt_MesReturnRecord mesReturnRecord = new Dt_MesReturnRecord() { ApiUrl = httpResponseResult.ApiUrl, InterfaceType = 1, OrderId = outboundOrder.Id, OrderNo = outboundOrder.OrderNo, OrderType = outboundOrder.OrderType, RequestCode = reqCode, RequestData = requestData, FailureReason = message, LastReturnTime = DateTime.Now, HttpStatusCode = httpResponseResult.StatusCode.ObjToInt(), ResponseData = httpResponseResult.Content, ReturnType = 0, ReturnCount = 1, ReturnStatus = httpResponseResult.IsSuccess ? 1 : 2, SuccessTime = httpResponseResult.IsSuccess ? DateTime.Now : null }; _unitOfWorkManage.BeginTran(); _unitOfWorkManage.Db.Insertable(mesReturnRecord).ExecuteCommand(); if (isSuccess) { List<Dt_OutboundOrderDetail> outboundOrderDetails = outboundOrder.Details.Where(x => lineNos.Contains(x.lineNo)).ToList(); outboundOrderDetails.ForEach(x => { if (x.OverOutQuantity == x.OrderQuantity - x.MoveQty) { x.ReturnToMESStatus = isSuccess ? 1 : 2; } else { x.ReturnToMESStatus = isSuccess ? 3 : 4; } x.CurrentDeliveryQty = 0; x.ReturnJsonData = ""; }); _outboundOrderRepository.Db.Updateable(outboundOrderDetails).ExecuteCommand(); } _unitOfWorkManage.CommitTran(); WebResponseContent responseContent = new WebResponseContent(); responseContent.Status = isSuccess; responseContent.Message = message; return responseContent; } catch(Exception ex) { return WebResponseContent.Instance.Error(ex.Message); } } public AllocationReturnDTO? BuildAllocationFeedbackData(Dt_OutboundOrder outboundOrder, string fromWarehouse, string toWarehouse) { try { List<Dt_OutboundOrderDetail> details = outboundOrder.Details; List<AllocationDetail> returnDetails = new List<AllocationDetail>(); foreach (var detail in details) { List<Barcodes>? barcodes = JsonConvert.DeserializeObject<List<Barcodes>>(detail.ReturnJsonData); if (barcodes != null && barcodes.Any()) { UnitConvertResultDTO currentResult = _basicService.UnitQuantityConvert(detail.MaterielCode, detail.Unit, detail.BarcodeUnit, detail.CurrentDeliveryQty); UnitConvertResultDTO totalResult = _basicService.UnitQuantityConvert(detail.MaterielCode, detail.Unit, detail.BarcodeUnit, detail.OrderQuantity); returnDetails.Add(new AllocationDetail { Barcodes = barcodes, BatchNo = detail.BatchNo, LineNo = detail.lineNo, MaterialCode = detail.MaterielCode, Qty = totalResult.ToQuantity, WarehouseCode = detail.WarehouseCode, Unit = detail.BarcodeUnit }); } } AllocationReturnDTO outboundReturnDTO = new AllocationReturnDTO() { Business_type = outboundOrder.BusinessType, Details = returnDetails, FactoryArea = outboundOrder.FactoryArea, OperationType = 1, OrderNo = outboundOrder.OrderNo, FromWarehouse = fromWarehouse, ToWarehouse = toWarehouse }; return outboundReturnDTO; } catch (Exception ex) { return null; } } public void MaterialOutboundFeedback(Dt_OutboundOrder outboundOrder) { try { MaterialOutboundReturnDTO? returnDTO = BuildOutboundFeedbackData(outboundOrder); if (returnDTO != null) { @@ -112,7 +275,6 @@ { throw new Exception(ex.Message); } } public MaterialOutboundReturnDTO? BuildOutboundFeedbackData(Dt_OutboundOrder outboundOrder) @@ -124,6 +286,8 @@ List<MaterialOutboundDetail> returnDetails = new List<MaterialOutboundDetail>(); foreach (var detail in details) { if (!string.IsNullOrWhiteSpace(detail.ReturnJsonData)) { List<Barcodes>? barcodes = JsonConvert.DeserializeObject<List<Barcodes>>(detail.ReturnJsonData); if (barcodes != null && barcodes.Any()) @@ -143,6 +307,7 @@ }); } } } MaterialOutboundReturnDTO outboundReturnDTO = new MaterialOutboundReturnDTO() { ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_Core/Middlewares/ApiLogMiddleware.cs
@@ -93,7 +93,7 @@ ms.Position = 0; await ms.CopyToAsync(originalBody); if (!ignoreUrls.Any(x => context.Request.Path.Value?.Contains(x) ?? false)) if (!ignoreUrls.Any(x => context.Request.Path.Value?.ToLower().Contains(x.ToLower()) ?? false)) { Logger.Add(requestParam, responseParam); } ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_Core/Seed/DBSeed.cs
@@ -138,33 +138,33 @@ } #endregion } else { List<string> columnNames = dbContext.Db.DbMaintenance.GetColumnInfosByTableName(t.Name, false).Select(x => x.DbColumnName).ToList(); if (t.GetProperties().FirstOrDefault(x => !columnNames.Contains(x.Name)) != null) { bool isChange = true; List<PropertyInfo> propertyInfos = t.GetProperties().Where(x => !columnNames.Contains(x.Name)).ToList(); for (int i = 0; i < propertyInfos.Count; i++) { PropertyInfo propertyInfo = propertyInfos[i]; SugarColumn? sugarColumn = propertyInfo.GetCustomAttribute<SugarColumn>(); if (sugarColumn != null) { if (!sugarColumn.IsIgnore) { if (!sugarColumn.IsNullable) { isChange = false; break; } } } } if (isChange) dbContext.Db.CodeFirst.InitTables(t); } } //else //{ // List<string> columnNames = dbContext.Db.DbMaintenance.GetColumnInfosByTableName(t.Name, false).Select(x => x.DbColumnName).ToList(); // if (t.GetProperties().FirstOrDefault(x => !columnNames.Contains(x.Name)) != null) // { // bool isChange = true; // List<PropertyInfo> propertyInfos = t.GetProperties().Where(x => !columnNames.Contains(x.Name)).ToList(); // for (int i = 0; i < propertyInfos.Count; i++) // { // PropertyInfo propertyInfo = propertyInfos[i]; // SugarColumn? sugarColumn = propertyInfo.GetCustomAttribute<SugarColumn>(); // if (sugarColumn != null) // { // if (!sugarColumn.IsIgnore) // { // if (!sugarColumn.IsNullable) // { // isChange = false; // break; // } // } // } // } // if (isChange) // dbContext.Db.CodeFirst.InitTables(t); // } //} }); ConsoleHelper.WriteSuccessLine($"Tables Created Successfully!"); Console.WriteLine(); ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_Core/Util/HttpClientHelper.cs
@@ -39,7 +39,7 @@ SetRequestHeaders(request, config?.Headers); return await client.SendAsync(request); }, config, $"POST {url}").Result; httpResponseResult.ApiUrl = url; return httpResponseResult; } @@ -52,6 +52,7 @@ return await client.SendAsync(request); }, config, $"GET {url}").Result; httpResponseResult.ApiUrl = url; return httpResponseResult; } ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_Core/Util/HttpResponseResult.cs
@@ -46,6 +46,11 @@ /// å¼å¸¸ä¿¡æ¯ /// </summary> public Exception Exception { get; set; } /// <summary> /// /// </summary> public string ApiUrl { get; set; } } ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_DTO/Base/UnitConvertResultDTO.cs
@@ -39,7 +39,7 @@ /// <summary> /// /// </summary> public decimal UnitRatio { get; set; } public decimal UnitRatio { get; set; } = 1; /// <summary> /// ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_DTO/ReturnMES/AllocationReturnDTO.cs
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,92 @@ using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace WIDESEA_DTO.ReturnMES { /// <summary> /// /// </summary> public class AllocationReturnDTO : BaseReturnDTO { /// <summary> /// /// </summary> public string OrderNo { get; set; } /// <summary> /// ååº /// </summary> public string FactoryArea { get; set; } /// <summary> /// ä¸å¡ç±»å /// </summary> public string Business_type { get; set; } /// <summary> /// 1æ°å¢2ä¿®æ¹3å é¤ /// </summary> public int OperationType { get; set; } /// <summary> /// /// </summary> public string FromWarehouse { get; set; } /// <summary> /// /// </summary> public string ToWarehouse { get; set; } /// <summary> /// æç» /// </summary> public List<AllocationDetail> Details { get; set; } } /// <summary> /// æç» /// </summary> public class AllocationDetail { /// <summary> /// ç©æç¼ç /// </summary> public string MaterialCode { get; set; } /// <summary> /// è¡å· /// </summary> public string LineNo { get; set; } /// <summary> /// æ°é /// </summary> public decimal Qty { get; set; } /// <summary> /// /// </summary> public string BatchNo { get; set; } /// <summary> /// ä»åº /// </summary> public string WarehouseCode { get; set; } /// <summary> /// åä½ /// </summary> public string Unit { get; set; } /// <summary> /// æ¡ç ä¿¡æ¯ /// </summary> public List<Barcodes> Barcodes { get; set; } } } ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_DTO/ReturnMES/FeedbackMesResult.cs
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,15 @@ using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace WIDESEA_DTO.ReturnMES { /// <summary> /// /// </summary> public class FeedbackMesResult { } } ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_IBasicService/MESOperation/IFeedbackMesService.cs
@@ -9,6 +9,6 @@ { public interface IFeedbackMesService : IDependency { void MaterialOutboundFeedback(string orderNo); WebResponseContent OutboundFeedback(string orderNo); } } ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_Model/Models/Outbound/Dt_OutboundOrderDetail.cs
@@ -90,28 +90,28 @@ /// æªææ°é /// é»è®¤å¼: ///</summary> [SugarColumn(ColumnName = "MoveQty", ColumnDescription = "æªææ°é", IsNullable = true)] [SugarColumn(ColumnDescription = "æªææ°é", IsNullable = true)] public decimal MoveQty { get; set; } /// <summary> /// ä¾åºåç¼å· /// é»è®¤å¼: ///</summary> [SugarColumn(ColumnName = "supplyCode", ColumnDescription = "ä¾åºåç¼å·", IsNullable = true)] [SugarColumn(ColumnDescription = "ä¾åºåç¼å·", IsNullable = true)] public string? SupplyCode { get; set; } /// <summary> /// æ°é /// é»è®¤å¼: ///</summary> [SugarColumn(ColumnName = "barcodeQty", ColumnDescription = "æ°é", DefaultValue = "0", IsNullable = true)] [SugarColumn(ColumnDescription = "æ°é", DefaultValue = "0", IsNullable = true)] public decimal BarcodeQty { get; set; } /// <summary> /// åä½ /// é»è®¤å¼: ///</summary> [SugarColumn(ColumnName = "barcodeUnit", ColumnDescription = "åä½", IsNullable = true)] [SugarColumn(ColumnDescription = "åä½", IsNullable = true)] public string BarcodeUnit { get; set; } = null!; @@ -119,13 +119,13 @@ /// /// é»è®¤å¼: ///</summary> [SugarColumn(ColumnName = "barcodemoveQty", ColumnDescription = "æ°é", DefaultValue = "0", IsNullable = true)] [SugarColumn(ColumnDescription = "æ°é", DefaultValue = "0", IsNullable = true)] public decimal BarcodeMoveQty { get; set; } /// <summary> /// ä»åº /// é»è®¤å¼: ///</summary> [SugarColumn(ColumnName = "warehouseCode", ColumnDescription = "ä»åº", IsNullable = true)] [SugarColumn(ColumnDescription = "ä»åº", IsNullable = true)] public string? WarehouseCode { get; set; } /// <summary> @@ -142,7 +142,7 @@ [SugarColumn(IsIgnore = true)] public decimal NeedOutQuantity => OrderQuantity - MoveQty; [SugarColumn(IsNullable = true, ColumnDescription = "")] [SugarColumn(IsNullable = true, ColumnDescription = "", IsIgnore = true)] public decimal PickedQty { get; set; } [SugarColumn(IsNullable = true, ColumnDescription = "")] ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_OutboundService/OutboundOrderDetailService.cs
@@ -642,8 +642,6 @@ } } } } } return new PageGridData<Dt_OutboundOrderDetail>(); ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_OutboundService/OutboundQueryService.cs
@@ -18,8 +18,19 @@ { try { Dt_StockInfo stockInfo = _stockInfoRepository.Db.Queryable<Dt_StockInfo>().Where(x => x.PalletCode == palletCode).Includes(x => x.Details).First(); bool isMatMixed = stockInfo.Details.GroupBy(x => new { x.MaterielCode, x.MaterielName, x.BatchNo, x.SupplyCode, x.WarehouseCode }).Count() > 1; List<Dt_OutStockLockInfo> outStockLockInfos = _outboundLockInfoRepository.QueryData(x => x.PalletCode == palletCode && x.OrderNo == orderNo); return WebResponseContent.Instance.OK(data: outStockLockInfos); return WebResponseContent.Instance.OK(data: new { outStockLockInfos, stockInfo, isMatMixed }); } catch (Exception ex) { ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_OutboundService/OutboundService.cs
@@ -138,14 +138,18 @@ pickedDetails.AddRange(materielPickedDetails.PickedDetails); decimal allallocatedQuantity = materielCalc.UnallocatedQuantity; // æ´æ°åºåºåæç»ï¼å¢å é宿°éï¼ä¸å¢å å·²åºæ°éï¼ foreach (var detail in materielCalc.Details) { if (allallocatedQuantity <= 0) break; decimal lockQuantity = (detail.OrderQuantity - detail.OverOutQuantity); if (lockQuantity < materielCalc.UnallocatedQuantity) { detail.LockQuantity += lockQuantity; // å¢å é宿°é 䏿´æ° OverOutQuantity å OrderDetailStatusï¼å ä¸ºè¿æ²¡æå®é åºåº outboundOrderDetails.Add(detail); materielCalc.UnallocatedQuantity -= lockQuantity; } else { @@ -267,6 +271,18 @@ return result; } decimal inputQuantity = request.OutboundQuantity.Value; List<Dt_OutboundOrderDetail> outboundOrderDetails = new List<Dt_OutboundOrderDetail>(); foreach (var item in selectedDetails) { inputQuantity -= (item.OrderQuantity - item.MoveQty - item.LockQuantity); outboundOrderDetails.Add(item); if (inputQuantity <= 0) { break; } } result.MaterielCalculations = new List<MaterielOutboundCalculationDTO>() { new MaterielOutboundCalculationDTO @@ -281,9 +297,11 @@ AssignedQuantity = lockQuantity, UnallocatedQuantity = request.OutboundQuantity.Value, MovedQuantity = moveQuantity, Details = selectedDetails Details = outboundOrderDetails } }; outboundOrder.Details = outboundOrderDetails; } result.CanOutbound = true; @@ -790,7 +808,7 @@ } #endregion #region æ£é /// <summary> /// åºåºå®æå¤çï¼æ«ææ¡ç æ£ååºåï¼ /// </summary> @@ -885,12 +903,12 @@ return WebResponseContent.Instance.Error($"æ æ³åºåºï¼æ¡ç ï¼{request.Barcode}ï¼åºåï¼{stockDetail.StockQuantity}ï¼å·²åºåºï¼{totalAllocatedQuantity}ï¼åé éï¼{lockInfo.AssignQuantity}ï¼æç»å©ä½ï¼{detailRemainingQuantity}"); } if (actualOutboundQuantity + lockInfo.SortedQuantity > lockInfo.AssignQuantity) { response.Success = false; response.Message = $"æ æ³åºåºï¼æ¡ç ï¼{request.Barcode}ï¼åºåï¼{stockDetail.StockQuantity}ï¼åºåºé{actualOutboundQuantity + lockInfo.SortedQuantity}大äºåé é{lockInfo.AssignQuantity}"; return WebResponseContent.Instance.Error($"æ æ³åºåºï¼æ¡ç ï¼{request.Barcode}ï¼åºåï¼{stockDetail.StockQuantity}ï¼åºåºé{actualOutboundQuantity + lockInfo.SortedQuantity}大äºåé é{lockInfo.AssignQuantity}"); } //if (actualOutboundQuantity + lockInfo.SortedQuantity > lockInfo.AssignQuantity) //{ // response.Success = false; // response.Message = $"æ æ³åºåºï¼æ¡ç ï¼{request.Barcode}ï¼åºåï¼{stockDetail.StockQuantity}ï¼åºåºé{actualOutboundQuantity + lockInfo.SortedQuantity}大äºåé é{lockInfo.AssignQuantity}"; // return WebResponseContent.Instance.Error($"æ æ³åºåºï¼æ¡ç ï¼{request.Barcode}ï¼åºåï¼{stockDetail.StockQuantity}ï¼åºåºé{actualOutboundQuantity + lockInfo.SortedQuantity}大äºåé é{lockInfo.AssignQuantity}"); //} // 8. 夿æ¯å¦éè¦æå ï¼å½åºåºæ°éå°äºåºåæ°éæ¶éè¦æå ï¼ bool isUnpacked = actualOutboundQuantity < stockDetail.StockQuantity; @@ -930,6 +948,8 @@ // item.OverOutQuantity = item.OrderQuantity - item.MoveQty; //} decimal barcodeQuantity = allocatedQuantity; if (item.LockQuantity - item.OverOutQuantity >= allocatedQuantity) { item.OverOutQuantity += allocatedQuantity; @@ -938,6 +958,7 @@ } else { barcodeQuantity = item.LockQuantity - item.OverOutQuantity; allocatedQuantity -= (item.LockQuantity - item.OverOutQuantity); item.OverOutQuantity = item.LockQuantity; item.CurrentDeliveryQty = item.LockQuantity; @@ -949,7 +970,7 @@ Barcodes barcodes = new Barcodes { Barcode = request.Barcode, Qty = actualOutboundQuantity, Qty = barcodeQuantity, SupplyCode = stockDetail?.SupplyCode ?? "", BatchNo = stockDetail?.BatchNo ?? "", Unit = stockDetail?.Unit ?? "" @@ -1012,6 +1033,7 @@ if (CheckOutboundOrderCompleted(request.OrderNo)) { UpdateOutboundOrderStatus(request.OrderNo, OutOrderStatusEnum.åºåºå®æ.ObjToInt()); //todo: åä¼ MES } @@ -1325,5 +1347,7 @@ // æ£æ¥æææç»çå·²åºæ°éæ¯å¦é½çäºåæ®æ°é return details.All(x => x.OverOutQuantity >= x.OrderQuantity - x.MoveQty); } #endregion } } ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/Basic/MesFeedbackController.cs
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,24 @@ using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using WIDESEA_Core; using WIDESEA_IBasicService; namespace WIDESEA_WMSServer.Controllers.Basic { [Route("api/[controller]")] [ApiController] public class MesFeedbackController : ControllerBase { private readonly IFeedbackMesService _feedbackMesService; public MesFeedbackController(IFeedbackMesService feedbackMesService) { _feedbackMesService = feedbackMesService; } [HttpPost, HttpGet, Route("OutboundFeedback")] public WebResponseContent OutboundFeedback(string orderNo) { return _feedbackMesService.OutboundFeedback(orderNo); } } } ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/Outbound/OutboundController.cs
@@ -40,10 +40,14 @@ } } object lockObj = new object(); [HttpPost, Route("CompleteOutboundWithBarcode"), AllowAnonymous] public WebResponseContent CompleteOutboundWithBarcode([FromBody] OutboundCompleteRequestDTO request) { try { lock (lockObj) { if (!ModelState.IsValid) return WebResponseContent.Instance.Error(string.Join("; ", ModelState.Values @@ -52,6 +56,7 @@ return _outboundService.CompleteOutboundWithBarcode(request); } } catch (Exception ex) { return WebResponseContent.Instance.Error($"åºåºæ«ææä½å¤±è´¥: {ex.Message}");