165 lines
5.0 KiB
JavaScript
165 lines
5.0 KiB
JavaScript
/**
|
||
* 手机号强制认证 - 完全自包含逻辑模块
|
||
*
|
||
* 特点:
|
||
* 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<object>} 后端返回的完整数据
|
||
*/
|
||
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 }; |