This commit is contained in:
2026-09-29 17:56:05 +08:00
parent ef5c8250c5
commit 0aaf855ce2
13 changed files with 121 additions and 145 deletions
+26 -34
View File
@@ -1,5 +1,5 @@
import { reactive } from 'vue'
import { OVERSEAS_API_ROOT } from '../config/runtime.js'
import { API_ROOT } from '../config/runtime.js'
import { resetReceivingSession } from './receiving.js'
import { resetFulfillmentSession } from './fulfillment.js'
import { resetWarehouseWork } from './warehouse-work.js'
@@ -9,7 +9,7 @@ export const PDA_ROLE = 'OVERSEAS_WAREHOUSE_PDA_OPERATOR'
export const PDA_AUTHORITY = 'lastleg:pda:operate'
export const session = reactive({
currentUser: null, token: '', domesticToken: '', refreshToken: '', tenantId: '', apiBase: OVERSEAS_API_ROOT,
currentUser: null, token: '', refreshToken: '', tenantId: '', apiBase: API_ROOT,
authorization: { roles: [], authorities: [] }
})
@@ -47,7 +47,7 @@ function includesClaim(values, expected) {
}
function requireActiveClaims(claims, label) {
if (claims.exp && Number(claims.exp) * 1000 <= Date.now()) throw new Error(`${label}已过期`)
if (!Number.isFinite(Number(claims.exp)) || Number(claims.exp) * 1000 <= Date.now()) throw new Error(`${label}已过期`)
if (claims.app_code !== 'PLATFORM' || claimId(claims, 'tenant_id') !== '0') {
throw new Error('当前账号不属于平台仓库作业端')
}
@@ -67,25 +67,20 @@ function requireAuthorizationSnapshot(authorization) {
return { roles, authorities }
}
export function validatePdaTokenPair(accessToken, overseasAccessToken, authorization) {
const domestic = decodeAccessToken(accessToken)
const overseas = decodeAccessToken(overseasAccessToken)
requireActiveClaims(domestic, '登录状态')
requireActiveClaims(overseas, '海外作业令牌')
for (const claim of ['user_id', 'membership_id', 'tenant_id', 'app_code', 'overseas_warehouse_id']) {
if (claimId(domestic, claim) !== claimId(overseas, claim)) throw new Error('国内与海外令牌作业主体不一致')
}
const warehouseId = claimId(overseas, 'overseas_warehouse_id')
export function validatePdaToken(accessToken, authorization) {
const claims = decodeAccessToken(accessToken)
requireActiveClaims(claims, '登录状态')
const warehouseId = claimId(claims, 'overseas_warehouse_id')
if (!/^\d+$/.test(warehouseId) || warehouseId === '0') throw new Error('海外PDA账号未绑定有效作业仓库')
return { domestic, overseas, warehouseId, authorization: requireAuthorizationSnapshot(authorization) }
return { claims, warehouseId, authorization: requireAuthorizationSnapshot(authorization) }
}
function userFromClaims(pair, saved = {}) {
const savedWarehouseId = String(saved?.warehouseId || '')
const sameWarehouse = savedWarehouseId === pair.warehouseId
return {
id: claimId(pair.domestic, 'user_id'),
name: pair.domestic.username || '仓库作业员',
id: claimId(pair.claims, 'user_id'),
name: pair.claims.username || '仓库作业员',
role: PDA_ROLE,
roles: [...pair.authorization.roles],
warehouse: sameWarehouse && saved.warehouseName ? saved.warehouseName : '',
@@ -102,9 +97,9 @@ function storageAvailable() {
function persistSession() {
if (!storageAvailable()) return
uni.setStorageSync(SESSION_KEY, {
version: 2,
currentUser: session.currentUser,
token: session.token,
domesticToken: session.domesticToken,
refreshToken: session.refreshToken,
tenantId: session.tenantId,
apiBase: session.apiBase,
@@ -116,10 +111,9 @@ 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, warehouseCode: account.warehouseCode || '', warehouseName: account.warehouseName || '' }
session.token = options.token || account.token || ''
session.domesticToken = options.domesticToken || account.domesticToken || ''
session.refreshToken = options.refreshToken || account.refreshToken || ''
session.tenantId = options.tenantId || account.tenantId || ''
session.apiBase = options.apiBase || account.apiBase || OVERSEAS_API_ROOT
session.apiBase = options.apiBase || account.apiBase || API_ROOT
session.authorization = {
roles: [...(options.authorization?.roles || [])],
authorities: [...(options.authorization?.authorities || [])]
@@ -130,28 +124,26 @@ export function signIn(account, warehouse, options = {}) {
export function signInWithTokens(tokens) {
if (!tokens?.accessToken) throw new Error('登录响应缺少 accessToken')
if (!tokens?.overseasAccessToken) throw new Error('登录响应缺少 overseasAccessToken')
const pair = validatePdaTokenPair(tokens.accessToken, tokens.overseasAccessToken, tokens)
const pair = validatePdaToken(tokens.accessToken, tokens)
const user = userFromClaims(pair)
return signIn(user, user.warehouse, {
token: tokens.overseasAccessToken,
domesticToken: tokens.accessToken,
token: tokens.accessToken,
refreshToken: tokens.refreshToken || '',
tenantId: claimId(pair.domestic, 'tenant_id'),
tenantId: claimId(pair.claims, 'tenant_id'),
authorization: pair.authorization
})
}
export function replaceTokens(tokens) {
if (!tokens?.accessToken || !tokens?.overseasAccessToken) throw new Error('刷新响应缺少双区域访问令牌')
const pair = validatePdaTokenPair(tokens.accessToken, tokens.overseasAccessToken, tokens)
if (!tokens?.accessToken) throw new Error('刷新响应缺少访问令牌')
const pair = validatePdaToken(tokens.accessToken, tokens)
if (session.currentUser && (String(session.currentUser.id) !== claimId(pair.claims, 'user_id') || String(session.currentUser.warehouseId) !== pair.warehouseId)) throw new Error('作业主体或绑定仓库已变更,请重新登录')
const user = userFromClaims(pair, session.currentUser)
const nextRefreshToken = tokens.refreshToken || session.refreshToken
// Validate the complete replacement before mutating reactive or persisted session state.
session.domesticToken = tokens.accessToken
session.token = tokens.overseasAccessToken
session.token = tokens.accessToken
session.refreshToken = nextRefreshToken
session.tenantId = claimId(pair.domestic, 'tenant_id')
session.tenantId = claimId(pair.claims, 'tenant_id')
session.currentUser = user
session.authorization = pair.authorization
persistSession()
@@ -174,15 +166,16 @@ export function applyWarehouseProfile(profile) {
export function restoreSession() {
if (!storageAvailable()) return false
const saved = uni.getStorageSync(SESSION_KEY)
if (!saved?.token || !saved?.domesticToken || !saved?.refreshToken || !saved?.currentUser) {
if (!saved?.token || !saved?.refreshToken || !saved?.currentUser || saved.version !== 2) {
signOut()
return false
}
try {
const pair = validatePdaTokenPair(saved.domesticToken, saved.token, saved.authorization)
const pair = validatePdaToken(saved.token, saved.authorization)
if (String(saved.currentUser.id) !== claimId(pair.claims, 'user_id') || String(saved.currentUser.warehouseId) !== pair.warehouseId) throw new Error('缓存作业主体不一致')
Object.assign(session, saved, {
currentUser: userFromClaims(pair, saved.currentUser), tenantId: claimId(pair.domestic, 'tenant_id'),
apiBase: OVERSEAS_API_ROOT, authorization: pair.authorization
currentUser: userFromClaims(pair, saved.currentUser), tenantId: claimId(pair.claims, 'tenant_id'),
apiBase: API_ROOT, authorization: pair.authorization
})
return true
} catch (_) {
@@ -194,10 +187,9 @@ export function restoreSession() {
export function signOut() {
session.currentUser = null
session.token = ''
session.domesticToken = ''
session.refreshToken = ''
session.tenantId = ''
session.apiBase = OVERSEAS_API_ROOT
session.apiBase = API_ROOT
session.authorization = { roles: [], authorities: [] }
if (typeof uni !== 'undefined' && typeof uni.removeStorageSync === 'function') uni.removeStorageSync(SESSION_KEY)
resetReceivingSession()