Vue3使用vue-qrcode-reader实现扫码绑定设备功能

news2024/11/24 5:21:47
需求描述

移动端进入网站后,登录网站进入设备管理界面。点击添加设备,可以选择直接添加或者扫一扫。点击扫一扫进行扫描二维码获取设备序列号自动填充到添加设备界面的序列号输入框中。然后点击完成进行设备绑定。

  1. 安装vue-qrcode-reader 这里使用的版本是5.5.7
npm install vue-qrcode-reader --save
  1. 扫一扫界面ScanCode.vue
<template>
  <div class="block-main">
    <div class="head-wrap">
      <img
        src="../../assets/images/mobile/icon-arrow-left.png"
        class="btn-back"
        @click="goback"
      />
      <span class="title">扫一扫</span>
    </div>
    <div class="qr-container">
      <qrcode-stream
        @detect="onDecode"
        @camera-on="onCameraReady"
        @error="onError"
      />
    </div>
  </div>
</template>

<script>
import { reactive, ref, onMounted } from "vue";
import { useRouter } from "vue-router";
import { QrcodeStream } from "vue-qrcode-reader";
import { showToast } from "vant";
export default {
  components: {
    QrcodeStream,
    showToast,
  },
  setup() {
    const testVice = reactive([]);
    const router = useRouter();
    // 扫码成功后的回调
    const onDecode = (detectedCodes) => {
      if (detectedCodes.length > 0) {
        // 跳转到添加设备页面并传递设备编号
        let deviceCode = detectedCodes[0].rawValue;
        router.replace({
          path: "/deviceadd",
          query: { deviceCode },
        });
      } else {
        showToast("扫码失败");
      }
    };
    const onCameraReady = (res) => {
      console.log("摄像头准备好了");
    };
    const onError = (error) => {
      if (error.name === "NotAllowedError") {
        // user denied camera access permission
        showToast("用户拒绝相机访问权限");
      } else if (error.name === "NotFoundError") {
        // no suitable camera device installed
        showToast("未安装合适的摄像设备");
      } else if (error.name === "NotSupportedError") {
        // page is not served over HTTPS (or localhost)
         showToast("当前网页没有通过 HTTPS 或 localhost 安全协议提供服务");
      } else if (error.name === "NotReadableError") {
        // maybe camera is already in use
        showToast("相机被占用了)");
      } else if (error.name === "OverconstrainedError") {
        // did you request the front camera although there is none?
         showToast("尝试使用前置摄像头)");
      } else if (error.name === "StreamApiNotSupportedError") {
        showToast("浏览器似乎缺少功能)");
        // browser seems to be lacking features
      }
    };
    onMounted(() => {
      navigator.mediaDevices
        .enumerateDevices()
        .then((devices) => {
          devices.forEach((device) => {
            if (device.kind === "videoinput") {
              console.log(
                "Video input device: ",
                device.label,
                device.deviceId
              );
            }
          });
        })
        .catch((error) => {
          console.error("Error enumerating devices: ", error);
          showToast("Error enumerating devices");
        });
    });
    const goback = () => {
      router.go(-1);
    };
    return {
      testVice,
      onCameraReady,
      goback,
      onDecode,
      onError,
    };
  },
};
</script>

<style lang="scss" scoped>
.block-main {
  height: 100%;
  background: #fff;
  overflow: hidden;
  font-size: 16px;
  .head-wrap {
    height: 0.96rem;
    background: #31be7c;
    font-family: Microsoft YaHei UI;
    font-weight: 400;
    color: #fff;
    display: flex;
    align-items: center;
    position: fixed;
    left: 0;
    right: 0;
    .btn-back {
      margin-left: 0.4rem;
      width: 0.22rem;
      height: 0.38rem;
    }
    .title {
      font-size: 0.36rem;
      text-align: center;
      flex: 1;
    }
  }
  .qr-container {
    display: flex;
    justify-content: center;
    align-items: center;
    height: calc(100vh - 0.96rem); // 减去头部的高度
    margin-top: 0.96rem;
  }
}
</style>
  1. 添加设备界面DeviceAdd.vue
<template>
  <div class="block-main">
    <div class="head-wrap">
      <a href="javascript:void(0)" class="btn-cancel" @click="goBack">取消</a>
      <span class="title"></span>
      <a href="javascript:void(0)" class="btn-sure" @click="deviceReg">完成</a>
    </div>
    <div class="input-wrap" @click="showDeviceType">
      <span class="input">{{ deviceInfo.devtypeName }}</span>
      <img
        src="../../assets/images/mobile/icon-arrow-right.png"
        class="icon-arrow"
      />
    </div>
    <div class="input-wrap">
      <input
        type="text"
        class="input"
        v-model="deviceInfo.devsn"
        placeholder="请输入设备序列号"
      />
      <img
        v-if="deviceInfo.devsn"
        src="../../assets/images/mobile/icon-close-gray.png"
        class="icon-close"
        @click="clearInput"
      />
    </div>
    <div class="error-msg">{{ deviceInfo.devsn_error }}</div>
    <van-popup v-model:show="deviceTypeDialog" position="bottom">
      <van-picker
        :columns="devTypes"
        v-model:value="deviceInfo.devtype"
        @cancel="deviceTypeDialog = false"
        @confirm="onConfirm"
      />
    </van-popup>
  </div>
</template>

<script>
import { ref, reactive, onMounted } from "vue";
import { useRoute,useRouter } from "vue-router";
import {
  Picker,
  Popup,
  showFailToast,
  showSuccessToast,
  showToast,
  showLoadingToast,
} from "vant";
import { device_Reg } from "../../api/auth";
export default {
  components: {
    "van-picker": Picker,
    "van-popup": Popup,
  },
  setup() {
    const route = useRoute();
    const deviceTypeDialog = ref(false);
    const router = useRouter();
    const devTypes = [
      { value: 1, text: "设备类型1" },
      { value: 2, text: "设备类型2" },
      { value: 3, text: "设备类型3" },
    ];
    const deviceInfo = reactive({
      devtype: null,
      devtypeName: "请选择需要绑定的设备",
      devsn: "",
      devsn_error: "",
    });
    const showDeviceType = () => {
      deviceTypeDialog.value = true;
    };
    const clearInput = () => {
      deviceInfo.devsn = "";
      deviceInfo.devsn_error = "";
    };
    const onConfirm = ({ selectedOptions }) => {
      deviceTypeDialog.value = false;
      deviceInfo.devtype = selectedOptions[0].value;
      deviceInfo.devtypeName = selectedOptions[0].text;
    };
    const goBack = () => {
      router.go(-1);
    };

    const deviceReg = async () => {
      if (deviceInfo.devtype == null) {
        deviceInfo.devsn_error = "请选择设备类型";
        return;
      }
      if (!deviceInfo.devsn) {
        deviceInfo.devsn_error = "请填写设备序列号";
        return;
      }
      const toast = showLoadingToast({
        message: "数据提交中...",
        forbidClick: true,
      });
      let response = await device_Reg({
        devsn: deviceInfo.devsn,
        devtype: deviceInfo.devtype,
      });
      if (response.isSuccess == true) {
        toast.close();
        showSuccessToast("设备绑定成功");
        setTimeout(() => {
          router.go(-1);
        }, 2000);
      } else {
        deviceInfo.devsn_error = response.message;
        toast.close();
      }
    };
    onMounted(() => {
      const scannedDeviceSn = route.query.deviceCode;
      if (scannedDeviceSn) {
        deviceInfo.devsn = scannedDeviceSn;
      }
    });
    return {
      devTypes,
      deviceTypeDialog,
      deviceInfo,
      showDeviceType,
      clearInput,
      onConfirm,
      goBack,
      deviceReg,
    };
  },
};
</script>

<style lang="scss" scoped>
.block-main {
  height: auto;
  overflow: hidden;
  .head-wrap {
    height: 0.96rem;
    background: #31be7c;
    font-family: Microsoft YaHei UI;
    font-weight: 400;
    color: #fff;
    display: flex;
    align-items: center;
    .btn-cancel {
      padding-left: 0.4rem;
      padding-right: 0.4rem;
      height: 0.96rem;
      line-height: 0.96rem;
      font-size: 0.36rem;
      color: #fff;
    }
    .title {
      font-size: 0.36rem;
      text-align: center;
      flex: 1;
    }
    .btn-sure {
      width: 1.15rem;
      height: 0.55rem;
      background: #ffffff;
      border-radius: 5px;
      font-size: 0.36rem;
      line-height: 0.55rem;
      margin-right: 0.4rem;
      margin-left: 0.4rem;
      color: #31be7c;
    }
  }
  .input-wrap {
    height: 1.2rem;
    line-height: 1.2rem;
    border-bottom: 1px solid #ced6d2;
    display: flex;
    align-items: center;
    .input {
      flex: 1;
      margin-left: 0.58rem;
      font-size: 0.3rem;
      width: 0px;
      border-style: none;
      outline: none;
      height: 1rem;
      text-align: left;
    }
    .icon-close {
      width: 0.36rem;
      height: 0.36rem;
      margin-right: 0.4rem;
      margin-left: 0.4rem;
    }
    .icon-arrow {
      width: 0.2rem;
      height: 0.3rem;
      margin-left: 0.04rem;
      margin-right: 0.4rem;
      margin-left: 0.4rem;
    }
  }
  .error-msg {
    padding-left: 0.58rem;
    margin-top: 0.19rem;
    font-size: 0.24rem;
    color: #ff6c00;
    padding-right: 0.58rem;
    text-align: left;
    line-height: 0.24rem;
  }
}
</style>

效果图

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2127803.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

《OpenCV计算机视觉》—— 身份证号码识别案例

文章目录 一、案例实现的整体思路二、代码实现1.首先定义两个函数2.模板图像中数字的定位处理3.身份证号码数字的定位处理4.使用模板匹配&#xff0c;计算匹配得分&#xff0c;找到正确结果 一、案例实现的整体思路 下面是一个数字0~9的模板图片 案例身份证如下&#xff1a; 对…

http有什么方法升级成https?

&#x1f512; 获取与安装证书 JoySSL注册填写申请码230907即可领取免费申请资格https://www.joyssl.com/certificate/select/free.html?nid7 &#x1f4c4; 申请SSL证书 选择证书&#xff1a;首先需选择合适的SSL证书&#xff0c;如域名认证&#xff08;DV&#xff09;、公…

120页ppt丨集团公司战略规划内容、方法、步骤及战略规划案例研究

响应会员需求&#xff0c;晓零分享一份经典资料《120页ppt集团公司战略规划内容、方法、步骤及战略规划案例研究》&#xff0c;欢迎进入星球下载学习。 以下是对企业战略规划三个阶段八个步骤的详细解析&#xff1a; 一、阶段一&#xff1a;内外分析 项目启动和前期准备&…

Parallels Desktop 20 发布下载,macOS Sequoia 和 Windows 11 24H2 支持准备就绪

Parallels Desktop for Mac 20.0.0 (build 55653) - 在 Mac 上运行 Windows macOS Sequoia 和 Windows 11 24H2 支持准备就绪 请访问原文链接&#xff1a;https://sysin.org/blog/parallels-desktop/&#xff0c;查看最新版。原创作品&#xff0c;转载请保出处。 作者主页&a…

Java | Leetcode Java题解之第400题第N位数字

题目&#xff1a; 题解&#xff1a; class Solution {public int findNthDigit(int n) {int d 1, count 9;while (n > (long) d * count) {n - d * count;d;count * 10;}int index n - 1;int start (int) Math.pow(10, d - 1);int num start index / d;int digitInde…

wifiip地址可以随便改吗?wifi的ip地址怎么改变

对于普通用户来说&#xff0c;WiFi IP地址的管理和修改往往显得神秘而复杂。本文旨在深入探讨WiFi IP地址是否可以随意更改&#xff0c;以及如何正确地改变WiFi的IP地址。虎观代理小二将详细解释WiFi IP地址的基本概念、作用以及更改时需要注意的事项&#xff0c;帮助用户更好地…

欧盟《人工智能法案》的重点监管要求

文章目录 前言一、欧盟《人工智能法案》的重点监管要求(一)基于风险的监管路径1.具有不可接受风险的人工智能系统2.高风险人工智能系统3.有限风险与低风险人工智能系统(二)对高风险人工智能的监管要求1.针对高风险人工智能系统的要求2.针对高风险人工智能系统产业链参与者的…

shader 案例学习笔记之fract函数

fract函数 可以理解为模1取余&#xff0c;获取一个数的小数部分&#xff0c;如果参数是向量&#xff0c;那就是获取每个向量分量上的小数 案例一 #ifdef GL_ES precision mediump float; #endif// 渲染分辨率 uniform vec2 u_resolution; // 程序运行时间 uniform float u_ti…

【卷起来】VUE3.0教程-08-路由管理

在Vue中&#xff0c;我们可以通过vue-router路由管理页面之间的关系。 Vue Router是Vue.js的官方路由&#xff0c;它与Vue.js核心深度集成&#xff0c;让用Vue.js构建单页应用变得轻而易举。 &#x1f332; 在Vue中引入路由 安装路由 npm install --save vue-router 建立三个…

【C++登堂入室】类和对象(中)——类的6个默认成员函数

目录 一、类的6个默认成员函数 ​编辑二、构造函数 2.1 概念 2.2 特性 三、析构函数 3.1 概念 3.2 特性 四、拷贝构造函数 4.1 概念 4.2 特征 五、赋值运算符重载 5.1 运算符重载 5.2 赋值运算符重载 5.3 前置和后置重载 六、日期类的实现 七、const成员 八、…

气膜建筑:设备吊装口临时封闭的理想选择—轻空间

在设备吊装作业中&#xff0c;吊装口的临时封闭对于保障工作环境安全、设备保护及操作顺利至关重要。传统封闭方式&#xff0c;如钢结构或简易的盖板封闭&#xff0c;不仅耗时耗力&#xff0c;还可能影响施工效率。气膜建筑技术凭借其轻便、快速和高效的特点&#xff0c;为设备…

亚信安全亮相2024国家网安周主会场,多样活动助推行业新发展

9月9日至15日&#xff0c;2024年国家网络安全宣传周在全国范围内统一开展。本届网安周以“网络安全为人民&#xff0c;网络安全靠人民”为主题&#xff0c;亚信安全网安周系列活动在全国30多个城市全面展开&#xff0c;通过线下展览、专题论坛和网络安全知识宣讲等多种形式&…

【软件方案】大屏可视化智能展示平台解决方案(word原件完整版)

构建综合大屏可视化展示平台&#xff0c;旨在整合各业务板块&#xff0c;打造统一大数据分析引擎。此平台将深度融合数据驾驶舱与智慧调度系统&#xff0c;实现对企业运营的全面洞察与高效指挥。我们深入钻研客户信息数据&#xff0c;秉承“大数据”精髓&#xff0c;推动业务模…

【测试八股】软件测试面试八股文

&#x1f345; 点击文末小卡片&#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 以下是软件测试相关的面试题及答案&#xff0c;希望对各位能有帮助&#xff01; 1、测试分为哪几个阶段? 一般来说分为5个阶段&#xff1a;单元测试、集成测试…

警惕!血糖升高初期,这10大微妙信号你捕捉到了吗?

在这个快节奏的时代&#xff0c;饮食不规律、缺乏运动等生活习惯悄然间让高血糖这一“隐形杀手”潜伏在我们身边。然而&#xff0c;高血糖并非悄无声息&#xff0c;它在早期往往会通过一系列微妙却重要的身体信号向我们发出警告。今天&#xff0c;就让我们一同揭开血糖高早期的…

【Unity错误】No cloud project ID was found by the Analytics SDK

在编译默认的URP 2D项目时&#xff0c;出现这样一个错误&#xff1a;No cloud project ID was found by the Analytics SDK. This means Analytics events will not be sent. Please make sure to link your cloud project in the Unity editor to fix this problem. 原因&…

yolov5明厨亮灶检测系统,厨师帽-口罩检测,带pyqt界面-可检测图片和视频,支持中文标签,检测接口已封装好并优化,代码可读性强!

明厨亮灶检测系统是一个专门用于餐饮业厨房安全监管的智能系统。该系统结合了先进的计算机视觉技术&#xff0c;尤其是使用YOLOv5模型进行厨师帽和口罩的实时检测&#xff0c;并通过PyQt5构建了一个用户友好的图形界面。该系统不仅能够检测图片和视频中的目标&#xff0c;而且支…

如何看待 IBM 中国研发部裁员?

文章目录 引言背景趋势与影响人才发展对 IT 人才市场的影响IT 从业者积极应对全球化挑战 产业发展IT 产业的应对策略提升核心竞争力 结语 引言 近日&#xff0c;IBM 中国宣布撤出在华两大研发中心&#xff0c;引发了 IT 行业对于跨国公司在华研发战略的广泛讨论。这一决定不仅…

共享打印机无法连多种错误代码原因分析及解决方法

日常办公和生活中&#xff0c;打印机是不可或缺的重要设备。然而&#xff0c;在添加共享或使用共享打印机过程中&#xff0c;经常会遇各种问题。然后我们在添加共享打印机遇到最多的向种错误&#xff1a;0x0000011b、0x000004005、0x000006d9、0x00000040等等&#xff0c;然后这…

ggplot2 缩小的/一般长度的、带箭头的坐标轴 | R语言

1. 效果图 左侧为DimPlot2()效果图。 右侧为DimPlot()效果图&#xff0c;原图。 2. 代码 axis.line element_line(arrow arrow(type "open", length unit(0.3, "cm"))), 其中: type"open"表示是开放箭头&#xff0c;type“closed” 表示是…