|
|
@@ -125,11 +125,17 @@
|
|
|
<text>提交后将在 1-3 个工作日内完成审核</text>
|
|
|
</view>
|
|
|
</view>
|
|
|
+
|
|
|
+ <!-- 团队邀请:未登录提交时就地弹出登录浮层,登录后自动续提交。
|
|
|
+ 用本地浮层而非 401 → reLaunch 整页登录,是为了不销毁本组件:
|
|
|
+ 表单已填数据、inviteRefCode 均保留,登录后回到表单且不丢码。
|
|
|
+ login-sheet 由 main.js 全局注册;全局 loginSheetMixin 的 openLoginSheet 会命中本 ref。 -->
|
|
|
+ <login-sheet ref="loginSheet" @success="onInviteLoginSuccess" @close="onInviteLoginClose" />
|
|
|
</view>
|
|
|
</template>
|
|
|
|
|
|
<script>
|
|
|
-import { submitServiceRoleApply, getMyServiceRoleApply, uploadServiceRoleImage } from '../../utils/api'
|
|
|
+import { submitServiceRoleApply, getMyServiceRoleApply, uploadServiceRoleImage, bindReferralIfNotSelf } from '../../utils/api'
|
|
|
import { pickImage } from '../../utils/image-picker.js'
|
|
|
import AddressPicker from '@/components/address-picker.vue'
|
|
|
import fontScaleMixin from '@/mixins/font-scale.js'
|
|
|
@@ -162,7 +168,17 @@ export default {
|
|
|
},
|
|
|
submitting: false,
|
|
|
applyRecord: null,
|
|
|
- showStatusView: false
|
|
|
+ showStatusView: false,
|
|
|
+ // 团队邀请:直达链接 /pages/profile/service-role-apply?refCode=xxx 携带的邀请码(记录级归属)。
|
|
|
+ // 用户级推荐人链路的 storage.refCode 会被 user-edit.vue:733 消费并清除,绝不能复用;
|
|
|
+ // 故记录级另存独立 key 'serviceRoleApplyRefCode',与用户级彻底解耦、并存互不覆盖。
|
|
|
+ // 本组件字段用于常规提交;若未登录触发整页登录导致组件销毁,登录后回跳无参时由
|
|
|
+ // onLoad 从独立 key 恢复本字段,保证 refCode 端到端不丢。
|
|
|
+ inviteRefCode: '',
|
|
|
+ // 独立 storage key:记录级归属专用,不会被 user-edit 的用户级消费逻辑清除
|
|
|
+ inviteRefCodeStorageKey: 'serviceRoleApplyRefCode',
|
|
|
+ // 未登录点提交后挂起:浮层登录成功回调里续跑提交,避免用户二次点击
|
|
|
+ pendingSubmitAfterLogin: false
|
|
|
}
|
|
|
},
|
|
|
computed: {
|
|
|
@@ -224,7 +240,19 @@ export default {
|
|
|
}[this.applyStatus] || ''
|
|
|
}
|
|
|
},
|
|
|
- onLoad() {
|
|
|
+ onLoad(options) {
|
|
|
+ // 团队邀请:解析直达链接的邀请码,存组件字段 + 独立 storage key(记录级归属专用)。
|
|
|
+ // 不用 storage.refCode:那是「用户级推荐人」链路(App.vue 捕获→user-edit.vue:733 消费并清除),
|
|
|
+ // 与记录级彻底解耦、互不覆盖。
|
|
|
+ if (options && options.refCode) {
|
|
|
+ this.inviteRefCode = options.refCode
|
|
|
+ uni.setStorageSync(this.inviteRefCodeStorageKey, options.refCode)
|
|
|
+ } else {
|
|
|
+ // 未登录提交触发整页登录 / 401 reLaunch 时组件会被销毁;登录成功回跳若不带 refCode 参数,
|
|
|
+ // 从独立 key 恢复,确保「登录后回到表单且 inviteRefCode 不丢」。
|
|
|
+ var cached = uni.getStorageSync(this.inviteRefCodeStorageKey)
|
|
|
+ if (cached) this.inviteRefCode = cached
|
|
|
+ }
|
|
|
this.checkExistingApply()
|
|
|
},
|
|
|
methods: {
|
|
|
@@ -378,6 +406,48 @@ export default {
|
|
|
return
|
|
|
}
|
|
|
|
|
|
+ // 团队邀请:未登录时先就地弹登录浮层,登录后自动续提交。
|
|
|
+ // 不走接口层 401 → reLaunch 整页登录的原因:那会销毁本组件、丢失已填表单与 inviteRefCode,
|
|
|
+ // 且登录成功后回不到本表单。就地浮层由本页 <login-sheet> 承载,组件不销毁。
|
|
|
+ if (!uni.getStorageSync('token')) {
|
|
|
+ this.pendingSubmitAfterLogin = true
|
|
|
+ // refCode 一并透传给浮层:未登录态 App.vue 已把分享码存入用户级 storage.refCode,
|
|
|
+ // 这里再以 options.refCode 覆盖同源值(互不冲突),用户级 referrerId 仍由现状链路消费。
|
|
|
+ this.openLoginSheet({ refCode: this.inviteRefCode })
|
|
|
+ return
|
|
|
+ }
|
|
|
+ await this.doSubmit(newRoles)
|
|
|
+ },
|
|
|
+ // 就地浮层登录成功回调:自动续跑被挂起的提交(此时 token 已写入 storage)。
|
|
|
+ // 用户级 referrerId 由 App.vue onShow / user-edit.vue 的现状链路消费 storage.refCode 写入,
|
|
|
+ // 本页不重复调用 bindReferralIfNotSelf,避免记录级链路触发分销副作用。
|
|
|
+ onInviteLoginSuccess() {
|
|
|
+ if (!this.pendingSubmitAfterLogin) return
|
|
|
+ this.pendingSubmitAfterLogin = false
|
|
|
+
|
|
|
+ // 用户级 referrerId 消费(推荐人=邀请人):就地浮层登录不走 user-edit.vue:714 的消费点,
|
|
|
+ // 也不触发 App.vue onShow 带参补绑,故在此显式消费 App.vue:85 已存入的用户级 storage.refCode。
|
|
|
+ // 以下三行严格同构 user-edit.vue:714-733 的「读码 → bindReferralIfNotSelf → 清码」,
|
|
|
+ // 只清 refCode,不碰 inviteCode/inviteType(避免影响其他链路)。
|
|
|
+ // 两级隔离:用户级 → storage.refCode → users.referrerId(走 /api/invite/bind,固有分销副作用);
|
|
|
+ // 记录级 → storage.serviceRoleApplyRefCode → doSubmit 透传 refCode → 后端反查写
|
|
|
+ // inviter_user_id(绝不经 /api/invite/bind,绝不触发 applyReferralSideEffects)。
|
|
|
+ // 不 await、不阻塞记录级提交;绑定失败由 request() 统一 toast,可见但不影响申请受理。
|
|
|
+ const userRefCode = uni.getStorageSync('refCode')
|
|
|
+ if (userRefCode) {
|
|
|
+ bindReferralIfNotSelf(userRefCode).catch(function() {})
|
|
|
+ uni.removeStorageSync('refCode')
|
|
|
+ }
|
|
|
+
|
|
|
+ const newRoles = (this.selectedRoles || []).filter(r => this.approvedRoles.indexOf(r) === -1)
|
|
|
+ this.doSubmit(newRoles).catch(function() {})
|
|
|
+ },
|
|
|
+ // 浮层关闭(含「暂不登录先逛逛」handleSkipLogin):复位挂起标记,
|
|
|
+ // 避免用户放弃登录后标记残留,导致下次提交误走自动续提交分支。
|
|
|
+ onInviteLoginClose() {
|
|
|
+ this.pendingSubmitAfterLogin = false
|
|
|
+ },
|
|
|
+ async doSubmit(newRoles) {
|
|
|
this.submitting = true
|
|
|
uni.showLoading({ title: '提交中...' })
|
|
|
try {
|
|
|
@@ -390,19 +460,29 @@ export default {
|
|
|
city: this.form.city,
|
|
|
district: this.form.district,
|
|
|
street: this.form.street,
|
|
|
- addressDetail: this.form.addressDetail
|
|
|
+ addressDetail: this.form.addressDetail,
|
|
|
+ // 团队邀请记录级归属:透传直达链接的 refCode,由后端服务端反查邀请人 userId 写
|
|
|
+ // inviter_user_id。不传前端自算 inviterUserId(防冒领),不触发任何分销副作用。
|
|
|
+ refCode: this.inviteRefCode
|
|
|
})
|
|
|
uni.hideLoading()
|
|
|
if (res.code === 200) {
|
|
|
- // 提交成功,刷新状态
|
|
|
+ // 提交成功,刷新状态。此刻邀请归属已落库,清除独立 key 防止下次无码进入时误挂旧邀请人。
|
|
|
+ uni.removeStorageSync(this.inviteRefCodeStorageKey)
|
|
|
await this.checkExistingApply()
|
|
|
if (!this.showStatusView) this.showStatusView = true
|
|
|
} else {
|
|
|
+ // 少数业务码(如 5001 无家庭)会被 request() resolve 而非 reject,此时 request 未弹提示,需在此兜底
|
|
|
uni.showToast({ title: res.message || '提交失败', icon: 'none' })
|
|
|
}
|
|
|
} catch (e) {
|
|
|
uni.hideLoading()
|
|
|
- uni.showToast({ title: '提交失败,请重试', icon: 'none' })
|
|
|
+ // 邀请码无效/自邀请等后端业务错误:request() 已 showToast(e.message),这里用同一 message
|
|
|
+ // 再弹一次作双保险(同内容覆盖,不会泛化),确保「邀请码绑定失败必须有可见错误反馈」。
|
|
|
+ // 绝不用「提交失败,请重试」覆盖后端具体原因;401/纯网络异常由 request() 统一提示,此处静默。
|
|
|
+ if (e && e.message && e.code !== 401) {
|
|
|
+ uni.showToast({ title: e.message, icon: 'none' })
|
|
|
+ }
|
|
|
} finally {
|
|
|
this.submitting = false
|
|
|
}
|