import { reactive } from 'vue' import { resetPickingSession } from '@/stores/picking.js' import { PLATFORM_API_ROOT } from '@/config/runtime.js' const SESSION_KEY = 'pda-auth-session' export const session = reactive({ currentUser: null, token: '', refreshToken: '', tenantId: '', apiBase: PLATFORM_API_ROOT }) function decodeBase64Url(value) { const normalized = value.replace(/-/g, '+').replace(/_/g, '/') const padded = normalized.padEnd(Math.ceil(normalized.length / 4) * 4, '=') if (typeof atob === 'function') return decodeURIComponent(Array.from(atob(padded), (char) => `%${char.charCodeAt(0).toString(16).padStart(2, '0')}`).join('')) throw new Error('当前运行环境无法解析登录令牌') } export function decodeAccessToken(token) { const payload = String(token || '').split('.')[1] if (!payload) throw new Error('登录响应中的 accessToken 格式无效') try { return JSON.parse(decodeBase64Url(payload)) } catch (error) { if (error.message === '当前运行环境无法解析登录令牌') throw error throw new Error('登录响应中的 accessToken 无法解析') } } function storageAvailable() { return typeof uni !== 'undefined' && typeof uni.setStorageSync === 'function' && typeof uni.getStorageSync === 'function' } function persistSession() { if (!storageAvailable()) return uni.setStorageSync(SESSION_KEY, { currentUser: session.currentUser, token: session.token, refreshToken: session.refreshToken, tenantId: session.tenantId, apiBase: session.apiBase }) } export function signIn(account, warehouse, options = {}) { session.currentUser = { id: String(account.id), name: account.name, role: account.role, roles: account.roles || [], warehouse, warehouseId: account.warehouseId || null } session.token = options.token || account.token || '' session.refreshToken = options.refreshToken || account.refreshToken || '' session.tenantId = options.tenantId || account.tenantId || '' session.apiBase = options.apiBase || account.apiBase || PLATFORM_API_ROOT persistSession() return session.currentUser } export function signInWithTokens(tokens) { if (!tokens?.accessToken) throw new Error('登录响应缺少 accessToken') const claims = decodeAccessToken(tokens.accessToken) if (claims.app_code !== 'PLATFORM') throw new Error('当前账号不属于平台作业端') if (claims.exp && claims.exp * 1000 <= Date.now()) throw new Error('登录状态已过期') return signIn({ id: claims.user_id ?? '', name: claims.username || '仓库作业员', role: Array.isArray(claims.roles) ? claims.roles.join('、') : '', roles: claims.roles || [] }, '', { token: tokens.accessToken, refreshToken: tokens.refreshToken || '', tenantId: claims.tenant_id == null ? '' : String(claims.tenant_id) }) } export function restoreSession() { if (!storageAvailable()) return false const saved = uni.getStorageSync(SESSION_KEY) if (!saved?.token || !saved?.currentUser) return false try { const claims = decodeAccessToken(saved.token) if (claims.exp && claims.exp * 1000 <= Date.now()) return false Object.assign(session, saved, { apiBase: saved.apiBase || PLATFORM_API_ROOT }) return true } catch (_) { return false } } export function signOut() { session.currentUser = null session.token = '' session.refreshToken = '' session.tenantId = '' session.apiBase = PLATFORM_API_ROOT if (typeof uni !== 'undefined' && typeof uni.removeStorageSync === 'function') uni.removeStorageSync(SESSION_KEY) resetPickingSession() } export function requireSession() { if (session.currentUser || restoreSession()) return true uni.reLaunch({ url: '/pages/login/login' }) return false }