Merge branch 'release/test' of http://8.163.30.128:10082/html/pda-overseas-uniapp into release/test
This commit is contained in:
+3
-3
@@ -45,12 +45,12 @@ function overseasUrl(path) {
|
||||
const nativeRuntime = typeof plus !== 'undefined'
|
||||
|| (typeof location !== 'undefined' && location.protocol === 'file:')
|
||||
if (nativeRuntime && !/^https?:\/\//i.test(base)) {
|
||||
const error = new Error('海外服务地址未配置:App 必须设置绝对 HTTP(S) 地址 VITE_OVERSEAS_API_BASE_URL')
|
||||
error.code = 'PDA_OVERSEAS_API_BASE_REQUIRED'
|
||||
const error = new Error('海外服务地址未配置:App 必须设置绝对 HTTP(S) 地址 VITE_API_BASE_URL')
|
||||
error.code = 'PDA_API_BASE_REQUIRED'
|
||||
throw error
|
||||
}
|
||||
const value = `/${String(path || '').replace(/^\/+/, '')}`
|
||||
const normalized = /\/(?:api|overseas-api)$/.test(base)
|
||||
const normalized = /\/api$/.test(base)
|
||||
? value.replace(/^\/api(?=\/)/, '')
|
||||
: value
|
||||
return `${base}${normalized}`
|
||||
|
||||
+7
-24
@@ -1,31 +1,14 @@
|
||||
const runtimeEnvironment = import.meta.env || {}
|
||||
const configuredAuthApiRoot = runtimeEnvironment.VITE_AUTH_API_BASE_URL || ''
|
||||
const configuredOverseasApiRoot = runtimeEnvironment.VITE_OVERSEAS_API_BASE_URL || ''
|
||||
const configuredApiRoot = runtimeEnvironment.VITE_API_BASE_URL || ''
|
||||
const development = Boolean(runtimeEnvironment.DEV)
|
||||
|
||||
let selectedAuthApiRoot = configuredAuthApiRoot || '/api'
|
||||
let selectedOverseasApiRoot = configuredOverseasApiRoot || '/overseas-api'
|
||||
let selectedApiRoot = configuredApiRoot || '/api'
|
||||
// #ifdef H5
|
||||
selectedApiRoot = runtimeEnvironment.VITE_H5_API_BASE_URL || '/api'
|
||||
// #endif
|
||||
const nativeRuntime = typeof plus !== 'undefined'
|
||||
|| (typeof location !== 'undefined' && location.protocol === 'file:')
|
||||
|
||||
// H5 must stay same-origin and use Vite's CORS-safe proxy; App builds keep the absolute API roots above.
|
||||
// #ifdef H5
|
||||
selectedAuthApiRoot = runtimeEnvironment.VITE_H5_AUTH_API_BASE_URL || '/api'
|
||||
selectedOverseasApiRoot = runtimeEnvironment.VITE_H5_OVERSEAS_API_BASE_URL || '/overseas-api'
|
||||
// #endif
|
||||
|
||||
// HBuilderX/App 基座 can expose a file:// location; never allow a relative API
|
||||
// root there, even if a stale H5 bundle or compiler flag was reused.
|
||||
if (nativeRuntime) {
|
||||
selectedAuthApiRoot = configuredAuthApiRoot || selectedAuthApiRoot
|
||||
// Native file:// builds cannot use the H5-only /overseas-api Vite proxy.
|
||||
// Keep the missing value explicit so the request layer can report a useful
|
||||
// configuration error instead of surfacing an opaque uploadFile:fail.
|
||||
selectedOverseasApiRoot = configuredOverseasApiRoot || ''
|
||||
}
|
||||
|
||||
export const API_ROOT = String(selectedAuthApiRoot).replace(/\/$/, '')
|
||||
export const OVERSEAS_API_ROOT = String(selectedOverseasApiRoot).replace(/\/$/, '')
|
||||
if (nativeRuntime) selectedApiRoot = configuredApiRoot || ''
|
||||
export const API_ROOT = String(selectedApiRoot).replace(/\/$/, '')
|
||||
export const DEV_LOGIN = Object.freeze({
|
||||
username: development ? String(runtimeEnvironment.VITE_PDA_DEV_USERNAME || '') : '',
|
||||
password: development ? String(runtimeEnvironment.VITE_PDA_DEV_PASSWORD || '') : ''
|
||||
|
||||
+33
-34
@@ -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,33 @@ 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) {
|
||||
const previousClaims = decodeAccessToken(session.token)
|
||||
const identityChanged = ['user_id', 'membership_id', 'tenant_id', 'app_code', 'overseas_warehouse_id']
|
||||
.some((name) => claimId(previousClaims, name) !== claimId(pair.claims, name))
|
||||
if (identityChanged || 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 +173,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 +194,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()
|
||||
|
||||
Reference in New Issue
Block a user