Files

176 lines
7.2 KiB
JavaScript

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
}