fix: 顶栏颜色跟随小程序主题并保留跟随系统
This commit is contained in:
@@ -0,0 +1,112 @@
|
||||
import Taro from '@tarojs/taro'
|
||||
import { getMe, logout, getToken } from './api'
|
||||
import { getUserInfoRaw, clearUserInfo, isMockOpenid } from './store'
|
||||
|
||||
const CACHE_KEY = 'smart_auth_verified'
|
||||
const TTL = 30 * 60 * 1000
|
||||
|
||||
interface CacheEntry {
|
||||
openid: string
|
||||
ok: boolean
|
||||
at: number
|
||||
}
|
||||
|
||||
/**
|
||||
* 登录态全局缓存:首次校验通过后用内存+本地双缓存记住结果,
|
||||
* 之后进设计清单/订单等受保护页面不再重复请求后端。
|
||||
* 登录、退出登录、切换账号都会通过 invalidateAuthCache() 清掉缓存。
|
||||
*/
|
||||
let verifiedCache: CacheEntry | null = null
|
||||
let inflight: Promise<boolean> | null = null
|
||||
|
||||
export function invalidateAuthCache(): void {
|
||||
verifiedCache = null
|
||||
inflight = null
|
||||
try {
|
||||
Taro.removeStorageSync(CACHE_KEY)
|
||||
} catch {
|
||||
/* ignore */
|
||||
}
|
||||
}
|
||||
|
||||
function readCache(openid: string): boolean | null {
|
||||
const entry = verifiedCache || (() => {
|
||||
try {
|
||||
const raw = Taro.getStorageSync(CACHE_KEY)
|
||||
return raw && typeof raw === 'object' ? raw as CacheEntry : null
|
||||
} catch {
|
||||
return null
|
||||
}
|
||||
})()
|
||||
if (!entry || entry.openid !== openid) return null
|
||||
if (Date.now() - entry.at > TTL) return null
|
||||
verifiedCache = entry
|
||||
return entry.ok
|
||||
}
|
||||
|
||||
function writeCache(openid: string, ok: boolean): void {
|
||||
const entry: CacheEntry = { openid, ok, at: Date.now() }
|
||||
verifiedCache = entry
|
||||
try {
|
||||
Taro.setStorageSync(CACHE_KEY, entry)
|
||||
} catch {
|
||||
/* ignore */
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 本地已有真实 openid + token 时视为“本地已登录”。
|
||||
* 后端校验失败(网络抖动/服务端暂时不可用)不直接锁死页面,
|
||||
* 由后续 401 或主动登出再重置状态。
|
||||
*/
|
||||
function hasLocalSession(): boolean {
|
||||
const user = getUserInfoRaw()
|
||||
return !!user?.openid && !isMockOpenid(user.openid) && !!user.accessToken && !!getToken()
|
||||
}
|
||||
|
||||
export async function isAuthVerified(): Promise<boolean> {
|
||||
const localUser = getUserInfoRaw()
|
||||
if (!localUser?.openid) {
|
||||
console.log('[AuthGuard] 无本地用户,判定未登录')
|
||||
return false
|
||||
}
|
||||
console.log('[AuthGuard] 本地用户 openid=', localUser.openid)
|
||||
if (isMockOpenid(localUser.openid)) {
|
||||
clearUserInfo()
|
||||
logout()
|
||||
invalidateAuthCache()
|
||||
return false
|
||||
}
|
||||
|
||||
const cached = readCache(localUser.openid)
|
||||
if (cached !== null) {
|
||||
console.log('[AuthGuard] 命中本地缓存 ok=', cached)
|
||||
return cached
|
||||
}
|
||||
|
||||
if (!inflight) {
|
||||
inflight = getMe()
|
||||
.then((me) => {
|
||||
console.log('[AuthGuard] getMe 返回:', JSON.stringify(me))
|
||||
const consistent = !!me && !!me.id && me.openid === localUser.openid
|
||||
console.log('[AuthGuard] 一致性=', consistent)
|
||||
if (consistent) {
|
||||
writeCache(localUser.openid, true)
|
||||
return true
|
||||
}
|
||||
clearUserInfo()
|
||||
logout()
|
||||
invalidateAuthCache()
|
||||
return false
|
||||
})
|
||||
.catch((e) => {
|
||||
console.error('[AuthGuard] getMe 失败,走本地会话兜底:', e)
|
||||
return hasLocalSession()
|
||||
})
|
||||
.finally(() => {
|
||||
inflight = null
|
||||
})
|
||||
}
|
||||
|
||||
return inflight
|
||||
}
|
||||
+17
-6
@@ -2,6 +2,7 @@ import Taro from '@tarojs/taro'
|
||||
import type { DesignItem, OrderItem, AddressItem, StickerItem } from '../types'
|
||||
import { PRODUCT_ICON_MAP } from './productConfig'
|
||||
|
||||
import { invalidateAuthCache } from './authState'
|
||||
// 重新导出类型,供各页面从 store 直接引用(修正原「声明但不导出」的编译错误)
|
||||
export type { DesignItem, OrderItem, AddressItem, StickerItem }
|
||||
|
||||
@@ -66,6 +67,8 @@ export function setUserInfoRaw(info: any) {
|
||||
Taro.setStorageSync(`user_info_${info.openid}`, info)
|
||||
saveToRegistry(info.openid)
|
||||
}
|
||||
invalidateAuthCache()
|
||||
Taro.eventCenter?.trigger('authStateChanged', { openid: info?.openid || '' })
|
||||
}
|
||||
|
||||
export function getUserInfoByOpenid(openid: string): any | null {
|
||||
@@ -82,6 +85,8 @@ export function clearUserInfo() {
|
||||
// 仅退出登录,不删除用户数据
|
||||
Taro.removeStorageSync(USER_KEY)
|
||||
Taro.removeStorageSync(ACTIVE_USER_KEY)
|
||||
invalidateAuthCache()
|
||||
Taro.eventCenter?.trigger('authStateChanged', { openid: '' })
|
||||
}
|
||||
|
||||
export function setUserInfo(info: any) {
|
||||
@@ -259,17 +264,23 @@ export function setTheme(theme: ThemeMode) {
|
||||
Taro.setStorageSync(THEME_KEY, theme)
|
||||
}
|
||||
|
||||
// 跟随系统模式下,系统主题由 onThemeChange/getAppBaseInfo 写入缓存,供 resolveTheme 使用
|
||||
let detectedSystemTheme: 'light' | 'dark' | null = null
|
||||
|
||||
export function setDetectedSystemTheme(t: 'light' | 'dark'): void {
|
||||
detectedSystemTheme = t
|
||||
}
|
||||
|
||||
/** 根据自动模式解析实际生效主题 */
|
||||
export function resolveTheme(mode: ThemeMode): 'light' | 'dark' {
|
||||
if (mode === 'auto') {
|
||||
// 需 app.json 开启 darkmode 后 theme 字段才有效;getSystemInfoSync 已废弃,改用 getAppBaseInfo
|
||||
// darkmode 开启后 getAppBaseInfo().theme 能拿到系统主题;缓存仅用于启动时加速
|
||||
if (detectedSystemTheme) return detectedSystemTheme
|
||||
try {
|
||||
const info = Taro.getAppBaseInfo()
|
||||
return info.theme === 'dark' ? 'dark' : 'light'
|
||||
} catch {
|
||||
const info = Taro.getSystemInfoSync()
|
||||
return info.theme === 'dark' ? 'dark' : 'light'
|
||||
}
|
||||
if (info.theme === 'dark' || info.theme === 'light') return info.theme
|
||||
} catch { /* ignore */ }
|
||||
return 'light'
|
||||
}
|
||||
return mode
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user