Browse Source

Merge branch 'cfclub' of http://git.iwintrue.com/liaoxg/cfc into cfclub

liaoxg 1 day ago
parent
commit
93361a4bfd
1 changed files with 48 additions and 2 deletions
  1. 48 2
      cfc-frontend/pages/login/login.vue

+ 48 - 2
cfc-frontend/pages/login/login.vue

@@ -36,12 +36,22 @@
     <!-- 登录表单 -->
     <view class="login-form">
       <view class="phone-section">
+        <!--
+          disabled 必须同时受 agreed 和 loading 约束。
+          open-type="getPhoneNumber" 在「点击那一刻」就由渲染层向微信发起授权请求,
+          早于 @getphonenumber 回调执行 —— 也就是说每一次点击都会消耗一次平台调用配额,
+          JS 里的 if (!this.agreed) return 只能弹 toast,拦不住已经发生的调用。
+          未同意协议时按钮若仍可点,用户会因「点了没反应」而反复点击,最终触发微信限频:
+          [渲染层错误] invoke getPhoneNumber too frequently。
+          故未勾选协议时直接禁用按钮,让无效点击根本不会发生。
+        -->
         <button
           class="phone-btn"
           open-type="getPhoneNumber"
           @getphonenumber="getPhoneNumber"
+          @tap="onPhoneBtnTap"
           :loading="loading"
-          :disabled="loading"
+          :disabled="!agreed || loading || tapLock"
         >
           <text class="phone-btn-icon">📱</text>
           <text>手机号快捷登录</text>
@@ -75,6 +85,8 @@ export default {
   data() {
     return {
       loading: false,
+      // tapLock:在「点击」瞬间上锁,用于关闭授权弹窗弹出前的连点窗口(见 onPhoneBtnTap)
+      tapLock: false,
       agreed: false,
       nickname: '',
       avatar: '',
@@ -99,6 +111,13 @@ export default {
       // 预取后如果用户隔几分钟再点击授权,code 已失效会报 invalid code (40029)。
       // 正确做法:getPhoneNumber 中用户点击授权时实时获取。
     },
+  onUnload() {
+    // 清理 tap 锁兜底定时器,避免登录成功 reLaunch 后定时器仍在已销毁页面上置值
+    if (this._tapLockTimer) {
+      clearTimeout(this._tapLockTimer)
+      this._tapLockTimer = null
+    }
+  },
   methods: {
     handleImageError(e) {
       console.log('Logo 加载失败,使用默认显示')
@@ -120,12 +139,39 @@ export default {
       // 不登录直接进入首页
       uni.switchTab({ url: '/pages/index-home/index' })
     },
+    // 点击瞬间上锁,关闭「授权弹窗弹出前」的连点窗口。
+    //
+    // 为什么不能只在 getPhoneNumber 里判 loading:
+    // open-type="getPhoneNumber" 在点击那一刻就由渲染层向微信发起了授权调用,
+    // @getphonenumber 回调要等用户在系统弹窗里点完才返回。这中间几百毫秒内
+    // loading 还是 false、按钮仍可点,用户「以为没反应」就连点,
+    // 每次点击都真实消耗一次平台调用配额 → invoke getPhoneNumber too frequently。
+    // 在 @tap 上锁能让按钮在一个渲染周期内变为不可点,早于弹窗出现。
+    onPhoneBtnTap() {
+      if (this.loading || this.tapLock) return
+      this.tapLock = true
+      // 兜底:若因系统异常导致 getphonenumber 始终不回调,3 秒后强制解锁,
+      // 避免按钮永久锁死导致无法再登录。
+      if (this._tapLockTimer) clearTimeout(this._tapLockTimer)
+      this._tapLockTimer = setTimeout(() => {
+        this.tapLock = false
+        this._tapLockTimer = null
+      }, 3000)
+    },
     getPhoneNumber: function(e) {
+      // 授权流程已结束,释放 tap 锁与兜底定时器,按钮恢复可点。
+      // 注意:这里原有的 `if (this.loading) return` 已移除 —— loading 在本函数内才置 true,
+      // 保留它会把首个合法点击也拦掉;防重复消费改由下面的 tapLock 承担。
+      if (this._tapLockTimer) {
+        clearTimeout(this._tapLockTimer)
+        this._tapLockTimer = null
+      }
+      this.tapLock = false
+
       if (!this.agreed) {
         uni.showToast({ title: '请先同意用户协议', icon: 'none' })
         return
       }
-      if (this.loading) return
       if (!e.detail || !e.detail.code) {
         uni.showToast({ title: '授权失败,请重试', icon: 'none' })
         return