更新记录

1.0.0(2026-10-14) 下载此版本

  • 首次发布
  • 提供 IScannable、ScannerDevice 类型定义
  • 依赖 pro-device-core

平台兼容性

uni-app(5.06)

Vue2 Vue3 Chrome Safari app-vue app-nvue Android iOS 鸿蒙
√ √ √ √ √ - √ - -
微信小程序 支付宝小程序 抖音小程序 百度小程序 快手小程序 京东小程序 鸿蒙元服务 QQ小程序 飞书小程序 小红书小程序 快应用-华为 快应用-联盟
√ - - - - - - - - - - -

pro-device-scanner — 扫码设备接口

定义扫码设备的能力接口 IScannable 和组合类型 ScannerDevice。本包只包含接口定义,不含任何具体设备实现。

依赖 pro-device-core。具体扫码设备实现在项目层 src/devices/scanner/ 中。


导出内容

import type { IScannable, ScannerDevice } from '@/uni_modules/pro-device-scanner'
导出 类型 说明
IScannable interface 扫码能力接口
ScannerDevice type IConnectable & IScannable & IIdentifiable 组合

API 参考

IScannable — 扫码能力接口

interface IScannable {
  /** 订阅扫码结果,每次扫到条码/二维码时触发,返回取消订阅函数 */
  onScan(cb: (code: string) => void): Unsubscribe
}

ScannerDevice — 扫码设备完整类型

// 等价于 IConnectable & IScannable & IIdentifiable
type ScannerDevice = IConnectable & IScannable & IIdentifiable

使用示例

1. 连接扫码头并订阅扫码结果

import { createDeviceSession } from '@/devices'
import { ConnectionState } from '@/uni_modules/pro-device-core'

const session = createDeviceSession()

// 商米内置红外扫码头
const scanner = await session.acquire('scanner', {
  brand: 'sunmi',
  model: 'T2',  // 商米型号,会通过 uni.getSystemInfoSync() 自动获取
})

// 订阅扫码事件
const unsub = scanner.onScan((code) => {
  console.log('扫码结果:', code)
  // code 例:'1234567890128'(EAN-13)、'HW08-2026-001'(自定义格式)
})

// 取消订阅
unsub()

2. Vue 组件中绑定扫码回调

import { onMounted, onUnmounted, ref } from 'vue'
import type { ScannerDevice } from '@/uni_modules/pro-device-scanner'

const lastScanCode = ref('')
let scanner: ScannerDevice | null = null
let unsubScan: (() => void) | null = null

onMounted(async () => {
  try {
    scanner = await session.acquire('scanner', {
      brand: 'sunmi',
      model: uni.getSystemInfoSync().deviceModel,
    })

    // 注册扫码回调
    unsubScan = scanner.onScan((code) => {
      lastScanCode.value = code
      handleScan(code)
    })
  } catch (e) {
    console.error('扫码头初始化失败', e)
  }
})

onUnmounted(() => {
  unsubScan?.()      // 先取消订阅
  session.releaseAll()
})

function handleScan(code: string) {
  // 处理扫码逻辑:查询、填充表单、上报等
  uni.showToast({ title: `扫到:${code}`, icon: 'none' })
}

3. 配合 Pinia Store 使用(全局扫码设备)

// 从全局设备 Store 获取扫码设备
import { useAppDeviceStore } from '@/plugins/store/app-device'

const appDeviceStore = useAppDeviceStore()

// 组件内订阅
onMounted(() => {
  const scanner = appDeviceStore.scanner?.device
  if (!scanner) return
  unsubScan = scanner.onScan((code) => {
    formData.value.code = code
  })
})

onUnmounted(() => unsubScan?.())

4. 扫码驱动的表单自动填充

// 扫码结果驱动表单字段填充
const form = reactive({
  containerCode: '',
  wasteCode: '',
})

let scanStep = 0  // 0 = 扫容器码,1 = 扫废物码

const unsub = scanner.onScan((code) => {
  if (scanStep === 0) {
    form.containerCode = code
    uni.showToast({ title: '已扫容器码', icon: 'none' })
    scanStep = 1
  } else if (scanStep === 1) {
    form.wasteCode = code
    uni.showToast({ title: '已扫废物码,请确认', icon: 'none' })
    scanStep = 0
  }
})

5. 监听连接状态

import { ConnectionState } from '@/uni_modules/pro-device-core'

// ScannerDevice 同时是 IConnectable
const unsubState = scanner.onStateChange((state) => {
  if (state === ConnectionState.Connected) {
    uni.showToast({ title: '扫码头已就绪', icon: 'success' })
  } else if (state === ConnectionState.Error) {
    uni.showToast({ title: '扫码头连接异常', icon: 'error' })
  }
})

onUnmounted(() => unsubState())

实现新扫码设备

在项目层 src/devices/scanner/ 创建具体实现并注册:

// src/devices/scanner/my-ble-scanner.ts
import { BLEDeviceBase } from '../base/ble-device-base'
import type { IScannable } from '@/uni_modules/pro-device-scanner'
import type { DeviceConfig } from '@/uni_modules/pro-device-core'
import type { Unsubscribe } from '@/uni_modules/pro-device-core'

export class MyBLEScanner extends BLEDeviceBase implements IScannable {
  private _scanListeners: Array<(code: string) => void> = []

  constructor(config: DeviceConfig) {
    super(config)
    // 订阅传输层数据,解析扫码结果
    this._transport.onReceive((data) => {
      const code = decodeScanPacket(data)  // 设备专用协议解析
      if (code) this._scanListeners.forEach(cb => cb(code))
    })
  }

  onScan(cb: (code: string) => void): Unsubscribe {
    this._scanListeners.push(cb)
    return () => {
      this._scanListeners = this._scanListeners.filter(l => l !== cb)
    }
  }
}

// src/devices/index.ts 中注册
const scannerRegistry = new DeviceRegistry<ScannerDevice>()
  .registerBrand('sunmi', cfg => new SunmiScanner(cfg))
  .registerModel('MyBrand', 'S200', cfg => new MyBLEScanner(cfg))  // 新增

平台支持

本包为纯 TypeScript 接口定义,无平台依赖。

具体设备的平台支持取决于其实现层:商米内置扫码头(SunmiScanner)仅支持 APP-PLUS(Android)。

隐私、权限声明

1. 本插件需要申请的系统权限列表:

无

2. 本插件采集的数据、发送的服务器地址、以及数据用途说明:

插件不采集任何数据

3. 本插件是否包含广告,如包含需详细说明广告表达方式、展示频率:

无

许可协议

MIT协议

暂无用户评论。