/** * 手机号强制认证 - 完全自包含逻辑模块 * * 特点: * 1. 不引用项目中的 request.js / upload.js,避免其顶层 getApp() 带来的加载顺序错误 * 2. 所有请求直接使用 wx.request / wx.uploadFile,基础 URL 写死(与 app.globalData.apiBaseUrl 保持一致) * 3. check() 内部捕获所有异常,永远返回 false 或 true,不会抛出错误 * 4. submit() 抛出错误由认证页面自己处理,不影响主流程 * * 用法: * app.js 中: * try { * const { check } = require('./utils/phone-auth'); * if (await check()) { wx.reLaunch(...); return; } * } catch(e) {} * * 认证页面中: * const { submit } = require('../../utils/phone-auth'); * await submit(phoneCode, avatarPath); */ // ==================== 基础配置 ==================== const API_BASE = 'https://www.abas.asia/hqhd'; // 与你 app.js 里的 apiBaseUrl 一致 const AUTH_CHECK_URL = '/peizhi/yhbdsjh'; // 检查是否需要认证 const AUTH_SUBMIT_URL = '/yonghu/xiugai'; // 提交认证(复用修改信息接口) // ==================== 内部封装:wx.request ==================== function innerRequest(url, data = {}) { return new Promise((resolve, reject) => { const token = wx.getStorageSync('token'); // 运行时获取 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 整个响应对象,让上层自己解析 resolve(res); }, fail: (err) => { reject(err); } }); }); } // ==================== 内部封装:wx.uploadFile ==================== 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) => { // ✅ 修复:wx.uploadFile 成功时 statusCode 为 200 if (res.statusCode === 200) { try { const data = JSON.parse(res.data); resolve(data); // 直接返回解析后的对象,方便下游使用 } catch (e) { reject(new Error('解析响应数据失败')); } } else if (res.statusCode === 401) { wx.removeStorageSync('token'); reject(new Error('认证失败')); } else { reject(new Error(`上传失败,状态码:${res.statusCode}`)); } }, fail: (err) => { reject(new Error('网络请求失败')); } }); }, fail: () => { reject(new Error('文件不存在或无法访问')); } }); }); } // ==================== 公开方法 ==================== /** * 检查是否需要手机号认证 * - 无 token 或 任何异常 → 返回 false * - 后端明确 need_auth: true → 返回 true */ async function check() { const token = wx.getStorageSync('token'); if (!token) return false; try { const res = await innerRequest(AUTH_CHECK_URL, {}); // 假设后端返回格式:{ data: { need_auth: true/false } } 或直接在顶层 const body = res.data; return body && body.need_auth === true; } catch (e) { // 任何错误(网络、后端异常)都吞掉,不影响主流程 return false; } } /** * 提交认证(手机号 code + 头像文件) * @param {string} phoneCode 微信 getPhoneNumber 返回的 code * @param {string} avatarPath 头像临时路径 * @returns {Promise} 后端返回的完整数据 */ async function submit(phoneCode, avatarPath) { if (!phoneCode || !avatarPath) { throw new Error('缺少参数'); } // 将手机号 code 放入 formData const formData = { shoujihao_code: phoneCode }; // 调用上传 const data = await innerUpload(AUTH_SUBMIT_URL, avatarPath, formData); // ✅ 修复:正确判断后端返回的 code 字段,后端成功时 code === 0 if (data && data.code === 0) { // data.data 包含 { touxiang: '相对路径', phone: '...' } const respData = data.data || data; // 存储手机号 if (respData.phone) { wx.setStorageSync('phone', respData.phone); } // ✅ 修复:存储头像相对路径,与 xiugai 页面处理方式一致 if (respData.touxiang) { wx.setStorageSync('touxiang', respData.touxiang); } return respData; } else { throw new Error((data && data.msg) || '认证失败'); } } module.exports = { check, submit };