ÏîÄ¿´úÂë/WIDESEA_WMSClient/src/extension/outbound/extend/Picking.vue
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,190 @@ <template> <div class="picking-operation"> <div class="operation-toolbar"> <el-button type="primary" @click="showPickingConfirm"> åæ£ç¡®è®¤ </el-button> <el-button type="warning" @click="showSplitDialog" :disabled="selectedRows.length !== 1" > æå </el-button> <el-button type="success" @click="batchDirectOutbound"> ç´æ¥åºåº </el-button> <el-button type="info" @click="batchReturnToWarehouse"> ååº </el-button> </div> <!-- åºåºè¯¦æ å表 --> <div class="lock-info-table"> <base-table ref="lockInfoTable" :table-config="tableConfig" :height="300" selection @selection-change="handleSelectionChange" /> </div> <!-- åæ£ç¡®è®¤å¼¹çª --> <el-dialog v-model="pickingConfirmVisible" title="åæ£ç¡®è®¤" width="90%" top="5vh" destroy-on-close > <picking-confirm v-if="pickingConfirmVisible" :order-no="orderDetail.OrderNo" @confirm="handlePickingConfirm" @close="pickingConfirmVisible = false" /> </el-dialog> <!-- æå å¼¹çª --> <el-dialog v-model="splitVisible" title="æå æä½" width="600px" destroy-on-close > <split-package v-if="splitVisible && selectedLockInfo" :lock-info="selectedLockInfo" @confirm="handleSplitConfirm" @close="splitVisible = false" /> </el-dialog> </div> </template> <script setup> import { ref, reactive } from 'vue' import { ElMessage, ElMessageBox } from 'element-plus' import BaseTable from '@/components/base/BaseTable.vue' import PickingConfirm from './PickingConfirm.vue' import SplitPackage from './SplitPackage.vue' const props = defineProps({ orderDetail: { type: Object, required: true } }) const emit = defineEmits(['close']) const lockInfoTable = ref() const pickingConfirmVisible = ref(false) const splitVisible = ref(false) const selectedRows = ref([]) const selectedLockInfo = ref(null) const tableConfig = reactive({ url: '/api/outbound/getOutStockLockInfo', query: { orderDetailId: props.orderDetail.Id }, columns: [ { type: 'selection', width: 55 }, { prop: 'BatchNo', label: 'æ¹æ¬¡å·', width: 120 }, { prop: 'MaterielCode', label: 'ç©ææ¡ç ', width: 150 }, { prop: 'AssignQuantity', label: 'åé æ°é', width: 100 }, { prop: 'PickedQty', label: 'å·²æ£æ°é', width: 100 }, { prop: 'LocationCode', label: 'åºä½ç¼å·', width: 120 }, { prop: 'PalletCode', label: 'æçç¼å·', width: 120 }, { prop: 'Status', label: 'ç¶æ', width: 100 } ] }) const handleSelectionChange = (selection) => { selectedRows.value = selection } const showPickingConfirm = () => { pickingConfirmVisible.value = true } const showSplitDialog = async () => { if (selectedRows.value.length !== 1) { ElMessage.warning('è¯·éæ©ä¸æ¡è¦æå çè®°å½') return } try { // è·åéä¸è®°å½ç详ç»ä¿¡æ¯ const result = await $http.get('/api/outbound/getLockInfoDetail', { params: { lockInfoId: selectedRows.value[0].Id } }) if (result.success) { selectedLockInfo.value = result.data splitVisible.value = true } else { ElMessage.error('è·åæå è®°å½è¯¦æ 失败') } } catch (error) { ElMessage.error('è·åæå è®°å½è¯¦æ 失败') } } const batchDirectOutbound = async () => { try { await ElMessageBox.confirm('ç¡®å®è¦å¯¹æ´ä¸ªè®¢åæ§è¡ç´æ¥åºåºåï¼', 'æç¤º', { type: 'warning' }) const result = await $http.post('/api/outbound/batchDirectOutbound', { orderNo: props.orderDetail.OrderNo }) if (result.success) { ElMessage.success('æ¹éç´æ¥åºåºæå') lockInfoTable.value.refresh() } else { ElMessage.error(result.message) } } catch (error) { if (error !== 'cancel') { ElMessage.error('æ¹éç´æ¥åºåºå¤±è´¥') } } } const batchReturnToWarehouse = async () => { try { await ElMessageBox.confirm('ç¡®å®è¦å¯¹æªæ£éè´§ç©æ§è¡ååºåï¼', 'æç¤º', { type: 'warning' }) const result = await $http.post('/api/outbound/batchReturnToWarehouse', { orderNo: props.orderDetail.OrderNo }) if (result.success) { ElMessage.success('æ¹éååºæå') lockInfoTable.value.refresh() } else { ElMessage.error(result.message) } } catch (error) { if (error !== 'cancel') { ElMessage.error('æ¹éååºå¤±è´¥') } } } const handlePickingConfirm = () => { pickingConfirmVisible.value = false lockInfoTable.value.refresh() } const handleSplitConfirm = () => { splitVisible.value = false selectedLockInfo.value = null lockInfoTable.value.refresh() } </script> ÏîÄ¿´úÂë/WIDESEA_WMSClient/src/extension/outbound/extend/PickingConfirm.vue
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,294 @@ <template> <div class="picking-confirm"> <div class="scan-section"> <el-alert title="è¯·ä½¿ç¨æ«ç æªæ«ææçç åç©ææ¡ç ï¼æ«ç æªå¸¦å车åè½ï¼æ«å®ç©ææ¡ç èªå¨ç¡®è®¤" type="info" :closable="false" class="scan-alert" /> <el-form :model="scanForm" label-width="100px" class="scan-form"> <el-form-item label="æçç " required> <el-input ref="palletInput" v-model="scanForm.palletCode" placeholder="è¯·æ«ææçç " @keyup.enter="handlePalletScan" @blur="loadPalletSummary" clearable /> </el-form-item> <el-form-item label="ç©ææ¡ç " required> <el-input ref="materialInput" v-model="scanForm.materialBarcode" placeholder="è¯·æ«æç©ææ¡ç " :disabled="!scanForm.palletCode" @keyup.enter="handleMaterialScan" clearable /> </el-form-item> </el-form> <!-- æçæ£è´§ç»è®¡ --> <div v-if="palletSummary" class="pallet-summary"> <el-card header="æçæ£è´§ç»è®¡"> <el-descriptions :column="3" border> <el-descriptions-item label="æçå·"> {{ scanForm.palletCode }} </el-descriptions-item> <el-descriptions-item label="æªæ£è´§æ¡æ°"> <el-text type="warning">{{ palletSummary.unpickedCount }}</el-text> </el-descriptions-item> <el-descriptions-item label="æªæ£è´§æ»æ°"> <el-text type="danger">{{ palletSummary.unpickedTotal }}</el-text> </el-descriptions-item> </el-descriptions> </el-card> </div> <div class="action-buttons"> <el-button type="primary" @click="handleConfirm" :loading="confirmLoading"> æå¨ç¡®è®¤ </el-button> <el-button @click="handleReset">éç½®</el-button> <el-button @click="$emit('close')">åæ¶</el-button> </div> </div> <!-- å·²åæ£è®°å½å表 --> <div class="picked-records"> <el-card header="å·²åæ£è®°å½"> <base-table ref="pickedTable" :table-config="pickedTableConfig" :height="300" /> </el-card> </div> </div> </template> <script setup> import { ref, reactive, onMounted, nextTick } from 'vue' import { ElMessage } from 'element-plus' import BaseTable from '@/components/base/BaseTable.vue' const props = defineProps({ orderNo: { type: String, required: true } }) const emit = defineEmits(['confirm', 'close']) const palletInput = ref() const materialInput = ref() const pickedTable = ref() const scanForm = reactive({ palletCode: '', materialBarcode: '' }) const palletSummary = ref(null) const confirmLoading = ref(false) const pickedTableConfig = reactive({ url: '/api/outbound/getPickingRecords', query: { orderNo: props.orderNo }, columns: [ { prop: 'TaskNo', label: 'ä»»å¡å·', width: 150 }, { prop: 'Barcode', label: 'ç©ææ¡ç ', width: 150 }, { prop: 'MaterielName', label: 'ç©æåç§°', width: 150 }, { prop: 'PickQuantity', label: 'æ£è´§æ°é', width: 100 }, { prop: 'LocationCode', label: 'è´§ä½', width: 120 }, { prop: 'CreateTime', label: 'æ£è´§æ¶é´', width: 180 } ] }) onMounted(() => { nextTick(() => { if (palletInput.value) { palletInput.value.focus() } }) }) const loadOrderInfo = async () => { const orderId = route.query.orderId if (!orderId) return try { const response = await http.get(`/api/OutboundOrder/GetById?id=${orderId}`) if (response.status) { orderInfo.value = response.data } } catch (error) { ElMessage.error('å è½½åºåºåä¿¡æ¯å¤±è´¥') } } const handlePalletScan = async () => { if (scanForm.palletCode) { ElMessage.success(`å·²æ«ææç: ${scanForm.palletCode}`) await loadPalletSummary() nextTick(() => { if (materialInput.value) { materialInput.value.focus() } }) } } const handleMaterialScan = async () => { if (!scanForm.palletCode) { ElMessage.warning('è¯·å æ«ææçç ') palletInput.value.focus() return } if (!scanForm.materialBarcode) { ElMessage.warning('è¯·æ«æç©ææ¡ç ') return } await executePickingConfirm() } const loadPalletSummary = async () => { if (!scanForm.palletCode) { palletSummary.value = null return } try { const result = await $http.get('/api/outbound/getPalletPickingSummary', { params: { orderNo: props.orderNo, palletCode: scanForm.palletCode } }) if (result.success) { // å¤çç»è®¡ä¿¡æ¯ const summary = result.data const assigned = summary.find(x => x.Status === 'å·²åé ') || { TotalAssignQty: 0, TotalPickedQty: 0 } const picked = summary.find(x => x.Status === 'å·²æ£é') || { TotalPickedQty: 0 } palletSummary.value = { unpickedCount: assigned.TotalAssignQty > 0 ? 1 : 0, // ç®åè®¡ç® unpickedTotal: assigned.TotalAssignQty - assigned.TotalPickedQty } } } catch (error) { console.error('å è½½æçç»è®¡å¤±è´¥:', error) } } const handleConfirm = async () => { if (!scanForm.palletCode || !scanForm.materialBarcode) { ElMessage.warning('请填å宿´çæ«ç ä¿¡æ¯') return } await executePickingConfirm() } const executePickingConfirm = async () => { confirmLoading.value = true try { // å æ¾å°å¯¹åºçåºåºéå®ä¿¡æ¯ const lockInfoResult = await $http.get('/api/outbound/getOutStockLockInfo', { params: { orderNo: props.orderNo, palletCode: scanForm.palletCode, materialBarcode: scanForm.materialBarcode } }) if (!lockInfoResult.success || !lockInfoResult.data || lockInfoResult.data.length === 0) { ElMessage.error('æªæ¾å°å¯¹åºçåºåºéå®ä¿¡æ¯') return } const lockInfo = lockInfoResult.data[0] const request = { outStockLockId: lockInfo.Id, taskNo: `TASK_${Date.now()}`, palletCode: scanForm.palletCode, materialBarcode: scanForm.materialBarcode, locationCode: lockInfo.LocationCode } const result = await $http.post('/api/outbound/pickingConfirm', request) if (result.success) { ElMessage.success('åæ£ç¡®è®¤æå') handleReset() emit('confirm') // å·æ°å·²åæ£è®°å½ if (pickedTable.value) { pickedTable.value.refresh() } // éæ°å è½½æçç»è®¡ await loadPalletSummary() } else { ElMessage.error(result.message) } } catch (error) { ElMessage.error('åæ£ç¡®è®¤å¤±è´¥') } finally { confirmLoading.value = false } } const handleReset = () => { scanForm.materialBarcode = '' nextTick(() => { if (materialInput.value) { materialInput.value.focus() } }) } </script> <style scoped> .picking-confirm { display: flex; flex-direction: column; height: 70vh; } .scan-section { flex-shrink: 0; margin-bottom: 16px; } .scan-alert { margin-bottom: 16px; } .scan-form { max-width: 500px; } .pallet-summary { margin: 16px 0; } .action-buttons { margin-top: 16px; } .picked-records { flex: 1; min-height: 300px; } </style> ÏîÄ¿´úÂë/WIDESEA_WMSClient/src/extension/outbound/extend/SplitPackage.vue
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,176 @@ <template> <div class="split-package"> <el-alert title="æå æä½å°æéä¸çç©æå åæä¸¤ä¸ªå ï¼ç³»ç»ä¼èªå¨çææ°æ¡ç " type="info" :closable="false" class="split-alert" /> <!-- åç©æä¿¡æ¯å±ç¤º --> <el-card header="åç©æä¿¡æ¯" class="original-info"> <el-descriptions :column="2" border> <el-descriptions-item label="æ§æ¡ç "> <el-text type="primary">{{ lockInfo.MaterielCode }}</el-text> </el-descriptions-item> <el-descriptions-item label="ç©æåç§°"> {{ lockInfo.MaterielName }} </el-descriptions-item> <el-descriptions-item label="æ¹æ¬¡å·"> {{ lockInfo.BatchNo }} </el-descriptions-item> <el-descriptions-item label="æçç¼å·"> {{ lockInfo.PalletCode }} </el-descriptions-item> <el-descriptions-item label="åºä½ç¼å·"> {{ lockInfo.LocationCode }} </el-descriptions-item> <el-descriptions-item label="ä»»å¡å·"> {{ taskNo }} </el-descriptions-item> <el-descriptions-item label="åé æ°é"> <el-text type="info">{{ lockInfo.AssignQuantity }}</el-text> </el-descriptions-item> <el-descriptions-item label="å·²æ£æ°é"> <el-text type="warning">{{ lockInfo.PickedQty }}</el-text> </el-descriptions-item> <el-descriptions-item label="å¯æå æ°é"> <el-text type="success">{{ availableQuantity }}</el-text> </el-descriptions-item> </el-descriptions> </el-card> <!-- æå ä¿¡æ¯è¾å ¥ --> <el-card header="æå ä¿¡æ¯" class="split-info"> <el-form :model="splitForm" label-width="120px"> <el-form-item label="æå æ°é" required> <el-input-number v-model="splitForm.splitQuantity" :min="1" :max="availableQuantity" :precision="2" placeholder="请è¾å ¥æå æ°é" style="width: 200px" /> <div class="form-tips"> å¯æå æ°é: {{ availableQuantity }} {{ lockInfo.Unit }} </div> </el-form-item> <el-form-item label="æ°æ¡ç " v-if="newBarcode"> <el-text type="success">{{ newBarcode }}</el-text> <div class="form-tips">ç³»ç»èªå¨çæçæ°æ¡ç </div> </el-form-item> </el-form> </el-card> <div class="action-buttons"> <el-button type="primary" @click="handleConfirm" :loading="confirmLoading" :disabled="!splitForm.splitQuantity" > 确认æå </el-button> <el-button @click="$emit('close')">åæ¶</el-button> </div> </div> </template> <script setup> import { ref, reactive, computed } from 'vue' import { ElMessage } from 'element-plus' const props = defineProps({ lockInfo: { type: Object, required: true } }) const emit = defineEmits(['confirm', 'close']) const splitForm = reactive({ splitQuantity: 1 }) const confirmLoading = ref(false) const newBarcode = ref('') const taskNo = ref(`SPLIT_${Date.now()}`) // 计ç®å¯æå æ°é const availableQuantity = computed(() => { return props.lockInfo.AssignQuantity - props.lockInfo.PickedQty }) const handleConfirm = async () => { if (!splitForm.splitQuantity || splitForm.splitQuantity <= 0) { ElMessage.warning('请è¾å ¥ææçæå æ°é') return } if (splitForm.splitQuantity >= availableQuantity.value) { ElMessage.warning('æå æ°éå¿ é¡»å°äºå¯æå æ°é') return } confirmLoading.value = true try { const request = { lockInfoId: props.lockInfo.Id, taskNo: taskNo.value, splitQuantity: splitForm.splitQuantity } const result = await $http.post('/api/outbound/splitPackage', request) if (result.success) { newBarcode.value = result.data?.newBarcode || 'çææå' ElMessage.success(`æå æä½æåï¼æ°æ¡ç : ${newBarcode.value}`) // å»¶è¿å ³éï¼è®©ç¨æ·çå°æ°æ¡ç setTimeout(() => { emit('confirm') }, 2000) } else { ElMessage.error(result.message) } } catch (error) { ElMessage.error('æå æä½å¤±è´¥') } finally { confirmLoading.value = false } } </script> <style scoped> .split-package { max-height: 70vh; overflow-y: auto; } .split-alert { margin-bottom: 16px; } .original-info { margin-bottom: 16px; } .split-info { margin-bottom: 16px; } .form-tips { font-size: 12px; color: #909399; margin-top: 4px; } .action-buttons { text-align: center; margin-top: 20px; } </style> ÏîÄ¿´úÂë/WIDESEA_WMSClient/src/extension/outbound/extend/outOrderDetail.vue
@@ -329,7 +329,7 @@ handleOpenPicking() { this.$router.push({ path: '/outbound/picking', query: { orderId: this.row.id } query: { orderId: this.row.id ,orderNo:this.row.orderNo} }) }, outbound() { ÏîÄ¿´úÂë/WIDESEA_WMSClient/src/extension/outbound/outboundOrder.js
@@ -18,7 +18,7 @@ }, tableAction: '', //æå®æå¼ 表çæé(è¿éå¡«å表å,é»è®¤ä¸ç¨å¡«å) buttons: { view: [ { /* { name: 'åºåº', type: 'primary', value: 'åºåº', @@ -42,7 +42,7 @@ createDate: selectedRows[0].createDate || new Date().toLocaleDateString() // åºåºæ¥æ }); } }, }, */ { name: '空æçåºåº', type: 'primary', ÏîÄ¿´úÂë/WIDESEA_WMSClient/src/router/viewGird.js
@@ -76,7 +76,7 @@ }, { path: '/outbound/picking', name: 'PickingConfirm', name: 'PickingConfirm', component: () => import('@/views/outbound/PickingConfirm.vue'), meta: { title: 'æ£é确认', keepAlive: false } },{ ÏîÄ¿´úÂë/WIDESEA_WMSClient/src/views/outbound/PickingConfirm.vue
@@ -3,516 +3,375 @@ <div class="page-header"> <el-page-header @back="goBack"> <template #content> <span class="title">åºåºæ£é确认 - {{ orderInfo.orderNo }}</span> <span class="title">åºåºæ£é确认 - {{ this.$route.query.orderNo }}</span> </template> </el-page-header> </div> <el-row :gutter="20" class="main-content"> <el-col :span="8"> <div class="content-layout"> <!-- å·¦ä¾§ï¼æ«ç åºå --> <div class="left-section"> <div class="scan-section"> <el-card header="æ«ç åºå"> <el-form label-width="100px" size="small"> <el-form-item label="æçæ¡ç "> <el-input v-model="scanForm.palletCode" placeholder="æ«ææè¾å ¥æçæ¡ç " @keyup.enter="handlePalletScan" clearable > <template #append> <el-button @click="handlePalletScan">确认</el-button> </template> </el-input> </el-form-item> <el-alert title="è¯·ä½¿ç¨æ«ç æªæ«ææçç åç©ææ¡ç ï¼æ«ç æªå¸¦å车åè½ï¼æ«å®ç©ææ¡ç èªå¨ç¡®è®¤" type="info" :closable="false" class="scan-alert" /> <el-form-item label="ç©ææ¡ç "> <el-input v-model="scanForm.barcode" placeholder="æ«ææè¾å ¥ç©ææ¡ç " @keyup.enter="handleBarcodeScan" :disabled="!currentPallet" clearable > <template #append> <el-button @click="handleBarcodeScan" :disabled="!currentPallet">确认</el-button> </template> </el-input> </el-form-item> <el-form :model="scanForm" label-width="100px" class="scan-form"> <el-form-item label="æçç " required> <el-input ref="palletInput" v-model="scanForm.palletCode" placeholder="è¯·æ«ææçç " @keyup.enter="handlePalletScan" @blur="loadPalletSummary" clearable /> </el-form-item> <el-form-item label="æ£éæ°é"> <el-input-number v-model="scanForm.quantity" :min="1" :max="maxPickQuantity" :disabled="!currentLockInfo" /> </el-form-item> <el-form-item label="ç©ææ¡ç " required> <el-input ref="materialInput" v-model="scanForm.materialBarcode" placeholder="è¯·æ«æç©ææ¡ç " :disabled="!scanForm.palletCode" @keyup.enter="handleMaterialScan" clearable /> </el-form-item> </el-form> <!-- ç©æä¿¡æ¯æ¾ç¤º --> <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"> <p>å½åæç: {{ currentPallet.palletCode }}</p> <p>è´§ä½: {{ currentPallet.locationCode }}</p> <p>ç¶æ: {{ currentPallet.statusText }}</p> </div> </el-card> <!-- æçæ£è´§ç»è®¡ --> <div v-if="palletSummary" class="pallet-summary"> <el-card header="æçæ£è´§ç»è®¡"> <el-descriptions :column="3" border> <el-descriptions-item label="æçå·"> {{ scanForm.palletCode }} </el-descriptions-item> <el-descriptions-item label="æªæ£è´§æ¡æ°"> <el-text type="warning">{{ palletSummary.unpickedCount }}</el-text> </el-descriptions-item> <el-descriptions-item label="æªæ£è´§æ»æ°"> <el-text type="danger">{{ palletSummary.unpickedTotal }}</el-text> </el-descriptions-item> </el-descriptions> </el-card> </div> <div class="action-buttons"> <el-button type="warning" @click="handleBackToStock" :disabled="!currentPallet" style="margin-bottom: 10px;" > ååº <el-button type="primary" @click="handleConfirm" :loading="confirmLoading"> æå¨ç¡®è®¤ </el-button> <el-button type="success" @click="handleDirectOutbound" :disabled="!currentPallet" style="margin-bottom: 10px;" > ç´æ¥åºåº </el-button> <el-button type="primary" @click="handleOpenSplit" :disabled="!currentLockInfo" > æå </el-button> <el-button @click="handleReset">éç½®</el-button> <el-button @click="$emit('close')">åæ¶</el-button> </div> </div> </el-col> </div> <el-col :span="16"> <el-card header="æ£éç»æ"> <div class="summary-info"> <el-alert :title="`æªæ£è´§: ${unpickedCount} æ¡, ${unpickedQuantity} 个`" type="warning" :closable="false" /> </div> <!-- å³ä¾§ï¼åºåºè¯¦æ å表 --> <div class="right-section"> <el-card class="outbound-details-card" header="åºåºè¯¦æ "> <vol-table :data="pickedList" :columns="pickedColumns" :pagination="false" :height="400" > <template #action="{ row }"> <el-button type="text" @click="handleCancelPick(row)">æ¤é</el-button> </template> </vol-table> ref="outboundTable" :table-config="outboundTableConfig" :height="300" /> </el-card> </el-col> </el-row> </div> </div> <!-- æå å¼¹çª --> <vol-box v-model="splitVisible" title="æå æä½" :width="600" :height="500" > <SplitPackageModal v-if="splitVisible" :lockInfo="currentLockInfo" @success="handleSplitSuccess" @close="splitVisible = false" /> </vol-box> <!-- å·²åæ£è®°å½å表 --> <div class="picked-records"> <el-card header="å·²åæ£è®°å½"> <vol-table ref="pickedTable" :table-config="pickedTableConfig" :height="300" /> </el-card> </div> </div> </template> <script> import SplitPackageModal from './SplitPackageModal.vue' import http from '@/api/http.js' import { ref, defineComponent } from "vue"; import { ElMessage } from "element-plus"; import { useRoute } from 'vue-router' export default { components: { SplitPackageModal }, export default defineComponent({ name: 'PickingConfirm', components: { }, props: { orderNo: { type: String, required: true } }, emits: ['confirm', 'close'], data() { return { orderInfo: {}, scanForm: { palletCode: '', barcode: '', quantity: 1 materialBarcode: '' }, currentPallet: null, currentLockInfo: null, currentMaterialInfo: null, // æ°å¢ï¼å½åç©æä¿¡æ¯ pickedList: [], pickedColumns: [ { field: 'barcode', title: 'ç©ææ¡ç ', width: 150 }, { field: 'materielCode', title: 'ç©æç¼ç ', width: 120 }, { field: 'materielName', title: 'ç©æåç§°', width: 150 }, { field: 'pickQuantity', title: 'æ£éæ°é', width: 100 }, { field: 'palletCode', title: 'æçç¼å·', width: 120 }, { field: 'pickTime', title: 'æ£éæ¶é´', width: 160 }, { field: 'operator', title: 'æä½äºº', width: 100 }, { field: 'action', title: 'æä½', width: 80, slot: true } ], splitVisible: false, maxPickQuantity: 0, allLockInfos: [] // æ°å¢ï¼ä¿åææéå®ä¿¡æ¯ï¼ç¨äºæ¡ç å¹é } }, computed: { unpickedCount() { return this.orderInfo.unpickedCount || 0 }, unpickedQuantity() { return this.orderInfo.unpickedQuantity || 0 } }, methods: { goBack() { this.$router.back() }, async loadOrderInfo() { const orderId = this.$route.query.orderId if (!orderId) return try { const result = await this.http.get(`api/OutboundOrder/GetById?id=${orderId}`) if (result.status) { this.orderInfo = result.data } } catch (error) { this.$message.error('å è½½åºåºåä¿¡æ¯å¤±è´¥') } }, async handlePalletScan() { if (!this.scanForm.palletCode) { this.$message.warning('请è¾å ¥æçæ¡ç ') return } try { const result = await this.http.get( `api/OutboundPicking/GetPalletOutboundStatus?palletCode=${this.scanForm.palletCode}` ) if (result.status) { this.currentPallet = result.data await this.loadPalletLockInfo() this.$message.success(`æç ${this.scanForm.palletCode} è¯å«æå`) } else { this.$message.error(result.message) } } catch (error) { this.$message.error('æçè¯å«å¤±è´¥') } }, async loadPalletLockInfo() { if (!this.currentPallet) return try { const result = await this.http.get( `api/OutboundPicking/GetPalletLockInfos?palletCode=${this.currentPallet.palletCode}` ) if (result.status) { 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, materielCode: materialInfo.materielCode, // ä¼ éç©æç¼ç pickQuantity: this.scanForm.quantity, locationCode: this.currentPallet.locationCode, palletCode: this.currentPallet.palletCode, 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.currentMaterialInfo = null // å·æ°æ°æ® this.loadOrderInfo() this.loadPickedHistory() this.loadPalletLockInfo() } else { this.$message.error(result.message) } } catch (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 } }, async handleBackToStock() { if (!this.currentPallet) return try { await this.$confirm(`ç¡®å®å°æç ${this.currentPallet.palletCode} ååºåï¼`, 'æç¤º', { type: 'warning' }) const result = await this.http.post('api/BackToStock/GenerateBackToStockTask', { palletCode: this.currentPallet.palletCode, currentLocation: 'æ£éä½', operator: 'å½åç¨æ·' }) if (result.status) { this.$message.success('ååºä»»å¡å·²çæ') this.resetCurrentPallet() } } catch (error) { // ç¨æ·åæ¶ } }, async handleDirectOutbound() { if (!this.currentPallet) return try { await this.$confirm(`ç¡®å®å°æç ${this.currentPallet.palletCode} ç´æ¥åºåºåï¼`, 'æç¤º', { type: 'warning' }) const result = await this.http.post('api/OutboundPicking/DirectOutbound', { palletCode: this.currentPallet.palletCode }) if (result.status) { this.$message.success('ç´æ¥åºåºæå') this.resetCurrentPallet() this.loadOrderInfo() } } catch (error) { // ç¨æ·åæ¶ } }, handleOpenSplit() { if (!this.currentLockInfo) { this.$message.warning('请å éæ©éå®ä¿¡æ¯') return } this.splitVisible = true }, handleSplitSuccess() { this.$message.success('æå æå') this.loadPalletLockInfo() }, resetCurrentPallet() { this.currentPallet = null this.currentLockInfo = null this.currentMaterialInfo = null this.allLockInfos = [] this.scanForm.palletCode = '' }, async loadPickedHistory() { const orderId = this.$route.query.orderId if (!orderId) return try { const result = await this.http.get(`api/OutboundPicking/GetPickingHistory?orderId=${orderId}`) if (result.status) { this.pickedList = result.data } } catch (error) { console.error('å è½½æ£éåå²å¤±è´¥:', error) } }, async handleCancelPick(row) { try { await this.$confirm('ç¡®å®æ¤éè¿æ¡æ£éè®°å½åï¼', 'æç¤º', { type: 'warning' }) const result = await this.http.post('api/OutboundPicking/CancelPicking', { pickingHistoryId: row.id }) if (result.status) { this.$message.success('æ¤éæå') this.loadPickedHistory() this.loadOrderInfo() } } catch (error) { // ç¨æ·åæ¶ } palletSummary: null, confirmLoading: false, pickedTableConfig: { url: '/api/outbound/getPickingRecords', query: { orderNo: this.orderNo }, columns: [ { prop: 'TaskNo', label: 'ä»»å¡å·', width: 150 }, { prop: 'Barcode', label: 'ç©ææ¡ç ', width: 150 }, { prop: 'MaterielName', label: 'ç©æåç§°', width: 150 }, { prop: 'PickQuantity', label: 'æ£è´§æ°é', width: 100 }, { prop: 'LocationCode', label: 'è´§ä½', width: 120 }, { prop: 'CreateTime', label: 'æ£è´§æ¶é´', width: 180 } ] }, // åºåºè¯¦æ è¡¨æ ¼é ç½® outboundTableConfig: { url: '/api/outbound/getOutboundDetails', query: { orderNo: this.orderNo }, columns: [ { prop: 'OrderNo', label: 'åºåºåå·', width: 150 }, { prop: 'MaterialCode', label: 'ç©æç¼å·', width: 120 }, { prop: 'MaterialBarcode', label: 'ç©ææ¡ç ', width: 150 }, { prop: 'BatchNo', label: 'æ¹æ¬¡å·', width: 120 }, { prop: 'AssignQuantity', label: 'åé åºåºé', width: 100 }, { prop: 'PalletCode', label: 'æçç¼å·', width: 120 }, { prop: 'Unit', label: 'åä½', width: 80 } ] }, orderInfo: {orderNo:''} } }, mounted() { this.loadOrderInfo() this.loadPickedHistory() this.loadOrderInfo(); this.$nextTick(() => { if (this.$refs.palletInput) { this.$refs.palletInput.focus() } }) }, methods: { loadOrderInfo() { const orderId = this.$route.query.orderId if (!orderId) return try { this.http.get(`/api/OutboundOrder/GetById?id=${orderId}`).then(response => {debugger; if (response.status) { this.orderInfo = response.data } }) } catch (error) { ElMessage.error('å è½½åºåºåä¿¡æ¯å¤±è´¥') } }, goBack() { this.$router.back() }, async handlePalletScan() { if (this.scanForm.palletCode) { ElMessage.success(`å·²æ«ææç: ${this.scanForm.palletCode}`) await this.loadPalletSummary() this.$nextTick(() => { if (this.$refs.materialInput) { this.$refs.materialInput.focus() } }) } }, async handleMaterialScan() { if (!this.scanForm.palletCode) { ElMessage.warning('è¯·å æ«ææçç ') this.$refs.palletInput.focus() return } if (!this.scanForm.materialBarcode) { ElMessage.warning('è¯·æ«æç©ææ¡ç ') return } await this.executePickingConfirm() }, async loadPalletSummary() { if (!this.scanForm.palletCode) { this.palletSummary = null return } try { const result = await http.get('/api/outbound/getPalletPickingSummary', { params: { orderNo: this.orderNo, palletCode: this.scanForm.palletCode } }) if (result.success) { // å¤çç»è®¡ä¿¡æ¯ const summary = result.data const assigned = summary.find(x => x.Status === 'å·²åé ') || { TotalAssignQty: 0, TotalPickedQty: 0 } const picked = summary.find(x => x.Status === 'å·²æ£é') || { TotalPickedQty: 0 } this.palletSummary = { unpickedCount: assigned.TotalAssignQty > 0 ? 1 : 0, // ç®åè®¡ç® unpickedTotal: assigned.TotalAssignQty - assigned.TotalPickedQty } } } catch (error) { console.error('å è½½æçç»è®¡å¤±è´¥:', error) } }, async handleConfirm() { if (!this.scanForm.palletCode || !this.scanForm.materialBarcode) { ElMessage.warning('请填å宿´çæ«ç ä¿¡æ¯') return } await this.executePickingConfirm() }, async executePickingConfirm() { this.confirmLoading = true try { // å æ¾å°å¯¹åºçåºåºéå®ä¿¡æ¯ const lockInfoResult = await this.http.get('/api/outbound/getOutStockLockInfo', { params: { orderNo: this.orderNo, palletCode: this.scanForm.palletCode, materialBarcode: this.scanForm.materialBarcode } }) if (!lockInfoResult.success || !lockInfoResult.data || lockInfoResult.data.length === 0) { ElMessage.error('æªæ¾å°å¯¹åºçåºåºéå®ä¿¡æ¯') return } const lockInfo = lockInfoResult.data[0] const request = { outStockLockId: lockInfo.Id, taskNo: `TASK_${Date.now()}`, palletCode: this.scanForm.palletCode, materialBarcode: this.scanForm.materialBarcode, locationCode: lockInfo.LocationCode } const result = await this.http.post('/api/outbound/pickingConfirm', request) if (result.success) { ElMessage.success('åæ£ç¡®è®¤æå') this.handleReset() this.$emit('confirm') // å·æ°è¡¨æ ¼ if (this.$refs.pickedTable) { this.$refs.pickedTable.refresh() } // å·æ°åºåºè¯¦æ è¡¨æ ¼ if (this.$refs.outboundTable) { this.$refs.outboundTable.refresh() } // éæ°å è½½æçç»è®¡ await this.loadPalletSummary() } else { ElMessage.error(result.ElMessage) } } catch (error) { ElMessage.error('åæ£ç¡®è®¤å¤±è´¥') } finally { this.confirmLoading = false } }, handleReset() { this.scanForm.materialBarcode = '' this.$nextTick(() => { if (this.$refs.materialInput) { this.$refs.materialInput.focus() } }) } } } }) </script> <style scoped> .picking-confirm { padding: 20px; display: flex; flex-direction: column; height: 70vh; } .page-header { margin-bottom: 20px; .content-layout { display: flex; gap: 16px; margin-bottom: 16px; flex: 1; min-height: 0; /* éè¦ï¼é²æ¢flexåå ç´ æº¢åº */ } .title { font-size: 18px; font-weight: bold; .left-section { flex: 1; display: flex; flex-direction: column; } .right-section { flex: 1; display: flex; flex-direction: column; } .scan-section { margin-bottom: 20px; flex-shrink: 0; } .scan-alert { margin-bottom: 16px; } .scan-form { max-width: 500px; } .pallet-summary { margin: 16px 0; } .action-buttons { margin-top: 16px; } .outbound-details-card { height: 100%; display: flex; flex-direction: column; gap: 10px; } .action-buttons .el-button { width: 100%; .outbound-details-card :deep(.el-card__body) { flex: 1; padding: 0; } .current-info { margin-top: 15px; padding: 10px; background-color: #f5f7fa; border-radius: 4px; .picked-records { flex-shrink: 0; height: 300px; } .current-info p { margin: 5px 0; font-size: 14px; } .summary-info { margin-bottom: 15px; .picked-records :deep(.el-card__body) { padding: 0; } </style> ÏîÄ¿´úÂë/WIDESEA_WMSClient/vue.config.js
@@ -1,4 +1,3 @@ // const webpack = require("webpack"); module.exports = { productionSourceMap: false, ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_BasicService/WarehouseService.cs
@@ -89,17 +89,28 @@ 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) if (item.IsDelete == 1) { dbfirst.Code = item.Code; dbfirst.Name = item.Name; dbfirst.FactoryArea = item.FactoryArea; _warehouseArearepository.UpdateData(dbfirst); var first= _warehouseArearepository.Db.Queryable<Dt_WarehouseArea>().First(x => x.Code == item.Code); if(first != null) { _warehouseArearepository.DeleteData(first); } } else { _warehouseArearepository.AddData(new Dt_WarehouseArea { Code=item.Code,Name=item.Name,FactoryArea=item.FactoryArea}); 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/SupplierDTO.cs
@@ -70,7 +70,7 @@ /// åºåç»ç» /// </summary> [PropertyValidate("åºåç»ç»", NotNullAndEmpty = true)] public string InvOrgId { get; set; } = "æ·®å®ç¹åäºå"; public string InvOrgId { get; set; } = ""; /// <summary> /// æä½ç±»å ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_DTO/Outbound/OutboundOrderGetDTO.cs
@@ -4,6 +4,7 @@ using System.Linq; using System.Text; using System.Threading.Tasks; using WIDESEA_Model.Models; namespace WIDESEA_DTO.Outbound { @@ -22,7 +23,12 @@ public decimal SplitQuantity { get; set; } public string Operator { get; set; } } public class ConfirmPickingDto { public string OrderNo { get; set; } public string PalletCode { get; set; } public string Barcode { get; set; } } public class PickingConfirmRequest { @@ -115,7 +121,11 @@ public string CurrentBarcode { get; set; } = string.Empty; public decimal AssignQuantity { get; set; } } public class LockInfoDetailDto : Dt_OutStockLockInfo { public string MaterielName { get; set; } public string Unit { get; set; } } public class MaterielBarcodeValidateOutput : OutputDto { public bool IsValid { get; set; } @@ -213,4 +223,24 @@ public decimal pickQuantity { get; set; } public string pickTime { get; set; } = string.Empty; } public class CancelPickingDto { public string OrderNo { get; set; } public string PalletCode { get; set; } public string Barcode { get; set; } } public class SplitPackageDto { public string OrderNo { get; set; } public string PalletCode { get; set; } public string OriginalBarcode { get; set; } public decimal SplitQuantity { get; set; } } public class RevertSplitDto { public string OriginalBarcode { get; set; } } } ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_IOutboundService/IOutStockLockInfoService.cs
@@ -8,6 +8,7 @@ using WIDESEA_Core.BaseRepository; using WIDESEA_Core.BaseServices; using WIDESEA_Core.Enums; using WIDESEA_DTO.Outbound; using WIDESEA_Model.Models; namespace WIDESEA_IOutboundService @@ -21,8 +22,8 @@ Task<List<Dt_OutStockLockInfo>> GetByOrderDetailId(int orderDetailId); Task<List<Dt_OutStockLockInfo>> GetByPalletCode(string palletCode, int? status = null); Task<LockInfoDetailDto> GetLockInfoDetail(int lockInfoId); 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
@@ -16,9 +16,17 @@ IRepository<Dt_PickingRecord> Repository { get; } Task<WebResponseContent> CancelPicking(CancelPickingRequest request); Task<WebResponseContent> CancelPicking(string orderNo, string palletCode, string barcode); Task<WebResponseContent> ConfirmPicking(PickingConfirmRequest request); Task<List<Dt_PickingRecord>> GetPickingHistory(int orderId); Task<WebResponseContent> ValidateBarcode(string barcode); Task<WebResponseContent> ConfirmPicking(string orderNo, string palletCode, string barcode); Task<WebResponseContent> DirectOutbound(DirectOutboundRequest request); Task<List<OutStockLockListResp>> GetOutStockLockListAsync(string orderNo); Task<WebResponseContent> GetPalletOutboundStatus(string palletCode); Task GetPalletPickingSummary(string orderNo, string palletCode); Task<List<Dt_OutStockLockInfo>> GetPickedList(string orderNo, string palletCode); Task<List<Dt_PickingRecord>> GetPickingHistory(int orderId); Task<object> GetPickingSummary(string orderNo); Task<List<Dt_OutStockLockInfo>> GetUnpickedList(string orderNo, string palletCode); Task<WebResponseContent> ValidateBarcode(string barcode); } } ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_IOutboundService/ISplitPackageService.cs
@@ -15,6 +15,11 @@ { IRepository<Dt_SplitPackageRecord> Repository { get; } Task<WebResponseContent> SplitPackage(SplitPackageRequest request); Task<WebResponseContent> SplitPackage(SplitPackageDto request); Task<WebResponseContent> RevertSplitPackage(string originalBarcode); Task<WebResponseContent> GetSplitPackageInfo(string orderNo, string palletCode, string barcode); Task<WebResponseContent> GetSplitableLockInfos(int orderDetailId); } } ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_Model/Models/Outbound/Dt_OutboundLockInfo.cs
@@ -127,5 +127,8 @@ [Navigate(NavigateType.OneToOne, nameof(StockInfo))]//ä¸å¯¹ä¸ SchoolIdæ¯StudentAç±»éé¢ç public Dt_StockInfo StockInfo { get; set; } //ä¸è½èµå¼åªè½æ¯null [SugarColumn(IsIgnore = true)] public decimal RemainQuantity => AssignQuantity - PickedQty; } } ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_Model/Models/Outbound/Dt_OutboundOrderDetail.cs
@@ -111,5 +111,8 @@ /// </summary> [SugarColumn(IsNullable = true, ColumnDescription = "夿³¨")] public string Remark { get; set; } [SugarColumn(IsIgnore = true)] public decimal NeedOutQuantity => OrderQuantity - MoveQty; } } ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_Model/Models/Outbound/Dt_PickingRecord.cs
@@ -19,8 +19,13 @@ { [SugarColumn(IsPrimaryKey = true, IsIdentity = true)] public int Id { get; set; } public string OrderNo { get; set; } public int OrderDetailId { get; set; } public string PalletCode { get; set; } public int OutStockLockId { get; set; } public string MaterielCode { get; set; } [SugarColumn(Length = 100)] public string Barcode { get; set; } @@ -37,8 +42,8 @@ public int StockId { get; set; } } /// <summary> /// ååºè®°å½è¡¨ /// </summary> @@ -73,7 +78,10 @@ { [SugarColumn(IsPrimaryKey = true, IsIdentity = true)] public int Id { get; set; } public string OrderNo { get; set; } public string PalletCode { get; set; } public string StockId { get; set; } public bool IsReverted { get; set; } = false; public int OutStockLockInfoId { get; set; } // å ³èçåºåºéå®ä¿¡æ¯ public string OriginalBarcode { get; set; } // åæ¡ç public string NewBarcode { get; set; } // æ°æ¡ç @@ -82,14 +90,14 @@ /// æåæ°éï¼æ°æ¡ç æ°éï¼ /// </summary> public decimal SplitQty { get; set; } public decimal RemainQuantity { get; set; } public string MaterielCode { get; set; } // ç©æç¼ç public DateTime SplitTime { get; set; } = DateTime.Now; public string Operator { get; set; } // æä½äºº public int Status { get; set; } // ç¶æï¼1-å·²æå 2-å·²æ£é 3-å·²ååº } } ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_OutboundService/OutStockLockInfoService.cs
@@ -1,4 +1,5 @@ using System; using Microsoft.AspNetCore.Http; using System; using System.Collections.Generic; using System.Linq; using System.Text; @@ -10,6 +11,7 @@ using WIDESEA_Core.BaseServices; using WIDESEA_Core.Enums; using WIDESEA_Core.Helper; using WIDESEA_DTO.Outbound; using WIDESEA_IRecordService; using WIDESEA_IStockService; using WIDESEA_Model.Models; @@ -117,6 +119,37 @@ .ToListAsync(); } public async Task<LockInfoDetailDto> GetLockInfoDetail(int lockInfoId) { var lockInfo = await Db.Queryable<Dt_OutStockLockInfo>() .LeftJoin<Dt_OutboundOrderDetail>((lockInfo, detail) => lockInfo.OrderDetailId == detail.Id) .Where((lockInfo, detail) => lockInfo.Id == lockInfoId) .Select((lockInfo, detail) => new LockInfoDetailDto { Id = lockInfo.Id, OrderNo = lockInfo.OrderNo, OrderDetailId = lockInfo.OrderDetailId, BatchNo = lockInfo.BatchNo, MaterielCode = lockInfo.MaterielCode, StockId = lockInfo.StockId, OrderQuantity = lockInfo.OrderQuantity, OriginalQuantity = lockInfo.OriginalQuantity, AssignQuantity = lockInfo.AssignQuantity, PickedQty = lockInfo.PickedQty, LocationCode = lockInfo.LocationCode, PalletCode = lockInfo.PalletCode, Status = lockInfo.Status, IsSplitted = lockInfo.IsSplitted, ParentLockId = lockInfo.ParentLockId, MaterielName = detail.MaterielName, Unit = detail.Unit }) .FirstAsync(); return lockInfo; } /// <summary> /// æ ¹æ®æçç¼å·è·ååºåºéå®ä¿¡æ¯ /// </summary> ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_OutboundService/OutboundPickingService.cs
@@ -1,4 +1,6 @@ using System; using Microsoft.AspNetCore.Http; using SqlSugar; using System; using System.Collections.Generic; using System.Linq; using System.Text; @@ -9,6 +11,7 @@ using WIDESEA_Core; using WIDESEA_Core.BaseRepository; using WIDESEA_Core.BaseServices; using WIDESEA_Core.Helper; using WIDESEA_DTO.Outbound; using WIDESEA_IBasicService; using WIDESEA_IOutboundService; @@ -31,10 +34,11 @@ private readonly IStockInfoDetailService _stockInfoDetailService; private readonly ILocationInfoService _locationInfoService; private readonly IOutboundOrderDetailService _outboundOrderDetailService; private readonly IOutboundOrderService _outboundOrderService; private readonly ISplitPackageService _splitPackageService; public OutboundPickingService(IRepository<Dt_PickingRecord> BaseDal, IUnitOfWorkManage unitOfWorkManage, IStockInfoService stockInfoService, IStockService stockService, IOutStockLockInfoService outStockLockInfoService, IStockInfoDetailService stockInfoDetailService, ILocationInfoService locationInfoService, IOutboundOrderDetailService outboundOrderDetailService, ISplitPackageService splitPackageService) : base(BaseDal) public OutboundPickingService(IRepository<Dt_PickingRecord> BaseDal, IUnitOfWorkManage unitOfWorkManage, IStockInfoService stockInfoService, IStockService stockService, IOutStockLockInfoService outStockLockInfoService, IStockInfoDetailService stockInfoDetailService, ILocationInfoService locationInfoService, IOutboundOrderDetailService outboundOrderDetailService, ISplitPackageService splitPackageService, IOutboundOrderService outboundOrderService) : base(BaseDal) { _unitOfWorkManage = unitOfWorkManage; _stockInfoService = stockInfoService; @@ -44,9 +48,10 @@ _locationInfoService = locationInfoService; _outboundOrderDetailService = outboundOrderDetailService; _splitPackageService = splitPackageService; _outboundOrderService = outboundOrderService; } #region æ¥è¯¢åºåºè¯¦æ å表 public async Task<List<OutStockLockListResp>> GetOutStockLockListAsync(string orderNo) { @@ -57,13 +62,13 @@ return locks.Select(t => new OutStockLockListResp { Id = t.Id, // TaskNum = t.TaskNum, // TaskNum = t.TaskNum, PalletCode = t.PalletCode, CurrentBarcode = t.CurrentBarcode, AssignQuantity = t.AssignQuantity, PickedQty = t.PickedQty, Status = t.Status, // IsSplitted = t.IsSplitted // IsSplitted = t.IsSplitted }).ToList(); } #endregion @@ -87,13 +92,13 @@ return WebResponseContent.Instance.Error("æ¡ç ä¸åå¨"); } var result = new { Barcode = barcode, MaterielCode = stockDetail.MaterielCode, BatchNo = stockDetail.BatchNo, AvailableQuantity = stockDetail.StockQuantity - stockDetail.OutboundQuantity, LocationCode = stockDetail.StockInfo?.LocationCode, @@ -203,6 +208,162 @@ } } public async Task<WebResponseContent> ConfirmPicking(string orderNo, string palletCode, string barcode) { try { _unitOfWorkManage.BeginTran(); // 1. éªè¯æ¡ç æææ§ var stockDetail = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>() .Where(x => x.Barcode == barcode) .FirstAsync(); if (stockDetail == null) return WebResponseContent.Instance.Error("æ æçæ¡ç æç©æç¼ç "); // 2. æ£æ¥åºåå¯ç¨æ°é var availableQty = stockDetail.StockQuantity - stockDetail.OutboundQuantity; if (availableQty <= 0) return WebResponseContent.Instance.Error("åºåæ°éä¸è¶³"); // 3. æ¥æ¾ç¸å ³çåºåºè¯¦æ ä¿¡æ¯ var outStockInfo = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>() .Where(x => x.OrderNo == orderNo && x.PalletCode == palletCode && x.CurrentBarcode == barcode && x.Status == 0 && x.RemainQuantity > 0) .FirstAsync(); if (outStockInfo == null) return WebResponseContent.Instance.Error("æªæ¾å°å¯¹åºçæ£éä¿¡æ¯æå·²æ£é宿"); // 4. æ£æ¥åºåºè¯¦æ é宿°é if (outStockInfo.RemainQuantity <= 0) return WebResponseContent.Instance.Error("该æ¡ç å·²æ å©ä½å¯æ£éæ°é"); // 5. æ´æ°åºåºè¯¦æ çå·²æ£éæ°é outStockInfo.PickedQty = outStockInfo.AssignQuantity; outStockInfo.Status = 1; await _outStockLockInfoService.Db.Updateable(outStockInfo).ExecuteCommandAsync(); // 6. æ´æ°åºååºåºæ°é await _stockInfoDetailService.Db.Updateable<Dt_StockInfoDetail>() .SetColumns(x => x.OutboundQuantity == x.OutboundQuantity + outStockInfo.AssignQuantity) .Where(x => x.Id == stockDetail.Id) .ExecuteCommandAsync(); // 7. æ´æ°åºåºåæç» var orderDetail = await _outboundOrderDetailService.Db.Queryable<Dt_OutboundOrderDetail>() .Where(x => x.Id == outStockInfo.OrderDetailId) .FirstAsync(); orderDetail.OverOutQuantity += outStockInfo.AssignQuantity; await _outboundOrderDetailService.Db.Updateable(orderDetail).ExecuteCommandAsync(); // 8. æ£æ¥æ¯å¦å®æåºåº await CheckAndUpdateOrderStatus(orderNo); // 9. è®°å½æ£éåå² var pickingHistory = new Dt_PickingRecord { OrderNo = orderNo, PalletCode = palletCode, Barcode = barcode, MaterielCode = outStockInfo.MaterielCode, PickQuantity = outStockInfo.AssignQuantity, PickTime = DateTime.Now, OutStockLockId = outStockInfo.Id }; await Db.Insertable(pickingHistory).ExecuteCommandAsync(); _unitOfWorkManage.CommitTran(); return WebResponseContent.Instance.OK("æ£é确认æå"); } catch (Exception ex) { return WebResponseContent.Instance.Error($"æ£é确认失败ï¼{ex.Message}"); } } // æ£æ¥å¹¶æ´æ°è®¢åç¶æ private async Task CheckAndUpdateOrderStatus(string orderNo) { var orderDetails = await _stockInfoDetailService.Db.Queryable<Dt_OutboundOrderDetail>() .Where(x => x.OrderId == orderNo.ObjToInt()) .ToListAsync(); bool allCompleted = true; foreach (var detail in orderDetails) { if (detail.OverOutQuantity < detail.NeedOutQuantity) { allCompleted = false; break; } } if (allCompleted) { await _outboundOrderService.Db.Updateable<Dt_OutboundOrder>() .SetColumns(x => x.OrderStatus == 2) // 已宿 .Where(x => x.OrderNo == orderNo) .ExecuteCommandAsync(); } } // åæ¶æ£éåè½ public async Task<WebResponseContent> CancelPicking(string orderNo, string palletCode, string barcode) { try { _unitOfWorkManage.BeginTran(); // æ¥æ¾æ£éè®°å½ var outStockInfo = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>() .Where(x => x.OrderNo == orderNo && x.PalletCode == palletCode && x.CurrentBarcode == barcode && x.Status == 1) .FirstAsync(); if (outStockInfo == null) return WebResponseContent.Instance.Error("æªæ¾å°å·²æ£éè®°å½"); // è¿ååºåºè¯¦æ ç¶æ outStockInfo.PickedQty = 0; outStockInfo.Status = 0; await _outStockLockInfoService.Db.Updateable(outStockInfo).ExecuteCommandAsync(); // è¿ååºååºåºæ°é await _stockInfoDetailService.Db.Updateable<Dt_StockInfoDetail>() .SetColumns(x => x.OutboundQuantity == x.OutboundQuantity - outStockInfo.AssignQuantity) .Where(x => x.Barcode == barcode) .ExecuteCommandAsync(); // è¿ååºåºåæç» var orderDetail = await _outboundOrderDetailService.Db.Queryable<Dt_OutboundOrderDetail>() .Where(x => x.Id == outStockInfo.OrderDetailId) .FirstAsync(); orderDetail.OverOutQuantity -= outStockInfo.AssignQuantity; await _outboundOrderDetailService.Db.Updateable(orderDetail).ExecuteCommandAsync(); // å 餿£éåå² await Db.Deleteable<Dt_PickingRecord>() .Where(x => x.OutStockLockId == outStockInfo.Id) .ExecuteCommandAsync(); _unitOfWorkManage.CommitTran(); return WebResponseContent.Instance.OK("åæ¶æ£éæå"); } catch (Exception ex) { return WebResponseContent.Instance.Error($"åæ¶æ£é失败ï¼{ex.Message}"); } } /// <summary> /// æ ¹æ®æ¡ç æ¥æ¾éå®ä¿¡æ¯ /// </summary> @@ -217,6 +378,45 @@ .FirstAsync(); } // è·åæªæ£éå表 public async Task<List<Dt_OutStockLockInfo>> GetUnpickedList(string orderNo, string palletCode) { var list = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>() .Where(x => x.OrderNo == orderNo && x.PalletCode == palletCode && x.Status == 0 && x.RemainQuantity > 0) .ToListAsync(); return list; } // è·åå·²æ£éå表 public async Task<List<Dt_OutStockLockInfo>> GetPickedList(string orderNo, string palletCode) { var list = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>() .Where(x => x.OrderNo == orderNo && x.PalletCode == palletCode && x.Status == 1) .ToListAsync(); return list; } // è·åæ£éæ±æ» public async Task<object> GetPickingSummary(string orderNo) { var summary = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>() .Where(x => x.OrderNo == orderNo && x.Status == 0) .GroupBy(x => new { x.PalletCode, x.MaterielCode }) .Select(x => new { PalletCode = x.PalletCode, MaterielCode = x.MaterielCode, UnpickedCount = SqlFunc.AggregateCount(x.Id), UnpickedQuantity = SqlFunc.AggregateSum(x.RemainQuantity) }) .ToListAsync(); return summary; } /// <summary> /// è·åæ£éåå² /// </summary> @@ -235,6 +435,25 @@ .ToListAsync(); } public async Task GetPalletPickingSummary(string orderNo, string palletCode) { var summary = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>() .Where(x => x.OrderNo == orderNo && x.PalletCode == palletCode) .GroupBy(x => new { x.PalletCode, x.Status }) .Select(x => new { PalletCode = x.PalletCode, Status = x.Status, TotalAssignQty = SqlFunc.AggregateSum(x.AssignQuantity), TotalPickedQty = SqlFunc.AggregateSum(x.PickedQty) }) .ToListAsync(); // return summary; } /// <summary> /// æ¤éæ£é /// </summary> ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_OutboundService/SplitPackageService.cs
@@ -1,4 +1,5 @@ using System; using Microsoft.AspNetCore.Http; using System; using System.Collections.Generic; using System.Linq; using System.Text; @@ -34,40 +35,31 @@ /// <summary> /// æå æç®±æä½ /// </summary> public async Task<WebResponseContent> SplitPackage(SplitPackageRequest request) public async Task<WebResponseContent> SplitPackage(SplitPackageDto request) { try { _unitOfWorkManage.BeginTran(); // 1. éªè¯åºåºéå®ä¿¡æ¯ var lockInfo = await Db.Queryable<Dt_OutStockLockInfo>() .Where(x => x.Id == request.OutStockLockInfoId && x.Status == (int)OutLockStockStatusEnum.åºåºä¸) var lockInfo = await _stockInfoDetailService.Db.Queryable<Dt_OutStockLockInfo>() .Where(x => x.OrderNo == request.OrderNo && x.PalletCode == request.PalletCode && x.CurrentBarcode == request.OriginalBarcode && x.Status == 0) .FirstAsync(); if (lockInfo == null) return WebResponseContent.Instance.Error("æªæ¾å°ææçåºåºéå®ä¿¡æ¯"); //// 2. éªè¯å½åæ¡ç çå¯ç¨æ°é //var currentStockDetail = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>() // .Where(x => x.Barcode == lockInfo.CurrentBarcode && // x.MaterielCode == request.MaterielCode && // x.StockId == lockInfo.StockId) // .FirstAsync(); //if (currentStockDetail == null) // return WebResponseContent.Instance.Error("å½åæ¡ç å¨åºåä¸ä¸åå¨"); //// 3. æ£æ¥å¯ç¨æ°é //decimal availableQuantity = currentStockDetail.StockQuantity - currentStockDetail.OutboundQuantity; //if (request.SplitQuantity > availableQuantity) // return WebResponseContent.Instance.Error($"æå æ°éä¸è½å¤§äºå¯ç¨æ°éï¼å¯ç¨æ°éï¼{availableQuantity}"); // 2. æ£æ¥å©ä½é宿°é decimal remainingLockQuantity = lockInfo.AssignQuantity - lockInfo.PickedQty; if (request.SplitQuantity > remainingLockQuantity) return WebResponseContent.Instance.Error($"æå æ°éä¸è½å¤§äºå©ä½é宿°éï¼å©ä½ï¼{remainingLockQuantity}"); var stockDetail = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>() .Where(x => x.Barcode == request.OriginalBarcode) .FirstAsync(); // 3. çææ°æ¡ç string newBarcode = ""; @@ -109,9 +101,11 @@ OriginalBarcode = lockInfo.CurrentBarcode, NewBarcode = newBarcode, SplitQty = request.SplitQuantity, MaterielCode = request.MaterielCode, RemainQuantity = lockInfo.RemainQuantity - request.SplitQuantity, MaterielCode = lockInfo.MaterielCode, SplitTime = DateTime.Now, Operator = request.Operator, OrderNo = request.OrderNo, PalletCode = request.PalletCode, Status = (int)SplitPackageStatusEnum.å·²æå }; await Db.Insertable(splitHistory).ExecuteCommandAsync(); @@ -134,6 +128,80 @@ } } // æ¤éæå public async Task<WebResponseContent> RevertSplitPackage(string originalBarcode) { try { _unitOfWorkManage.BeginTran(); // æ¥æ¾æè¿çæªæ¤éæå è®°å½ var splitPackage = await Db.Queryable<Dt_SplitPackageRecord>() .Where(x => x.OriginalBarcode == originalBarcode && !x.IsReverted) .OrderByDescending(x => x.CreateDate) .FirstAsync(); if (splitPackage == null) return WebResponseContent.Instance.Error("æªæ¾å°æå è®°å½"); // æ£æ¥æ°æ¡ç æ¯å¦å·²æ£é var newOutStockInfo = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>() .Where(x => x.CurrentBarcode == splitPackage.NewBarcode) .FirstAsync(); if (newOutStockInfo.Status == 1) return WebResponseContent.Instance.Error("æ°æ¡ç å·²æ£éï¼æ æ³æ¤éæå "); // è¿åååºåºè¯¦æ æ°é var originalOutStockInfo = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>() .Where(x => x.CurrentBarcode == originalBarcode) .FirstAsync(); originalOutStockInfo.AssignQuantity += splitPackage.SplitQty; await _outStockLockInfoService.Db.Updateable(originalOutStockInfo).ExecuteCommandAsync(); // å 餿°åºåºè¯¦æ è®°å½ await _outStockLockInfoService.Db.Deleteable<Dt_OutStockLockInfo>() .Where(x => x.CurrentBarcode == splitPackage.NewBarcode) .ExecuteCommandAsync(); // æ è®°æå è®°å½ä¸ºå·²æ¤é splitPackage.IsReverted = true; await Db.Updateable(splitPackage).ExecuteCommandAsync(); _unitOfWorkManage.CommitTran(); return WebResponseContent.Instance.OK("æ¤éæå æå"); } catch (Exception ex) { return WebResponseContent.Instance.Error($"æ¤éæå 失败ï¼{ex.Message}"); } } // è·åæå ä¿¡æ¯ public async Task< WebResponseContent > GetSplitPackageInfo(string orderNo, string palletCode, string barcode) { var outStockInfo = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>() .Where(x => x.OrderNo == orderNo && x.PalletCode == palletCode && x.CurrentBarcode == barcode && x.Status == 0) .FirstAsync(); if (outStockInfo == null) return WebResponseContent.Instance .Error("æªæ¾å°å¯¹åºçåºåºä¿¡æ¯"); var stockDetail = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>() .Where(x => x.Barcode == barcode) .FirstAsync(); return WebResponseContent.Instance .OK("",new { MaterielCode = outStockInfo.MaterielCode, RemainQuantity = outStockInfo.RemainQuantity, Unit = "个" // æ ¹æ®å®é æ åµè·ååä½ }); } /// <summary> /// è·å坿å çåºåºéå®ä¿¡æ¯ /// </summary> ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_TaskInfoService/TaskService.cs
@@ -362,8 +362,7 @@ return content.Error($"æªæ¾å°å¯¹åºçç»ç¹è´§ä½ä¿¡æ¯"); } _stockRepository.Db.Deleteable(stockInfo).ExecuteCommand(); int beforeStatus = locationInfo.LocationStatus; locationInfo.LocationStatus = LocationStatusEnum.Free.ObjToInt(); @@ -374,6 +373,7 @@ task.TaskStatus = TaskStatusEnum.Finish.ObjToInt(); BaseDal.DeleteAndMoveIntoHty(task, App.User.UserId == 0 ? OperateTypeEnum.èªå¨å®æ : OperateTypeEnum.äººå·¥å®æ); _stockService.StockInfoService.Repository.DeleteAndMoveIntoHty(stockInfo, App.User.UserId == 0 ? OperateTypeEnum.èªå¨å®æ : OperateTypeEnum.äººå·¥å®æ); _stockRepository.Db.Deleteable(stockInfo).ExecuteCommand(); _locationStatusChangeRecordService.AddLocationStatusChangeRecord(locationInfo, beforeStatus, StockChangeType.Outbound.ObjToInt(), stockInfo.Details.FirstOrDefault()?.OrderNo ?? "", task.TaskNum); @@ -390,8 +390,7 @@ /// <summary> /// ååºå®æåè° - AGVå°æçæ¾åè´§ä½åè°ç¨ /// </summary> /// ååºå®æåè° public async Task<WebResponseContent> BackToStockComplete(Dt_Task task) { try ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/Outbound/OutStockLockInfoController.cs
@@ -1,8 +1,10 @@ using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Org.BouncyCastle.Utilities.Collections; using WIDESEA_Core; using WIDESEA_Core.BaseController; using WIDESEA_Core.Helper; using WIDESEA_IOutboundService; using WIDESEA_Model.Models; @@ -19,5 +21,14 @@ { } [HttpGet("getOutStockLockInfo")] public async Task<WebResponseContent> GetOutStockLockInfo(string orderDetailId) { var list = await Service.GetByOrderDetailId(orderDetailId.ObjToInt()); return WebResponseContent.Instance.OK(null, list); } } } ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/Outbound/OutboundPickingController.cs
@@ -1,4 +1,5 @@ using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using WIDESEA_Core; using WIDESEA_Core.BaseController; using WIDESEA_DTO.Outbound; @@ -38,14 +39,43 @@ return WebResponseContent.Instance.OK(null, lockInfos); } /// <summary> /// æ£é确认 /// </summary> [HttpPost("ConfirmPicking")] public async Task<WebResponseContent> ConfirmPicking([FromBody] PickingConfirmRequest request) [HttpGet("unpicked-list")] public async Task<WebResponseContent> GetUnpickedList(string orderNo, string palletCode) { return await Service.ConfirmPicking(request); var lists= await Service.GetUnpickedList(orderNo, palletCode); return WebResponseContent.Instance.OK("", lists); } [HttpGet("picked-list")] public async Task<WebResponseContent> GetPickedList(string orderNo, string palletCode) { var lists = await Service.GetPickedList(orderNo, palletCode); return WebResponseContent.Instance.OK("", lists); } [HttpPost("confirm-picking")] public async Task<WebResponseContent> ConfirmPicking([FromBody] ConfirmPickingDto dto) { return await Service.ConfirmPicking(dto.OrderNo, dto.PalletCode, dto.Barcode); } [HttpGet("picking-summary")] public async Task<WebResponseContent> GetPickingSummary(string orderNo) { var data = await Service.GetPickingSummary(orderNo); return WebResponseContent.Instance.OK("", data); } ///// <summary> ///// æ£é确认 ///// </summary> //[HttpPost("ConfirmPicking")] //public async Task<WebResponseContent> ConfirmPicking([FromBody] PickingConfirmRequest request) //{ // return await Service.ConfirmPicking(request); //} /// <summary> /// éªè¯æ¡ç å¹¶è·åç©æä¿¡æ¯ /// </summary> @@ -58,7 +88,7 @@ /// æå æä½ /// </summary> [HttpPost("SplitPackage")] public async Task<WebResponseContent> SplitPackage([FromBody] SplitPackageRequest request) public async Task<WebResponseContent> SplitPackage([FromBody] SplitPackageDto request) { return await _splitPackageService.SplitPackage(request); }