WeRunAuth.vue 6.32 KB
<template>
  <view class="werun-auth-container">
    <!-- 未授权状态 -->
    <view v-if="!isAuthorized" class="auth-prompt">
      <view class="px-5 py-6 bg-white rounded-xl shadow-md mx-4 mt-4">
        <view class="flex flex-col items-center justify-center py-8">
          <view class="mb-4">
            <image
              src="https://placehold.co/100x100/e2f3ff/0369a1?text=步数&font=roboto"
              class="w-20 h-20 rounded-full"
            />
          </view>
          <text class="text-lg font-medium mb-2">获取微信运动数据</text>
          <text class="text-gray-500 text-center mb-6 px-4">
            授权后可查看您的步数信息,与家人一起记录健康生活
          </text>
          <view
            class="bg-blue-500 text-white px-8 py-3 rounded-full text-sm"
            @click="requestAuth"
          >
            立即授权
          </view>
        </view>
      </view>
    </view>

    <!-- 已授权状态 - 显示步数相关内容 -->
    <view v-else>
      <slot :isLoading="isLoading" />
    </view>
  </view>
</template>

<script setup>
import { ref, onMounted, defineEmits } from 'vue'
import Taro from '@tarojs/taro'

// import { syncWxStepAPI } from '@/api/points'
import { fetch } from '@/api/fn'

// 定义事件
const emit = defineEmits(['auth-change', 'steps-update', 'steps-synced', 'sync-failed'])

// 响应式数据
const isAuthorized = ref(false)
const isLoading = ref(false)
const showManualUpdate = ref(false)

/**
 * @description 检查微信运动授权状态
 * @param {boolean} shouldGetData - 是否在授权后获取步数数据
 */
const checkAuthStatus = async (shouldGetData = false) => {
  try {
    const authSetting = await Taro.getSetting()
    const hasWeRunAuth = authSetting.authSetting['scope.werun']

    isAuthorized.value = hasWeRunAuth === true

    // 通知父组件授权状态变化
    emit('auth-change', isAuthorized.value)

    // 根据参数决定是否获取步数数据
    if (isAuthorized.value && shouldGetData) {
      await getWeRunData()
    }
  } catch (error) {
    console.error('检查授权状态失败:', error)
    isAuthorized.value = false
    emit('auth-change', false)
  }
}

/**
 * @description 请求微信运动授权
 */
const requestAuth = async () => {
  try {
    isLoading.value = true

    // 请求微信运动授权
    await Taro.authorize({
      scope: 'scope.werun'
    })

    isAuthorized.value = true
    emit('auth-change', true)

    // 授权成功后获取步数数据
    await getWeRunData()

    Taro.showToast({
      title: '授权成功',
      icon: 'success'
    })
  } catch (error) {
    console.error('授权失败:', error)

    // 用户拒绝授权,引导到设置页面
    Taro.showModal({
      title: '授权提示',
      content: '需要获取微信运动数据权限才能使用步数功能,请在设置中开启',
      confirmText: '去设置',
      success: (res) => {
        if (res.confirm) {
          Taro.openSetting({
            success: (settingRes) => {
              if (settingRes.authSetting['scope.werun']) {
                checkAuthStatus()
              }
            }
          })
        }
      }
    })
  } finally {
    isLoading.value = false
  }
}

/**
 * @description 获取微信运动数据
 */
const getWeRunData = async () => {
  try {
    isLoading.value = true

    // 检查是否为测试用户(openid以h-开头),如果是则跳过步数同步
    try {
      const { getUserProfileAPI } = await import('@/api/user')
      const profileResponse = await getUserProfileAPI()
      if (profileResponse.code === 1 && profileResponse.data?.user?.openid) {
        const openid = profileResponse.data.user.openid
        if (openid.startsWith('h-')) {
          console.log('检测到测试用户openid:', openid, '跳过步数同步')
          Taro.showToast({
            title: '测试用户无需同步步数',
            icon: 'none',
            duration: 2000
          })
          isLoading.value = false
          return
        }
      }
    } catch (profileError) {
      console.warn('获取用户信息失败,继续执行步数同步:', profileError)
    }

    // 先调用 wx.login 获取 code
    const loginRes = await Taro.login()

    // 获取微信运动数据
    const weRunRes = await Taro.getWeRunData()

    console.log('微信运动数据获取成功:', {
      encryptedData: weRunRes.encryptedData,
      iv: weRunRes.iv,
      code: loginRes.code
    })

    // 同步微信步数 - 直接调用原始API以获取完整响应
    try {
      const response = await fetch.post('/srv/?a=point&t=sync_wx_step', { encryptedData: weRunRes.encryptedData, iv: weRunRes.iv });
      const { code, data, msg } = response.data;

      if (code == 1) {
        // 提示获取步数成功
        console.warn('同步微信步数成功', data);

        // 同步成功,隐藏手动更新按钮
        showManualUpdate.value = false;

        // 触发步数同步完成事件,通知父组件
        emit('steps-synced', data);

        isLoading.value = false
      } else {
        // 检查是否是401错误且包含同步微信步数失败的消息
        if (msg && msg.includes('同步微信步数失败')) {
          console.warn('同步微信步数失败,显示手动更新按钮');
          showManualUpdate.value = true;
          emit('sync-failed', { showManualUpdate: true });
        }
        Taro.showToast({
          title: msg || '同步步数失败',
          icon: 'none',
          duration: 2000
        });
      }
    } catch (apiError) {
      console.error('同步微信步数API调用失败:', apiError);
      Taro.showToast({
        title: '网络请求失败',
        icon: 'none'
      });
    }
  } catch (error) {
    console.error('获取微信运动数据失败:', error)

    Taro.showToast({
      title: '获取步数失败',
      icon: 'none'
    })
  } finally {
    isLoading.value = false
  }
}

/**
 * @description 刷新步数数据
 */
const refreshSteps = async () => {
  if (isAuthorized.value) {
    await getWeRunData()
  }
}

// 暴露方法给父组件
defineExpose({
  refreshSteps,
  checkAuthStatus,
  showManualUpdate
})

// 组件挂载时检查授权状态,但不获取步数数据
onMounted(() => {
  checkAuthStatus(false)
})
</script>

<style scoped>
.werun-auth-container {
  width: 100%;
}

.auth-prompt {
  text-align: center;
}
</style>