Przeglądaj źródła

merge(miniprogram): 团队邀请 P2/P1 技术债修复——幂等抛错误报循环收敛 + 审核态补绑入口 合入 cfclub 主线

Agnes Agent 17 godzin temu
rodzic
commit
31bbfc25af
1 zmienionych plików z 54 dodań i 1 usunięć
  1. 54 1
      cfc-frontend/pages/profile/service-role-apply.vue

+ 54 - 1
cfc-frontend/pages/profile/service-role-apply.vue

@@ -14,6 +14,12 @@
         <text class="reject-label">拒绝原因</text>
         <text class="reject-reason">{{ applyRecord && applyRecord.rejectReason }}</text>
       </view>
+      <!-- P1 补绑入口:记录已存在(status 0/1/2)、表单隐藏后,绑定失败时唯一可达的就地补绑路径。
+           @click 直连 bindUserReferral,绝不接 handleSubmit/doSubmit(表单隐藏 + 后端查重 ServiceImpl:74-76 会拒)。 -->
+      <view v-if="!userRefBound && inviteRefCode" class="rebind-section">
+        <text class="rebind-desc">推荐人尚未绑定成功,请在网络稳定后补绑</text>
+        <button class="btn-rebind" :disabled="bindingRef" @click="bindUserReferral">补绑推荐人</button>
+      </view>
       <view class="action-buttons">
         <button v-if="applyStatus === 'rejected'" class="btn-reapply" @click="handleReapply">
           重新申请
@@ -485,10 +491,28 @@ export default {
           return
         }
         // 非 200 且非 skipped 理论上由 request() reject 走 catch,此处防御性兜底按失败处理
-        this.showBindRetryHint(bindRes && bindRes.message)
+        // P2 幂等抛错误报循环收敛:后端已绑定成功但响应丢失、重试命中「已绑定推荐人」时按实质成功收敛。
+        var retryMsg = bindRes && bindRes.message
+        if (retryMsg && String(retryMsg).indexOf('已绑定推荐人') > -1) {
+          this.userRefBound = true
+          uni.removeStorageSync('refCode')
+          uni.showToast({ title: '推荐人已绑定', icon: 'none' })
+          return
+        }
+        this.showBindRetryHint(retryMsg)
       } catch (e) {
         // 401 由 request() 统一 reLaunch 登录页,不在这里叠加 modal
         if (e && e.code === 401) return
+        // P2 幂等抛错误报循环收敛(在 401 检查之后、showBindRetryHint 之前):
+        // 后端已实际绑定成功(CF 资产已发)但响应在传输中丢失 → 重试命中「已绑定推荐人,不可修改」,
+        // 此时按实质成功收敛:置幂等标记 + 清僵尸码 + toast,不弹失败 modal,
+        // 避免 userRefBound 永远 false、流程无法收敛为成功态。
+        if (e && e.message && String(e.message).indexOf('已绑定推荐人') > -1) {
+          this.userRefBound = true
+          uni.removeStorageSync('refCode')
+          uni.showToast({ title: '推荐人已绑定', icon: 'none' })
+          return
+        }
         // 失败:userRefBound 保持 false、inviteRefCode 未清,故可就地重试(不依赖 storage.refCode)。
         // request() 拦截器已对非 200 业务响应 toast 后端具体 message(如「邀请码无效」「已有推荐人」),
         // 这里用 modal 同时承载后端原文 + 明确重试引导:既不覆盖具体错误,又给出可见的重试入口。
@@ -675,6 +699,35 @@ export default {
   line-height: 1.6;
   display: block;
 }
+/* P1 推荐人补绑区:与 status-tip 同款卡片,按钮沿用 .btn-reapply 尺寸与品牌渐变,视觉同体系 */
+.rebind-section {
+  background: $app-surface;
+  border-radius: 16rpx;
+  padding: 24rpx 28rpx;
+  margin-bottom: 40rpx;
+  width: 100%;
+  box-sizing: border-box;
+}
+.rebind-desc {
+  font-size: calc(24rpx * var(--font-scale, 1));
+  color: $status-warning-strong;
+  display: block;
+  margin-bottom: 20rpx;
+}
+.btn-rebind {
+  width: 100%;
+  height: 88rpx;
+  line-height: 88rpx;
+  border-radius: 24rpx;
+  font-size: calc(30rpx * var(--font-scale, 1));
+  text-align: center;
+  border: none;
+  background: linear-gradient(135deg, $brand-primary, $brand-primary-light);
+  color: $app-surface;
+}
+.btn-rebind[disabled] {
+  opacity: 0.5;
+}
 .action-buttons {
   width: 100%;
   display: flex;