Web 扫码枪对接

扫码枪对接知识点

  • 扫码枪本质是一个外接的输入设备(类似键盘)
  • 扫码枪按照说明书配置好
  • web对接扫码枪的原理:
    • 监听input框输入事件keyup.enter
    • 扫码枪输出文字的间隔在几十ms
    • 可能会受中文输入法的影响(因为本质就是个输入设备)
  • 是否需要保留web页面的input显示,取决于你的产品是否需要保留手动输入的功能
  • 扫码页面需要不停聚焦input框
<template>
  <div class="scanner">
    <el-button size="mini" @click="handleClick"> {{ buttonText }}<i class="el-icon-camera-solid el-icon--right"></i> </el-button>
    <l-fullscreen-dialog
      :okLabel="$t('确认') + $t('(已扫描:') + scanData.length + $t('条)')"
      :title="$t(title)"
      :visible.sync="visible"
      @ok="handleOk"
      @opened="handleOpened"
      @close="handleClose"
    >
      <template #headerMid>
        <div class="scanner-title">
          <el-tag size="medium" type="primary" effect="plain">{{ $t("单据编码:") + document }}</el-tag>
          <el-tag size="medium" type="primary" effect="plain">{{ $t("产品名称:") + name }}</el-tag>
          <el-tag size="medium" type="primary" effect="plain">{{ $t("已扫描:") + scanData.length + $t(" 条") }}</el-tag>
          <el-tag size="medium" type="primary" effect="plain" v-if="max">{{ $t("本次扫描上限:") + max + $t(" 条") }}</el-tag>
        </div>
      </template>
      <el-table size="mini" border stripe :data="scanData" :empty-text="$t('暂无扫描数据')">
        <el-table-column type="index" label="序号" width="60"></el-table-column>
        <el-table-column prop="value" label="扫描内容"></el-table-column>
        <el-table-column label="操作" width="220" align="right">
          <!-- eslint-disable-next-line vue/no-unused-vars -->
          <template slot="header" slot-scope="scope">
            <input
              ref="scannerInput"
              class="scanner-input"
              v-model="scanInput"
              @keyup.enter="handleScan"
              @blur="handleInputBlur"
              :placeholder="$t('条码失效时,手动输入后回车')"
            />
          </template>
          <template slot-scope="{ $index }">
            <el-button size="mini" type="danger" @click="handleDelete($index)"><i class="el-icon-delete" /> </el-button>
          </template>
        </el-table-column>
      </el-table>
    </l-fullscreen-dialog>
  </div>
</template>

<script>
  export default {
    name: "l-scanner",
    props: {
      title: {
        type: String,
        default: "扫码录入"
      },
      document: {
        type: String,
        default: ""
      },
      name: {
        type: String,
        default: ""
      },
      value: {
        type: Array,
        default: () => []
      },
      max: {
        type: Number
      }
    },
    data() {
      return {
        visible: false,
        scanInput: "",
        scanData: [],
        isManualBlur: false
      };
    },
    computed: {
      buttonText() {
        return this.value.length > 0 ? `已扫码 (${this.value.length} 条)` : "扫码录入";
      }
    },
    methods: {
      handleClick() {
        this.visible = true;
        this.scanData = this.value.map(v => ({ value: v }));
      },
      handleScan() {
        if (this.scanData.length >= this.max) {
          this.scanInput = "";
          this.$message.warning(this.$t("本次扫描数量已达上限"));
          return;
        }

        const code = this.scanInput.trim();
        if (code) {
          if (!this.scanData.some(v => v.value === code)) {
            this.scanData.push({ value: code });
            this.$message.success(this.$t("录入成功"));
          } else {
            this.$message.warning(this.$t("【警告】重复录入"));
          }
          this.scanInput = "";
          this.$nextTick(this.focusScanner);
        }
      },
      handleDelete(index) {
        this.scanData.splice(index, 1);
      },
      focusScanner() {
        const input = this.$refs.scannerInput;
        input && input.focus();
      },
      handleInputBlur() {
        if (!this.isManualBlur) {
          setTimeout(this.focusScanner, 100);
        }
        this.isManualBlur = false;
      },
      handleOpened() {
        this.$nextTick(() => {
          this.focusScanner();
          setTimeout(this.focusScanner, 50);
        });
      },
      handleOk() {
        if (this.scanData.length < 1) return this.$message.warning(this.$t("请先扫码后提交数据"));
        const result = this.scanData.map(item => item.value);
        this.$emit("input", result);
        this.$emit("updateNumber", this.scanData.length);
        this.visible = false;
      },
      handleClose() {
        this.scanInput = "";
        this.scanData = [];
      }
    }
  };
</script>
<style lang="scss" scoped>
  .scanner {
    &-title {
      span {
        margin-right: 10px;
      }
    }
  }
  .scanner-input {
    width: 100%;
  }
</style>

posted @ 2025-05-10 14:02  wanglei1900  阅读(43)  评论(0)    收藏  举报