import { reactive } from 'vue' import { resetPickingSession } from '@/stores/picking.js' import { PLATFORM_API_ROOT } from '@/config/runtime.js' import { decodeAccessToken } from '@/utils/jwt-claims.js' export { decodeAccessToken } from '@/utils/jwt-claims.js' let sessionRevision = 0 export function getSessionRevision() { return sessionRevision } const SESSION_KEY = 'pda-auth-session' const LOGIN_PREFERENCE_KEY = 'pda-login-account-preference' export const session = reactive({ currentUser: null, token: '', refreshToken: '', tenantId: '', apiBase: PLATFORM_API_ROOT }) export function isDomesticPdaOperator(user = session.currentUser) { return Array.isArray(user?.roles) && user.roles.includes('CN_FIRSTLEG_PDA_OPERATOR') } export function isAccessTokenExpiring(token = session.token, skewSeconds = 30) { try { const expiresAt = Number(decodeAccessToken(token).exp || 0) * 1000 return !expiresAt || expiresAt <= Date.now() + skewSeconds * 1000 } catch (_) { return true } } function storageAvailable() { return typeof uni !== 'undefined' && typeof uni.setStorageSync === 'function' && typeof uni.getStorageSync === 'function' } export function loadLoginPreference() { if (!storageAvailable()) return { rememberAccount: true, account: '' } const saved = uni.getStorageSync(LOGIN_PREFERENCE_KEY) if (!saved || typeof saved !== 'object') return { rememberAccount: true, account: '' } return { rememberAccount: saved.rememberAccount !== false, account: String(saved.account || '') } } export function saveLoginPreference(rememberAccount, account = '') { if (!storageAvailable()) return uni.setStorageSync(LOGIN_PREFERENCE_KEY, { rememberAccount: Boolean(rememberAccount), account: rememberAccount ? String(account || '').trim() : '' }) } function persistSession() { if (!storageAvailable()) return uni.setStorageSync(SESSION_KEY, { currentUser: session.currentUser, token: session.token, refreshToken: session.refreshToken, tenantId: session.tenantId }) } export function signIn(account, warehouse, options = {}) { sessionRevision++ session.currentUser = { id: String(account.id), name: account.name, role: account.role, roles: account.roles || [], warehouse, warehouseId: account.warehouseId || null, domesticWarehouseId: account.domesticWarehouseId || null, warehouseBound: Boolean(account.domesticWarehouseId) } session.token = options.token || account.token || '' session.refreshToken = options.refreshToken || account.refreshToken || '' session.tenantId = options.tenantId || account.tenantId || '' // The endpoint belongs to the installed build, not to a persisted login. // Otherwise changing environments leaves existing devices on the old API. session.apiBase = PLATFORM_API_ROOT persistSession() return session.currentUser } export function signInWithTokens(tokens) { if (!tokens?.accessToken) throw new Error('登录响应缺少 accessToken') if (!tokens?.refreshToken) throw new Error('登录响应缺少 refreshToken') 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 || tokens.roles) ? (claims.roles || tokens.roles).join('、') : '', roles: claims.roles || tokens.roles || [], domesticWarehouseId: claims.domestic_warehouse_id || tokens.domesticWarehouseId || null }, '', { token: tokens.accessToken, refreshToken: tokens.refreshToken || '', tenantId: claims.tenant_id == null ? '' : String(claims.tenant_id) }) } export function selectWarehouse(warehouse) { if (!session.currentUser) throw new Error('请先登录') if (!warehouse?.id || !warehouse?.warehouseName) throw new Error('请选择有效的作业仓库') const warehouseId = String(warehouse.id) if (isDomesticPdaOperator() && String(session.currentUser.domesticWarehouseId || '') !== warehouseId) throw new Error('当前账号已绑定固定作业仓库,不能切换') if (String(session.currentUser.warehouseId || '') !== warehouseId) resetPickingSession() session.currentUser = { ...session.currentUser, warehouseId, warehouse: String(warehouse.warehouseName), warehouseCode: String(warehouse.warehouseCode || '') } persistSession() return session.currentUser } export function updateTokenPair(tokens) { if (!tokens?.accessToken) throw new Error('刷新响应缺少 accessToken') if (!tokens?.refreshToken) throw new Error('刷新响应缺少 refreshToken') const claims = decodeAccessToken(tokens.accessToken) if (claims.app_code !== 'PLATFORM') throw new Error('当前账号不属于平台作业端') if (claims.exp && claims.exp * 1000 <= Date.now()) throw new Error('刷新后的登录状态已过期') const previousUser = session.currentUser || {} session.currentUser = { ...previousUser, id: String(claims.user_id ?? previousUser.id ?? ''), name: claims.username || previousUser.name || '仓库作业员', role: Array.isArray(claims.roles) ? claims.roles.join('、') : (previousUser.role || ''), roles: claims.roles || previousUser.roles || [], domesticWarehouseId: claims.domestic_warehouse_id || previousUser.domesticWarehouseId || null, warehouseBound: Boolean(claims.domestic_warehouse_id || previousUser.domesticWarehouseId) } session.token = tokens.accessToken session.refreshToken = tokens.refreshToken session.tenantId = claims.tenant_id == null ? session.tenantId : String(claims.tenant_id) persistSession() return session.token } 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.app_code !== 'PLATFORM') throw new Error('登录域无效') if (claims.exp && claims.exp * 1000 <= Date.now() && !saved.refreshToken) throw new Error('登录状态已过期') const savedUser = saved.currentUser || {} Object.assign(session, saved, { currentUser: { ...savedUser, id: String(claims.user_id ?? savedUser.id ?? ''), name: claims.username || savedUser.name || '仓库作业员', role: Array.isArray(claims.roles) ? claims.roles.join('、') : (savedUser.role || ''), roles: claims.roles || savedUser.roles || [], domesticWarehouseId: claims.domestic_warehouse_id || savedUser.domesticWarehouseId || null, warehouseBound: Boolean(claims.domestic_warehouse_id || savedUser.domesticWarehouseId) }, tenantId: claims.tenant_id == null ? (saved.tenantId || '') : String(claims.tenant_id), apiBase: saved.apiBase || PLATFORM_API_ROOT }) sessionRevision++ persistSession() return true } catch (_) { signOut() return false } } export function signOut() { sessionRevision++ 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 }