Files
property-resident-side/property-uniapp-project/common/checkLogin.js
2026-08-13 08:03:26 +08:00

134 lines
3.7 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.
/**
* 登录检查工具 — 统一拦截未登录用户的功能操作
*
* 使用方式:
* import { requireLogin } from '@/common/checkLogin.js'
* if (!requireLogin()) return
*
* 页面级调用即可,全局 navigateTo 拦截器App.vue onLaunch 中注册)作为兜底。
*
* 防重复机制:
* _loginPending — requireLogin 立即设置,阻止在 setTimeout 等待期内重复调度
* _loginNavigating — navigateToLogin 设置,阻止实际跳转重复
*/
/** 无需登录即可访问的页面路径白名单(全局拦截器使用) */
export const PUBLIC_PATHS = [
'/pageSubPack/loginSub/login',
'/pageSubPack/loginSub/register-new-user',
'/pageSubPack/loginSub/forget-pwd',
'/pageSubPack/loginSub/change-pwd',
'/pageSubPack/loginSub/privacy',
'/pageSubPack/loginSub/user-agreement',
'/pages/navigation/navigation'
]
// ==================== 登录页跳转防重复锁 ====================
// 使用 getApp().globalData 存储,避免模块被分包/异步 chunk 多次实例化导致锁失效
function getLock() {
const app = getApp()
if (!app.globalData) app.globalData = {}
return app.globalData
}
/**
* 判断当前是否已在登录页
*/
function isOnLoginPage() {
const pages = getCurrentPages()
if (!pages || pages.length === 0) return false
const route = pages[pages.length - 1].route || ''
return route.includes('loginSub/login')
}
/**
* 跳转到登录页(统一入口,带防重复锁)
* 所有需要跳转登录页的地方都应调用此函数,不要直接调用 uni.navigateTo / uni.reLaunch
*
* @param {object} [options]
* @param {string} [options.method='navigateTo'] - 跳转方式:'navigateTo' | 'reLaunch' | 'redirectTo'
* @param {string} [options.url='/pageSubPack/loginSub/login?mode=pwd'] - 目标 url
*/
export function navigateToLogin(options = {}) {
const {
method = 'navigateTo',
url = '/pageSubPack/loginSub/login?mode=pwd'
} = options
// 已经在登录页,跳过
if (isOnLoginPage()) return
const lock = getLock()
// reLaunch 优先级最高,强制放行(用于 token 过期、退出登录等场景)
if (method !== 'reLaunch' && lock._loginNavigating) return
lock._loginNavigating = true
const navFn = uni[method]
if (!navFn) {
lock._loginNavigating = false
return
}
navFn({
url,
fail() {
// 跳转失败时重置锁,允许后续重试
lock._loginNavigating = false
}
})
}
/**
* 重置登录跳转锁(登录页 onLoad 时调用)
*/
export function resetLoginLock() {
const lock = getLock()
lock._loginPending = false
lock._loginNavigating = false
}
/**
* 判断指定路径是否为公开页面(无需登录)
* @param {string} url - navigateTo 的目标 url
* @returns {boolean}
*/
export function isPublicPath(url) {
if (!url) return true
// 去掉查询参数
const path = url.split('?')[0]
return PUBLIC_PATHS.some(p => path === p || path.startsWith(p + '?'))
}
/**
* 检查是否已登录;未登录则弹出提示并跳转登录页
* @param {object} [options]
* @param {string} [options.message='请先登录'] - 提示文案
* @param {boolean} [options.redirect=true] - 是否自动跳转登录页
* @returns {boolean} 已登录返回 true否则返回 false
*/
export function requireLogin(options = {}) {
const {
message = '请先登录',
redirect = true
} = options
const token = uni.getStorageSync('token')
if (token) return true
uni.showToast({ title: message, icon: 'none' })
if (redirect) {
// 立即加锁,防止在 setTimeout 等待期内重复调度
const lock = getLock()
if (lock._loginPending) return false
lock._loginPending = true
setTimeout(() => {
lock._loginPending = false
navigateToLogin({ method: 'navigateTo' })
}, 1000)
}
return false
}