/** * 手机号强制认证 - 完全自包含逻辑模块 * * check / ensurePhoneAuth 每次均请求后端 /peizhi/yhbdsjh 判断 need_auth */ const API_BASE = 'https://www.abas.asia/hqhd'; const AUTH_CHECK_URL = '/peizhi/yhbdsjh'; const AUTH_SUBMIT_URL = '/yonghu/xiugai'; const AUTH_PAGE = '/pages/phone-auth/phone-auth'; const RETURN_ROLE_KEY = 'phone_auth_return_role'; function innerRequest(url, data = {}) { return new Promise((resolve, reject) => { const token = wx.getStorageSync('token'); const header = { 'Content-Type': 'application/json' }; if (token) header['Authorization'] = 'Bearer ' + token; wx.request({ url: API_BASE + url, method: 'POST', data, header, success: (res) => resolve(res), fail: (err) => reject(err), }); }); } function innerUpload(url, filePath, formData = {}, fileName = 'avatar') { return new Promise((resolve, reject) => { const token = wx.getStorageSync('token'); if (!token) { reject(new Error('未登录')); return; } wx.getFileInfo({ filePath, success: () => { wx.uploadFile({ url: API_BASE + url, filePath, name: fileName, formData, header: { Authorization: 'Bearer ' + token }, success: (res) => { if (res.statusCode === 200) { try { resolve(JSON.parse(res.data)); } catch (e) { reject(new Error('解析响应数据失败')); } } else if (res.statusCode === 401) { wx.removeStorageSync('token'); reject(new Error('认证失败')); } else { reject(new Error(`上传失败,状态码:${res.statusCode}`)); } }, fail: () => reject(new Error('网络请求失败')), }); }, fail: () => reject(new Error('文件不存在或无法访问')), }); }); } function isOnPhoneAuthPage() { const pages = getCurrentPages(); const cur = pages[pages.length - 1]; return !!(cur && cur.route === 'pages/phone-auth/phone-auth'); } function parseCheckResponse(res) { if (!res || res.statusCode === 401) { return { ok: false, needAuth: false }; } if (res.statusCode !== 200) { return { ok: false, needAuth: false }; } const body = res.data; if (!body || typeof body !== 'object') { return { ok: false, needAuth: false }; } const code = Number(body.code); if (code !== 0 && code !== 200) { return { ok: false, needAuth: false }; } const needAuth = body.need_auth === true || (body.data && body.data.need_auth === true); return { ok: true, needAuth: !!needAuth }; } /** * 询问后端是否需要手机号认证 * @returns {Promise} true=需要认证 */ async function check() { const token = wx.getStorageSync('token'); if (!token) return false; try { const res = await innerRequest(AUTH_CHECK_URL, {}); const parsed = parseCheckResponse(res); if (!parsed.ok) return false; return parsed.needAuth; } catch (e) { return false; } } function redirectToPhoneAuth(returnRole) { if (returnRole) { wx.setStorageSync(RETURN_ROLE_KEY, returnRole); } if (!isOnPhoneAuthPage()) { wx.reLaunch({ url: AUTH_PAGE }); } } /** * 打手端等场景:向后端确认,未认证则跳转认证页 * @returns {Promise} true=已通过或无需认证;false=已跳转认证页 */ async function ensurePhoneAuth(options = {}) { const { redirect = true, role = 'dashou' } = options; const token = wx.getStorageSync('token'); if (!token) return true; const needAuth = await check(); if (!needAuth) return true; if (redirect) redirectToPhoneAuth(role); return false; } function getPhoneAuthReturnPage() { const role = wx.getStorageSync(RETURN_ROLE_KEY) || ''; wx.removeStorageSync(RETURN_ROLE_KEY); if (role === 'dashou') return '/pages/accept-order/accept-order'; if (role === 'shangjia') return '/pages/merchant-orders/merchant-orders'; return '/pages/mine/mine'; } async function submit(phoneCode, avatarPath) { if (!phoneCode || !avatarPath) { throw new Error('缺少参数'); } const data = await innerUpload(AUTH_SUBMIT_URL, avatarPath, { shoujihao_code: phoneCode, }); if (data && data.code === 0) { const respData = data.data || data; if (respData.phone) wx.setStorageSync('phone', respData.phone); if (respData.touxiang) wx.setStorageSync('touxiang', respData.touxiang); return respData; } throw new Error((data && data.msg) || '认证失败'); } module.exports = { check, submit, ensurePhoneAuth, redirectToPhoneAuth, getPhoneAuthReturnPage, };