<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      使用zxing實現掃碼功能

      1.安裝zxing

      "devDependencies": {
          "@zxing/library": "^0.21.3",
      }

       

      2.手機端頁面使用示例(該掃碼功能也可用于PC端掃碼)

      <template>
        <div :class="subFormItem ? 'sub-comp' : 'custom-comp'">
          <center>
            <van-icon name="scan" class="scan-icon" @click="startScan" />
            <div>{{ item.placeholder }}</div>
          </center>
          <!-- 添加掃碼界面容器 -->
          <div v-if="isScanning" class="scan-container">
            <div class="scan-mask"></div>
            <div class="scan-box">
              <video id="videoElement" class="scan-video"></video>
              <div class="scan-area"></div>
              <div class="scan-controls">
                <van-button type="primary" @click="stopScan">取消</van-button>
              </div>
            </div>
          </div>
        </div>
      </template>
      
      <script setup>
      import {
        onMounted,
        ref,
        toRefs,
        defineAsyncComponent,
        computed,
        watch,
        onUnmounted,
      } from "vue";
      import { Toast, Dialog } from "vant";
      import { BrowserQRCodeReader, NotFoundException } from "@zxing/library";
      import TaskApi from "@/modules/new_collect/api/taskApi";
      import { useRouter, useRoute } from "vue-router";
      
      const route = useRoute();
      const router = useRouter();
      const props = defineProps({
        formData: Object,
        item: Object,
        isReadOnly: Boolean,
        wholeFormData: Object,
        subFormItem: Object,
        subFormIdx: Number,
      });
      const { formData, item, isReadOnly, wholeFormData, subFormItem, subFormIdx } =
        toRefs(props);
      const isCompReadOnly = ref(false);
      const isScanning = ref(false); // 掃碼狀態
      let codeReader = null; // 掃碼器實例
      
      onMounted(() => {
        isCompReadOnly.value = isReadOnly.value || item.value.isReadOnly;
      });
      
      // 清理掃碼資源
      onUnmounted(() => {
        stopScan();
      });
      
      // 開始掃碼
      const startScan = () => {
        if (isCompReadOnly.value) return;
      
        isScanning.value = true;
      
        // 延遲執行,等待DOM渲染完成
        setTimeout(() => {
          codeReader = new BrowserQRCodeReader();
          const videoInputDeviceId = null; // 可選:指定攝像頭ID
      
          codeReader.decodeFromVideoDevice(
            videoInputDeviceId,
            "videoElement",
            (result, err) => {
              if (result) {
                console.log("掃碼結果:", result.text);
                formData.value[item.value.prop] = result.text;
                Toast.success("掃碼成功");
                stopScan();
                getOptions();
              }
              if (err && !(err instanceof NotFoundException)) {
                console.error(err);
                Toast.fail("掃碼失敗,請重試");
              }
            }
          );
        }, 100);
      };
      
      // 停止掃碼
      const stopScan = () => {
        isScanning.value = false;
      
        // 釋放攝像頭資源
        if (codeReader) {
          codeReader.reset();
          codeReader = null;
        }
      };
      const dataSource = ref();
      const fieldOptions = ref([]);
      const showDropdownPicker = ref(false);
      const getOptions = async () => {
        if (!item.value.sheetId || !item.value.field) {
          return;
        }
        const { data } = await TaskApi.getSheetAndFieldByRules(
          { sheetName: item.value.sheetId },
          [
            {
              field: item.value.field,
              criteria: "=",
              content: formData.value[item.value.prop],
            },
          ]
        );
        if (data.code !== 200) {
          Toast.fail(data.message);
          return;
        }
        // showDropdownPicker.value = true;
        dataSource.value = data.data.map((v) => {
          return {
            ...v,
            checked: false,
          };
        });
        sessionStorage.setItem("formData", JSON.stringify(formData.value));
        if (dataSource.value.length > 1) {
          router.push("/ScanCodeBindSelect/list");
          sessionStorage.setItem(
            "currentDataSource",
            JSON.stringify(dataSource.value)
          );
        } else if (dataSource.value.length == 1) {
          dataSource.value[0].checked = true;
          dataSource.value.forEach((v) => {
            if (v.checked) {
              Object.keys(item.value.fieldRelation).forEach((key) => {
                Object.keys(v).forEach((g) => {
                  if (g == key) {
                    props.formData[item.value.fieldRelation[key]] = v[g];
                  }
                });
              });
            }
          });
          const formData = sessionStorage.getItem("formData")
            ? JSON.parse(sessionStorage.getItem("formData"))
            : {};
          for (let k in formData) {
            props.formData[k] = formData[k];
          }
          sessionStorage.removeItem("currentDataSource");
          sessionStorage.removeItem("formData");
        }
      
        fieldOptions.value = data.data.map((item) => item.id);
      };
      
      watch(
        () => sessionStorage.getItem("currentDataSource"),
        (val) => {
          if (val) {
            if (sessionStorage.getItem("currentDataSource")) {
              let dataSource = JSON.parse(val);
              if (Array.isArray(dataSource))
                dataSource &&
                  dataSource.forEach((v) => {
                    if (v.checked) {
                      Object.keys(item.value.fieldRelation).forEach((key) => {
                        Object.keys(v).forEach((g) => {
                          if (g == key) {
                            props.formData[item.value.fieldRelation[key]] = v[g];
                          }
                        });
                      });
                    }
                  });
              const formData = sessionStorage.getItem("formData")
                ? JSON.parse(sessionStorage.getItem("formData"))
                : {};
              for (let k in formData) {
                props.formData[k] = formData[k];
              }
              sessionStorage.removeItem("currentDataSource");
              sessionStorage.removeItem("formData");
            }
          }
        },
        {
          immediate: true,
          deep: true,
        }
      );
      
      const onDropdownConfirm = (val) => {
        console.log(val);
        showDropdownPicker.value = false;
      };
      </script>
      
      <style scoped lang="less">
      .custom-comp {
        margin: 0px 20px;
        width: 90%;
      }
      .component {
        .custom-comp {
          margin: 0;
          width: 100%;
        }
      }
      
      /* 掃碼界面樣式 */
      .scan-container {
        position: fixed;
        top: 0;
        left: 0;
        width: 100%;
        height: 100%;
        z-index: 9999;
      }
      
      .scan-mask {
        position: absolute;
        top: 0;
        left: 0;
        width: 100%;
        height: 100%;
        background-color: rgba(0, 0, 0, 0.7);
      }
      
      .scan-box {
        position: absolute;
        top: 50%;
        left: 50%;
        transform: translate(-50%, -50%);
        width: 80%;
        max-width: 400px;
        background-color: #fff;
        border-radius: 8px;
        overflow: hidden;
      }
      
      .scan-video {
        width: 100%;
        height: auto;
      }
      
      .scan-area {
        position: absolute;
        top: 50%;
        left: 50%;
        transform: translate(-50%, -50%);
        width: 200px;
        height: 200px;
        border: 2px solid #409eff;
        box-shadow: 0 0 0 1000px rgba(0, 0, 0, 0.5);
        background-color: transparent;
      }
      
      .scan-controls {
        padding: 15px;
        text-align: center;
      }
      .list {
        padding-bottom: 60px;
      }
      .list-item {
        margin: 16px 16px 0 16px;
        border-radius: 8px;
        width: auto;
      }
      .scan-icon {
        font-size: 80px;
      }
      </style>

      tips:必須是localhost或https才能使用掃碼功能

      posted @ 2025-07-14 11:21  羅毅豪  閱讀(79)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 久久99热只有频精品8| 色道久久综合亚洲精品蜜桃| 亚洲熟妇色自偷自拍另类| 国产无套乱子伦精彩是白视频| 好硬好湿好爽好深视频| 男人的天堂av一二三区| 精品国产一区二区三区香| 欧美疯狂三p群体交乱视频| 昌吉市| 人妻中文字幕精品一页| 国产精品综合一区二区三区 | 国产一级二级三级毛片| 天天做天天爱夜夜爽导航| 酒店大战丝袜高跟鞋人妻| 亚洲AV无码破坏版在线观看| 亚洲综合国产激情另类一区| 国产黄色免费看| 亚洲国产精品无码一区二区三区| 久久精品蜜芽亚洲国产AV| 亚洲视频欧美不卡| 冀州市| 欧美性潮喷xxxxx免费视频看| 40岁大乳的熟妇在线观看| 欧美亚洲人成网站在线观看| 国产老熟女一区二区三区| 精选国产av精选一区二区三区 | 狠狠亚洲色一日本高清色| 久久er热在这里只有精品66| 另类 专区 欧美 制服| 亚洲精品二区在线播放| 国产成人久久777777| 国产一区二区在线观看粉嫩| 依依成人精品视频在线观看| 亚洲中文字幕av天堂| 999精品色在线播放| 九九热精品在线视频免费| 91久久国产成人免费观看| 国产91小视频在线观看| 国产精品不卡一区二区久久| 国产91丝袜在线观看| 成年无码av片在线蜜芽|