Files
Wechat/utils/phone-auth.js

217 lines
6.3 KiB
JavaScript

/**
* 手机号强制认证:每次调用 check / ensurePhoneAuth 均请求后端 /peizhi/yhbdsjh
*/
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';
const RETURN_PAGE_KEY = 'phone_auth_return_page';
function buildHeaders(extra = {}) {
const token = wx.getStorageSync('token');
const header = { 'Content-Type': 'application/json', ...extra };
if (token) header['Authorization'] = 'Bearer ' + token;
try {
const { buildClubHeaders } = require('./club-context.js');
return buildClubHeaders(header);
} catch (e) {
const clubId = wx.getStorageSync('club_id') || 'xq';
header['X-Club-Id'] = clubId;
return header;
}
}
function innerRequest(url, data = {}) {
return new Promise((resolve, reject) => {
wx.request({
url: API_BASE + url,
method: 'POST',
data,
header: buildHeaders(),
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: buildHeaders({ 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 };
}
/** 根据当前主端/身份推断认证完成后回跳角色 */
function resolveReturnRole() {
const primary = wx.getStorageSync('primaryRole') || wx.getStorageSync('currentRole') || '';
if (primary === 'dashou' || primary === 'shangjia') return primary;
if (Number(wx.getStorageSync('shangjiastatus')) === 1) return 'shangjia';
if (Number(wx.getStorageSync('staffstatus')) === 1) return 'shangjia';
if (
Number(wx.getStorageSync('dashoustatus')) === 1
|| Number(wx.getStorageSync('guanshistatus')) === 1
|| Number(wx.getStorageSync('zuzhangstatus')) === 1
|| Number(wx.getStorageSync('kaoheguanstatus')) === 1
) {
return 'dashou';
}
return 'mine';
}
function defaultReturnPage(role) {
if (role === 'dashou') return '/pages/accept-order/accept-order';
if (role === 'shangjia') return '/pages/merchant-home/merchant-home';
try {
const { getLoginPageUrl } = require('./fighter-only.js');
return getLoginPageUrl();
} catch (e) {
return '/pages/fighter/fighter';
}
}
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, returnPage) {
const role = returnRole || resolveReturnRole();
wx.setStorageSync(RETURN_ROLE_KEY, role);
if (returnPage) {
wx.setStorageSync(RETURN_PAGE_KEY, returnPage);
} else {
wx.removeStorageSync(RETURN_PAGE_KEY);
}
if (!isOnPhoneAuthPage()) {
wx.reLaunch({ url: AUTH_PAGE });
}
}
/**
* 向后端确认是否需要手机号认证;需要则跳转认证页
* @returns {Promise<boolean>} true=无需认证或已满足;false=已跳转认证页
*/
async function ensurePhoneAuth(options = {}) {
const { redirect = true, role, returnPage } = options;
const token = wx.getStorageSync('token');
if (!token) return true;
const needAuth = await check();
if (!needAuth) return true;
if (redirect) {
redirectToPhoneAuth(role || resolveReturnRole(), returnPage);
}
return false;
}
function getPhoneAuthReturnPage() {
const savedPage = wx.getStorageSync(RETURN_PAGE_KEY);
wx.removeStorageSync(RETURN_PAGE_KEY);
if (savedPage) {
wx.removeStorageSync(RETURN_ROLE_KEY);
return savedPage;
}
const role = wx.getStorageSync(RETURN_ROLE_KEY) || resolveReturnRole();
wx.removeStorageSync(RETURN_ROLE_KEY);
return defaultReturnPage(role);
}
async function submit(phoneCode, avatarPath) {
if (!phoneCode || !avatarPath) {
throw new Error('缺少参数');
}
const data = await innerUpload(AUTH_SUBMIT_URL, avatarPath, {
shoujihao_code: phoneCode,
});
// 无论手机号是否成功,都先更新已保存字段(如头像)的缓存
// 后端在手机号失败时仍会保存头像,返回 code 6 + data(含已保存字段)
const respData = (data && data.data) || data || {};
if (respData.touxiang) wx.setStorageSync('touxiang', respData.touxiang);
if (respData.phone) wx.setStorageSync('phone', respData.phone);
if (data && data.code === 0) {
return respData;
}
throw new Error((data && data.msg) || '认证失败');
}
module.exports = {
check,
submit,
ensurePhoneAuth,
redirectToPhoneAuth,
getPhoneAuthReturnPage,
resolveReturnRole,
};