wxScanTest.vue 4.1 KB
<template>
  <div class="scan-test-page">
    <div class="card">
      <div class="row">
        <div class="label">环境</div>
        <div class="value">{{ in_wechat ? '微信内' : '非微信' }}</div>
      </div>
      <div class="row last">
        <div class="label">JSSDK</div>
        <div class="value" :class="{ ok: wx_ready === true, fail: wx_ready === false }">
          {{ wx_ready_text }}
        </div>
      </div>
    </div>

    <div class="card">
      <div class="card-title">扫码结果</div>
      <van-field
        v-model="scan_result"
        type="textarea"
        rows="3"
        autosize
        readonly
        placeholder="点击下方按钮开始扫码"
      />
      <div class="btn-wrap">
        <van-button
          block
          color="#A67939"
          :loading="scanning"
          :disabled="scanning"
          @click="start_scan"
        >
          调起扫码
        </van-button>
      </div>
    </div>
  </div>
</template>

<script setup>
import { computed, onMounted, ref } from 'vue'
import wx from 'weixin-js-sdk'
import { showToast } from 'vant'
import { wxInfo } from '@/utils/tools'

const scan_result = ref('')
const scanning = ref(false)
const wx_ready = ref(null)

const in_wechat = computed(() => wxInfo().isTable === true)

const wx_ready_text = computed(() => {
  if (!in_wechat.value) return '非微信环境无需初始化'
  if (wx_ready.value === true) return '已就绪'
  if (wx_ready.value === false) return '初始化失败'
  return '未检测'
})

/**
 * @description 确保微信 JSSDK 已完成初始化(依赖 App.vue 注入的全局 Promise)
 * @returns {Promise<boolean>} 是否已就绪
 */
const ensure_wx_ready = async () => {
  // App.vue 在启动时会初始化 wx.config,并把 ready 结果写到 window.__wx_ready_promise
  if (!window.__wx_ready_promise) return false
  const ok = await window.__wx_ready_promise
  return ok === true
}

/**
 * @description 调起微信扫码并展示结果(仅微信环境可用)
 * @returns {Promise<void>}
 */
const start_scan = async () => {
  if (!in_wechat.value) {
    showToast('请在微信内打开该页面')
    return
  }
  if (scanning.value) return

  scanning.value = true
  try {
    const ok = await ensure_wx_ready()
    wx_ready.value = ok
    if (!ok) {
      showToast('wx 初始化失败')
      return
    }
    // JSSDK 扫码:needResult=1 表示直接拿到结果文本,不跳转微信扫码结果页
    const result = await new Promise((resolve) => {
      wx.scanQRCode({
        needResult: 1,
        scanType: ['qrCode', 'barCode'],
        success: (res) => resolve(res?.resultStr || ''),
        fail: () => resolve(''),
        cancel: () => resolve(''),
      })
    })
    scan_result.value = String(result || '')
    if (!scan_result.value) showToast('未获取到二维码内容')
  } finally {
    scanning.value = false
  }
}

/**
 * @description 页面初始化:同步展示“是否在微信内”和“JSSDK 是否就绪”
 * @returns {Promise<void>}
 */
const init_scan_test_page = async () => {
  if (!in_wechat.value) {
    wx_ready.value = false
    return
  }
  wx_ready.value = await ensure_wx_ready()
}

onMounted(init_scan_test_page)
</script>

<style lang="less" scoped>
.scan-test-page {
  min-height: 100vh;
  background-color: #F6F6F6;
  padding: 16px;
  box-sizing: border-box;

  .card {
    background: #fff;
    border-radius: 12px;
    padding: 16px;
    box-shadow: 0 6px 18px rgba(0, 0, 0, 0.04);
  }

  .card + .card {
    margin-top: 12px;
  }

  .card-title {
    font-size: 14px;
    color: #6B7280;
    margin-bottom: 12px;
  }

  .row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 10px 0;
    border-bottom: 1px solid #F3F4F6;

    .label {
      font-size: 14px;
      color: #6B7280;
    }

    .value {
      font-size: 16px;
      color: #111827;
      font-weight: 600;
      margin-left: 12px;
      word-break: break-all;
      text-align: right;
    }

    .ok {
      color: #16A34A;
    }

    .fail {
      color: #E24A4A;
    }
  }

  .row.last {
    border-bottom: 0;
  }

  .btn-wrap {
    margin-top: 12px;
  }
}
</style>