fix(pda): leave expired sessions and clarify dispatch navigation
This commit is contained in:
+40
-13
@@ -1,7 +1,18 @@
|
||||
import { refresh } from './auth.js'
|
||||
import { session, replaceTokens, signOut } from '../stores/session.js'
|
||||
import { session, replaceTokens, signOut, getSessionRevision } from '../stores/session.js'
|
||||
|
||||
let refreshPromise = null
|
||||
let refreshRevision = -1
|
||||
|
||||
function requireCurrentSession(revision) {
|
||||
if (revision !== getSessionRevision()) throw new Error('登录会话已变更,请重新操作')
|
||||
}
|
||||
|
||||
function expireSession(revision) {
|
||||
if (revision !== getSessionRevision()) return
|
||||
signOut()
|
||||
uni.reLaunch({ url: '/pages/login/login' })
|
||||
}
|
||||
|
||||
function errorFrom(response, fallback) {
|
||||
const body = response?.data || {}
|
||||
@@ -21,23 +32,27 @@ function successful(response, body) {
|
||||
return response?.statusCode === 200 && ['00000', '200'].includes(String(body?.code))
|
||||
}
|
||||
|
||||
async function refreshOverseasToken() {
|
||||
async function refreshOverseasToken(revision) {
|
||||
requireCurrentSession(revision)
|
||||
if (!session.refreshToken) {
|
||||
signOut()
|
||||
expireSession(revision)
|
||||
throw new Error('登录状态已过期,请重新登录')
|
||||
}
|
||||
if (!refreshPromise) {
|
||||
refreshPromise = refresh(session.refreshToken)
|
||||
.then((tokens) => { replaceTokens(tokens); return session.token })
|
||||
.catch((error) => { signOut(); throw error })
|
||||
.finally(() => { refreshPromise = null })
|
||||
if (!refreshPromise || refreshRevision !== revision) {
|
||||
refreshRevision = revision
|
||||
const pending = refresh(session.refreshToken)
|
||||
.then((tokens) => { requireCurrentSession(revision); replaceTokens(tokens); return session.token })
|
||||
.catch((error) => { expireSession(revision); throw error })
|
||||
.finally(() => { if (refreshPromise === pending) refreshPromise = null })
|
||||
refreshPromise = pending
|
||||
}
|
||||
return refreshPromise
|
||||
}
|
||||
|
||||
async function tokenAfterUnauthorized(failedToken) {
|
||||
async function tokenAfterUnauthorized(failedToken, revision) {
|
||||
requireCurrentSession(revision)
|
||||
if (session.token && session.token !== failedToken) return session.token
|
||||
return refreshOverseasToken()
|
||||
return refreshOverseasToken(revision)
|
||||
}
|
||||
|
||||
function overseasUrl(path) {
|
||||
@@ -70,13 +85,17 @@ function rawRequest(method, path, data, token) {
|
||||
}
|
||||
|
||||
export async function overseasRequest(method, path, data, retry = true) {
|
||||
const revision = getSessionRevision()
|
||||
console.info('[Overseas PDA API] request', { method, path })
|
||||
const attemptedToken = session.token
|
||||
let response = await rawRequest(method, path, data, attemptedToken)
|
||||
requireCurrentSession(revision)
|
||||
if (retry && unauthorized(response)) {
|
||||
const replacementToken = await tokenAfterUnauthorized(attemptedToken)
|
||||
const replacementToken = await tokenAfterUnauthorized(attemptedToken, revision)
|
||||
response = await rawRequest(method, path, data, replacementToken)
|
||||
}
|
||||
requireCurrentSession(revision)
|
||||
if (unauthorized(response)) expireSession(revision)
|
||||
const body = response?.data || {}
|
||||
console.info('[Overseas PDA API] response', { method, path, statusCode: response?.statusCode, code: body?.code,
|
||||
message: body?.message, requestId: body?.requestId || response?.header?.['x-request-id'] || response?.header?.['X-Request-Id'],
|
||||
@@ -149,27 +168,35 @@ function rawDownload(path, token) {
|
||||
}
|
||||
|
||||
export async function overseasUpload(path, filePath, name = 'file', retry = true) {
|
||||
const revision = getSessionRevision()
|
||||
const attemptedToken = session.token
|
||||
let response = await rawUpload(path, filePath, name, attemptedToken)
|
||||
requireCurrentSession(revision)
|
||||
let body = null
|
||||
try { body = JSON.parse(response.data || '{}') } catch (_) { /* handled below */ }
|
||||
if (retry && unauthorized({ ...response, data: body })) {
|
||||
const replacementToken = await tokenAfterUnauthorized(attemptedToken)
|
||||
const replacementToken = await tokenAfterUnauthorized(attemptedToken, revision)
|
||||
response = await rawUpload(path, filePath, name, replacementToken)
|
||||
try { body = JSON.parse(response.data || '{}') } catch (_) { body = null }
|
||||
}
|
||||
requireCurrentSession(revision)
|
||||
if (unauthorized({ ...response, data: body })) expireSession(revision)
|
||||
if (!successful(response, body)) throw errorFrom({ ...response, data: body }, '海外作业文件上传失败')
|
||||
return body.data
|
||||
}
|
||||
|
||||
export async function overseasDownload(path, options = {}) {
|
||||
const revision = getSessionRevision()
|
||||
const { retry = true, expectedContentTypePrefix = '' } = options
|
||||
const attemptedToken = session.token
|
||||
let response = await rawDownload(path, attemptedToken)
|
||||
requireCurrentSession(revision)
|
||||
if (retry && unauthorized(response)) {
|
||||
const replacementToken = await tokenAfterUnauthorized(attemptedToken)
|
||||
const replacementToken = await tokenAfterUnauthorized(attemptedToken, revision)
|
||||
response = await rawDownload(path, replacementToken)
|
||||
}
|
||||
requireCurrentSession(revision)
|
||||
if (unauthorized(response)) expireSession(revision)
|
||||
if (response?.statusCode !== 200 || !response?.tempFilePath) {
|
||||
throw errorFrom({ ...response, data: {} }, '签收照片下载失败')
|
||||
}
|
||||
|
||||
@@ -26,12 +26,12 @@
|
||||
</view>
|
||||
|
||||
<template v-if="!loading && !current">
|
||||
<view class="list-toolbar"><view><text class="list-title">待处理排车任务</text><text class="list-count">{{ tasks.length }} 个任务</text></view><button :disabled="loading" @tap="loadTasks">刷新</button></view>
|
||||
<view class="list-toolbar"><view><text class="list-title">排车任务</text><text class="list-count">{{ tasks.length }} 个任务</text></view><button :disabled="loading" @tap="loadTasks">刷新</button></view>
|
||||
<view v-if="tasks.length" class="task-list">
|
||||
<button v-for="task in tasks" :key="task.dispatchNo" class="task-card" @tap="openTask(task.dispatchNo)">
|
||||
<view class="task-head"><view class="task-code-row"><text class="business-code">{{ task.dispatchNo || '—' }}</text><text v-if="task.dispatchNo === recentTaskNo" class="recent-badge">上次作业</text></view><text class="status-badge">{{ statusLabel(task.status) }}</text></view>
|
||||
<text class="task-meta">任务号 {{ task.taskNo || '—' }} · 车牌 {{ task.vehiclePlate || '—' }}</text>
|
||||
<text class="task-enter">查看并开始拣货 ›</text>
|
||||
<text class="task-enter">查看任务详情 ›</text>
|
||||
</button>
|
||||
</view>
|
||||
<view v-else-if="!error" class="fulfillment-state"><text class="state-title">暂无排车拣货任务</text><text>可刷新列表,或直接扫描排车单号恢复作业。</text></view>
|
||||
|
||||
@@ -5,6 +5,8 @@ import { resetFulfillmentSession } from './fulfillment.js'
|
||||
import { resetWarehouseWork } from './warehouse-work.js'
|
||||
|
||||
const SESSION_KEY = 'overseas-pda-auth-session'
|
||||
let sessionRevision = 0
|
||||
export function getSessionRevision() { return sessionRevision }
|
||||
export const PDA_ROLE = 'OVERSEAS_WAREHOUSE_PDA_OPERATOR'
|
||||
export const PDA_AUTHORITY = 'lastleg:pda:operate'
|
||||
|
||||
@@ -108,6 +110,7 @@ function persistSession() {
|
||||
}
|
||||
|
||||
export function signIn(account, warehouse, options = {}) {
|
||||
sessionRevision += 1
|
||||
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 || ''
|
||||
@@ -184,6 +187,7 @@ export function restoreSession() {
|
||||
currentUser: userFromClaims(pair, saved.currentUser), tenantId: claimId(pair.claims, 'tenant_id'),
|
||||
apiBase: API_ROOT, authorization: pair.authorization
|
||||
})
|
||||
sessionRevision += 1
|
||||
return true
|
||||
} catch (_) {
|
||||
signOut()
|
||||
@@ -192,6 +196,7 @@ export function restoreSession() {
|
||||
}
|
||||
|
||||
export function signOut() {
|
||||
sessionRevision += 1
|
||||
session.currentUser = null
|
||||
session.token = ''
|
||||
session.refreshToken = ''
|
||||
|
||||
Reference in New Issue
Block a user