fix: 李红攀:V2.0.061采购入库、销售出库添加扫码功能
This commit is contained in:
@@ -268,17 +268,28 @@ onMounted(async () => {
|
|||||||
}, 500)
|
}, 500)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const ERROR_DISPLAY_MS = 2000
|
||||||
|
|
||||||
/** 重置到初始状态 */
|
/** 重置到初始状态 */
|
||||||
function resetToIdle() {
|
function resetToIdle() {
|
||||||
clearScanInputs()
|
clearScanInputs()
|
||||||
locationInfo.value = null
|
locationInfo.value = null
|
||||||
productPreview.value = null
|
productPreview.value = null
|
||||||
step.value = 'idle'
|
step.value = 'idle'
|
||||||
// 延迟清空错误 + 聚焦光标,让用户先看到错误提示
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
clearFeedback()
|
clearFeedback()
|
||||||
focusLocationInput()
|
focusLocationInput()
|
||||||
}, 800)
|
}, ERROR_DISPLAY_MS)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 停留在产品扫码阶段 + 聚焦产品输入框(扫产品失败用) */
|
||||||
|
function resetToProductScan() {
|
||||||
|
productBarCode.value = ''
|
||||||
|
productPreview.value = null
|
||||||
|
setTimeout(() => {
|
||||||
|
clearFeedback()
|
||||||
|
focusProductInput()
|
||||||
|
}, ERROR_DISPLAY_MS)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 聚焦库位码输入框 */
|
/** 聚焦库位码输入框 */
|
||||||
@@ -394,13 +405,13 @@ async function handleProductScan() {
|
|||||||
productPreview.value = await getProductByBarCode(code)
|
productPreview.value = await getProductByBarCode(code)
|
||||||
} catch {
|
} catch {
|
||||||
setErrorFeedback(`条码 ${code} 未匹配到产品`)
|
setErrorFeedback(`条码 ${code} 未匹配到产品`)
|
||||||
resetToIdle()
|
resetToProductScan()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!productPreview.value?.id) {
|
if (!productPreview.value?.id) {
|
||||||
setErrorFeedback(`条码 ${code} 未匹配到产品`)
|
setErrorFeedback(`条码 ${code} 未匹配到产品`)
|
||||||
resetToIdle()
|
resetToProductScan()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,134 +3,129 @@
|
|||||||
<view v-if="records.length === 0" class="recent-scan-list__empty">
|
<view v-if="records.length === 0" class="recent-scan-list__empty">
|
||||||
暂无扫码记录
|
暂无扫码记录
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<view
|
<view
|
||||||
v-for="(record, index) in records"
|
v-for="(record, index) in records"
|
||||||
:key="record.id || index"
|
:key="record.id || index"
|
||||||
class="recent-scan-item"
|
class="scan-card"
|
||||||
:class="{ 'recent-scan-item--new': index === latestIndex }"
|
:class="{ 'scan-card--latest': latestIndex === index }"
|
||||||
>
|
>
|
||||||
<view class="recent-scan-item__main">
|
<view class="scan-card__header">
|
||||||
<view class="recent-scan-item__info">
|
<text class="scan-card__name">{{ record.productName || '-' }}</text>
|
||||||
<text class="recent-scan-item__name">{{ record.productName || '-' }}</text>
|
<text class="scan-card__delete" @tap="$emit('delete', index)">删除</text>
|
||||||
<text class="recent-scan-item__spec">{{ record.productSpec || '-' }}</text>
|
|
||||||
</view>
|
</view>
|
||||||
<view class="recent-scan-item__meta">
|
|
||||||
<text class="recent-scan-item__location">{{ record.locationCode || '-' }}</text>
|
<view class="scan-card__meta">
|
||||||
<text class="recent-scan-item__count">x{{ record.scanCount || 1 }}</text>
|
<text>条码:{{ record.productBarCode || '-' }}</text>
|
||||||
|
<text>规格:{{ record.productSpec || '-' }}</text>
|
||||||
</view>
|
</view>
|
||||||
|
<view class="scan-card__meta">
|
||||||
|
<text>仓库:{{ record.warehouseName || '-' }}</text>
|
||||||
|
<text>单位:{{ record.productUnit || '-' }}</text>
|
||||||
</view>
|
</view>
|
||||||
<view class="recent-scan-item__time">
|
<view class="scan-card__meta">
|
||||||
<text>{{ formatTime(record.scanTime) }}</text>
|
<text>库位:{{ record.locationCode || '-' }}</text>
|
||||||
<text class="recent-scan-item__delete" @tap.stop="$emit('delete', index)">删除</text>
|
<text>批次:{{ record.batchNo || '-' }}</text>
|
||||||
|
</view>
|
||||||
|
<view class="scan-card__footer">
|
||||||
|
<text class="scan-card__time">{{ formatTime(record.scanTime) }}</text>
|
||||||
|
<text class="scan-card__count">{{ record.scanCount }}</text>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import type { ScanRecord } from '../index.vue'
|
||||||
|
|
||||||
defineProps<{
|
defineProps<{
|
||||||
records: any[]
|
records: ScanRecord[]
|
||||||
latestIndex?: number
|
latestIndex?: number
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
defineEmits<{
|
defineEmits<{
|
||||||
(event: 'delete', index: number): void
|
(event: 'delete', index: number): void
|
||||||
|
(event: 'clear'): void
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
function formatTime(timeStr?: string) {
|
function formatTime(time?: string) {
|
||||||
if (!timeStr) return ''
|
if (!time) return '-'
|
||||||
try {
|
const date = new Date(time)
|
||||||
const d = new Date(timeStr)
|
return `${date.getHours().toString().padStart(2, '0')}:${date.getMinutes().toString().padStart(2, '0')}:${date.getSeconds().toString().padStart(2, '0')}`
|
||||||
return `${d.getHours().toString().padStart(2, '0')}:${d.getMinutes().toString().padStart(2, '0')}:${d.getSeconds().toString().padStart(2, '0')}`
|
|
||||||
} catch {
|
|
||||||
return ''
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.recent-scan-list {
|
.recent-scan-list {
|
||||||
&__empty {
|
&__empty {
|
||||||
text-align: center;
|
padding: 48rpx;
|
||||||
|
border-radius: 16rpx;
|
||||||
|
background: #fff;
|
||||||
color: #86909c;
|
color: #86909c;
|
||||||
font-size: 24rpx;
|
text-align: center;
|
||||||
padding: 24rpx 0;
|
font-size: 26rpx;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.recent-scan-item {
|
.scan-card {
|
||||||
padding: 16rpx 0;
|
margin-bottom: 16rpx;
|
||||||
border-bottom: 1rpx solid #f0f0f0;
|
padding: 24rpx;
|
||||||
|
border: 2rpx solid transparent;
|
||||||
|
border-radius: 16rpx;
|
||||||
|
background: #fff;
|
||||||
|
|
||||||
&:last-child {
|
&--latest {
|
||||||
border-bottom: none;
|
border-color: #1677ff;
|
||||||
|
box-shadow: 0 8rpx 20rpx rgba(22, 119, 255, 0.12);
|
||||||
}
|
}
|
||||||
|
|
||||||
&--new {
|
&__header,
|
||||||
background: #f6ffed;
|
&__meta,
|
||||||
margin: 0 -24rpx;
|
&__footer {
|
||||||
padding: 16rpx 24rpx;
|
|
||||||
border-radius: 12rpx;
|
|
||||||
border-bottom: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__main {
|
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
gap: 12rpx;
|
gap: 16rpx;
|
||||||
margin-bottom: 8rpx;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&__info {
|
&__header {
|
||||||
display: flex;
|
margin-bottom: 10rpx;
|
||||||
flex-direction: column;
|
|
||||||
gap: 4rpx;
|
|
||||||
min-width: 0;
|
|
||||||
flex: 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&__name {
|
&__name {
|
||||||
font-size: 26rpx;
|
|
||||||
font-weight: 600;
|
|
||||||
color: #1f2329;
|
color: #1f2329;
|
||||||
}
|
font-size: 28rpx;
|
||||||
|
|
||||||
&__spec {
|
|
||||||
font-size: 22rpx;
|
|
||||||
color: #86909c;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__meta {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: flex-end;
|
|
||||||
gap: 4rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__location {
|
|
||||||
font-size: 24rpx;
|
|
||||||
color: #52c41a;
|
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__count {
|
|
||||||
font-size: 24rpx;
|
|
||||||
color: #f5222d;
|
|
||||||
font-weight: 600;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__time {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: space-between;
|
|
||||||
font-size: 20rpx;
|
|
||||||
color: #86909c;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__delete {
|
&__delete {
|
||||||
color: #f5222d;
|
flex-shrink: 0;
|
||||||
padding: 4rpx 8rpx;
|
color: #f53f3f;
|
||||||
|
font-size: 24rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__meta {
|
||||||
|
margin-top: 6rpx;
|
||||||
|
color: #4e5969;
|
||||||
|
font-size: 22rpx;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__footer {
|
||||||
|
margin-top: 10rpx;
|
||||||
|
padding-top: 10rpx;
|
||||||
|
border-top: 2rpx solid #f2f3f5;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__time {
|
||||||
|
color: #86909c;
|
||||||
|
font-size: 22rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__count {
|
||||||
|
color: #1677ff;
|
||||||
|
font-size: 28rpx;
|
||||||
|
font-weight: 700;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -268,17 +268,28 @@ onMounted(async () => {
|
|||||||
}, 500)
|
}, 500)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const ERROR_DISPLAY_MS = 2000
|
||||||
|
|
||||||
/** 重置到初始状态 */
|
/** 重置到初始状态 */
|
||||||
function resetToIdle() {
|
function resetToIdle() {
|
||||||
clearScanInputs()
|
clearScanInputs()
|
||||||
locationInfo.value = null
|
locationInfo.value = null
|
||||||
productPreview.value = null
|
productPreview.value = null
|
||||||
step.value = 'idle'
|
step.value = 'idle'
|
||||||
// 延迟清空错误 + 聚焦光标,让用户先看到错误提示
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
clearFeedback()
|
clearFeedback()
|
||||||
focusLocationInput()
|
focusLocationInput()
|
||||||
}, 800)
|
}, ERROR_DISPLAY_MS)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 停留在产品扫码阶段 + 聚焦产品输入框(扫产品失败用) */
|
||||||
|
function resetToProductScan() {
|
||||||
|
productBarCode.value = ''
|
||||||
|
productPreview.value = null
|
||||||
|
setTimeout(() => {
|
||||||
|
clearFeedback()
|
||||||
|
focusProductInput()
|
||||||
|
}, ERROR_DISPLAY_MS)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 聚焦库位码输入框 */
|
/** 聚焦库位码输入框 */
|
||||||
@@ -394,13 +405,13 @@ async function handleProductScan() {
|
|||||||
productPreview.value = await getProductByBarCode(code)
|
productPreview.value = await getProductByBarCode(code)
|
||||||
} catch {
|
} catch {
|
||||||
setErrorFeedback(`条码 ${code} 未匹配到产品`)
|
setErrorFeedback(`条码 ${code} 未匹配到产品`)
|
||||||
resetToIdle()
|
resetToProductScan()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!productPreview.value?.id) {
|
if (!productPreview.value?.id) {
|
||||||
setErrorFeedback(`条码 ${code} 未匹配到产品`)
|
setErrorFeedback(`条码 ${code} 未匹配到产品`)
|
||||||
resetToIdle()
|
resetToProductScan()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user