优化
This commit is contained in:
+14
-12
@@ -1,15 +1,17 @@
|
||||
import { overseasRequest, overseasUpload } from '@/api/overseas.js'
|
||||
|
||||
function scope(customerId) { return `?customerId=${encodeURIComponent(customerId)}` }
|
||||
function base(planNo) { return `/pda/v1/last-leg/inbound-plans/${encodeURIComponent(planNo)}` }
|
||||
const RECEIVING_BASE = '/pda/v1/last-leg/receiving-containers'
|
||||
const current = (suffix = '') => `${RECEIVING_BASE}/current${suffix}`
|
||||
|
||||
export const getInboundTask = (planNo, customerId) => overseasRequest('GET', `${base(planNo)}${scope(customerId)}`)
|
||||
export const pushInboundTask = (planNo, customerId, request) => overseasRequest('POST', `${base(planNo)}/push${scope(customerId)}`, request)
|
||||
export const assignInboundPallet = (planNo, customerId, planPalletId, request) => overseasRequest('POST', `${base(planNo)}/pallets/${encodeURIComponent(planPalletId)}/assign${scope(customerId)}`, request)
|
||||
export const countInboundPackages = (planNo, customerId, allocationId, request) => overseasRequest('POST', `${base(planNo)}/allocations/${encodeURIComponent(allocationId)}/count${scope(customerId)}`, request)
|
||||
export const pickInboundPackages = (planNo, customerId, allocationId, request) => overseasRequest('POST', `${base(planNo)}/allocations/${encodeURIComponent(allocationId)}/pick${scope(customerId)}`, request)
|
||||
export const scanInboundCarton = (planNo, customerId, request) => overseasRequest('POST', `${base(planNo)}/cartons/scan${scope(customerId)}`, request)
|
||||
export const removeInboundCarton = (planNo, customerId, request) => overseasRequest('POST', `${base(planNo)}/cartons/remove${scope(customerId)}`, request)
|
||||
export const bindUnloadPhotos = (planNo, customerId, request) => overseasRequest('POST', `${base(planNo)}/unload-photos${scope(customerId)}`, request)
|
||||
export const completeInboundTask = (planNo, customerId) => overseasRequest('POST', `${base(planNo)}/complete${scope(customerId)}`)
|
||||
export const uploadUnloadPhotoFile = (planNo, customerId, filePath) => overseasUpload(`${base(planNo)}/unload-photos/files${scope(customerId)}`, filePath)
|
||||
export const listReceivingCandidates = () => overseasRequest('GET', `${RECEIVING_BASE}/candidates`)
|
||||
export const getReceivingContainer = (containerNo) => overseasRequest('GET', `${RECEIVING_BASE}/${encodeURIComponent(containerNo)}`)
|
||||
export const prepareReceivingContainer = (containerNo, request) => overseasRequest('POST', `${RECEIVING_BASE}/${encodeURIComponent(containerNo)}/prepare`, request)
|
||||
export const uploadCurrentUnloadPhoto = (filePath) => overseasUpload(current('/unload-photos/files'), filePath)
|
||||
export const signCurrentReceiving = (request) => overseasRequest('POST', current('/sign'), request)
|
||||
export const getCurrentReceiving = () => overseasRequest('GET', current())
|
||||
export const resolveCurrentCarton = (cartonMark) => overseasRequest('POST', current('/cartons/resolve'), { cartonMark })
|
||||
export const resolveCurrentSku = (skuCode) => overseasRequest('POST', current('/skus/resolve'), { skuCode })
|
||||
export const resolveCurrentPallet = (palletCode, inboundCode) => overseasRequest('POST', current('/pallets/resolve'), { palletCode, inboundCode })
|
||||
export const receiveCurrentBulk = (request) => overseasRequest('POST', current('/receipts/bulk'), request)
|
||||
export const receiveCurrentCarton = (request) => overseasRequest('POST', current('/receipts/carton'), request)
|
||||
export const completeCurrentReceiving = (request) => overseasRequest('POST', current('/complete'), request)
|
||||
|
||||
+21
-11
@@ -17,6 +17,10 @@ function unauthorized(response) {
|
||||
return response?.statusCode === 401 || code === 'A0401'
|
||||
}
|
||||
|
||||
function successful(response, body) {
|
||||
return response?.statusCode === 200 && ['00000', '200'].includes(String(body?.code))
|
||||
}
|
||||
|
||||
async function refreshOverseasToken() {
|
||||
if (!session.refreshToken) throw new Error('登录状态已过期,请重新登录')
|
||||
if (!refreshPromise) {
|
||||
@@ -46,26 +50,32 @@ export async function overseasRequest(method, path, data, retry = true) {
|
||||
response = await rawRequest(method, path, data, session.token)
|
||||
}
|
||||
const body = response?.data || {}
|
||||
if (response.statusCode !== 200 || String(body.code) !== '200') throw errorFrom(response, '海外作业请求失败')
|
||||
if (!successful(response, body)) throw errorFrom(response, '海外作业请求失败')
|
||||
return body.data
|
||||
}
|
||||
|
||||
export function overseasUpload(path, filePath, name = 'file') {
|
||||
function rawUpload(path, filePath, name, token) {
|
||||
return new Promise((resolve, reject) => {
|
||||
uni.uploadFile({
|
||||
url: `${session.apiBase}${path}`,
|
||||
filePath,
|
||||
name,
|
||||
header: { Authorization: `Bearer ${session.token}` },
|
||||
success(response) {
|
||||
let body = null
|
||||
try { body = JSON.parse(response.data || '{}') } catch (_) { /* handled below */ }
|
||||
if (response.statusCode !== 200 || String(body?.code) !== '200') {
|
||||
reject(errorFrom({ ...response, data: body }, '卸柜照片上传失败')); return
|
||||
}
|
||||
resolve(body.data)
|
||||
},
|
||||
header: { Authorization: `Bearer ${token}` },
|
||||
success: resolve,
|
||||
fail: (cause) => reject(Object.assign(new Error(cause.errMsg || '卸柜照片上传失败'), { network: true }))
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
export async function overseasUpload(path, filePath, name = 'file', retry = true) {
|
||||
let response = await rawUpload(path, filePath, name, session.token)
|
||||
let body = null
|
||||
try { body = JSON.parse(response.data || '{}') } catch (_) { /* handled below */ }
|
||||
if (retry && unauthorized({ ...response, data: body })) {
|
||||
await refreshOverseasToken()
|
||||
response = await rawUpload(path, filePath, name, session.token)
|
||||
try { body = JSON.parse(response.data || '{}') } catch (_) { body = null }
|
||||
}
|
||||
if (!successful(response, body)) throw errorFrom({ ...response, data: body }, '卸柜照片上传失败')
|
||||
return body.data
|
||||
}
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
export const MODULES = [
|
||||
{ key: 'inbound', name: '入仓作业', icon: '入', description: '到仓、卸柜收货与上架', operations: [
|
||||
{ name: '到仓登记', icon: '到', iconType: 'download', description: '扫描入仓计划并登记车辆到仓', available: true, badge: '已接入' },
|
||||
{ name: '卸柜收货', icon: '卸', iconType: 'paperplane', description: '按箱或托盘确认卸柜实收', available: true, badge: '已接入' },
|
||||
{ name: '入仓上架', icon: '上', iconType: 'upload', description: '扫描容器与目标库位完成上架', available: true, badge: '已接入' }
|
||||
{ key: 'inbound', name: '入仓作业', icon: '入', description: '柜号签收、卸柜收货与入库', operations: [
|
||||
{ name: '拆柜收货', icon: '卸', iconType: 'download', description: '待卸柜拍照签收,按目的类型扫码收货', available: true, badge: '真实接口' }
|
||||
] },
|
||||
{ key: 'inventory', name: '库内作业', icon: '库', description: '盘点、移库与托盘管理', operations: [
|
||||
{ name: '库存盘点', icon: '盘', iconType: 'list', description: '按任务扫描库位和库存', available: true, badge: '原型' },
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<view class="module-hero" :class="`module-hero-${currentModule.key}`"><view class="module-hero-icon">{{ currentModule.icon }}</view><view><text class="module-hero-title">{{ currentModule.name }}</text><text class="module-hero-desc">{{ currentModule.description }}</text></view></view>
|
||||
<text class="group-title">业务功能</text>
|
||||
<view class="operation-list"><button v-for="operation in currentModule.operations" :key="operation.name" class="operation-item" :class="{ 'operation-item-disabled': !operation.available }" :disabled="!operation.available" @tap="openOperation(operation)"><view class="operation-icon">{{ operation.icon }}</view><view class="operation-info"><text class="operation-name">{{ operation.name }}</text><text class="operation-desc">{{ operation.description }}</text></view><text v-if="operation.available" class="operation-prototype">{{ operation.badge }}</text><text v-else class="operation-prototype">未开放</text><text v-if="operation.available" class="operation-arrow">›</text></button></view>
|
||||
<view class="module-empty-note">当前为海外仓独立工程首版原型;真实作业接口统一经海外网关接入。</view>
|
||||
<view class="module-empty-note">拆柜收货已经海外网关接入真实接口;标记“原型”的库内与换标功能不会模拟提交成功。</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,64 @@
|
||||
import { reactive } from 'vue'
|
||||
|
||||
export const receiving = reactive({
|
||||
candidates: [], selected: null, current: null, photoSlots: [null, null, null],
|
||||
selectedInboundCode: '', resolvedCarton: null, resolvedSku: null, resolvedPallet: null,
|
||||
activeScanTarget: 'container', lastReceipt: null
|
||||
})
|
||||
|
||||
const idempotencyKeys = new Map()
|
||||
|
||||
export function receivingPhase(session = receiving.current) {
|
||||
if (!session) return 'candidates'
|
||||
if (session.status === 'WAIT_SIGN') return 'sign'
|
||||
if (session.status === 'SIGNED' || session.status === 'RECEIVING') return 'receive'
|
||||
if (session.status === 'COMPLETED') return 'completed'
|
||||
return 'candidates'
|
||||
}
|
||||
|
||||
export function receivingProgress(session = receiving.current) {
|
||||
const total = Math.max(0, Number(session?.totalPackages || 0))
|
||||
const received = Math.max(0, Number(session?.receivedPackages || 0))
|
||||
return { total, received, pending: Math.max(0, Number(session?.pendingPackages ?? total - received)), percent: total ? Math.min(100, Math.round(received / total * 100)) : 0 }
|
||||
}
|
||||
|
||||
export function selectedInbound(session = receiving.current) {
|
||||
return (session?.inbounds || []).find((item) => item.inboundCode === receiving.selectedInboundCode) || null
|
||||
}
|
||||
|
||||
export function setCurrentReceiving(value) {
|
||||
receiving.current = value || null
|
||||
receiving.selected = value || null
|
||||
const chosen = selectedInbound(value)
|
||||
if (!chosen || Number(chosen.pendingPackages || 0) <= 0) {
|
||||
receiving.selectedInboundCode = (value?.inbounds || []).find((item) => Number(item.pendingPackages || 0) > 0)?.inboundCode || value?.inbounds?.[0]?.inboundCode || ''
|
||||
}
|
||||
if (value?.photos?.length) {
|
||||
const roles = ['LICENSE_PLATE', 'CONTAINER_SEAL', 'DOOR_OPEN']
|
||||
receiving.photoSlots = roles.map((role) => {
|
||||
const photo = value.photos.find((item) => item.role === role)
|
||||
return photo ? { ...photo, fileId: String(photo.fileId), role, uploaded: true } : null
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export function resetReceivingDraft({ keepCurrent = false } = {}) {
|
||||
receiving.selected = keepCurrent ? receiving.current : null
|
||||
if (!keepCurrent) receiving.current = null
|
||||
receiving.photoSlots = [null, null, null]
|
||||
receiving.selectedInboundCode = ''
|
||||
receiving.resolvedCarton = null
|
||||
receiving.resolvedSku = null
|
||||
receiving.resolvedPallet = null
|
||||
receiving.activeScanTarget = keepCurrent ? 'pallet' : 'container'
|
||||
receiving.lastReceipt = null
|
||||
idempotencyKeys.clear()
|
||||
}
|
||||
|
||||
export function idempotencyKey(action, payload = {}) {
|
||||
const signature = `${action}:${JSON.stringify(payload)}`
|
||||
if (!idempotencyKeys.has(signature)) idempotencyKeys.set(signature, `pda-${Date.now()}-${Math.random().toString(16).slice(2)}`)
|
||||
return { signature, value: idempotencyKeys.get(signature) }
|
||||
}
|
||||
|
||||
export function releaseIdempotencyKey(signature) { idempotencyKeys.delete(signature) }
|
||||
Reference in New Issue
Block a user