feat:产品入库-托盘码支持扫码器录入

master
黄伟杰 16 hours ago
parent f1d3552f1f
commit 31059c65e7

@ -64,6 +64,14 @@ export function getPalletPage(params = {}) {
})
}
export function getPallet(id) {
return request({
url: '/admin-api/erp/pallet/get',
method: 'get',
params: { id }
})
}
export function createPallet(data) {
return request({
url: '/admin-api/erp/pallet/create',

@ -111,11 +111,20 @@
<text class="form-label">{{ t('productInbound.palletCode') }}<text class="required-star">*</text></text>
<text v-if="selectedPallets.length" class="label-tip">{{ t('productInbound.selectedPalletCount', { count: selectedPallets.length }) }}</text>
</view>
<view :class="['select-field', selectedPallets.length ? 'selected' : '']" @click="goSelectPallet" >
<view class="select-content">
<text :class="selectedPallets.length ? 'select-value' : 'select-placeholder'">{{ palletCode || t('productInbound.selectPallet') }}</text>
<view class="task-product-search-row">
<input
id="product-inbound-pallet-scan-input"
v-model="palletScanInput"
class="task-product-scan-input"
type="text"
:placeholder="palletCode || t('productInbound.selectPallet')"
confirm-type="done"
@input="onPalletScanInput"
@confirm="onPalletScanConfirm"
/>
<view class="task-product-select-field" @click="goSelectPallet">
<text class="task-product-select-text">{{ t('productInbound.selectPalletTitle') }}</text>
</view>
<uni-icons type="right" size="18" color="#9ca3af"></uni-icons>
</view>
</view>
@ -188,8 +197,8 @@ import { computed, ref } from 'vue'
import { onLoad, onShow } from '@dcloudio/uni-app'
import { useI18n } from 'vue-i18n'
import NavBar from '@/components/common/NavBar.vue'
import { getTaskDefaultPackagingSchemes } from '@/api/mes/productInbound'
import { getProduct, getProductPage } from '@/api/erp/productInfo'
import { getPallet, getTaskDefaultPackagingSchemes } from '@/api/mes/productInbound'
import { getProduct } from '@/api/erp/productInfo'
import { getWarehouseAreaSimpleList, getWarehouseSimpleList } from '@/api/mes/moldget'
const { t } = useI18n()
@ -203,16 +212,17 @@ const selectedPallets = ref([])
const editingIndex = ref(null)
const taskProductScanInput = ref('')
const productScanInput = ref('')
const palletScanInput = ref('')
const warehouseOptions = ref([])
const warehouseAreaMap = ref({})
const taskProductList = ref([])
const PRODUCT_CATEGORY_TYPE = 1
const PRODUCT_PAGE_SIZE = 10
const SCAN_AUTO_SEARCH_DELAY = 300
let taskProductScanTimer = null
let productScanTimer = null
let palletScanTimer = null
const productName = computed(() => selectedTaskProduct.value?.productName || product.value.name || '')
const productId = computed(() => selectedTaskProduct.value?.productId || product.value.id)
@ -364,6 +374,7 @@ function setRelateTask(value) {
selectedTaskProduct.value = null
taskProductScanInput.value = ''
productScanInput.value = ''
palletScanInput.value = ''
taskId.value = null
taskCode.value = ''
selectedTaskData.value = null
@ -393,6 +404,11 @@ function getProductMaterialScanCode(value) {
const match = text.match(/^PRODUCTMATERIAL[-:]?\s*(.+)$/i)
return match ? match[1].trim() : ''
}
function getPalletScanCode(value) {
const text = String(value || '').trim()
const match = text.match(/^PALLET[-:]?\s*(.+)$/i)
return match ? match[1].trim() : ''
}
function getProductIdValue(item) {
return item?.id || item?.productId
}
@ -413,49 +429,14 @@ function getTaskProductScanValues(item) {
item?.name
].map(normalizeScanValue).filter(Boolean)
}
function normalizeProductPageList(res) {
const root = res && res.data !== undefined ? res.data : res
return Array.isArray(root) ? root : (root?.list || root?.rows || root?.records || [])
}
function pickMatchedProduct(list, keyword) {
const normalized = normalizeScanValue(keyword)
return list.find((item) => {
const values = [getProductIdValue(item), getProductCodeValue(item), getProductNameValue(item)].map(normalizeScanValue).filter(Boolean)
return values.includes(normalized)
}) || list[0]
}
async function getProductDetailOrSelf(item) {
const id = getProductIdValue(item)
if (!id) return item
try {
const res = await getProduct(id)
return { ...item, ...(res?.data || res || {}) }
} catch (e) {
return item
}
}
async function findProductByScanCode(scanCode) {
const keyword = String(scanCode || '').trim()
if (!keyword) return null
const codeRes = await getProductPage({ pageNo: 1, pageSize: PRODUCT_PAGE_SIZE, categoryType: PRODUCT_CATEGORY_TYPE, barCode: keyword })
const codeList = normalizeProductPageList(codeRes)
let matched = pickMatchedProduct(codeList, keyword)
if (!matched) {
const nameRes = await getProductPage({ pageNo: 1, pageSize: PRODUCT_PAGE_SIZE, categoryType: PRODUCT_CATEGORY_TYPE, name: keyword })
const nameList = normalizeProductPageList(nameRes)
matched = pickMatchedProduct(nameList, keyword)
}
if (!matched && /^\d+$/.test(keyword)) {
try {
const res = await getProduct(keyword)
const detail = res?.data || res
if (detail?.id && (!detail.categoryType || Number(detail.categoryType) === PRODUCT_CATEGORY_TYPE)) matched = detail
} catch (e) {}
}
return matched ? getProductDetailOrSelf(matched) : null
const id = String(scanCode || '').trim()
if (!/^\d+$/.test(id)) return null
const res = await getProduct(id)
const detail = res?.data || res
if (!detail?.id) return null
if (detail.categoryType && Number(detail.categoryType) !== PRODUCT_CATEGORY_TYPE) return null
return detail
}
function getTaskProductByProduct(productItem) {
const productValues = [getProductIdValue(productItem), getProductCodeValue(productItem), getProductNameValue(productItem)].map(normalizeScanValue).filter(Boolean)
@ -518,6 +499,7 @@ async function onTaskProductScanConfirm() {
}
selectedTaskProduct.value = buildTaskProductSelection(matched)
selectedPallets.value = []
palletScanInput.value = ''
taskProductScanInput.value = ''
} catch (e) {
uni.hideLoading()
@ -542,12 +524,70 @@ async function onProductScanConfirm() {
product.value = matched
selectedTaskProduct.value = null
selectedPallets.value = []
palletScanInput.value = ''
productScanInput.value = ''
} catch (e) {
uni.hideLoading()
uni.showToast({ title: t('productInbound.loadFailed'), icon: 'none' })
}
}
function schedulePalletScanSearch(value) {
if (!getPalletScanCode(value)) return
if (palletScanTimer) clearTimeout(palletScanTimer)
palletScanTimer = setTimeout(() => {
palletScanTimer = null
onPalletScanConfirm()
}, SCAN_AUTO_SEARCH_DELAY)
}
function onPalletScanInput(e) {
schedulePalletScanSearch(e?.detail?.value ?? palletScanInput.value)
}
function addScannedPallet(pallet) {
if (!pallet?.id) return
const exists = selectedPallets.value.some((item) => String(item.id) === String(pallet.id))
if (exists) return
selectedPallets.value.push({
...pallet,
packageCount: pallet.productCount || pallet.packageCount || palletPackageQuantity.value || 1
})
}
async function findPalletByScanCode(scanCode) {
const id = String(scanCode || '').trim()
if (!/^\d+$/.test(id)) return null
const res = await getPallet(id)
const detail = res?.data || res
if (!detail?.id) return null
if (detail.productId && productId.value && String(detail.productId) !== String(productId.value)) return null
return detail
}
async function onPalletScanConfirm() {
if (palletScanTimer) {
clearTimeout(palletScanTimer)
palletScanTimer = null
}
const scanCode = getPalletScanCode(palletScanInput.value)
if (!scanCode) return
if (!productId.value) {
uni.showToast({ title: t('productInbound.selectProductFirst'), icon: 'none' })
return
}
try {
uni.showLoading({ title: t('productInbound.loading'), mask: true })
const matched = await findPalletByScanCode(scanCode)
uni.hideLoading()
if (!matched?.id) {
uni.showToast({ title: '\u6ca1\u6709\u8fd9\u4e2a\u6258\u76d8', icon: 'none' })
return
}
addScannedPallet(matched)
await loadAreasForPallets([matched])
palletScanInput.value = ''
} catch (e) {
uni.hideLoading()
uni.showToast({ title: t('productInbound.loadFailed'), icon: 'none' })
}
}
function goSelectPallet() {
if (!productId.value) {
uni.showToast({ title: t('productInbound.selectProductFirst'), icon: 'none' })
@ -683,6 +723,7 @@ onShow(async () => {
selectedTaskProduct.value = null
taskProductScanInput.value = ''
selectedPallets.value = []
palletScanInput.value = ''
gd._productInboundTaskSelectResult = null
try {
uni.showLoading({ title: t('productInbound.loading'), mask: true })
@ -706,6 +747,7 @@ onShow(async () => {
productScanInput.value = ''
}
selectedPallets.value = []
palletScanInput.value = ''
gd._productInboundProductSelectResult = null
}
const palletResult = gd?._productInboundPalletSelectResult

Loading…
Cancel
Save