浏览代码

H5端扫一扫功能完成

fanghuisheng 1 天之前
父节点
当前提交
a1a4d98c70
共有 5 个文件被更改,包括 159 次插入2 次删除
  1. 1 0
      package.json
  2. 90 0
      src/components/oa-scan/index.vue
  3. 8 0
      src/pages.json
  4. 2 2
      src/pages/business/meeting/index.vue
  5. 58 0
      src/utils/oaScanCode.js

+ 1 - 0
package.json

@@ -55,6 +55,7 @@
     "@dcloudio/uni-quickapp-webview": "3.0.0-alpha-4020320240703001",
     "@microsoft/fetch-event-source": "^2.0.1",
     "echarts": "^5.3.3",
+    "html5-qrcode": "^2.3.8",
     "jsencrypt": "^3.3.2",
     "pinia": "2.0.14",
     "pinia-plugin-persistedstate": "^3.1.0",

+ 90 - 0
src/components/oa-scan/index.vue

@@ -0,0 +1,90 @@
+<template>
+  <view class="scan-container">
+    <!-- #ifdef H5 -->
+    <view id="reader" class="reader"></view>
+    <view class="tip">将二维码放入框内</view>
+    <!-- #endif -->
+  </view>
+</template>
+
+<script setup>
+import { onMounted, onUnmounted } from "vue";
+import { onUnload } from "@dcloudio/uni-app";
+// #ifdef H5
+import { Html5Qrcode } from "html5-qrcode";
+import { finishScanSuccess, finishScanFail, cancelScan } from "@/utils/oaScanCode.js";
+// #endif
+
+// #ifdef H5
+let scanner = null;
+let handled = false;
+
+function deliverResult(result) {
+  if (handled) return;
+  handled = true;
+  finishScanSuccess(result);
+}
+
+async function startScan() {
+  try {
+    scanner = new Html5Qrcode("reader");
+    await scanner.start(
+      { facingMode: "environment" },
+      {
+        fps: 10,
+        qrbox: { width: 250, height: 250 },
+      },
+      (decodedText) => {
+        scanner
+          ?.stop()
+          .then(() => {
+            scanner?.clear();
+            scanner = null;
+            deliverResult(decodedText);
+          })
+          .catch(() => {
+            deliverResult(decodedText);
+          });
+      },
+      () => {}
+    );
+  } catch (e) {
+    uni.showToast({ title: "摄像头权限被拒", icon: "none" });
+    finishScanFail(e);
+  }
+}
+
+onMounted(() => {
+  startScan();
+});
+
+onUnload(() => {
+  cancelScan();
+});
+
+onUnmounted(() => {
+  if (scanner) {
+    scanner.stop().catch(() => {});
+    scanner.clear();
+    scanner = null;
+  }
+});
+// #endif
+</script>
+
+<style lang="scss" scoped>
+.scan-container {
+  padding: 20rpx;
+}
+
+.reader {
+  width: 100%;
+  height: 60vh;
+}
+
+.tip {
+  text-align: center;
+  margin-top: 20rpx;
+  color: #666;
+}
+</style>

+ 8 - 0
src/pages.json

@@ -19,6 +19,14 @@
                 "navigationBarTextStyle": "black"
             }
         },
+        {
+            "path": "components/oa-scan/index",
+            "style": {
+                "navigationBarTitleText": "扫一扫",
+                "navigationBarBackgroundColor": "#000000",
+                "navigationBarTextStyle": "white"
+            }
+        },
         {
             "path": "pages/register",
             "style": {

+ 2 - 2
src/pages/business/meeting/index.vue

@@ -137,6 +137,7 @@ import { onLoad, onShow, onReady, onHide, onLaunch, onUnload, onNavigationBarBut
 import { ref, reactive, computed, getCurrentInstance, toRefs, inject } from "vue";
 /*----------------------------------接口引入-----------------------------------*/
 import { MeetingRoomList, MeetingRoomReservationList, deviceApi, signOnOut } from "@/api/business/meeting.js";
+import { oaScanCode } from "@/utils/oaScanCode.js";
 /*----------------------------------组件引入-----------------------------------*/
 import timeSlot from "./components/timeSlot.vue";
 import switchSlot from "./components/switchSlot.vue";
@@ -314,10 +315,9 @@ function changeSheet(e) {
   } else if (e.name == "我的会议") {
     proxy.$tab.navigateTo(`/pages/business/meeting/my/index`).then(() => {});
   } else if (e.name == "扫一扫") {
-    uni.scanCode({
+    oaScanCode({
       autoZoom: false,
       scanType: ["qrCode"],
-      // onlyFromCamera: true,
       success: (res) => {
         if (res.result == "会议空闲中") {
           proxy.$modal.msg("当前无可参加的会议!");

+ 58 - 0
src/utils/oaScanCode.js

@@ -0,0 +1,58 @@
+/**
+ * 与 uni.scanCode 参数一致;H5 跳转摄像头扫码页,其它端走原生 uni.scanCode
+ */
+
+let pending = null;
+
+export function oaScanCode(options = {}) {
+  // #ifdef H5
+  pending = options;
+  uni.navigateTo({
+    url: "/components/oa-scan/index",
+    fail: (err) => {
+      finishScanFail(err);
+    },
+  });
+  return;
+  // #endif
+
+  // #ifndef H5
+  uni.scanCode(options);
+  // #endif
+}
+
+/** 扫码页成功时调用 */
+export function finishScanSuccess(result) {
+  const opts = pending;
+  pending = null;
+  const run = () => {
+    opts?.success?.({ result });
+    opts?.complete?.();
+  };
+  uni.navigateBack({
+    success: run,
+    fail: run,
+  });
+}
+
+/** 扫码页失败时调用 */
+export function finishScanFail(err) {
+  const opts = pending;
+  pending = null;
+  const run = () => {
+    opts?.fail?.(err);
+    opts?.complete?.();
+  };
+  const pages = getCurrentPages();
+  if (pages.length > 1) {
+    uni.navigateBack({ complete: run });
+  } else {
+    run();
+  }
+}
+
+/** 用户返回未扫码 */
+export function cancelScan() {
+  if (!pending) return;
+  finishScanFail({ errMsg: "scanCode:fail cancel" });
+}