fix(first-leg): preserve edit commands and add versioned cancellation
This commit is contained in:
@@ -10,6 +10,7 @@ import {
|
||||
getMerchantWarehouses,
|
||||
submitMerchantFirstLegOrder,
|
||||
updateMerchantFirstLegOrder,
|
||||
cancelMerchantFirstLegOrder,
|
||||
type ApiFirstLegStatus,
|
||||
type FirstLegOrderSaveRequest,
|
||||
type MerchantFirstLegOrder,
|
||||
@@ -468,9 +469,21 @@ function mapWarehouse(item: MerchantWarehouse): ClientWarehouse {
|
||||
}
|
||||
}
|
||||
|
||||
export interface DraftEditSession {
|
||||
readonly orderId: string
|
||||
readonly expectedVersion: number
|
||||
}
|
||||
|
||||
export const useFirstLegOrdersStore = defineStore('client-first-leg-orders', () => {
|
||||
const orders = ref<FirstLegOrder[]>([])
|
||||
const pendingSubmitKeys = new Map<string, string>()
|
||||
const pendingEdits = new WeakMap<DraftEditSession, { key: string; payload: { expectedVersion: number; draft: FirstLegOrderSaveRequest } }>()
|
||||
const pendingCancellations = new Map<string, { key: string; payload: { expectedVersion: number; reason: string } }>()
|
||||
|
||||
function beginDraftEdit(detail: FirstLegOrder): DraftEditSession {
|
||||
if (!canClientEditFirstLegOrder(detail.status) || !Number.isSafeInteger(detail.version) || detail.version < 0) throw new Error('请重新打开草稿详情后编辑')
|
||||
return Object.freeze({ orderId: detail.id, expectedVersion: detail.version })
|
||||
}
|
||||
const warehouses = ref<ClientWarehouse[]>([])
|
||||
const loading = ref(false)
|
||||
const loadedFromApi = ref(false)
|
||||
@@ -588,18 +601,52 @@ export const useFirstLegOrdersStore = defineStore('client-first-leg-orders', ()
|
||||
return mapped
|
||||
}
|
||||
|
||||
async function saveDraft(draft: FirstLegOrderDraft, customerName: string, id?: string) {
|
||||
async function saveDraft(draft: FirstLegOrderDraft, customerName: string, id?: string, editSession?: DraftEditSession) {
|
||||
const warehouse = prepareDraftForSave(draft, warehouses.value)
|
||||
if (id) {
|
||||
const order = getById(id)
|
||||
if (!order || !canClientEditFirstLegOrder(order.status)) throw new Error('当前订单状态不允许编辑')
|
||||
await updateMerchantFirstLegOrder(id, savePayload(draft, warehouse, customerName))
|
||||
return loadLegacyDetail(id)
|
||||
if (!editSession || editSession.orderId !== id) throw new Error('请重新打开草稿详情后编辑')
|
||||
const payload = { expectedVersion: editSession.expectedVersion, draft: savePayload(draft, warehouse, customerName) }
|
||||
let pending = pendingEdits.get(editSession)
|
||||
if (pending && JSON.stringify(pending.payload) !== JSON.stringify(payload)) throw new Error('上次保存结果未确认,请重试原内容,或重新打开详情后编辑')
|
||||
// Observe an uncertain previous outcome without replacing its frozen version.
|
||||
if (pending) await getMerchantFirstLegOrder(id)
|
||||
if (!pending) {
|
||||
pending = { key: createIdempotencyKey(`first-leg-edit-${id}`), payload: JSON.parse(JSON.stringify(payload)) }
|
||||
pendingEdits.set(editSession, pending)
|
||||
}
|
||||
await updateMerchantFirstLegOrder(id, pending.payload, pending.key)
|
||||
const saved = await loadLegacyDetail(id)
|
||||
pendingEdits.delete(editSession)
|
||||
return saved
|
||||
}
|
||||
const createdId = await createMerchantFirstLegOrder(savePayload(draft, warehouse, customerName))
|
||||
return loadLegacyDetail(String(createdId))
|
||||
}
|
||||
|
||||
async function cancelOrder(id: string, expectedVersion: number, reason: string) {
|
||||
if (!Number.isSafeInteger(expectedVersion) || expectedVersion < 0 || !reason.trim() || reason.trim().length > 500) throw new Error('取消订单需要详情版本及 1–500 字取消原因')
|
||||
const payload = { expectedVersion, reason: reason.trim() }
|
||||
let pending = pendingCancellations.get(id)
|
||||
if (pending && JSON.stringify(pending.payload) !== JSON.stringify(payload)) throw new Error('上次取消结果未确认,请使用原版本和原因重试')
|
||||
if (pending) await getMerchantFirstLegOrder(id)
|
||||
if (!pending) {
|
||||
pending = { key: createIdempotencyKey(`first-leg-cancel-${id}`), payload }
|
||||
pendingCancellations.set(id, pending)
|
||||
}
|
||||
await cancelMerchantFirstLegOrder(id, pending.payload, pending.key)
|
||||
pendingCancellations.delete(id)
|
||||
orders.value = orders.value.filter(order => order.id !== id)
|
||||
}
|
||||
|
||||
async function prepareCancellation(id: string) {
|
||||
const { order } = await getMerchantFirstLegOrder(id)
|
||||
const labels: Record<string, string> = { DRAFT: '草稿', SUBMITTED: '审核中', APPROVED: '已审核', ACCEPTED: '已接单', REJECTED: '已退回' }
|
||||
if (!Object.hasOwn(labels, order.status)) throw new Error('当前订单状态不允许取消,请刷新订单查看最新进度')
|
||||
if (!Number.isSafeInteger(order.version) || order.version < 0) throw new Error('订单版本缺失,请重新加载详情')
|
||||
pendingCancellations.delete(id)
|
||||
return { id, expectedVersion: order.version, businessNo: order.orderNo || order.inboundCode || '—', statusLabel: labels[order.status] }
|
||||
}
|
||||
|
||||
async function saveDraftBatch(
|
||||
drafts: Array<{ clientRowId: string; draft: FirstLegOrderDraft }>,
|
||||
customerName: string,
|
||||
@@ -621,8 +668,8 @@ export const useFirstLegOrdersStore = defineStore('client-first-leg-orders', ()
|
||||
return loadUnifiedDetail(id)
|
||||
}
|
||||
|
||||
async function submit(draft: FirstLegOrderDraft, customerName: string, id?: string, companyAuditStatus?: MerchantTenantStatus) {
|
||||
const order = await saveDraft(draft, customerName, id)
|
||||
async function submit(draft: FirstLegOrderDraft, customerName: string, id?: string, companyAuditStatus?: MerchantTenantStatus, editSession?: DraftEditSession) {
|
||||
const order = await saveDraft(draft, customerName, id, editSession)
|
||||
return submitSaved(order.id, companyAuditStatus)
|
||||
}
|
||||
|
||||
@@ -630,5 +677,5 @@ export const useFirstLegOrdersStore = defineStore('client-first-leg-orders', ()
|
||||
return loadLegacyDetail(id, getById(id))
|
||||
}
|
||||
|
||||
return { orders, warehouses, loading, loadedFromApi, loadError, warehouseLoadError, draftLoadError, activeCount, pendingCount, getById, load, loadDetail, loadDraftDetail, loadWarehouseDetail, loadWarehouseType, saveDraft, saveDraftBatch, submitSaved, submit }
|
||||
return { orders, warehouses, loading, loadedFromApi, loadError, warehouseLoadError, draftLoadError, activeCount, pendingCount, getById, load, loadDetail, loadDraftDetail, loadWarehouseDetail, loadWarehouseType, beginDraftEdit, saveDraft, prepareCancellation, cancelOrder, saveDraftBatch, submitSaved, submit }
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user