移动端:增加测试批次模式隔离
This commit is contained in:
@@ -0,0 +1,115 @@
|
||||
<template>
|
||||
<view class="w-full">
|
||||
<view class="flex items-center rounded-xl bg-white p-2 shadow-sm">
|
||||
<input
|
||||
v-model="scanValue"
|
||||
class="h-11 min-w-0 flex-1 px-3 text-sm text-gray-700"
|
||||
type="text"
|
||||
confirm-type="done"
|
||||
maxlength="128"
|
||||
:focus="focusRequested"
|
||||
:disabled="disabled || loading"
|
||||
placeholder="请扫描或输入托盘二维码后按回车"
|
||||
@confirm="handleSubmit"
|
||||
@input="clearError"
|
||||
/>
|
||||
<button
|
||||
class="ml-2 h-10 rounded-lg bg-blue-500 px-3 text-xs text-white active:opacity-80 disabled:bg-gray-300"
|
||||
:disabled="disabled || loading"
|
||||
@click="handleSubmit"
|
||||
>
|
||||
{{ loading ? "校验中" : "提交扫描" }}
|
||||
</button>
|
||||
</view>
|
||||
<text v-if="errorMessage" class="mt-2 block text-xs text-red-500">
|
||||
{{ errorMessage }}
|
||||
</text>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { nextTick, onMounted, ref, watch } from "vue";
|
||||
import { isDuplicateScan, normalizeScanValue } from "@/utils/palletScan";
|
||||
|
||||
const props = defineProps({
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
loading: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
duplicateWindowMs: {
|
||||
type: Number,
|
||||
default: 500,
|
||||
},
|
||||
});
|
||||
|
||||
const emit = defineEmits(["scan", "invalid", "duplicate"]);
|
||||
const scanValue = ref("");
|
||||
const errorMessage = ref("");
|
||||
const focusRequested = ref(false);
|
||||
let lastScanValue = "";
|
||||
let lastScanAt = 0;
|
||||
|
||||
function focusInput() {
|
||||
if (props.disabled || props.loading) return;
|
||||
focusRequested.value = false;
|
||||
nextTick(() => {
|
||||
if (!props.disabled && !props.loading) {
|
||||
focusRequested.value = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function clearError() {
|
||||
errorMessage.value = "";
|
||||
}
|
||||
|
||||
function handleSubmit() {
|
||||
if (props.disabled || props.loading) return;
|
||||
|
||||
let normalizedValue;
|
||||
try {
|
||||
normalizedValue = normalizeScanValue(scanValue.value);
|
||||
} catch (error) {
|
||||
errorMessage.value = error.message;
|
||||
emit("invalid", error.message);
|
||||
focusInput();
|
||||
return;
|
||||
}
|
||||
|
||||
const scannedAt = Date.now();
|
||||
if (
|
||||
isDuplicateScan(
|
||||
normalizedValue,
|
||||
lastScanValue,
|
||||
scannedAt,
|
||||
lastScanAt,
|
||||
props.duplicateWindowMs,
|
||||
)
|
||||
) {
|
||||
scanValue.value = "";
|
||||
emit("duplicate", normalizedValue);
|
||||
focusInput();
|
||||
return;
|
||||
}
|
||||
|
||||
lastScanValue = normalizedValue;
|
||||
lastScanAt = scannedAt;
|
||||
scanValue.value = "";
|
||||
errorMessage.value = "";
|
||||
emit("scan", normalizedValue);
|
||||
focusInput();
|
||||
}
|
||||
|
||||
onMounted(focusInput);
|
||||
|
||||
watch(
|
||||
() => [props.disabled, props.loading],
|
||||
([disabled, loading]) => {
|
||||
if (!disabled && !loading) focusInput();
|
||||
},
|
||||
);
|
||||
</script>
|
||||
Reference in New Issue
Block a user