ÏîÄ¿´úÂë/WIDESEA_WMSClient/src/extension/inbound/extend/Pallet.vue
@@ -12,50 +12,72 @@ > <div class="barcode-scanner-container"> <!-- æçä¿¡æ¯æ¾ç¤º --> <div class="tray-info" v-if="trayBarcode"> <i class="el-icon-s-management"></i> å½åæç®±: {{ trayBarcode }} <!-- <el-button class="small-button" type="text" @click="clearTray" style="float: right;" > æ¸ é¤æç </el-button> --> <!-- ä»åºåºåéæ© - ç´§åå¸å± --> <div class="location-section compact"> <el-form :model="form" :rules="rules" ref="locationForm" class="compact-form"> <el-form-item label="ä»åºåºå" prop="locationType" class="location-select compact-item"> <el-select v-model="form.locationType" placeholder="è¯·éæ©ä»åºåºå" clearable filterable @change="handleLocationChange" style="width: 100%" :loading="locationLoading" size="medium" > <el-option v-for="item in locationTypes" :key="item.locationType" :label="item.locationTypeDesc" :value="item.locationType" /> </el-select> </el-form-item> </el-form> </div> <!-- æ«ç ææå¨è¾å ¥åºå --> <div class="input-section"> <el-card shadow="hover"> <div slot="header"> <span><i class="el-icon-scanner"></i> </span> <!-- æçä¿¡æ¯æ¾ç¤º - ç´§åå¸å± --> <div class="tray-info compact" v-if="trayBarcode"> <i class="el-icon-s-management"></i> å½åæç®±: {{ trayBarcode }} <span class="location-info" v-if="form.locationType"> | ä»åºåºå: {{ currentLocationDesc }} </span> </div> <!-- æ«ç åºå - ç´§åå¸å± --> <div class="input-section compact"> <el-card shadow="hover" class="compact-card"> <div slot="header" class="compact-header"> <span><i class="el-icon-scanner"></i> æ«ç åºå</span> <span class="scan-status"> <span class="scan-indicator"></span>æ«ç 就绪 <span class="scan-indicator"></span> {{ form.locationType ? 'æ«ç 就绪' : '请å éæ©ä»åºåºå' }} </span> </div> <!-- æçæ¡ç è¾å ¥ --> <div class="input-wrapper custom-input-group"> <div class="input-label">æç®±ç </div> <div class="input-wrapper custom-input-group compact-input"> <div class="input-label">æç®±ç </div> <el-input ref="trayInput" v-model="trayBarcode" placeholder="è¯·æ«ææè¾å ¥æç®±ç åæå车é®" clearable :disabled="!form.locationType" @keyup.enter.native="handleTraySubmit" @clear="handleTrayClear" @input="handleTrayInput" class="custom-input" class="custom-input" size="medium" > <template slot="prepend"> <span> æç®±ç </span> </template> <template slot="append"> <el-button @click="handleTraySubmit" type="primary" icon="el-icon-position" :disabled="!form.locationType || !trayBarcode" size="medium" > 确认 </el-button> @@ -64,29 +86,28 @@ </div> <!-- ç©ææ¡ç è¾å ¥ --> <div class="input-wrapper custom-input-group"> <div class="input-wrapper custom-input-group compact-input"> <div class="input-label">ç©ææ¡ç </div> <el-input ref="barcodeInput" v-model="barcode" placeholder="è¯·æ«ææè¾å ¥ç©ææ¡ç åæå车é®" clearable :disabled="!trayBarcode" :disabled="!form.locationType || !trayBarcode" @keyup.enter.native="handleBarcodeSubmit" @clear="handleClear" @input="handleBarcodeInput" class="custom-input" class="custom-input" size="medium" > <template slot="prepend"> <span>ç©ææ¡ç </span> </template> <template slot="append"> <el-button :loading="loading" @click="handleBarcodeSubmit" type="primary" icon="el-icon-search" :disabled="!trayBarcode" :disabled="!form.locationType || !trayBarcode || !barcode" size="medium" > {{ loading ? 'æ¥è¯¢ä¸...' : 'æ¥è¯¢' }} </el-button> @@ -94,22 +115,23 @@ </el-input> </div> <div class="input-tips"> <p>æç¤ºï¼å è¾å ¥æç®±ç ï¼ç¶åè¾å ¥ç©ææ¡ç </p> <div class="input-tips compact-tips"> <p>æç¤ºï¼è¯·å éæ©ä»åºåºåï¼ç¶åè¾å ¥æç®±ç ï¼æåè¾å ¥ç©ææ¡ç </p> <p v-if="!form.locationType" class="warning-text">â ï¸ è¯·å éæ©ä»åºåºå</p> <p v-if="form.locationType && !trayBarcode" class="warning-text">â ï¸ è¯·å è¾å ¥æç®±ç </p> </div> </el-card> </div> <!-- å è½½ç¶æ --> <div v-if="loading" class="loading"> <div v-if="loading" class="loading compact"> <el-progress :percentage="100" status="success" :show-text="false" /> <p>æ£å¨æ¥è¯¢ç©æä¿¡æ¯...</p> </div> <!-- é误æç¤º --> <div v-if="error" class="error-message"> <div v-if="error" class="error-message compact"> <el-alert :title="error" type="error" @@ -119,68 +141,45 @@ /> </div> <!-- ç©æå表 --> <div class="material-list"> <el-card shadow="hover"> <div slot="header"> <!-- ç©æå表 - åºå®é«åº¦å¸¦æ»å¨æ¡ --> <div class="material-list compact"> <el-card shadow="hover" class="compact-card"> <div slot="header" class="compact-header"> <span><i class="el-icon-tickets"></i> ç»çæ°æ®</span> <span class="list-actions"> <el-tag type="primary">å ± {{ materials.length }} æ¡è®°å½</el-tag> <el-tag type="primary">å·²ç»ç {{ totalStockCount }}</el-tag> <el-tag type="primary">åºåæ°é {{ totalStockSum }}<span>{{ uniqueUnit }}</span></el-tag> <el-tag v-if="trayBarcode" type="success">æç: {{ trayBarcode }}</el-tag> <!-- <el-button v-if="materials.length > 0" class="small-button clear-all-btn" type="danger" icon="el-icon-delete" @click="clearAllMaterials" > æ¸ ç©ºå表 </el-button> --> <!-- <el-button class="small-button clear-all-btn" @click="debugMode = !debugMode" > {{ debugMode ? 'éèè°è¯' : 'æ¾ç¤ºè°è¯' }} </el-button> --> <el-tag type="primary" size="small">å ± {{ materials.length }} æ¡</el-tag> <el-tag type="primary" size="small">å·²ç»ç {{ totalStockCount }}</el-tag> <el-tag type="primary" size="small">åºå {{ totalStockSum }}{{ uniqueUnit }}</el-tag> <el-tag v-if="trayBarcode" type="success" size="small">æç: {{ trayBarcode }}</el-tag> <el-tag v-if="form.locationType" type="info" size="small">åºå: {{ currentLocationDesc }}</el-tag> </span> </div> <div v-if="materials.length === 0" class="empty-state"> <div v-if="materials.length === 0" class="empty-state compact"> <i class="el-icon-document"></i> <p v-if="!trayBarcode">请å è¾å ¥æç®±æ¡ç </p> <p v-if="!form.locationType">请å éæ©ä»åºåºå</p> <p v-else-if="!trayBarcode">请å è¾å ¥æç®±æ¡ç </p> <p v-else>ææ ç©ææ°æ®ï¼è¯·æ«ææè¾å ¥ç©ææ¡ç </p> </div> <el-table v-else :data="materials" stripe style="width: 100%" > <el-table-column type="index" label="åºå·" width="60" align="center"></el-table-column> <el-table-column prop="barcode" label="æ¡ç " min-width="140"></el-table-column> <el-table-column prop="materielCode" label="ç©æç¼ç " min-width="150"></el-table-column> <el-table-column prop="batchNo" label="æ¹æ¬¡" min-width="150"></el-table-column> <el-table-column prop="stockQuantity" label="æ°é" min-width="130"></el-table-column> <el-table-column prop="unit" label="åä½" width="80" align="center"></el-table-column> <el-table-column prop="supplyCode" label="ä¾åºå" min-width="130"></el-table-column> <el-table-column prop="warehouseCode" label="ä»åº" min-width="120"></el-table-column> <!-- <el-table-column label="æä½" width="100" align="center"> <template slot-scope="scope"> <el-button v-if="scope" class="small-button" type="danger" icon="el-icon-delete" circle @click="removeMaterial(scope.$index)" ></el-button> </template> </el-table-column> --> </el-table> <div class="table-container" v-else> <el-table :data="materials" stripe style="width: 100%" height="100%" size="small" > <el-table-column type="index" label="åºå·" width="60" align="center"></el-table-column> <el-table-column prop="barcode" label="æ¡ç " min-width="140" show-overflow-tooltip></el-table-column> <el-table-column prop="materielCode" label="ç©æç¼ç " min-width="150" show-overflow-tooltip></el-table-column> <el-table-column prop="batchNo" label="æ¹æ¬¡" min-width="150" show-overflow-tooltip></el-table-column> <el-table-column prop="stockQuantity" label="æ°é" min-width="130" align="right"></el-table-column> <el-table-column prop="unit" label="åä½" width="80" align="center"></el-table-column> <el-table-column prop="supplyCode" label="ä¾åºå" min-width="130" show-overflow-tooltip></el-table-column> <el-table-column prop="warehouseCode" label="ä»åº" min-width="120" show-overflow-tooltip></el-table-column> </el-table> </div> </el-card> </div> </div> @@ -191,7 +190,6 @@ </div> --> </vol-box> </template> <script> import http from '@/api/http.js'; import VolBox from '@/components/basic/VolBox.vue'; @@ -234,7 +232,22 @@ totalStockCount: 0, uniqueUnit: '', sumLoading: false, sumError: '' sumError: '', // ä»åºåºåç¸å ³åé locationTypes: [], locationLoading: false, form: { locationType: null }, rules: { locationType: [ { validator: this.validateLocationType, trigger: 'change' } ] } } }, computed: { @@ -242,7 +255,12 @@ get() { return this.visible; }, set(newVal) { this.$emit('update:visible', newVal); } }, currentDocNo() { return this.docNo; } currentDocNo() { return this.docNo; }, // å½åéæ©çä»åºåºåæè¿° currentLocationDesc() { const location = this.locationTypes.find(item => item.locationType === this.form.locationType) return location ? location.locationTypeDesc : '' } }, watch: { visible(newVal, oldVal) { @@ -254,7 +272,8 @@ this.resetData(); this.$nextTick(() => { setTimeout(() => { this.focusTrayInput(); // this.focusTrayInput(); this.initLocationTypes(); // åå§åä»åºåºå this.fetchStockStatistics(); // å è½½ç»è®¡æ°æ® }, 300); }); @@ -286,7 +305,8 @@ // 使ç¨setTimeoutç¡®ä¿DOMå®å ¨æ¸²æååèç¦ setTimeout(() => { this.focusTrayInput(); // this.focusTrayInput(); this.focusLocationSelect(); }, 300); }, beforeDestroy() { @@ -295,6 +315,76 @@ this.clearAllTimers(); }, methods: { /** * èªå®ä¹ä»åºåºåéªè¯ * å 许å¼ä¸º0ï¼å 为0æ¯åæ³çlocationType */ validateLocationType(rule, value, callback) { // æ£æ¥å¼æ¯å¦ä¸ºnullãundefinedæç©ºå符串ï¼ä½å 许æ°å0 if (value === null || value === undefined || value === '') { callback(new Error('è¯·éæ©ä»åºåºå')); } else { // å¼ä¸º0æå ¶ä»ææå¼é½éè¿éªè¯ callback(); } }, /** * åå§åä»åºåºåæ°æ® */ async initLocationTypes() { this.locationLoading = true; this.error = ''; try { const response = await http.post('/api/LocationInfo/GetLocationTypes'); if (response.status && Array.isArray(response.data)) { this.locationTypes = response.data; if (this.locationTypes.length === 0) { this.error = 'æªè·åå°ä»åºåºåæ°æ®'; } else { // 妿æé»è®¤åºåï¼å¯ä»¥å¨è¿é设置 // this.form.locationType = this.locationTypes[0].locationType; } } else { this.error = 'è·åä»åºåºåæ°æ®å¤±è´¥'; } } catch (error) { console.error('è·åä»åºåºå失败:', error); this.error = `è·åä»åºåºå失败: ${error.message || 'ç½ç»é误'}`; } finally { this.locationLoading = false; } }, /** * ä»åºåºååæ´å¤ç */ handleLocationChange(value) { console.log('éæ©ä»åºåºå:', value, 'ç±»å:', typeof value, this.currentLocationDesc); // ç«å³æ¸ é¤éè¯¯ä¿¡æ¯ this.error = ''; // æå¨è§¦å表åéªè¯æ´æ° this.$nextTick(() => { if (this.$refs.locationForm) { // æ¸ é¤è¯¥å段çéªè¯ç¶æï¼ç¶åéæ°éªè¯ this.$refs.locationForm.clearValidate('locationType'); // çæå»¶è¿åéæ°éªè¯ï¼ç¡®ä¿DOMå·²æ´æ° setTimeout(() => { this.$refs.locationForm.validateField('locationType', (errorMsg) => { if (!errorMsg && (value === 0 || value)) { console.log('ä»åºåºåéªè¯éè¿:', value); // åºåéæ©åï¼èªå¨èç¦å°æçè¾å ¥æ¡ this.focusTrayInput(); } }); }, 100); } }); }, // æ°å¢ï¼æ¥è¯¢å端åºåç»è®¡æ°æ®ï¼è°ç¨ä¹åç SumQuantity æ¥å£ï¼ async fetchStockStatistics() { // åæ®å·ä¸ºç©ºæ¶ä¸æ¥è¯¢ @@ -326,6 +416,69 @@ this.sumLoading = false; } }, /** * 表åéªè¯ */ async validateForm() { return new Promise((resolve) => { if (!this.$refs.locationForm) { this.error = 'è¡¨åæªåå§å'; this.$message.warning('请å éæ©ä»åºåºå'); resolve(false); return; } this.$refs.locationForm.validate((valid) => { if (valid) { this.error = ''; resolve(true); } else { // æå¨æ£æ¥locationTypeï¼æ£ç¡®å¤çå¼ä¸º0çæ åµ if (this.form.locationType === null || this.form.locationType === undefined || this.form.locationType === '') { this.error = '请å éæ©ä»åºåºå'; this.$message.warning('请å éæ©ä»åºåºå'); } else { // 妿å¼åå¨ï¼å æ¬0ï¼ï¼ä½éªè¯ä¸éè¿ï¼å¯è½æ¯å ¶ä»éªè¯é误 this.error = 'è¯·æ£æ¥è¡¨å填忝妿£ç¡®'; } resolve(false); } }); }); }, // èç¦å°ä»åºåºåéæ© focusLocationSelect() { if (this.$refs.locationForm) { const selectEl = this.$el.querySelector('.el-select .el-input__inner'); if (selectEl) { selectEl.focus(); this.currentFocus = 'location'; } } }, // èç¦å°æçè¾å ¥æ¡ focusTrayInput() { if (this.$refs.trayInput && this.$refs.trayInput.$el) { const inputEl = this.$refs.trayInput.$el.querySelector('input'); if (inputEl) { inputEl.focus(); this.currentFocus = 'tray'; this.scanTarget = 'tray'; } } }, // èç¦å°ç©æè¾å ¥æ¡ focusBarcodeInput() { if (this.$refs.barcodeInput && this.$refs.barcodeInput.$el) { const inputEl = this.$refs.barcodeInput.$el.querySelector('input'); if (inputEl) { inputEl.focus(); this.currentFocus = 'material'; this.scanTarget = 'material'; } } }, // éç½®æææ°æ® resetData() { console.log('éç½®å¼¹æ¡æ°æ®'); @@ -338,13 +491,20 @@ this.lastKeyTime = null; this.isManualInput = false; this.isScanning = false; this.currentFocus = 'tray'; this.currentFocus = 'location'; this.scanTarget = 'tray'; this.clearAllTimers(); this.totalStockSum = 0; this.totalStockCount = 0; this.sumLoading = false; this.sumError = ''; this.form.locationType = null; // æ¸ é¤è¡¨åéªè¯ç¶æ this.$nextTick(() => { if (this.$refs.locationForm) { this.$refs.locationForm.clearValidate(); } }); }, // æ¸ é¤ææè®¡æ¶å¨ @@ -366,7 +526,16 @@ // 使ç¨setTimeoutç¡®ä¿DOMå®å ¨æ¸²æååèç¦ this.$nextTick(() => { setTimeout(() => { this.focusTrayInput(); this.initLocationTypes(); // åå§åä»åºåºå // ç¡®ä¿è¡¨åå¼ç¨åå¨ååèç¦ if (this.$refs.locationForm) { this.focusLocationSelect(); } else { // å¦æè¡¨åå¼ç¨è¿ä¸åå¨ï¼ç¨åéè¯ setTimeout(() => { this.focusLocationSelect(); }, 500); } }, 300); }); }, @@ -383,7 +552,9 @@ }, // 确认æé® handleConfirm() { async handleConfirm() { if (!await this.validateForm()) return; if (this.materials.length === 0) { this.$message.warning('请è³å°æ·»å ä¸ä¸ªç©æ'); return; @@ -395,6 +566,8 @@ } const result = { locationType: this.form.locationType, locationDesc: this.currentLocationDesc, trayBarcode: this.trayBarcode, materials: this.materials, docNo: this.docNo @@ -404,84 +577,70 @@ this.$emit('back-success', result); this.palletVisible = false; }, // èç¦å°æçè¾å ¥æ¡ focusTrayInput() { if (this.$refs.trayInput && this.$refs.trayInput.$el) { const inputEl = this.$refs.trayInput.$el.querySelector('input'); if (inputEl) { inputEl.focus(); this.currentFocus = 'tray'; this.scanTarget = 'tray'; } } }, // èç¦å°ç©æè¾å ¥æ¡ focusBarcodeInput() { if (this.$refs.barcodeInput && this.$refs.barcodeInput.$el) { const inputEl = this.$refs.barcodeInput.$el.querySelector('input'); if (inputEl) { inputEl.focus(); this.currentFocus = 'material'; this.scanTarget = 'material'; } } }, // å¤çæçè¾å ¥ // å¤çæçè¾å ¥ handleTrayInput() { // æ 记为æå¨è¾å ¥æ¨¡å¼ this.isManualInput = true; this.isScanning = false; // æ¸ é¤ä¹åç计æ¶å¨ if (this.manualInputTimer) { clearTimeout(this.manualInputTimer); } // 设置计æ¶å¨ï¼å¦æä¸æ®µæ¶é´å 没æè¾å ¥ï¼åé置为æ«ç æ¨¡å¼ this.manualInputTimer = setTimeout(() => { this.isManualInput = false; }, 1000); // æ 记为æå¨è¾å ¥æ¨¡å¼ this.isManualInput = true; this.isScanning = false; // æ¸ é¤ä¹åç计æ¶å¨ if (this.manualInputTimer) { clearTimeout(this.manualInputTimer); } // 设置计æ¶å¨ï¼å¦æä¸æ®µæ¶é´å 没æè¾å ¥ï¼åé置为æ«ç æ¨¡å¼ this.manualInputTimer = setTimeout(() => { this.isManualInput = false; }, 1000); }, // å¤çç©æè¾å ¥ handleBarcodeInput() { // æ 记为æå¨è¾å ¥æ¨¡å¼ this.isManualInput = true; this.isScanning = false; // æ¸ é¤ä¹åç计æ¶å¨ if (this.manualInputTimer) { clearTimeout(this.manualInputTimer); } // 设置计æ¶å¨ï¼å¦æä¸æ®µæ¶é´å 没æè¾å ¥ï¼åé置为æ«ç æ¨¡å¼ this.manualInputTimer = setTimeout(() => { this.isManualInput = false; }, 1000); }, // å¤çæçæ¡ç æäº¤ handleTraySubmit() { const currentTrayBarcode = this.trayBarcode.trim(); if (!currentTrayBarcode) { this.error = '请è¾å ¥ææ«ææçæ¡ç '; return; } // æ 记为æå¨è¾å ¥æ¨¡å¼ this.isManualInput = true; this.isScanning = false; // æ¸ é¤ä¹åç计æ¶å¨ if (this.manualInputTimer) { clearTimeout(this.manualInputTimer); } // 设置计æ¶å¨ï¼å¦æä¸æ®µæ¶é´å 没æè¾å ¥ï¼åé置为æ«ç æ¨¡å¼ this.manualInputTimer = setTimeout(() => { this.isManualInput = false; }, 1000); }, // å¤çæçæ¡ç æäº¤ async handleTraySubmit() { // å ç´æ¥æ£æ¥locationTypeï¼é¿å 表åéªè¯ç弿¥é®é¢ if (!this.form.locationType) { this.error = '请å éæ©ä»åºåºå'; this.$message.warning('请å éæ©ä»åºåºå'); return; } // ç¶ååè¿è¡å®æ´ç表åéªè¯ if (!await this.validateForm()) return; const currentTrayBarcode = this.trayBarcode.trim(); if (!currentTrayBarcode) { this.error = '请è¾å ¥ææ«ææçæ¡ç '; return; } this.error = ''; // 设置æçæ¡ç åï¼èªå¨èç¦å°ç©æè¾å ¥æ¡ this.focusBarcodeInput(); this.$message({ message: `æçæ¡ç 已设置: ${currentTrayBarcode}`, type: 'success', duration: 2000 }); }, this.error = ''; // 设置æçæ¡ç åï¼èªå¨èç¦å°ç©æè¾å ¥æ¡ this.focusBarcodeInput(); this.$message({ message: `æçæ¡ç 已设置: ${currentTrayBarcode}`, type: 'success', duration: 2000 }); }, // æ¸ é¤æç clearTray() { @@ -510,6 +669,7 @@ // å¤çç©ææ¡ç æäº¤ async handleBarcodeSubmit() { if (!await this.validateForm()) return; const currentBarcode = this.barcode.trim(); if (!this.trayBarcode) { @@ -553,6 +713,8 @@ this.materials.push({ ...item, trayCode: this.trayBarcode, locationType: this.form.locationType, locationDesc: this.currentLocationDesc, scanTime: this.formatTime(new Date()) }); }); @@ -590,7 +752,8 @@ { palletCode: this.trayBarcode, orderNo: this.docNo, barcodes: barcode barcodes: barcode, locationType: this.form.locationType // æ·»å ä»åºåºåä¿¡æ¯ } ); @@ -729,135 +892,299 @@ .barcode-scanner-container { max-width: 1200px; margin: 0 auto; padding: 20px; padding: 10px; display: flex; flex-direction: column; height: 100%; gap: 8px; } /* ç´§åå¸å±æ ·å¼ */ .compact { margin-bottom: 0; } .compact-form { margin-bottom: 0; } .compact-item { margin-bottom: 0; } .compact-card { margin-bottom: 0; } .compact-card >>> .el-card__body { padding: 12px; } .compact-header { display: flex; justify-content: space-between; align-items: center; padding: 0 !important; } .compact-header >>> .el-card__header { padding: 8px 12px; } .compact-input { margin: 8px 0; } .compact-tips { margin-top: 8px; font-size: 11px; } /* ä»åºåºåéæ© - ç´§å */ .location-section.compact { margin-bottom: 8px; } .location-section.compact >>> .el-form-item { margin-bottom: 0; } /* æçä¿¡æ¯ - ç´§å */ .tray-info.compact { padding: 6px 10px; margin-bottom: 8px; font-size: 13px; } /* æ«ç åºå - ç´§å */ .input-section.compact { margin-bottom: 8px; flex-shrink: 0; } /* ç©æå表 - åºå®é«åº¦å¸¦æ»å¨ */ .material-list.compact { flex: 1; min-height: 0; /* éè¦ï¼å 许flexå项æ¶ç¼© */ display: flex; flex-direction: column; } .material-list.compact >>> .el-card { display: flex; flex-direction: column; height: 100%; } .material-list.compact >>> .el-card__body { flex: 1; display: flex; flex-direction: column; padding: 0; min-height: 0; } .table-container { flex: 1; min-height: 0; overflow: hidden; } .material-list.compact >>> .el-table { flex: 1; } .material-list.compact >>> .el-table__body-wrapper { overflow-y: auto; } /* ç´§åçç©ºç¶æ */ .empty-state.compact { padding: 20px 0; flex: 1; display: flex; flex-direction: column; justify-content: center; align-items: center; } .empty-state.compact i { font-size: 36px; margin-bottom: 8px; } .empty-state.compact p { font-size: 13px; } /* å ¶ä»åææ ·å¼è°æ´ */ .page-title { text-align: center; margin-bottom: 30px; margin-bottom: 15px; } .input-section { margin-bottom: 30px; } .scan-status { float: right; font-size: 12px; color: #67C23A; } .scan-indicator { display: inline-block; width: 10px; height: 10px; width: 8px; height: 8px; border-radius: 50%; background-color: #67C23A; margin-right: 5px; animation: pulse 1.5s infinite; } @keyframes pulse { 0% { opacity: 1; } 50% { opacity: 0.4; } 100% { opacity: 1; } } .input-wrapper { position: relative; margin-bottom: 15px; } .input-tips { margin-top: 10px; font-size: 12px; margin-top: 6px; color: #909399; } .loading { text-align: center; margin: 20px 0; .warning-text { color: #E6A23C; font-weight: bold; } .loading p { margin-top: 10px; .loading.compact { text-align: center; margin: 10px 0; padding: 5px; } .loading.compact p { margin-top: 5px; color: #409EFF; font-size: 12px; } .error-message { margin-bottom: 20px; .error-message.compact { margin: 5px 0; } .material-list { margin-top: 30px; .error-message.compact >>> .el-alert { padding: 6px 12px; } .list-actions { float: right; display: flex; align-items: center; gap: 4px; } .list-actions >>> .el-tag { height: 24px; line-height: 22px; padding: 0 6px; } .clear-all-btn { margin-left: 10px; margin-left: 8px; } .empty-state { text-align: center; padding: 40px 0; color: #909399; } .empty-state i { font-size: 48px; margin-bottom: 10px; } .material-code { font-family: 'Courier New', monospace; font-weight: bold; color: #409EFF; } .tray-info { background: #f0f9ff; padding: 10px 15px; border-radius: 4px; margin-bottom: 15px; border-left: 4px solid #409EFF; .location-info { color: #606266; font-weight: normal; } .debug-info { background: #f5f7fa; padding: 10px; padding: 8px; border-radius: 4px; margin-top: 10px; font-size: 12px; margin-top: 8px; font-size: 11px; color: #909399; } .small-button { padding: 7px 9px; font-size: 12px; padding: 6px 8px; font-size: 11px; } .custom-input-group { display: flex; align-items: center; width: 100%; margin: 20px 0; border: 1px solid #DCDFE6; border-radius: 4px; overflow: hidden; background: #fff; } .input-label { padding: 0 15px; background: #F5F7FA; border-right: 1px solid #DCDFE6; color: #606266; font-size: 14px; white-space: nowrap; height: 40px; line-height: 40px; flex-shrink: 0; } /* è¾å ¥æ¡ç»æ ·å¼è°æ´ */ .custom-input-group { display: flex; align-items: center; width: 100%; margin: 8px 0; border: 1px solid #DCDFE6; border-radius: 4px; overflow: hidden; background: #fff; } .input-container { display: flex; flex: 1; align-items: center; } .input-label { padding: 0 12px; background: #F5F7FA; border-right: 1px solid #DCDFE6; color: #606266; font-size: 13px; white-space: nowrap; height: 36px; line-height: 36px; flex-shrink: 0; min-width: 70px; text-align: center; } .custom-input { flex: 1; } .input-container { display: flex; flex: 1; align-items: center; } .custom-input ::v-deep .el-input__inner { border: none; border-radius: 0; height: 40px; line-height: 40px; } .custom-input { flex: 1; } .custom-input >>> .el-input__inner { border: none; border-radius: 0; height: 36px; line-height: 36px; font-size: 13px; } /* ååºå¼è°æ´ */ @media (max-width: 768px) { .barcode-scanner-container { padding: 5px; } .custom-input-group { flex-direction: column; border: none; } .input-label { width: 100%; border-right: none; border-bottom: 1px solid #DCDFE6; margin-bottom: 5px; } .input-container { width: 100%; border: 1px solid #DCDFE6; border-radius: 4px; } } </style> ÏîÄ¿´úÂë/WIDESEA_WMSClient/src/views/outbound/PickingConfirm.vue
@@ -48,6 +48,14 @@ :disabled="!currentLockInfo" /> </el-form-item> <!-- ç©æä¿¡æ¯æ¾ç¤º --> <el-form-item label="ç©æç¼ç " v-if="currentMaterialInfo"> <el-input v-model="currentMaterialInfo.materielCode" readonly /> </el-form-item> <el-form-item label="ç©æåç§°" v-if="currentMaterialInfo"> <el-input v-model="currentMaterialInfo.materielName" readonly /> </el-form-item> </el-form> <div class="current-info" v-if="currentPallet"> @@ -141,6 +149,7 @@ }, currentPallet: null, currentLockInfo: null, currentMaterialInfo: null, // æ°å¢ï¼å½åç©æä¿¡æ¯ pickedList: [], pickedColumns: [ { field: 'barcode', title: 'ç©ææ¡ç ', width: 150 }, @@ -153,7 +162,8 @@ { field: 'action', title: 'æä½', width: 80, slot: true } ], splitVisible: false, maxPickQuantity: 0 maxPickQuantity: 0, allLockInfos: [] // æ°å¢ï¼ä¿åææéå®ä¿¡æ¯ï¼ç¨äºæ¡ç å¹é } }, computed: { @@ -174,7 +184,7 @@ if (!orderId) return try { const result = await this.http.post(`api/OutboundOrder/GetById?id=${orderId}`) const result = await this.http.get(`api/OutboundOrder/GetById?id=${orderId}`) if (result.status) { this.orderInfo = result.data } @@ -195,7 +205,7 @@ ) if (result.status) { this.currentPallet = result.data this.loadPalletLockInfo() await this.loadPalletLockInfo() this.$message.success(`æç ${this.scanForm.palletCode} è¯å«æå`) } else { this.$message.error(result.message) @@ -212,42 +222,148 @@ 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 if (result.status) { this.allLockInfos = result.data // é»è®¤éæ©ç¬¬ä¸ä¸ªéå®ä¿¡æ¯ if (this.allLockInfos.length > 0) { this.currentLockInfo = this.allLockInfos[0] this.currentMaterialInfo = { materielCode: this.currentLockInfo.materielCode, materielName: this.currentLockInfo.materielName } this.maxPickQuantity = this.currentLockInfo.assignQuantity - this.currentLockInfo.pickedQty } } } catch (error) { console.error('å è½½éå®ä¿¡æ¯å¤±è´¥:', error) } }, // æ ¹æ®æ¡ç æ¥æ¾å¯¹åºçéå®ä¿¡æ¯åç©æä¿¡æ¯ findLockInfoByBarcode(barcode) { if (!this.allLockInfos || this.allLockInfos.length === 0) { return null } // é¦å 精确å¹é å½åæ¡ç let lockInfo = this.allLockInfos.find(x => x.currentBarcode === barcode) if (lockInfo) { return lockInfo } // å¦ææ²¡æç²¾ç¡®å¹é ï¼æ¥æ¾è¯¥æ¡ç 对åºçç©ææ¯å¦å¨éå®ä¿¡æ¯ä¸ // è¿ééè¦è°ç¨å端æ¥å£éªè¯æ¡ç 对åºçç©æ return null }, async handleBarcodeScan() { // å®ç°æ«ç 确认é»è¾ if (!this.scanForm.barcode) { this.$message.warning('请è¾å ¥ç©ææ¡ç ') return } if (!this.currentPallet) { this.$message.warning('è¯·å æ«ææçæ¡ç ') return } if (this.scanForm.quantity <= 0) { this.$message.warning('请è¾å ¥ææçæ£éæ°é') return } try { // éªè¯æ¡ç å¹¶è·åç©æä¿¡æ¯ const materialInfo = await this.validateBarcode(this.scanForm.barcode) if (!materialInfo) { this.$message.error('æ æçç©ææ¡ç ') return } // æ¥æ¾å¯¹åºçéå®ä¿¡æ¯ const targetLockInfo = this.findLockInfoByBarcodeAndMaterial(this.scanForm.barcode, materialInfo.materielCode) if (!targetLockInfo) { this.$message.error('è¯¥ç©ææ¡ç ä¸å¨å½åæççéå®ä¿¡æ¯ä¸') return } // æ£æ¥æ£éæ°é const availableQuantity = targetLockInfo.assignQuantity - targetLockInfo.pickedQty if (this.scanForm.quantity > availableQuantity) { this.$message.error(`æ£éæ°éè¶ è¿å¯ç¨æ°éï¼å©ä½å¯æ£éï¼${availableQuantity}`) return } // åå¤è¯·æ±æ°æ® const request = { orderDetailId: targetLockInfo.orderDetailId, barcode: this.scanForm.barcode, quantity: this.scanForm.quantity, materielCode: materialInfo.materielCode, // ä¼ éç©æç¼ç pickQuantity: this.scanForm.quantity, locationCode: this.currentPallet.locationCode, palletCode: this.currentPallet.palletCode, orderId: this.orderInfo.id stockId: targetLockInfo.stockId, outStockLockInfoId: targetLockInfo.id // ä¼ ééå®ä¿¡æ¯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.currentMaterialInfo = null // å·æ°æ°æ® this.loadOrderInfo() this.loadPickedHistory() this.loadPalletLockInfo() } else { this.$message.error(result.message) } } catch (error) { this.$message.error('æ£é确认失败') this.$message.error('æ£é确认失败: ' + (error.message || 'æªç¥é误')) } }, // æ ¹æ®æ¡ç åç©æç¼ç æ¥æ¾éå®ä¿¡æ¯ findLockInfoByBarcodeAndMaterial(barcode, materielCode) { if (!this.allLockInfos || this.allLockInfos.length === 0) { return null } // é¦å å°è¯ç²¾ç¡®å¹é æ¡ç let lockInfo = this.allLockInfos.find(x => x.currentBarcode === barcode && x.materielCode === materielCode ) if (lockInfo) { return lockInfo } // å¦æç²¾ç¡®å¹é 失败ï¼åªå¹é ç©æç¼ç ï¼å 许ä»åä¸ç©æçä¸åæ¡ç æ£éï¼ lockInfo = this.allLockInfos.find(x => x.materielCode === materielCode && (x.assignQuantity - x.pickedQty) > 0 ) return lockInfo }, // éªè¯æ¡ç å¹¶è·åç©æä¿¡æ¯ async validateBarcode(barcode) { try { const result = await this.http.get(`api/OutboundPicking/ValidateBarcode?barcode=${barcode}`) if (result.status) { return result.data } else { this.$message.error(result.message) return null } } catch (error) { this.$message.error('æ¡ç éªè¯å¤±è´¥') return null } }, @@ -261,7 +377,8 @@ const result = await this.http.post('api/BackToStock/GenerateBackToStockTask', { palletCode: this.currentPallet.palletCode, currentLocation: 'æ£éä½' currentLocation: 'æ£éä½', operator: 'å½åç¨æ·' }) if (result.status) { @@ -311,6 +428,8 @@ resetCurrentPallet() { this.currentPallet = null this.currentLockInfo = null this.currentMaterialInfo = null this.allLockInfos = [] this.scanForm.palletCode = '' }, @@ -351,4 +470,49 @@ this.loadPickedHistory() } } </script> </script> <style scoped> .picking-confirm { padding: 20px; } .page-header { margin-bottom: 20px; } .title { font-size: 18px; font-weight: bold; } .scan-section { margin-bottom: 20px; } .action-buttons { display: flex; flex-direction: column; gap: 10px; } .action-buttons .el-button { width: 100%; } .current-info { margin-top: 15px; padding: 10px; background-color: #f5f7fa; border-radius: 4px; } .current-info p { margin: 5px 0; font-size: 14px; } .summary-info { margin-bottom: 15px; } </style> ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/.vs/WIDESEA_WMSServer/CopilotIndices/17.14.878.3237/CodeChunks.db-shmBinary files differ
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/.vs/WIDESEA_WMSServer/CopilotIndices/17.14.878.3237/SemanticSymbols.db-shmBinary files differ
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_BasicService/LocationInfoService.cs
@@ -36,13 +36,13 @@ private readonly IUnitOfWorkManage _unitOfWorkManage; private readonly IRepository<Dt_StockInfo> _stockInfoRepository; public IRepository<Dt_LocationInfo> Repository => BaseDal; public readonly IRepository<Dt_LocationType> _locationTypeRepository; public LocationInfoService(IRepository<Dt_LocationInfo> BaseDal, IUnitOfWorkManage unitOfWorkManage, IRepository<Dt_StockInfo> stockInfoRepository ) : base(BaseDal) public LocationInfoService(IRepository<Dt_LocationInfo> BaseDal, IUnitOfWorkManage unitOfWorkManage, IRepository<Dt_StockInfo> stockInfoRepository, IRepository<Dt_LocationType> locationTypeRepository) : base(BaseDal) { _unitOfWorkManage = unitOfWorkManage; _stockInfoRepository = stockInfoRepository; _locationTypeRepository = locationTypeRepository; } /// <summary> @@ -173,6 +173,12 @@ return Repository.QueryData(x => locationCodes.Contains(x.LocationCode)); } public List<LocationTypeDto> GetLocationTypes() { return _locationTypeRepository.Db.Queryable<Dt_LocationType>().Select(x=> new LocationTypeDto { LocationType=x.LocationType,LocationTypeDesc=x.LocationTypeDesc}).ToList(); } /// <summary> /// åå§åè´§ä½ /// </summary> ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_BasicService/WarehouseService.cs
@@ -12,16 +12,19 @@ using WIDESEA_Common.CommonEnum; using WIDESEA_Core.Caches; using WIDESEA_Core.BaseRepository; using WIDESEA_Model.Models.Basic; using WIDESEA_DTO.Basic; namespace WIDESEA_BasicService { public partial class WarehouseService : ServiceBase<Dt_Warehouse, IRepository<Dt_Warehouse>>, IWarehouseService { private readonly ICacheService _cacheService; public WarehouseService(IRepository<Dt_Warehouse> BaseDal,ICacheService cacheService) : base(BaseDal) private readonly IRepository<Dt_WarehouseArea> _warehouseArearepository; public WarehouseService(IRepository<Dt_Warehouse> BaseDal, ICacheService cacheService, IRepository<Dt_WarehouseArea> warehouseArearepository) : base(BaseDal) { _cacheService = cacheService; _warehouseArearepository = warehouseArearepository; } public IRepository<Dt_Warehouse> Repository => BaseDal; @@ -80,6 +83,35 @@ return WarehouseDisableStatus(new int[] { key }); } public async Task<WebResponseContent> ReceiveWarehouseArea(List<WarehouseAreaDto> models) { var lists = _warehouseArearepository.Db.Queryable<Dt_WarehouseArea>().ToList(); foreach (var item in models) { var dbfirst = lists.FirstOrDefault(x => x.Code == item.Code); if (dbfirst != null) { dbfirst.Code = item.Code; dbfirst.Name = item.Name; dbfirst.FactoryArea = item.FactoryArea; _warehouseArearepository.UpdateData(dbfirst); } else { _warehouseArearepository.AddData(new Dt_WarehouseArea { Code=item.Code,Name=item.Name,FactoryArea=item.FactoryArea}); } } return WebResponseContent.Instance.OK(); } } } ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_DTO/Basic/LocationGroupDTO.cs
@@ -1,8 +1,10 @@ using System; using SqlSugar; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using WIDESEA_Core.DB.Models; namespace WIDESEA_DTO.Basic { @@ -32,4 +34,10 @@ public int EnableStatusB { get; set; } } public class LocationTypeDto { public int LocationType { get; set; } public string LocationTypeDesc { get; set; } } } ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_DTO/Basic/SupplierDTO.cs
@@ -1,9 +1,11 @@ using System; using SqlSugar; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using WIDESEA_Core.Attributes; using WIDESEA_Core.DB.Models; namespace WIDESEA_DTO.Basic { @@ -76,4 +78,13 @@ [PropertyValidate("æä½ç±»å", NotNullAndEmpty = true,Check = new object[] { 0, 1, 2 })] public string OperateType { get; set; } } public class WarehouseAreaDto { public string Code { get; set; } public string Name { get; set; } public string FactoryArea { get; set; } } } ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_DTO/Outbound/OutboundOrderGetDTO.cs
@@ -31,6 +31,8 @@ public decimal PickQuantity { get; set; } public string LocationCode { get; set; } public string PalletCode { get; set; } public int StockId { get; set; } // åºåID public int OutStockLockInfoId { get; set; } // åºåºéå®ä¿¡æ¯ID } public class DirectOutboundRequest ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_IBasicService/ILocationInfoService.cs
@@ -59,6 +59,8 @@ List<Dt_LocationInfo> GetLocationInfos(List<string> locationCodes); List<LocationTypeDto> GetLocationTypes(); } ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_IBasicService/IWarehouseService.cs
@@ -6,6 +6,7 @@ using WIDESEA_Core; using WIDESEA_Core.BaseRepository; using WIDESEA_Core.BaseServices; using WIDESEA_DTO.Basic; using WIDESEA_Model.Models; namespace WIDESEA_IBasicService @@ -13,5 +14,7 @@ public interface IWarehouseService : IService<Dt_Warehouse> { IRepository<Dt_Warehouse> Repository { get; } Task<WebResponseContent> ReceiveWarehouseArea(List<WarehouseAreaDto> models); } } ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_IOutboundService/IOutStockLockInfoService.cs
@@ -21,8 +21,9 @@ Task<List<Dt_OutStockLockInfo>> GetByOrderDetailId(int orderDetailId); Task<List<Dt_OutStockLockInfo>> GetByPalletCode(string palletCode, int? status = null); Dt_OutStockLockInfo GetOutStockLockInfo(Dt_OutboundOrder outboundOrder, Dt_OutboundOrderDetail outboundOrderDetail, Dt_StockInfo outStock, decimal assignQuantity, int? taskNum = null); Dt_OutStockLockInfo GetOutStockLockInfo(Dt_OutboundOrder outboundOrder, Dt_OutboundOrderDetail outboundOrderDetail, Dt_StockInfo outStock, decimal assignQuantity, string barcode = null, int? taskNum = null); Dt_OutStockLockInfo GetOutStockLockInfo(Dt_OutboundOrder outboundOrder,Dt_OutboundOrderDetail outboundOrderDetail,Dt_StockInfo outStock, decimal assignQuantity, string barcode = null); Task<List<Dt_OutStockLockInfo>> GetPalletLockInfos(string palletCode); Task<WebResponseContent> UpdateLockInfoBarcode(int lockInfoId, string newBarcode); } ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_IOutboundService/IOutboundPickingService.cs
@@ -18,7 +18,7 @@ Task<WebResponseContent> CancelPicking(CancelPickingRequest request); Task<WebResponseContent> ConfirmPicking(PickingConfirmRequest request); Task<List<Dt_PickingRecord>> GetPickingHistory(int orderId); Task<WebResponseContent> ValidateBarcode(string barcode); Task<WebResponseContent> GetPalletOutboundStatus(string palletCode); } } ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_IStockService/IStockInfoService.cs
@@ -12,7 +12,8 @@ List<Dt_StockInfo> GetStockInfos(string materielCode, string lotNo, List<string> locationCodes); List<Dt_StockInfo> GetUseableStocks(string materielCode, string batchNo); List<Dt_StockInfo> GetOutboundStocks(List<Dt_StockInfo> stockInfos, string materielCode, decimal needQuantity, out decimal residueQuantity); void AddMaterielGroup(Dt_StockInfo stockInfo); (List<Dt_StockInfo>, Dictionary<int, decimal>) GetOutboundStocks(List<Dt_StockInfo> stockInfos, string materielCode, decimal needQuantity, out decimal residueQuantity); } } ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_InboundService/InboundOrderService.cs
@@ -358,6 +358,7 @@ Status = 0, OrderNo = inboundOrder.InboundOrderNo, BusinessType = inboundOrder.BusinessType, ProductionDate=DateTime.Now.ToString("yyyy-mm-dd HH:mm:ss") }); item.ReceiptQuantity = item.BarcodeQty; @@ -376,7 +377,7 @@ { inboundOrder.OrderStatus = InOrderStatusEnum.å ¥åºä¸.ObjToInt(); } inboundOrder.Operator = App.User.UserName; content = MaterielGroupUpdateData(inboundOrder, dbinboundOrderDetails, stockInfo); if (content.Status) { ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_Model/Models/Basic/Dt_LocationInfo.cs
@@ -30,7 +30,7 @@ /// è´§ä½ç¼å· /// </summary> [SugarColumn(IsNullable = true, Length = 30, ColumnDescription = "è´§ä½ç¼å·")] public string LocationCode { get; set; } public string LocationCode { get; set; } /// <summary> /// è´§ä½åç§° @@ -42,13 +42,13 @@ /// å··éç¼å· /// </summary> [SugarColumn(IsNullable = true, Length = 20, ColumnDescription = "å··éç¼å·")] public string RoadwayNo { get; set; } public string RoadwayNo { get; set; } /// <summary> /// è´§ä½è¡ /// </summary> [SugarColumn(IsNullable = true, ColumnDescription = "è´§ä½è¡")] public int Row { get; set; } public int Row { get; set; } /// <summary> /// è´§ä½å @@ -60,25 +60,25 @@ /// è´§ä½å± /// </summary> [SugarColumn(IsNullable = true, ColumnDescription = "è´§ä½å±")] public int Layer { get; set; } public int Layer { get; set; } /// <summary> /// è´§ä½æ·±åº¦ /// </summary> [SugarColumn(IsNullable = true, ColumnDescription = "è´§ä½æ·±åº¦")] public int Depth { get; set; } public int Depth { get; set; } /// <summary> /// è´§ä½ç±»å /// </summary> [SugarColumn(IsNullable = true, ColumnDescription = "è´§ä½ç±»å")] public int LocationType { get; set; } public int LocationType { get; set; } /// <summary> /// è´§ä½ç¶æ /// </summary> [SugarColumn(IsNullable = true, DefaultValue = "0", ColumnDescription = "è´§ä½ç¶æ")] public int LocationStatus { get; set; } public int LocationStatus { get; set; } /// <summary> /// ç¦ç¨ç¶æ @@ -90,6 +90,19 @@ /// 夿³¨ /// </summary> [SugarColumn(IsNullable = true, Length = 200, ColumnDescription = "夿³¨")] public string Remark { get; set; } public string Remark { get; set; } } [SugarTable(nameof(Dt_LocationType), "è´§ä½åºåç±»å")] public class Dt_LocationType : BaseEntity { /// <summary> /// ä¸»é® /// </summary> [SugarColumn(IsPrimaryKey = true, IsIdentity = true, ColumnDescription = "主é®")] public int Id { get; set; } public int LocationType { get; set; } public string LocationTypeDesc { get; set; } } } ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_Model/Models/Basic/Dt_WarehouseArea.cs
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,24 @@ using SqlSugar; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using WIDESEA_Core.DB.Models; namespace WIDESEA_Model.Models.Basic { [SugarTable(nameof(Dt_WarehouseArea), "ä»åºåºåä¿¡æ¯")] public class Dt_WarehouseArea : BaseEntity { /// <summary> /// ä¸»é® /// </summary> [SugarColumn(IsPrimaryKey = true, IsIdentity = true, ColumnDescription = "主é®")] public int Id { get; set; } public string Code { get; set; } public string Name { get; set; } public string FactoryArea { get; set; } } } ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_Model/Models/Inbound/Dt_InboundOrder.cs
@@ -93,6 +93,8 @@ [SugarColumn(IsNullable = true, Length = 200, ColumnDescription = "夿³¨")] public string Remark { get; set; } [SugarColumn(IsNullable = false, Length = 50, ColumnDescription = "æä½è ")] public string Operator { get; set; } /// <summary> /// å ¥åºåæç» /// </summary> ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_Model/Models/Outbound/Dt_OutboundLockInfo.cs
@@ -108,6 +108,8 @@ [SugarColumn(IsNullable = true, ColumnDescription = "ä»»å¡å·")] public int? TaskNum { get; set; } public string SupplyCode { get; set; } public string WarehouseCode { get; set; } /// <summary> /// ç¶æ ç¶æï¼0-å·²åé 1-é¨åæ£é 2-å·²æ£é 3-已宿 /// </summary> ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_Model/Models/Outbound/Dt_OutboundOrder.cs
@@ -99,6 +99,9 @@ [SugarColumn(IsNullable = true, Length = 200, ColumnDescription = "夿³¨")] public string Remark { get; set; } [SugarColumn(IsNullable = false, Length = 50, ColumnDescription = "æä½è ")] public string Operator { get; set; } /// <summary> /// åºåºåæç» /// </summary> ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_Model/Models/Stock/Dt_StockInfoDetail.cs
@@ -132,7 +132,7 @@ [SugarColumn(IsNullable = true, ColumnDescription = "夿³¨")] public string Remark { get; set; } [SugarColumn(IsIgnore = true)] [Navigate(NavigateType.ManyToOne, nameof(Dt_StockInfo.Id), nameof(Id))] public Dt_StockInfo StockInfo { get; set; } } } ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_OutboundService/OutStockLockInfoService.cs
@@ -32,59 +32,52 @@ _recordService = recordService; } public Dt_OutStockLockInfo GetOutStockLockInfo(Dt_OutboundOrder outboundOrder, Dt_OutboundOrderDetail outboundOrderDetail, Dt_StockInfo outStock, decimal assignQuantity, int? taskNum = null) { Dt_OutStockLockInfo outStockLockInfo = new Dt_OutStockLockInfo() { PalletCode = outStock.PalletCode, AssignQuantity = assignQuantity, MaterielCode = outboundOrderDetail.MaterielCode, BatchNo = outboundOrderDetail.BatchNo ?? outStock.Details.FirstOrDefault()?.BatchNo, LocationCode = outStock.LocationCode, MaterielName = outboundOrderDetail.MaterielName, OrderDetailId = outboundOrderDetail.Id, OrderNo = outboundOrder.OrderNo, OrderType = outboundOrder.OrderType, OriginalQuantity = outStock.Details.Where(x => x.MaterielCode == outboundOrderDetail.MaterielCode).Sum(x => x.StockQuantity), Status = taskNum == null ? OutLockStockStatusEnum.å·²åé .ObjToInt() : OutLockStockStatusEnum.åºåºä¸.ObjToInt(), StockId = outStock.Id, TaskNum = taskNum, OrderQuantity = outboundOrderDetail.OrderQuantity, Unit = outboundOrderDetail.Unit, //ProductionDate = outStock.Details.Where(x => x.MaterielCode == outboundOrderDetail.MaterielCode).FirstOrDefault()?.ProductionDate, //EffectiveDate = outStock.Details.Where(x => x.MaterielCode == outboundOrderDetail.MaterielCode).FirstOrDefault()?.EffectiveDate }; return outStockLockInfo; } /// <summary> /// å建åºåºéå®ä¿¡æ¯ /// å建åºåºéå®ä¿¡æ¯ - ä¿®å¤çæ¬ /// </summary> public Dt_OutStockLockInfo GetOutStockLockInfo(Dt_OutboundOrder outboundOrder, Dt_OutboundOrderDetail outboundOrderDetail, Dt_StockInfo outStock, decimal assignQuantity, string barcode = null, int? taskNum = null) public Dt_OutStockLockInfo GetOutStockLockInfo( Dt_OutboundOrder outboundOrder, Dt_OutboundOrderDetail outboundOrderDetail, Dt_StockInfo outStock, decimal assignQuantity, string barcode = null) { // è·ååºåæç»ä¸çæ¡ç ä¿¡æ¯ï¼å¦ææªæå®æ¡ç ï¼ä½¿ç¨ç¬¬ä¸ä¸ªå¯ç¨æ¡ç ï¼ var stockDetails = outStock.Details.Where(x => x.MaterielCode == outboundOrderDetail.MaterielCode && x.StockQuantity > x.OutboundQuantity) .OrderBy(x => x.ProductionDate).ToList(); // è·ååºåæç»ä¿¡æ¯ var stockDetails = outStock.Details .Where(x => x.MaterielCode == outboundOrderDetail.MaterielCode) .ToList(); if (!stockDetails.Any()) { throw new Exception($"æªæ¾å°ç©æ[{outboundOrderDetail.MaterielCode}]çå¯ç¨åºåæç»"); throw new Exception($"æªæ¾å°ç©æ[{outboundOrderDetail.MaterielCode}]çåºåæç»"); } // ç¡®å®æ¡ç ï¼å¦ææªæå®ï¼ä½¿ç¨ææ©å ¥åºçæ¡ç ï¼ var targetBarcode = barcode; if (string.IsNullOrEmpty(targetBarcode)) // ç¡®å®æ¡ç string targetBarcode; if (!string.IsNullOrEmpty(barcode)) { targetBarcode = stockDetails.First().Barcode; // éªè¯æå®çæ¡ç æ¯å¦åå¨ var specifiedBarcodeDetail = stockDetails.FirstOrDefault(x => x.Barcode == barcode); if (specifiedBarcodeDetail == null) { throw new Exception($"æå®çæ¡ç [{barcode}]å¨åºåä¸ä¸åå¨"); } targetBarcode = barcode; } // è·å该æ¡ç çå¯ç¨æ°é var barcodeDetail = stockDetails.FirstOrDefault(x => x.Barcode == targetBarcode); if (barcodeDetail == null) else { throw new Exception($"æ¡ç [{targetBarcode}]å¨åºåä¸ä¸åå¨"); // 使ç¨ç¬¬ä¸ä¸ªå¯ç¨æ¡ç var firstAvailableDetail = stockDetails .Where(x => x.StockQuantity > x.OutboundQuantity) .OrderBy(x => x.ProductionDate) .FirstOrDefault(); if (firstAvailableDetail == null) { throw new Exception($"ç©æ[{outboundOrderDetail.MaterielCode}]没æå¯ç¨åºå"); } targetBarcode = firstAvailableDetail.Barcode; } return new Dt_OutStockLockInfo() @@ -101,19 +94,18 @@ OriginalQuantity = outStock.Details .Where(x => x.MaterielCode == outboundOrderDetail.MaterielCode) .Sum(x => x.StockQuantity), Status = taskNum == null ? (int)OutLockStockStatusEnum.å·²åé : (int)OutLockStockStatusEnum.åºåºä¸, Status = (int)OutLockStockStatusEnum.å·²åé , StockId = outStock.Id, TaskNum = taskNum, Unit = outboundOrderDetail.Unit, // æ°å¢å段èµå¼ CurrentBarcode = targetBarcode, // å½ååé çæ¡ç OriginalLockQuantity = assignQuantity, // åå§é宿°é IsSplitted = 0 // åå§æªæå SupplyCode = outboundOrderDetail.SupplyCode, WarehouseCode = outboundOrderDetail.WarehouseCode, // æ°å¢å段 CurrentBarcode = targetBarcode, OriginalLockQuantity = assignQuantity, IsSplitted = 0 }; } /// <summary> /// æ ¹æ®è®¢åæç»IDè·ååºåºéå®ä¿¡æ¯ /// </summary> ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_OutboundService/OutboundOrderDetailService.cs
@@ -1,4 +1,5 @@ using WIDESEA_Common.LocationEnum; using Microsoft.Extensions.Logging; using WIDESEA_Common.LocationEnum; using WIDESEA_Common.StockEnum; using WIDESEA_Core; using WIDESEA_Core.BaseRepository; @@ -24,8 +25,8 @@ private readonly IRecordService _recordService; private readonly IOutboundOrderService _outboundOrderService; private readonly ILocationStatusChangeRecordService _locationStatusChangeRecordService; public OutboundOrderDetailService(IRepository<Dt_OutboundOrderDetail> BaseDal, IUnitOfWorkManage unitOfWorkManage, IStockService stockService, IOutStockLockInfoService outStockLockInfoService, IBasicService basicService, IRecordService recordService, ILocationInfoService locationInfoService, ILocationStatusChangeRecordService locationStatusChangeRecordService, IOutboundOrderService outboundOrderService) : base(BaseDal) private readonly ILogger<OutboundOrderDetailService> _logger; public OutboundOrderDetailService(IRepository<Dt_OutboundOrderDetail> BaseDal, IUnitOfWorkManage unitOfWorkManage, IStockService stockService, IOutStockLockInfoService outStockLockInfoService, IBasicService basicService, IRecordService recordService, ILocationInfoService locationInfoService, ILocationStatusChangeRecordService locationStatusChangeRecordService, IOutboundOrderService outboundOrderService, ILogger<OutboundOrderDetailService> logger) : base(BaseDal) { _unitOfWorkManage = unitOfWorkManage; _stockService = stockService; @@ -35,6 +36,7 @@ _locationInfoService = locationInfoService; _locationStatusChangeRecordService = locationStatusChangeRecordService; _outboundOrderService = outboundOrderService; _logger = logger; } @@ -85,10 +87,10 @@ } // åé åºåï¼æå è¿å åºï¼ List<Dt_StockInfo> autoAssignStocks = _stockService.StockInfoService.GetOutboundStocks( var (autoAssignStocks, stockAllocations) = _stockService.StockInfoService.GetOutboundStocks( stockInfos, item.MaterielCode, needQuantity, out decimal residueQuantity); if (residueQuantity > 0) if (residueQuantity > 0 && residueQuantity == needQuantity) { throw new Exception($"ç©æ[{item.MaterielCode}]åºåä¸è¶³ï¼éè¦{needQuantity}ï¼å¯ç¨{needQuantity - residueQuantity}"); } @@ -96,7 +98,7 @@ outStocks.AddRange(autoAssignStocks); // æå è¿å åºåååé é宿°éå°å个æç» DistributeLockQuantityByFIFO(item.Details, autoAssignStocks, outStockLockInfos, outboundOrder); DistributeLockQuantityByFIFO(item.Details, autoAssignStocks, stockAllocations, outStockLockInfos, outboundOrder); } locationInfos.AddRange(_locationInfoService.GetLocationInfos(outStocks.Select(x => x.LocationCode).Distinct().ToList())); @@ -105,52 +107,59 @@ } /// <summary> /// æå è¿å åºåååé é宿°éå°å个æç» /// æå è¿å åºåååé é宿°éå°å个æç» - ä¿®å¤çæ¬ /// </summary> private void DistributeLockQuantityByFIFO( List<Dt_OutboundOrderDetail> details, List<Dt_StockInfo> assignStocks, Dictionary<int, decimal> stockAllocations, List<Dt_OutStockLockInfo> outStockLockInfos, Dt_OutboundOrder outboundOrder) { // æå è¿å åºæåºåºåºåæç»ï¼å设å å建çæç»éè¦ä¼å æ»¡è¶³ï¼ var sortedDetails = details .OrderBy(x => x.Id) // æIDæåºï¼å设å å建çIDå° .Where(d => d.OrderQuantity - d.OverOutQuantity - d.LockQuantity > 0) // åªå¤çè¿éè¦åé çæ°é .OrderBy(x => x.Id) .ToList(); // æå è¿å åºæåºåºåï¼çäº§æ¥æææ©çä¼å ï¼ var sortedStockDetails = assignStocks if (!sortedDetails.Any()) return; // è·åææåé äºåºåçæç»ï¼æå è¿å åºæåº var allocatedStockDetails = assignStocks .SelectMany(x => x.Details) .Where(x => details.Any(d => d.MaterielCode == x.MaterielCode)) .Where(x => stockAllocations.ContainsKey(x.Id)) .OrderBy(x => x.ProductionDate) .ThenBy(x => x.StockId) .ToList(); // 为æ¯ä¸ªåºåæç»å建åé è®°å½ foreach (var stockDetail in sortedStockDetails) foreach (var stockDetail in allocatedStockDetails) { var stockInfo = assignStocks.First(x => x.Id == stockDetail.StockId); var allocatedQuantity = stockDetail.OutboundQuantity; // è¿ä¸ªåºåæç»åé çæ°é if (!stockAllocations.TryGetValue(stockDetail.Id, out decimal allocatedQuantity)) continue; if (allocatedQuantity <= 0) continue; // æé¡ºåºåé ç»å个åºåºåæç» var stockInfo = assignStocks.First(x => x.Id == stockDetail.StockId); decimal remainingAllocate = allocatedQuantity; // æé¡ºåºåé ç»å个åºåºåæç» foreach (var detail in sortedDetails) { if (remainingAllocate <= 0) break; // 计ç®è¿ä¸ªæç»è¿éè¦åé çæ°é var alreadyAssigned = outStockLockInfos .Where(x => x.OrderDetailId == detail.Id && x.StockId == stockInfo.Id) .Sum(x => x.AssignQuantity); var detailNeed = detail.OrderQuantity - detail.OverOutQuantity - detail.LockQuantity - alreadyAssigned; var detailNeed = detail.OrderQuantity - detail.OverOutQuantity - detail.LockQuantity; if (detailNeed <= 0) continue; // åé æ°é var assignQuantity = Math.Min(remainingAllocate, detailNeed); // éªè¯æ¡ç æ¯å¦åå¨ if (string.IsNullOrEmpty(stockDetail.Barcode)) { throw new Exception($"åºåæç»ID[{stockDetail.Id}]çæ¡ç 为空"); } // å建åºåºéå®ä¿¡æ¯ var lockInfo = _outStockLockInfoService.GetOutStockLockInfo( @@ -162,10 +171,32 @@ remainingAllocate -= assignQuantity; } // å¦æè¿æå©ä½åé æ°éï¼è¯´æé»è¾æè¯¯ // å¦æè¿æå©ä½åé æ°éï¼éæ°åé æè®°å½è¦å if (remainingAllocate > 0) { throw new Exception($"åºååé é»è¾é误ï¼å©ä½æªåé æ°éï¼{remainingAllocate}"); // éæ°åé ç»å ¶ä»éè¦åé çæç» foreach (var detail in sortedDetails) { if (remainingAllocate <= 0) break; var detailNeed = detail.OrderQuantity - detail.OverOutQuantity - detail.LockQuantity; if (detailNeed <= 0) continue; var assignQuantity = Math.Min(remainingAllocate, detailNeed); var lockInfo = _outStockLockInfoService.GetOutStockLockInfo( outboundOrder, detail, stockInfo, assignQuantity, stockDetail.Barcode); outStockLockInfos.Add(lockInfo); detail.LockQuantity += assignQuantity; remainingAllocate -= assignQuantity; } // å¦æè¿æå©ä½ï¼è®°å½è¦åä½ä¸æåºå¼å¸¸ if (remainingAllocate > 0) { _logger.LogWarning($"åºååé å仿å©ä½æ°éæªåé : {remainingAllocate}, æ¡ç : {stockDetail.Barcode}"); } } } } @@ -219,7 +250,7 @@ var (barcode, barcodeQuantity) = GetBarcodeForAllocation(barcodeAllocation, canAssign); var lockInfo = _outStockLockInfoService.GetOutStockLockInfo( outboundOrder, detail, stock, canAssign, barcode,null); outboundOrder, detail, stock, canAssign, barcode); outStockLockInfos.Add(lockInfo); availableAssign -= canAssign; ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_OutboundService/OutboundPickingService.cs
@@ -46,6 +46,47 @@ _splitPackageService = splitPackageService; } public async Task<WebResponseContent> ValidateBarcode(string barcode) { try { if (string.IsNullOrEmpty(barcode)) { return WebResponseContent.Instance.Error("æ¡ç ä¸è½ä¸ºç©º"); } // æ ¹æ®æ¡ç æ¥è¯¢åºåæç» var stockDetail = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>() .Includes(x => x.StockInfo) .Where(x => x.Barcode == barcode) .FirstAsync(); if (stockDetail == null) { return WebResponseContent.Instance.Error("æ¡ç ä¸åå¨"); } var result = new { Barcode = barcode, MaterielCode = stockDetail.MaterielCode, BatchNo = stockDetail.BatchNo, AvailableQuantity = stockDetail.StockQuantity - stockDetail.OutboundQuantity, LocationCode = stockDetail.StockInfo?.LocationCode, PalletCode = stockDetail.StockInfo?.PalletCode }; return WebResponseContent.Instance.OK(null, result); } catch (Exception ex) { return WebResponseContent.Instance.Error($"æ¡ç éªè¯å¤±è´¥: {ex.Message}"); } } /// <summary> /// æ«ç æ£é确认 - ç®åçæ¬ /// åªå¤çå®é æ£éçåºåæ£å ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_StockService/StockInfoService.cs
@@ -87,15 +87,25 @@ /// <param name="needQuantity"></param> /// <param name="residueQuantity"></param> /// <returns></returns> public List<Dt_StockInfo> GetOutboundStocks(List<Dt_StockInfo> stockInfos, string materielCode, decimal needQuantity, out decimal residueQuantity) public (List<Dt_StockInfo>, Dictionary<int, decimal>) GetOutboundStocks(List<Dt_StockInfo> stockInfos, string materielCode, decimal needQuantity, out decimal residueQuantity) { List<Dt_StockInfo> outStocks = new List<Dt_StockInfo>(); // æå è¿å åºæåºï¼ææ¡ç ççäº§æ¥æï¼ Dictionary<int, decimal> stockAllocations = new Dictionary<int, decimal>(); // è®°å½æ¯ä¸ªåºåæç»çåé æ°é // æå è¿å åºæåºææç¸å ³çåºåæç» var sortedStockDetails = stockInfos .SelectMany(x => x.Details) .Where(x => x.MaterielCode == materielCode && x.StockQuantity > x.OutboundQuantity) .OrderBy(x => x.ProductionDate).ThenBy(x => x.StockId) .Where(x => x.MaterielCode == materielCode && x.StockQuantity > x.OutboundQuantity) // æå¯ç¨åºå .OrderBy(x => x.ProductionDate) // æçäº§æ¥ææåºï¼å è¿å åº .ThenBy(x => x.StockId) // ç¸åçäº§æ¥ææåºåIDæåº .ToList(); if (!sortedStockDetails.Any()) { residueQuantity = needQuantity; return (outStocks, stockAllocations); } // è®¡ç®æ»å¯ç¨åºå var stockTotalQuantity = sortedStockDetails.Sum(x => x.StockQuantity - x.OutboundQuantity); @@ -103,6 +113,7 @@ if (stockTotalQuantity < needQuantity) { residueQuantity = needQuantity - stockTotalQuantity; // 䏿åºå¼å¸¸ï¼å 许é¨ååé } else { @@ -111,17 +122,22 @@ decimal remainingNeed = needQuantity; // ææ¡ç åé åºå // æå è¿å åºé¡ºåºåé åºå foreach (var detail in sortedStockDetails) { if (remainingNeed <= 0) break; decimal availableQuantity = detail.StockQuantity - detail.OutboundQuantity; if (availableQuantity <= 0) continue; decimal allocateQuantity = Math.Min(availableQuantity, remainingNeed); // æ´æ°åºåºæ°é detail.OutboundQuantity += allocateQuantity; remainingNeed -= allocateQuantity; // è®°å½åé æ°é stockAllocations[detail.Id] = allocateQuantity; // 妿è¿ä¸ªåºåè¿æ²¡æ·»å å°åºåºå表ä¸ï¼å°±æ·»å var stockInfo = stockInfos.First(x => x.Id == detail.StockId); @@ -132,8 +148,9 @@ } residueQuantity = remainingNeed; return outStocks; return (outStocks, stockAllocations); } /// <summary> /// æ ¹æ®æ¡ç è·ååºåä¿¡æ¯ /// </summary> ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/Basic/LocationInfoController.cs
@@ -45,12 +45,17 @@ public WebResponseContent TTTTTAssignLocation() { var sddd = Service.AssignLocation(); return WebResponseContent.Instance.OK("resdasd", sddd); } [HttpPost, Route("GetLocationTypes"), AllowAnonymous, MethodParamsValidate] public WebResponseContent GetLocationTypes() { var lists = Service.GetLocationTypes(); return WebResponseContent.Instance.OK("", lists); } } } ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/Basic/WarehouseController.cs
@@ -1,9 +1,15 @@ using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Newtonsoft.Json; using WIDESEA_Core; using WIDESEA_Core.Attributes; using WIDESEA_Core.BaseController; using WIDESEA_DTO.Basic; using WIDESEA_DTO.Inbound; using WIDESEA_IBasicService; using WIDESEA_Model.Models; using WIDESEA_WMSServer.Controllers.Inbound; namespace WIDESEA_WMSServer.Controllers.Basic { @@ -14,9 +20,34 @@ [ApiController] public class WarehouseController : ApiBaseController<IWarehouseService, Dt_Warehouse> { public WarehouseController(IWarehouseService service) : base(service) private readonly ILogger<WarehouseController> _logger; public WarehouseController(IWarehouseService service, ILogger<WarehouseController> logger) : base(service) { _logger = logger; } /// <summary> /// æ¥æ¶MES ä»åºä¿¡æ¯ /// </summary> /// <param name="model"></param> /// <returns></returns> [HttpPost, Route("ReceiveWarehouse"), AllowAnonymous, MethodParamsValidate] public async Task<WebResponseContent> ReceiveWarehouse([FromBody] List<WarehouseAreaDto> model) { if (model == null || !model.Any()) { return WebResponseContent.Instance.Error("ä»åºæ°æ®ä¸è½ä¸ºç©º"); } _logger.LogInformation("WarehouseController ReceiveWarehouse: " + JsonConvert.SerializeObject(model)); var content = await Service.ReceiveWarehouseArea(model); if (content.Status) return WebResponseContent.Instance.OK(200); else return WebResponseContent.Instance.Error(content.Message); } } } ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/Outbound/OutboundOrderController.cs
@@ -62,7 +62,7 @@ /// <summary> /// æ ¹æ®IDè·ååºåºå /// </summary>ss [HttpPost, Route("GetById"), AllowAnonymous, MethodParamsValidate] [HttpGet, Route("GetById"), AllowAnonymous, MethodParamsValidate] public async Task<WebResponseContent> GetById(int id) { var order = await Service.GetById(id); ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/Outbound/OutboundPickingController.cs
@@ -46,7 +46,14 @@ { return await Service.ConfirmPicking(request); } /// <summary> /// éªè¯æ¡ç å¹¶è·åç©æä¿¡æ¯ /// </summary> [HttpGet("ValidateBarcode")] public async Task<WebResponseContent> ValidateBarcode(string barcode) { return await Service.ValidateBarcode(barcode); } /// <summary> /// æå æä½ /// </summary>