Appearance
BizScanInput 扫码采集
扫码枪采集清单:聚焦输入框扫码(回车即提交一码)、重复码策略(数量加一 / 拒绝并抖动提示)、已扫清单(数量加减、单删、清空、种数与件数合计)、本地 validator 校验拒绝、行插槽接管。仓库出入库连扫、盘点清点、资产巡检登记、门店收货验收——扫码枪输入以回车结束,天然适配;与 BizTagInput(自由文本标签)互补。
基础连扫
- SKU-100024无线鼠标 ×22
- SKU-100038机械键盘1
共 2 种 / 3 件
输入 / 模拟扫码后回车录入,清单实时累计种数与件数。
<script setup lang="ts">
/** 场景:出入库连扫——回车录入,清单累计 */
import { ref } from 'vue'
import { BizScanInput } from 'vue3-ep-biz-lib'
import type { BizScanItem } from 'vue3-ep-biz-lib'
const items = ref<BizScanItem[]>([
{ code: 'SKU-100024', count: 2, remark: '无线鼠标 ×2' },
{ code: 'SKU-100038', count: 1, remark: '机械键盘' },
])
</script>
<template>
<div style="max-width: 520px">
<BizScanInput v-model="items" :height="200" />
</div>
</template>
显示代码
重复策略
连续录入同一码 SN-88213904 会被拒绝并抖动提示;再试试别的码
- SN-882139041
共 1 种 / 1 件
duplicate="reject" 重复码拒绝并提示(防重扫场景),默认 plus 数量加一。<script setup lang="ts">
/** 场景:重复策略——reject 拒绝重扫(已提示),plus 数量加一 */
import { ref } from 'vue'
import { ElAlert } from 'element-plus'
import { BizScanInput } from 'vue3-ep-biz-lib'
import type { BizScanItem } from 'vue3-ep-biz-lib'
const items = ref<BizScanItem[]>([{ code: 'SN-88213904', count: 1 }])
</script>
<template>
<div style="max-width: 520px">
<ElAlert title="连续录入同一码 SN-88213904 会被拒绝并抖动提示;再试试别的码" type="info" :closable="false" style="margin-bottom: 10px" />
<BizScanInput v-model="items" duplicate="reject" :height="160" />
</div>
</template>
显示代码
校验拦截
试试录入 ASSET-0001(通过)与 TOY-123(拦截)。最近拦截:无
validator 本地规则拦截非法码(前缀白名单),reject 事件可上报。<script setup lang="ts">
/** 场景:校验拦截——前缀白名单,reject 外抛 */
import { ref } from 'vue'
import { ElAlert } from 'element-plus'
import { BizScanInput } from 'vue3-ep-biz-lib'
import type { BizScanItem } from 'vue3-ep-biz-lib'
const items = ref<BizScanItem[]>([])
const rejected = ref('')
/** 仅接受 ASSET- 前缀的资产码 */
const validator = (code: string): string | null =>
code.startsWith('ASSET-') ? null : '仅支持 ASSET- 前缀的资产码'
</script>
<template>
<div style="max-width: 520px">
<ElAlert :title="`试试录入 ASSET-0001(通过)与 TOY-123(拦截)。最近拦截:${rejected === '' ? '无' : rejected}`" type="info" :closable="false" style="margin-bottom: 10px" />
<BizScanInput v-model="items" :validator="validator" :height="160" @reject="(code, reason) => (rejected = `${code}(${reason})`)" />
</div>
</template>
显示代码
行插槽
- SKU-A102滤芯组件 · 库位 A-01-036
- SKU-B205密封圈套装 · 库位 B-02-112
共 2 种 / 8 件
行插槽接管(品名 / 库位等附加信息展示)。
<script setup lang="ts">
/** 场景:行插槽——品名 / 库位附加信息展示 */
import { ref } from 'vue'
import { BizScanInput } from 'vue3-ep-biz-lib'
import type { BizScanItem, BizScanInputSlotProps } from 'vue3-ep-biz-lib'
interface InvItem extends BizScanItem {
name?: string
location?: string
}
const items = ref<InvItem[]>([
{ code: 'SKU-A102', count: 6, name: '滤芯组件', location: 'A-01-03' },
{ code: 'SKU-B205', count: 2, name: '密封圈套装', location: 'B-02-11' },
])
</script>
<template>
<div style="max-width: 560px">
<BizScanInput v-model="items" placeholder="扫码录入盘点明细" :height="200">
<template #default="{ item }: BizScanInputSlotProps">
<span style="display: flex; flex-direction: column; min-width: 0; flex: 1">
<span style="font-size: 13px; font-weight: 600">{{ item.code }}</span>
<span style="font-size: 12px; color: var(--el-text-color-secondary)">
{{ (item as InvItem).name ?? '未知品名' }} · 库位 {{ (item as InvItem).location ?? '—' }}
</span>
</span>
</template>
</BizScanInput>
</div>
</template>
显示代码
事件与清单
- 事件日志在此显示
scan / reject / clear 事件日志,expose
scan 程序化录入。<script setup lang="ts">
/** 场景:事件日志——scan / reject / clear + expose 程序化录入 */
import { ref } from 'vue'
import { ElButton, ElInput } from 'element-plus'
import { BizScanInput } from 'vue3-ep-biz-lib'
import type { BizScanInputInstance, BizScanItem } from 'vue3-ep-biz-lib'
const items = ref<BizScanItem[]>([])
const logs = ref<string[]>([])
const manual = ref('')
const scanRef = ref<BizScanInputInstance>()
const push = (text: string): void => {
logs.value = [text, ...logs.value].slice(0, 6)
}
</script>
<template>
<div style="max-width: 560px">
<div style="display: flex; gap: 8px; margin-bottom: 10px">
<ElInput v-model="manual" placeholder="程序化录入的码值" size="small" style="width: 220px" />
<ElButton size="small" @click="() => { manual = ''; scanRef?.scan(); push('scan():已提交输入框当前内容') }">scan() 提交</ElButton>
<ElButton size="small" @click="scanRef?.focus()">focus 聚焦</ElButton>
</div>
<BizScanInput
ref="scanRef"
v-model="items"
:height="150"
@scan="(code) => push(`scan:${code}`)"
@reject="(code, reason) => push(`reject:${code}(${reason})`)"
@clear="() => push('clear:清单已清空')"
/>
<ul style="margin: 10px 0 0; padding: 8px 12px; list-style: none; border: 1px solid var(--el-border-color-lighter); border-radius: 4px; font-size: 12px; color: var(--el-text-color-secondary)">
<li v-if="logs.length === 0" style="padding: 2px 0">事件日志在此显示</li>
<li v-for="(log, i) in logs" :key="i" style="padding: 2px 0">{{ log }}</li>
</ul>
</div>
</template>
显示代码
收货验收表单
与表单组合:单据信息 + 扫码清单 + 提交(业务侧拿 v-model 提交)。
<script setup lang="ts">
/** 场景:收货验收表单——单据信息 + 扫码清单 + 提交 */
import { reactive, ref } from 'vue'
import { ElButton, ElForm, ElFormItem, ElInput, ElMessage } from 'element-plus'
import { BizScanInput } from 'vue3-ep-biz-lib'
import type { BizScanItem } from 'vue3-ep-biz-lib'
const form = reactive({ supplier: '', orderNo: '' })
const items = ref<BizScanItem[]>([])
const submit = (): void => {
if (form.orderNo === '') {
ElMessage.warning('请填写收货单号')
return
}
if (items.value.length === 0) {
ElMessage.warning('请扫码录入验收明细')
return
}
ElMessage.success(`验收提交:${items.value.length} 种 / ${items.value.reduce((s, i) => s + i.count, 0)} 件`)
}
</script>
<template>
<div style="max-width: 560px">
<ElForm label-width="80px" size="default">
<ElFormItem label="供应商">
<ElInput v-model="form.supplier" placeholder="如:华顺精密" />
</ElFormItem>
<ElFormItem label="收货单号">
<ElInput v-model="form.orderNo" placeholder="如:SH-20260930-001" />
</ElFormItem>
<ElFormItem label="验收明细">
<BizScanInput v-model="items" placeholder="逐件扫码,重码自动累计" :height="150" />
</ElFormItem>
<ElFormItem>
<ElButton type="primary" @click="submit">提交验收</ElButton>
</ElFormItem>
</ElForm>
</div>
</template>
显示代码
Props
| 属性名 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| v-model | BizScanItem[] | [] | 已扫清单(code 唯一 + count) |
| placeholder | string | '扫码枪扫码或输入码值后回车' | 输入占位 |
| duplicate | 'plus' | 'reject' | 'plus' | 重复码策略 |
| inputtable | boolean | true | 允许手工键入(纯扫码枪场景可关) |
| disabled | boolean | false | 禁用 |
| height | number | — | 清单高度(超出滚动) |
| validator | (code) => string | null | — | 校验函数(返回错误文案则拒绝) |
| trim | boolean | true | 提交前去首尾空白 |
Events
| 事件名 | 参数 | 说明 |
|---|---|---|
| scan | (code, item) | 录入成功(新码或数量加一) |
| reject | (code, reason) | 拒绝(校验失败 / 重复) |
| clear | — | 清空清单 |
Slots
| 插槽名 | 作用域 | 说明 |
|---|---|---|
| default | { item, index } | 清单行内容接管 |
Expose
| 名称 | 类型 | 说明 |
|---|---|---|
| focus | () => void | 聚焦输入框 |
| scan | () => void | 程序化提交当前输入 |
| getTotal | () => number | 合计件数 |