fix(appointments): handle synchronization and transport continuation
This commit is contained in:
@@ -17,6 +17,7 @@ import WorkReceivingPanel from './WorkReceivingPanel.vue'
|
||||
import WorkBatchContinuation from './WorkBatchContinuation.vue'
|
||||
import type { FbaAppointmentDto } from '@/modules/overseas-warehouse'
|
||||
import type { LeaveGuard } from './useWorkDraft'
|
||||
import { useWorkSyncRead } from './useWorkSyncRead'
|
||||
const props = defineProps<{ itemKey: string; initialAction?: WorkAction | null; canLeave: LeaveGuard }>()
|
||||
const emit = defineEmits<{ open: [key: string, action?: WorkAction]; external: [path: string]; saved: [result?: WorkCommandResult, command?: WorkCommand['command']]; updated: []; container: [id: string, label: string] }>()
|
||||
const detail = ref<WorkDetail | null>(null), loading = ref(false), error = ref<ApiErrorDetails | null>(null), action = ref<WorkAction | null>(null)
|
||||
@@ -28,9 +29,11 @@ const batchKey = ref<string | null>(null), openedAppointmentNo = ref<string | nu
|
||||
const receivingKey = ref<string | null>(null)
|
||||
const continuation = ref<{ batchKey: string; customerId?: string; labels?: Array<{ customerId: string; label: string }> } | null>(null)
|
||||
let controller: AbortController | null = null, request = 0
|
||||
const syncRead = useWorkSyncRead(), syncing = syncRead.syncing
|
||||
async function load() {
|
||||
const generation = ++request; controller?.abort(); controller = new AbortController(); loading.value = true; error.value = null
|
||||
try { const result = await getWorkDetail(props.itemKey, controller.signal); if (generation === request) detail.value = result }
|
||||
const signal = controller.signal
|
||||
try { const result = await syncRead.read(() => getWorkDetail(props.itemKey, signal), signal); if (generation === request) detail.value = result }
|
||||
catch (cause) { if (generation === request) error.value = getApiErrorDetails(cause, '工作事项读取失败') }
|
||||
finally { if (generation === request) loading.value = false }
|
||||
}
|
||||
@@ -60,7 +63,9 @@ const secondaryActions = computed(() => detail.value?.item.allowedActions.filter
|
||||
async function choose(next: WorkAction) {
|
||||
if (!detail.value || loading.value || error.value || !await props.canLeave()) return
|
||||
actionNotice.value = ''
|
||||
if (!actionAllowed(detail.value.item, next)) { actionNotice.value = '操作资格已变化,请刷新事项后查看当前下一步。'; return }
|
||||
// 跨事项的主要下一步只用于导航,目标面板会重新读取并校验自己的写入资格。
|
||||
const linkedNext = next.targetWorkItemKey && next.targetWorkItemKey !== props.itemKey && detail.value.item.nextAction && sameAction(next, detail.value.item.nextAction)
|
||||
if (!linkedNext && !actionAllowed(detail.value.item, next)) { actionNotice.value = '操作资格已变化,请刷新事项后查看当前下一步。'; return }
|
||||
saveCompleted.value = false
|
||||
if (next.targetWorkItemKey && next.targetWorkItemKey !== props.itemKey) { emit('open', next.targetWorkItemKey, next); return }
|
||||
const path = actionRoute(next, detail.value.references, detail.value.item)
|
||||
@@ -102,7 +107,7 @@ onBeforeUnmount(() => { ++request; controller?.abort() })
|
||||
<template>
|
||||
<div :aria-busy="loading">
|
||||
<LoadErrorState v-if="error" title="工作事项读取失败" :message="error.message" :loading="loading" @retry="load"><template #details><ApiErrorMeta :details="error" /></template></LoadErrorState>
|
||||
<p v-if="loading">正在读取当前事项与操作资格…</p>
|
||||
<p v-if="loading" role="status">{{ syncing ? '预约工作清单同步中,正在自动读取最新事项;已保存内容无需重复提交。' : '正在读取当前事项与操作资格…' }}</p>
|
||||
<template v-if="detail">
|
||||
<h3>{{ detail.item.title }}</h3><p>{{ typeLabels[detail.item.type] }} · {{ flowLabels[detail.item.flow] }} · {{ workStatus(detail.item) }}</p>
|
||||
<p>{{ workDate(detail.item) }} · {{ detail.item.timezone || '地点时区待核实' }}</p><p>{{ detail.item.destinationName || detail.item.originName || '地点待核实' }} · {{ detail.item.owner?.name || '待分派' }}</p>
|
||||
|
||||
Reference in New Issue
Block a user