Files
MBTI_wang/miniprogram/utils/phoneAuth.js
卡若 aca2e263bb feat: 管理端聚合页、小程序/抖音埋点与统计、飞书线索 webhook、API 迁移与路由
- admin:OrdersHub/UsersHub、Commerce/Ops/Enterprise Hub、MpAnalytics、Feishu/小程序配置面板、鉴权存储
- api:Analytics、DataMigration、FeishuLeadWebhook、mp 事件迁移 SQL
- 微信/抖音小程序:analytics 上报与相关页面调整
- 开发文档与 scripts 补充

Made-with: Cursor
2026-03-27 17:22:04 +08:00

117 lines
3.8 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* 手机号授权工具:基于微信 getPhoneNumber + 服务器端换取手机号接口
* 手机号与个人资料:详见 isProfileComplete 规则
*/
/**
* 个人资料是否已满足业务门禁(避免反复跳转「完善资料」)
* - 已绑定手机号:视为可用(付费/深度服务以手机为准;仅首字头像无 URL 不再卡死)
* - 未绑手机:需昵称+头像,引导去资料页补齐并授权手机
* @returns {boolean}
*/
function isProfileComplete() {
const app = getApp()
const user = app.globalData.userInfo || wx.getStorageSync('userInfo')
if (!user) return false
const phone = (user.phone || user.phoneNumber || '').trim()
if (phone.length > 0) return true
const nickname = (user.nickname || user.nickName || user.username || '').trim()
const avatar = (user.avatar || user.avatarUrl || '').trim()
return nickname.length > 0 && avatar.length > 0
}
/**
* 若资料未完善则跳转到个人资料页,需登录
* @returns {boolean} true=已完善可继续false=已跳转
*/
function ensureProfileCompleteAndRedirect() {
const app = getApp()
const token = app.globalData.token || wx.getStorageSync('token')
if (!token) return true
if (isProfileComplete()) return true
wx.showToast({ title: '请先完善个人资料', icon: 'none' })
wx.navigateTo({ url: '/pages/user-profile/index' })
return false
}
/**
* 当前用户是否已有手机号(从 globalData.userInfo 或 storage 读取)
* @returns {boolean}
*/
function hasPhone() {
const app = getApp()
const user = app.globalData.userInfo || wx.getStorageSync('userInfo')
const phone = (user && (user.phone || user.phoneNumber)) ? String(user.phone || user.phoneNumber).trim() : ''
return phone.length > 0
}
/**
* 使用 getPhoneNumber 回调里的 code 调用后端接口换取手机号,并写回 userInfo
* @param {string} code
* @returns {Promise<object>} resolve 为更新后的 userInfo
*/
function bindPhoneByCode(code) {
return new Promise((resolve, reject) => {
if (!code) {
wx.showToast({ title: '获取手机号失败', icon: 'none' })
reject(new Error('empty code'))
return
}
const app = getApp()
const token = app.globalData.token || wx.getStorageSync('token')
if (!token) {
wx.showToast({ title: '请先登录', icon: 'none' })
reject(new Error('no token'))
return
}
const apiBase = app.globalData.apiBase || ''
if (!apiBase) {
wx.showToast({ title: '服务未配置', icon: 'none' })
reject(new Error('no api base'))
return
}
wx.showLoading({ title: '处理中...', mask: true })
wx.request({
url: `${apiBase.replace(/\/$/, '')}/api/auth/wechat/phone`,
method: 'POST',
header: {
'Authorization': 'Bearer ' + token,
'Content-Type': 'application/json',
},
data: { code },
success: (res) => {
wx.hideLoading()
if (res.statusCode === 200 && res.data && res.data.code === 200) {
const data = res.data.data || {}
const user = data.user || app.globalData.userInfo || {}
const phone = data.phone || user.phone || ''
const newUser = { ...user, phone }
app.globalData.userInfo = newUser
wx.setStorageSync('userInfo', newUser)
wx.showToast({ title: '授权成功', icon: 'success' })
resolve(newUser)
} else {
const msg = res.data && res.data.message ? res.data.message : '获取手机号失败'
wx.showToast({ title: msg, icon: 'none' })
reject(new Error(msg))
}
},
fail: () => {
wx.hideLoading()
wx.showToast({ title: '网络请求失败', icon: 'none' })
reject(new Error('network error'))
},
})
})
}
module.exports = {
hasPhone,
bindPhoneByCode,
isProfileComplete,
ensureProfileCompleteAndRedirect,
}