修复采购审核竞态并整理管理页面展示

This commit is contained in:
2026-10-30 15:42:37 +08:00
parent 8cc8b4fb94
commit 4abd6ffd5d
23 changed files with 791 additions and 75 deletions
@@ -30,6 +30,8 @@ const reviewOpen = ref(false), reviewSaving = ref(false), reviewLoading = ref(fa
const reviewRow = ref<OverseasPurchaseSummary | null>(null), reviewWarehouses = ref<Awaited<ReturnType<typeof listOverseasPurchaseWarehouseOptions>>>([])
const reviewRequestKey = ref('')
const reviewForm = reactive({ decision: 'APPROVE' as 'APPROVE' | 'REJECT', purchaseWarehouseId: '', remark: '' })
let reviewGeneration = 0
watch(reviewOpen, value => { if (!value) invalidateReviewRequest() }, { flush: 'sync' })
const fields = computed<QueryField[]>(() => [
{ key: 'orderNo', type: 'input', label: '订单编号', placeholder: '请输入订单编号', width: 210 },
{ key: 'customerId', type: 'select', label: '客户', placeholder: '全部客户', width: 210, options: customerOptions.value.map((item) => ({ label: item.customerName, value: item.customerId })), props: { filterable: true, loading: customersLoading.value } },
@@ -53,7 +55,7 @@ const columns: DataTableColumn[] = [
]
function formatDateTime(value?: string | null) { return value ? value.replace('T', ' ').slice(0, 16) : '—' }
let generation = 0; let inFlight: Promise<void> | null = null; let requestKey = ''
onBeforeUnmount(() => { generation++ })
onBeforeUnmount(() => { generation++; invalidateReviewRequest() })
function load() {
const query: OverseasPurchaseQuery = { page: page.value, size: pageSize.value, customerId: String(applied.value.customerId || ''), orderNo: String(applied.value.orderNo || ''), purchaseCategory: String(applied.value.purchaseCategory || ''), productName: String(applied.value.productName || ''), status: String(applied.value.status || '') as OverseasPurchaseStatus | '' }
const key = JSON.stringify([auth.user?.id, query])
@@ -69,19 +71,29 @@ function load() {
})
inFlight = promise; return promise
}
watch(() => auth.user?.id, () => { rows.value = []; total.value = 0; void load() })
watch(() => auth.user?.id, () => { reviewOpen.value = false; rows.value = []; total.value = 0; void load() })
function search(model: QueryModel) { applied.value = { ...model }; if (page.value === 1) void load(); else page.value = 1 }
function open(row: OverseasPurchaseSummary) { void router.push({ name: 'overseas-business-purchase-detail', params: { purchaseId: row.orderNo }, query: { customerId: row.customerId } }) }
function invalidateReviewRequest() {
reviewGeneration++
reviewLoading.value = false; reviewWarehouses.value = []; reviewRow.value = null
}
async function beginReview(row: OverseasPurchaseSummary) {
if (reviewSaving.value) return
const current = ++reviewGeneration; const owner = auth.user?.id
reviewRow.value = row; reviewWarehouses.value = []; reviewRequestKey.value = crypto.randomUUID(); Object.assign(reviewForm, { decision: 'APPROVE', purchaseWarehouseId: '', remark: '' }); reviewOpen.value = true
reviewLoading.value = true
try { reviewWarehouses.value = await listOverseasPurchaseWarehouseOptions(row.procurementDirection) }
catch (error) { ElMessage.error(getApiErrorDetails(error, '仓库加载失败').message) }
finally { reviewLoading.value = false }
// 关闭、切换订单或操作员后,旧请求的结果、提示和结束回调均不得影响当前审核。
const isCurrent = () => current === reviewGeneration && reviewOpen.value && owner === auth.user?.id
try {
const warehouses = await listOverseasPurchaseWarehouseOptions(row.procurementDirection)
if (isCurrent()) reviewWarehouses.value = warehouses
} catch (error) { if (isCurrent()) ElMessage.error(getApiErrorDetails(error, '仓库加载失败').message) }
finally { if (isCurrent()) reviewLoading.value = false }
}
async function submitReview() {
const row = reviewRow.value
if (!row || reviewSaving.value) return
if (!row || reviewSaving.value || reviewLoading.value || !reviewOpen.value) return
if (reviewForm.decision === 'APPROVE' && !reviewForm.purchaseWarehouseId) { ElMessage.warning('请选择采购仓库'); return }
if (reviewForm.decision === 'REJECT' && !reviewForm.remark.trim()) { ElMessage.warning('请填写驳回原因'); return }
reviewSaving.value = true