移动端:增加测试批次模式隔离

This commit is contained in:
焦龙言
2026-09-24 09:45:08 +08:00
parent 886a4479c4
commit d15b8e2f6c
29 changed files with 3561 additions and 9 deletions
@@ -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>